deps: upgrade libuv to a0c1d84
authorBen Noordhuis <info@bnoordhuis.nl>
Tue, 26 Feb 2013 19:30:12 +0000 (20:30 +0100)
committerBen Noordhuis <info@bnoordhuis.nl>
Tue, 26 Feb 2013 19:30:12 +0000 (20:30 +0100)
20 files changed:
deps/uv/build.mk
deps/uv/common.gypi
deps/uv/include/uv-private/uv-unix.h
deps/uv/include/uv.h
deps/uv/src/unix/async.c
deps/uv/src/unix/core.c
deps/uv/src/unix/fs.c
deps/uv/src/unix/internal.h
deps/uv/src/unix/loop.c
deps/uv/src/unix/proctitle.c
deps/uv/src/unix/udp.c
deps/uv/src/uv-common.c
deps/uv/src/uv-common.h
deps/uv/src/win/core.c
deps/uv/src/win/udp.c
deps/uv/test/runner.c
deps/uv/test/test-list.h
deps/uv/test/test-loop-stop.c [new file with mode: 0644]
deps/uv/uv.gyp
deps/uv/vcbuild.bat

index 88de949dd34c3b6163977b503ebb263b71342400..a19db4948dd90ec551a72d424ee818815e36ed89 100644 (file)
@@ -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 \
index c3d9527cc8f06424270f77f489421866ba81c835..8c6c887584cd785e8efe5a54c36d8b209ad05ee3 100644 (file)
       },
       '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': [
           'PREBINDING': 'NO',                       # No -Wl,-prebind
           'USE_HEADERMAP': 'NO',
           'OTHER_CFLAGS': [
-            '-fno-strict-aliasing',
+            '-fstrict-aliasing',
           ],
           'WARNING_CFLAGS': [
             '-Wall',
index fe32c4b8ac2488a9556bbec1d68d25e92ee85664..729082e0bc98244fc083d7fc06243af73edcadd9 100644 (file)
@@ -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; */                                      \
index 4d6a2e80cd8c3fcbec6e43322baeb70ce6e5b900..de375d4b0eea0bd899607bc632e6a18f9deac2f6 100644 (file)
@@ -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
 };
 
index 322167c68c507a882bb9c6674af5efce228e4445..43f54ed4b286525f48fc56b7780558761d5de434 100644 (file)
  * 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 <errno.h>
 #include <assert.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
-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;
 }
index e5c9a4d98a2aab7b641ac4592e56285e45b078e9..a281f2e0812315379434f67dfcc29961d7d568e2 100644 (file)
@@ -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;
 }
index f9181df1274de1de657dc9dfda2c6061b7a13c6c..53f46ce7c72b3c85b573a5c677e54f0ea1bf5171 100644 (file)
@@ -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;
       }
index d6d2e45fd1f2317696964243197997203ac581b6..7d08c1dac97af7f39efb0d1f3501878f05fe85ad 100644 (file)
@@ -45,6 +45,9 @@
 # include <CoreServices/CoreServices.h>
 #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);
index 993531074909f7e8132dbafa55a7e9510b0d2c02..75b0702a3ab7fad342a19f81f150ffd67647dcff 100644 (file)
@@ -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);
index c4043af31186207e0e3fb5f16df3799e478036d1..6728e2387f2d0365b33f8e01c98bac3fcdc66359 100644 (file)
@@ -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_;
index 56c1b25072fdcb765c76481bd4104981cc2828b6..49028985d6d514a16efd7f8fd93fa73929412546 100644 (file)
@@ -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))
index ae2ca7147473f0d11074aec197aa5a8416b2fa97..8c9d323af3382747e2fe1047560c821f1b385483 100644 (file)
@@ -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;
+}
index d4d1c8b277fefb9df251d179a1235526a7417c92..4ba8516913395cdf00cbd04b7709f6890494e65b 100644 (file)
@@ -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);
 
 
index e56536a7fa13899509e7cffd7c05917d6256dc64..a06c23f3cd162cb8cb70fe85280b554c5b7293c8 100644 (file)
@@ -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;
 }
index 23410528f531da402f3d104e44560c8c005192e8..b6b6e0f722c84bd489ca0ce0696b17a67595a655 100644 (file)
@@ -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);
 }
 
 
index 1b9a980926fa063ead864c85fb1ad6ffc6b3c349..6e4b4f6736429e1460f3477e20c4e448f62c1cf6 100644 (file)
@@ -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");
index 6c7da04ce0996c84d8ce1efc31278836ffebb459..2341463a19a9515d7e529c4cc1c5493aede19a12 100644 (file)
@@ -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 (file)
index 0000000..db52a09
--- /dev/null
@@ -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;
+}
index 075724dc52841a5d607d634897b0bc110ac35ec7..55f1e23943c96cbcd1285b9b3db0958166cecb21 100644 (file)
             '-pedantic',
             '-Wall',
             '-Wextra',
-            '-Wno-unused-parameter'
+            '-Wstrict-aliasing',
+            '-Wno-unused-parameter',
           ],
           'sources': [
             'include/uv-private/uv-unix.h',
         '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',
index 5864a3a99d25790f745f9e2379a126591e1a5b83..aa8a757c8953078d4b70b1e51d8fbb6860ac93f8 100644 (file)
@@ -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