From 7bc449c06329716770d4bbf59b252c66ba17a9d1 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 26 Feb 2013 20:30:12 +0100 Subject: [PATCH] deps: upgrade libuv to a0c1d84 --- deps/uv/build.mk | 1 + deps/uv/common.gypi | 10 +- deps/uv/include/uv-private/uv-unix.h | 24 ++- deps/uv/include/uv.h | 10 ++ deps/uv/src/unix/async.c | 243 +++++++++++++++++++++------ deps/uv/src/unix/core.c | 28 ++- deps/uv/src/unix/fs.c | 1 + deps/uv/src/unix/internal.h | 10 +- deps/uv/src/unix/loop.c | 15 +- deps/uv/src/unix/proctitle.c | 73 +++----- deps/uv/src/unix/udp.c | 86 +++++----- deps/uv/src/uv-common.c | 52 ++++++ deps/uv/src/uv-common.h | 19 +++ deps/uv/src/win/core.c | 33 +++- deps/uv/src/win/udp.c | 38 ++--- deps/uv/test/runner.c | 7 +- deps/uv/test/test-list.h | 2 + deps/uv/test/test-loop-stop.c | 73 ++++++++ deps/uv/uv.gyp | 4 +- deps/uv/vcbuild.bat | 2 +- 20 files changed, 526 insertions(+), 205 deletions(-) create mode 100644 deps/uv/test/test-loop-stop.c diff --git a/deps/uv/build.mk b/deps/uv/build.mk index 88de949dd3..a19db4948d 100644 --- a/deps/uv/build.mk +++ b/deps/uv/build.mk @@ -85,6 +85,7 @@ TESTS= \ test/test-ipc.o \ test/test-ipc-send-recv.o \ test/test-loop-handles.o \ + test/test-loop-stop.o \ test/test-multiple-listen.o \ test/test-mutexes.o \ test/test-pass-always.o \ diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi index c3d9527cc8..8c6c887584 100644 --- a/deps/uv/common.gypi +++ b/deps/uv/common.gypi @@ -45,7 +45,13 @@ }, 'Release': { 'defines': [ 'NDEBUG' ], - 'cflags': [ '-O3', '-fomit-frame-pointer', '-fdata-sections', '-ffunction-sections' ], + 'cflags': [ + '-O3', + '-fstrict-aliasing', + '-fomit-frame-pointer', + '-fdata-sections', + '-ffunction-sections', + ], 'msvs_settings': { 'VCCLCompilerTool': { 'target_conditions': [ @@ -163,7 +169,7 @@ 'PREBINDING': 'NO', # No -Wl,-prebind 'USE_HEADERMAP': 'NO', 'OTHER_CFLAGS': [ - '-fno-strict-aliasing', + '-fstrict-aliasing', ], 'WARNING_CFLAGS': [ '-Wall', diff --git a/deps/uv/include/uv-private/uv-unix.h b/deps/uv/include/uv-private/uv-unix.h index fe32c4b8ac..729082e0bc 100644 --- a/deps/uv/include/uv-private/uv-unix.h +++ b/deps/uv/include/uv-private/uv-unix.h @@ -54,9 +54,6 @@ # include "uv-bsd.h" #endif -struct uv__io_s; -struct uv_loop_s; - #ifndef UV_IO_PRIVATE_PLATFORM_FIELDS # define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */ #endif @@ -64,6 +61,10 @@ struct uv_loop_s; #define UV_IO_PRIVATE_FIELDS \ UV_IO_PRIVATE_PLATFORM_FIELDS \ +struct uv__io_s; +struct uv__async; +struct uv_loop_s; + typedef void (*uv__io_cb)(struct uv_loop_s* loop, struct uv__io_s* w, unsigned int events); @@ -79,6 +80,16 @@ struct uv__io_s { UV_IO_PRIVATE_FIELDS }; +typedef void (*uv__async_cb)(struct uv_loop_s* loop, + struct uv__async* w, + unsigned int nevents); + +struct uv__async { + uv__async_cb cb; + uv__io_t io_watcher; + int wfd; +}; + struct uv__work { void (*work)(struct uv__work *w); void (*done)(struct uv__work *w, int status); @@ -167,8 +178,7 @@ typedef struct { ngx_queue_t check_handles; \ ngx_queue_t idle_handles; \ ngx_queue_t async_handles; \ - uv__io_t async_watcher; \ - int async_pipefd[2]; \ + struct uv__async async_watcher; \ /* RB_HEAD(uv__timers, uv_timer_s) */ \ struct uv__timers { \ struct uv_timer_s* rbh_root; \ @@ -252,9 +262,9 @@ typedef struct { ngx_queue_t queue; #define UV_ASYNC_PRIVATE_FIELDS \ - volatile sig_atomic_t pending; \ uv_async_cb async_cb; \ - ngx_queue_t queue; + ngx_queue_t queue; \ + int pending; \ #define UV_TIMER_PRIVATE_FIELDS \ /* RB_ENTRY(uv_timer_s) tree_entry; */ \ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 4d6a2e80cd..de375d4b0e 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -258,6 +258,14 @@ UV_EXTERN uv_loop_t* uv_default_loop(void); */ UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode); +/* + * This function will stop the event loop by forcing uv_run to end + * as soon as possible, but not sooner than the next loop iteration. + * If this function was called before blocking for i/o, the loop won't + * block for i/o on this iteration. + */ +UV_EXTERN void uv_stop(uv_loop_t*); + /* * Manually modify the event loop's reference count. Useful if the user wants * to have a handle or timeout that doesn't keep the loop alive. @@ -1934,6 +1942,8 @@ struct uv_loop_s { unsigned int active_handles; ngx_queue_t handle_queue; ngx_queue_t active_reqs; + /* Internal flag to signal loop stop */ + unsigned int stop_flag; UV_LOOP_PRIVATE_FIELDS }; diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c index 322167c68c..43f54ed4b2 100644 --- a/deps/uv/src/unix/async.c +++ b/deps/uv/src/unix/async.c @@ -18,21 +18,73 @@ * IN THE SOFTWARE. */ +/* This file contains both the uv__async internal infrastructure and the + * user-facing uv_async_t functions. + */ + #include "uv.h" #include "internal.h" #include #include #include +#include #include -static int uv__async_init(uv_loop_t* loop); -static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); +static void uv__async_event(uv_loop_t* loop, + struct uv__async* w, + unsigned int nevents); +static int uv__async_make_pending(int* pending); +static int uv__async_eventfd(void); + + +int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { + if (uv__async_start(loop, &loop->async_watcher, uv__async_event)) + return uv__set_sys_error(loop, errno); + uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC); + handle->async_cb = async_cb; + handle->pending = 0; + + ngx_queue_insert_tail(&loop->async_handles, &handle->queue); + uv__handle_start(handle); + + return 0; +} -static int uv__async_make_pending(volatile sig_atomic_t* ptr) { + +int uv_async_send(uv_async_t* handle) { + if (uv__async_make_pending(&handle->pending) == 0) + uv__async_send(&handle->loop->async_watcher); + + return 0; +} + + +void uv__async_close(uv_async_t* handle) { + ngx_queue_remove(&handle->queue); + uv__handle_stop(handle); +} + + +static void uv__async_event(uv_loop_t* loop, + struct uv__async* w, + unsigned int nevents) { + ngx_queue_t* q; + uv_async_t* h; + + ngx_queue_foreach(q, &loop->async_handles) { + h = ngx_queue_data(q, uv_async_t, queue); + if (!h->pending) continue; + h->pending = 0; + h->async_cb(h, 0); + } +} + + +static int uv__async_make_pending(int* pending) { /* Do a cheap read first. */ - if (*ptr) + if (ACCESS_ONCE(int, *pending) != 0) return 1; /* Micro-optimization: use atomic memory operations to detect if we've been @@ -47,100 +99,183 @@ static int uv__async_make_pending(volatile sig_atomic_t* ptr) { #if defined(__i386__) || defined(__x86_64__) { unsigned int val = 1; - __asm__ __volatile__("xchgl %0, %1" : "+r" (val) : "m" (*ptr)); + __asm__ __volatile__ ("xchgl %0, %1" + : "+r" (val) + : "m" (*pending)); return val != 0; } #elif defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ > 0) - return __sync_val_compare_and_swap(ptr, 0, 1) != 0; + return __sync_val_compare_and_swap(pending, 0, 1) != 0; #else - *ptr = 1; + ACCESS_ONCE(int, *pending) = 1; return 0; #endif } -int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { - if (uv__async_init(loop)) - return uv__set_sys_error(loop, errno); +static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + struct uv__async* wa; + char buf[1024]; + unsigned n; + ssize_t r; - uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC); - handle->async_cb = async_cb; - handle->pending = 0; + n = 0; + for (;;) { + r = read(w->fd, buf, sizeof(buf)); - ngx_queue_insert_tail(&loop->async_handles, &handle->queue); - uv__handle_start(handle); + if (r > 0) + n += r; - return 0; + if (r == sizeof(buf)) + continue; + + if (r != -1) + break; + + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + + if (errno == EINTR) + continue; + + abort(); + } + + wa = container_of(w, struct uv__async, io_watcher); + +#if defined(__linux__) + if (wa->wfd == -1) { + uint64_t val; + assert(n == sizeof(val)); + memcpy(&val, buf, sizeof(val)); /* Avoid alignment issues. */ + wa->cb(loop, wa, val); + return; + } +#endif + + wa->cb(loop, wa, n); } -int uv_async_send(uv_async_t* handle) { +void uv__async_send(struct uv__async* wa) { + const void* buf; + ssize_t len; + int fd; int r; - if (uv__async_make_pending(&handle->pending)) - return 0; /* already pending */ + buf = ""; + len = 1; + fd = wa->wfd; + +#if defined(__linux__) + if (fd == -1) { + static const uint64_t val = 1; + buf = &val; + len = sizeof(val); + fd = wa->io_watcher.fd; /* eventfd */ + } +#endif do - r = write(handle->loop->async_pipefd[1], "x", 1); + r = write(fd, buf, len); while (r == -1 && errno == EINTR); - assert(r == -1 || r == 1); + if (r == len) + return; - if (r == -1 && errno != EAGAIN && errno != EWOULDBLOCK) - return uv__set_sys_error(handle->loop, errno); + if (r == -1) + if (errno == EAGAIN || errno == EWOULDBLOCK) + return; - return 0; + abort(); } -void uv__async_close(uv_async_t* handle) { - ngx_queue_remove(&handle->queue); - uv__handle_stop(handle); +void uv__async_init(struct uv__async* wa) { + wa->io_watcher.fd = -1; + wa->wfd = -1; } -static int uv__async_init(uv_loop_t* loop) { - if (loop->async_pipefd[0] != -1) +int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) { + int pipefd[2]; + int fd; + + if (wa->io_watcher.fd != -1) return 0; - if (uv__make_pipe(loop->async_pipefd, UV__F_NONBLOCK)) + fd = uv__async_eventfd(); + if (fd >= 0) { + pipefd[0] = fd; + pipefd[1] = -1; + } + else if (fd != -ENOSYS) + return -1; + else if (uv__make_pipe(pipefd, UV__F_NONBLOCK)) return -1; - uv__io_init(&loop->async_watcher, uv__async_io, loop->async_pipefd[0]); - uv__io_start(loop, &loop->async_watcher, UV__POLLIN); + uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]); + uv__io_start(loop, &wa->io_watcher, UV__POLLIN); + wa->wfd = pipefd[1]; + wa->cb = cb; return 0; } -static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - char buf[1024]; - ngx_queue_t* q; - uv_async_t* h; - ssize_t r; +void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) { + if (wa->io_watcher.fd == -1) + return; - while (1) { - r = read(loop->async_pipefd[0], buf, sizeof(buf)); + uv__io_stop(loop, &wa->io_watcher, UV__POLLIN); + close(wa->io_watcher.fd); + wa->io_watcher.fd = -1; - if (r == sizeof(buf)) - continue; + if (wa->wfd != -1) { + close(wa->wfd); + wa->wfd = -1; + } +} - if (r != -1) - break; - if (errno == EAGAIN || errno == EWOULDBLOCK) - break; +static int uv__async_eventfd() { +#if defined(__linux__) + static int no_eventfd2; + static int no_eventfd; + int fd; - if (errno == EINTR) - continue; + if (no_eventfd2) + goto skip_eventfd2; - abort(); - } + fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK); + if (fd != -1) + return fd; - ngx_queue_foreach(q, &loop->async_handles) { - h = ngx_queue_data(q, uv_async_t, queue); - if (!h->pending) continue; - h->pending = 0; - h->async_cb(h, 0); + if (errno != ENOSYS) + return -errno; + + no_eventfd2 = 1; + +skip_eventfd2: + + if (no_eventfd) + goto skip_eventfd; + + fd = uv__eventfd(0); + if (fd != -1) { + uv__cloexec(fd, 1); + uv__nonblock(fd, 1); + return fd; } + + if (errno != ENOSYS) + return -errno; + + no_eventfd = 1; + +skip_eventfd: + +#endif + + return -ENOSYS; } diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index e5c9a4d98a..a281f2e081 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -259,6 +259,9 @@ int uv_backend_fd(const uv_loop_t* loop) { int uv_backend_timeout(const uv_loop_t* loop) { + if (loop->stop_flag != 0) + return 0; + if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) return 0; @@ -280,22 +283,35 @@ static int uv__loop_alive(uv_loop_t* loop) { int uv_run(uv_loop_t* loop, uv_run_mode mode) { + int timeout; int r; - if (!uv__loop_alive(loop)) - return 0; - - do { + r = uv__loop_alive(loop); + while (r != 0 && loop->stop_flag == 0) { uv__update_time(loop); uv__run_timers(loop); uv__run_idle(loop); uv__run_prepare(loop); uv__run_pending(loop); - uv__io_poll(loop, (mode & UV_RUN_NOWAIT ? 0 : uv_backend_timeout(loop))); + + timeout = 0; + if ((mode & UV_RUN_NOWAIT) == 0) + timeout = uv_backend_timeout(loop); + + uv__io_poll(loop, timeout); uv__run_check(loop); uv__run_closing_handles(loop); r = uv__loop_alive(loop); - } while (r && !(mode & (UV_RUN_ONCE | UV_RUN_NOWAIT))); + + if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT)) + break; + } + + /* The if statement lets gcc compile it to a conditional store. Avoids + * dirtying a cache line. + */ + if (loop->stop_flag != 0) + loop->stop_flag = 0; return r; } diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index f9181df127..53f46ce7c7 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -374,6 +374,7 @@ static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) { while (n == -1 && errno == EINTR); if (n == -1 || (pfd.revents & ~POLLOUT) != 0) { + errno = EIO; nsent = -1; goto out; } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index d6d2e45fd1..7d08c1dac9 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -45,6 +45,9 @@ # include #endif +#define ACCESS_ONCE(type, var) \ + (*(volatile type*) &(var)) + #define UNREACHABLE() \ do { \ assert(0 && "unreachable code"); \ @@ -111,7 +114,6 @@ int uv__nonblock(int fd, int set); int uv__cloexec(int fd, int set); int uv__socket(int domain, int type, int protocol); int uv__dup(int fd); -int uv_async_stop(uv_async_t* handle); void uv__make_close_pending(uv_handle_t* handle); void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd); @@ -122,6 +124,12 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w); int uv__io_active(const uv__io_t* w, unsigned int events); void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ +/* async */ +void uv__async_send(struct uv__async* wa); +void uv__async_init(struct uv__async* wa); +int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb); +void uv__async_stop(uv_loop_t* loop, struct uv__async* wa); + /* loop */ int uv__loop_init(uv_loop_t* loop, int default_loop); void uv__loop_delete(uv_loop_t* loop); diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index 9935310749..75b0702a3a 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -50,14 +50,14 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) { loop->closing_handles = NULL; loop->time = uv__hrtime() / 1000000; - loop->async_pipefd[0] = -1; - loop->async_pipefd[1] = -1; + uv__async_init(&loop->async_watcher); loop->signal_pipefd[0] = -1; loop->signal_pipefd[1] = -1; loop->backend_fd = -1; loop->emfile_fd = -1; loop->timer_counter = 0; + loop->stop_flag = 0; if (uv__platform_loop_init(loop, default_loop)) return -1; @@ -85,16 +85,7 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) { void uv__loop_delete(uv_loop_t* loop) { uv__signal_loop_cleanup(loop); uv__platform_loop_delete(loop); - - if (loop->async_pipefd[0] != -1) { - close(loop->async_pipefd[0]); - loop->async_pipefd[0] = -1; - } - - if (loop->async_pipefd[1] != -1) { - close(loop->async_pipefd[1]); - loop->async_pipefd[1] = -1; - } + uv__async_stop(loop, &loop->async_watcher); if (loop->emfile_fd != -1) { close(loop->emfile_fd); diff --git a/deps/uv/src/unix/proctitle.c b/deps/uv/src/unix/proctitle.c index c4043af311..6728e2387f 100644 --- a/deps/uv/src/unix/proctitle.c +++ b/deps/uv/src/unix/proctitle.c @@ -30,68 +30,45 @@ static void* args_mem; static struct { char* str; - int len; + size_t len; } process_title; char** uv_setup_args(int argc, char** argv) { char** new_argv; - char** new_env; size_t size; - int envc; char* s; int i; -#if defined(__APPLE__) - char*** _NSGetArgv(void); - char*** _NSGetEnviron(void); - char** environ = *_NSGetEnviron(); -#else - extern char** environ; -#endif - - for (envc = 0; environ[envc]; envc++); + if (argc <= 0) + return argv; - if (envc == 0) - s = argv[argc - 1]; - else - s = environ[envc - 1]; + /* Calculate how much memory we need for the argv strings. */ + size = 0; + for (i = 0; i < argc; i++) + size += strlen(argv[i]) + 1; process_title.str = argv[0]; - process_title.len = s + strlen(s) + 1 - argv[0]; + process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0]; + assert(process_title.len + 1 == size); /* argv memory should be adjacent. */ - size = process_title.len; - size += (argc + 1) * sizeof(char**); - size += (envc + 1) * sizeof(char**); - s = args_mem = malloc(size); + /* Add space for the argv pointers. */ + size += (argc + 1) * sizeof(char*); - if (s == NULL) { - process_title.str = NULL; - process_title.len = 0; + new_argv = malloc(size); + if (new_argv == NULL) return argv; + args_mem = new_argv; + + /* Copy over the strings and set up the pointer table. */ + s = (char*) &new_argv[argc + 1]; + for (i = 0; i < argc; i++) { + size = strlen(argv[i]) + 1; + memcpy(s, argv[i], size); + new_argv[i] = s; + s += size; } - - new_argv = (char**) s; - new_env = new_argv + argc + 1; - s = (char*) (new_env + envc + 1); - memcpy(s, process_title.str, process_title.len); - - for (i = 0; i < argc; i++) - new_argv[i] = s + (argv[i] - argv[0]); - new_argv[argc] = NULL; - - s += environ[0] - argv[0]; - - for (i = 0; i < envc; i++) - new_env[i] = s + (environ[i] - environ[0]); - new_env[envc] = NULL; - -#if defined(__APPLE__) - *_NSGetArgv() = new_argv; - *_NSGetEnviron() = new_env; -#else - environ = new_env; -#endif + new_argv[i] = NULL; return new_argv; } @@ -101,8 +78,8 @@ uv_err_t uv_set_process_title(const char* title) { if (process_title.len == 0) return uv_ok_; - /* No need to terminate, last char is always '\0'. */ - strncpy(process_title.str, title, process_title.len - 1); + /* No need to terminate, byte after is always '\0'. */ + strncpy(process_title.str, title, process_title.len); uv__set_process_title(title); return uv_ok_; diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 56c1b25072..49028985d6 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -35,13 +35,13 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents); static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents); static void uv__udp_sendmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents); static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain); -static int uv__udp_send(uv_udp_send_t* req, - uv_udp_t* handle, - uv_buf_t bufs[], - int bufcnt, - struct sockaddr* addr, - socklen_t addrlen, - uv_udp_send_cb send_cb); +static int uv__send(uv_udp_send_t* req, + uv_udp_t* handle, + uv_buf_t bufs[], + int bufcnt, + struct sockaddr* addr, + socklen_t addrlen, + uv_udp_send_cb send_cb); void uv__udp_close(uv_udp_t* handle) { @@ -413,13 +413,13 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain) { } -static int uv__udp_send(uv_udp_send_t* req, - uv_udp_t* handle, - uv_buf_t bufs[], - int bufcnt, - struct sockaddr* addr, - socklen_t addrlen, - uv_udp_send_cb send_cb) { +static int uv__send(uv_udp_send_t* req, + uv_udp_t* handle, + uv_buf_t bufs[], + int bufcnt, + struct sockaddr* addr, + socklen_t addrlen, + uv_udp_send_cb send_cb) { assert(bufcnt > 0); if (uv__udp_maybe_deferred_bind(handle, addr->sa_family)) @@ -645,41 +645,41 @@ out: } -int uv_udp_send(uv_udp_send_t* req, - uv_udp_t* handle, - uv_buf_t bufs[], - int bufcnt, - struct sockaddr_in addr, - uv_udp_send_cb send_cb) { - return uv__udp_send(req, - handle, - bufs, - bufcnt, - (struct sockaddr*)&addr, - sizeof addr, - send_cb); -} - - -int uv_udp_send6(uv_udp_send_t* req, +int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], int bufcnt, - struct sockaddr_in6 addr, + struct sockaddr_in addr, uv_udp_send_cb send_cb) { - return uv__udp_send(req, - handle, - bufs, - bufcnt, - (struct sockaddr*)&addr, - sizeof addr, - send_cb); + return uv__send(req, + handle, + bufs, + bufcnt, + (struct sockaddr*)&addr, + sizeof addr, + send_cb); +} + + +int uv__udp_send6(uv_udp_send_t* req, + uv_udp_t* handle, + uv_buf_t bufs[], + int bufcnt, + struct sockaddr_in6 addr, + uv_udp_send_cb send_cb) { + return uv__send(req, + handle, + bufs, + bufcnt, + (struct sockaddr*)&addr, + sizeof addr, + send_cb); } -int uv_udp_recv_start(uv_udp_t* handle, - uv_alloc_cb alloc_cb, - uv_udp_recv_cb recv_cb) { +int uv__udp_recv_start(uv_udp_t* handle, + uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb) { if (alloc_cb == NULL || recv_cb == NULL) { uv__set_artificial_error(handle->loop, UV_EINVAL); return -1; @@ -703,7 +703,7 @@ int uv_udp_recv_start(uv_udp_t* handle, } -int uv_udp_recv_stop(uv_udp_t* handle) { +int uv__udp_recv_stop(uv_udp_t* handle) { uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN); if (!uv__io_active(&handle->io_watcher, UV__POLLOUT)) diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index ae2ca71474..8c9d323af3 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -254,6 +254,53 @@ int uv_tcp_connect6(uv_connect_t* req, } +int uv_udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + uv_buf_t bufs[], + int bufcnt, + struct sockaddr_in addr, + uv_udp_send_cb send_cb) { + if (handle->type != UV_UDP || addr.sin_family != AF_INET) { + return uv__set_artificial_error(handle->loop, UV_EINVAL); + } + + return uv__udp_send(req, handle, bufs, bufcnt, addr, send_cb); +} + + +int uv_udp_send6(uv_udp_send_t* req, + uv_udp_t* handle, + uv_buf_t bufs[], + int bufcnt, + struct sockaddr_in6 addr, + uv_udp_send_cb send_cb) { + if (handle->type != UV_UDP || addr.sin6_family != AF_INET6) { + return uv__set_artificial_error(handle->loop, UV_EINVAL); + } + + return uv__udp_send6(req, handle, bufs, bufcnt, addr, send_cb); +} + + +int uv_udp_recv_start(uv_udp_t* handle, + uv_alloc_cb alloc_cb, + uv_udp_recv_cb recv_cb) { + if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL) { + return uv__set_artificial_error(handle->loop, UV_EINVAL); + } + + return uv__udp_recv_start(handle, alloc_cb, recv_cb); +} + + +int uv_udp_recv_stop(uv_udp_t* handle) { + if (handle->type != UV_UDP) { + return uv__set_artificial_error(handle->loop, UV_EINVAL); + } + + return uv__udp_recv_stop(handle); +} + #ifdef _WIN32 static UINT __stdcall uv__thread_start(void *ctx_v) #else @@ -377,3 +424,8 @@ void uv_ref(uv_handle_t* handle) { void uv_unref(uv_handle_t* handle) { uv__handle_unref(handle); } + + +void uv_stop(uv_loop_t* loop) { + loop->stop_flag = 1; +} diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index d4d1c8b277..4ba8516913 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -93,6 +93,25 @@ int uv__tcp_connect6(uv_connect_t* req, struct sockaddr_in6 address, uv_connect_cb cb); +int uv__udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + uv_buf_t bufs[], + int bufcnt, + struct sockaddr_in addr, + uv_udp_send_cb send_cb); + +int uv__udp_send6(uv_udp_send_t* req, + uv_udp_t* handle, + uv_buf_t bufs[], + int bufcnt, + struct sockaddr_in6 addr, + uv_udp_send_cb send_cb); + +int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb, + uv_udp_recv_cb recv_cb); + +int uv__udp_recv_stop(uv_udp_t* handle); + void uv__fs_poll_close(uv_fs_poll_t* handle); diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index e56536a7fa..a06c23f3cd 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -116,6 +116,7 @@ static void uv_loop_init(uv_loop_t* loop) { loop->active_udp_streams = 0; loop->timer_counter = 0; + loop->stop_flag = 0; loop->last_err = uv_ok_; } @@ -249,10 +250,13 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { } } -#define UV_LOOP_ALIVE(loop) \ - ((loop)->active_handles > 0 || \ - !ngx_queue_empty(&(loop)->active_reqs) || \ - (loop)->endgame_handles != NULL) + +static int uv__loop_alive(uv_loop_t* loop) { + return loop->active_handles > 0 || + !ngx_queue_empty(&loop->active_reqs) || + loop->endgame_handles != NULL; +} + int uv_run(uv_loop_t *loop, uv_run_mode mode) { int r; @@ -263,8 +267,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { else poll = &uv_poll; - r = UV_LOOP_ALIVE(loop); - while (r) { + if (!uv__loop_alive(loop)) + return 0; + + r = uv__loop_alive(loop); + while (r != 0 && loop->stop_flag == 0) { uv_update_time(loop); uv_process_timers(loop); @@ -282,14 +289,22 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { (*poll)(loop, loop->idle_handles == NULL && loop->pending_reqs_tail == NULL && loop->endgame_handles == NULL && - UV_LOOP_ALIVE(loop) && + !loop->stop_flag && + (loop->active_handles > 0 || + !ngx_queue_empty(&loop->active_reqs)) && !(mode & UV_RUN_NOWAIT)); uv_check_invoke(loop); - r = UV_LOOP_ALIVE(loop); - + r = uv__loop_alive(loop); if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT)) break; } + + /* The if statement lets the compiler compile it to a conditional store. + * Avoids dirtying a cache line. + */ + if (loop->stop_flag != 0) + loop->stop_flag = 0; + return r; } diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 23410528f5..b6b6e0f722 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -341,7 +341,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { } -int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, +int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb) { uv_loop_t* loop = handle->loop; @@ -371,7 +371,7 @@ int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, } -int uv_udp_recv_stop(uv_udp_t* handle) { +int uv__udp_recv_stop(uv_udp_t* handle) { if (handle->flags & UV_HANDLE_READING) { handle->flags &= ~UV_HANDLE_READING; handle->loop->active_udp_streams--; @@ -382,7 +382,7 @@ int uv_udp_recv_stop(uv_udp_t* handle) { } -static int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], +static int uv__send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], int bufcnt, struct sockaddr* addr, int addr_len, uv_udp_send_cb cb) { uv_loop_t* loop = handle->loop; DWORD result, bytes; @@ -424,7 +424,7 @@ static int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], } -int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], +int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], int bufcnt, struct sockaddr_in addr, uv_udp_send_cb cb) { if (!(handle->flags & UV_HANDLE_BOUND) && @@ -432,17 +432,17 @@ int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], return -1; } - return uv__udp_send(req, - handle, - bufs, - bufcnt, - (struct sockaddr*) &addr, - sizeof addr, - cb); + return uv__send(req, + handle, + bufs, + bufcnt, + (struct sockaddr*) &addr, + sizeof addr, + cb); } -int uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], +int uv__udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], int bufcnt, struct sockaddr_in6 addr, uv_udp_send_cb cb) { if (!(handle->flags & UV_HANDLE_BOUND) && @@ -450,13 +450,13 @@ int uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], return -1; } - return uv__udp_send(req, - handle, - bufs, - bufcnt, - (struct sockaddr*) &addr, - sizeof addr, - cb); + return uv__send(req, + handle, + bufs, + bufcnt, + (struct sockaddr*) &addr, + sizeof addr, + cb); } diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c index 1b9a980926..6e4b4f6736 100644 --- a/deps/uv/test/runner.c +++ b/deps/uv/test/runner.c @@ -102,7 +102,9 @@ int run_tests(int timeout, int benchmark_output) { continue; } - rewind_cursor(); + if (!tap_output) + rewind_cursor(); + if (!benchmark_output && !tap_output) { log_progress(total, passed, failed, task->task_name); } @@ -115,7 +117,8 @@ int run_tests(int timeout, int benchmark_output) { current++; } - rewind_cursor(); + if (!tap_output) + rewind_cursor(); if (!benchmark_output && !tap_output) { log_progress(total, passed, failed, "Done.\n"); diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 6c7da04ce0..2341463a19 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -23,6 +23,7 @@ TEST_DECLARE (platform_output) TEST_DECLARE (callback_order) TEST_DECLARE (run_once) TEST_DECLARE (run_nowait) +TEST_DECLARE (loop_stop) TEST_DECLARE (barrier_1) TEST_DECLARE (barrier_2) TEST_DECLARE (barrier_3) @@ -230,6 +231,7 @@ TASK_LIST_START #endif TEST_ENTRY (run_once) TEST_ENTRY (run_nowait) + TEST_ENTRY (loop_stop) TEST_ENTRY (barrier_1) TEST_ENTRY (barrier_2) TEST_ENTRY (barrier_3) diff --git a/deps/uv/test/test-loop-stop.c b/deps/uv/test/test-loop-stop.c new file mode 100644 index 0000000000..db52a094e7 --- /dev/null +++ b/deps/uv/test/test-loop-stop.c @@ -0,0 +1,73 @@ +/* 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" + +static uv_prepare_t prepare_handle; +static uv_timer_t timer_handle; +static int prepare_called = 0; +static int timer_called = 0; +static int num_ticks = 10; + + +static void prepare_cb(uv_prepare_t* handle, int status) { + ASSERT(handle == &prepare_handle); + ASSERT(status == 0); + prepare_called++; + if (prepare_called == num_ticks) + uv_prepare_stop(handle); +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &timer_handle); + ASSERT(status == 0); + timer_called++; + if (timer_called == 1) + uv_stop(uv_default_loop()); + else if (timer_called == num_ticks) + uv_timer_stop(handle); +} + + +TEST_IMPL(loop_stop) { + int r; + uv_prepare_init(uv_default_loop(), &prepare_handle); + uv_prepare_start(&prepare_handle, prepare_cb); + uv_timer_init(uv_default_loop(), &timer_handle); + uv_timer_start(&timer_handle, timer_cb, 100, 100); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r != 0); + ASSERT(timer_called == 1); + + r = uv_run(uv_default_loop(), UV_RUN_NOWAIT); + ASSERT(r != 0); + ASSERT(prepare_called == 3); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(timer_called == 10); + ASSERT(prepare_called == 10); + + return 0; +} diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 075724dc52..55f1e23943 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -112,7 +112,8 @@ '-pedantic', '-Wall', '-Wextra', - '-Wno-unused-parameter' + '-Wstrict-aliasing', + '-Wno-unused-parameter', ], 'sources': [ 'include/uv-private/uv-unix.h', @@ -279,6 +280,7 @@ 'test/test-ipc-send-recv.c', 'test/test-list.h', 'test/test-loop-handles.c', + 'test/test-loop-stop.c', 'test/test-walk-handles.c', 'test/test-multiple-listen.c', 'test/test-pass-always.c', diff --git a/deps/uv/vcbuild.bat b/deps/uv/vcbuild.bat index 5864a3a99d..aa8a757c89 100644 --- a/deps/uv/vcbuild.bat +++ b/deps/uv/vcbuild.bat @@ -77,7 +77,7 @@ if errorlevel 1 goto gyp_install_failed goto have_gyp :gyp_install_failed -echo Failed to download gyp. Make sure you have subversion installed, or +echo Failed to download gyp. Make sure you have git installed, or echo manually install gyp into %~dp0build\gyp. goto exit