Merge pull request #48 from ValKmjolnir/develop
👾 finish subprocess module
This commit is contained in:
commit
0725352349
|
@ -60,9 +60,8 @@ private:
|
||||||
"__pipe", "__fork", "__waitpid", "__chdir",
|
"__pipe", "__fork", "__waitpid", "__chdir",
|
||||||
"__environ", "__getcwd", "__getenv",
|
"__environ", "__getcwd", "__getenv",
|
||||||
// subprocess
|
// subprocess
|
||||||
"__subprocess_popen",
|
"__subprocess_create",
|
||||||
"__subprocess_pclose",
|
"__subprocess_terminate"
|
||||||
"__subprocess_read_stdout"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// file mapper for file -> index
|
// file mapper for file -> index
|
||||||
|
|
|
@ -9,8 +9,15 @@
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
linker::linker(): show_path_flag(false), this_file("") {
|
linker::linker(): show_path_flag(false), this_file("") {
|
||||||
|
const auto env_get_path = getenv("PATH");
|
||||||
|
if (!env_get_path) {
|
||||||
|
err.warn("link", "cannot get env \"PATH\".");
|
||||||
|
envpath = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto seperator = util::is_windows()? ';':':';
|
const auto seperator = util::is_windows()? ';':':';
|
||||||
const auto PATH = std::string(getenv("PATH"));
|
const auto PATH = std::string(env_get_path);
|
||||||
usize last = 0, position = PATH.find(seperator, 0);
|
usize last = 0, position = PATH.find(seperator, 0);
|
||||||
while(position!=std::string::npos) {
|
while(position!=std::string::npos) {
|
||||||
std::string dirpath = PATH.substr(last, position-last);
|
std::string dirpath = PATH.substr(last, position-last);
|
||||||
|
|
|
@ -4,65 +4,187 @@
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define popen _popen
|
#define popen _popen
|
||||||
#define pclose _pclose
|
#define pclose _pclose
|
||||||
|
#define perror _perror
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#include <sys/wait.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cwchar>
|
||||||
|
#include <clocale>
|
||||||
|
#include <vector>
|
||||||
|
#include <csignal>
|
||||||
|
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
const auto subprocess_object_name = "subprocess";
|
const auto subproc_desc_name = "subprocess_descriptor";
|
||||||
|
|
||||||
void subprocess_destructor(void* ptr) {
|
void subprocess_desc_dtor(void* ptr) {
|
||||||
pclose(static_cast<FILE*>(ptr));
|
#ifdef WIN32
|
||||||
|
auto pi = &static_cast<subprocess_descriptor*>(ptr)->pi;
|
||||||
|
|
||||||
|
WaitForSingleObject(pi->hProcess, 0);
|
||||||
|
TerminateProcess(pi->hProcess, 0);
|
||||||
|
CloseHandle(pi->hProcess);
|
||||||
|
CloseHandle(pi->hThread);
|
||||||
|
#else
|
||||||
|
auto pid = static_cast<subprocess_descriptor*>(ptr)->pid;
|
||||||
|
|
||||||
|
int status;
|
||||||
|
pid_t result = waitpid(pid, &status, WNOHANG);
|
||||||
|
|
||||||
|
// child process running
|
||||||
|
if (result==0) {
|
||||||
|
kill(pid, SIGTERM);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var builtin_subprocess_popen(context* ctx, gc* ngc) {
|
var builtin_subprocess_create(context* ctx, gc* ngc) {
|
||||||
auto command = ctx->localr[1];
|
auto cmd = ctx->localr[1];
|
||||||
if (!command.is_str()) {
|
if (!cmd.is_vec()) {
|
||||||
return nas_err("subprocess::popen", "expect a string as the command");
|
return nas_err("subprocess::create", "expect a string as the command");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fd = popen(command.str().c_str(), "r");
|
for(const auto& v : cmd.vec().elems) {
|
||||||
if (fd == nullptr) {
|
if (!v.is_str()) {
|
||||||
return nas_err("subprocess::popen", "failed to create sub-process");
|
return nas_err("subprocess::create", "non-string arguments");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ret = ngc->alloc(vm_type::vm_ghost);
|
auto obj = ngc->alloc(vm_type::vm_ghost);
|
||||||
ret.ghost().set(subprocess_object_name, subprocess_destructor, nullptr, fd);
|
obj.ghost().set(
|
||||||
return ret;
|
subproc_desc_name,
|
||||||
|
subprocess_desc_dtor,
|
||||||
|
nullptr,
|
||||||
|
new subprocess_descriptor
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
auto si = &static_cast<subprocess_descriptor*>(obj.ghost().pointer)->si;
|
||||||
|
auto pi = &static_cast<subprocess_descriptor*>(obj.ghost().pointer)->pi;
|
||||||
|
|
||||||
|
// init STARTUPINFO
|
||||||
|
ZeroMemory(si, sizeof(STARTUPINFOW));
|
||||||
|
si->cb = sizeof(STARTUPINFOW);
|
||||||
|
si->dwFlags = STARTF_USESHOWWINDOW;
|
||||||
|
si->wShowWindow = SW_SHOW;
|
||||||
|
|
||||||
|
// init PROCESS_INFORMATION
|
||||||
|
ZeroMemory(pi, sizeof(PROCESS_INFORMATION));
|
||||||
|
|
||||||
|
auto command = cmd.vec().elems[0].str();
|
||||||
|
for(usize i = 1; i<cmd.vec().elems.size(); ++i) {
|
||||||
|
command += " " + cmd.vec().elems[i].str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::setlocale(LC_ALL, ".UTF8");
|
||||||
|
auto str_length = 1 + (command.length()<<1);
|
||||||
|
auto buffer = new wchar_t[str_length];
|
||||||
|
auto converted = mbstowcs(buffer, command.c_str(), str_length);
|
||||||
|
if (converted == size_t(-1)) {
|
||||||
|
delete[] buffer;
|
||||||
|
return nas_err("subprocess::create", "failed to convert wchat_t*");
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[converted] = L'\0';
|
||||||
|
|
||||||
|
if (!CreateProcessW(
|
||||||
|
nullptr,
|
||||||
|
buffer,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
si,
|
||||||
|
pi
|
||||||
|
)) {
|
||||||
|
return nas_err("subprocess::create",
|
||||||
|
"failed to create subprocess: " +
|
||||||
|
std::to_string(GetLastError())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
delete[] buffer;
|
||||||
|
#else
|
||||||
|
// create argv
|
||||||
|
char** argv = new char*[cmd.vec().elems.size()+1];
|
||||||
|
for(usize i = 0; i<cmd.vec().elems.size(); ++i) {
|
||||||
|
argv[i] = strdup(cmd.vec().elems[i].str().c_str());
|
||||||
|
}
|
||||||
|
argv[cmd.vec().elems.size()] = nullptr;
|
||||||
|
|
||||||
|
// create child process
|
||||||
|
auto pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
return nas_err("subprocess::create", "failed to create sub-process");
|
||||||
|
}
|
||||||
|
// child process
|
||||||
|
if (pid==0) {
|
||||||
|
execvp(argv[0], argv);
|
||||||
|
nas_err("subprocess::create", "failed to execute command");
|
||||||
|
_exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parent process
|
||||||
|
static_cast<subprocess_descriptor*>(obj.ghost().pointer)->pid = pid;
|
||||||
|
for(usize i = 0; argv[i]; ++i) {
|
||||||
|
delete argv[i];
|
||||||
|
}
|
||||||
|
delete[] argv;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
var builtin_subprocess_pclose(context* ctx, gc* ngc) {
|
var builtin_subprocess_terminate(context* ctx, gc* ngc) {
|
||||||
auto fd = ctx->localr[1];
|
auto obj = ctx->localr[1];
|
||||||
if (!fd.object_check(subprocess_object_name)) {
|
if (!obj.object_check(subproc_desc_name)) {
|
||||||
return nas_err("subprocess::pclose", "not a valid subprocess");
|
return nas_err("subprocess::terminate",
|
||||||
|
"need correct subprocess descriptor"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
auto res = pclose(static_cast<FILE*>(fd.ghost().pointer));
|
|
||||||
fd.ghost().pointer = nullptr;
|
#ifdef WIN32
|
||||||
fd.ghost().clear();
|
auto pi = &static_cast<subprocess_descriptor*>(obj.ghost().pointer)->pi;
|
||||||
|
|
||||||
|
WaitForSingleObject(pi->hProcess, 0);
|
||||||
|
TerminateProcess(pi->hProcess, -1);
|
||||||
|
|
||||||
|
DWORD res;
|
||||||
|
GetExitCodeProcess(pi->hProcess, &res);
|
||||||
|
|
||||||
|
CloseHandle(pi->hProcess);
|
||||||
|
CloseHandle(pi->hThread);
|
||||||
|
#else
|
||||||
|
auto pid = static_cast<subprocess_descriptor*>(obj.ghost().pointer)->pid;
|
||||||
|
|
||||||
|
int status;
|
||||||
|
pid_t result = waitpid(pid, &status, WNOHANG);
|
||||||
|
|
||||||
|
// child process running
|
||||||
|
if (result==0) {
|
||||||
|
kill(pid, SIGTERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = WIFEXITED(status)? WEXITSTATUS(status):-1;
|
||||||
|
#endif
|
||||||
|
|
||||||
return var::num(res);
|
return var::num(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
var builtin_subprocess_read_stdout(context* ctx, gc* ngc) {
|
|
||||||
auto fd = ctx->localr[1];
|
|
||||||
if (!fd.object_check(subprocess_object_name)) {
|
|
||||||
return nas_err("subprocess::pclose", "not a valid subprocess");
|
|
||||||
}
|
|
||||||
char buffer[1025];
|
|
||||||
auto res = ngc->alloc(vm_type::vm_str);
|
|
||||||
while(fgets(
|
|
||||||
buffer,
|
|
||||||
sizeof(buffer)-1,
|
|
||||||
static_cast<FILE*>(fd.ghost().pointer))!=nullptr) {
|
|
||||||
res.str() += buffer;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
nasal_builtin_table subprocess_native[] = {
|
nasal_builtin_table subprocess_native[] = {
|
||||||
{"__subprocess_popen", builtin_subprocess_popen},
|
{"__subprocess_create", builtin_subprocess_create},
|
||||||
{"__subprocess_pclose", builtin_subprocess_pclose},
|
{"__subprocess_terminate", builtin_subprocess_terminate},
|
||||||
{"__subprocess_read_stdout", builtin_subprocess_read_stdout},
|
|
||||||
{nullptr, nullptr}
|
{nullptr, nullptr}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,29 @@
|
||||||
#include "nasal_gc.h"
|
#include "nasal_gc.h"
|
||||||
#include "natives/builtin.h"
|
#include "natives/builtin.h"
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
void subprocess_destructor(void*);
|
struct subprocess_descriptor {
|
||||||
|
#ifndef WIN32
|
||||||
|
pid_t pid;
|
||||||
|
#else
|
||||||
|
STARTUPINFOW si;
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
var builtin_subprocess_popen(context*, gc*);
|
void subprocess_desc_dtor(void*);
|
||||||
var builtin_subprocess_pclose(context*, gc*);
|
|
||||||
var builtin_subprocess_read_stdout(context*, gc*);
|
var builtin_subprocess_create(context*, gc*);
|
||||||
|
var builtin_subprocess_terminate(context*, gc*);
|
||||||
extern nasal_builtin_table subprocess_native[];
|
extern nasal_builtin_table subprocess_native[];
|
||||||
|
|
||||||
}
|
}
|
|
@ -13,7 +13,7 @@ var dlopen = func(libname) {
|
||||||
if (io.exists(libname))
|
if (io.exists(libname))
|
||||||
return __dlopen(libname);
|
return __dlopen(libname);
|
||||||
# find dynamic lib through PATH
|
# find dynamic lib through PATH
|
||||||
var envpath = split(os.platform()=="windows"? ";":":",unix.getenv("PATH"));
|
var envpath = split(os.platform()=="windows"? ";":":", unix.getenv("PATH"));
|
||||||
# first find ./module
|
# first find ./module
|
||||||
append(envpath, ".");
|
append(envpath, ".");
|
||||||
var path = os.platform()=="windows"? "\\module\\":"/module/";
|
var path = os.platform()=="windows"? "\\module\\":"/module/";
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
var popen = func(cmd) {
|
|
||||||
return __subprocess_popen(cmd);
|
var create = func(vec) {
|
||||||
|
return __subprocess_create(vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
var pclose = func(subproc) {
|
var terminate = func(pid) {
|
||||||
return __subprocess_pclose(subproc);
|
return __subprocess_terminate(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
var read = func(subproc) {
|
|
||||||
return __subprocess_read_stdout(subproc);
|
|
||||||
}
|
|
|
@ -70,7 +70,7 @@ if (size(argv)==2) {
|
||||||
var modified_time = io.fstat(filename).st_mtime;
|
var modified_time = io.fstat(filename).st_mtime;
|
||||||
println(os_time(), info_hd(), "\e[1mwatching ", filename, " ..\e[0m");
|
println(os_time(), info_hd(), "\e[1mwatching ", filename, " ..\e[0m");
|
||||||
while(1) {
|
while(1) {
|
||||||
unix.sleep(5);
|
unix.sleep(1);
|
||||||
if (!io.exists(filename)) {
|
if (!io.exists(filename)) {
|
||||||
println(
|
println(
|
||||||
os_time(),
|
os_time(),
|
||||||
|
@ -91,7 +91,6 @@ while(1) {
|
||||||
foreach(var i; args) {
|
foreach(var i; args) {
|
||||||
cmd ~= " " ~ i;
|
cmd ~= " " ~ i;
|
||||||
}
|
}
|
||||||
cmd ~= " 2>&1";
|
|
||||||
println(
|
println(
|
||||||
os_time(),
|
os_time(),
|
||||||
info_hd(),
|
info_hd(),
|
||||||
|
@ -100,12 +99,11 @@ while(1) {
|
||||||
"\"\e[0m"
|
"\"\e[0m"
|
||||||
);
|
);
|
||||||
|
|
||||||
var subproc = subprocess.popen(cmd);
|
var subproc = subprocess.create(["nasal", filename]~args);
|
||||||
var stdout_info = subprocess.read(subproc);
|
|
||||||
var ret = subprocess.pclose(subproc);
|
unix.sleep(2);
|
||||||
if (size(stdout_info)>0) {
|
var ret = subprocess.terminate(subproc);
|
||||||
println(stdout_info);
|
|
||||||
}
|
|
||||||
println(
|
println(
|
||||||
os_time(),
|
os_time(),
|
||||||
ret!=0? err_hd():info_hd(),
|
ret!=0? err_hd():info_hd(),
|
||||||
|
|
Loading…
Reference in New Issue