Detaching doesn't work yet, the setsid() call fails and leaves the child process
attached to the parent's session.

Revert "test: Add test case for spawning detached child processes."
Revert "win: Implement options.detached for uv_spawn() for Windows."
Revert "unix: Implement options.detached for uv_spawn() for unix."
Revert "Add "detached" member to uv_process_options_t to denote whether a child
        process should spawn detached from its parent."

This reverts commit ea9baef95c.
This reverts commit e99fdf0df6.
This reverts commit 149d32cb96.
This reverts commit b3e0ad4db8.
This commit is contained in:
Ben Noordhuis 2012-02-28 15:22:44 +01:00
parent 57c5fa1af1
commit ec0eff955e
6 changed files with 31 additions and 152 deletions

View File

@ -1063,12 +1063,6 @@ typedef struct uv_process_options_s {
*/
char* cwd;
/*
* If set, this flag indicates that the child should be spawned in a detached
* state.
*/
int detached;
/*
* TODO describe how this works.
*/

View File

@ -239,6 +239,7 @@ 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) {

View File

@ -25,7 +25,6 @@
#include <assert.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fcntl.h> /* O_CLOEXEC, O_NONBLOCK */
#include <poll.h>
#include <unistd.h>
@ -42,11 +41,6 @@
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;
@ -163,9 +157,6 @@ 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
@ -188,44 +179,26 @@ 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.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.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;
}
/* This pipe is used by the parent to wait until
* the child has called `execve()`. We need this
@ -291,21 +264,6 @@ 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);
@ -339,14 +297,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
uv__close(signal_pipe[0]);
#endif
if (options.detached) {
process->pid = pid_map[0];
if (munmap(pid_map, sizeof(pid_t)) != 0) {
goto error;
}
} else {
process->pid = pid;
}
process->pid = pid;
ev_child_init(&process->child_watcher, uv__chld, pid, 0);
ev_child_start(process->loop->ev, &process->child_watcher);

View File

@ -859,9 +859,6 @@ static int duplicate_std_handle(uv_loop_t* loop, DWORD id, HANDLE* dup) {
return 0;
}
void _detach_cb(uv_handle_t *handle) {
/* TODO: something here? */
}
int uv_spawn(uv_loop_t* loop, uv_process_t* process,
uv_process_options_t options) {
@ -874,7 +871,6 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
HANDLE* child_stdio = process->child_stdio;
STARTUPINFOW startup;
PROCESS_INFORMATION info;
DWORD process_flags;
if (!options.file) {
uv__set_artificial_error(loop, UV_EINVAL);
@ -906,25 +902,6 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
}
}
if (options.detached) {
if (options.stdin_stream) {
uv_close((uv_handle_t*)options.stdin_stream, _detach_cb);
options.stdin_stream = NULL;
}
if (options.stdout_stream) {
uv_close((uv_handle_t*)options.stdout_stream, _detach_cb);
options.stdout_stream = NULL;
}
if (options.stderr_stream) {
uv_close((uv_handle_t*)options.stderr_stream, _detach_cb);
options.stderr_stream = NULL;
}
process_flags = CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW |
CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS;
} else {
process_flags = CREATE_UNICODE_ENVIRONMENT;
}
/* Get PATH env. variable. */
size = GetEnvironmentVariableW(L"PATH", NULL, 0) + 1;
path = (wchar_t*)malloc(size * sizeof(wchar_t));
@ -963,7 +940,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
GENERIC_READ | FILE_WRITE_ATTRIBUTES,
0);
}
} else if (!options.detached) {
} else {
err = duplicate_std_handle(loop, STD_INPUT_HANDLE, &child_stdio[0]);
}
if (err) {
@ -977,7 +954,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
PIPE_ACCESS_INBOUND,
GENERIC_WRITE,
0);
} else if (!options.detached) {
} else {
err = duplicate_std_handle(loop, STD_OUTPUT_HANDLE, &child_stdio[1]);
}
if (err) {
@ -992,7 +969,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
PIPE_ACCESS_INBOUND,
GENERIC_WRITE,
0);
} else if (!options.detached) {
} else {
err = duplicate_std_handle(loop, STD_ERROR_HANDLE, &child_stdio[2]);
}
if (err) {
@ -1003,23 +980,19 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
startup.lpReserved = NULL;
startup.lpDesktop = NULL;
startup.lpTitle = NULL;
if (options.detached) {
startup.dwFlags = NULL;
} else {
startup.dwFlags = STARTF_USESTDHANDLES;
}
startup.dwFlags = STARTF_USESTDHANDLES;
startup.cbReserved2 = 0;
startup.lpReserved2 = NULL;
startup.hStdInput = options.detached ? NULL : child_stdio[0];
startup.hStdOutput = options.detached ? NULL : child_stdio[1];
startup.hStdError = options.detached ? NULL : child_stdio[2];
startup.hStdInput = child_stdio[0];
startup.hStdOutput = child_stdio[1];
startup.hStdError = child_stdio[2];
if (CreateProcessW(application_path,
arguments,
NULL,
NULL,
options.detached ? 0 : 1,
process_flags,
1,
CREATE_UNICODE_ENVIRONMENT,
env,
cwd,
&startup,
@ -1033,20 +1006,16 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
options.stdin_stream->ipc_pid = info.dwProcessId;
}
if (!options.detached) {
result = RegisterWaitForSingleObject(&process->wait_handle,
process->process_handle, exit_wait_callback, (void*)process, INFINITE,
WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
if (!result) {
uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
}
}
CloseHandle(info.hThread);
if (options.detached) {
CloseHandle(info.hProcess);
exit_wait_callback((void*)process, FALSE);
/* Setup notifications for when the child process exits. */
result = RegisterWaitForSingleObject(&process->wait_handle,
process->process_handle, exit_wait_callback, (void*)process, INFINITE,
WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
if (!result) {
uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
}
CloseHandle(info.hThread);
} else {
/* CreateProcessW failed, but this failure should be delivered */
/* asynchronously to retain unix compatibility. So pretend spawn */

View File

@ -104,7 +104,6 @@ TEST_DECLARE (spawn_exit_code)
TEST_DECLARE (spawn_stdout)
TEST_DECLARE (spawn_stdin)
TEST_DECLARE (spawn_and_kill)
TEST_DECLARE (spawn_detached)
TEST_DECLARE (spawn_and_kill_with_std)
TEST_DECLARE (spawn_and_ping)
TEST_DECLARE (kill)
@ -280,7 +279,6 @@ TASK_LIST_START
TEST_ENTRY (spawn_stdout)
TEST_ENTRY (spawn_stdin)
TEST_ENTRY (spawn_and_kill)
TEST_ENTRY (spawn_detached)
TEST_ENTRY (spawn_and_kill_with_std)
TEST_ENTRY (spawn_and_ping)
TEST_ENTRY (kill)

View File

@ -77,22 +77,6 @@ static void kill_cb(uv_process_t* process, int exit_status, int term_signal) {
ASSERT(err.code == UV_ESRCH);
}
static void detach_cb(uv_process_t* process, int exit_status, int term_signal) {
uv_err_t err;
printf("detach_cb\n");
exit_cb_called++;
ASSERT(exit_status == 0);
uv_close((uv_handle_t*)process, close_cb);
/*
* Unlike other tests, this one needs to make sure the process *is*
* still alive.
*/
err = uv_kill(process->pid, 0);
ASSERT(err.code == 0);
err = uv_kill(process->pid, 15);
ASSERT(err.code == 0);
}
static uv_buf_t on_alloc(uv_handle_t* handle, size_t suggested_size) {
uv_buf_t buf;
@ -246,24 +230,6 @@ TEST_IMPL(spawn_and_kill) {
return 0;
}
TEST_IMPL(spawn_detached) {
int r;
init_process_options("spawn_helper4", detach_cb);
options.detached = 1;
r = uv_spawn(uv_default_loop(), &process, options);
ASSERT(r == 0);
r = uv_run(uv_default_loop());
ASSERT(r == 0);
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 1);
return 0;
}
TEST_IMPL(spawn_and_kill_with_std) {
int r;