diff --git a/Makefile b/Makefile index eb03586c..cbbcb2e1 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,8 @@ CMAKE_DEFINES := \ -DTARGET_PLATFORM=$(TUV_PLATFORM) \ -DBUILDTESTER=${TUV_BUILDTESTER} \ -DBUILD_HOST_HELPER=${TUV_BUILDHOSTHELPER} \ - -DCREATE_SHARED_LIB=${TUV_CREATE_SHARED_LIB} + -DCREATE_SHARED_LIB=${TUV_CREATE_SHARED_LIB} \ + -DTUV_FEATURE_SIGNAL=ON ifneq ($(TUV_BOARD),unknown) CMAKE_DEFINES += -DTARGET_BOARD=${TUV_BOARD} diff --git a/cmake/option/option_unix_common.cmake b/cmake/option/option_unix_common.cmake index 60c0514d..11593d72 100644 --- a/cmake/option/option_unix_common.cmake +++ b/cmake/option/option_unix_common.cmake @@ -51,7 +51,6 @@ set(PLATFORM_SRCFILES ${UNIX_PATH}/poll.c ${UNIX_PATH}/process.c # ${UNIX_PATH}/proctitle.c -# ${UNIX_PATH}/signal.c ${UNIX_PATH}/spinlock.h ${UNIX_PATH}/stream.c ${UNIX_PATH}/tcp.c @@ -61,6 +60,12 @@ set(PLATFORM_SRCFILES ${UNIX_PATH}/udp.c ) +if(TUV_FEATURE_SIGNAL) + set(PLATFORM_SRCFILES "${PLATFORM_SRCFILES}" + ${UNIX_PATH}/signal.c) + set(FLAGS_COMMON "${FLAGS_COMMON}" "-DTUV_FEATURE_SIGNAL=1") +endif() + set(TEST_MAINFILE "${TEST_ROOT}/runner_main.c") set(TEST_UNITFILES @@ -79,6 +84,7 @@ set(TEST_UNITFILES "${TEST_ROOT}/test_active.c" "${TEST_ROOT}/test_walk_handles.c" "${TEST_ROOT}/test_async.c" + "${TEST_ROOT}/test_signal.c" ) # configuration values diff --git a/src/unix/core.c b/src/unix/core.c index ee62b117..1ad3262e 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -143,6 +143,14 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { uv__poll_close((uv_poll_t*)handle); break; +#ifdef TUV_FEATURE_SIGNAL + case UV_SIGNAL: + uv__signal_close((uv_signal_t*) handle); + /* Signal handles may not be closed immediately. The signal code will */ + /* itself close uv__make_close_pending whenever appropriate. */ + return; +#endif + default: assert(0); } @@ -199,7 +207,7 @@ static void uv__finish_close(uv_handle_t* handle) { // case UV_FS_EVENT: // case UV_FS_POLL: case UV_POLL: - // case UV_SIGNAL: + case UV_SIGNAL: break; case UV_NAMED_PIPE: diff --git a/src/unix/loop.c b/src/unix/loop.c index 39bce4f5..16b3b0f7 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -46,6 +46,10 @@ int uv_loop_init(uv_loop_t* loop) { void* saved_data; int err; +#ifdef TUV_FEATURE_SIGNAL + uv__signal_global_once_init(); +#endif + saved_data = loop->data; memset(loop, 0, sizeof(*loop)); loop->data = saved_data; @@ -68,6 +72,10 @@ int uv_loop_init(uv_loop_t* loop) { loop->closing_handles = NULL; uv__update_time(loop); uv__async_init(&loop->async_watcher); +#ifdef TUV_FEATURE_SIGNAL + loop->signal_pipefd[0] = -1; + loop->signal_pipefd[1] = -1; +#endif loop->backend_fd = -1; loop->emfile_fd = -1; @@ -78,6 +86,12 @@ int uv_loop_init(uv_loop_t* loop) { if (err) return err; +#ifdef TUV_FEATURE_SIGNAL + err = uv_signal_init(loop, &loop->child_watcher); + if (err) + goto fail_signal_init; +#endif + uv__handle_unref(&loop->child_watcher); loop->child_watcher.flags |= UV__HANDLE_INTERNAL; QUEUE_INIT(&loop->process_handles); @@ -106,6 +120,11 @@ int uv_loop_init(uv_loop_t* loop) { uv_rwlock_destroy(&loop->cloexec_lock); fail_rwlock_init: +#ifdef TUV_FEATURE_SIGNAL + uv__signal_loop_cleanup(loop); +#endif + +fail_signal_init: uv__platform_loop_delete(loop); return err; @@ -113,6 +132,9 @@ int uv_loop_init(uv_loop_t* loop) { void uv__loop_close(uv_loop_t* loop) { +#ifdef TUV_FEATURE_SIGNAL + uv__signal_loop_cleanup(loop); +#endif uv__platform_loop_delete(loop); uv__async_stop(loop, &loop->async_watcher); diff --git a/test/runner_list.h b/test/runner_list.h index bdfc5bdf..3d1199f6 100644 --- a/test/runner_list.h +++ b/test/runner_list.h @@ -114,6 +114,7 @@ TE(getaddrinfo_basic, 5000) \ TE(getaddrinfo_basic_sync, 5000) \ TE(getaddrinfo_concurrent, 5000) \ + TE(we_get_signal, 5000) \ #elif defined(__TUV_RAW__) #define TEST_LIST_EXT(TE) \ diff --git a/test/test_signal.c b/test/test_signal.c new file mode 100644 index 00000000..284d4784 --- /dev/null +++ b/test/test_signal.c @@ -0,0 +1,154 @@ +/* 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. + */ + + +/* This test does not pretend to be cross-platform. */ +#ifndef _WIN32 + +#include "uv.h" +#include "runner.h" + +#include +#include +#include +#include +#include +#include +#include + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define NSIGNALS 10 + +#define container_of(ptr, type, member) \ + ((type *) ((char *) (ptr) - offsetof(type, member))) + +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); + TUV_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 + TUV_ASSERT(0); + } +} + + +static void timer_cb(uv_timer_t* handle) { + 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; + TUV_ASSERT(0 == uv_signal_init(loop, &ctx->handle)); + TUV_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; + TUV_ASSERT(0 == uv_timer_init(loop, &ctx->handle)); + TUV_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 */ + TUV_ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + TUV_ASSERT(tc.ncalls == NSIGNALS); + TUV_ASSERT(sc.ncalls == NSIGNALS); + + start_timer(loop, SIGCHLD, &tc); + TUV_ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + TUV_ASSERT(tc.ncalls == NSIGNALS); + TUV_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); + TUV_ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + TUV_ASSERT(tc.ncalls == NSIGNALS); + TUV_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); + TUV_ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + for (i = 0; i < ARRAY_SIZE(sc); i++) + TUV_ASSERT(sc[i].ncalls == NSIGNALS); + + for (i = 0; i < ARRAY_SIZE(tc); i++) + TUV_ASSERT(tc[i].ncalls == NSIGNALS); + + return 0; +} + +#endif /* _WIN32 */