From ee50db6e36d97d62d4e52ca2097b06664b794135 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 10 Jul 2012 02:13:49 +0200 Subject: [PATCH] unix, windows: preliminary signal handler support * a no-op on Windows for now * only supports the main loop on UNIX (again, for now) --- config-unix.mk | 1 + include/uv-private/uv-unix.h | 5 + include/uv-private/uv-win.h | 3 + include/uv.h | 27 ++++ src/unix/core.c | 5 + src/unix/internal.h | 4 + src/unix/loop.c | 8 +- src/unix/signal.c | 269 +++++++++++++++++++++++++++++++++++ src/win/handle-inl.h | 4 + src/win/handle.c | 4 + src/win/internal.h | 7 + src/win/signal.c | 57 ++++++++ test/test-list.h | 6 + test/test-signal.c | 157 ++++++++++++++++++++ uv.gyp | 3 + 15 files changed, 559 insertions(+), 1 deletion(-) create mode 100644 src/unix/signal.c create mode 100644 src/win/signal.c create mode 100644 test/test-signal.c diff --git a/config-unix.mk b/config-unix.mk index e3e95459..53c636de 100644 --- a/config-unix.mk +++ b/config-unix.mk @@ -37,6 +37,7 @@ OBJS += src/unix/loop-watcher.o OBJS += src/unix/pipe.o OBJS += src/unix/poll.o OBJS += src/unix/process.o +OBJS += src/unix/signal.o OBJS += src/unix/stream.o OBJS += src/unix/tcp.o OBJS += src/unix/thread.o diff --git a/include/uv-private/uv-unix.h b/include/uv-private/uv-unix.h index d6b022c0..d265339f 100644 --- a/include/uv-private/uv-unix.h +++ b/include/uv-private/uv-unix.h @@ -134,6 +134,7 @@ struct uv__io_s { /* RB_HEAD(uv__timers, uv_timer_s) */ \ struct uv__timers { struct uv_timer_s* rbh_root; } timer_handles; \ uint64_t time; \ + void* signal_ctx; \ UV_LOOP_PRIVATE_PLATFORM_FIELDS #define UV_REQ_BUFSML_SIZE (4) @@ -272,6 +273,10 @@ struct uv__io_s { struct termios orig_termios; \ int mode; +#define UV_SIGNAL_PRIVATE_FIELDS \ + ngx_queue_t queue; \ + unsigned int signum; \ + /* UV_FS_EVENT_PRIVATE_FIELDS */ #if defined(__linux__) diff --git a/include/uv-private/uv-win.h b/include/uv-private/uv-win.h index d0c125c3..9e0db118 100644 --- a/include/uv-private/uv-win.h +++ b/include/uv-private/uv-win.h @@ -511,6 +511,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); wchar_t* dirw; \ char* buffer; +#define UV_SIGNAL_PRIVATE_FIELDS \ + /* empty */ + int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size, char* utf8Buffer, size_t utf8Size); int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer, diff --git a/include/uv.h b/include/uv.h index e08cc303..d85f74fe 100644 --- a/include/uv.h +++ b/include/uv.h @@ -146,6 +146,7 @@ typedef enum { XX(TIMER, timer) \ XX(TTY, tty) \ XX(UDP, udp) \ + XX(SIGNAL, signal) \ #define UV_REQ_TYPE_MAP(XX) \ XX(CONNECT, connect) \ @@ -193,6 +194,7 @@ typedef struct uv_async_s uv_async_t; typedef struct uv_process_s uv_process_t; typedef struct uv_fs_event_s uv_fs_event_t; typedef struct uv_fs_poll_s uv_fs_poll_t; +typedef struct uv_signal_s uv_signal_t; /* Request types. */ typedef struct uv_req_s uv_req_t; @@ -316,6 +318,9 @@ typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle, const uv_statbuf_t* prev, const uv_statbuf_t* curr); +typedef void (*uv_signal_cb)(uv_signal_t* handle, int signum); + + typedef enum { UV_LEAVE_GROUP = 0, UV_JOIN_GROUP @@ -1567,6 +1572,27 @@ UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle, UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle); + +/* + * UNIX signal handling on a per-event loop basis. The implementation is not + * ultra efficient so don't go creating a million event loops with a million + * signal watchers. + * + * TODO(bnoordhuis) As of 2012-08-10 only the default event loop supports + * signals. That will be fixed. + */ +struct uv_signal_s { + UV_HANDLE_FIELDS + uv_signal_cb signal_cb; + UV_SIGNAL_PRIVATE_FIELDS +}; + +/* These functions are no-ops on Windows. */ +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle); +int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum); +int uv_signal_stop(uv_signal_t* handle); + + /* * Gets load avg * See: http://en.wikipedia.org/wiki/Load_(computing) @@ -1804,6 +1830,7 @@ struct uv_loop_s { #undef UV_FS_REQ_PRIVATE_FIELDS #undef UV_WORK_PRIVATE_FIELDS #undef UV_FS_EVENT_PRIVATE_FIELDS +#undef UV_SIGNAL_PRIVATE_FIELDS #undef UV_LOOP_PRIVATE_FIELDS #undef UV_LOOP_PRIVATE_PLATFORM_FIELDS diff --git a/src/unix/core.c b/src/unix/core.c index 4bc6b77d..7b261722 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -116,6 +116,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { uv__fs_poll_close((uv_fs_poll_t*)handle); break; + case UV_SIGNAL: + uv__signal_close((uv_signal_t*)handle); + break; + default: assert(0); } @@ -143,6 +147,7 @@ static void uv__finish_close(uv_handle_t* handle) { case UV_FS_EVENT: case UV_FS_POLL: case UV_POLL: + case UV_SIGNAL: break; case UV_NAMED_PIPE: diff --git a/src/unix/internal.h b/src/unix/internal.h index 233f7428..fbb5d641 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -153,6 +153,10 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); void uv__run_timers(uv_loop_t* loop); unsigned int uv__next_timeout(uv_loop_t* loop); +/* signal */ +void uv__signal_close(uv_signal_t* handle); +void uv__signal_unregister(uv_loop_t* loop); + /* various */ void uv__async_close(uv_async_t* handle); void uv__check_close(uv_check_t* handle); diff --git a/src/unix/loop.c b/src/unix/loop.c index bd91c01f..f7690898 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -44,6 +44,7 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) { ngx_queue_init(&loop->prepare_handles); ngx_queue_init(&loop->handle_queue); loop->closing_handles = NULL; + loop->signal_ctx = NULL; loop->time = uv_hrtime() / 1000000; loop->async_pipefd[0] = -1; loop->async_pipefd[1] = -1; @@ -63,7 +64,9 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) { void uv__loop_delete(uv_loop_t* loop) { + uv__signal_unregister(loop); ev_loop_destroy(loop->ev); + #if __linux__ if (loop->inotify_fd != -1) { uv__io_stop(loop, &loop->inotify_read_watcher); @@ -71,8 +74,11 @@ void uv__loop_delete(uv_loop_t* loop) { loop->inotify_fd = -1; } #endif + #if HAVE_PORTS_FS - if (loop->fs_fd != -1) + if (loop->fs_fd != -1) { close(loop->fs_fd); + loop->fs_fd = -1; + } #endif } diff --git a/src/unix/signal.c b/src/unix/signal.c new file mode 100644 index 00000000..8ef640b6 --- /dev/null +++ b/src/unix/signal.c @@ -0,0 +1,269 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include +#include + +struct signal_ctx { + int pipefd[2]; + uv__io_t io_watcher; + unsigned int nqueues; + ngx_queue_t queues[1]; /* variable length */ +}; + +static void uv__signal_handler(int signum); +static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, int events); +static struct signal_ctx* uv__signal_ctx_new(uv_loop_t* loop); +static void uv__signal_ctx_delete(struct signal_ctx* ctx); +static void uv__signal_write(int fd, unsigned int val); +static unsigned int uv__signal_read(int fd); +static unsigned int uv__signal_max(void); + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_SIGNAL); + handle->signum = 0; + return 0; +} + + +int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum_) { + struct signal_ctx* ctx; + struct sigaction sa; + unsigned int signum; + uv_loop_t* loop; + ngx_queue_t* q; + + /* XXX doing this check in uv_signal_init() - the logical place for it - + * leads to an infinite loop when uv__loop_init() inits a signal watcher + */ + /* FIXME */ + assert(handle->loop == uv_default_loop() && + "uv_signal_t is currently only supported by the default loop"); + + loop = handle->loop; + signum = signum_; + + if (uv__is_active(handle)) + return uv__set_artificial_error(loop, UV_EBUSY); + + if (signal_cb == NULL) + return uv__set_artificial_error(loop, UV_EINVAL); + + if (signum <= 0) + return uv__set_artificial_error(loop, UV_EINVAL); + + ctx = loop->signal_ctx; + + if (ctx == NULL) { + ctx = uv__signal_ctx_new(loop); + + if (ctx == NULL) + return uv__set_artificial_error(loop, UV_ENOMEM); + + loop->signal_ctx = ctx; + } + + if (signum > ctx->nqueues) + return uv__set_artificial_error(loop, UV_EINVAL); + + q = ctx->queues + signum; + + if (!ngx_queue_empty(q)) + goto skip; + + /* XXX use a separate signal stack? */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = uv__signal_handler; + + /* XXX save old action so we can restore it later on? */ + if (sigaction(signum, &sa, NULL)) + return uv__set_artificial_error(loop, UV_EINVAL); + +skip: + ngx_queue_insert_tail(q, &handle->queue); + uv__handle_start(handle); + handle->signum = signum; + handle->signal_cb = signal_cb; + + return 0; +} + + +int uv_signal_stop(uv_signal_t* handle) { + struct signal_ctx* ctx; + struct sigaction sa; + unsigned int signum; + uv_loop_t* loop; + + if (!uv__is_active(handle)) + return 0; + + signum = handle->signum; + loop = handle->loop; + ctx = loop->signal_ctx; + assert(signum > 0); + assert(signum <= ctx->nqueues); + + ngx_queue_remove(&handle->queue); + uv__handle_stop(handle); + handle->signum = 0; + + if (!ngx_queue_empty(ctx->queues + signum)) + goto skip; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; /* XXX restore previous action? */ + + if (sigaction(signum, &sa, NULL)) + return uv__set_artificial_error(loop, UV_EINVAL); + +skip: + return 0; +} + + +void uv__signal_close(uv_signal_t* handle) { + uv_signal_stop(handle); +} + + +void uv__signal_unregister(uv_loop_t* loop) { + uv__signal_ctx_delete(loop->signal_ctx); + loop->signal_ctx = NULL; +} + + +static void uv__signal_handler(int signum) { + struct signal_ctx* ctx = uv_default_loop()->signal_ctx; + uv__signal_write(ctx->pipefd[1], (unsigned int) signum); +} + + +static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, int events) { + struct signal_ctx* ctx; + unsigned int signum; + uv_signal_t* h; + ngx_queue_t* q; + + ctx = container_of(w, struct signal_ctx, io_watcher); + signum = uv__signal_read(ctx->pipefd[0]); + assert(signum > 0); + assert(signum <= ctx->nqueues); + + ngx_queue_foreach(q, ctx->queues + signum) { + h = ngx_queue_data(q, uv_signal_t, queue); + h->signal_cb(h, signum); + } +} + + +static struct signal_ctx* uv__signal_ctx_new(uv_loop_t* loop) { + struct signal_ctx* ctx; + unsigned int nqueues; + unsigned int i; + + nqueues = uv__signal_max(); + assert(nqueues > 0); + + /* The first ctx->queues entry is never used. It wastes a few bytes of memory + * but it saves us from having to substract 1 from the signum all the time - + * which inevitably someone will forget to do. + */ + ctx = calloc(1, sizeof(*ctx) + sizeof(ctx->queues[0]) * (nqueues + 1)); + if (ctx == NULL) + return NULL; + + if (uv__make_pipe(ctx->pipefd, UV__F_NONBLOCK)) { + free(ctx); + return NULL; + } + + uv__io_init(&ctx->io_watcher, uv__signal_event, ctx->pipefd[0], UV__IO_READ); + uv__io_start(loop, &ctx->io_watcher); + ctx->nqueues = nqueues; + + for (i = 1; i <= nqueues; i++) + ngx_queue_init(ctx->queues + i); + + return ctx; +} + + +static void uv__signal_ctx_delete(struct signal_ctx* ctx) { + if (ctx == NULL) return; + close(ctx->pipefd[0]); + close(ctx->pipefd[1]); + free(ctx); +} + + +static void uv__signal_write(int fd, unsigned int val) { + ssize_t n; + + do + n = write(fd, &val, sizeof(val)); + while (n == -1 && errno == EINTR); + + if (n == sizeof(val)) + return; + + if (n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + return; /* pipe full - nothing we can do about that */ + + abort(); +} + + +static unsigned int uv__signal_read(int fd) { + unsigned int val; + ssize_t n; + + do + n = read(fd, &val, sizeof(val)); + while (n == -1 && errno == EINTR); + + if (n == sizeof(val)) + return val; + + abort(); +} + + +static unsigned int uv__signal_max(void) { +#if defined(_SC_RTSIG_MAX) + int max = sysconf(_SC_RTSIG_MAX); + if (max != -1) return max; +#endif +#if defined(SIGRTMAX) + return SIGRTMAX; +#elif defined(NSIG) + return NSIG; +#else + return 32; +#endif +} diff --git a/src/win/handle-inl.h b/src/win/handle-inl.h index 4064c24c..fc2f4f14 100644 --- a/src/win/handle-inl.h +++ b/src/win/handle-inl.h @@ -135,6 +135,10 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) { uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle); break; + case UV_SIGNAL: + uv_signal_endgame(loop, (uv_signal_t*) handle); + break; + default: assert(0); break; diff --git a/src/win/handle.c b/src/win/handle.c index d4b86de9..36c94d02 100644 --- a/src/win/handle.c +++ b/src/win/handle.c @@ -138,6 +138,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { uv_want_endgame(loop, handle); return; + case UV_SIGNAL: + uv_signal_close(loop, (uv_signal_t*) handle); + return; + default: /* Not supported */ abort(); diff --git a/src/win/internal.h b/src/win/internal.h index b9f8bba7..f46f6133 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -274,6 +274,13 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle); void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle); +/* + * Signals. + */ +void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle); +void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle); + + /* * Utilities. */ diff --git a/src/win/signal.c b/src/win/signal.c new file mode 100644 index 00000000..9742ec61 --- /dev/null +++ b/src/win/signal.c @@ -0,0 +1,57 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" +#include "handle-inl.h" +#include + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_SIGNAL); + return 0; +} + + +int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + /* XXX call uv__handle_start() and bump the refcount? */ + return 0; +} + + +int uv_signal_stop(uv_signal_t* handle) { + return 0; +} + + +void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) { + uv__handle_start(handle); + uv_want_endgame(loop, (uv_handle_t*)handle); +} + + +void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) { + if (handle->flags & UV_HANDLE_CLOSING) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); + uv__handle_close(handle); + } +} diff --git a/test/test-list.h b/test/test-list.h index d7884b1a..3eab32db 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -180,6 +180,8 @@ TEST_DECLARE (dlerror) TEST_DECLARE (poll_duplex) TEST_DECLARE (poll_unidirectional) TEST_DECLARE (poll_close) +TEST_DECLARE (we_get_signal) +TEST_DECLARE (we_get_signals) #ifdef _WIN32 TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) TEST_DECLARE (argument_escaping) @@ -366,6 +368,10 @@ TASK_LIST_START TEST_ENTRY (spawn_stdout_to_file) TEST_ENTRY (fs_poll) TEST_ENTRY (kill) + + TEST_ENTRY (we_get_signal) + TEST_ENTRY (we_get_signals) + #ifdef _WIN32 TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows) TEST_ENTRY (argument_escaping) diff --git a/test/test-signal.c b/test/test-signal.c new file mode 100644 index 00000000..1515d17b --- /dev/null +++ b/test/test-signal.c @@ -0,0 +1,157 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#ifdef _WIN32 + +TEST_IMPL(we_get_signal) { + return 0; +} + +#else /* !_WIN32 */ + +#include +#include +#include +#include +#include + +/* This test does not pretend to be cross-platform. */ +#include +#include +#include + +#define NSIGNALS 10 + +struct timer_ctx { + unsigned int ncalls; + uv_timer_t handle; + int signum; +}; + +struct signal_ctx { + enum { CLOSE, STOP } stop_or_close; + unsigned int ncalls; + uv_signal_t handle; + int signum; +}; + + +static void signal_cb(uv_signal_t* handle, int signum) { + struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle); + ASSERT(signum == ctx->signum); + + if (++ctx->ncalls == NSIGNALS) { + if (ctx->stop_or_close == STOP) + uv_signal_stop(handle); + else if (ctx->stop_or_close == CLOSE) + uv_close((uv_handle_t*)handle, NULL); + else + ASSERT(0); + } +} + + +static void timer_cb(uv_timer_t* handle, int status) { + struct timer_ctx* ctx = container_of(handle, struct timer_ctx, handle); + + raise(ctx->signum); + + if (++ctx->ncalls == NSIGNALS) + uv_close((uv_handle_t*)handle, NULL); +} + + +static void start_watcher(uv_loop_t* loop, int signum, struct signal_ctx* ctx) { + ctx->ncalls = 0; + ctx->signum = signum; + ctx->stop_or_close = CLOSE; + ASSERT(0 == uv_signal_init(loop, &ctx->handle)); + ASSERT(0 == uv_signal_start(&ctx->handle, signal_cb, signum)); +} + + +static void start_timer(uv_loop_t* loop, int signum, struct timer_ctx* ctx) { + ctx->ncalls = 0; + ctx->signum = signum; + ASSERT(0 == uv_timer_init(loop, &ctx->handle)); + ASSERT(0 == uv_timer_start(&ctx->handle, timer_cb, 5, 5)); +} + + +TEST_IMPL(we_get_signal) { + struct signal_ctx sc; + struct timer_ctx tc; + uv_loop_t* loop; + + loop = uv_default_loop(); + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, &sc); + sc.stop_or_close = STOP; /* stop, don't close the signal handle */ + ASSERT(0 == uv_run(loop)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == NSIGNALS); + + start_timer(loop, SIGCHLD, &tc); + ASSERT(0 == uv_run(loop)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == NSIGNALS); + + sc.ncalls = 0; + sc.stop_or_close = CLOSE; /* now close it when it's done */ + uv_signal_start(&sc.handle, signal_cb, SIGCHLD); + + start_timer(loop, SIGCHLD, &tc); + ASSERT(0 == uv_run(loop)); + ASSERT(tc.ncalls == NSIGNALS); + ASSERT(sc.ncalls == NSIGNALS); + + return 0; +} + + +TEST_IMPL(we_get_signals) { + struct signal_ctx sc[4]; + struct timer_ctx tc[2]; + uv_loop_t* loop; + unsigned int i; + + loop = uv_default_loop(); + start_watcher(loop, SIGUSR1, sc + 0); + start_watcher(loop, SIGUSR1, sc + 1); + start_watcher(loop, SIGUSR2, sc + 2); + start_watcher(loop, SIGUSR2, sc + 3); + start_timer(loop, SIGUSR1, tc + 0); + start_timer(loop, SIGUSR2, tc + 1); + ASSERT(0 == uv_run(loop)); + + for (i = 0; i < ARRAY_SIZE(sc); i++) + ASSERT(sc[i].ncalls == NSIGNALS); + + for (i = 0; i < ARRAY_SIZE(tc); i++) + ASSERT(tc[i].ncalls == NSIGNALS); + + return 0; +} + +#endif /* _WIN32 */ diff --git a/uv.gyp b/uv.gyp index 1fa285fc..10e2cb9b 100644 --- a/uv.gyp +++ b/uv.gyp @@ -76,6 +76,7 @@ 'src/win/process-stdio.c', 'src/win/req.c', 'src/win/req-inl.h', + 'src/win/signal.c', 'src/win/stream.c', 'src/win/stream-inl.h', 'src/win/tcp.c', @@ -127,6 +128,7 @@ 'src/unix/pipe.c', 'src/unix/poll.c', 'src/unix/process.c', + 'src/unix/signal.c', 'src/unix/stream.c', 'src/unix/tcp.c', 'src/unix/thread.c', @@ -256,6 +258,7 @@ 'test/test-semaphore.c', 'test/test-shutdown-close.c', 'test/test-shutdown-eof.c', + 'test/test-signal.c', 'test/test-spawn.c', 'test/test-fs-poll.c', 'test/test-stdio-over-pipes.c',