From 149d32cb96592fc5037c7072e1a3ab9a3fa888a6 Mon Sep 17 00:00:00 2001 From: Charlie McConnell Date: Thu, 23 Feb 2012 13:07:11 -0800 Subject: [PATCH] unix: Implement options.detached for uv_spawn() for unix. --- src/unix/core.c | 1 - src/unix/process.c | 75 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 93345a3bb..e91602ca8 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -239,7 +239,6 @@ void uv__finish_close(uv_handle_t* handle) { uv_loop_t* loop = handle->loop; assert(handle->flags & UV_CLOSING); - assert(!(handle->flags & UV_CLOSED)); handle->flags |= UV_CLOSED; switch (handle->type) { diff --git a/src/unix/process.c b/src/unix/process.c index becf60fe3..e648779af 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -25,6 +25,7 @@ #include #include #include +#include #include /* O_CLOEXEC, O_NONBLOCK */ #include #include @@ -37,6 +38,11 @@ extern char **environ; #endif +#ifndef MAP_ANONYMOUS +#ifdef MAP_ANON +#define MAP_ANONYMOUS MAP_ANON +#endif +#endif static void uv__chld(EV_P_ ev_child* watcher, int revents) { int status = watcher->rstatus; @@ -153,6 +159,9 @@ static int uv__process_init_pipe(uv_pipe_t* handle, int fds[2], int flags) { return uv__make_pipe(fds, flags); } +void _detach_cb() { + /* TODO: Does something need to happen here? */ +} #ifndef SPAWN_WAIT_EXEC # define SPAWN_WAIT_EXEC 1 @@ -175,26 +184,44 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, int status; pid_t pid; int flags; + int *pid_map; uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); loop->counters.process_init++; process->exit_cb = options.exit_cb; - if (options.stdin_stream && - uv__process_init_pipe(options.stdin_stream, stdin_pipe, 0)) { - goto error; + if (options.detached) { + pid_map = mmap(0, sizeof(pid_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (pid_map == MAP_FAILED) { + goto error; + } + if (options.stdin_stream) { + uv_close((uv_handle_t*)options.stdin_stream, _detach_cb); + } + if (options.stdout_stream) { + uv_close((uv_handle_t*)options.stdout_stream, _detach_cb); + } + if (options.stderr_stream) { + uv_close((uv_handle_t*)options.stderr_stream, _detach_cb); + } + } else { + if (options.stdin_stream && + uv__process_init_pipe(options.stdin_stream, stdin_pipe, 0)) { + goto error; + } + + if (options.stdout_stream && + uv__process_init_pipe(options.stdout_stream, stdout_pipe, 0)) { + goto error; + } + + if (options.stderr_stream && + uv__process_init_pipe(options.stderr_stream, stderr_pipe, 0)) { + goto error; + } } - if (options.stdout_stream && - uv__process_init_pipe(options.stdout_stream, stdout_pipe, 0)) { - goto error; - } - - if (options.stderr_stream && - uv__process_init_pipe(options.stderr_stream, stderr_pipe, 0)) { - goto error; - } /* This pipe is used by the parent to wait until * the child has called `execve()`. We need this @@ -260,6 +287,21 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, uv__nonblock(STDERR_FILENO, 0); } + if (options.detached) { + setsid(); + umask(027); + pid = fork(); + if (pid < 0) { + perror("Second fork()"); + _exit(errno); + } else if (pid > 0) { + /* First child saves the pid of the second child and exits. */ + pid_map[0] = pid; + exit(0); + } + /* Second child continues below */ + } + if (options.cwd && chdir(options.cwd)) { perror("chdir()"); _exit(127); @@ -293,7 +335,14 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, uv__close(signal_pipe[0]); #endif - process->pid = pid; + if (options.detached) { + process->pid = pid_map[0]; + if (munmap(pid_map, sizeof(pid_t)) != 0) { + goto error; + } + } else { + process->pid = pid; + } ev_child_init(&process->child_watcher, uv__chld, pid, 0); ev_child_start(process->loop->ev, &process->child_watcher);