From 75ba6819135d4bd3a7ed93ad5f625d56c65e3102 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 8 Aug 2012 14:42:34 +0200 Subject: [PATCH] unix: remove dependency on ev_child --- include/uv-private/uv-unix.h | 4 +- src/unix/loop.c | 14 ++++- src/unix/process.c | 103 +++++++++++++++++++++++++---------- 3 files changed, 90 insertions(+), 31 deletions(-) diff --git a/include/uv-private/uv-unix.h b/include/uv-private/uv-unix.h index d265339f..bd3e7e36 100644 --- a/include/uv-private/uv-unix.h +++ b/include/uv-private/uv-unix.h @@ -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; \ @@ -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) @@ -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 \ diff --git a/src/unix/loop.c b/src/unix/loop.c index f7690898..1118ac6a 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -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)); @@ -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; diff --git a/src/unix/process.c b/src/unix/process.c index dcdf0594..18f76715 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -22,13 +22,16 @@ #include "uv.h" #include "internal.h" +#include +#include #include #include + +#include #include -#include #include -#include #include +#include #ifdef __APPLE__ # include @@ -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); +} - assert(&process->child_watcher == watcher); - assert(revents & EV_CHILD); - ev_child_stop(EV_A_ &process->child_watcher); +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; - if (process->exit_cb == NULL) - return; + h = uv__process_queue(loop, pid); - if (WIFEXITED(status)) - exit_status = WEXITSTATUS(status); + ngx_queue_foreach(q, h) { + handle = ngx_queue_data(q, uv_process_t, queue); + if (handle->pid == pid) return handle; + } - if (WIFSIGNALED(status)) - term_signal = WTERMSIG(status); + return NULL; +} - if (process->errorno) - uv__set_sys_error(process->loop, process->errorno); - process->exit_cb(process, exit_status, term_signal); +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); + + for (;;) { + pid = waitpid(-1, &status, WNOHANG); + + if (pid == 0) + return; + + if (pid == -1) { + if (errno == ECHILD) + return; /* XXX stop signal watcher? */ + else + abort(); + } + + process = uv__process_find(handle->loop, pid); + if (process == NULL) + continue; /* XXX bug? abort? */ + + 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); + } } @@ -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; @@ -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) @@ -402,12 +448,6 @@ 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); @@ -415,9 +455,15 @@ int uv_spawn(uv_loop_t* loop, } } - uv__handle_start(process); - free(pipes); + 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); return 0; error: @@ -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); }