Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

Commit

Permalink
unix: remove dependency on ev_child
Browse files Browse the repository at this point in the history
  • Loading branch information
bnoordhuis committed Aug 10, 2012
1 parent ee50db6 commit 75ba681
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 30 deletions.
4 changes: 3 additions & 1 deletion include/uv-private/uv-unix.h
Expand Up @@ -125,6 +125,7 @@ struct uv__io_s {
uv_async_t uv_eio_done_poll_notifier; \
uv_idle_t uv_eio_poller; \
uv_handle_t* closing_handles; \
ngx_queue_t process_handles[1]; \
ngx_queue_t prepare_handles; \
ngx_queue_t check_handles; \
ngx_queue_t idle_handles; \
Expand All @@ -135,6 +136,7 @@ struct uv__io_s {
struct uv__timers { struct uv_timer_s* rbh_root; } timer_handles; \
uint64_t time; \
void* signal_ctx; \
uv_signal_t child_watcher; \
UV_LOOP_PRIVATE_PLATFORM_FIELDS

#define UV_REQ_BUFSML_SIZE (4)
Expand Down Expand Up @@ -259,7 +261,7 @@ struct uv__io_s {
int retcode;

#define UV_PROCESS_PRIVATE_FIELDS \
ev_child child_watcher; \
ngx_queue_t queue; \
int errorno; \

#define UV_FS_PRIVATE_FIELDS \
Expand Down
14 changes: 12 additions & 2 deletions src/unix/loop.c
Expand Up @@ -28,10 +28,13 @@


int uv__loop_init(uv_loop_t* loop, int default_loop) {
unsigned int i;
int flags;

#if HAVE_KQUEUE
int flags = EVBACKEND_KQUEUE;
flags = EVBACKEND_KQUEUE;
#else
int flags = EVFLAG_AUTO;
flags = EVFLAG_AUTO;
#endif

memset(loop, 0, sizeof(*loop));
Expand All @@ -52,6 +55,13 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
ev_set_userdata(loop->ev, loop);
eio_channel_init(&loop->uv_eio_channel, loop);

uv_signal_init(loop, &loop->child_watcher);
uv__handle_unref(&loop->child_watcher);
loop->child_watcher.flags |= UV__HANDLE_INTERNAL;

for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++)
ngx_queue_init(loop->process_handles + i);

#if __linux__
loop->inotify_watchers = NULL;
loop->inotify_fd = -1;
Expand Down
101 changes: 74 additions & 27 deletions src/unix/process.c
Expand Up @@ -22,13 +22,16 @@
#include "uv.h"
#include "internal.h"

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <poll.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <poll.h>

#ifdef __APPLE__
# include <TargetConditionals.h>
Expand All @@ -42,30 +45,71 @@ extern char **environ;
#endif


static void uv__chld(EV_P_ ev_child* watcher, int revents) {
int status = watcher->rstatus;
int exit_status = 0;
int term_signal = 0;
uv_process_t *process = watcher->data;
static ngx_queue_t* uv__process_queue(uv_loop_t* loop, int pid) {
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;
ngx_queue_t* h;
ngx_queue_t* q;

assert(&process->child_watcher == watcher);
assert(revents & EV_CHILD);
h = uv__process_queue(loop, pid);

ngx_queue_foreach(q, h) {
handle = ngx_queue_data(q, uv_process_t, queue);
if (handle->pid == pid) return handle;
}

return NULL;
}

ev_child_stop(EV_A_ &process->child_watcher);

if (process->exit_cb == NULL)
return;
static void uv__chld(uv_signal_t* handle, int signum) {
uv_process_t* process;
int exit_status;
int term_signal;
int status;
pid_t pid;

assert(signum == SIGCHLD);

if (WIFEXITED(status))
exit_status = WEXITSTATUS(status);
for (;;) {
pid = waitpid(-1, &status, WNOHANG);

if (WIFSIGNALED(status))
term_signal = WTERMSIG(status);
if (pid == 0)
return;

if (pid == -1) {
if (errno == ECHILD)
return; /* XXX stop signal watcher? */
else
abort();
}

if (process->errorno)
uv__set_sys_error(process->loop, process->errorno);
process = uv__process_find(handle->loop, pid);
if (process == NULL)
continue; /* XXX bug? abort? */

process->exit_cb(process, exit_status, term_signal);
if (process->exit_cb == NULL)
continue;

exit_status = 0;
term_signal = 0;

if (WIFEXITED(status))
exit_status = WEXITSTATUS(status);

if (WIFSIGNALED(status))
term_signal = WTERMSIG(status);

if (process->errorno)
uv__set_sys_error(process->loop, process->errorno);

process->exit_cb(process, exit_status, term_signal);
}
}


Expand Down Expand Up @@ -306,6 +350,7 @@ int uv_spawn(uv_loop_t* loop,
struct pollfd pfd;
int (*pipes)[2];
int stdio_count;
ngx_queue_t* q;
pid_t pid;
int i;
int r;
Expand All @@ -318,6 +363,7 @@ int uv_spawn(uv_loop_t* loop,

uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
loop->counters.process_init++;
ngx_queue_init(&process->queue);

stdio_count = options.stdio_count;
if (stdio_count < 3)
Expand Down Expand Up @@ -402,22 +448,22 @@ int uv_spawn(uv_loop_t* loop,

close(signal_pipe[0]);

ev_child_init(&process->child_watcher, uv__chld, pid, 0);
ev_child_start(process->loop->ev, &process->child_watcher);
process->child_watcher.data = process;
process->exit_cb = options.exit_cb;
process->pid = pid;

for (i = 0; i < options.stdio_count; i++) {
if (uv__process_open_stream(options.stdio + i, pipes[i], i == 0)) {
while (i--) uv__process_close_stream(options.stdio + i);
goto error;
}
}

q = uv__process_queue(loop, pid);
ngx_queue_insert_tail(q, &process->queue);
uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);

process->pid = pid;
process->exit_cb = options.exit_cb;
uv__handle_start(process);
free(pipes);

free(pipes);
return 0;

error:
Expand Down Expand Up @@ -457,6 +503,7 @@ uv_err_t uv_kill(int pid, int signum) {


void uv__process_close(uv_process_t* handle) {
ev_child_stop(handle->loop->ev, &handle->child_watcher);
/* TODO stop signal watcher when this is the last handle */
ngx_queue_remove(&handle->queue);
uv__handle_stop(handle);
}

0 comments on commit 75ba681

Please sign in to comment.