DLLEXPORT int jl_spawn(char *name, char **argv, uv_loop_t *loop, uv_process_t *proc, jl_value_t *julia_struct, uv_handle_type stdin_type, uv_pipe_t *stdin_pipe, uv_handle_type stdout_type, uv_pipe_t *stdout_pipe, uv_handle_type stderr_type, uv_pipe_t *stderr_pipe, int detach, char **env) { uv_process_options_t opts; uv_stdio_container_t stdio[3]; int error; opts.file = name; opts.env = env; #ifdef _OS_WINDOWS_ opts.flags = 0; #else opts.flags = UV_PROCESS_RESET_SIGPIPE; #endif opts.cwd = NULL; opts.args = argv; if (detach) opts.flags |= UV_PROCESS_DETACHED; opts.stdio = stdio; opts.stdio_count = 3; stdio[0].type = stdin_type; stdio[0].data.stream = (uv_stream_t*)(stdin_pipe); stdio[1].type = stdout_type; stdio[1].data.stream = (uv_stream_t*)(stdout_pipe); stdio[2].type = stderr_type; stdio[2].data.stream = (uv_stream_t*)(stderr_pipe); opts.exit_cb = &jl_uv_return_spawn; error = uv_spawn(loop,proc,opts); return error; }
static void spawn(void) { uv_stdio_container_t stdio[2]; int r; ASSERT(process_open == 0); ASSERT(pipe_open == 0); args[0] = exepath; args[1] = "spawn_helper"; args[2] = NULL; options.file = exepath; options.args = args; options.exit_cb = exit_cb; uv_pipe_init(loop, &out, 0); options.stdio = stdio; options.stdio_count = 2; options.stdio[0].flags = UV_IGNORE; options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; options.stdio[1].data.stream = (uv_stream_t*)&out; r = uv_spawn(loop, &process, options); ASSERT(r == 0); process_open = 1; pipe_open = 1; output_used = 0; r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); ASSERT(r == 0); }
DLLEXPORT int jl_spawn(char *name, char **argv, uv_loop_t *loop, uv_process_t *proc, jl_value_t *julia_struct, uv_handle_type stdin_type,uv_pipe_t *stdin_pipe, uv_handle_type stdout_type,uv_pipe_t *stdout_pipe, uv_handle_type stderr_type,uv_pipe_t *stderr_pipe) { #ifdef __APPLE__ char **environ = *_NSGetEnviron(); #endif uv_process_options_t opts; uv_stdio_container_t stdio[3]; int error; opts.file = name; #ifndef __WIN32__ opts.env = environ; #else opts.env = NULL; #endif opts.cwd = NULL; opts.args = argv; opts.flags = 0; opts.stdio = stdio; opts.stdio_count = 3; stdio[0].type = stdin_type; stdio[0].data.stream = (uv_stream_t*)(stdin_pipe); stdio[1].type = stdout_type; stdio[1].data.stream = (uv_stream_t*)(stdout_pipe); stdio[2].type = stderr_type; stdio[2].data.stream = (uv_stream_t*)(stderr_pipe); //opts.detached = 0; #This has been removed upstream to be uncommented once it is possible again opts.exit_cb = &jl_return_spawn; error = uv_spawn(loop,proc,opts); proc->data = julia_struct; return error; }
static int LuaIO_process_exec(lua_State* L) { const char* cmd; if (lua_type(L, 1) == LUA_TSTRING) { cmd = lua_tostring(L, 1); } else { return luaL_argerror(L, 2, "process.exec(cmd) error: cmd is required and must be [string]\n"); } /*shell, -c, cmd, null*/ char** args = LuaIO_malloc(sizeof(char*) * 4); args[0] = "/bin/sh"; args[1] = "-c"; args[2] = (char*)cmd; args[3] = NULL; if (!LuaIO_process_stdio_ptr) { LuaIO_process_stdio[0].flags = UV_INHERIT_FD; LuaIO_process_stdio[0].data.fd = 0; LuaIO_process_stdio[1].flags = UV_INHERIT_FD; LuaIO_process_stdio[1].data.fd = 1; LuaIO_process_stdio[2].flags = UV_INHERIT_FD; LuaIO_process_stdio[2].data.fd = 2; LuaIO_process_stdio_ptr = LuaIO_process_stdio; } uv_process_options_t* options = LuaIO_malloc(sizeof(uv_process_options_t)); if (!options) { LuaIO_free(args); return luaL_error(L, "process.exec(cmd) error: no memory for uv_process_options_t options\n"); } LuaIO_memzero(options, sizeof(uv_process_options_t)); options->exit_cb = LuaIO_process_onexit; options->file = "/bin/sh"; options->args = args; options->stdio_count = 3; options->stdio = LuaIO_process_stdio_ptr; uv_process_t* handle = LuaIO_malloc(sizeof(uv_process_t)); if (!handle) { LuaIO_process_free_options(options); return luaL_error(L, "process.exec(cmd) error: no memory for uv_process_t handle\n"); } LuaIO_memzero(handle, sizeof(uv_process_t)); int ret = uv_spawn(uv_default_loop(), handle, options); if (ret < 0) { LuaIO_process_free_options(options); uv_close((uv_handle_t*)handle, NULL); return luaL_error(L, "process.exec(cmd) uv_spawn() error: %s\n", uv_strerror(ret)); } if (!LuaIO_process_signal_ptr) { uv_signal_init(uv_default_loop(), &LuaIO_process_signal); LuaIO_process_signal_ptr = &LuaIO_process_signal; uv_signal_start(LuaIO_process_signal_ptr, LuaIO_process_signal_callback, SIGQUIT); } lua_pushinteger(L, handle->pid); return 1; }
JL_DLLEXPORT int jl_spawn(char *name, char **argv, uv_loop_t *loop, uv_process_t *proc, jl_value_t *julia_struct, uv_handle_type stdin_type, uv_pipe_t *stdin_pipe, uv_handle_type stdout_type, uv_pipe_t *stdout_pipe, uv_handle_type stderr_type, uv_pipe_t *stderr_pipe, int flags, char **env, char *cwd, uv_exit_cb cb) { uv_process_options_t opts; uv_stdio_container_t stdio[3]; int error; opts.file = name; opts.env = env; #ifdef _OS_WINDOWS_ opts.flags = flags; #else opts.flags = flags | UV_PROCESS_RESET_SIGPIPE; #endif opts.cwd = cwd; opts.args = argv; opts.stdio = stdio; opts.stdio_count = 3; stdio[0].type = stdin_type; stdio[0].data.stream = (uv_stream_t*)(stdin_pipe); stdio[1].type = stdout_type; stdio[1].data.stream = (uv_stream_t*)(stdout_pipe); stdio[2].type = stderr_type; stdio[2].data.stream = (uv_stream_t*)(stderr_pipe); opts.exit_cb = cb; error = uv_spawn(loop,proc,&opts); return error; }
static void spawn() { int r; ASSERT(process_open == 0); ASSERT(pipe_open == 0); args[0] = exepath; args[1] = "spawn_helper"; args[2] = NULL; options.file = exepath; options.args = args; options.exit_cb = exit_cb; uv_pipe_init(&out); options.stdout_stream = &out; r = uv_spawn(&process, options); ASSERT(r == 0); process_open = 1; pipe_open = 1; output_used = 0; r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); ASSERT(r == 0); }
int main(int argc, char** argv) { char* priv = NULL; char** arguments = NULL; uv_process_t* child_req = NULL; uv_process_options_t* options = NULL; priv = calloc(1, sizeof(uv_process_t) + sizeof(uv_process_options_t) + 2 * sizeof(char*)); if (priv == NULL) { fprintf(stderr, "Failed to allocate the memory block\n"); return -1; } child_req = (void*)priv; options = (void*)(priv + sizeof(uv_process_t)); arguments = (void*)(priv + sizeof(uv_process_t) + sizeof(uv_process_options_t)); arguments[0] = "./subproc"; arguments[1] = NULL; options->exit_cb = _on_subproc_exit; options->file = "./subproc"; options->args = arguments; if (uv_spawn(uv_default_loop(), child_req, *options)) { fprintf(stderr, "Failed to start the process"); return -1; } uv_run(uv_default_loop()); return 0; }
void spawn() { int i; char** env = NULL; env = env_copy(environ, env); child = malloc(sizeof(uv_process_t)); uv_stdio_container_t stdio[4]; uv_process_options_t options; uv_pipe_init(loop, &child_stdout, 0); uv_pipe_init(loop, &child_stderr, 0); uv_pipe_init(loop, &child_ipc, 0); // // Setup child's stdio. stdout and stderr are pipes so that we can read // child process' output. // FD 3 is a pipe used for IPC. // options.stdio_count = 4; stdio[0].flags = UV_INHERIT_FD; stdio[0].data.fd = 0; stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; stdio[1].data.stream = (uv_stream_t*) &child_stdout; stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; stdio[2].data.stream = (uv_stream_t*) &child_stderr; stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; stdio[3].data.stream = (uv_stream_t*) &child_ipc; options.env = env; options.cwd = NULL; options.file = arguments[0]; options.args = arguments; options.flags = 0; options.stdio = stdio; options.exit_cb = on_process_exit; for (i = 0; i < PLUGIN_COUNT; i++) { if (plugins[i].process_options_cb) { plugins[i].process_options_cb(&options); } } if (uv_spawn(loop, child, options)) { fprintf(stderr, "uv_spawn: %s\n", uv_err_name(uv_last_error(loop))); return; } for (i = 0; i < PLUGIN_COUNT; i++) { if (plugins[i].process_spawned_cb) { plugins[i].process_spawned_cb(child, &options); } } uv_read_start(options.stdio[1].data.stream, forza__on_alloc, forza__on_stdout_read); uv_read_start(options.stdio[2].data.stream, forza__on_alloc, forza__on_stderr_read); uv_read_start(options.stdio[3].data.stream, forza__on_alloc, forza__on_ipc_read); }
bool process::start(uv_loop_t *loop, const char *file, const char * const *args, void *owner, uv_exit_cb on_exit, void (*deleter)(void *)) noexcept { assert(loop); this->owner = owner; this->deleter = deleter; int r; ++wait_close; close_on_return close_in((uv_handle_t *)&in, close_cb); if ((r = uv_pipe_init(loop, &in, 0)) < 0) { pruv_log_uv_err(LOG_ERR, "uv_pipe_init in", r); return false; } ++wait_close; close_on_return close_out((uv_handle_t *)&out, close_cb); if ((r = uv_pipe_init(loop, &out, 0)) < 0) { pruv_log_uv_err(LOG_ERR, "uv_pipe_init out", r); return false; } uv_process_options_t options; memset(&options, 0, sizeof(options)); options.exit_cb = on_exit; options.file = file; // http://pubs.opengroup.org/onlinepubs/009604499/functions/exec.html // RATIONALE section describes, why args can't be const. // It is only due to limitation of the ISO C. // In fact args is completely constant. options.args = const_cast<char **>(args); options.flags = UV_PROCESS_WINDOWS_HIDE; options.stdio_count = 2; uv_stdio_container_t stdio[2]; options.stdio = stdio; options.stdio[0].flags = uv_stdio_flags(UV_CREATE_PIPE | UV_READABLE_PIPE); options.stdio[0].data.stream = (uv_stream_t *)∈ options.stdio[1].flags = uv_stdio_flags(UV_CREATE_PIPE | UV_WRITABLE_PIPE); options.stdio[1].data.stream = (uv_stream_t *)&out; ++wait_close; close_on_return close_this_proc((uv_handle_t *)this, close_cb); if ((r = uv_spawn(loop, (uv_process_t *)this, &options)) < 0) { pruv_log_uv_err(LOG_ERR, "uv_spawn", r); return false; } close_in.h = close_out.h = close_this_proc.h = nullptr; return true; }
static void LuaIO_process_onexit(uv_process_t* handle, int64_t status, int signal) { if (handle->data) { LuaIO_process_data_t* data = handle->data; fprintf(stderr, "process[%d] exit. status: %" PRId64 ", signal: %d, file: %s\n", handle->pid, status, signal, data->options->args[1]); data->options->file = LuaIO_process_exepath_ptr; data->options->args[0] = LuaIO_process_exepath_ptr; uv_process_t* process = (uv_process_t*) LuaIO_malloc(sizeof(uv_process_t)); if (!process) { LuaIO_process_free_options(data->options); luaL_unref(LuaIO_get_main_thread(), LUA_REGISTRYINDEX, data->options_ref); LuaIO_free(data); fprintf(stderr, "process[%s] restart failed. no more memory for process\n", data->options->args[1]); } LuaIO_memzero(process, sizeof(uv_process_t)); process->data = data; int ret = uv_spawn(uv_default_loop(), process, data->options); if (ret < 0) { LuaIO_process_free_options(data->options); luaL_unref(LuaIO_get_main_thread(), LUA_REGISTRYINDEX, data->options_ref); LuaIO_free(data); uv_close((uv_handle_t*)process, NULL); fprintf(stderr, "process[%s] restart failed. uv_spawn() error: %s\n", data->options->args[1], uv_strerror(ret)); } if (data->cpu >= 0) LuaIO_set_affinity(process->pid, data->cpu); return; } fprintf(stderr, "process[%d] exit. status: %" PRId64 ", signal: %d\n", handle->pid, status, signal); uv_close((uv_handle_t*)handle, NULL); }
void setup_workers() { size_t path_size = 500; uv_exepath(worker_path, &path_size); strcpy(worker_path + (strlen(worker_path) - strlen("multi-echo-server")), "worker"); fprintf(stderr, "Worker path: %s\n", worker_path); char* args[2]; args[0] = worker_path; args[1] = NULL; round_robin_counter = 0; // ... // launch same number of workers as number of CPUs uv_cpu_info_t *info; int cpu_count; uv_cpu_info(&info, &cpu_count); uv_free_cpu_info(info, cpu_count); child_worker_count = cpu_count; workers = calloc(sizeof(struct child_worker), cpu_count); while (cpu_count--) { struct child_worker *worker = &workers[cpu_count]; uv_pipe_init(loop, &worker->pipe, 1); uv_stdio_container_t child_stdio[3]; child_stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; child_stdio[0].data.stream = (uv_stream_t*) &worker->pipe; child_stdio[1].flags = UV_IGNORE; child_stdio[2].flags = UV_INHERIT_FD; child_stdio[2].data.fd = 2; worker->options.stdio = child_stdio; worker->options.stdio_count = 3; worker->options.exit_cb = close_process_handle; worker->options.file = args[0]; worker->options.args = args; uv_spawn(loop, &worker->req, worker->options); fprintf(stderr, "Started worker %d\n", worker->req.pid); } }
int main() { loop = uv_default_loop(); char* args[3]; args[0] = "mkdir"; args[1] = "test-dir"; args[2] = NULL; options.exit_cb = on_exit; options.file = "mkdir"; options.args = args; if (uv_spawn(loop, &child_req, options)) { fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop))); return 1; } return uv_run(loop, UV_RUN_DEFAULT); }
void spawn_helper(uv_pipe_t* channel, uv_process_t* process, const char* helper) { uv_process_options_t options; size_t exepath_size; char exepath[1024]; char* args[3]; int r; uv_stdio_container_t stdio[3]; r = uv_pipe_init(uv_default_loop(), channel, 1); ASSERT(r == 0); ASSERT(channel->ipc); exepath_size = sizeof(exepath); r = uv_exepath(exepath, &exepath_size); ASSERT(r == 0); exepath[exepath_size] = '\0'; args[0] = exepath; args[1] = (char*)helper; args[2] = NULL; memset(&options, 0, sizeof(options)); options.file = exepath; options.args = args; options.exit_cb = exit_cb; options.stdio = stdio; options.stdio_count = ARRAY_SIZE(stdio); stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE; stdio[0].data.stream = (uv_stream_t*) channel; stdio[1].flags = UV_INHERIT_FD; stdio[1].data.fd = 1; stdio[2].flags = UV_INHERIT_FD; stdio[2].data.fd = 2; r = uv_spawn(uv_default_loop(), process, &options); ASSERT(r == 0); }
void setup_workers() { int r; exepath_for_worker(); char* args[2]; args[0] = exepath; args[1] = NULL; round_robin_counter = 0; int cpu_count = get_cpu_count(); child_worker_count = cpu_count; workers = calloc(sizeof(struct child_worker), cpu_count); while (cpu_count--) { struct child_worker *worker = &workers[cpu_count]; // pipe is acting as IPC channel uv_pipe_init(loop, &worker->pipe, IPC); // https://github.com/thlorenz/libuv-dox/blob/master/types.md#uv_stdio_container_t // https://github.com/thlorenz/libuv-dox/blob/master/types.md#uv_stdio_flags uv_stdio_container_t child_stdio[3]; child_stdio[STDIN].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; child_stdio[STDIN].data.stream = (uv_stream_t*) &worker->pipe; child_stdio[STDOUT].flags = UV_IGNORE; child_stdio[STDERR].flags = UV_INHERIT_FD; child_stdio[STDERR].data.fd = STDERR; // https://github.com/thlorenz/libuv-dox/blob/master/types.md#uv_process_options_t worker->options.stdio_count = 3; worker->options.stdio = child_stdio; worker->options.exit_cb = on_exit; worker->options.file = exepath; worker->options.args = args; r = uv_spawn(loop, &worker->req, &worker->options); if (r) ERROR("spawning worker", r); fprintf(stderr, "Started worker %d\n", worker->req.pid); } }
void spawn_child(int detach) { uv_stdio_container_t stdio[3]; int i; options.stdio_count = 3; if (detach) { for (i = 0; i < options.stdio_count; i++) { stdio[i].flags = UV_IGNORE; } } else { for (i = 0; i < options.stdio_count; i++) { stdio[i].flags = UV_INHERIT_FD; stdio[i].data.fd = i; } } options.file = opts.child_args[0]; options.args = opts.child_args; options.stdio = stdio; options.env = environ; options.exit_cb = detach ? NULL : spawn_cb; if (detach) options.flags = UV_PROCESS_DETACHED; if (uv_spawn(loop, &child_req, options)) { fprintf(stderr, "Error %s\n", uv_err_name(uv_last_error(loop))); fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop))); } if (detach) { uv_unref((uv_handle_t*)&child_req); return; } if (opts.pidname != NULL) { write_pid_file(child_req.pid, opts.pidname); } }
int main() { loop = uv_default_loop(); char* args[3]; args[0] = "sleep"; args[1] = "100"; args[2] = NULL; options.exit_cb = NULL; options.file = "sleep"; options.args = args; options.flags = UV_PROCESS_DETACHED; if (uv_spawn(loop, &child_req, options)) { fprintf(stderr, "%s\n", uv_strerror(uv_last_error(loop))); return 1; } fprintf(stderr, "Launched sleep with PID %d\n", child_req.pid); uv_unref((uv_handle_t*) &child_req); return uv_run(loop, UV_RUN_DEFAULT); }
MVMObject * MVM_file_openpipe(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env, MVMString *err_path) { MVMint64 spawn_result = 0; uv_process_t *process = calloc(1, sizeof(uv_process_t)); uv_process_options_t process_options = {0}; uv_stdio_container_t process_stdio[3]; int i; int status; int readable = 1; uv_pipe_t *out, *in; char * const cmdin = MVM_string_utf8_encode_C_string(tc, cmd); char * const _cwd = MVM_string_utf8_encode_C_string(tc, cwd); const MVMuint64 size = MVM_repr_elems(tc, env); MVMIter * const iter = (MVMIter *)MVM_iter(tc, env); char **_env = malloc((size + 1) * sizeof(char *)); #ifdef _WIN32 const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */ char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec")); char *args[3]; args[0] = "/c"; { MVMint64 len = strlen(cmdin); MVMint64 i; for (i = 0; i < len; i++) if (cmdin[i] == '/') cmdin[i] = '\\'; } args[1] = cmdin; args[2] = NULL; #else char * const _cmd = "/bin/sh"; char *args[4]; args[0] = "/bin/sh"; args[1] = "-c"; args[2] = cmdin; args[3] = NULL; #endif INIT_ENV(); /* Making openpipe distinguish between :rp and :wp and all other options * is left as an excercise for the reader. readable = strncmp(cmdin, "/usr/bin/wc", 11) != 0; */ if (readable) { /* We want to read from the child's stdout. */ out = malloc(sizeof(uv_pipe_t)); uv_pipe_init(tc->loop, out, 0); uv_pipe_open(out, 0); process_stdio[0].flags = UV_INHERIT_FD; // child's stdin process_stdio[0].data.fd = 0; process_stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; // child's stdout process_stdio[1].data.stream = (uv_stream_t*)out; } else { /* We want to print to the child's stdin. */ in = malloc(sizeof(uv_pipe_t)); uv_pipe_init(tc->loop, in, 0); uv_pipe_open(in, 1); process_stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; // child's stdin process_stdio[0].data.stream = (uv_stream_t*)in; process_stdio[1].flags = UV_INHERIT_FD; // child's stdout process_stdio[1].data.fd = 1; } process_stdio[2].flags = UV_INHERIT_FD; // child's stderr process_stdio[2].data.fd = 2; process_options.stdio = process_stdio; process_options.file = _cmd; process_options.args = args; process_options.cwd = _cwd; process_options.flags = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS | UV_PROCESS_WINDOWS_HIDE; process_options.env = _env; process_options.stdio_count = 3; process_options.exit_cb = spawn_on_exit; uv_ref((uv_handle_t *)process); spawn_result = uv_spawn(tc->loop, process, &process_options); if (spawn_result) { FREE_ENV(); free(_cwd); free(cmdin); uv_unref((uv_handle_t *)process); MVM_exception_throw_adhoc(tc, "Failed to open pipe: %d", errno); } FREE_ENV(); free(_cwd); free(cmdin); uv_unref((uv_handle_t *)process); return MVM_io_syncpipe(tc, (uv_stream_t *)(readable ? out : in), process); }
int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg) { uv_stdio_container_t proc_stdio[3]; uv_process_options_t proc_opts; uv_process_t proc; uv_pipe_t proc_stdin, proc_stdout; uv_write_t write_req; int expected_exits = 1; ProcessData pdata = { .reading = false, .exited = 0, .old_mode = cur_tmode, .old_state = State, .shell_stdin = (uv_stream_t *)&proc_stdin, .wbuffer = NULL, }; out_flush(); if (opts & kShellOptCooked) { // set to normal mode settmode(TMODE_COOK); } // While the child is running, ignore terminating signals signal_reject_deadly(); // Create argv for `uv_spawn` // TODO(tarruda): we can use a static buffer for small argument vectors. 1024 // bytes should be enough for most of the commands and if more is necessary // we can allocate a another buffer proc_opts.args = shell_build_argv(cmd, extra_shell_arg); proc_opts.file = proc_opts.args[0]; proc_opts.exit_cb = exit_cb; // Initialize libuv structures proc_opts.stdio = proc_stdio; proc_opts.stdio_count = 3; // Hide window on Windows :) proc_opts.flags = UV_PROCESS_WINDOWS_HIDE; proc_opts.cwd = NULL; proc_opts.env = NULL; // The default is to inherit all standard file descriptors(this will change // when the UI is moved to an external process) proc_stdio[0].flags = UV_INHERIT_FD; proc_stdio[0].data.fd = 0; proc_stdio[1].flags = UV_INHERIT_FD; proc_stdio[1].data.fd = 1; proc_stdio[2].flags = UV_INHERIT_FD; proc_stdio[2].data.fd = 2; if (opts & (kShellOptHideMess | kShellOptExpand)) { // Ignore the shell stdio(redirects to /dev/null on unixes) proc_stdio[0].flags = UV_IGNORE; proc_stdio[1].flags = UV_IGNORE; proc_stdio[2].flags = UV_IGNORE; } else { State = EXTERNCMD; if (opts & kShellOptWrite) { // Write from the current buffer into the process stdin uv_pipe_init(uv_default_loop(), &proc_stdin, 0); write_req.data = &pdata; proc_stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; proc_stdio[0].data.stream = (uv_stream_t *)&proc_stdin; } if (opts & kShellOptRead) { // Read from the process stdout into the current buffer uv_pipe_init(uv_default_loop(), &proc_stdout, 0); proc_stdout.data = &pdata; proc_stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; proc_stdio[1].data.stream = (uv_stream_t *)&proc_stdout; ga_init(&pdata.ga, 1, BUFFER_LENGTH); } } if (uv_spawn(uv_default_loop(), &proc, &proc_opts)) { // Failed, probably due to `sh` not being executable if (!emsg_silent) { MSG_PUTS(_("\nCannot execute shell ")); msg_outtrans(p_sh); msg_putchar('\n'); } return proc_cleanup_exit(&pdata, &proc_opts, opts); } // Assign the flag address after `proc` is initialized by `uv_spawn` proc.data = &pdata; if (opts & kShellOptWrite) { // Queue everything for writing to the shell stdin write_selection(&write_req); expected_exits++; } if (opts & kShellOptRead) { // Start the read stream for the shell stdout uv_read_start((uv_stream_t *)&proc_stdout, alloc_cb, read_cb); expected_exits++; } // Keep running the loop until all three handles are completely closed while (pdata.exited < expected_exits) { uv_run(uv_default_loop(), UV_RUN_ONCE); if (got_int) { // Forward SIGINT to the shell // TODO(tarruda): for now this is only needed if the terminal is in raw // mode, but when the UI is externalized we'll also need it, so leave it // here uv_process_kill(&proc, SIGINT); got_int = false; } } if (opts & kShellOptRead) { if (pdata.ga.ga_len > 0) { // If there's an unfinished line in the growable array, append it now. append_ga_line(&pdata.ga); // remember that the NL was missing curbuf->b_no_eol_lnum = curwin->w_cursor.lnum; } else { curbuf->b_no_eol_lnum = 0; } ga_clear(&pdata.ga); } if (opts & kShellOptWrite) { free(pdata.wbuffer); } return proc_cleanup_exit(&pdata, &proc_opts, opts); } static int tokenize(char_u *str, char **argv) { int argc = 0, len; char_u *p = str; while (*p != NUL) { len = word_length(p); if (argv != NULL) { // Fill the slot argv[argc] = xmalloc(len + 1); memcpy(argv[argc], p, len); argv[argc][len] = NUL; } argc++; p += len; p = skipwhite(p); } return argc; }
// Initializes uv_process_t and starts the process. int luv_spawn(lua_State* L) { int before = lua_gettop(L); uv_pipe_t* stdin_stream = (uv_pipe_t*)luv_checkudata(L, 1, "pipe"); uv_pipe_t* stdout_stream = (uv_pipe_t*)luv_checkudata(L, 2, "pipe"); uv_pipe_t* stderr_stream = (uv_pipe_t*)luv_checkudata(L, 3, "pipe"); const char* command = luaL_checkstring(L, 4); luaL_checktype(L, 5, LUA_TTABLE); // args luaL_checktype(L, 6, LUA_TTABLE); // options // Parse the args array size_t argc = lua_objlen(L, 5) + 1; char** args = malloc(argc + 1); args[0] = (char*)command; int i; for (i = 1; i < argc; i++) { lua_rawgeti(L, 5, i); args[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } args[argc] = NULL; // Get the cwd lua_getfield(L, 6, "cwd"); char* cwd = (char*)lua_tostring(L, -1); lua_pop(L, 1); // Get the env lua_getfield(L, 6, "env"); char** env = NULL; if (lua_type(L, -1) == LUA_TTABLE) { argc = lua_objlen(L, -1); env = malloc(argc + 1); for (i = 0; i < argc; i++) { lua_rawgeti(L, -1, i + 1); env[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } env[argc] = NULL; } lua_pop(L, 1); uv_process_options_t options; options.exit_cb = luv_process_on_exit; options.file = command; options.args = args; options.env = env; options.cwd = cwd; options.stdin_stream = stdin_stream; options.stdout_stream = stdout_stream; options.stderr_stream = stderr_stream; // Create the userdata uv_process_t* handle = (uv_process_t*)lua_newuserdata(L, sizeof(uv_process_t)); int r = uv_spawn(uv_default_loop(), handle, options); free(args); if (env) free(env); if (r) { uv_err_t err = uv_last_error(uv_default_loop()); return luaL_error(L, "spawn: %s", uv_strerror(err)); } // Set metatable for type luaL_getmetatable(L, "luv_process"); lua_setmetatable(L, -2); // Create a local environment for storing stuff lua_newtable(L); lua_setfenv (L, -2); // Store a reference to the userdata in the handle luv_ref_t* ref = (luv_ref_t*)malloc(sizeof(luv_ref_t)); ref->L = L; lua_pushvalue(L, -1); // duplicate so we can _ref it ref->r = luaL_ref(L, LUA_REGISTRYINDEX); handle->data = ref; assert(lua_gettop(L) == before + 1); // return the userdata return 1; }
MVMint64 MVM_proc_spawn(MVMThreadContext *tc, MVMObject *argv, MVMString *cwd, MVMObject *env, MVMObject *in, MVMObject *out, MVMObject *err, MVMint64 flags) { MVMint64 result = 0, spawn_result; uv_process_t *process = MVM_calloc(1, sizeof(uv_process_t)); uv_process_options_t process_options = {0}; uv_stdio_container_t process_stdio[3]; int i; char * const _cwd = MVM_string_utf8_c8_encode_C_string(tc, cwd); const MVMuint64 size = MVM_repr_elems(tc, env); MVMIter * const iter = (MVMIter *)MVM_iter(tc, env); char **_env = MVM_malloc((size + 1) * sizeof(char *)); const MVMuint64 arg_size = MVM_repr_elems(tc, argv); char **args = MVM_malloc((arg_size + 1) * sizeof(char *)); MVMRegister reg; i = 0; while(i < arg_size) { REPR(argv)->pos_funcs.at_pos(tc, STABLE(argv), argv, OBJECT_BODY(argv), i, ®, MVM_reg_obj); args[i++] = MVM_string_utf8_c8_encode_C_string(tc, MVM_repr_get_str(tc, reg.o)); } args[arg_size] = NULL; INIT_ENV(); setup_process_stdio(tc, in, process, &process_stdio[0], 0, flags, "spawn"); setup_process_stdio(tc, out, process, &process_stdio[1], 1, flags >> 3, "spawn"); setup_process_stdio(tc, err, process, &process_stdio[2], 2, flags >> 6, "spawn"); process_options.stdio = process_stdio; process_options.file = arg_size ? args[0] : NULL; process_options.args = args; process_options.cwd = _cwd; process_options.flags = UV_PROCESS_WINDOWS_HIDE; process_options.env = _env; process_options.stdio_count = 3; process_options.exit_cb = spawn_on_exit; if (flags & (MVM_PIPE_CAPTURE_IN | MVM_PIPE_CAPTURE_OUT | MVM_PIPE_CAPTURE_ERR)) { process->data = MVM_calloc(1, sizeof(MVMint64)); uv_ref((uv_handle_t *)process); spawn_result = uv_spawn(tc->loop, process, &process_options); if (spawn_result) result = spawn_result; } else { process->data = &result; uv_ref((uv_handle_t *)process); spawn_result = uv_spawn(tc->loop, process, &process_options); if (spawn_result) result = spawn_result; else uv_run(tc->loop, UV_RUN_DEFAULT); } FREE_ENV(); MVM_free(_cwd); uv_unref((uv_handle_t *)process); i = 0; while(args[i]) MVM_free(args[i++]); MVM_free(args); return result; }
static int luv_spawn(lua_State* L) { uv_process_t* handle; uv_process_options_t options; size_t i, len = 0; int ret; memset(&options, 0, sizeof(options)); options.exit_cb = exit_cb; options.file = luaL_checkstring(L, 1); options.flags = 0; // Make sure the 2nd argument is a table luaL_checktype(L, 2, LUA_TTABLE); // get the args list lua_getfield(L, 2, "args"); // +1 for inserted command at front if (lua_type(L, -1) == LUA_TTABLE) { len = 1 + lua_rawlen(L, -1); } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 3, "args option must be table"); } else { len = 1; } // +1 for null terminator at end options.args = malloc((len + 1) * sizeof(*options.args)); if (!options.args) { luv_clean_options(&options); return luaL_error(L, "Problem allocating args"); } options.args[0] = (char*)options.file; for (i = 1; i < len; ++i) { lua_rawgeti(L, -1, i); options.args[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } options.args[len] = NULL; lua_pop(L, 1); // get the stdio list lua_getfield(L, 2, "stdio"); if (lua_type(L, -1) == LUA_TTABLE) { options.stdio_count = len = lua_rawlen(L, -1); options.stdio = malloc(len * sizeof(*options.stdio)); if (!options.stdio) { luv_clean_options(&options); return luaL_error(L, "Problem allocating stdio"); } for (i = 0; i < len; ++i) { lua_rawgeti(L, -1, i + 1); // integers are assumed to be file descripters if (lua_type(L, -1) == LUA_TNUMBER) { options.stdio[i].flags = UV_INHERIT_FD; options.stdio[i].data.fd = lua_tointeger(L, -1); } // userdata is assumed to be a uv_stream_t instance else if (lua_type(L, -1) == LUA_TUSERDATA) { uv_os_fd_t fd; uv_stream_t* stream = luv_check_stream(L, -1); int err = uv_fileno((uv_handle_t*)stream, &fd); if (err == UV_EINVAL || err == UV_EBADF) { options.stdio[i].flags = UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE; } else { options.stdio[i].flags = UV_INHERIT_STREAM; } options.stdio[i].data.stream = stream; } else if (lua_type(L, -1) == LUA_TNIL) { options.stdio[i].flags = UV_IGNORE; } else { luv_clean_options(&options); return luaL_argerror(L, 2, "stdio table entries must be nil, uv_stream_t, or integer"); } lua_pop(L, 1); } } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "stdio option must be table"); } lua_pop(L, 1); // Get the env lua_getfield(L, 2, "env"); if (lua_type(L, -1) == LUA_TTABLE) { len = lua_rawlen(L, -1); options.env = malloc((len + 1) * sizeof(*options.env)); if (!options.env) { luv_clean_options(&options); return luaL_error(L, "Problem allocating env"); } for (i = 0; i < len; ++i) { lua_rawgeti(L, -1, i + 1); options.env[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } options.env[len] = NULL; } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "env option must be table"); } lua_pop(L, 1); // Get the cwd lua_getfield(L, 2, "cwd"); if (lua_type(L, -1) == LUA_TSTRING) { options.cwd = (char*)lua_tostring(L, -1); } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "cwd option must be string"); } lua_pop(L, 1); // Check for uid lua_getfield(L, 2, "uid"); if (lua_type(L, -1) == LUA_TNUMBER) { options.uid = lua_tointeger(L, -1); options.flags |= UV_PROCESS_SETUID; } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "uid option must be number"); } lua_pop(L, 1); // Check for gid lua_getfield(L, 2, "gid"); if (lua_type(L, -1) == LUA_TNUMBER) { options.gid = lua_tointeger(L, -1); options.flags |= UV_PROCESS_SETGID; } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "gid option must be number"); } lua_pop(L, 1); // Check for the boolean flags lua_getfield(L, 2, "verbatim"); if (lua_toboolean(L, -1)) { options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS; } lua_pop(L, 1); lua_getfield(L, 2, "detached"); if (lua_toboolean(L, -1)) { options.flags |= UV_PROCESS_DETACHED; } lua_pop(L, 1); lua_getfield(L, 2, "hide"); if (lua_toboolean(L, -1)) { options.flags |= UV_PROCESS_WINDOWS_HIDE; } lua_pop(L, 1); handle = lua_newuserdata(L, sizeof(*handle)); handle->type = UV_PROCESS; handle->data = luv_setup_handle(L); if (!lua_isnoneornil(L, 3)) { luv_check_callback(L, handle->data, LUV_EXIT, 3); } ret = uv_spawn(luv_loop(L), handle, &options); luv_clean_options(&options); if (ret < 0) { /* The async callback is required here because luajit GC may reclaim the * luv handle before libuv is done closing it down. */ uv_close((uv_handle_t*)handle, luv_spawn_close_cb); return luv_error(L, ret); } lua_pushinteger(L, handle->pid); return 2; }
int job_start(char **argv, void *data, rstream_cb stdout_cb, rstream_cb stderr_cb, job_exit_cb job_exit_cb) { int i; Job *job; // Search for a free slot in the table for (i = 0; i < MAX_RUNNING_JOBS; i++) { if (table[i] == NULL) { break; } } if (i == MAX_RUNNING_JOBS) { // No free slots return 0; } job = xmalloc(sizeof(Job)); // Initialize job->id = i + 1; job->pending_refs = 3; job->pending_closes = 4; job->data = data; job->stdout_cb = stdout_cb; job->stderr_cb = stderr_cb; job->exit_cb = job_exit_cb; job->stopped = false; job->exit_timeout = EXIT_TIMEOUT; job->proc_opts.file = argv[0]; job->proc_opts.args = argv; job->proc_opts.stdio = job->stdio; job->proc_opts.stdio_count = 3; job->proc_opts.flags = UV_PROCESS_WINDOWS_HIDE; job->proc_opts.exit_cb = exit_cb; job->proc_opts.cwd = NULL; job->proc_opts.env = NULL; job->proc.data = NULL; job->proc_stdin.data = NULL; job->proc_stdout.data = NULL; job->proc_stderr.data = NULL; // Initialize the job std{in,out,err} uv_pipe_init(uv_default_loop(), &job->proc_stdin, 0); job->stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; job->stdio[0].data.stream = (uv_stream_t *)&job->proc_stdin; uv_pipe_init(uv_default_loop(), &job->proc_stdout, 0); job->stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; job->stdio[1].data.stream = (uv_stream_t *)&job->proc_stdout; uv_pipe_init(uv_default_loop(), &job->proc_stderr, 0); job->stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; job->stdio[2].data.stream = (uv_stream_t *)&job->proc_stderr; // Spawn the job if (uv_spawn(uv_default_loop(), &job->proc, &job->proc_opts) != 0) { free_job(job); return -1; } // Give all handles a reference to the job handle_set_job((uv_handle_t *)&job->proc, job); handle_set_job((uv_handle_t *)&job->proc_stdin, job); handle_set_job((uv_handle_t *)&job->proc_stdout, job); handle_set_job((uv_handle_t *)&job->proc_stderr, job); job->in = wstream_new(JOB_WRITE_MAXMEM); wstream_set_stream(job->in, (uv_stream_t *)&job->proc_stdin); // Start the readable streams job->out = rstream_new(read_cb, JOB_BUFFER_SIZE, job, true); job->err = rstream_new(read_cb, JOB_BUFFER_SIZE, job, true); rstream_set_stream(job->out, (uv_stream_t *)&job->proc_stdout); rstream_set_stream(job->err, (uv_stream_t *)&job->proc_stderr); rstream_start(job->out); rstream_start(job->err); // Save the job to the table table[i] = job; // Start polling job status if this is the first if (job_count == 0) { uv_prepare_start(&job_prepare, job_prepare_cb); } job_count++; return job->id; }
pid_t h2o_spawnp(const char *cmd, char *const *argv, const int *mapped_fds, int cloexec_mutex_is_locked) { #if defined(__linux__) /* posix_spawnp of Linux does not return error if the executable does not exist, see * https://gist.github.com/kazuho/0c233e6f86d27d6e4f09 */ extern char **environ; int pipefds[2] = {-1, -1}, errnum; pid_t pid; /* create pipe, used for sending error codes */ if (pipe2(pipefds, O_CLOEXEC) != 0) goto Error; /* fork */ if (!cloexec_mutex_is_locked) pthread_mutex_lock(&cloexec_mutex); if ((pid = fork()) == 0) { /* in child process, map the file descriptors and execute; return the errnum through pipe if exec failed */ if (mapped_fds != NULL) { for (; *mapped_fds != -1; mapped_fds += 2) { if (mapped_fds[1] != -1) dup2(mapped_fds[0], mapped_fds[1]); close(mapped_fds[0]); } } char **env = build_spawn_env(); if (env != NULL) environ = env; execvp(cmd, argv); errnum = errno; write(pipefds[1], &errnum, sizeof(errnum)); _exit(EX_SOFTWARE); } if (!cloexec_mutex_is_locked) pthread_mutex_unlock(&cloexec_mutex); if (pid == -1) goto Error; /* parent process */ close(pipefds[1]); pipefds[1] = -1; ssize_t rret; errnum = 0; while ((rret = read(pipefds[0], &errnum, sizeof(errnum))) == -1 && errno == EINTR) ; if (rret != 0) { /* spawn failed */ while (waitpid(pid, NULL, 0) != pid) ; pid = -1; errno = errnum; goto Error; } /* spawn succeeded */ close(pipefds[0]); return pid; Error: errnum = errno; if (pipefds[0] != -1) close(pipefds[0]); if (pipefds[1] != -1) close(pipefds[1]); errno = errnum; return -1; #elif defined _MSC_VER //-- : process : https://msdn.microsoft.com/en-us/library/20y988d2.aspx pid_t pid; extern char** environ; uv_loop_t *loop; uv_process_t child_req; uv_process_options_t options = { 0 }; //-- Default initialization must be 0 loop = uv_default_loop(); //-- Container for file descruptor uv_stdio_container_t child_stdio[3]; child_stdio[0].flags = UV_IGNORE; child_stdio[1].flags = UV_INHERIT_FD; //STD_OUT should be redirected to calling function child_stdio[2].flags = UV_IGNORE; if (mapped_fds != NULL) { for (; *mapped_fds != -1; mapped_fds += 2) { if (mapped_fds[1] != -1) //dup2(mapped_fds[0], mapped_fds[1]); //Equivalent to dup2() in *inx systems. child_stdio[1].data.fd = mapped_fds[0]; //2 or 1? //close(mapped_fds[0]); //add or delete a close or open action to a spawn file actions object } } if (!cloexec_mutex_is_locked) uv_mutex_lock(&cloexec_mutex); options.stdio = child_stdio; options.exit_cb = waitpid; //This function will be executed when child exists. options.file = cmd; options.args = argv; options.env = environ; //If the process is successfully spawned, this function will return 0. errno = uv_spawn(loop, &child_req, &options); pid = child_req.pid; if (!cloexec_mutex_is_locked) uv_mutex_unlock(&cloexec_mutex); if (errno != 0) return -1; return pid; #else posix_spawn_file_actions_t file_actions; pid_t pid; extern char **environ; char **env = build_spawn_env(); posix_spawn_file_actions_init(&file_actions); if (mapped_fds != NULL) { for (; *mapped_fds != -1; mapped_fds += 2) { if (mapped_fds[1] != -1) posix_spawn_file_actions_adddup2(&file_actions, mapped_fds[0], mapped_fds[1]); posix_spawn_file_actions_addclose(&file_actions, mapped_fds[0]); } } if (!cloexec_mutex_is_locked) pthread_mutex_lock(&cloexec_mutex); errno = posix_spawnp(&pid, cmd, &file_actions, NULL, argv, env != NULL ? env : environ); if (!cloexec_mutex_is_locked) pthread_mutex_unlock(&cloexec_mutex); free(env); if (errno != 0) return -1; return pid; #endif }
MVMint64 MVM_proc_shell(MVMThreadContext *tc, MVMString *cmd, MVMString *cwd, MVMObject *env, MVMObject *in, MVMObject *out, MVMObject *err, MVMint64 flags) { MVMint64 result = 0, spawn_result; uv_process_t *process = MVM_calloc(1, sizeof(uv_process_t)); uv_process_options_t process_options = {0}; uv_stdio_container_t process_stdio[3]; int i; char * const cmdin = MVM_string_utf8_c8_encode_C_string(tc, cmd); char * const _cwd = MVM_string_utf8_c8_encode_C_string(tc, cwd); const MVMuint64 size = MVM_repr_elems(tc, env); MVMIter * const iter = (MVMIter *)MVM_iter(tc, env); char **_env = MVM_malloc((size + 1) * sizeof(char *)); #ifdef _WIN32 const MVMuint16 acp = GetACP(); /* We should get ACP at runtime. */ char * const _cmd = ANSIToUTF8(acp, getenv("ComSpec")); char *args[3]; args[0] = "/c"; args[1] = cmdin; args[2] = NULL; #else char * const _cmd = "/bin/sh"; char *args[4]; args[0] = "/bin/sh"; args[1] = "-c"; args[2] = cmdin; args[3] = NULL; #endif INIT_ENV(); setup_process_stdio(tc, in, process, &process_stdio[0], 0, flags, "shell"); setup_process_stdio(tc, out, process, &process_stdio[1], 1, flags >> 3, "shell"); setup_process_stdio(tc, err, process, &process_stdio[2], 2, flags >> 6, "shell"); process_options.stdio = process_stdio; process_options.file = _cmd; process_options.args = args; process_options.cwd = _cwd; process_options.flags = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS | UV_PROCESS_WINDOWS_HIDE; process_options.env = _env; process_options.stdio_count = 3; process_options.exit_cb = spawn_on_exit; if (flags & (MVM_PIPE_CAPTURE_IN | MVM_PIPE_CAPTURE_OUT | MVM_PIPE_CAPTURE_ERR)) { process->data = MVM_calloc(1, sizeof(MVMint64)); uv_ref((uv_handle_t *)process); spawn_result = uv_spawn(tc->loop, process, &process_options); if (spawn_result) result = spawn_result; } else { process->data = &result; uv_ref((uv_handle_t *)process); spawn_result = uv_spawn(tc->loop, process, &process_options); if (spawn_result) result = spawn_result; else uv_run(tc->loop, UV_RUN_DEFAULT); } FREE_ENV(); MVM_free(_cwd); #ifdef _WIN32 MVM_free(_cmd); #endif MVM_free(cmdin); uv_unref((uv_handle_t *)process); return result; }
static int LuaIO_process_fork(lua_State* L) { if (lua_type(L, 1) != LUA_TTABLE) { return luaL_argerror(L, 1, "process.fork(options) error: options must be [table]\n"); } if (!LuaIO_process_exepath_ptr) { size_t length = sizeof(LuaIO_process_exepath); int err = uv_exepath(LuaIO_process_exepath, &length); if (err < 0) { return luaL_error(L, "process.fork(options) uv_exepath() error: %s\n", uv_strerror(err)); } LuaIO_process_exepath_ptr = LuaIO_process_exepath; } lua_getfield(L, 1, "file"); const char* file; if (lua_type(L, -1) == LUA_TSTRING) { file = lua_tostring(L, -1); } else { return luaL_argerror(L, 2, "process.fork(options) error: options.file is required and must be [string]\n"); } lua_pop(L, 1); lua_getfield(L, 1, "args"); size_t args_length = 0; char** args = NULL; if (lua_type(L, -1) == LUA_TTABLE) { args_length = lua_rawlen(L, -1); /*execpath, file, null => args_length + 3*/ args = LuaIO_malloc(sizeof(char*) * (args_length + 3)); if (!args) { return luaL_error(L, "process.fork(options) error: no memory for args\n"); } for (size_t i = 1; i <= args_length; ++i) { lua_rawgeti(L, -1, i); args[i + 1] = (char*)luaL_checkstring(L, -1); lua_pop(L, 1); } } else if (lua_type(L, -1) == LUA_TNIL) { /*execpath, file, null => args_length + 3*/ args = LuaIO_malloc(sizeof(char*) * 3); if (!args) { return luaL_error(L, "process.fork(options) error: no memory for args\n"); } } else { return luaL_argerror(L, 2, "process.fork(options) error: options.args must be [table]\n"); } lua_pop(L, 1); args[0] = LuaIO_process_exepath_ptr; args[1] = (char*)file; args[args_length + 2] = NULL; if (!LuaIO_process_stdio_ptr) { LuaIO_process_stdio[0].flags = UV_INHERIT_FD; LuaIO_process_stdio[0].data.fd = 0; LuaIO_process_stdio[1].flags = UV_INHERIT_FD; LuaIO_process_stdio[1].data.fd = 1; LuaIO_process_stdio[2].flags = UV_INHERIT_FD; LuaIO_process_stdio[2].data.fd = 2; LuaIO_process_stdio_ptr = LuaIO_process_stdio; } uv_process_options_t* options = LuaIO_malloc(sizeof(uv_process_options_t)); if (!options) { LuaIO_free(args); return luaL_error(L, "process.fork(options) error: no memory for uv_process_options_t options\n"); } LuaIO_memzero(options, sizeof(uv_process_options_t)); options->exit_cb = LuaIO_process_onexit; options->file = LuaIO_process_exepath_ptr; options->args = args; options->stdio_count = 3; options->stdio = LuaIO_process_stdio_ptr; lua_getfield(L, 1, "uid"); if (lua_type(L, -1) == LUA_TNUMBER) { options->uid = lua_tointeger(L, -1); options->flags |= UV_PROCESS_SETUID; } else if (lua_type(L, -1) != LUA_TNIL) { LuaIO_process_free_options(options); return luaL_argerror(L, 2, "process.fork(options) error: options.uid must be [number]\n"); } lua_pop(L, 1); lua_getfield(L, 1, "gid"); if (lua_type(L, -1) == LUA_TNUMBER) { options->gid = lua_tointeger(L, -1); options->flags |= UV_PROCESS_SETGID; } else if (lua_type(L, -1) != LUA_TNIL) { LuaIO_process_free_options(options); return luaL_argerror(L, 2, "process.fork(options) error: options.gid must be [number]\n"); } lua_pop(L, 1); lua_getfield(L, 1, "detached"); if (lua_toboolean(L, -1)) { options->flags |= UV_PROCESS_DETACHED; } lua_pop(L, 1); lua_getfield(L, 1, "forever"); int forever = lua_toboolean(L, -1); lua_pop(L, 1); int cpu = -1; lua_getfield(L, 1, "cpu"); if (lua_type(L, -1) == LUA_TNUMBER) { cpu = lua_tointeger(L, -1); } else if (lua_type(L, -1) != LUA_TNIL) { LuaIO_process_free_options(options); return luaL_argerror(L, 2, "process.fork(options) error: options.cpu must be [number]\n"); } lua_pop(L, 1); uv_process_t* handle = LuaIO_malloc(sizeof(uv_process_t)); if (!handle) { LuaIO_process_free_options(options); return luaL_error(L, "process.fork(options) error: no memory for uv_process_t handle.\n"); } LuaIO_memzero(handle, sizeof(uv_process_t)); LuaIO_process_data_t* data = NULL; if (forever) { data = LuaIO_malloc(sizeof(LuaIO_process_data_t)); if (!data) { LuaIO_process_free_options(options); return luaL_error(L, "process.fork(options) error:no memory for LuaIO_process_data_t data.\n"); } lua_pushvalue(L, 1); data->options_ref = luaL_ref(L, LUA_REGISTRYINDEX); data->options = options; data->cpu = cpu; handle->data = data; } int ret = uv_spawn(uv_default_loop(), handle, options); if (ret < 0) { LuaIO_process_free_options(options); luaL_unref(L, LUA_REGISTRYINDEX, data->options_ref); LuaIO_free(data); uv_close((uv_handle_t*)handle, NULL); return luaL_error(L, "process.fork(options) uv_spawn() error: %s\n", uv_strerror(ret)); } if (cpu >= 0) LuaIO_set_affinity(handle->pid, cpu); if (!LuaIO_process_signal_ptr) { uv_signal_init(uv_default_loop(), &LuaIO_process_signal); LuaIO_process_signal_ptr = &LuaIO_process_signal; uv_signal_start(LuaIO_process_signal_ptr, LuaIO_process_signal_callback, SIGQUIT); } lua_pushinteger(L, handle->pid); return 1; }
static int luv_new_process(lua_State* L) { const char* cmd = luaL_checkstring(L, 1); size_t argc; char** args; int i; char* cwd; char** env; uv_process_options_t opts; int rv; luaL_checktype(L, 2, LUA_TTABLE); /* options */ memset(&opts, 0, sizeof(uv_process_options_t)); argc = lua_objlen(L, 2); args = (char**)malloc((argc + 1) * sizeof(char*)); args[0] = (char*)cmd; for (i = 1; i <= argc; i++) { lua_rawgeti(L, -1, i); args[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } args[argc + 1] = NULL; cwd = NULL; lua_getfield(L, 2, "cwd"); if (!lua_isnil(L, -1)) { cwd = (char*)lua_tostring(L, -1); } lua_pop(L, 1); env = NULL; lua_getfield(L, 2, "env"); if (!lua_isnil(L, -1)) { int i, len; const char* key; const char* val; len = 32; env = (char**)malloc(32 * sizeof(char*)); lua_pushnil(L); i = 0; while (lua_next(L, -2) != 0) { if (i >= len) { len *= 2; env = (char**)realloc(env, len * sizeof(char*)); } key = lua_tostring(L, -2); val = lua_tostring(L, -1); lua_pushfstring(L, "%s=%s", key, val); env[i++] = (char*)lua_tostring(L, -1); lua_pop(L, 2); } env[i] = NULL; } lua_pop(L, 1); opts.exit_cb = _exit_cb; opts.file = cmd; opts.args = args; opts.env = env; opts.cwd = cwd; uv_stdio_container_t stdio[3]; opts.stdio_count = 3; const char* stdfh_names[] = { "stdin", "stdout", "stderr" }; for (i = 0; i < 3; i++) { lua_getfield(L, 2, stdfh_names[i]); if (lua_isnil(L, -1)) { stdio[i].flags = UV_IGNORE; } else { luv_object_t* obj = (luv_object_t*)luaL_checkudata(L, -1, LUV_PIPE_T); stdio[i].flags = UV_INHERIT_STREAM; stdio[i].data.stream = &obj->h.stream; } lua_pop(L, 1); } opts.stdio = stdio; lua_getfield(L, 2, "detach"); if (lua_toboolean(L, -1)) { opts.flags |= UV_PROCESS_DETACHED; } else { opts.flags = 0; } lua_pop(L, 1); luv_state_t* curr = luvL_state_self(L); luv_object_t* self = (luv_object_t*)lua_newuserdata(L, sizeof(luv_object_t)); luaL_getmetatable(L, LUV_PROCESS_T); lua_setmetatable(L, -2); luvL_object_init(curr, self); lua_insert(L, 1); lua_settop(L, 1); rv = uv_spawn(luvL_event_loop(L), &self->h.process, opts); free(args); if (env) free(env); if (rv) { uv_err_t err = uv_last_error(luvL_event_loop(L)); return luaL_error(L, uv_strerror(err)); } if (opts.flags & UV_PROCESS_DETACHED) { uv_unref((uv_handle_t*)&self->h.process); return 1; } else { return luvL_cond_wait(&self->rouse, curr); } }
int ftw_libuv_spawn_process(struct ftw_libuv_callsite **callsite, LVUserEventRef *lv_event, char *exe, char *cmd, int64_t *exit_code, int64_t *signal) { int rc; char *args [3]; uv_loop_t loop; uv_pipe_t stdout_pipe; uv_pipe_t stderr_pipe; uv_process_t new_process; uv_process_options_t opts = {0}; uv_stdio_container_t iostreams [3]; struct ftw_libuv_process proc_data = {0}; struct ftw_libuv_stream context; /* Preconditions expected of LabVIEW. */ ftw_assert(callsite && *callsite && lv_event && cmd); rc = uv_loop_init(&loop); if (rc) { return rc; } args[0] = exe; args[1] = cmd; args[2] = NULL; proc_data.exit_code = exit_code; proc_data.signal = signal; new_process.data = &proc_data; context.msg_to_lv_event = lv_event; stdout_pipe.data = &context; stderr_pipe.data = &context; rc = uv_pipe_init(&loop, &stdout_pipe, 0); if (rc) { uv_loop_close(&loop); return rc; } rc = uv_pipe_init(&loop, &stderr_pipe, 0); if (rc) { uv_loop_close(&loop); return rc; } opts.stdio_count = 3; opts.stdio = iostreams; opts.stdio[0].flags = UV_IGNORE; opts.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; opts.stdio[1].data.stream = (uv_stream_t *) &stdout_pipe; opts.stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; opts.stdio[2].data.stream = (uv_stream_t *) &stderr_pipe; //opts.stdio[2].flags = UV_IGNORE; opts.file = exe; opts.args = args; opts.exit_cb = ftw_libuv_callback_process_exit; rc = uv_spawn(&loop, &new_process, &opts); if (rc) { uv_loop_close(&loop); return rc; } rc = uv_read_start((uv_stream_t*) &stdout_pipe, ftw_libuv_callback_alloc, ftw_libuv_callback_read_pipe); if (rc) { uv_loop_close(&loop); return rc; } rc = uv_read_start((uv_stream_t*) &stderr_pipe, ftw_libuv_callback_alloc, ftw_libuv_callback_read_pipe); if (rc) { uv_loop_close(&loop); return rc; } rc = uv_run(&loop, UV_RUN_DEFAULT); if (rc) { uv_loop_close(&loop); return rc; } rc = uv_loop_close(&loop); return rc; }
static void launch_vice_with_config(PluginData* data) { int r, cmdIndex = 1; uv_process_options_t options = { 0 }; log_debug("spawning vice...\n", ""); char* args[10]; args[0] = (char*)data->config.vice_exe; // TODO: Must generate the breakpoint file from the json one args[cmdIndex++] = "-remotemonitor"; if (data->config.breakpoint_file) { //args[cmdIndex++] = "-moncommands"; //args[cmdIndex++] = "examples/c64_vice/test_mon.txt"; } //args[cmdIndex++] = (char*)data->config.prg_file; args[cmdIndex++] = NULL; options.exit_cb = 0; options.file = data->config.vice_exe; options.args = args; if ((r = uv_spawn(uv_default_loop(), &data->process, &options))) { MESSAGE_FUNCS->error("Unable to launch VICE", uv_strerror(r)); return; } sleepMs(3000); connect_to_local_host(data); // if connected we load the image and make sure we get a reply back if (VICEConnection_isConnected(data->conn)) { log_debug("connected to vice...\n", ""); if (!load_image(data, data->config.prg_file)) { return; } log_debug("image loaded ...\n", ""); // parse the parse_mon_file(data, data->config.breakpoint_file); log_debug("start from basic...\n", ""); // start vice! log_debug("started from basic\n", ""); uint16_t address = 0; //get_basic_start(data); parse_mon_file(data, data->config.breakpoint_file); if (address != 0) { log_debug("start from %x\n", address); send_command(data, "g %x\n", address); } return; } log_debug("unable to make connection with vice\n", ""); }
static PyObject * Process_func_spawn(Process *self, PyObject *args, PyObject *kwargs) { int err, flags, len, stdio_count; unsigned int uid, gid; char *cwd, *cwd2, *file, *file2, *arg_str, *tmp_str, *key_str, *value_str; char **ptr, **process_args, **process_env; Py_ssize_t i, n, pos; PyObject *key, *value, *item, *tmp, *callback, *arguments, *env, *stdio, *ret; uv_process_options_t options; uv_stdio_container_t *stdio_container; static char *kwlist[] = {"file", "exit_callback", "args", "env", "cwd", "uid", "gid", "flags", "stdio", NULL}; cwd = NULL; ptr = process_args = process_env = NULL; tmp = arguments = env = stdio = NULL; stdio_container = NULL; flags = uid = gid = stdio_count = 0; RAISE_IF_SPAWNED(self, NULL); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|OOO!sIIiO:__init__", kwlist, &file, &callback, &arguments, &PyDict_Type, &env, &cwd, &uid, &gid, &flags, &stdio)) { return NULL; } if (callback != Py_None && !PyCallable_Check(callback)) { PyErr_SetString(PyExc_TypeError, "a callable is required"); return NULL; } if (arguments && !PySequence_Check(arguments)) { PyErr_SetString(PyExc_TypeError, "only iterable objects are supported for 'args'"); return NULL; } if (stdio && !PySequence_Check(stdio)) { PyErr_SetString(PyExc_TypeError, "only iterable objects are supported for 'stdio'"); return NULL; } memset(&options, 0, sizeof(uv_process_options_t)); options.uid = uid; options.gid = gid; options.flags = flags; options.exit_cb = on_process_exit; file2 = PyMem_Malloc(strlen(file) + 1); if (!file2) { PyErr_NoMemory(); ret = NULL; goto cleanup; } strcpy(file2, file); options.file = file2; if (arguments) { n = PySequence_Length(arguments); process_args = PyMem_Malloc(sizeof *process_args * (n + 2)); if (!process_args) { PyErr_NoMemory(); PyMem_Free(file2); ret = NULL; goto cleanup; } process_args[0] = file2; i = 0; while (i < n) { item = PySequence_GetItem(arguments, i); if (!item || !PyArg_Parse(item, "s;args contains a non-string value", &arg_str)) { Py_XDECREF(item); ret = NULL; goto cleanup; } tmp_str = PyMem_Malloc(strlen(arg_str) + 1); if (!tmp_str) { Py_DECREF(item); ret = NULL; goto cleanup; } strcpy(tmp_str, arg_str); process_args[i+1] = tmp_str; Py_DECREF(item); i++; } process_args[i+1] = NULL; } else { process_args = PyMem_Malloc(sizeof *process_args * 2); if (!process_args) { PyErr_NoMemory(); PyMem_Free(file2); ret = NULL; goto cleanup; } process_args[0] = file2; process_args[1] = NULL; } options.args = process_args; if (cwd) { cwd2 = PyMem_Malloc(strlen(cwd) + 1); if (!cwd2) { PyErr_NoMemory(); ret = NULL; goto cleanup; } strcpy(cwd2, cwd); options.cwd = cwd2; } if (env) { n = PyDict_Size(env); if (n > 0) { process_env = PyMem_Malloc(sizeof *process_env * (n + 1)); if (!process_env) { PyErr_NoMemory(); ret = NULL; goto cleanup; } i = 0; pos = 0; while (PyDict_Next(env, &pos, &key, &value)) { if (!PyArg_Parse(key, "s;env contains a non-string key", &key_str) || !PyArg_Parse(value, "s;env contains a non-string value", &value_str)) { ret = NULL; goto cleanup; } len = strlen(key_str) + strlen(value_str) + 2; tmp_str = PyMem_Malloc(len); if (!tmp_str) { PyErr_NoMemory(); ret = NULL; goto cleanup; } PyOS_snprintf(tmp_str, len, "%s=%s", key_str, value_str); process_env[i] = tmp_str; i++; } process_env[i] = NULL; } } options.env = process_env; if (stdio) { n = PySequence_Length(stdio); stdio_container = PyMem_Malloc(sizeof *stdio_container * n); if (!stdio_container) { PyErr_NoMemory(); ret = NULL; goto cleanup; } item = NULL; for (i = 0;i < n; i++) { item = PySequence_GetItem(stdio, i); if (!item || !PyObject_TypeCheck(item, &StdIOType)) { Py_XDECREF(item); PyErr_SetString(PyExc_TypeError, "a StdIO instance is required"); ret = NULL; goto cleanup; } stdio_count++; stdio_container[i].flags = ((StdIO *)item)->flags; if (((StdIO *)item)->flags & (UV_CREATE_PIPE | UV_INHERIT_STREAM)) { stdio_container[i].data.stream = (uv_stream_t *)(UV_HANDLE(((StdIO *)item)->stream)); } else if (((StdIO *)item)->flags & UV_INHERIT_FD) { stdio_container[i].data.fd = ((StdIO *)item)->fd; } Py_DECREF(item); } } options.stdio = stdio_container; options.stdio_count = stdio_count; err = uv_spawn(UV_HANDLE_LOOP(self), &self->process_h, &options); if (err < 0) { RAISE_UV_EXCEPTION(err, PyExc_ProcessError); ret = NULL; goto cleanup; } tmp = (PyObject *)self->on_exit_cb; Py_INCREF(callback); self->on_exit_cb = callback; Py_XDECREF(tmp); tmp = self->stdio; Py_XINCREF(stdio); self->stdio = stdio; Py_XDECREF(tmp); HANDLE(self)->initialized = True; self->spawned = True; ret = Py_None; /* Increase refcount so that object is not removed before the exit callback is called */ Py_INCREF(self); cleanup: if (options.args) { for (ptr = options.args; *ptr != NULL; ptr++) { PyMem_Free(*ptr); } } if (options.env) { for (ptr = options.env; *ptr != NULL; ptr++) { PyMem_Free(*ptr); } } PyMem_Free(options.args); PyMem_Free(options.cwd); PyMem_Free(options.env); PyMem_Free(options.stdio); Py_XINCREF(ret); return ret; }
extern "C" int rust_uv_spawn(uv_loop_t *loop, uv_process_t *p, uv_process_options_t options) { return uv_spawn(loop, p, options); }