diff --git a/deps/uv/include/uv-private/linklist.h b/deps/uv/include/uv-private/linklist.h new file mode 100644 index 00000000000..1f21eb70ebd --- /dev/null +++ b/deps/uv/include/uv-private/linklist.h @@ -0,0 +1,116 @@ +#ifndef _linklist_h_ +#define _linklist_h_ 1 + +// +//typedef struct _SLINK{ +// _SLINK* _next; +//} SLINK,*PSLINK; + + +//template< typename PSLINK > +//inline void SLINK_Initialize(PSLINK _head ) +//{ (_head)->_next = NULL; } +#define SLINK_Initialize(_head) ((_head)->_next = NULL) + +//template< typename PSLINK > +//inline bool SLINK_IsEmpty(PSLINK _head ) +//{ return ((_head)->_next == NULL);} +#define SLINK_IsEmpty(_head) ((_head)->_next == NULL) + +//template< typename PSLINK ,typename PVALUE > +//inline PVALUE SLINK_Pop(PSLINK _head ) +//{ +// PVALUE head_item = (_head)->_next; +// (_head)->_next = ((_head)->_next->_next); +// return head_item; +//} +#define SLINK_Pop(_head) (_head)->_next;\ + (_head)->_next = (_head)->_next->_next; + +//template< typename PSLINK ,typename PVALUE > +//inline void SLINK_Push(PSLINK _head, PVALUE _link) +//{ +// (_link)->_next = (_head)->_next; +// (_head)->_next = (_link); +//} +#define SLINK_Push(_head, _link) (_link)->_next = (_head)->_next; \ + (_head)->_next = (_link) + +/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////DOUBLE///LINK///////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////// + +// +//typedef struct _DLINK{ +// _DLINK* _prev; +// _DLINK* _next; +//} DLINK,*PDLINK; + +//template< typename PDLINK > +//void DLINK_Initialize(PDLINK _head) +//{ +// (_head)->_next = (_head)->_prev = (_head); +//} +#define DLINK_Initialize(_head) ((_head)->_next = (_head)->_prev = (_head)) + +//template< typename PDLINK > +//bool DLINK_IsEmpty(PDLINK) +//{ +// return ((_head)->_next == (_head)); +//} +#define DLINK_IsEmpty(_head) ((_head)->_next == (_head)) + +//template< typename PDLINK ,typename PVALUE > +//inline void DLINK_InsertNext(PDLINK _head,PVALUE _dlink) +//{ +// (_dlink)->_next = (_head)->_next; +// (_dlink)->_prev = (_head); +// (_head)->_next->_prev = (_dlink); +// (_head)->_next = (_dlink); +//} +#define DLINK_InsertNext(_head,_dlink) (_dlink)->_next = (_head)->_next;\ + (_dlink)->_prev = (_head);\ + (_head)->_next->_prev = (_dlink);\ + (_head)->_next = (_dlink) + +//template< typename PDLINK ,typename PVALUE > +//inline void DLINK_InsertPrev(PDLINK _head,PVALUE _dlink ) +//{ +// (_dlink)->_prev = (_head)->_prev; +// (_dlink)->_next = (_head); +// (_head)->_prev->_next = (_dlink); +// (_head)->_prev = (_dlink); +//} +#define DLINK_InsertPrev(_head,_dlink) (_dlink)->_prev = (_head)->_prev;\ + (_dlink)->_next = (_head);\ + (_head)->_prev->_next = (_dlink);\ + (_head)->_prev = (_dlink) +//template< typename PDLINK > +//inline void DLINK_Remove(PDLINK _dlink) +//{ +// (_dlink)->_prev->_next = (_dlink)->_next; +// (_dlink)->_next->_prev = (_dlink)->_prev; +//} +#define DLINK_Remove(_dlink) (_dlink)->_prev->_next = (_dlink)->_next;\ + (_dlink)->_next->_prev = (_dlink)->_prev +//template< typename PDLINK ,typename PVALUE > +//inline PVALUE DLINK_ExtructPrev(PDLINK _head ) +//{ +// PVALUE v = (_head)->_prev; +// DLINK_Remove((_head)->_prev); +// return v; +//} +#define DLINK_ExtructPrev(_head) (_head)->_prev;\ + DLINK_Remove((_head)->_prev) +//template< typename PDLINK ,typename PVALUE > +//inline PVALUE DLINK_ExtructNext(PDLINK _head) +//{ +// PVALUE v = (_head)->_next; +// DLINK_Remove((_head)->_next); +// return v; +//} +#define DLINK_ExtructNext(_head) (_head)->_next;\ + DLINK_Remove((_head)->_next) + + +#endif // _linklist_h_ diff --git a/deps/uv/include/uv-private/uv-win.h b/deps/uv/include/uv-private/uv-win.h index 372d65c67eb..f9a9a538a74 100644 --- a/deps/uv/include/uv-private/uv-win.h +++ b/deps/uv/include/uv-private/uv-win.h @@ -62,6 +62,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); uv_handle_t* endgame_handles; \ /* The head of the timers tree */ \ struct uv_timer_tree_s timers; \ + /* The head of the timers tree */ \ + struct uv_signal_s signal_handles; \ /* Lists of active loop (prepare / check / idle) watchers */ \ uv_prepare_t* prepare_handles; \ uv_check_t* check_handles; \ @@ -182,6 +184,12 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); struct { uv_pipe_connection_fields }; \ }; +#define UV_SIGNAL_PRIVATE_FIELDS \ + struct uv_signal_s* _prev; \ + struct uv_signal_s* _next; \ + int signum; \ + uv_signal_cb signal_cb; + /* TODO: put the parser states in an union - TTY handles are always */ /* half-duplex so read-state can safely overlap write-state. */ #define UV_TTY_PRIVATE_FIELDS \ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index b8bdc093022..f37d8571c75 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -51,6 +51,7 @@ typedef struct uv_udp_s uv_udp_t; typedef struct uv_pipe_s uv_pipe_t; typedef struct uv_tty_s uv_tty_t; typedef struct uv_timer_s uv_timer_t; +typedef struct uv_signal_s uv_signal_t; typedef struct uv_prepare_s uv_prepare_t; typedef struct uv_check_s uv_check_t; typedef struct uv_idle_s uv_idle_t; @@ -127,6 +128,7 @@ typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status); typedef void (*uv_connection_cb)(uv_stream_t* server, int status); typedef void (*uv_close_cb)(uv_handle_t* handle); typedef void (*uv_timer_cb)(uv_timer_t* handle, int status); +typedef void (*uv_signal_cb)(uv_signal_t* handle, int status); /* TODO: do these really need a status argument? */ typedef void (*uv_async_cb)(uv_async_t* handle, int status); typedef void (*uv_prepare_cb)(uv_prepare_t* handle, int status); @@ -213,7 +215,8 @@ typedef enum { UV_ARES_TASK, UV_ARES_EVENT, UV_PROCESS, - UV_FS_EVENT + UV_FS_EVENT, + UV_SIGNAL } uv_handle_type; typedef enum { @@ -739,6 +742,28 @@ int uv_async_init(uv_loop_t*, uv_async_t* async, uv_async_cb async_cb); int uv_async_send(uv_async_t* async); + +/* + * uv_signal_t is a subclass of uv_handle_t. + * + * Wraps libev's ev_signal watcher. Used to get woken up at a specified time + * in the future. + */ +struct uv_signal_s { + UV_HANDLE_FIELDS + UV_SIGNAL_PRIVATE_FIELDS +}; + + +void uv_signal_registerHandler(uv_loop_t* loop); +void uv_signal_unregisterHandler(uv_loop_t* loop); + +int uv_signal_init(uv_loop_t*, uv_signal_t* handle, uv_signal_cb cb, int signum); + +int uv_signal_start(uv_signal_t* handle); + +int uv_signal_stop(uv_signal_t* handle); + /* * uv_timer_t is a subclass of uv_handle_t. * diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index cb4a28b8238..2331950bd12 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -70,6 +70,7 @@ static void uv_loop_init(uv_loop_t* loop) { loop->endgame_handles = NULL; RB_INIT(&loop->timers); + DLINK_Initialize(&loop->signal_handles); loop->check_handles = NULL; loop->prepare_handles = NULL; diff --git a/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c index b67139cbc6a..c4bfe0d69d2 100644 --- a/deps/uv/src/win/handle.c +++ b/deps/uv/src/win/handle.c @@ -52,6 +52,7 @@ uv_handle_type uv_guess_handle(uv_file file) { int uv_is_active(uv_handle_t* handle) { switch (handle->type) { + case UV_SIGNAL: case UV_TIMER: case UV_IDLE: case UV_PREPARE: @@ -117,6 +118,11 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { uv_want_endgame(loop, handle); } return; + + case UV_SIGNAL: + uv_signal_stop((uv_signal_t*)handle); + uv_want_endgame(loop, handle); + return; case UV_TIMER: uv_timer_stop((uv_timer_t*)handle); @@ -196,6 +202,10 @@ void uv_process_endgames(uv_loop_t* loop) { uv_udp_endgame(loop, (uv_udp_t*) handle); break; + case UV_SIGNAL: + uv_signal_endgame(loop, (uv_signal_t*) handle); + break; + case UV_TIMER: uv_timer_endgame(loop, (uv_timer_t*) handle); break; diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index fa20e4660cf..c7d48f0f952 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -26,10 +26,16 @@ #include "../uv-common.h" #include "tree.h" +#include "linklist.h" #include "winapi.h" #include "winsock.h" +/** + * signal + */ +void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle); + /* * Timers */ diff --git a/deps/uv/src/win/signal.c b/deps/uv/src/win/signal.c new file mode 100644 index 00000000000..c142f9909c5 --- /dev/null +++ b/deps/uv/src/win/signal.c @@ -0,0 +1,244 @@ +/* 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 +#include +#include +#include + +#include "uv.h" +#include "internal.h" + + + +static uv_once_t uv_signal_init_guard_ = UV_ONCE_INIT; +CRITICAL_SECTION uv_signal_data_guard_; +uv_loop_t** uv_loops_; +size_t uv_loop_capcity_; +size_t uv_loop_count_; + + +static void uv_signal_async(uv_loop_t* loop, int type); + + + +void uv_signal_ctrlHandler(int sigact) +{ + size_t index; + signal(sigact, &uv_signal_ctrlHandler); + + EnterCriticalSection(&uv_signal_data_guard_); + + for(index = 0; index < uv_loop_count_; ++ index) + { + uv_signal_async(uv_loops_[index], sigact); + } + + LeaveCriticalSection(&uv_signal_data_guard_); + + +} + +BOOL WINAPI uv_signal_consoleHandler(DWORD fdwCtrlType ) +{ + int type; + + switch(fdwCtrlType){ + case CTRL_C_EVENT: + type = SIGINT; + break; + case CTRL_BREAK_EVENT: + type = SIGBREAK; + break; + case CTRL_CLOSE_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + default: + return FALSE; + } + uv_signal_ctrlHandler(type); + return FALSE; +} + +void uv_signal_system_init(void) +{ + uv_loop_capcity_ = 64; + uv_loops_ = (uv_loop_t**)malloc(sizeof(uv_loop_t*)*uv_loop_capcity_); + uv_loop_count_ = 0; + + InitializeCriticalSection(&uv_signal_data_guard_); + + //SetConsoleCtrlHandler(&uv_signal_consoleHandler, TRUE); + signal(SIGINT, &uv_signal_ctrlHandler); + signal(SIGBREAK, &uv_signal_ctrlHandler); + + signal(SIGILL, &uv_signal_ctrlHandler); + signal(SIGFPE, &uv_signal_ctrlHandler); + signal(SIGSEGV, &uv_signal_ctrlHandler); + signal(SIGTERM, &uv_signal_ctrlHandler); + signal(SIGABRT, &uv_signal_ctrlHandler); +} + +void uv_signal_registerHandler(uv_loop_t* loop) +{ + size_t index; + + uv_once(&uv_signal_init_guard_, &uv_signal_system_init); + + EnterCriticalSection(&uv_signal_data_guard_); + + for(index = 0; index < uv_loop_count_; ++ index) + { + if(uv_loops_[index] == loop) + goto end; + } + + if(uv_loop_count_ >= uv_loop_capcity_) + { + uv_loop_capcity_ *= 2; + uv_loops_ = (uv_loop_t**)realloc(uv_loops_, sizeof(uv_loop_t*)*uv_loop_capcity_); + } + + uv_loops_[uv_loop_count_ ++ ] = loop; + uv_ref(loop); +end: + LeaveCriticalSection(&uv_signal_data_guard_); +} + + +void uv_signal_unregisterHandler(uv_loop_t* loop) +{ + size_t index; + + uv_once(&uv_signal_init_guard_, &uv_signal_system_init); + + EnterCriticalSection(&uv_signal_data_guard_); + + for(index = 0; index < uv_loop_count_; ++ index) + { + if(uv_loops_[index] == loop) + { + memmove(&uv_loops_[index], &uv_loops_[index+1], uv_loop_count_ - index -1); + -- uv_loop_count_; + uv_unref(loop); + goto end; + } + } + +end: + LeaveCriticalSection(&uv_signal_data_guard_); +} + + +int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + loop->counters.handle_init++; + loop->counters.timer_init++; + + handle->type = UV_SIGNAL; + handle->loop = loop; + handle->flags = 0; + handle->_next = NULL; + handle->_prev = NULL; + + + handle->signal_cb = signal_cb; + handle->signum = signum; + + uv_ref(loop); + + return 0; +} + + +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; + + if (handle->close_cb) { + handle->close_cb((uv_handle_t*)handle); + } + + uv_unref(loop); + } +} + + +int uv_signal_start(uv_signal_t* handle) { + uv_loop_t* loop = handle->loop; + + handle->flags |= UV_HANDLE_ACTIVE; + + DLINK_InsertNext(&loop->signal_handles, handle); + + return 0; +} + + +int uv_signal_stop(uv_signal_t* handle) { + uv_loop_t* loop = handle->loop; + + if (!(handle->flags & UV_HANDLE_ACTIVE)) + return 0; + + DLINK_Remove(handle); + handle->_next = NULL; + handle->_prev = NULL; + + handle->flags &= ~UV_HANDLE_ACTIVE; + return 0; +} + + +typedef struct signal_data_s { + struct uv_async_s async; + int signum; +} signal_data_t; + + +static void on_async_close(uv_handle_t* handle) { + signal_data_t* data = (signal_data_t*)((uv_async_t*)handle)->data; + free(data); +} + +void uv_signal_handler(uv_async_t* async, int signal) { + signal_data_t* data = (signal_data_t*)async->data; + + uv_signal_t* head = &(async->loop->signal_handles); + uv_signal_t* handle = head; + while(head != (handle = handle->_next)) { + if(handle->signum == data->signum) { + handle->signal_cb(handle, data->signum); + } + } + + uv_close((uv_handle_t*)async, on_async_close); +} + + +static void uv_signal_async(uv_loop_t* loop, int type) +{ + signal_data_t* async = (signal_data_t*)malloc(sizeof(signal_data_t)); + uv_async_init(loop, &async->async, &uv_signal_handler); + async->signum = type; + async->async.data = async; + uv_async_send(&async->async); +} \ No newline at end of file diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c index 476496759f0..27139016a62 100644 --- a/deps/uv/src/win/stream.c +++ b/deps/uv/src/win/stream.c @@ -93,7 +93,7 @@ int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, int uv_read_stop(uv_stream_t* handle) { - if (handle->type = UV_TTY) { + if (handle->type == UV_TTY) { return uv_tty_read_stop((uv_tty_t*) handle); } else { handle->flags &= ~UV_HANDLE_READING; diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 1d243c48f2d..353edd911ad 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -96,6 +96,7 @@ TEST_DECLARE (fs_event_watch_file) TEST_DECLARE (fs_event_watch_file_current_dir) TEST_DECLARE (threadpool_queue_work_simple) #ifdef _WIN32 +TEST_DECLARE (signal) TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) TEST_DECLARE (argument_escaping) TEST_DECLARE (environment_creation) @@ -203,6 +204,7 @@ TASK_LIST_START TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows) TEST_ENTRY (argument_escaping) TEST_ENTRY (environment_creation) + TEST_ENTRY (signal) #endif TEST_ENTRY (fs_file_noent) diff --git a/deps/uv/test/test-signal.c b/deps/uv/test/test-signal.c new file mode 100644 index 00000000000..e9f716ddb98 --- /dev/null +++ b/deps/uv/test/test-signal.c @@ -0,0 +1,189 @@ +/* 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" +#include + + +static int sigint_called = 0; +static int sigbreak_called = 0; +static int sigill_called = 0; +static int sigfpe_called = 0; +static int sigsegv_called = 0; +static int sigterm_called = 0; +static int sigabrt_called = 0; + + +static int sigint_closed = 0; +static int sigbreak_closed = 0; +static int sigill_closed = 0; +static int sigfpe_closed = 0; +static int sigsegv_closed = 0; +static int sigterm_closed = 0; +static int sigabrt_closed = 0; + + + +static void signal_cb(uv_signal_t* handle, int signum) { + switch(signum){ + case SIGINT: + sigint_called ++; + break; + case SIGBREAK: + sigbreak_called++; + break; + case SIGILL: + sigill_called ++; + break; + case SIGFPE: + sigfpe_called ++; + break; + case SIGSEGV: + sigsegv_called ++; + break; + case SIGTERM: + sigterm_called ++; + break; + case SIGABRT: + sigabrt_called ++; + break; + default: + FATAL("signal_cb be called with unkown signal"); + } +} + + +static void never_cb(uv_timer_t* handle, int status) { + FATAL("never_cb should never be called"); +} + + +TEST_IMPL(signal) { + uv_signal_t sigint; + uv_signal_t sigbreak; + uv_signal_t sigill; + uv_signal_t sigfpe; + uv_signal_t sigsegv; + uv_signal_t sigterm; + uv_signal_t sigabrt; + + uv_signal_registerHandler(uv_default_loop()); + + uv_signal_init(uv_default_loop(), &sigint, &signal_cb, SIGINT); + uv_signal_init(uv_default_loop(), &sigbreak, &signal_cb, SIGBREAK); + uv_signal_init(uv_default_loop(), &sigill, &signal_cb, SIGILL); + uv_signal_init(uv_default_loop(), &sigfpe, &signal_cb, SIGFPE); + uv_signal_init(uv_default_loop(), &sigsegv, &signal_cb, SIGSEGV); + uv_signal_init(uv_default_loop(), &sigterm, &signal_cb, SIGTERM); + uv_signal_init(uv_default_loop(), &sigabrt, &signal_cb, SIGABRT); + + + + uv_signal_start(&sigint); + uv_signal_start(&sigbreak); + uv_signal_start(&sigill); + uv_signal_start(&sigfpe); + uv_signal_start(&sigsegv); + uv_signal_start(&sigterm); + uv_signal_start(&sigabrt); + + + uv_unref(uv_default_loop()); + uv_unref(uv_default_loop()); + uv_unref(uv_default_loop()); + uv_unref(uv_default_loop()); + uv_unref(uv_default_loop()); + uv_unref(uv_default_loop()); + uv_unref(uv_default_loop()); + uv_unref(uv_default_loop()); + + raise(SIGINT); + uv_run(uv_default_loop()); + ASSERT(sigint_called == 1); + raise(SIGINT); + uv_run(uv_default_loop()); + ASSERT(sigint_called == 2); + raise(SIGBREAK); + uv_run(uv_default_loop()); + ASSERT(sigbreak_called == 1); + + raise(SIGILL); + uv_run(uv_default_loop()); + ASSERT(sigill_called == 1); + raise(SIGFPE); + uv_run(uv_default_loop()); + ASSERT(sigfpe_called == 1); + raise(SIGSEGV); + uv_run(uv_default_loop()); + ASSERT(sigsegv_called == 1); + raise(SIGTERM); + uv_run(uv_default_loop()); + ASSERT(sigterm_called == 1); + raise(SIGABRT); + uv_run(uv_default_loop()); + ASSERT(sigabrt_called == 1); + + + ASSERT(sigint_called == 2); + ASSERT(sigbreak_called == 1); + ASSERT(sigill_called == 1); + ASSERT(sigfpe_called == 1); + ASSERT(sigsegv_called == 1); + ASSERT(sigterm_called == 1); + ASSERT(sigabrt_called == 1); + + + uv_signal_stop(&sigint); + uv_signal_stop(&sigbreak); + uv_signal_stop(&sigill); + uv_signal_stop(&sigfpe); + uv_signal_stop(&sigsegv); + uv_signal_stop(&sigterm); + uv_signal_stop(&sigabrt); + + + raise(SIGINT); + raise(SIGBREAK); + raise(SIGILL); + raise(SIGFPE); + raise(SIGSEGV); + raise(SIGTERM); + raise(SIGABRT); + uv_run(uv_default_loop()); + uv_run(uv_default_loop()); + uv_run(uv_default_loop()); + uv_run(uv_default_loop()); + uv_run(uv_default_loop()); + uv_run(uv_default_loop()); + uv_run(uv_default_loop()); + uv_run(uv_default_loop()); + + ASSERT(sigint_called == 2); + ASSERT(sigbreak_called == 1); + ASSERT(sigill_called == 1); + ASSERT(sigfpe_called == 1); + ASSERT(sigsegv_called == 1); + ASSERT(sigterm_called == 1); + ASSERT(sigabrt_called == 1); + + return 0; +} diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index e32dddd3b5d..f4face3f90f 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -124,6 +124,8 @@ 'src/win/winapi.h', 'src/win/winsock.c', 'src/win/winsock.h', + 'include/uv-private/linklist.h', + 'src/win/signal.c', ], 'link_settings': { 'libraries': [ @@ -266,6 +268,7 @@ 'test/test-udp-dgram-too-big.c', 'test/test-udp-ipv6.c', 'test/test-udp-send-and-recv.c', + 'test/test-signal.c', ], 'conditions': [ [ 'OS=="win"', { diff --git a/node.gyp b/node.gyp index 5fe87dec1b7..3a43dbad2f9 100644 --- a/node.gyp +++ b/node.gyp @@ -163,6 +163,7 @@ 'src/node_stdio_win32.cc', # headers to make for a more pleasant IDE experience 'src/platform_win32.h', + 'src/signal_wrap.cc', ], 'defines': [ 'FD_SETSIZE=1024', diff --git a/src/signal_wrap.cc b/src/signal_wrap.cc new file mode 100644 index 00000000000..9457b331cc5 --- /dev/null +++ b/src/signal_wrap.cc @@ -0,0 +1,155 @@ +#include +#include + +#define UNWRAP \ + assert(!args.Holder().IsEmpty()); \ + assert(args.Holder()->InternalFieldCount() > 0); \ + SignalWrap* wrap = \ + static_cast(args.Holder()->GetPointerFromInternalField(0)); \ + if (!wrap) { \ + SetErrno(UV_EBADF); \ + return scope.Close(Integer::New(-1)); \ + } + +namespace node { + +using v8::Object; +using v8::Handle; +using v8::Local; +using v8::Persistent; +using v8::Value; +using v8::HandleScope; +using v8::FunctionTemplate; +using v8::String; +using v8::Function; +using v8::TryCatch; +using v8::Context; +using v8::Arguments; +using v8::Integer; + + +class SignalWrap : public HandleWrap { + public: + static void Initialize(Handle target) { + HandleScope scope; + + HandleWrap::Initialize(target); + + Local constructor = FunctionTemplate::New(New); + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(String::NewSymbol("SignalWatcher")); + + NODE_SET_PROTOTYPE_METHOD(constructor, "close", HandleWrap::Close); + + NODE_SET_PROTOTYPE_METHOD(constructor, "start", Start); + NODE_SET_PROTOTYPE_METHOD(constructor, "stop", Stop); + + target->Set(String::NewSymbol("SignalWatcher"), constructor->GetFunction()); + } + + private: + static Handle New(const Arguments& args) { + // This constructor should not be exposed to public javascript. + // Therefore we assert that we are not trying to call this as a + // normal function. + assert(args.IsConstructCall()); + + HandleScope scope; + + if (args.Length() != 1 || !args[0]->IsInt32()) { + return ThrowException(String::New("Bad arguments")); + } + + int sig = args[0]->Int32Value(); + + + SignalWrap *wrap = new SignalWrap(args.This(), sig); + assert(wrap); + + return scope.Close(args.This()); + } + + SignalWrap(Handle object, int sig) + : HandleWrap(object, (uv_handle_t*) &handle_){ + active_ = false; + int r = uv_signal_init(uv_default_loop(), &handle_, OnSignal, sig); + handle_.data = this; + + uv_unref(uv_default_loop()); + } + + ~SignalWrap() { + if (!active_) uv_ref(uv_default_loop()); + } + + void StateChange() { + bool was_active = active_; + active_ = uv_is_active((uv_handle_t*) &handle_); + + if (!was_active && active_) { + // If our state is changing from inactive to active, we + // increase the loop's reference count. + uv_ref(uv_default_loop()); + } else if (was_active && !active_) { + // If our state is changing from active to inactive, we + // decrease the loop's reference count. + uv_unref(uv_default_loop()); + } + } + + static Handle Start(const Arguments& args) { + + HandleScope scope; + + UNWRAP + + + int r = uv_signal_start(&wrap->handle_); + + // Error starting the timer. + if (r) SetErrno(uv_last_error(uv_default_loop()).code); + + wrap->StateChange(); + + return scope.Close(Integer::New(r)); + } + + static Handle Stop(const Arguments& args) { + HandleScope scope; + + UNWRAP + + int r = uv_signal_stop(&wrap->handle_); + + if (r) SetErrno(uv_last_error(uv_default_loop()).code); + + wrap->StateChange(); + + return scope.Close(Integer::New(r)); + } + + + static void OnSignal(uv_signal_t* handle, int type) { + + + SignalWrap* wrap = static_cast(handle->data); + assert(wrap); + + + wrap->StateChange(); + + Local argv[1] = { Integer::New(type) }; + MakeCallback(wrap->object_, "callback", 1, argv); + } + + uv_signal_t handle_; + // This member is set false initially. When the signal is turned + // on uv_ref is called. When the timer is turned off uv_unref is + // called. Used to mirror libev semantics. + bool active_; +}; + + +} // namespace node + +NODE_MODULE(node_signal_watcher, node::SignalWrap::Initialize);