Skip to content

Commit

Permalink
unix: fix SIGCHLD processing in process.c
Browse files Browse the repository at this point in the history
Quick for for joyent#887.
  • Loading branch information
bnoordhuis authored and alexcrichton committed Aug 27, 2013
1 parent b647c27 commit b9607e8
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 43 deletions.
1 change: 1 addition & 0 deletions include/uv-unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ typedef struct {
#define UV_PROCESS_PRIVATE_FIELDS \
void* queue[2]; \
int errorno; \
int status; \

#define UV_FS_PRIVATE_FIELDS \
const char *new_path; \
Expand Down
92 changes: 49 additions & 43 deletions src/unix/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,68 +47,73 @@ static QUEUE* uv__process_queue(uv_loop_t* loop, int pid) {
}


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 (;;) {
do
pid = waitpid(-1, &status, WNOHANG);
while (pid == -1 && errno == EINTR);
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);
}
}
}

Expand Down Expand Up @@ -426,6 +431,7 @@ int uv_spawn(uv_loop_t* loop,

close(signal_pipe[1]);

process->status = 0;
process->errorno = 0;
do
r = read(signal_pipe[0], &process->errorno, sizeof(process->errorno));
Expand Down

0 comments on commit b9607e8

Please sign in to comment.