ext/libuv/src/unix/process.c in libuv-0.10.2 vs ext/libuv/src/unix/process.c in libuv-0.10.3
- old
+ new
@@ -45,70 +45,77 @@
assert(pid > 0);
return loop->process_handles + pid % ARRAY_SIZE(loop->process_handles);
}
-static uv_process_t* uv__process_find(uv_loop_t* loop, int pid) {
- uv_process_t* handle;
- QUEUE* h;
- QUEUE* q;
-
- h = uv__process_queue(loop, pid);
-
- QUEUE_FOREACH(q, h) {
- handle = QUEUE_DATA(q, uv_process_t, queue);
- if (handle->pid == pid) return handle;
- }
-
- return NULL;
-}
-
-
static void uv__chld(uv_signal_t* handle, int signum) {
uv_process_t* process;
+ uv_loop_t* loop;
int exit_status;
int term_signal;
+ unsigned int i;
int status;
pid_t pid;
+ QUEUE pending;
+ QUEUE* h;
+ QUEUE* q;
assert(signum == SIGCHLD);
- for (;;) {
- pid = waitpid(-1, &status, WNOHANG);
+ QUEUE_INIT(&pending);
+ loop = handle->loop;
- if (pid == 0)
- return;
+ for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++) {
+ h = loop->process_handles + i;
+ q = QUEUE_HEAD(h);
- if (pid == -1) {
- if (errno == ECHILD)
- return; /* XXX stop signal watcher? */
- else
- abort();
- }
+ while (q != h) {
+ process = QUEUE_DATA(q, uv_process_t, queue);
+ q = QUEUE_NEXT(q);
- process = uv__process_find(handle->loop, pid);
- if (process == NULL)
- continue; /* XXX bug? abort? */
+ do
+ pid = waitpid(process->pid, &status, WNOHANG);
+ while (pid == -1 && errno == EINTR);
- uv__handle_stop(process);
+ if (pid == 0)
+ continue;
- if (process->exit_cb == NULL)
- continue;
+ if (pid == -1) {
+ if (errno != ECHILD)
+ abort();
+ continue;
+ }
- exit_status = 0;
- term_signal = 0;
+ process->status = status;
+ QUEUE_REMOVE(&process->queue);
+ QUEUE_INSERT_TAIL(&pending, &process->queue);
+ }
- if (WIFEXITED(status))
- exit_status = WEXITSTATUS(status);
+ while (!QUEUE_EMPTY(&pending)) {
+ q = QUEUE_HEAD(&pending);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
- if (WIFSIGNALED(status))
- term_signal = WTERMSIG(status);
+ process = QUEUE_DATA(q, uv_process_t, queue);
+ uv__handle_stop(process);
- if (process->errorno)
- exit_status = process->errorno; /* execve() failed */
+ if (process->exit_cb == NULL)
+ continue;
- process->exit_cb(process, exit_status, term_signal);
+ exit_status = 0;
+ if (WIFEXITED(process->status))
+ exit_status = WEXITSTATUS(process->status);
+
+ term_signal = 0;
+ if (WIFSIGNALED(process->status))
+ term_signal = WTERMSIG(process->status);
+
+ if (process->errorno != 0)
+ exit_status = process->errorno; /* execve() failed */
+
+ process->exit_cb(process, exit_status, term_signal);
+ }
}
}
int uv__make_socketpair(int fds[2], int flags) {
@@ -180,11 +187,11 @@
}
/*
* Used for initializing stdio streams like options.stdin_stream. Returns
- * zero on success.
+ * zero on success. See also the cleanup section in uv_spawn().
*/
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
int mask;
int fd;
@@ -227,11 +234,11 @@
int flags;
if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0)
return 0;
- if (close(pipefds[1]))
+ if (uv__close(pipefds[1]))
if (errno != EINTR && errno != EINPROGRESS)
abort();
pipefds[1] = -1;
uv__nonblock(pipefds[0], 1);
@@ -266,27 +273,29 @@
assert(n == sizeof(val));
}
-static void uv__process_child_init(uv_process_options_t options,
+static void uv__process_child_init(const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
int error_fd) {
int close_fd;
int use_fd;
int fd;
- if (options.flags & UV_PROCESS_DETACHED)
+ if (options->flags & UV_PROCESS_DETACHED)
setsid();
for (fd = 0; fd < stdio_count; fd++) {
close_fd = pipes[fd][0];
use_fd = pipes[fd][1];
- if (use_fd >= 0)
- close(close_fd);
+ if (use_fd >= 0) {
+ if (close_fd != -1)
+ uv__close(close_fd);
+ }
else if (fd >= 3)
continue;
else {
/* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
* set
@@ -302,69 +311,69 @@
if (fd == use_fd)
uv__cloexec(use_fd, 0);
else {
dup2(use_fd, fd);
- close(use_fd);
+ uv__close(use_fd);
}
if (fd <= 2)
uv__nonblock(fd, 0);
}
- if (options.cwd && chdir(options.cwd)) {
+ if (options->cwd != NULL && chdir(options->cwd)) {
uv__write_int(error_fd, -errno);
perror("chdir()");
_exit(127);
}
- if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) {
+ if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
uv__write_int(error_fd, -errno);
perror("setgid()");
_exit(127);
}
- if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) {
+ if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
uv__write_int(error_fd, -errno);
perror("setuid()");
_exit(127);
}
- if (options.env) {
- environ = options.env;
+ if (options->env != NULL) {
+ environ = options->env;
}
- execvp(options.file, options.args);
+ execvp(options->file, options->args);
uv__write_int(error_fd, -errno);
perror("execvp()");
_exit(127);
}
int uv_spawn(uv_loop_t* loop,
uv_process_t* process,
- const uv_process_options_t options) {
+ const uv_process_options_t* options) {
int signal_pipe[2] = { -1, -1 };
int (*pipes)[2];
int stdio_count;
QUEUE* q;
ssize_t r;
pid_t pid;
int err;
int i;
- assert(options.file != NULL);
- assert(!(options.flags & ~(UV_PROCESS_DETACHED |
- UV_PROCESS_SETGID |
- UV_PROCESS_SETUID |
- UV_PROCESS_WINDOWS_HIDE |
- UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
+ assert(options->file != NULL);
+ assert(!(options->flags & ~(UV_PROCESS_DETACHED |
+ UV_PROCESS_SETGID |
+ UV_PROCESS_SETUID |
+ UV_PROCESS_WINDOWS_HIDE |
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
QUEUE_INIT(&process->queue);
- stdio_count = options.stdio_count;
+ stdio_count = options->stdio_count;
if (stdio_count < 3)
stdio_count = 3;
err = -ENOMEM;
pipes = malloc(stdio_count * sizeof(*pipes));
@@ -374,12 +383,12 @@
for (i = 0; i < stdio_count; i++) {
pipes[i][0] = -1;
pipes[i][1] = -1;
}
- for (i = 0; i < options.stdio_count; i++) {
- err = uv__process_init_stdio(options.stdio + i, pipes[i]);
+ for (i = 0; i < options->stdio_count; i++) {
+ err = uv__process_init_stdio(options->stdio + i, pipes[i]);
if (err)
goto error;
}
/* This pipe is used by the parent to wait until
@@ -410,22 +419,23 @@
pid = fork();
if (pid == -1) {
err = -errno;
- close(signal_pipe[0]);
- close(signal_pipe[1]);
+ uv__close(signal_pipe[0]);
+ uv__close(signal_pipe[1]);
goto error;
}
if (pid == 0) {
uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
abort();
}
- close(signal_pipe[1]);
+ uv__close(signal_pipe[1]);
+ process->status = 0;
process->errorno = 0;
do
r = read(signal_pipe[0], &process->errorno, sizeof(process->errorno));
while (r == -1 && errno == EINTR);
@@ -436,38 +446,45 @@
else if (r == -1 && errno == EPIPE)
; /* okay, got EPIPE */
else
abort();
- close(signal_pipe[0]);
+ uv__close(signal_pipe[0]);
- for (i = 0; i < options.stdio_count; i++) {
- err = uv__process_open_stream(options.stdio + i, pipes[i], i == 0);
+ for (i = 0; i < options->stdio_count; i++) {
+ err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0);
if (err == 0)
continue;
while (i--)
- uv__process_close_stream(options.stdio + i);
+ uv__process_close_stream(options->stdio + i);
goto error;
}
q = uv__process_queue(loop, pid);
QUEUE_INSERT_TAIL(q, &process->queue);
process->pid = pid;
- process->exit_cb = options.exit_cb;
+ process->exit_cb = options->exit_cb;
uv__handle_start(process);
free(pipes);
return 0;
error:
- for (i = 0; i < stdio_count; i++) {
- close(pipes[i][0]);
- close(pipes[i][1]);
+ if (pipes != NULL) {
+ for (i = 0; i < stdio_count; i++) {
+ if (i < options->stdio_count)
+ if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
+ continue;
+ if (pipes[i][0] != -1)
+ close(pipes[i][0]);
+ if (pipes[i][1] != -1)
+ close(pipes[i][1]);
+ }
+ free(pipes);
}
- free(pipes);
return err;
}