diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index ab742c9..8b4d123 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -60,9 +60,8 @@ private: "__pipe", "__fork", "__waitpid", "__chdir", "__environ", "__getcwd", "__getenv", // subprocess - "__subprocess_popen", - "__subprocess_pclose", - "__subprocess_read_stdout" + "__subprocess_create", + "__subprocess_terminate" }; // file mapper for file -> index diff --git a/src/nasal_import.cpp b/src/nasal_import.cpp index 4093516..77a206e 100644 --- a/src/nasal_import.cpp +++ b/src/nasal_import.cpp @@ -9,8 +9,15 @@ namespace nasal { 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 PATH = std::string(getenv("PATH")); + const auto PATH = std::string(env_get_path); usize last = 0, position = PATH.find(seperator, 0); while(position!=std::string::npos) { std::string dirpath = PATH.substr(last, position-last); diff --git a/src/natives/subprocess.cpp b/src/natives/subprocess.cpp index f6974e0..a04038e 100644 --- a/src/natives/subprocess.cpp +++ b/src/natives/subprocess.cpp @@ -4,65 +4,187 @@ #ifdef _MSC_VER #define popen _popen #define pclose _pclose +#define perror _perror +#endif + +#ifndef _MSC_VER +#include +#endif + +#ifndef WIN32 +#include #endif #include +#include +#include +#include +#include +#include namespace nasal { -const auto subprocess_object_name = "subprocess"; +const auto subproc_desc_name = "subprocess_descriptor"; -void subprocess_destructor(void* ptr) { - pclose(static_cast(ptr)); +void subprocess_desc_dtor(void* ptr) { +#ifdef WIN32 + auto pi = &static_cast(ptr)->pi; + + WaitForSingleObject(pi->hProcess, 0); + TerminateProcess(pi->hProcess, 0); + CloseHandle(pi->hProcess); + CloseHandle(pi->hThread); +#else + auto pid = static_cast(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) { - auto command = ctx->localr[1]; - if (!command.is_str()) { - return nas_err("subprocess::popen", "expect a string as the command"); +var builtin_subprocess_create(context* ctx, gc* ngc) { + auto cmd = ctx->localr[1]; + if (!cmd.is_vec()) { + return nas_err("subprocess::create", "expect a string as the command"); } - auto fd = popen(command.str().c_str(), "r"); - if (fd == nullptr) { - return nas_err("subprocess::popen", "failed to create sub-process"); + for(const auto& v : cmd.vec().elems) { + if (!v.is_str()) { + return nas_err("subprocess::create", "non-string arguments"); + } } - var ret = ngc->alloc(vm_type::vm_ghost); - ret.ghost().set(subprocess_object_name, subprocess_destructor, nullptr, fd); - return ret; + auto obj = ngc->alloc(vm_type::vm_ghost); + obj.ghost().set( + subproc_desc_name, + subprocess_desc_dtor, + nullptr, + new subprocess_descriptor + ); + +#ifdef WIN32 + auto si = &static_cast(obj.ghost().pointer)->si; + auto pi = &static_cast(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(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) { - auto fd = ctx->localr[1]; - if (!fd.object_check(subprocess_object_name)) { - return nas_err("subprocess::pclose", "not a valid subprocess"); +var builtin_subprocess_terminate(context* ctx, gc* ngc) { + auto obj = ctx->localr[1]; + if (!obj.object_check(subproc_desc_name)) { + return nas_err("subprocess::terminate", + "need correct subprocess descriptor" + ); } - auto res = pclose(static_cast(fd.ghost().pointer)); - fd.ghost().pointer = nullptr; - fd.ghost().clear(); + +#ifdef WIN32 + auto pi = &static_cast(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(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); } -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(fd.ghost().pointer))!=nullptr) { - res.str() += buffer; - } - return res; -} - nasal_builtin_table subprocess_native[] = { - {"__subprocess_popen", builtin_subprocess_popen}, - {"__subprocess_pclose", builtin_subprocess_pclose}, - {"__subprocess_read_stdout", builtin_subprocess_read_stdout}, + {"__subprocess_create", builtin_subprocess_create}, + {"__subprocess_terminate", builtin_subprocess_terminate}, {nullptr, nullptr} }; diff --git a/src/natives/subprocess.h b/src/natives/subprocess.h index 23029a4..4e25f19 100644 --- a/src/natives/subprocess.h +++ b/src/natives/subprocess.h @@ -4,13 +4,29 @@ #include "nasal_gc.h" #include "natives/builtin.h" +#ifndef _MSC_VER +#include +#endif + +#ifndef WIN32 +#include +#endif + 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*); -var builtin_subprocess_pclose(context*, gc*); -var builtin_subprocess_read_stdout(context*, gc*); +void subprocess_desc_dtor(void*); + +var builtin_subprocess_create(context*, gc*); +var builtin_subprocess_terminate(context*, gc*); extern nasal_builtin_table subprocess_native[]; } \ No newline at end of file diff --git a/std/dylib.nas b/std/dylib.nas index a808653..a63b0a0 100644 --- a/std/dylib.nas +++ b/std/dylib.nas @@ -13,7 +13,7 @@ var dlopen = func(libname) { if (io.exists(libname)) return __dlopen(libname); # 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 append(envpath, "."); var path = os.platform()=="windows"? "\\module\\":"/module/"; diff --git a/std/subprocess.nas b/std/subprocess.nas index e82cf8b..f256ca8 100644 --- a/std/subprocess.nas +++ b/std/subprocess.nas @@ -1,11 +1,8 @@ -var popen = func(cmd) { - return __subprocess_popen(cmd); + +var create = func(vec) { + return __subprocess_create(vec); } -var pclose = func(subproc) { - return __subprocess_pclose(subproc); +var terminate = func(pid) { + return __subprocess_terminate(pid); } - -var read = func(subproc) { - return __subprocess_read_stdout(subproc); -} \ No newline at end of file diff --git a/test/watchdog.nas b/test/watchdog.nas index 5c3c32b..6b0658b 100644 --- a/test/watchdog.nas +++ b/test/watchdog.nas @@ -70,7 +70,7 @@ if (size(argv)==2) { var modified_time = io.fstat(filename).st_mtime; println(os_time(), info_hd(), "\e[1mwatching ", filename, " ..\e[0m"); while(1) { - unix.sleep(5); + unix.sleep(1); if (!io.exists(filename)) { println( os_time(), @@ -91,7 +91,6 @@ while(1) { foreach(var i; args) { cmd ~= " " ~ i; } - cmd ~= " 2>&1"; println( os_time(), info_hd(), @@ -100,12 +99,11 @@ while(1) { "\"\e[0m" ); - var subproc = subprocess.popen(cmd); - var stdout_info = subprocess.read(subproc); - var ret = subprocess.pclose(subproc); - if (size(stdout_info)>0) { - println(stdout_info); - } + var subproc = subprocess.create(["nasal", filename]~args); + + unix.sleep(2); + var ret = subprocess.terminate(subproc); + println( os_time(), ret!=0? err_hd():info_hd(),