diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index 175fb06..8b4d123 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -60,11 +60,8 @@ private: "__pipe", "__fork", "__waitpid", "__chdir", "__environ", "__getcwd", "__getenv", // subprocess - "__subprocess_popen", - "__subprocess_pclose", - "__subprocess_read_stdout", - "__subprocess_fork", - "__subprocess_kill" + "__subprocess_create", + "__subprocess_terminate" }; // file mapper for file -> index diff --git a/src/natives/subprocess.cpp b/src/natives/subprocess.cpp index 6ef5f81..c89275d 100644 --- a/src/natives/subprocess.cpp +++ b/src/natives/subprocess.cpp @@ -17,101 +17,106 @@ #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"); - } - - auto fd = popen(command.str().c_str(), "r"); - if (fd == nullptr) { - return nas_err("subprocess::popen", "failed to create sub-process"); - } - - var ret = ngc->alloc(vm_type::vm_ghost); - ret.ghost().set(subprocess_object_name, subprocess_destructor, nullptr, fd); - return ret; -} - -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"); - } - auto res = pclose(static_cast(fd.ghost().pointer)); - fd.ghost().pointer = nullptr; - fd.ghost().clear(); - 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; -} - -var builtin_subprocess_fork(context* ctx, gc* ngc) { +var builtin_subprocess_create(context* ctx, gc* ngc) { auto cmd = ctx->localr[1]; if (!cmd.is_vec()) { - return nas_err("subprocess::fork", "expect a string as the command"); + return nas_err("subprocess::create", "expect a string as the command"); } + for(const auto& v : cmd.vec().elems) { + if (!v.is_str()) { + return nas_err("subprocess::create", "non-string arguments"); + } + } + + auto obj = ngc->alloc(vm_type::vm_ghost); + obj.ghost().set( + subproc_desc_name, + subprocess_desc_dtor, + nullptr, + new subprocess_descriptor + ); + #ifdef WIN32 - // STARTUPINFO si; - // PROCESS_INFORMATION pi; + auto si = &static_cast(obj.ghost().pointer)->si; + auto pi = &static_cast(obj.ghost().pointer)->pi; - // // init STARTUPINFO - // ZeroMemory(&si, sizeof(si)); - // si.cb = sizeof(si); - // si.dwFlags = STARTF_USESHOWWINDOW; - // si.wShowWindow = SW_SHOW; + // init STARTUPINFO + ZeroMemory(si, sizeof(STARTUPINFOW)); + si->cb = sizeof(STARTUPINFOW); + si->dwFlags = STARTF_USESHOWWINDOW; + si->wShowWindow = SW_SHOW; - // // init PROCESS_INFORMATION - // ZeroMemory(&pi, sizeof(pi)); + // init PROCESS_INFORMATION + ZeroMemory(pi, sizeof(PROCESS_INFORMATION)); - // auto len = MultiByteToWideChar(CP_UTF8, 0, cmd.str().c_str(), -1, nullptr, 0); + 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; - return var::num(pid); #endif - return nil; + return obj; } -var builtin_subprocess_kill(context* ctx, gc* ngc) { -#ifdef WIN32 - // TODO -#else - auto pid = ctx->localr[1]; - if (!pid.is_num()) { - return nas_err("subprocess::kill", "need numeral pid"); +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" + ); } +#ifdef WIN32 + auto pi = &static_cast(obj.ghost().pointer)->pi; + + WaitForSingleObject(pi->hProcess, 0); + TerminateProcess(pi->hProcess, 0); + CloseHandle(pi->hProcess); + CloseHandle(pi->hThread); +#else + auto pid = static_cast(obj.ghost().pointer)->pid; + int status; - pid_t result = waitpid(pid.num(), &status, WNOHANG); + pid_t result = waitpid(pid, &status, WNOHANG); + // child process running if (result==0) { - kill(pid.num(), SIGTERM); + kill(pid, SIGTERM); } #endif + return nil; } nasal_builtin_table subprocess_native[] = { - {"__subprocess_popen", builtin_subprocess_popen}, - {"__subprocess_pclose", builtin_subprocess_pclose}, - {"__subprocess_read_stdout", builtin_subprocess_read_stdout}, - {"__subprocess_fork", builtin_subprocess_fork}, - {"__subprocess_kill", builtin_subprocess_kill}, + {"__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 144b63d..4e25f19 100644 --- a/src/natives/subprocess.h +++ b/src/natives/subprocess.h @@ -4,16 +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_fork(context*, gc*); -var builtin_subprocess_kill(context*, gc*); +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/subprocess.nas b/std/subprocess.nas index c8b5abf..f256ca8 100644 --- a/std/subprocess.nas +++ b/std/subprocess.nas @@ -1,19 +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 read = func(subproc) { - return __subprocess_read_stdout(subproc); -} - -var fork = func(vec) { - return __subprocess_fork(vec); -} - -var kill = func(pid) { - return __subprocess_kill(pid); +var terminate = func(pid) { + return __subprocess_terminate(pid); }