uv: upgrade to 8073a26
authorBert Belder <bertbelder@gmail.com>
Mon, 20 Aug 2012 16:41:07 +0000 (18:41 +0200)
committerBert Belder <bertbelder@gmail.com>
Mon, 20 Aug 2012 16:41:31 +0000 (18:41 +0200)
72 files changed:
deps/uv/config-unix.mk
deps/uv/gyp_uv
deps/uv/include/uv-private/eio.h
deps/uv/include/uv-private/ngx-queue.h
deps/uv/include/uv-private/uv-bsd.h [new file with mode: 0644]
deps/uv/include/uv-private/uv-darwin.h [new file with mode: 0644]
deps/uv/include/uv-private/uv-linux.h [new file with mode: 0644]
deps/uv/include/uv-private/uv-sunos.h [new file with mode: 0644]
deps/uv/include/uv-private/uv-unix.h
deps/uv/include/uv-private/uv-win.h
deps/uv/include/uv.h
deps/uv/src/fs-poll.c
deps/uv/src/unix/async.c
deps/uv/src/unix/core.c
deps/uv/src/unix/cygwin.c
deps/uv/src/unix/darwin.c
deps/uv/src/unix/freebsd.c
deps/uv/src/unix/fs.c
deps/uv/src/unix/internal.h
deps/uv/src/unix/kqueue.c
deps/uv/src/unix/linux/inotify.c
deps/uv/src/unix/linux/linux-core.c
deps/uv/src/unix/loop-watcher.c
deps/uv/src/unix/loop.c
deps/uv/src/unix/netbsd.c
deps/uv/src/unix/openbsd.c
deps/uv/src/unix/pipe.c
deps/uv/src/unix/poll.c
deps/uv/src/unix/process.c
deps/uv/src/unix/signal.c [new file with mode: 0644]
deps/uv/src/unix/stream.c
deps/uv/src/unix/sunos.c
deps/uv/src/unix/tcp.c
deps/uv/src/unix/timer.c
deps/uv/src/unix/tty.c
deps/uv/src/unix/udp.c
deps/uv/src/unix/uv-eio.c
deps/uv/src/uv-common.h
deps/uv/src/win/async.c
deps/uv/src/win/atomicops-inl.h [new file with mode: 0644]
deps/uv/src/win/core.c
deps/uv/src/win/dl.c
deps/uv/src/win/error.c
deps/uv/src/win/fs-event.c
deps/uv/src/win/getaddrinfo.c
deps/uv/src/win/handle-inl.h
deps/uv/src/win/handle.c
deps/uv/src/win/internal.h
deps/uv/src/win/loop-watcher.c
deps/uv/src/win/pipe.c
deps/uv/src/win/poll.c
deps/uv/src/win/process-stdio.c
deps/uv/src/win/process.c
deps/uv/src/win/req-inl.h
deps/uv/src/win/signal.c [new file with mode: 0644]
deps/uv/src/win/stream-inl.h
deps/uv/src/win/tcp.c
deps/uv/src/win/timer.c
deps/uv/src/win/tty.c
deps/uv/src/win/udp.c
deps/uv/src/win/util.c
deps/uv/test/benchmark-fs-stat.c
deps/uv/test/benchmark-sizes.c
deps/uv/test/runner-win.c
deps/uv/test/runner.c
deps/uv/test/test-counters-init.c [deleted file]
deps/uv/test/test-delayed-accept.c
deps/uv/test/test-list.h
deps/uv/test/test-signal.c [new file with mode: 0644]
deps/uv/test/test-spawn.c
deps/uv/test/test-tcp-unexpected-read.c
deps/uv/uv.gyp

index e3e9545..53c636d 100644 (file)
@@ -37,6 +37,7 @@ OBJS += src/unix/loop-watcher.o
 OBJS += src/unix/pipe.o
 OBJS += src/unix/poll.o
 OBJS += src/unix/process.o
+OBJS += src/unix/signal.o
 OBJS += src/unix/stream.o
 OBJS += src/unix/tcp.o
 OBJS += src/unix/thread.o
index 00da3ae..a8528fa 100755 (executable)
@@ -22,7 +22,9 @@ def compiler_version():
   proc = subprocess.Popen(CC.split() + ['--version'], stdout=subprocess.PIPE)
   is_clang = 'clang' in proc.communicate()[0].split('\n')[0]
   proc = subprocess.Popen(CC.split() + ['-dumpversion'], stdout=subprocess.PIPE)
-  version = tuple(map(int, proc.communicate()[0].split('.')))
+  version = proc.communicate()[0].split('.')
+  version = map(int, version[:2])
+  version = tuple(version)
   return (version, is_clang)
 
 
index aab9988..975f7ef 100644 (file)
@@ -251,7 +251,7 @@ struct eio_req
 
   eio_channel *channel; /* data used to direct poll callbacks arising from this req */
 
-#if __i386 || __amd64
+#if defined(__i386) || defined(__amd64)
   unsigned char cancelled;
 #else
   sig_atomic_t cancelled;
index 6fd0071..201107e 100644 (file)
@@ -62,7 +62,7 @@ struct ngx_queue_s {
     (q)->prev
 
 
-#if (NGX_DEBUG)
+#if defined(NGX_DEBUG)
 
 #define ngx_queue_remove(x)                                                   \
     (x)->next->prev = (x)->prev;                                              \
diff --git a/deps/uv/include/uv-private/uv-bsd.h b/deps/uv/include/uv-private/uv-bsd.h
new file mode 100644 (file)
index 0000000..26830a6
--- /dev/null
@@ -0,0 +1,30 @@
+/* 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.
+ */
+
+#ifndef UV_BSD_H
+#define UV_BSD_H
+
+#define UV_PLATFORM_FS_EVENT_FIELDS                                           \
+  uv__io_t event_watcher;                                                     \
+  int fflags;                                                                 \
+  int fd;                                                                     \
+
+#endif /* UV_BSD_H */
diff --git a/deps/uv/include/uv-private/uv-darwin.h b/deps/uv/include/uv-private/uv-darwin.h
new file mode 100644 (file)
index 0000000..93f2ca4
--- /dev/null
@@ -0,0 +1,37 @@
+/* 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.
+ */
+
+#ifndef UV_DARWIN_H
+#define UV_DARWIN_H
+
+#if defined(__APPLE__) && defined(__MACH__)
+# include <mach/mach.h>
+# include <mach/task.h>
+# include <mach/semaphore.h>
+# define UV_PLATFORM_SEM_T semaphore_t
+#endif
+
+#define UV_PLATFORM_FS_EVENT_FIELDS                                           \
+  ev_io event_watcher;                                                        \
+  int fflags;                                                                 \
+  int fd;                                                                     \
+
+#endif /* UV_DARWIN_H */
diff --git a/deps/uv/include/uv-private/uv-linux.h b/deps/uv/include/uv-private/uv-linux.h
new file mode 100644 (file)
index 0000000..0d50123
--- /dev/null
@@ -0,0 +1,34 @@
+/* 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.
+ */
+
+#ifndef UV_LINUX_H
+#define UV_LINUX_H
+
+#define UV_PLATFORM_LOOP_FIELDS                                               \
+  uv__io_t inotify_read_watcher;                                              \
+  void* inotify_watchers;                                                     \
+  int inotify_fd;                                                             \
+
+#define UV_PLATFORM_FS_EVENT_FIELDS                                           \
+  ngx_queue_t watchers;                                                       \
+  int wd;                                                                     \
+
+#endif /* UV_LINUX_H */
diff --git a/deps/uv/include/uv-private/uv-sunos.h b/deps/uv/include/uv-private/uv-sunos.h
new file mode 100644 (file)
index 0000000..9d55e23
--- /dev/null
@@ -0,0 +1,40 @@
+/* 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.
+ */
+
+#ifndef UV_SUNOS_H
+#define UV_SUNOS_H
+
+#include <sys/port.h>
+#include <port.h>
+
+#if defined(PORT_SOURCE_FILE)
+
+# define UV_PLATFORM_LOOP_FIELDS                                              \
+  uv__io_t fs_event_watcher;                                                  \
+  int fs_fd;                                                                  \
+
+# define UV_PLATFORM_FS_EVENT_FIELDS                                          \
+  file_obj_t fo;                                                              \
+  int fd;                                                                     \
+
+#endif /* defined(PORT_SOURCE_FILE) */
+
+#endif /* UV_SUNOS_H */
index a8dda72..560889e 100644 (file)
 #include <termios.h>
 #include <pwd.h>
 
+#include <semaphore.h>
 #include <pthread.h>
 #include <signal.h>
 
-#if defined(__APPLE__) && defined(__MACH__)
-# include <mach/mach.h>
-# include <mach/task.h>
-# include <mach/semaphore.h>
-#else
-# include <semaphore.h>
+struct uv__io_s;
+struct uv_loop_s;
+
+typedef struct uv__io_s uv__io_t;
+typedef void (*uv__io_cb)(struct uv_loop_s* loop, uv__io_t* handle, int events);
+
+struct uv__io_s {
+  ev_io io_watcher;
+};
+
+#if defined(__linux__)
+# include "uv-linux.h"
+#elif defined(__sun)
+# include "uv-sunos.h"
+#elif defined(__APPLE__)
+# include "uv-darwin.h"
+#elif defined(__DragonFly__)  || \
+      defined(__FreeBSD__)    || \
+      defined(__OpenBSD__)    || \
+      defined(__NetBSD__)
+# include "uv-bsd.h"
+#endif
+
+#ifndef UV_PLATFORM_SEM_T
+# define UV_PLATFORM_SEM_T sem_t
+#endif
+
+#ifndef UV_PLATFORM_LOOP_FIELDS
+# define UV_PLATFORM_LOOP_FIELDS /* empty */
 #endif
 
-#if __sun
-# include <sys/port.h>
-# include <port.h>
+#ifndef UV_PLATFORM_FS_EVENT_FIELDS
+# define UV_PLATFORM_FS_EVENT_FIELDS /* empty */
 #endif
 
 /* Note: May be cast to struct iovec. See writev(2). */
@@ -63,9 +86,7 @@ typedef struct {
 } uv_buf_t;
 
 typedef int uv_file;
-
 typedef int uv_os_sock_t;
-
 typedef struct stat uv_statbuf_t;
 
 #define UV_ONCE_INIT PTHREAD_ONCE_INIT
@@ -74,11 +95,7 @@ typedef pthread_once_t uv_once_t;
 typedef pthread_t uv_thread_t;
 typedef pthread_mutex_t uv_mutex_t;
 typedef pthread_rwlock_t uv_rwlock_t;
-#if defined(__APPLE__) && defined(__MACH__)
-typedef semaphore_t uv_sem_t;
-#else
-typedef sem_t uv_sem_t;
-#endif
+typedef UV_PLATFORM_SEM_T uv_sem_t;
 
 /* Platform-specific definitions for uv_spawn support. */
 typedef gid_t uv_gid_t;
@@ -86,37 +103,14 @@ typedef uid_t uv_uid_t;
 
 /* Platform-specific definitions for uv_dlopen support. */
 #define UV_DYNAMIC /* empty */
+
 typedef struct {
   void* handle;
   char* errmsg;
 } uv_lib_t;
 
-struct uv__io_s;
-struct uv_loop_s;
-
-typedef struct uv__io_s uv__io_t;
-typedef void (*uv__io_cb)(struct uv_loop_s* loop, uv__io_t* handle, int events);
-
-struct uv__io_s {
-  ev_io io_watcher;
-};
-
-#define UV_REQ_TYPE_PRIVATE /* empty */
-
-#if __linux__
-# define UV_LOOP_PRIVATE_PLATFORM_FIELDS              \
-  uv__io_t inotify_read_watcher;                      \
-  void* inotify_watchers;                             \
-  int inotify_fd;
-#elif defined(PORT_SOURCE_FILE)
-# define UV_LOOP_PRIVATE_PLATFORM_FIELDS              \
-  uv__io_t fs_event_watcher;                          \
-  int fs_fd;
-#else
-# define UV_LOOP_PRIVATE_PLATFORM_FIELDS
-#endif
-
 #define UV_LOOP_PRIVATE_FIELDS                                                \
+  unsigned long flags;                                                        \
   /* Poll result queue */                                                     \
   eio_channel uv_eio_channel;                                                 \
   struct ev_loop* ev;                                                         \
@@ -125,6 +119,7 @@ struct uv__io_s {
   uv_async_t uv_eio_done_poll_notifier;                                       \
   uv_idle_t uv_eio_poller;                                                    \
   uv_handle_t* closing_handles;                                               \
+  ngx_queue_t process_handles[1];                                             \
   ngx_queue_t prepare_handles;                                                \
   ngx_queue_t check_handles;                                                  \
   ngx_queue_t idle_handles;                                                   \
@@ -132,111 +127,94 @@ struct uv__io_s {
   uv__io_t async_watcher;                                                     \
   int async_pipefd[2];                                                        \
   /* RB_HEAD(uv__timers, uv_timer_s) */                                       \
-  struct uv__timers { struct uv_timer_s* rbh_root; } timer_handles;           \
+  struct uv__timers {                                                         \
+    struct uv_timer_s* rbh_root;                                              \
+  } timer_handles;                                                            \
   uint64_t time;                                                              \
-  UV_LOOP_PRIVATE_PLATFORM_FIELDS
+  void* signal_ctx;                                                           \
+  uv_signal_t child_watcher;                                                  \
+  UV_PLATFORM_LOOP_FIELDS                                                     \
 
-#define UV_REQ_BUFSML_SIZE (4)
+#define UV_REQ_TYPE_PRIVATE /* empty */
 
 #define UV_REQ_PRIVATE_FIELDS  /* empty */
 
-#define UV_WRITE_PRIVATE_FIELDS \
-  ngx_queue_t queue; \
-  int write_index; \
-  uv_buf_t* bufs; \
-  int bufcnt; \
-  int error; \
-  uv_buf_t bufsml[UV_REQ_BUFSML_SIZE];
-
-#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */
-
-#define UV_CONNECT_PRIVATE_FIELDS \
-  ngx_queue_t queue;
-
-#define UV_UDP_SEND_PRIVATE_FIELDS  \
-  ngx_queue_t queue;                \
-  struct sockaddr_in6 addr;         \
-  int bufcnt;                       \
-  uv_buf_t* bufs;                   \
-  ssize_t status;                   \
-  uv_udp_send_cb send_cb;           \
-  uv_buf_t bufsml[UV_REQ_BUFSML_SIZE];  \
-
 #define UV_PRIVATE_REQ_TYPES /* empty */
 
+#define UV_WRITE_PRIVATE_FIELDS                                               \
+  ngx_queue_t queue;                                                          \
+  int write_index;                                                            \
+  uv_buf_t* bufs;                                                             \
+  int bufcnt;                                                                 \
+  int error;                                                                  \
+  uv_buf_t bufsml[4];                                                         \
 
-/* TODO: union or classes please! */
-#define UV_HANDLE_PRIVATE_FIELDS \
-  int flags; \
-  uv_handle_t* next_closing; \
-
-
-#define UV_STREAM_PRIVATE_FIELDS \
-  uv_connect_t *connect_req; \
-  uv_shutdown_t *shutdown_req; \
-  uv__io_t read_watcher; \
-  uv__io_t write_watcher; \
-  ngx_queue_t write_queue; \
-  ngx_queue_t write_completed_queue; \
-  uv_connection_cb connection_cb; \
-  int delayed_error; \
-  int accepted_fd; \
-  int fd; \
-
-
-/* UV_TCP, idle_handle is for UV_TCP_SINGLE_ACCEPT handles */
-#define UV_TCP_PRIVATE_FIELDS         \
-  uv_idle_t* idle_handle;             \
-
-
-/* UV_UDP */
-#define UV_UDP_PRIVATE_FIELDS         \
-  int fd;                             \
-  uv_alloc_cb alloc_cb;               \
-  uv_udp_recv_cb recv_cb;             \
-  uv__io_t read_watcher;              \
-  uv__io_t write_watcher;             \
-  ngx_queue_t write_queue;            \
-  ngx_queue_t write_completed_queue;  \
+#define UV_CONNECT_PRIVATE_FIELDS                                             \
+  ngx_queue_t queue;                                                          \
 
+#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */
 
-/* UV_NAMED_PIPE */
-#define UV_PIPE_PRIVATE_FIELDS \
+#define UV_UDP_SEND_PRIVATE_FIELDS                                            \
+  ngx_queue_t queue;                                                          \
+  struct sockaddr_in6 addr;                                                   \
+  int bufcnt;                                                                 \
+  uv_buf_t* bufs;                                                             \
+  ssize_t status;                                                             \
+  uv_udp_send_cb send_cb;                                                     \
+  uv_buf_t bufsml[4];                                                         \
+
+#define UV_HANDLE_PRIVATE_FIELDS                                              \
+  int flags;                                                                  \
+  uv_handle_t* next_closing;                                                  \
+
+#define UV_STREAM_PRIVATE_FIELDS                                              \
+  uv_connect_t *connect_req;                                                  \
+  uv_shutdown_t *shutdown_req;                                                \
+  uv__io_t read_watcher;                                                      \
+  uv__io_t write_watcher;                                                     \
+  ngx_queue_t write_queue;                                                    \
+  ngx_queue_t write_completed_queue;                                          \
+  uv_connection_cb connection_cb;                                             \
+  int delayed_error;                                                          \
+  int accepted_fd;                                                            \
+  int fd;                                                                     \
+
+#define UV_TCP_PRIVATE_FIELDS                                                 \
+  uv_idle_t* idle_handle;  /* for UV_TCP_SINGLE_ACCEPT handles */             \
+
+#define UV_UDP_PRIVATE_FIELDS                                                 \
+  int fd;                                                                     \
+  uv_alloc_cb alloc_cb;                                                       \
+  uv_udp_recv_cb recv_cb;                                                     \
+  uv__io_t read_watcher;                                                      \
+  uv__io_t write_watcher;                                                     \
+  ngx_queue_t write_queue;                                                    \
+  ngx_queue_t write_completed_queue;                                          \
+
+#define UV_PIPE_PRIVATE_FIELDS                                                \
   const char* pipe_fname; /* strdup'ed */
 
-
-/* UV_POLL */
-#define UV_POLL_PRIVATE_FIELDS        \
-  int fd;                             \
+#define UV_POLL_PRIVATE_FIELDS                                                \
+  int fd;                                                                     \
   uv__io_t io_watcher;
 
-
-/* UV_PREPARE */
-#define UV_PREPARE_PRIVATE_FIELDS \
-  uv_prepare_cb prepare_cb; \
+#define UV_PREPARE_PRIVATE_FIELDS                                             \
+  uv_prepare_cb prepare_cb;                                                   \
   ngx_queue_t queue;
 
-
-/* UV_CHECK */
-#define UV_CHECK_PRIVATE_FIELDS \
-  uv_check_cb check_cb; \
+#define UV_CHECK_PRIVATE_FIELDS                                               \
+  uv_check_cb check_cb;                                                       \
   ngx_queue_t queue;
 
-
-/* UV_IDLE */
-#define UV_IDLE_PRIVATE_FIELDS \
-  uv_idle_cb idle_cb; \
+#define UV_IDLE_PRIVATE_FIELDS                                                \
+  uv_idle_cb idle_cb;                                                         \
   ngx_queue_t queue;
 
-
-/* UV_ASYNC */
 #define UV_ASYNC_PRIVATE_FIELDS                                               \
   volatile sig_atomic_t pending;                                              \
   uv_async_cb async_cb;                                                       \
   ngx_queue_t queue;
 
-
-/* UV_TIMER */
 #define UV_TIMER_PRIVATE_FIELDS                                               \
   /* RB_ENTRY(uv_timer_s) node; */                                            \
   struct {                                                                    \
@@ -249,66 +227,35 @@ struct uv__io_s {
   uint64_t timeout;                                                           \
   uint64_t repeat;
 
-#define UV_GETADDRINFO_PRIVATE_FIELDS \
-  uv_getaddrinfo_cb cb; \
-  struct addrinfo* hints; \
-  char* hostname; \
-  char* service; \
-  struct addrinfo* res; \
+#define UV_GETADDRINFO_PRIVATE_FIELDS                                         \
+  uv_getaddrinfo_cb cb;                                                       \
+  struct addrinfo* hints;                                                     \
+  char* hostname;                                                             \
+  char* service;                                                              \
+  struct addrinfo* res;                                                       \
   int retcode;
 
-#define UV_PROCESS_PRIVATE_FIELDS \
-  ev_child child_watcher;
+#define UV_PROCESS_PRIVATE_FIELDS                                             \
+  ngx_queue_t queue;                                                          \
+  int errorno;                                                                \
 
-#define UV_FS_PRIVATE_FIELDS \
-  struct stat statbuf; \
-  eio_req* eio;
+#define UV_FS_PRIVATE_FIELDS                                                  \
+  struct stat statbuf;                                                        \
+  uv_file file;                                                               \
+  eio_req* eio;                                                               \
 
-#define UV_WORK_PRIVATE_FIELDS \
+#define UV_WORK_PRIVATE_FIELDS                                                \
   eio_req* eio;
 
-#define UV_TTY_PRIVATE_FIELDS \
-  struct termios orig_termios; \
+#define UV_TTY_PRIVATE_FIELDS                                                 \
+  struct termios orig_termios;                                                \
   int mode;
 
-/* UV_FS_EVENT_PRIVATE_FIELDS */
-#if defined(__linux__)
-
-#define UV_FS_EVENT_PRIVATE_FIELDS    \
-  ngx_queue_t watchers;               \
-  uv_fs_event_cb cb;                  \
-  int wd;                             \
-  void* pad0;                         \
-  void* pad1;                         \
-
-#elif defined(__APPLE__)  \
-  || defined(__FreeBSD__) \
-  || defined(__DragonFly__) \
-  || defined(__OpenBSD__) \
-  || defined(__NetBSD__)
-
-#define UV_FS_EVENT_PRIVATE_FIELDS \
-  ev_io event_watcher; \
-  uv_fs_event_cb cb; \
-  int fflags; \
-  int fd;
-
-#elif defined(__sun)
-
-#ifdef PORT_SOURCE_FILE
-# define UV_FS_EVENT_PRIVATE_FIELDS \
-  uv_fs_event_cb cb; \
-  file_obj_t fo; \
-  int fd;
-#else /* !PORT_SOURCE_FILE */
-# define UV_FS_EVENT_PRIVATE_FIELDS
-#endif
-
-#else
-
-/* Stub for platforms where the file watcher isn't implemented yet. */
-#define UV_FS_EVENT_PRIVATE_FIELDS
+#define UV_SIGNAL_PRIVATE_FIELDS                                              \
+  ngx_queue_t queue;
 
-#endif
+#define UV_FS_EVENT_PRIVATE_FIELDS                                            \
+  uv_fs_event_cb cb;                                                          \
+  UV_PLATFORM_FS_EVENT_FIELDS                                                 \
 
 #endif /* UV_UNIX_H */
index 5b0aba6..dbbeced 100644 (file)
@@ -29,12 +29,14 @@ typedef intptr_t ssize_t;
 # define _SSIZE_T_DEFINED
 #endif
 
-#include <process.h>
-#include <stdint.h>
 #include <winsock2.h>
 #include <mswsock.h>
 #include <ws2tcpip.h>
 #include <windows.h>
+
+#include <process.h>
+#include <signal.h>
+#include <stdint.h>
 #include <sys/stat.h>
 
 #include "tree.h"
@@ -43,32 +45,50 @@ typedef intptr_t ssize_t;
 #define MAX_PIPENAME_LEN 256
 
 #ifndef S_IFLNK
-# define S_IFLNK          0xA000
+# define S_IFLNK 0xA000
 #endif
 
+/* Additional signals supported by uv_signal and or uv_kill. The CRT defines
+ * the following signals already:
+ *
+ *   #define SIGINT           2
+ *   #define SIGILL           4
+ *   #define SIGABRT_COMPAT   6
+ *   #define SIGFPE           8
+ *   #define SIGSEGV         11
+ *   #define SIGTERM         15
+ *   #define SIGBREAK        21
+ *   #define SIGABRT         22
+ *
+ * The additional signals have values that are common on other Unix
+ * variants (Linux and Darwin)
+ */
+#define SIGHUP                1
+#define SIGKILL               9
+
 /*
  * Guids and typedefs for winsock extension functions
  * Mingw32 doesn't have these :-(
  */
 #ifndef WSAID_ACCEPTEX
-# define WSAID_ACCEPTEX                                        \
-         {0xb5367df1, 0xcbac, 0x11cf,                          \
+# define WSAID_ACCEPTEX                                                       \
+         {0xb5367df1, 0xcbac, 0x11cf,                                         \
          {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
 
-# define WSAID_CONNECTEX                                       \
-         {0x25a207b9, 0xddf3, 0x4660,                          \
+# define WSAID_CONNECTEX                                                      \
+         {0x25a207b9, 0xddf3, 0x4660,                                         \
          {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}}
 
-# define WSAID_GETACCEPTEXSOCKADDRS                            \
-         {0xb5367df2, 0xcbac, 0x11cf,                          \
+# define WSAID_GETACCEPTEXSOCKADDRS                                           \
+         {0xb5367df2, 0xcbac, 0x11cf,                                         \
          {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
 
-# define WSAID_DISCONNECTEX                                    \
-         {0x7fda2e11, 0x8630, 0x436f,                          \
+# define WSAID_DISCONNECTEX                                                   \
+         {0x7fda2e11, 0x8630, 0x436f,                                         \
          {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
 
-# define WSAID_TRANSMITFILE                                    \
-         {0xb5367df0, 0xcbac, 0x11cf,                          \
+# define WSAID_TRANSMITFILE                                                   \
+         {0xb5367df0, 0xcbac, 0x11cf,                                         \
          {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
 
   typedef BOOL PASCAL (*LPFN_ACCEPTEX)
@@ -246,272 +266,281 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   /* Counter to keep track of active udp streams */                           \
   unsigned int active_udp_streams;
 
-#define UV_REQ_TYPE_PRIVATE               \
-  /* TODO: remove the req suffix */       \
-  UV_ACCEPT,                              \
-  UV_FS_EVENT_REQ,                        \
-  UV_POLL_REQ,                            \
-  UV_PROCESS_EXIT,                        \
-  UV_PROCESS_CLOSE,                       \
-  UV_READ,                                \
-  UV_UDP_RECV,                            \
-  UV_WAKEUP,
-
-#define UV_REQ_PRIVATE_FIELDS             \
-  union {                                 \
-    /* Used by I/O operations */          \
-    struct {                              \
-      OVERLAPPED overlapped;              \
-      size_t queued_bytes;                \
-    };                                    \
-  };                                      \
+#define UV_REQ_TYPE_PRIVATE                                                   \
+  /* TODO: remove the req suffix */                                           \
+  UV_ACCEPT,                                                                  \
+  UV_FS_EVENT_REQ,                                                            \
+  UV_POLL_REQ,                                                                \
+  UV_PROCESS_EXIT,                                                            \
+  UV_READ,                                                                    \
+  UV_UDP_RECV,                                                                \
+  UV_WAKEUP,                                                                  \
+  UV_SIGNAL_REQ,
+
+#define UV_REQ_PRIVATE_FIELDS                                                 \
+  union {                                                                     \
+    /* Used by I/O operations */                                              \
+    struct {                                                                  \
+      OVERLAPPED overlapped;                                                  \
+      size_t queued_bytes;                                                    \
+    };                                                                        \
+  };                                                                          \
   struct uv_req_s* next_req;
 
-#define UV_WRITE_PRIVATE_FIELDS           \
-  int ipc_header;                         \
-  uv_buf_t write_buffer;                  \
-  HANDLE event_handle;                    \
+#define UV_WRITE_PRIVATE_FIELDS                                               \
+  int ipc_header;                                                             \
+  uv_buf_t write_buffer;                                                      \
+  HANDLE event_handle;                                                        \
   HANDLE wait_handle;
 
-#define UV_CONNECT_PRIVATE_FIELDS         \
+#define UV_CONNECT_PRIVATE_FIELDS                                             \
   /* empty */
 
-#define UV_SHUTDOWN_PRIVATE_FIELDS        \
+#define UV_SHUTDOWN_PRIVATE_FIELDS                                            \
   /* empty */
 
-#define UV_UDP_SEND_PRIVATE_FIELDS        \
+#define UV_UDP_SEND_PRIVATE_FIELDS                                            \
   /* empty */
 
-#define UV_PRIVATE_REQ_TYPES              \
-  typedef struct uv_pipe_accept_s {       \
-    UV_REQ_FIELDS                         \
-    HANDLE pipeHandle;                    \
-    struct uv_pipe_accept_s* next_pending; \
-  } uv_pipe_accept_t;                     \
-                                          \
-  typedef struct uv_tcp_accept_s {        \
-    UV_REQ_FIELDS                         \
-    SOCKET accept_socket;                 \
-    char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \
-    HANDLE event_handle;                  \
-    HANDLE wait_handle;                   \
-    struct uv_tcp_accept_s* next_pending; \
-  } uv_tcp_accept_t;                      \
-                                          \
-  typedef struct uv_read_s {              \
-    UV_REQ_FIELDS                         \
-    HANDLE event_handle;                  \
-    HANDLE wait_handle;                   \
+#define UV_PRIVATE_REQ_TYPES                                                  \
+  typedef struct uv_pipe_accept_s {                                           \
+    UV_REQ_FIELDS                                                             \
+    HANDLE pipeHandle;                                                        \
+    struct uv_pipe_accept_s* next_pending;                                    \
+  } uv_pipe_accept_t;                                                         \
+                                                                              \
+  typedef struct uv_tcp_accept_s {                                            \
+    UV_REQ_FIELDS                                                             \
+    SOCKET accept_socket;                                                     \
+    char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32];             \
+    HANDLE event_handle;                                                      \
+    HANDLE wait_handle;                                                       \
+    struct uv_tcp_accept_s* next_pending;                                     \
+  } uv_tcp_accept_t;                                                          \
+                                                                              \
+  typedef struct uv_read_s {                                                  \
+    UV_REQ_FIELDS                                                             \
+    HANDLE event_handle;                                                      \
+    HANDLE wait_handle;                                                       \
   } uv_read_t;
 
-#define uv_stream_connection_fields       \
-  unsigned int write_reqs_pending;        \
+#define uv_stream_connection_fields                                           \
+  unsigned int write_reqs_pending;                                            \
   uv_shutdown_t* shutdown_req;
 
-#define uv_stream_server_fields           \
+#define uv_stream_server_fields                                               \
   uv_connection_cb connection_cb;
 
-#define UV_STREAM_PRIVATE_FIELDS          \
-  unsigned int reqs_pending;              \
-  int activecnt;                          \
-  uv_read_t read_req;                     \
-  union {                                 \
-    struct { uv_stream_connection_fields };  \
-    struct { uv_stream_server_fields     };  \
+#define UV_STREAM_PRIVATE_FIELDS                                              \
+  unsigned int reqs_pending;                                                  \
+  int activecnt;                                                              \
+  uv_read_t read_req;                                                         \
+  union {                                                                     \
+    struct { uv_stream_connection_fields };                                   \
+    struct { uv_stream_server_fields     };                                   \
   };
 
-#define uv_tcp_server_fields              \
-  uv_tcp_accept_t* accept_reqs;           \
-  unsigned int processed_accepts;         \
-  uv_tcp_accept_t* pending_accepts;       \
+#define uv_tcp_server_fields                                                  \
+  uv_tcp_accept_t* accept_reqs;                                               \
+  unsigned int processed_accepts;                                             \
+  uv_tcp_accept_t* pending_accepts;                                           \
   LPFN_ACCEPTEX func_acceptex;
 
-#define uv_tcp_connection_fields          \
-  uv_buf_t read_buffer;                   \
+#define uv_tcp_connection_fields                                              \
+  uv_buf_t read_buffer;                                                       \
   LPFN_CONNECTEX func_connectex;
 
-#define UV_TCP_PRIVATE_FIELDS             \
-  SOCKET socket;                          \
-  int bind_error;                         \
-  union {                                 \
-    struct { uv_tcp_server_fields };      \
-    struct { uv_tcp_connection_fields };  \
+#define UV_TCP_PRIVATE_FIELDS                                                 \
+  SOCKET socket;                                                              \
+  int bind_error;                                                             \
+  union {                                                                     \
+    struct { uv_tcp_server_fields };                                          \
+    struct { uv_tcp_connection_fields };                                      \
   };
 
-#define UV_UDP_PRIVATE_FIELDS             \
-  SOCKET socket;                          \
-  unsigned int reqs_pending;              \
-  int activecnt;                          \
-  uv_req_t recv_req;                      \
-  uv_buf_t recv_buffer;                   \
-  struct sockaddr_storage recv_from;      \
-  int recv_from_len;                      \
-  uv_udp_recv_cb recv_cb;                 \
-  uv_alloc_cb alloc_cb;                   \
-  LPFN_WSARECV func_wsarecv;              \
+#define UV_UDP_PRIVATE_FIELDS                                                 \
+  SOCKET socket;                                                              \
+  unsigned int reqs_pending;                                                  \
+  int activecnt;                                                              \
+  uv_req_t recv_req;                                                          \
+  uv_buf_t recv_buffer;                                                       \
+  struct sockaddr_storage recv_from;                                          \
+  int recv_from_len;                                                          \
+  uv_udp_recv_cb recv_cb;                                                     \
+  uv_alloc_cb alloc_cb;                                                       \
+  LPFN_WSARECV func_wsarecv;                                                  \
   LPFN_WSARECVFROM func_wsarecvfrom;
 
-#define uv_pipe_server_fields             \
-  int pending_instances;                  \
-  uv_pipe_accept_t* accept_reqs;          \
+#define uv_pipe_server_fields                                                 \
+  int pending_instances;                                                      \
+  uv_pipe_accept_t* accept_reqs;                                              \
   uv_pipe_accept_t* pending_accepts;
 
-#define uv_pipe_connection_fields         \
-  uv_timer_t* eof_timer;                  \
-  uv_write_t ipc_header_write_req;        \
-  int ipc_pid;                            \
-  uint64_t remaining_ipc_rawdata_bytes;   \
-  unsigned char reserved[sizeof(void*)];  \
-  struct {                                \
-    WSAPROTOCOL_INFOW* socket_info;       \
-    int tcp_connection;                   \
-  } pending_ipc_info;                     \
+#define uv_pipe_connection_fields                                             \
+  uv_timer_t* eof_timer;                                                      \
+  uv_write_t ipc_header_write_req;                                            \
+  int ipc_pid;                                                                \
+  uint64_t remaining_ipc_rawdata_bytes;                                       \
+  unsigned char reserved[sizeof(void*)];                                      \
+  struct {                                                                    \
+    WSAPROTOCOL_INFOW* socket_info;                                           \
+    int tcp_connection;                                                       \
+  } pending_ipc_info;                                                         \
   uv_write_t* non_overlapped_writes_tail;
 
-#define UV_PIPE_PRIVATE_FIELDS            \
-  HANDLE handle;                          \
-  wchar_t* name;                          \
-  union {                                 \
-    struct { uv_pipe_server_fields };     \
-    struct { uv_pipe_connection_fields }; \
+#define UV_PIPE_PRIVATE_FIELDS                                                \
+  HANDLE handle;                                                              \
+  WCHAR* name;                                                                \
+  union {                                                                     \
+    struct { uv_pipe_server_fields };                                         \
+    struct { uv_pipe_connection_fields };                                     \
   };
 
 /* 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             \
-  HANDLE handle;                          \
-  HANDLE read_line_handle;                \
-  uv_buf_t read_line_buffer;              \
-  HANDLE read_raw_wait;                   \
-  DWORD original_console_mode;            \
-  /* Fields used for translating win */   \
-  /* keystrokes into vt100 characters */  \
-  char last_key[8];                       \
-  unsigned char last_key_offset;          \
-  unsigned char last_key_len;             \
-  INPUT_RECORD last_input_record;         \
-  WCHAR last_utf16_high_surrogate;        \
-  /* utf8-to-utf16 conversion state */    \
-  unsigned char utf8_bytes_left;          \
-  unsigned int utf8_codepoint;            \
-  /* eol conversion state */              \
-  unsigned char previous_eol;             \
-  /* ansi parser state */                 \
-  unsigned char ansi_parser_state;        \
-  unsigned char ansi_csi_argc;            \
-  unsigned short ansi_csi_argv[4];        \
-  COORD saved_position;                   \
-  WORD saved_attributes;
-
-#define UV_POLL_PRIVATE_FIELDS            \
-  SOCKET socket;                          \
-  /* Used in fast mode */                 \
-  SOCKET peer_socket;                     \
-  AFD_POLL_INFO afd_poll_info_1;          \
-  AFD_POLL_INFO afd_poll_info_2;          \
-  /* Used in fast and slow mode. */       \
-  uv_req_t poll_req_1;                    \
-  uv_req_t poll_req_2;                    \
-  unsigned char submitted_events_1;       \
-  unsigned char submitted_events_2;       \
-  unsigned char mask_events_1;            \
-  unsigned char mask_events_2;            \
+#define UV_TTY_PRIVATE_FIELDS                                                 \
+  HANDLE handle;                                                              \
+  union {                                                                     \
+    struct {                                                                  \
+      /* Used for readable TTY handles */                                     \
+      HANDLE read_line_handle;                                                \
+      uv_buf_t read_line_buffer;                                              \
+      HANDLE read_raw_wait;                                                   \
+      DWORD original_console_mode;                                            \
+      /* Fields used for translating win keystrokes into vt100 characters */  \
+      char last_key[8];                                                       \
+      unsigned char last_key_offset;                                          \
+      unsigned char last_key_len;                                             \
+      WCHAR last_utf16_high_surrogate;                                        \
+      INPUT_RECORD last_input_record;                                         \
+    };                                                                        \
+    struct {                                                                  \
+      /* Used for writable TTY handles */                                     \
+      /* utf8-to-utf16 conversion state */                                    \
+      unsigned int utf8_codepoint;                                            \
+      unsigned char utf8_bytes_left;                                          \
+      /* eol conversion state */                                              \
+      unsigned char previous_eol;                                             \
+      /* ansi parser state */                                                 \
+      unsigned char ansi_parser_state;                                        \
+      unsigned char ansi_csi_argc;                                            \
+      unsigned short ansi_csi_argv[4];                                        \
+      COORD saved_position;                                                   \
+      WORD saved_attributes;                                                  \
+    };                                                                        \
+  };
+
+#define UV_POLL_PRIVATE_FIELDS                                                \
+  SOCKET socket;                                                              \
+  /* Used in fast mode */                                                     \
+  SOCKET peer_socket;                                                         \
+  AFD_POLL_INFO afd_poll_info_1;                                              \
+  AFD_POLL_INFO afd_poll_info_2;                                              \
+  /* Used in fast and slow mode. */                                           \
+  uv_req_t poll_req_1;                                                        \
+  uv_req_t poll_req_2;                                                        \
+  unsigned char submitted_events_1;                                           \
+  unsigned char submitted_events_2;                                           \
+  unsigned char mask_events_1;                                                \
+  unsigned char mask_events_2;                                                \
   unsigned char events;
 
-#define UV_TIMER_PRIVATE_FIELDS           \
-  RB_ENTRY(uv_timer_s) tree_entry;        \
-  int64_t due;                            \
-  int64_t repeat;                         \
+#define UV_TIMER_PRIVATE_FIELDS                                               \
+  RB_ENTRY(uv_timer_s) tree_entry;                                            \
+  int64_t due;                                                                \
+  int64_t repeat;                                                             \
   uv_timer_cb timer_cb;
 
-#define UV_ASYNC_PRIVATE_FIELDS           \
-  struct uv_req_s async_req;              \
-  uv_async_cb async_cb;                   \
-  /* char to avoid alignment issues */    \
+#define UV_ASYNC_PRIVATE_FIELDS                                               \
+  struct uv_req_s async_req;                                                  \
+  uv_async_cb async_cb;                                                       \
+  /* char to avoid alignment issues */                                        \
   char volatile async_sent;
 
-#define UV_PREPARE_PRIVATE_FIELDS         \
-  uv_prepare_t* prepare_prev;             \
-  uv_prepare_t* prepare_next;             \
+#define UV_PREPARE_PRIVATE_FIELDS                                             \
+  uv_prepare_t* prepare_prev;                                                 \
+  uv_prepare_t* prepare_next;                                                 \
   uv_prepare_cb prepare_cb;
 
-#define UV_CHECK_PRIVATE_FIELDS           \
-  uv_check_t* check_prev;                 \
-  uv_check_t* check_next;                 \
+#define UV_CHECK_PRIVATE_FIELDS                                               \
+  uv_check_t* check_prev;                                                     \
+  uv_check_t* check_next;                                                     \
   uv_check_cb check_cb;
 
-#define UV_IDLE_PRIVATE_FIELDS            \
-  uv_idle_t* idle_prev;                   \
-  uv_idle_t* idle_next;                   \
+#define UV_IDLE_PRIVATE_FIELDS                                                \
+  uv_idle_t* idle_prev;                                                       \
+  uv_idle_t* idle_next;                                                       \
   uv_idle_cb idle_cb;
 
-#define UV_HANDLE_PRIVATE_FIELDS          \
-  uv_handle_t* endgame_next;              \
+#define UV_HANDLE_PRIVATE_FIELDS                                              \
+  uv_handle_t* endgame_next;                                                  \
   unsigned int flags;
 
-#define UV_GETADDRINFO_PRIVATE_FIELDS     \
-  uv_getaddrinfo_cb getaddrinfo_cb;       \
-  void* alloc;                            \
-  wchar_t* node;                          \
-  wchar_t* service;                       \
-  struct addrinfoW* hints;                \
-  struct addrinfoW* res;                  \
+#define UV_GETADDRINFO_PRIVATE_FIELDS                                         \
+  uv_getaddrinfo_cb getaddrinfo_cb;                                           \
+  void* alloc;                                                                \
+  WCHAR* node;                                                                \
+  WCHAR* service;                                                             \
+  struct addrinfoW* hints;                                                    \
+  struct addrinfoW* res;                                                      \
   int retcode;
 
-#define UV_PROCESS_PRIVATE_FIELDS         \
-  struct uv_process_exit_s {              \
-    UV_REQ_FIELDS                         \
-  } exit_req;                             \
-  struct uv_process_close_s {             \
-    UV_REQ_FIELDS                         \
-  } close_req;                            \
-  BYTE* child_stdio_buffer;               \
-  int exit_signal;                        \
-  DWORD spawn_errno;                      \
-  HANDLE wait_handle;                     \
-  HANDLE process_handle;                  \
-  HANDLE close_handle;
-
-#define UV_FS_PRIVATE_FIELDS              \
-  int flags;                              \
-  DWORD sys_errno_;                       \
-  union {                                 \
-    /* TODO: remove me in 0.9. */         \
-    WCHAR* pathw;                         \
-    int fd;                               \
-  };                                      \
-  union {                                 \
-    struct {                              \
-      int mode;                           \
-      WCHAR* new_pathw;                   \
-      int file_flags;                     \
-      int fd_out;                         \
-      void* buf;                          \
-      size_t length;                      \
-      int64_t offset;                     \
-    };                                    \
-    struct _stati64 stat;                 \
-    struct {                              \
-      double atime;                       \
-      double mtime;                       \
-    };                                    \
+#define UV_PROCESS_PRIVATE_FIELDS                                             \
+  struct uv_process_exit_s {                                                  \
+    UV_REQ_FIELDS                                                             \
+  } exit_req;                                                                 \
+  BYTE* child_stdio_buffer;                                                   \
+  uv_err_t spawn_error;                                                       \
+  int exit_signal;                                                            \
+  HANDLE wait_handle;                                                         \
+  HANDLE process_handle;                                                      \
+  volatile char exit_cb_pending;
+
+#define UV_FS_PRIVATE_FIELDS                                                  \
+  int flags;                                                                  \
+  DWORD sys_errno_;                                                           \
+  union {                                                                     \
+    /* TODO: remove me in 0.9. */                                             \
+    WCHAR* pathw;                                                             \
+    int fd;                                                                   \
+  };                                                                          \
+  union {                                                                     \
+    struct {                                                                  \
+      int mode;                                                               \
+      WCHAR* new_pathw;                                                       \
+      int file_flags;                                                         \
+      int fd_out;                                                             \
+      void* buf;                                                              \
+      size_t length;                                                          \
+      int64_t offset;                                                         \
+    };                                                                        \
+    struct _stati64 stat;                                                     \
+    struct {                                                                  \
+      double atime;                                                           \
+      double mtime;                                                           \
+    };                                                                        \
   };
 
-#define UV_WORK_PRIVATE_FIELDS            \
-
-#define UV_FS_EVENT_PRIVATE_FIELDS        \
-  struct uv_fs_event_req_s {              \
-    UV_REQ_FIELDS                         \
-  } req;                                  \
-  HANDLE dir_handle;                      \
-  int req_pending;                        \
-  uv_fs_event_cb cb;                      \
-  wchar_t* filew;                         \
-  wchar_t* short_filew;                   \
-  wchar_t* dirw;                          \
+#define UV_WORK_PRIVATE_FIELDS                                                \
+
+#define UV_FS_EVENT_PRIVATE_FIELDS                                            \
+  struct uv_fs_event_req_s {                                                  \
+    UV_REQ_FIELDS                                                             \
+  } req;                                                                      \
+  HANDLE dir_handle;                                                          \
+  int req_pending;                                                            \
+  uv_fs_event_cb cb;                                                          \
+  WCHAR* filew;                                                               \
+  WCHAR* short_filew;                                                         \
+  WCHAR* dirw;                                                                \
   char* buffer;
 
-int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size,
+#define UV_SIGNAL_PRIVATE_FIELDS                                              \
+  RB_ENTRY(uv_signal_s) tree_entry;                                           \
+  struct uv_req_s signal_req;                                                 \
+  unsigned long pending_signum;
+
+int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
     char* utf8Buffer, size_t utf8Size);
-int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer,
+int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
     size_t utf16Size);
index 19fa6e0..66ee41c 100644 (file)
@@ -19,7 +19,7 @@
  * IN THE SOFTWARE.
  */
 
-/* See uv_loop_new for an introduction. */
+/* See http://nikhilm.github.com/uvbook/ for an introduction. */
 
 #ifndef UV_H
 #define UV_H
@@ -53,6 +53,10 @@ extern "C" {
 #include <stdint.h> /* int64_t */
 #include <sys/types.h> /* size_t */
 
+#if defined(__SVR4) && !defined(__unix__)
+# define __unix__
+#endif
+
 #if defined(__unix__) || defined(__POSIX__) || defined(__APPLE__)
 # include "uv-private/uv-unix.h"
 #else
@@ -60,64 +64,64 @@ extern "C" {
 #endif
 
 /* Expand this list if necessary. */
-#define UV_ERRNO_MAP(XX) \
-  XX( -1, UNKNOWN, "unknown error") \
-  XX(  0, OK, "success") \
-  XX(  1, EOF, "end of file") \
-  XX(  2, EADDRINFO, "getaddrinfo error") \
-  XX(  3, EACCES, "permission denied") \
-  XX(  4, EAGAIN, "no more processes") \
-  XX(  5, EADDRINUSE, "address already in use") \
-  XX(  6, EADDRNOTAVAIL, "") \
-  XX(  7, EAFNOSUPPORT, "") \
-  XX(  8, EALREADY, "") \
-  XX(  9, EBADF, "bad file descriptor") \
-  XX( 10, EBUSY, "resource busy or locked") \
-  XX( 11, ECONNABORTED, "software caused connection abort") \
-  XX( 12, ECONNREFUSED, "connection refused") \
-  XX( 13, ECONNRESET, "connection reset by peer") \
-  XX( 14, EDESTADDRREQ, "destination address required") \
-  XX( 15, EFAULT, "bad address in system call argument") \
-  XX( 16, EHOSTUNREACH, "host is unreachable") \
-  XX( 17, EINTR, "interrupted system call") \
-  XX( 18, EINVAL, "invalid argument") \
-  XX( 19, EISCONN, "socket is already connected") \
-  XX( 20, EMFILE, "too many open files") \
-  XX( 21, EMSGSIZE, "message too long") \
-  XX( 22, ENETDOWN, "network is down") \
-  XX( 23, ENETUNREACH, "network is unreachable") \
-  XX( 24, ENFILE, "file table overflow") \
-  XX( 25, ENOBUFS, "no buffer space available") \
-  XX( 26, ENOMEM, "not enough memory") \
-  XX( 27, ENOTDIR, "not a directory") \
-  XX( 28, EISDIR, "illegal operation on a directory") \
-  XX( 29, ENONET, "machine is not on the network") \
-  XX( 31, ENOTCONN, "socket is not connected") \
-  XX( 32, ENOTSOCK, "socket operation on non-socket") \
-  XX( 33, ENOTSUP, "operation not supported on socket") \
-  XX( 34, ENOENT, "no such file or directory") \
-  XX( 35, ENOSYS, "function not implemented") \
-  XX( 36, EPIPE, "broken pipe") \
-  XX( 37, EPROTO, "protocol error") \
-  XX( 38, EPROTONOSUPPORT, "protocol not supported") \
-  XX( 39, EPROTOTYPE, "protocol wrong type for socket") \
-  XX( 40, ETIMEDOUT, "connection timed out") \
-  XX( 41, ECHARSET, "") \
-  XX( 42, EAIFAMNOSUPPORT, "") \
-  XX( 44, EAISERVICE, "") \
-  XX( 45, EAISOCKTYPE, "") \
-  XX( 46, ESHUTDOWN, "") \
-  XX( 47, EEXIST, "file already exists") \
-  XX( 48, ESRCH, "no such process") \
-  XX( 49, ENAMETOOLONG, "name too long") \
-  XX( 50, EPERM, "operation not permitted") \
-  XX( 51, ELOOP, "too many symbolic links encountered") \
-  XX( 52, EXDEV, "cross-device link not permitted") \
-  XX( 53, ENOTEMPTY, "directory not empty") \
-  XX( 54, ENOSPC, "no space left on device") \
-  XX( 55, EIO, "i/o error") \
-  XX( 56, EROFS, "read-only file system" ) \
-  XX( 57, ENODEV, "no such device" ) \
+#define UV_ERRNO_MAP(XX)                                                      \
+  XX( -1, UNKNOWN, "unknown error")                                           \
+  XX(  0, OK, "success")                                                      \
+  XX(  1, EOF, "end of file")                                                 \
+  XX(  2, EADDRINFO, "getaddrinfo error")                                     \
+  XX(  3, EACCES, "permission denied")                                        \
+  XX(  4, EAGAIN, "no more processes")                                        \
+  XX(  5, EADDRINUSE, "address already in use")                               \
+  XX(  6, EADDRNOTAVAIL, "")                                                  \
+  XX(  7, EAFNOSUPPORT, "")                                                   \
+  XX(  8, EALREADY, "")                                                       \
+  XX(  9, EBADF, "bad file descriptor")                                       \
+  XX( 10, EBUSY, "resource busy or locked")                                   \
+  XX( 11, ECONNABORTED, "software caused connection abort")                   \
+  XX( 12, ECONNREFUSED, "connection refused")                                 \
+  XX( 13, ECONNRESET, "connection reset by peer")                             \
+  XX( 14, EDESTADDRREQ, "destination address required")                       \
+  XX( 15, EFAULT, "bad address in system call argument")                      \
+  XX( 16, EHOSTUNREACH, "host is unreachable")                                \
+  XX( 17, EINTR, "interrupted system call")                                   \
+  XX( 18, EINVAL, "invalid argument")                                         \
+  XX( 19, EISCONN, "socket is already connected")                             \
+  XX( 20, EMFILE, "too many open files")                                      \
+  XX( 21, EMSGSIZE, "message too long")                                       \
+  XX( 22, ENETDOWN, "network is down")                                        \
+  XX( 23, ENETUNREACH, "network is unreachable")                              \
+  XX( 24, ENFILE, "file table overflow")                                      \
+  XX( 25, ENOBUFS, "no buffer space available")                               \
+  XX( 26, ENOMEM, "not enough memory")                                        \
+  XX( 27, ENOTDIR, "not a directory")                                         \
+  XX( 28, EISDIR, "illegal operation on a directory")                         \
+  XX( 29, ENONET, "machine is not on the network")                            \
+  XX( 31, ENOTCONN, "socket is not connected")                                \
+  XX( 32, ENOTSOCK, "socket operation on non-socket")                         \
+  XX( 33, ENOTSUP, "operation not supported on socket")                       \
+  XX( 34, ENOENT, "no such file or directory")                                \
+  XX( 35, ENOSYS, "function not implemented")                                 \
+  XX( 36, EPIPE, "broken pipe")                                               \
+  XX( 37, EPROTO, "protocol error")                                           \
+  XX( 38, EPROTONOSUPPORT, "protocol not supported")                          \
+  XX( 39, EPROTOTYPE, "protocol wrong type for socket")                       \
+  XX( 40, ETIMEDOUT, "connection timed out")                                  \
+  XX( 41, ECHARSET, "")                                                       \
+  XX( 42, EAIFAMNOSUPPORT, "")                                                \
+  XX( 44, EAISERVICE, "")                                                     \
+  XX( 45, EAISOCKTYPE, "")                                                    \
+  XX( 46, ESHUTDOWN, "")                                                      \
+  XX( 47, EEXIST, "file already exists")                                      \
+  XX( 48, ESRCH, "no such process")                                           \
+  XX( 49, ENAMETOOLONG, "name too long")                                      \
+  XX( 50, EPERM, "operation not permitted")                                   \
+  XX( 51, ELOOP, "too many symbolic links encountered")                       \
+  XX( 52, EXDEV, "cross-device link not permitted")                           \
+  XX( 53, ENOTEMPTY, "directory not empty")                                   \
+  XX( 54, ENOSPC, "no space left on device")                                  \
+  XX( 55, EIO, "i/o error")                                                   \
+  XX( 56, EROFS, "read-only file system" )                                    \
+  XX( 57, ENODEV, "no such device" )                                          \
   XX( 58, ECANCELED, "operation canceled" )
 
 
@@ -128,29 +132,30 @@ typedef enum {
 } uv_err_code;
 #undef UV_ERRNO_GEN
 
-#define UV_HANDLE_TYPE_MAP(XX)  \
-  XX(ASYNC, async)              \
-  XX(CHECK, check)              \
-  XX(FS_EVENT, fs_event)        \
-  XX(FS_POLL, fs_poll)          \
-  XX(IDLE, idle)                \
-  XX(NAMED_PIPE, pipe)          \
-  XX(POLL, poll)                \
-  XX(PREPARE, prepare)          \
-  XX(PROCESS, process)          \
-  XX(TCP, tcp)                  \
-  XX(TIMER, timer)              \
-  XX(TTY, tty)                  \
-  XX(UDP, udp)                  \
-
-#define UV_REQ_TYPE_MAP(XX)     \
-  XX(CONNECT, connect)          \
-  XX(WRITE, write)              \
-  XX(SHUTDOWN, shutdown)        \
-  XX(UDP_SEND, udp_send)        \
-  XX(FS, fs)                    \
-  XX(WORK, work)                \
-  XX(GETADDRINFO, getaddrinfo)  \
+#define UV_HANDLE_TYPE_MAP(XX)                                                \
+  XX(ASYNC, async)                                                            \
+  XX(CHECK, check)                                                            \
+  XX(FS_EVENT, fs_event)                                                      \
+  XX(FS_POLL, fs_poll)                                                        \
+  XX(IDLE, idle)                                                              \
+  XX(NAMED_PIPE, pipe)                                                        \
+  XX(POLL, poll)                                                              \
+  XX(PREPARE, prepare)                                                        \
+  XX(PROCESS, process)                                                        \
+  XX(TCP, tcp)                                                                \
+  XX(TIMER, timer)                                                            \
+  XX(TTY, tty)                                                                \
+  XX(UDP, udp)                                                                \
+  XX(SIGNAL, signal)                                                          \
+
+#define UV_REQ_TYPE_MAP(XX)                                                   \
+  XX(CONNECT, connect)                                                        \
+  XX(WRITE, write)                                                            \
+  XX(SHUTDOWN, shutdown)                                                      \
+  XX(UDP_SEND, udp_send)                                                      \
+  XX(FS, fs)                                                                  \
+  XX(WORK, work)                                                              \
+  XX(GETADDRINFO, getaddrinfo)                                                \
 
 typedef enum {
   UV_UNKNOWN_HANDLE = 0,
@@ -189,6 +194,7 @@ typedef struct uv_async_s uv_async_t;
 typedef struct uv_process_s uv_process_t;
 typedef struct uv_fs_event_s uv_fs_event_t;
 typedef struct uv_fs_poll_s uv_fs_poll_t;
+typedef struct uv_signal_s uv_signal_t;
 
 /* Request types. */
 typedef struct uv_req_s uv_req_t;
@@ -312,6 +318,9 @@ typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle,
                               const uv_statbuf_t* prev,
                               const uv_statbuf_t* curr);
 
+typedef void (*uv_signal_cb)(uv_signal_t* handle, int signum);
+
+
 typedef enum {
   UV_LEAVE_GROUP = 0,
   UV_JOIN_GROUP
@@ -336,14 +345,14 @@ UV_EXTERN const char* uv_strerror(uv_err_t err);
 UV_EXTERN const char* uv_err_name(uv_err_t err);
 
 
-#define UV_REQ_FIELDS \
-  /* public */ \
-  void* data; \
-  /* private */ \
-  ngx_queue_t active_queue; \
-  UV_REQ_PRIVATE_FIELDS \
-  /* read-only */ \
-  uv_req_type type; \
+#define UV_REQ_FIELDS                                                         \
+  /* public */                                                                \
+  void* data;                                                                 \
+  /* private */                                                               \
+  ngx_queue_t active_queue;                                                   \
+  UV_REQ_PRIVATE_FIELDS                                                       \
+  /* read-only */                                                             \
+  uv_req_type type;                                                           \
 
 /* Abstract base class of all requests. */
 struct uv_req_s {
@@ -454,13 +463,13 @@ UV_EXTERN size_t uv_strlcpy(char* dst, const char* src, size_t size);
 UV_EXTERN size_t uv_strlcat(char* dst, const char* src, size_t size);
 
 
-#define UV_STREAM_FIELDS \
-  /* number of bytes queued for writing */ \
-  size_t write_queue_size; \
-  uv_alloc_cb alloc_cb; \
-  uv_read_cb read_cb; \
-  uv_read2_cb read2_cb; \
-  /* private */ \
+#define UV_STREAM_FIELDS                                                      \
+  /* number of bytes queued for writing */                                    \
+  size_t write_queue_size;                                                    \
+  uv_alloc_cb alloc_cb;                                                       \
+  uv_read_cb read_cb;                                                         \
+  uv_read2_cb read2_cb;                                                       \
+  /* private */                                                               \
   UV_STREAM_PRIVATE_FIELDS
 
 /*
@@ -1098,8 +1107,7 @@ UV_EXTERN int uv_async_send(uv_async_t* async);
 /*
  * uv_timer_t is a subclass of uv_handle_t.
  *
- * Wraps libev's ev_timer watcher. Used to get woken up at a specified time
- * in the future.
+ * Used to get woken up at a specified time in the future.
  */
 struct uv_timer_s {
   UV_HANDLE_FIELDS
@@ -1108,8 +1116,22 @@ struct uv_timer_s {
 
 UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* timer);
 
-UV_EXTERN int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb,
-    int64_t timeout, int64_t repeat);
+/*
+ * Start the timer. `timeout` and `repeat` are in milliseconds.
+ *
+ * If timeout is zero, the callback fires on the next tick of the event loop.
+ *
+ * If repeat is non-zero, the callback fires first after timeout milliseconds
+ * and then repeatedly after repeat milliseconds.
+ *
+ * timeout and repeat are signed integers but that will change in a future
+ * version of libuv. Don't pass in negative values, you'll get a nasty surprise
+ * when that change becomes effective.
+ */
+UV_EXTERN int uv_timer_start(uv_timer_t* timer,
+                             uv_timer_cb cb,
+                             int64_t timeout,
+                             int64_t repeat);
 
 UV_EXTERN int uv_timer_stop(uv_timer_t* timer);
 
@@ -1121,10 +1143,10 @@ UV_EXTERN int uv_timer_stop(uv_timer_t* timer);
 UV_EXTERN int uv_timer_again(uv_timer_t* timer);
 
 /*
- * Set the repeat value. Note that if the repeat value is set from a timer
- * callback it does not immediately take effect. If the timer was non-repeating
- * before, it will have been stopped. If it was repeating, then the old repeat
- * value will have been used to schedule the next timeout.
+ * Set the repeat value in milliseconds. Note that if the repeat value is set
+ * from a timer callback it does not immediately take effect. If the timer was
+ * non-repeating before, it will have been stopped. If it was repeating, then
+ * the old repeat value will have been used to schedule the next timeout.
  */
 UV_EXTERN void uv_timer_set_repeat(uv_timer_t* timer, int64_t repeat);
 
@@ -1529,14 +1551,17 @@ struct uv_fs_event_s {
 struct uv_fs_poll_s {
   UV_HANDLE_FIELDS
   /* Private, don't touch. */
-  int busy_polling; /* TODO(bnoordhuis) Fold into flags field. */
-  unsigned int interval;
-  uint64_t start_time;
-  char* path;
-  uv_fs_poll_cb poll_cb;
-  uv_timer_t timer_handle;
-  uv_fs_t* fs_req;
-  uv_statbuf_t statbuf;
+  void* poll_ctx;
+  /* v0.8 ABI compatibility */
+  char padding[sizeof(int)
+             + sizeof(unsigned int)
+             + sizeof(uint64_t)
+             + sizeof(char*)
+             + sizeof(uv_fs_poll_cb)
+             + sizeof(uv_timer_t)
+             + sizeof(uv_fs_t*)
+             + sizeof(uv_statbuf_t)
+             - sizeof(void*)];
 };
 
 UV_EXTERN int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle);
@@ -1563,6 +1588,46 @@ UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle,
 
 UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle);
 
+
+/*
+ * UNIX signal handling on a per-event loop basis. The implementation is not
+ * ultra efficient so don't go creating a million event loops with a million
+ * signal watchers.
+ *
+ * TODO(bnoordhuis) As of 2012-08-10 only the default event loop supports
+ *                  signals. That will be fixed.
+ *
+ * Some signal support is available on Windows:
+ *
+ *   SIGINT is normally delivered when the user presses CTRL+C. However, like
+ *   on Unix, it is not generated when terminal raw mode is enabled.
+ *
+ *   SIGBREAK is delivered when the user pressed CTRL+BREAK.
+ *
+ *   SIGHUP is generated when the user closes the console window. On SIGHUP the
+ *   program is given approximately 10 seconds to perform cleanup. After that
+ *   Windows will unconditionally terminate it.
+ *
+ * Watchers for other signals can be successfully created, but these signals
+ * are never generated. These signals are: SIGILL, SIGABRT, SIGFPE, SIGSEGV,
+ * SIGTERM and SIGKILL.
+ *
+ * Note that calls to raise() or abort() to programmatically raise a signal are
+ * not detected by libuv; these will not trigger a signal watcher.
+ */
+struct uv_signal_s {
+  UV_HANDLE_FIELDS
+  uv_signal_cb signal_cb;
+  UV_SIGNAL_PRIVATE_FIELDS
+  int signum;
+};
+
+/* These functions are no-ops on Windows. */
+int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle);
+int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum);
+int uv_signal_stop(uv_signal_t* handle);
+
+
 /*
  * Gets load avg
  * See: http://en.wikipedia.org/wiki/Load_(computing)
@@ -1772,8 +1837,6 @@ struct uv_counters_s {
 
 struct uv_loop_s {
   UV_LOOP_PRIVATE_FIELDS
-  /* Diagnostic counters */
-  uv_counters_t counters;
   /* The last error */
   uv_err_t last_err;
   /* Loop reference counting */
@@ -1800,6 +1863,7 @@ struct uv_loop_s {
 #undef UV_FS_REQ_PRIVATE_FIELDS
 #undef UV_WORK_PRIVATE_FIELDS
 #undef UV_FS_EVENT_PRIVATE_FIELDS
+#undef UV_SIGNAL_PRIVATE_FIELDS
 #undef UV_LOOP_PRIVATE_FIELDS
 #undef UV_LOOP_PRIVATE_PLATFORM_FIELDS
 
index 99d3bcf..c952dfc 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+struct poll_ctx {
+  uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */
+  int busy_polling;
+  unsigned int interval;
+  uint64_t start_time;
+  uv_loop_t* loop;
+  uv_fs_poll_cb poll_cb;
+  uv_timer_t timer_handle;
+  uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */
+  uv_statbuf_t statbuf;
+  char path[1]; /* variable length */
+};
+
 static int statbuf_eq(const uv_statbuf_t* a, const uv_statbuf_t* b);
-static void timer_cb(uv_timer_t* timer, int status);
 static void poll_cb(uv_fs_t* req);
+static void timer_cb(uv_timer_t* timer, int status);
+static void timer_close_cb(uv_handle_t* handle);
 
 static uv_statbuf_t zero_statbuf;
 
 
 int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) {
-  /* TODO(bnoordhuis) Mark fs_req internal. */
   uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL);
-  loop->counters.fs_poll_init++;
-
-  if (uv_timer_init(loop, &handle->timer_handle))
-    return -1;
-
-  handle->timer_handle.flags |= UV__HANDLE_INTERNAL;
-  uv__handle_unref(&handle->timer_handle);
-
   return 0;
 }
 
@@ -52,30 +57,37 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
                      uv_fs_poll_cb cb,
                      const char* path,
                      unsigned int interval) {
-  uv_fs_t* req;
+  struct poll_ctx* ctx;
+  uv_loop_t* loop;
   size_t len;
 
   if (uv__is_active(handle))
     return 0;
 
-  len = strlen(path) + 1;
-  req = malloc(sizeof(*req) + len);
+  loop = handle->loop;
+  len = strlen(path);
+  ctx = calloc(1, sizeof(*ctx) + len);
+
+  if (ctx == NULL)
+    return uv__set_artificial_error(loop, UV_ENOMEM);
 
-  if (req == NULL)
-    return uv__set_artificial_error(handle->loop, UV_ENOMEM);
+  ctx->loop = loop;
+  ctx->poll_cb = cb;
+  ctx->interval = interval ? interval : 1;
+  ctx->start_time = uv_now(loop);
+  ctx->parent_handle = handle;
+  memcpy(ctx->path, path, len + 1);
 
-  req->data = handle;
-  handle->path = memcpy(req + 1, path, len);
-  handle->fs_req = req;
-  handle->poll_cb = cb;
-  handle->interval = interval ? interval : 1;
-  handle->start_time = uv_now(handle->loop);
-  handle->busy_polling = 0;
-  memset(&handle->statbuf, 0, sizeof(handle->statbuf));
+  if (uv_timer_init(loop, &ctx->timer_handle))
+    abort();
+
+  ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;
+  uv__handle_unref(&ctx->timer_handle);
 
-  if (uv_fs_stat(handle->loop, handle->fs_req, handle->path, poll_cb))
+  if (uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb))
     abort();
 
+  handle->poll_ctx = ctx;
   uv__handle_start(handle);
 
   return 0;
@@ -83,25 +95,19 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
 
 
 int uv_fs_poll_stop(uv_fs_poll_t* handle) {
+  struct poll_ctx* ctx;
+
   if (!uv__is_active(handle))
     return 0;
 
-  /* Don't free the fs req if it's active. Signal poll_cb that it needs to free
-   * the req by removing the handle backlink.
-   *
-   * TODO(bnoordhuis) Have uv-unix postpone the close callback until the req
-   * finishes so we don't need this pointer / lifecycle hackery. The callback
-   * always runs on the next tick now.
-   */
-  if (handle->fs_req->data)
-    handle->fs_req->data = NULL;
-  else
-    free(handle->fs_req);
+  ctx = handle->poll_ctx;
+  assert(ctx != NULL);
+  assert(ctx->parent_handle != NULL);
 
-  handle->fs_req = NULL;
-  handle->path = NULL;
+  ctx->parent_handle = NULL;
+  uv_timer_stop(&ctx->timer_handle);
 
-  uv_timer_stop(&handle->timer_handle);
+  handle->poll_ctx = NULL;
   uv__handle_stop(handle);
 
   return 0;
@@ -110,73 +116,75 @@ int uv_fs_poll_stop(uv_fs_poll_t* handle) {
 
 void uv__fs_poll_close(uv_fs_poll_t* handle) {
   uv_fs_poll_stop(handle);
-  uv_close((uv_handle_t*)&handle->timer_handle, NULL);
 }
 
 
 static void timer_cb(uv_timer_t* timer, int status) {
-  uv_fs_poll_t* handle;
+  struct poll_ctx* ctx;
 
-  handle = container_of(timer, uv_fs_poll_t, timer_handle);
-  handle->start_time = uv_now(handle->loop);
-  handle->fs_req->data = handle;
+  ctx = container_of(timer, struct poll_ctx, timer_handle);
 
-  if (uv_fs_stat(handle->loop, handle->fs_req, handle->path, poll_cb))
-    abort();
+  if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */
+    uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
+    return;
+  }
 
-  assert(uv__is_active(handle));
+  assert(ctx->parent_handle->poll_ctx == ctx);
+  ctx->start_time = uv_now(ctx->loop);
+
+  if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb))
+    abort();
 }
 
 
 static void poll_cb(uv_fs_t* req) {
   uv_statbuf_t* statbuf;
-  uv_fs_poll_t* handle;
+  struct poll_ctx* ctx;
   uint64_t interval;
 
-  handle = req->data;
-
-  if (handle == NULL) /* Handle has been stopped or closed. */
-    goto out;
+  ctx = container_of(req, struct poll_ctx, fs_req);
 
-  assert(req == handle->fs_req);
+  if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */
+    uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
+    uv_fs_req_cleanup(req);
+    return;
+  }
 
   if (req->result != 0) {
-    if (handle->busy_polling != -req->errorno) {
-      uv__set_artificial_error(handle->loop, req->errorno);
-      handle->poll_cb(handle, -1, &handle->statbuf, &zero_statbuf);
-      handle->busy_polling = -req->errorno;
+    if (ctx->busy_polling != -req->errorno) {
+      uv__set_artificial_error(ctx->loop, req->errorno);
+      ctx->poll_cb(ctx->parent_handle, -1, &ctx->statbuf, &zero_statbuf);
+      ctx->busy_polling = -req->errorno;
     }
     goto out;
   }
 
   statbuf = req->ptr;
 
-  if (handle->busy_polling != 0)
-    if (handle->busy_polling < 0 || !statbuf_eq(&handle->statbuf, statbuf))
-      handle->poll_cb(handle, 0, &handle->statbuf, statbuf);
+  if (ctx->busy_polling != 0)
+    if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf))
+      ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf);
 
-  handle->statbuf = *statbuf;
-  handle->busy_polling = 1;
+  ctx->statbuf = *statbuf;
+  ctx->busy_polling = 1;
 
 out:
   uv_fs_req_cleanup(req);
 
-  if (req->data == NULL) { /* Handle has been stopped or closed. */
-    free(req);
-    return;
-  }
-
-  req->data = NULL; /* Tell uv_fs_poll_stop() it's safe to free the req. */
-
   /* Reschedule timer, subtract the delay from doing the stat(). */
-  interval = handle->interval;
-  interval -= (uv_now(handle->loop) - handle->start_time) % interval;
+  interval = ctx->interval;
+  interval -= (uv_now(ctx->loop) - ctx->start_time) % interval;
 
-  if (uv_timer_start(&handle->timer_handle, timer_cb, interval, 0))
+  if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0))
     abort();
 }
 
 
+static void timer_close_cb(uv_handle_t* handle) {
+  free(container_of(handle, struct poll_ctx, timer_handle));
+}
+
+
 static int statbuf_eq(const uv_statbuf_t* a, const uv_statbuf_t* b) {
 #ifdef _WIN32
   return a->st_mtime == b->st_mtime
index 192a361..6386c6d 100644 (file)
@@ -65,8 +65,6 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
     return uv__set_sys_error(loop, errno);
 
   uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
-  loop->counters.async_init++;
-
   handle->async_cb = async_cb;
   handle->pending = 0;
 
index 4bc6b77..7b26172 100644 (file)
@@ -116,6 +116,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
     uv__fs_poll_close((uv_fs_poll_t*)handle);
     break;
 
+  case UV_SIGNAL:
+    uv__signal_close((uv_signal_t*)handle);
+    break;
+
   default:
     assert(0);
   }
@@ -143,6 +147,7 @@ static void uv__finish_close(uv_handle_t* handle) {
     case UV_FS_EVENT:
     case UV_FS_POLL:
     case UV_POLL:
+    case UV_SIGNAL:
       break;
 
     case UV_NAMED_PIPE:
index a99779d..8c0797e 100644 (file)
 #define NANOSEC ((uint64_t) 1e9)
 
 
+int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
+  return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
 uint64_t uv_hrtime() {
   struct timespec ts;
   clock_gettime(CLOCK_MONOTONIC, &ts);
-  return (ts.tv_sec * NANOSEC + ts.tv_nsec);
+  return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
 }
 
 void uv_loadavg(double avg[3]) {
@@ -73,7 +82,6 @@ int uv_fs_event_init(uv_loop_t* loop,
                      const char* filename,
                      uv_fs_event_cb cb,
                      int flags) {
-  loop->counters.fs_event_init++;
   uv__set_sys_error(loop, ENOSYS);
   return -1;
 }
index cb45db0..b1586a3 100644 (file)
 
 static char *process_title;
 
+
+int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
+  return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
 #if TARGET_OS_IPHONE
 /* see: http://developer.apple.com/library/mac/#qa/qa1398/_index.html */
 uint64_t uv_hrtime() {
index be8006c..76f2793 100644 (file)
 static char *process_title;
 
 
+int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
+  return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
 uint64_t uv_hrtime(void) {
   struct timespec ts;
   clock_gettime(CLOCK_MONOTONIC, &ts);
-  return (ts.tv_sec * NANOSEC + ts.tv_nsec);
+  return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
 }
 
 
index e62832d..875f0b9 100644 (file)
@@ -72,6 +72,7 @@ static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, uv_fs_type fs_type,
   req->result = 0;
   req->ptr = NULL;
   req->path = path ? strdup(path) : NULL;
+  req->file = -1;
   req->errorno = 0;
   req->eio = NULL;
 
@@ -85,7 +86,7 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
   if (req->cb)
     uv__req_unregister(req->loop, req);
 
-  free(req->path);
+  free((void*)req->path);
   req->path = NULL;
 
   switch (req->fs_type) {
@@ -445,6 +446,20 @@ int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
 }
 
 
+#if defined(__APPLE__) && defined(F_FULLFSYNC)
+ssize_t uv__fs_fdatasync(uv_file file) {
+  return fcntl(file, F_FULLFSYNC);
+}
+
+
+void uv__fs_fdatasync_work(eio_req* eio) {
+  uv_fs_t* req = eio->data;
+
+  eio->result = uv__fs_fdatasync(req->file);
+}
+#endif
+
+
 int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
   char* path = NULL;
 #if defined(__FreeBSD__) \
@@ -453,6 +468,31 @@ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
    * do a full fsync instead.
    */
   WRAP_EIO(UV_FS_FDATASYNC, eio_fdatasync, fsync, ARGS1(file))
+#elif defined(__APPLE__) && defined(F_FULLFSYNC)
+  /* OSX >= 10.6 does have fdatasync, but better use fcntl anyway */
+  uv_fs_req_init(loop, req, UV_FS_FDATASYNC, path, cb);
+  req->file = file;
+
+  if (cb) {
+    /* async */
+    req->eio = eio_custom(uv__fs_fdatasync_work,
+                          EIO_PRI_DEFAULT,
+                          uv__fs_after,
+                          req,
+                          &loop->uv_eio_channel);
+    if (req->eio == NULL) {
+      uv__set_sys_error(loop, ENOMEM);
+      return -1;
+    }
+  } else {
+    /* sync */
+    req->result = uv__fs_fdatasync(file);
+    if (req->result) {
+      uv__set_sys_error(loop, errno);
+    }
+    return req->result;
+  }
+  return 0;
 #else
   WRAP_EIO(UV_FS_FDATASYNC, eio_fdatasync, fdatasync, ARGS1(file))
 #endif
index 233f742..6e16b2c 100644 (file)
@@ -82,7 +82,7 @@
 #define UV__IO_WRITE EV_WRITE
 #define UV__IO_ERROR EV_ERROR
 
-/* flags */
+/* handle flags */
 enum {
   UV_CLOSING          = 0x01,   /* uv_close() called but not finished. */
   UV_CLOSED           = 0x02,   /* close(2) finished. */
@@ -97,10 +97,14 @@ enum {
   UV_TCP_SINGLE_ACCEPT = 0x400  /* Only accept() when idle. */
 };
 
+/* loop flags */
+enum {
+  UV_LOOP_EIO_INITIALIZED = 1
+};
+
 inline static void uv__req_init(uv_loop_t* loop,
                                 uv_req_t* req,
                                 uv_req_type type) {
-  loop->counters.req_init++;
   req->type = type;
   uv__req_register(loop, req);
 }
@@ -153,6 +157,14 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
 void uv__run_timers(uv_loop_t* loop);
 unsigned int uv__next_timeout(uv_loop_t* loop);
 
+/* signal */
+void uv__signal_close(uv_signal_t* handle);
+void uv__signal_unregister(uv_loop_t* loop);
+
+/* platform specific */
+int uv__platform_loop_init(uv_loop_t* loop, int default_loop);
+void uv__platform_loop_delete(uv_loop_t* loop);
+
 /* various */
 void uv__async_close(uv_async_t* handle);
 void uv__check_close(uv_check_t* handle);
index ee1bbd1..be68b58 100644 (file)
@@ -90,8 +90,6 @@ int uv_fs_event_init(uv_loop_t* loop,
                      int flags) {
   int fd;
 
-  loop->counters.fs_event_init++;
-
   /* We don't support any flags yet. */
   assert(!flags);
 
index 51ea996..3c29088 100644 (file)
@@ -176,8 +176,6 @@ int uv_fs_event_init(uv_loop_t* loop,
   int events;
   int wd;
 
-  loop->counters.fs_event_init++;
-
   /* We don't support any flags yet. */
   assert(!flags);
 
index 34f48a9..f20edd0 100644 (file)
@@ -63,15 +63,31 @@ static struct {
   size_t len;
 } process_title;
 
+static void read_models(unsigned int numcpus, uv_cpu_info_t* ci);
+static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
+static void read_times(unsigned int numcpus, uv_cpu_info_t* ci);
+static unsigned long read_cpufreq(unsigned int cpunum);
+
+
+int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
+  loop->inotify_watchers = NULL;
+  loop->inotify_fd = -1;
+  return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+  if (loop->inotify_fd == -1) return;
+  uv__io_stop(loop, &loop->inotify_read_watcher);
+  close(loop->inotify_fd);
+  loop->inotify_fd = -1;
+}
+
 
-/*
- * There's probably some way to get time from Linux than gettimeofday(). What
- * it is, I don't know.
- */
 uint64_t uv_hrtime() {
   struct timespec ts;
   clock_gettime(CLOCK_MONOTONIC, &ts);
-  return (ts.tv_sec * NANOSEC + ts.tv_nsec);
+  return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
 }
 
 
@@ -301,81 +317,163 @@ uv_err_t uv_uptime(double* uptime) {
 
 
 uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
-  unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
-               multiplier = ((uint64_t)1000L / ticks), cpuspeed;
-  int numcpus = 0, i = 0;
-  unsigned long ticks_user, ticks_sys, ticks_idle, ticks_nice, ticks_intr;
-  char line[512], speedPath[256], model[512];
-  FILE *fpStat = fopen("/proc/stat", "r");
-  FILE *fpModel = fopen("/proc/cpuinfo", "r");
-  FILE *fpSpeed;
-  uv_cpu_info_t* cpu_info;
-
-  if (fpModel) {
-    while (fgets(line, 511, fpModel) != NULL) {
-      if (strncmp(line, "model name", 10) == 0) {
-        numcpus++;
-        if (numcpus == 1) {
-          char *p = strchr(line, ':') + 2;
-          strcpy(model, p);
-          model[strlen(model)-1] = 0;
-        }
-      } else if (strncmp(line, "cpu MHz", 7) == 0) {
-        if (numcpus == 1) {
-          sscanf(line, "%*s %*s : %u", &cpuspeed);
-        }
-      }
-    }
-    fclose(fpModel);
-  }
+  unsigned int numcpus;
+  uv_cpu_info_t* ci;
 
-  *cpu_infos = (uv_cpu_info_t*)malloc(numcpus * sizeof(uv_cpu_info_t));
-  if (!(*cpu_infos)) {
-    return uv__new_artificial_error(UV_ENOMEM);
-  }
+  *cpu_infos = NULL;
+  *count = 0;
 
+  numcpus = sysconf(_SC_NPROCESSORS_ONLN);
+  assert(numcpus != (unsigned int) -1);
+  assert(numcpus != 0);
+
+  ci = calloc(numcpus, sizeof(*ci));
+  if (ci == NULL)
+    return uv__new_sys_error(ENOMEM);
+
+  read_speeds(numcpus, ci);
+  read_models(numcpus, ci);
+  read_times(numcpus, ci);
+
+  *cpu_infos = ci;
   *count = numcpus;
 
-  cpu_info = *cpu_infos;
-
-  if (fpStat) {
-    while (fgets(line, 511, fpStat) != NULL) {
-      if (strncmp(line, "cpu ", 4) == 0) {
-        continue;
-      } else if (strncmp(line, "cpu", 3) != 0) {
-        break;
-      }
-
-      sscanf(line, "%*s %lu %lu %lu %lu %*s %lu",
-             &ticks_user, &ticks_nice, &ticks_sys, &ticks_idle, &ticks_intr);
-      snprintf(speedPath, sizeof(speedPath),
-               "/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_max_freq", i);
-
-      fpSpeed = fopen(speedPath, "r");
-
-      if (fpSpeed) {
-        if (fgets(line, 511, fpSpeed) != NULL) {
-          sscanf(line, "%u", &cpuspeed);
-          cpuspeed /= 1000;
-        }
-        fclose(fpSpeed);
-      }
-
-      cpu_info->cpu_times.user = ticks_user * multiplier;
-      cpu_info->cpu_times.nice = ticks_nice * multiplier;
-      cpu_info->cpu_times.sys = ticks_sys * multiplier;
-      cpu_info->cpu_times.idle = ticks_idle * multiplier;
-      cpu_info->cpu_times.irq = ticks_intr * multiplier;
-
-      cpu_info->model = strdup(model);
-      cpu_info->speed = cpuspeed;
-
-      cpu_info++;
+  return uv_ok_;
+}
+
+
+static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
+  unsigned int num;
+
+  for (num = 0; num < numcpus; num++)
+    ci[num].speed = read_cpufreq(num) / 1000;
+}
+
+
+static void read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
+#if defined(__i386__) || defined(__x86_64__)
+  static const char marker[] = "model name\t: ";
+#elif defined(__arm__)
+  static const char marker[] = "Processor\t: ";
+#elif defined(__mips__)
+  static const char marker[] = "cpu model\t\t: ";
+#else
+# warning uv_cpu_info() is not supported on this architecture.
+  static const char marker[] = "(dummy)";
+#endif
+  unsigned int num;
+  char buf[1024];
+  char* model;
+  FILE* fp;
+
+  fp = fopen("/proc/cpuinfo", "r");
+  if (fp == NULL)
+    return;
+
+  num = 0;
+
+  while (fgets(buf, sizeof(buf), fp)) {
+    if (num >= numcpus)
+      break;
+
+    if (strncmp(buf, marker, sizeof(marker) - 1))
+      continue;
+
+    model = buf + sizeof(marker) - 1;
+    model = strndup(model, strlen(model) - 1); /* strip newline */
+    ci[num++].model = model;
+  }
+  fclose(fp);
+}
+
+
+static void read_times(unsigned int numcpus, uv_cpu_info_t* ci) {
+  unsigned long clock_ticks;
+  struct uv_cpu_times_s ts;
+  unsigned long user;
+  unsigned long nice;
+  unsigned long sys;
+  unsigned long idle;
+  unsigned long dummy;
+  unsigned long irq;
+  unsigned int num;
+  unsigned int len;
+  char buf[1024];
+  FILE* fp;
+
+  clock_ticks = sysconf(_SC_CLK_TCK);
+  assert(clock_ticks != (unsigned long) -1);
+  assert(clock_ticks != 0);
+
+  fp = fopen("/proc/stat", "r");
+  if (fp == NULL)
+    return;
+
+  if (!fgets(buf, sizeof(buf), fp))
+    abort();
+
+  num = 0;
+
+  while (fgets(buf, sizeof(buf), fp)) {
+    if (num >= numcpus)
+      break;
+
+    if (strncmp(buf, "cpu", 3))
+      break;
+
+    /* skip "cpu<num> " marker */
+    {
+      unsigned int n = num;
+      for (len = sizeof("cpu0"); n /= 10; len++);
+      assert(sscanf(buf, "cpu%u ", &n) == 1 && n == num);
     }
-    fclose(fpStat);
+
+    /* Line contains user, nice, system, idle, iowait, irq, softirq, steal,
+     * guest, guest_nice but we're only interested in the first four + irq.
+     *
+     * Don't use %*s to skip fields or %ll to read straight into the uint64_t
+     * fields, they're not allowed in C89 mode.
+     */
+    if (6 != sscanf(buf + len,
+                    "%lu %lu %lu %lu %lu %lu",
+                    &user,
+                    &nice,
+                    &sys,
+                    &idle,
+                    &dummy,
+                    &irq))
+      abort();
+
+    ts.user = clock_ticks * user;
+    ts.nice = clock_ticks * nice;
+    ts.sys  = clock_ticks * sys;
+    ts.idle = clock_ticks * idle;
+    ts.irq  = clock_ticks * irq;
+    ci[num++].cpu_times = ts;
   }
+  fclose(fp);
+}
 
-  return uv_ok_;
+
+static unsigned long read_cpufreq(unsigned int cpunum) {
+  unsigned long val;
+  char buf[1024];
+  FILE* fp;
+
+  snprintf(buf,
+           sizeof(buf),
+           "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq",
+           cpunum);
+
+  fp = fopen(buf, "r");
+  if (fp == NULL)
+    return 0;
+
+  val = 0;
+  fscanf(fp, "%lu", &val);
+  fclose(fp);
+
+  return val;
 }
 
 
index 6e6a689..9d1414b 100644 (file)
@@ -25,7 +25,6 @@
 #define UV_LOOP_WATCHER_DEFINE(name, type)                                    \
   int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) {              \
     uv__handle_init(loop, (uv_handle_t*)handle, UV_##type);                   \
-    loop->counters.name##_init++;                                             \
     handle->name##_cb = NULL;                                                 \
     return 0;                                                                 \
   }                                                                           \
index bd91c01..70cdc82 100644 (file)
 
 
 int uv__loop_init(uv_loop_t* loop, int default_loop) {
+  unsigned int i;
+  int flags;
+
 #if HAVE_KQUEUE
-  int flags = EVBACKEND_KQUEUE;
+  flags = EVBACKEND_KQUEUE;
 #else
-  int flags = EVFLAG_AUTO;
+  flags = EVFLAG_AUTO;
 #endif
 
   memset(loop, 0, sizeof(*loop));
@@ -44,6 +47,7 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
   ngx_queue_init(&loop->prepare_handles);
   ngx_queue_init(&loop->handle_queue);
   loop->closing_handles = NULL;
+  loop->signal_ctx = NULL;
   loop->time = uv_hrtime() / 1000000;
   loop->async_pipefd[0] = -1;
   loop->async_pipefd[1] = -1;
@@ -51,28 +55,22 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
   ev_set_userdata(loop->ev, loop);
   eio_channel_init(&loop->uv_eio_channel, loop);
 
-#if __linux__
-  loop->inotify_watchers = NULL;
-  loop->inotify_fd = -1;
-#endif
-#if HAVE_PORTS_FS
-  loop->fs_fd = -1;
-#endif
+  uv_signal_init(loop, &loop->child_watcher);
+  uv__handle_unref(&loop->child_watcher);
+  loop->child_watcher.flags |= UV__HANDLE_INTERNAL;
+
+  for (i = 0; i < ARRAY_SIZE(loop->process_handles); i++)
+    ngx_queue_init(loop->process_handles + i);
+
+  if (uv__platform_loop_init(loop, default_loop))
+    return -1;
+
   return 0;
 }
 
 
 void uv__loop_delete(uv_loop_t* loop) {
+  uv__platform_loop_delete(loop);
+  uv__signal_unregister(loop);
   ev_loop_destroy(loop->ev);
-#if __linux__
-  if (loop->inotify_fd != -1) {
-    uv__io_stop(loop, &loop->inotify_read_watcher);
-    close(loop->inotify_fd);
-    loop->inotify_fd = -1;
-  }
-#endif
-#if HAVE_PORTS_FS
-  if (loop->fs_fd != -1)
-    close(loop->fs_fd);
-#endif
 }
index a1a7091..b1c437b 100644 (file)
 #define NANOSEC ((uint64_t) 1e9)
 
 
+int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
+  return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
 uint64_t uv_hrtime(void) {
   struct timespec ts;
   clock_gettime(CLOCK_MONOTONIC, &ts);
-  return (ts.tv_sec * NANOSEC + ts.tv_nsec);
+  return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
 }
 
 void uv_loadavg(double avg[3]) {
index 865f8e9..4319270 100644 (file)
 static char *process_title;
 
 
+int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
+  return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
 uint64_t uv_hrtime(void) {
   struct timespec ts;
   clock_gettime(CLOCK_MONOTONIC, &ts);
-  return (ts.tv_sec * NANOSEC + ts.tv_nsec);
+  return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
 }
 
 
index 957e96f..30809dc 100644 (file)
@@ -34,7 +34,6 @@ static void uv__pipe_accept(uv_loop_t* loop, uv__io_t* w, int events);
 
 int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
   uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
-  loop->counters.pipe_init++;
   handle->shutdown_req = NULL;
   handle->connect_req = NULL;
   handle->pipe_fname = NULL;
index 13796ab..8d6e299 100644 (file)
@@ -54,8 +54,6 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, int events) {
 
 int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
   uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
-  loop->counters.poll_init++;
-
   handle->fd = fd;
   handle->poll_cb = NULL;
   uv__io_init(&handle->io_watcher, uv__poll_io, fd, 0);
index 4d54e04..67f2d73 100644 (file)
 #include "uv.h"
 #include "internal.h"
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <assert.h>
 #include <errno.h>
+
+#include <sys/types.h>
 #include <sys/wait.h>
-#include <poll.h>
 #include <unistd.h>
-#include <stdio.h>
 #include <fcntl.h>
+#include <poll.h>
 
 #ifdef __APPLE__
 # include <TargetConditionals.h>
@@ -42,26 +45,71 @@ extern char **environ;
 #endif
 
 
-static void uv__chld(EV_P_ ev_child* watcher, int revents) {
-  int status = watcher->rstatus;
-  int exit_status = 0;
-  int term_signal = 0;
-  uv_process_t *process = watcher->data;
+static ngx_queue_t* uv__process_queue(uv_loop_t* loop, int pid) {
+  assert(pid > 0);
+  return loop->process_handles + pid % ARRAY_SIZE(loop->process_handles);
+}
 
-  assert(&process->child_watcher == watcher);
-  assert(revents & EV_CHILD);
 
-  ev_child_stop(EV_A_ &process->child_watcher);
+static uv_process_t* uv__process_find(uv_loop_t* loop, int pid) {
+  uv_process_t* handle;
+  ngx_queue_t* h;
+  ngx_queue_t* q;
 
-  if (WIFEXITED(status)) {
-    exit_status = WEXITSTATUS(status);
-  }
+  h = uv__process_queue(loop, pid);
 
-  if (WIFSIGNALED(status)) {
-    term_signal = WTERMSIG(status);
+  ngx_queue_foreach(q, h) {
+    handle = ngx_queue_data(q, uv_process_t, queue);
+    if (handle->pid == pid) return handle;
   }
 
-  if (process->exit_cb) {
+  return NULL;
+}
+
+
+static void uv__chld(uv_signal_t* handle, int signum) {
+  uv_process_t* process;
+  int exit_status;
+  int term_signal;
+  int status;
+  pid_t pid;
+
+  assert(signum == SIGCHLD);
+
+  for (;;) {
+    pid = waitpid(-1, &status, WNOHANG);
+
+    if (pid == 0)
+      return;
+
+    if (pid == -1) {
+      if (errno == ECHILD)
+        return; /* XXX stop signal watcher? */
+      else
+        abort();
+    }
+
+    process = uv__process_find(handle->loop, pid);
+    if (process == NULL)
+      continue; /* XXX bug? abort? */
+
+    if (process->exit_cb == NULL)
+      continue;
+
+    exit_status = 0;
+    term_signal = 0;
+
+    if (WIFEXITED(status))
+      exit_status = WEXITSTATUS(status);
+
+    if (WIFSIGNALED(status))
+      term_signal = WTERMSIG(status);
+
+    if (process->errorno) {
+      uv__set_sys_error(process->loop, process->errorno);
+      exit_status = -1; /* execve() failed */
+    }
+
     process->exit_cb(process, exit_status, term_signal);
   }
 }
@@ -122,8 +170,7 @@ int uv__make_pipe(int fds[2], int flags) {
  * Used for initializing stdio streams like options.stdin_stream. Returns
  * zero on success.
  */
-static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2],
-                                  int writable) {
+static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
   int fd = -1;
   switch (container->flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
                               UV_INHERIT_STREAM)) {
@@ -151,7 +198,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2],
         return -1;
       }
 
-      fds[writable ? 1 : 0] = fd;
+      fds[1] = fd;
 
       return 0;
     default:
@@ -174,16 +221,19 @@ static int uv__process_stdio_flags(uv_stdio_container_t* container,
 }
 
 
-static int uv__process_open_stream(uv_stdio_container_t* container, int fds[2],
+static int uv__process_open_stream(uv_stdio_container_t* container,
+                                   int fds[2],
                                    int writable) {
-  int fd = fds[writable ? 1 : 0];
-  int child_fd = fds[writable ? 0 : 1];
+  int child_fd;
   int flags;
+  int fd;
+
+  fd = fds[0];
+  child_fd = fds[1];
 
   /* No need to create stream */
-  if (!(container->flags & UV_CREATE_PIPE) || fd < 0) {
+  if (!(container->flags & UV_CREATE_PIPE) || fd < 0)
     return 0;
-  }
 
   assert(child_fd >= 0);
   close(child_fd);
@@ -197,62 +247,78 @@ static int uv__process_open_stream(uv_stdio_container_t* container, int fds[2],
 
 static void uv__process_close_stream(uv_stdio_container_t* container) {
   if (!(container->flags & UV_CREATE_PIPE)) return;
-
   uv__stream_close((uv_stream_t*)container->data.stream);
 }
 
 
+static void uv__write_int(int fd, int val) {
+  ssize_t n;
+
+  do
+    n = write(fd, &val, sizeof(val));
+  while (n == -1 && errno == EINTR);
+
+  if (n == -1 && errno == EPIPE)
+    return; /* parent process has quit */
+
+  assert(n == sizeof(val));
+}
+
+
 static void uv__process_child_init(uv_process_options_t options,
                                    int stdio_count,
-                                   int* pipes) {
+                                   int (*pipes)[2],
+                                   int error_fd) {
+  int close_fd;
+  int use_fd;
   int i;
 
-  if (options.flags & UV_PROCESS_DETACHED) {
+  if (options.flags & UV_PROCESS_DETACHED)
     setsid();
-  }
 
-  /* Dup fds */
   for (i = 0; i < stdio_count; i++) {
-    /*
-     * stdin has swapped ends of pipe
-     * (it's the only one readable stream)
-     */
-    int close_fd = i == 0 ? pipes[i * 2 + 1] : pipes[i * 2];
-    int use_fd = i == 0 ? pipes[i * 2] : pipes[i * 2 + 1];
-
-    if (use_fd >= 0) {
+    close_fd = pipes[i][0];
+    use_fd = pipes[i][1];
+
+    if (use_fd >= 0)
       close(close_fd);
-    } else if (i < 3) {
-      /* `/dev/null` stdin, stdout, stderr even if they've flag UV_IGNORE */
+    else if (i >= 3)
+      continue;
+    else {
+      /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
+       * set
+       */
       use_fd = open("/dev/null", i == 0 ? O_RDONLY : O_RDWR);
 
-      if (use_fd < 0) {
+      if (use_fd == -1) {
+        uv__write_int(error_fd, errno);
         perror("failed to open stdio");
         _exit(127);
       }
-    } else {
-      continue;
     }
 
-    if (i != use_fd) {
+    if (i == use_fd)
+      uv__cloexec(use_fd, 0);
+    else {
       dup2(use_fd, i);
       close(use_fd);
-    } else {
-      uv__cloexec(use_fd, 0);
     }
   }
 
   if (options.cwd && chdir(options.cwd)) {
+    uv__write_int(error_fd, errno);
     perror("chdir()");
     _exit(127);
   }
 
   if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) {
+    uv__write_int(error_fd, errno);
     perror("setgid()");
     _exit(127);
   }
 
   if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) {
+    uv__write_int(error_fd, errno);
     perror("setuid()");
     _exit(127);
   }
@@ -260,63 +326,57 @@ static void uv__process_child_init(uv_process_options_t options,
   environ = options.env;
 
   execvp(options.file, options.args);
+  uv__write_int(error_fd, errno);
   perror("execvp()");
   _exit(127);
 }
 
 
-#ifndef SPAWN_WAIT_EXEC
-# define SPAWN_WAIT_EXEC 1
-#endif
-
-int uv_spawn(uv_loop_t* loop, uv_process_t* process,
-    uv_process_options_t options) {
-  /*
-   * Save environ in the case that we get it clobbered
-   * by the child process.
-   */
-  char** save_our_env = environ;
-
-  int stdio_count = options.stdio_count < 3 ? 3 : options.stdio_count;
-  int* pipes = malloc(2 * stdio_count * sizeof(int));
-
-#if SPAWN_WAIT_EXEC
+int uv_spawn(uv_loop_t* loop,
+             uv_process_t* process,
+             const uv_process_options_t options) {
   int signal_pipe[2] = { -1, -1 };
-  struct pollfd pfd;
-#endif
-  int status;
+  int (*pipes)[2];
+  int stdio_count;
+  ngx_queue_t* q;
+  ssize_t r;
   pid_t pid;
   int i;
 
-  if (pipes == NULL) {
-    errno = ENOMEM;
-    goto error;
-  }
-
   assert(options.file != NULL);
   assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
                              UV_PROCESS_DETACHED |
                              UV_PROCESS_SETGID |
                              UV_PROCESS_SETUID)));
 
-
   uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
-  loop->counters.process_init++;
-  uv__handle_start(process);
+  ngx_queue_init(&process->queue);
 
-  process->exit_cb = options.exit_cb;
+  stdio_count = options.stdio_count;
+  if (stdio_count < 3)
+    stdio_count = 3;
+
+  pipes = malloc(stdio_count * sizeof(*pipes));
+  if (pipes == NULL) {
+    errno = ENOMEM;
+    goto error;
+  }
 
-  /* Init pipe pairs */
   for (i = 0; i < stdio_count; i++) {
-    pipes[i * 2] = -1;
-    pipes[i * 2 + 1] = -1;
+    pipes[i][0] = -1;
+    pipes[i][1] = -1;
   }
 
-  /* Create socketpairs/pipes, or use raw fd */
-  for (i = 0; i < options.stdio_count; i++) {
-    if (uv__process_init_stdio(&options.stdio[i], pipes + i * 2, i != 0)) {
+  for (i = 0; i < options.stdio_count; i++)
+    if (uv__process_init_stdio(options.stdio + i, pipes[i]))
       goto error;
-    }
+
+  /* swap stdin file descriptors, it's the only writable stream */
+  {
+    int* p = pipes[0];
+    int t = p[0];
+    p[0] = p[1];
+    p[1] = t;
   }
 
   /* This pipe is used by the parent to wait until
@@ -337,81 +397,68 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
    *
    * To avoid ambiguity, we create a pipe with both ends
    * marked close-on-exec. Then, after the call to `fork()`,
-   * the parent polls the read end until it sees POLLHUP.
+   * the parent polls the read end until it EOFs or errors with EPIPE.
    */
-#if SPAWN_WAIT_EXEC
-  if (uv__make_pipe(signal_pipe, UV__F_NONBLOCK))
+  if (uv__make_pipe(signal_pipe, 0))
     goto error;
-#endif
+
+  uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
 
   pid = fork();
 
   if (pid == -1) {
-#if SPAWN_WAIT_EXEC
     close(signal_pipe[0]);
     close(signal_pipe[1]);
-#endif
-    environ = save_our_env;
     goto error;
   }
 
   if (pid == 0) {
-    /* Child */
-    uv__process_child_init(options, stdio_count, pipes);
-
-    /* Execution never reaches here. */
+    uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
+    abort();
   }
 
-  /* Parent. */
-
-  /* Restore environment. */
-  environ = save_our_env;
-
-#if SPAWN_WAIT_EXEC
-  /* POLLHUP signals child has exited or execve()'d. */
   close(signal_pipe[1]);
-  do {
-    pfd.fd = signal_pipe[0];
-    pfd.events = POLLIN|POLLHUP;
-    pfd.revents = 0;
-    errno = 0, status = poll(&pfd, 1, -1);
-  }
-  while (status == -1 && (errno == EINTR || errno == ENOMEM));
 
-  assert((status == 1) && "poll() on pipe read end failed");
-  close(signal_pipe[0]);
-#endif
+  process->errorno = 0;
+  do
+    r = read(signal_pipe[0], &process->errorno, sizeof(process->errorno));
+  while (r == -1 && errno == EINTR);
 
-  process->pid = pid;
+  if (r == 0)
+    ; /* okay, EOF */
+  else if (r == sizeof(process->errorno))
+    ; /* okay, read errorno */
+  else if (r == -1 && errno == EPIPE)
+    ; /* okay, got EPIPE */
+  else
+    abort();
 
-  ev_child_init(&process->child_watcher, uv__chld, pid, 0);
-  ev_child_start(process->loop->ev, &process->child_watcher);
-  process->child_watcher.data = process;
+  close(signal_pipe[0]);
 
   for (i = 0; i < options.stdio_count; i++) {
-    if (uv__process_open_stream(&options.stdio[i], pipes + i * 2, i == 0)) {
-      int j;
-      /* Close all opened streams */
-      for (j = 0; j < i; j++) {
-        uv__process_close_stream(&options.stdio[j]);
-      }
-
+    if (uv__process_open_stream(options.stdio + i, pipes[i], i == 0)) {
+      while (i--) uv__process_close_stream(options.stdio + i);
       goto error;
     }
   }
 
-  free(pipes);
+  q = uv__process_queue(loop, pid);
+  ngx_queue_insert_tail(q, &process->queue);
+
+  process->pid = pid;
+  process->exit_cb = options.exit_cb;
+  uv__handle_start(process);
 
+  free(pipes);
   return 0;
 
 error:
   uv__set_sys_error(process->loop, errno);
 
   for (i = 0; i < stdio_count; i++) {
-    close(pipes[i * 2]);
-    close(pipes[i * 2 + 1]);
+    close(pipes[i][0]);
+    close(pipes[i][1]);
   }
-
   free(pipes);
 
   return -1;
@@ -442,6 +489,7 @@ uv_err_t uv_kill(int pid, int signum) {
 
 
 void uv__process_close(uv_process_t* handle) {
-  ev_child_stop(handle->loop->ev, &handle->child_watcher);
+  /* TODO stop signal watcher when this is the last handle */
+  ngx_queue_remove(&handle->queue);
   uv__handle_stop(handle);
 }
diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c
new file mode 100644 (file)
index 0000000..8ef640b
--- /dev/null
@@ -0,0 +1,269 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+
+struct signal_ctx {
+  int pipefd[2];
+  uv__io_t io_watcher;
+  unsigned int nqueues;
+  ngx_queue_t queues[1]; /* variable length */
+};
+
+static void uv__signal_handler(int signum);
+static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, int events);
+static struct signal_ctx* uv__signal_ctx_new(uv_loop_t* loop);
+static void uv__signal_ctx_delete(struct signal_ctx* ctx);
+static void uv__signal_write(int fd, unsigned int val);
+static unsigned int uv__signal_read(int fd);
+static unsigned int uv__signal_max(void);
+
+
+int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
+  uv__handle_init(loop, (uv_handle_t*)handle, UV_SIGNAL);
+  handle->signum = 0;
+  return 0;
+}
+
+
+int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum_) {
+  struct signal_ctx* ctx;
+  struct sigaction sa;
+  unsigned int signum;
+  uv_loop_t* loop;
+  ngx_queue_t* q;
+
+  /* XXX doing this check in uv_signal_init() - the logical place for it -
+   * leads to an infinite loop when uv__loop_init() inits a signal watcher
+   */
+  /* FIXME */
+  assert(handle->loop == uv_default_loop() &&
+         "uv_signal_t is currently only supported by the default loop");
+
+  loop = handle->loop;
+  signum = signum_;
+
+  if (uv__is_active(handle))
+    return uv__set_artificial_error(loop, UV_EBUSY);
+
+  if (signal_cb == NULL)
+    return uv__set_artificial_error(loop, UV_EINVAL);
+
+  if (signum <= 0)
+    return uv__set_artificial_error(loop, UV_EINVAL);
+
+  ctx = loop->signal_ctx;
+
+  if (ctx == NULL) {
+    ctx = uv__signal_ctx_new(loop);
+
+    if (ctx == NULL)
+      return uv__set_artificial_error(loop, UV_ENOMEM);
+
+    loop->signal_ctx = ctx;
+  }
+
+  if (signum > ctx->nqueues)
+    return uv__set_artificial_error(loop, UV_EINVAL);
+
+  q = ctx->queues + signum;
+
+  if (!ngx_queue_empty(q))
+    goto skip;
+
+  /* XXX use a separate signal stack? */
+  memset(&sa, 0, sizeof(sa));
+  sa.sa_handler = uv__signal_handler;
+
+  /* XXX save old action so we can restore it later on? */
+  if (sigaction(signum, &sa, NULL))
+    return uv__set_artificial_error(loop, UV_EINVAL);
+
+skip:
+  ngx_queue_insert_tail(q, &handle->queue);
+  uv__handle_start(handle);
+  handle->signum = signum;
+  handle->signal_cb = signal_cb;
+
+  return 0;
+}
+
+
+int uv_signal_stop(uv_signal_t* handle) {
+  struct signal_ctx* ctx;
+  struct sigaction sa;
+  unsigned int signum;
+  uv_loop_t* loop;
+
+  if (!uv__is_active(handle))
+    return 0;
+
+  signum = handle->signum;
+  loop = handle->loop;
+  ctx = loop->signal_ctx;
+  assert(signum > 0);
+  assert(signum <= ctx->nqueues);
+
+  ngx_queue_remove(&handle->queue);
+  uv__handle_stop(handle);
+  handle->signum = 0;
+
+  if (!ngx_queue_empty(ctx->queues + signum))
+    goto skip;
+
+  memset(&sa, 0, sizeof(sa));
+  sa.sa_handler = SIG_DFL; /* XXX restore previous action? */
+
+  if (sigaction(signum, &sa, NULL))
+    return uv__set_artificial_error(loop, UV_EINVAL);
+
+skip:
+  return 0;
+}
+
+
+void uv__signal_close(uv_signal_t* handle) {
+  uv_signal_stop(handle);
+}
+
+
+void uv__signal_unregister(uv_loop_t* loop) {
+  uv__signal_ctx_delete(loop->signal_ctx);
+  loop->signal_ctx = NULL;
+}
+
+
+static void uv__signal_handler(int signum) {
+  struct signal_ctx* ctx = uv_default_loop()->signal_ctx;
+  uv__signal_write(ctx->pipefd[1], (unsigned int) signum);
+}
+
+
+static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, int events) {
+  struct signal_ctx* ctx;
+  unsigned int signum;
+  uv_signal_t* h;
+  ngx_queue_t* q;
+
+  ctx = container_of(w, struct signal_ctx, io_watcher);
+  signum = uv__signal_read(ctx->pipefd[0]);
+  assert(signum > 0);
+  assert(signum <= ctx->nqueues);
+
+  ngx_queue_foreach(q, ctx->queues + signum) {
+    h = ngx_queue_data(q, uv_signal_t, queue);
+    h->signal_cb(h, signum);
+  }
+}
+
+
+static struct signal_ctx* uv__signal_ctx_new(uv_loop_t* loop) {
+  struct signal_ctx* ctx;
+  unsigned int nqueues;
+  unsigned int i;
+
+  nqueues = uv__signal_max();
+  assert(nqueues > 0);
+
+  /* The first ctx->queues entry is never used. It wastes a few bytes of memory
+   * but it saves us from having to substract 1 from the signum all the time -
+   * which inevitably someone will forget to do.
+   */
+  ctx = calloc(1, sizeof(*ctx) + sizeof(ctx->queues[0]) * (nqueues + 1));
+  if (ctx == NULL)
+    return NULL;
+
+  if (uv__make_pipe(ctx->pipefd, UV__F_NONBLOCK)) {
+    free(ctx);
+    return NULL;
+  }
+
+  uv__io_init(&ctx->io_watcher, uv__signal_event, ctx->pipefd[0], UV__IO_READ);
+  uv__io_start(loop, &ctx->io_watcher);
+  ctx->nqueues = nqueues;
+
+  for (i = 1; i <= nqueues; i++)
+    ngx_queue_init(ctx->queues + i);
+
+  return ctx;
+}
+
+
+static void uv__signal_ctx_delete(struct signal_ctx* ctx) {
+  if (ctx == NULL) return;
+  close(ctx->pipefd[0]);
+  close(ctx->pipefd[1]);
+  free(ctx);
+}
+
+
+static void uv__signal_write(int fd, unsigned int val) {
+  ssize_t n;
+
+  do
+    n = write(fd, &val, sizeof(val));
+  while (n == -1 && errno == EINTR);
+
+  if (n == sizeof(val))
+    return;
+
+  if (n == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
+    return; /* pipe full - nothing we can do about that */
+
+  abort();
+}
+
+
+static unsigned int uv__signal_read(int fd) {
+  unsigned int val;
+  ssize_t n;
+
+  do
+    n = read(fd, &val, sizeof(val));
+  while (n == -1 && errno == EINTR);
+
+  if (n == sizeof(val))
+    return val;
+
+  abort();
+}
+
+
+static unsigned int uv__signal_max(void) {
+#if defined(_SC_RTSIG_MAX)
+  int max = sysconf(_SC_RTSIG_MAX);
+  if (max != -1) return max;
+#endif
+#if defined(SIGRTMAX)
+  return SIGRTMAX;
+#elif defined(NSIG)
+  return NSIG;
+#else
+  return 32;
+#endif
+}
index 26875a7..0ab86f3 100644 (file)
@@ -57,8 +57,6 @@ void uv__stream_init(uv_loop_t* loop,
                      uv_stream_t* stream,
                      uv_handle_type type) {
   uv__handle_init(loop, (uv_handle_t*)stream, type);
-  loop->counters.stream_init++;
-
   stream->alloc_cb = NULL;
   stream->close_cb = NULL;
   stream->connection_cb = NULL;
@@ -489,7 +487,6 @@ start:
   } else {
     /* Successful write */
 
-    /* Update the counters. */
     while (n >= 0) {
       uv_buf_t* buf = &(req->bufs[req->write_index]);
       size_t len = buf->len;
@@ -834,10 +831,16 @@ static void uv__stream_connect(uv_stream_t* stream) {
 }
 
 
-int uv_write2(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt,
-    uv_stream_t* send_handle, uv_write_cb cb) {
+int uv_write2(uv_write_t* req,
+              uv_stream_t* stream,
+              uv_buf_t bufs[],
+              int bufcnt,
+              uv_stream_t* send_handle,
+              uv_write_cb cb) {
   int empty_queue;
 
+  assert(bufcnt > 0);
+
   assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
       stream->type == UV_TTY) &&
       "uv_write (unix) does not yet support other types of streams");
@@ -864,7 +867,7 @@ int uv_write2(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt,
   req->send_handle = send_handle;
   ngx_queue_init(&req->queue);
 
-  if (bufcnt <= UV_REQ_BUFSML_SIZE)
+  if (bufcnt <= (int) ARRAY_SIZE(req->bufsml))
     req->bufs = req->bufsml;
   else
     req->bufs = malloc(sizeof(uv_buf_t) * bufcnt);
index 8c626a3..18412b8 100644 (file)
 #endif
 
 
+int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
+  loop->fs_fd = -1;
+  return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+  if (loop->fs_fd == -1) return;
+  close(loop->fs_fd);
+  loop->fs_fd = -1;
+}
+
+
 uint64_t uv_hrtime() {
   return (gethrtime());
 }
@@ -183,8 +196,6 @@ int uv_fs_event_init(uv_loop_t* loop,
   int portfd;
   int first_run = 0;
 
-  loop->counters.fs_event_init++;
-
   /* We don't support any flags yet. */
   assert(!flags);
   if (loop->fs_fd == -1) {
@@ -233,7 +244,6 @@ int uv_fs_event_init(uv_loop_t* loop,
                      const char* filename,
                      uv_fs_event_cb cb,
                      int flags) {
-  loop->counters.fs_event_init++;
   uv__set_sys_error(loop, ENOSYS);
   return -1;
 }
@@ -344,8 +354,10 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
       cpu_info->model = NULL;
     } else {
       knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"clock_MHz");
-      assert(knp->data_type == KSTAT_DATA_INT32);
-      cpu_info->speed = knp->value.i32;
+      assert(knp->data_type == KSTAT_DATA_INT32 ||
+             knp->data_type == KSTAT_DATA_INT64);
+      cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32
+                                                             : knp->value.i64;
 
       knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"brand");
       assert(knp->data_type == KSTAT_DATA_STRING);
index d9cbd0b..441473c 100644 (file)
@@ -30,7 +30,6 @@
 
 int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
   uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
-  loop->counters.tcp_init++;
   tcp->idle_handle = NULL;
   return 0;
 }
index 0d81997..a560584 100644 (file)
@@ -39,8 +39,6 @@ RB_GENERATE_STATIC(uv__timers, uv_timer_s, tree_entry, uv__timer_cmp)
 
 
 int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
-  loop->counters.timer_init++;
-
   uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
   handle->timer_cb = NULL;
 
index 7193db8..3ef9064 100644 (file)
@@ -45,7 +45,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
     tty->flags |= UV_STREAM_BLOCKING;
   }
 
-  loop->counters.tty_init++;
   tty->mode = 0;
   return 0;
 }
index 9f87060..1838bc7 100644 (file)
@@ -418,6 +418,8 @@ static int uv__udp_send(uv_udp_send_t* req,
                         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))
     return -1;
 
@@ -429,7 +431,7 @@ static int uv__udp_send(uv_udp_send_t* req,
   req->handle = handle;
   req->bufcnt = bufcnt;
 
-  if (bufcnt <= UV_REQ_BUFSML_SIZE) {
+  if (bufcnt <= (int) ARRAY_SIZE(req->bufsml)) {
     req->bufs = req->bufsml;
   }
   else if ((req->bufs = malloc(bufcnt * sizeof(bufs[0]))) == NULL) {
@@ -453,8 +455,6 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
   memset(handle, 0, sizeof *handle);
 
   uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
-  loop->counters.udp_init++;
-
   handle->fd = -1;
   ngx_queue_init(&handle->write_queue);
   ngx_queue_init(&handle->write_completed_queue);
index 0d931b8..e5ba2f2 100644 (file)
@@ -83,8 +83,8 @@ static void uv__eio_init(void) {
 
 
 void uv_eio_init(uv_loop_t* loop) {
-  if (loop->counters.eio_init) return;
-  loop->counters.eio_init = 1;
+  if (loop->flags & UV_LOOP_EIO_INITIALIZED) return;
+  loop->flags |= UV_LOOP_EIO_INITIALIZED;
 
   uv_idle_init(loop, &loop->uv_eio_poller);
   uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll);
index d159727..4608ee5 100644 (file)
@@ -158,7 +158,6 @@ UNUSED static void uv__handle_unref(uv_handle_t* h) {
 UNUSED static void uv__handle_init(uv_loop_t* loop,
                                    uv_handle_t* handle,
                                    uv_handle_type type) {
-  loop->counters.handle_init++;
   handle->loop = loop;
   handle->type = type;
   handle->flags = UV__HANDLE_REF; /* ref the loop when active */
index 1b733c4..40dee1f 100644 (file)
 
 #include "uv.h"
 #include "internal.h"
+#include "atomicops-inl.h"
 #include "handle-inl.h"
 #include "req-inl.h"
 
 
-/* Atomic set operation on char */
-#ifdef _MSC_VER /* MSVC */
-
-/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is  slightly less */
-/* efficient than InterlockedExchange, but InterlockedExchange8 does not */
-/* exist, and interlocked operations on larger targets might require the */
-/* target to be aligned. */
-#pragma intrinsic(_InterlockedOr8)
-
-static char __declspec(inline) uv_atomic_exchange_set(char volatile* target) {
-  return _InterlockedOr8(target, 1);
-}
-
-#else /* GCC */
-
-/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
-static inline char uv_atomic_exchange_set(char volatile* target) {
-  const char one = 1;
-  char old_value;
-  __asm__ __volatile__ ("lock xchgb %0, %1\n\t"
-                        : "=r"(old_value), "=m"(*target)
-                        : "0"(one), "m"(*target)
-                        : "memory");
-  return old_value;
-}
-
-#endif
-
-
 void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
   if (handle->flags & UV_HANDLE_CLOSING &&
       !handle->async_sent) {
@@ -78,8 +50,6 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
   req->type = UV_WAKEUP;
   req->data = handle;
 
-  loop->counters.async_init++;
-
   uv__handle_start(handle);
 
   return 0;
@@ -107,7 +77,7 @@ int uv_async_send(uv_async_t* handle) {
   /* or closed handle. */
   assert(!(handle->flags & UV_HANDLE_CLOSING));
 
-  if (!uv_atomic_exchange_set(&handle->async_sent)) {
+  if (!uv__atomic_exchange_set(&handle->async_sent)) {
     POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
   }
 
diff --git a/deps/uv/src/win/atomicops-inl.h b/deps/uv/src/win/atomicops-inl.h
new file mode 100644 (file)
index 0000000..61e0060
--- /dev/null
@@ -0,0 +1,56 @@
+/* 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.
+ */
+
+#ifndef UV_WIN_ATOMICOPS_INL_H_
+#define UV_WIN_ATOMICOPS_INL_H_
+
+#include "uv.h"
+
+
+/* Atomic set operation on char */
+#ifdef _MSC_VER /* MSVC */
+
+/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is  slightly less */
+/* efficient than InterlockedExchange, but InterlockedExchange8 does not */
+/* exist, and interlocked operations on larger targets might require the */
+/* target to be aligned. */
+#pragma intrinsic(_InterlockedOr8)
+
+static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) {
+  return _InterlockedOr8(target, 1);
+}
+
+#else /* GCC */
+
+/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
+static inline char uv__atomic_exchange_set(char volatile* target) {
+  const char one = 1;
+  char old_value;
+  __asm__ __volatile__ ("lock xchgb %0, %1\n\t"
+                        : "=r"(old_value), "=m"(*target)
+                        : "0"(one), "m"(*target)
+                        : "memory");
+  return old_value;
+}
+
+#endif
+
+#endif /* UV_WIN_ATOMICOPS_INL_H_ */
index e288fc4..2c76b10 100644 (file)
@@ -55,6 +55,9 @@ static void uv_init(void) {
   /* Initialize FS */
   uv_fs_init();
 
+  /* Initialize signal stuff */
+  uv_signals_init();
+
   /* Initialize console */
   uv_console_init();
 
@@ -96,8 +99,6 @@ static void uv_loop_init(uv_loop_t* loop) {
   loop->active_udp_streams = 0;
 
   loop->last_err = uv_ok_;
-
-  memset(&loop->counters, 0, sizeof loop->counters);
 }
 
 
index 88ddd74..d5b8f7c 100644 (file)
@@ -26,7 +26,7 @@ static int uv__dlerror(uv_lib_t* lib, int errorno);
 
 
 int uv_dlopen(const char* filename, uv_lib_t* lib) {
-  wchar_t filename_w[32768];
+  WCHAR filename_w[32768];
 
   lib->handle = NULL;
   lib->errmsg = NULL;
index 91f5111..bb7a46f 100644 (file)
@@ -110,8 +110,8 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
     case WSAEFAULT:                         return UV_EFAULT;
     case ERROR_HOST_UNREACHABLE:            return UV_EHOSTUNREACH;
     case WSAEHOSTUNREACH:                   return UV_EHOSTUNREACH;
-    case ERROR_OPERATION_ABORTED:           return UV_EINTR;
-    case WSAEINTR:                          return UV_EINTR;
+    case ERROR_OPERATION_ABORTED:           return UV_ECANCELED;
+    case WSAEINTR:                          return UV_ECANCELED;
     case ERROR_INVALID_DATA:                return UV_EINVAL;
     case ERROR_SYMLINK_NOT_SUPPORTED:       return UV_EINVAL;
     case WSAEINVAL:                         return UV_EINVAL;
index 68e03e3..810be4f 100644 (file)
@@ -55,8 +55,6 @@ static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle,
   }
 
   uv__handle_start(handle);
-
-  loop->counters.fs_event_init++;
 }
 
 
@@ -90,15 +88,15 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
 }
 
 
-static int uv_split_path(const wchar_t* filename, wchar_t** dir,
-    wchar_t** file) {
+static int uv_split_path(const WCHAR* filename, WCHAR** dir,
+    WCHAR** file) {
   int len = wcslen(filename);
   int i = len;
   while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
 
   if (i == 0) {
     if (dir) {
-      *dir = (wchar_t*)malloc((MAX_PATH + 1) * sizeof(wchar_t));
+      *dir = (WCHAR*)malloc((MAX_PATH + 1) * sizeof(WCHAR));
       if (!*dir) {
         uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
       }
@@ -113,7 +111,7 @@ static int uv_split_path(const wchar_t* filename, wchar_t** dir,
     *file = wcsdup(filename);
   } else {
     if (dir) {
-      *dir = (wchar_t*)malloc((i + 1) * sizeof(wchar_t));
+      *dir = (WCHAR*)malloc((i + 1) * sizeof(WCHAR));
       if (!*dir) {
         uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
       }
@@ -121,7 +119,7 @@ static int uv_split_path(const wchar_t* filename, wchar_t** dir,
       (*dir)[i] = L'\0';
     }
 
-    *file = (wchar_t*)malloc((len - i) * sizeof(wchar_t));
+    *file = (WCHAR*)malloc((len - i) * sizeof(WCHAR));
     if (!*file) {
       uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
     }
@@ -137,8 +135,8 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
     const char* filename, uv_fs_event_cb cb, int flags) {
   int name_size, is_path_dir;
   DWORD attr, last_error;
-  wchar_t* dir = NULL, *dir_to_watch, *filenamew = NULL;
-  wchar_t short_path[MAX_PATH];
+  WCHAR* dir = NULL, *dir_to_watch, *filenamew = NULL;
+  WCHAR short_path[MAX_PATH];
 
   /* We don't support any flags yet. */
   assert(!flags);
@@ -146,14 +144,14 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
   uv_fs_event_init_handle(loop, handle, filename, cb);
 
   /* Convert name to UTF16. */
-  name_size = uv_utf8_to_utf16(filename, NULL, 0) * sizeof(wchar_t);
-  filenamew = (wchar_t*)malloc(name_size);
+  name_size = uv_utf8_to_utf16(filename, NULL, 0) * sizeof(WCHAR);
+  filenamew = (WCHAR*)malloc(name_size);
   if (!filenamew) {
     uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
   }
 
   if (!uv_utf8_to_utf16(filename, filenamew,
-      name_size / sizeof(wchar_t))) {
+      name_size / sizeof(WCHAR))) {
     uv__set_sys_error(loop, GetLastError());
     return -1;
   }
@@ -294,7 +292,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
   FILE_NOTIFY_INFORMATION* file_info;
   int sizew, size, result;
   char* filename = NULL;
-  wchar_t* filenamew, *long_filenamew = NULL;
+  WCHAR* filenamew, *long_filenamew = NULL;
   DWORD offset = 0;
 
   assert(req->type == UV_FS_EVENT_REQ);
@@ -323,9 +321,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
          */
         if (handle->dirw ||
           _wcsnicmp(handle->filew, file_info->FileName,
-            file_info->FileNameLength / sizeof(wchar_t)) == 0 ||
+            file_info->FileNameLength / sizeof(WCHAR)) == 0 ||
           _wcsnicmp(handle->short_filew, file_info->FileName,
-            file_info->FileNameLength / sizeof(wchar_t)) == 0) {
+            file_info->FileNameLength / sizeof(WCHAR)) == 0) {
 
           if (handle->dirw) {
             /*
@@ -337,9 +335,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
               file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
               /* Construct a full path to the file. */
               size = wcslen(handle->dirw) +
-                file_info->FileNameLength / sizeof(wchar_t) + 2;
+                file_info->FileNameLength / sizeof(WCHAR) + 2;
 
-              filenamew = (wchar_t*)malloc(size * sizeof(wchar_t));
+              filenamew = (WCHAR*)malloc(size * sizeof(WCHAR));
               if (!filenamew) {
                 uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
               }
@@ -353,7 +351,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
               size = GetLongPathNameW(filenamew, NULL, 0);
 
               if (size) {
-                long_filenamew = (wchar_t*)malloc(size * sizeof(wchar_t));
+                long_filenamew = (WCHAR*)malloc(size * sizeof(WCHAR));
                 if (!long_filenamew) {
                   uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
                 }
@@ -388,7 +386,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
                */
               if (!long_filenamew) {
                 filenamew = file_info->FileName;
-                sizew = file_info->FileNameLength / sizeof(wchar_t);
+                sizew = file_info->FileNameLength / sizeof(WCHAR);
               }
             } else {
               /* Removed or renamed callbacks don't provide filename. */
index 41e7a4a..c2017ef 100644 (file)
     int ai_socktype;
     int ai_protocol;
     size_t ai_addrlen;
-    wchar_t* ai_canonname;
+    WCHAR* ai_canonname;
     struct sockaddr* ai_addr;
     struct addrinfoW* ai_next;
   } ADDRINFOW, *PADDRINFOW;
 
-  DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const wchar_t* node,
-                                          const wchar_t* service,
+  DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
+                                          const WCHAR* service,
                                           const ADDRINFOW* hints,
                                           PADDRINFOW* result);
 
@@ -271,7 +271,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
 
   /* calculate required memory size for all input values */
   if (node != NULL) {
-    nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(wchar_t));
+    nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(WCHAR));
     if (nodesize == 0) {
       uv__set_sys_error(loop, GetLastError());
       goto error;
@@ -280,7 +280,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
 
   if (service != NULL) {
     servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) *
-                               sizeof(wchar_t));
+                               sizeof(WCHAR));
     if (servicesize == 0) {
       uv__set_sys_error(loop, GetLastError());
       goto error;
@@ -303,10 +303,10 @@ int uv_getaddrinfo(uv_loop_t* loop,
   /* convert node string to UTF16 into allocated memory and save pointer in */
   /* the reques. */
   if (node != NULL) {
-    req->node = (wchar_t*)alloc_ptr;
+    req->node = (WCHAR*)alloc_ptr;
     if (uv_utf8_to_utf16(node,
-                         (wchar_t*) alloc_ptr,
-                         nodesize / sizeof(wchar_t)) == 0) {
+                         (WCHAR*) alloc_ptr,
+                         nodesize / sizeof(WCHAR)) == 0) {
       uv__set_sys_error(loop, GetLastError());
       goto error;
     }
@@ -318,10 +318,10 @@ int uv_getaddrinfo(uv_loop_t* loop,
   /* convert service string to UTF16 into allocated memory and save pointer */
   /* in the req. */
   if (service != NULL) {
-    req->service = (wchar_t*)alloc_ptr;
+    req->service = (WCHAR*)alloc_ptr;
     if (uv_utf8_to_utf16(service,
-                         (wchar_t*) alloc_ptr,
-                         servicesize / sizeof(wchar_t)) == 0) {
+                         (WCHAR*) alloc_ptr,
+                         servicesize / sizeof(WCHAR)) == 0) {
       uv__set_sys_error(loop, GetLastError());
       goto error;
     }
index 4064c24..18db5e6 100644 (file)
@@ -123,6 +123,10 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
         uv_async_endgame(loop, (uv_async_t*) handle);
         break;
 
+      case UV_SIGNAL:
+        uv_signal_endgame(loop, (uv_signal_t*) handle);
+        break;
+
       case UV_PROCESS:
         uv_process_endgame(loop, (uv_process_t*) handle);
         break;
index d4b86de..74bd56c 100644 (file)
@@ -124,6 +124,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
       uv_async_close(loop, (uv_async_t*) handle);
       return;
 
+    case UV_SIGNAL:
+      uv_signal_close(loop, (uv_signal_t*) handle);
+      return;
+
     case UV_PROCESS:
       uv_process_close(loop, (uv_process_t*) handle);
       return;
index b9f8bba..b0d1d18 100644 (file)
 #define UV_HANDLE_PIPESERVER                    0x02000000
 
 /* Only used by uv_tty_t handles. */
-#define UV_HANDLE_TTY_RAW                       0x01000000
-#define UV_HANDLE_TTY_SAVED_POSITION            0x02000000
-#define UV_HANDLE_TTY_SAVED_ATTRIBUTES          0x04000000
+#define UV_HANDLE_TTY_READABLE                  0x01000000
+#define UV_HANDLE_TTY_RAW                       0x02000000
+#define UV_HANDLE_TTY_SAVED_POSITION            0x04000000
+#define UV_HANDLE_TTY_SAVED_ATTRIBUTES          0x08000000
 
 /* Only used by uv_poll_t handles. */
 #define UV_HANDLE_POLL_SLOW                     0x02000000
@@ -134,7 +135,7 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
 /*
  * Pipes
  */
-int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
+uv_err_t uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
     char* name, size_t nameSize);
 
 int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
@@ -232,10 +233,22 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
 
 
 /*
+ * Signal watcher
+ */
+void uv_signals_init();
+int uv__signal_dispatch(int signum);
+
+void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle);
+void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
+
+void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
+    uv_req_t* req);
+
+
+/*
  * Spawn
  */
 void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
-void uv_process_proc_close(uv_loop_t* loop, uv_process_t* handle);
 void uv_process_close(uv_loop_t* loop, uv_process_t* handle);
 void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
 
@@ -287,7 +300,7 @@ uv_err_code uv_translate_sys_error(int sys_errno);
 /*
  * Process stdio handles.
  */
-int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
+uv_err_t uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
     BYTE** buffer_ptr);
 void uv__stdio_destroy(BYTE* buffer);
 void uv__stdio_noinherit(BYTE* buffer);
index 615f7cd..1a02862 100644 (file)
@@ -39,7 +39,6 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
 #define UV_LOOP_WATCHER_DEFINE(name, NAME)                                    \
   int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) {              \
     uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME);                  \
-    loop->counters.name##_init++;                                             \
                                                                               \
     return 0;                                                                 \
   }                                                                           \
index 5da14ea..a4bb764 100644 (file)
@@ -88,8 +88,6 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
 
   uv_req_init(loop, (uv_req_t*) &handle->ipc_header_write_req);
 
-  loop->counters.pipe_init++;
-
   return 0;
 }
 
@@ -159,11 +157,11 @@ static HANDLE open_named_pipe(WCHAR* name, DWORD* duplex_flags) {
 }
 
 
-int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
+uv_err_t uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
     char* name, size_t nameSize) {
   HANDLE pipeHandle;
   int errorno;
-  int err;
+  uv_err_t err;
   char* ptr = (char*)handle;
 
   for (;;) {
@@ -181,9 +179,8 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
 
     errorno = GetLastError();
     if (errorno != ERROR_PIPE_BUSY && errorno != ERROR_ACCESS_DENIED) {
-      uv__set_sys_error(loop, errorno);
-      err = -1;
-      goto done;
+      err = uv__new_sys_error(errorno);
+      goto error;
     }
 
     /* Pipe name collision.  Increment the pointer and try again. */
@@ -194,17 +191,17 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
                              loop->iocp,
                              (ULONG_PTR)handle,
                              0) == NULL) {
-    uv__set_sys_error(loop, GetLastError());
-    err = -1;
-    goto done;
+    err = uv__new_sys_error(GetLastError());
+    goto error;
   }
 
   uv_pipe_connection_init(handle);
   handle->handle = pipeHandle;
-  err = 0;
 
-done:
-  if (err && pipeHandle != INVALID_HANDLE_VALUE) {
+  return uv_ok_;
+
+ error:
+  if (pipeHandle != INVALID_HANDLE_VALUE) {
     CloseHandle(pipeHandle);
   }
 
@@ -433,13 +430,13 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
   }
 
   /* Convert name to UTF16. */
-  nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(wchar_t);
-  handle->name = (wchar_t*)malloc(nameSize);
+  nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR);
+  handle->name = (WCHAR*)malloc(nameSize);
   if (!handle->name) {
     uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
   }
 
-  if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(wchar_t))) {
+  if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) {
     uv__set_sys_error(loop, GetLastError());
     return -1;
   }
@@ -545,13 +542,13 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
   req->cb = cb;
 
   /* Convert name to UTF16. */
-  nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(wchar_t);
-  handle->name = (wchar_t*)malloc(nameSize);
+  nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR);
+  handle->name = (WCHAR*)malloc(nameSize);
   if (!handle->name) {
     uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
   }
 
-  if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(wchar_t))) {
+  if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) {
     errorno = GetLastError();
     goto error;
   }
index 9800b71..3081989 100644 (file)
@@ -558,8 +558,6 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
   handle->poll_req_2.type = UV_POLL_REQ;
   handle->poll_req_2.data = handle;
 
-  loop->counters.poll_init++;
-
   return 0;
 }
 
index ad845a0..7777740 100644 (file)
@@ -94,13 +94,14 @@ void uv_disable_stdio_inheritance(void) {
 }
 
 
-static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
-    HANDLE* child_pipe_ptr, unsigned int flags) {
+static uv_err_t uv__create_stdio_pipe_pair(uv_loop_t* loop,
+    uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
   char pipe_name[64];
   SECURITY_ATTRIBUTES sa;
   DWORD server_access = 0;
   DWORD client_access = 0;
   HANDLE child_pipe = INVALID_HANDLE_VALUE;
+  uv_err_t err;
 
   if (flags & UV_READABLE_PIPE) {
     server_access |= PIPE_ACCESS_OUTBOUND;
@@ -112,13 +113,13 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
   }
 
   /* Create server pipe handle. */
-  if (uv_stdio_pipe_server(loop,
-                           server_pipe,
-                           server_access,
-                           pipe_name,
-                           sizeof(pipe_name)) < 0) {
+  err = uv_stdio_pipe_server(loop,
+                             server_pipe,
+                             server_access,
+                             pipe_name,
+                             sizeof(pipe_name));
+  if (err.code != UV_OK)
     goto error;
-  }
 
   /* Create child pipe handle. */
   sa.nLength = sizeof sa;
@@ -133,7 +134,7 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
                            server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0,
                            NULL);
   if (child_pipe == INVALID_HANDLE_VALUE) {
-    uv__set_sys_error(loop, GetLastError());
+    err = uv__new_sys_error(GetLastError());
     goto error;
   }
 
@@ -157,13 +158,13 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
   /* both ends of the pipe created. */
   if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
     if (GetLastError() != ERROR_PIPE_CONNECTED) {
-      uv__set_sys_error(loop, GetLastError());
+      err = uv__new_sys_error(GetLastError());
       goto error;
     }
   }
 
   *child_pipe_ptr = child_pipe;
-  return 0;
+  return uv_ok_;
 
  error:
   if (server_pipe->handle != INVALID_HANDLE_VALUE) {
@@ -174,7 +175,7 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
     CloseHandle(child_pipe);
   }
 
-  return -1;
+  return err;
 }
 
 
@@ -227,7 +228,7 @@ static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
 }
 
 
-static int uv__create_nul_handle(uv_loop_t* loop, HANDLE* handle_ptr,
+uv_err_t uv__create_nul_handle(HANDLE* handle_ptr,
     DWORD access) {
   HANDLE handle;
   SECURITY_ATTRIBUTES sa;
@@ -244,36 +245,34 @@ static int uv__create_nul_handle(uv_loop_t* loop, HANDLE* handle_ptr,
                        0,
                        NULL);
   if (handle == INVALID_HANDLE_VALUE) {
-    uv__set_sys_error(loop, GetLastError());
-    return -1;
+    return uv__new_sys_error(GetLastError());
   }
 
   *handle_ptr = handle;
-  return 0;
+  return uv_ok_;
 }
 
 
-int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
+uv_err_t uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
     BYTE** buffer_ptr) {
   BYTE* buffer;
   int count, i;
+  uv_err_t err;
 
   count = options->stdio_count;
 
   if (count < 0 || count > 255) {
     /* Only support FDs 0-255 */
-    uv__set_artificial_error(loop, UV_ENOTSUP);
-    return -1;
+    return uv__new_artificial_error(UV_ENOTSUP);
   } else if (count < 3) {
     /* There should always be at least 3 stdio handles. */
     count = 3;
   }
 
   /* Allocate the child stdio buffer */
-  buffer = malloc(CHILD_STDIO_SIZE(count));
+  buffer = (BYTE*) malloc(CHILD_STDIO_SIZE(count));
   if (buffer == NULL) {
-    uv__set_artificial_error(loop, UV_ENOMEM);
-    return -1;
+    return uv__new_artificial_error(UV_ENOMEM);
   }
 
   /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */
@@ -304,11 +303,12 @@ int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
         if (i <= 2) {
           DWORD access = (i == 0) ? FILE_GENERIC_READ :
                                     FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
-          if (uv__create_nul_handle(loop,
-                                &CHILD_STDIO_HANDLE(buffer, i),
-                                access) < 0) {
+
+          err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
+                                      access);
+          if (err.code != UV_OK)
             goto error;
-          }
+
           CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
         }
         break;
@@ -326,12 +326,12 @@ int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
         assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
         assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
 
-        if (uv__create_stdio_pipe_pair(loop,
-                                      parent_pipe,
-                                      &child_pipe,
-                                      fdopt.flags) < 0) {
+        err = uv__create_stdio_pipe_pair(loop,
+                                         parent_pipe,
+                                         &child_pipe,
+                                         fdopt.flags);
+        if (err.code != UV_OK)
           goto error;
-        }
 
         CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
         CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
@@ -430,11 +430,11 @@ int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options,
   }
 
   *buffer_ptr  = buffer;
-  return 0;
+  return uv_ok_;
 
  error:
   uv__stdio_destroy(buffer);
-  return -1;
+  return err;
 }
 
 
index a8f690d..dac9769 100644 (file)
@@ -36,7 +36,7 @@
 
 typedef struct env_var {
   const char* narrow;
-  const wchar_t* wide;
+  const WCHAR* wide;
   int len; /* including null or '=' */
   int supplied;
   int value_len;
@@ -45,38 +45,52 @@ typedef struct env_var {
 #define E_V(str) { str "=", L##str, sizeof(str), 0, 0 }
 
 
-#define UTF8_TO_UTF16(s, t)                               \
-  size = uv_utf8_to_utf16(s, NULL, 0) * sizeof(wchar_t);  \
-  t = (wchar_t*)malloc(size);                             \
-  if (!t) {                                               \
-    uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");          \
-  }                                                       \
-  if (!uv_utf8_to_utf16(s, t, size / sizeof(wchar_t))) {  \
-    uv__set_sys_error(loop, GetLastError());              \
-    err = -1;                                             \
-    goto done;                                            \
+static uv_err_t uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
+  int ws_len, r;
+  WCHAR* ws;
+
+  ws_len = MultiByteToWideChar(CP_UTF8,
+                               0,
+                               s,
+                               -1,
+                               NULL,
+                               0);
+  if (ws_len <= 0) {
+    return uv__new_sys_error(GetLastError());
+  }
+
+  ws = (WCHAR*) malloc(ws_len * sizeof(WCHAR));
+  if (ws == NULL) {
+    return uv__new_artificial_error(UV_ENOMEM);
   }
 
+  r = MultiByteToWideChar(CP_UTF8,
+                          0,
+                          s,
+                          -1,
+                          ws,
+                          ws_len);
+  assert(r == ws_len);
+
+  *ws_ptr = ws;
+  return uv_ok_;
+}
+
 
 static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
   uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
   handle->exit_cb = NULL;
   handle->pid = 0;
+  handle->spawn_error = uv_ok_;
   handle->exit_signal = 0;
   handle->wait_handle = INVALID_HANDLE_VALUE;
   handle->process_handle = INVALID_HANDLE_VALUE;
-  handle->close_handle = INVALID_HANDLE_VALUE;
   handle->child_stdio_buffer = NULL;
+  handle->exit_cb_pending = 0;
 
   uv_req_init(loop, (uv_req_t*)&handle->exit_req);
   handle->exit_req.type = UV_PROCESS_EXIT;
   handle->exit_req.data = handle;
-  uv_req_init(loop, (uv_req_t*)&handle->close_req);
-  handle->close_req.type = UV_PROCESS_CLOSE;
-  handle->close_req.data = handle;
-
-  loop->counters.handle_init++;
-  loop->counters.process_init++;
 }
 
 
@@ -87,15 +101,15 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
 /*
  * Helper function for search_path
  */
-static wchar_t* search_path_join_test(const wchar_t* dir,
+static WCHAR* search_path_join_test(const WCHAR* dir,
                                       int dir_len,
-                                      const wchar_t* name,
+                                      const WCHAR* name,
                                       int name_len,
-                                      const wchar_t* ext,
+                                      const WCHAR* ext,
                                       int ext_len,
-                                      const wchar_t* cwd,
+                                      const WCHAR* cwd,
                                       int cwd_len) {
-  wchar_t *result, *result_pos;
+  WCHAR *result, *result_pos;
   DWORD attrs;
 
   if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) {
@@ -121,7 +135,7 @@ static wchar_t* search_path_join_test(const wchar_t* dir,
   }
 
   /* Allocate buffer for output */
-  result = result_pos = (wchar_t*)malloc(sizeof(wchar_t) *
+  result = result_pos = (WCHAR*)malloc(sizeof(WCHAR) *
       (cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1));
 
   /* Copy cwd */
@@ -178,14 +192,14 @@ static wchar_t* search_path_join_test(const wchar_t* dir,
 /*
  * Helper function for search_path
  */
-static wchar_t* path_search_walk_ext(const wchar_t *dir,
+static WCHAR* path_search_walk_ext(const WCHAR *dir,
                                      int dir_len,
-                                     const wchar_t *name,
+                                     const WCHAR *name,
                                      int name_len,
-                                     wchar_t *cwd,
+                                     WCHAR *cwd,
                                      int cwd_len,
                                      int name_has_ext) {
-  wchar_t* result;
+  WCHAR* result;
 
   /* If the name itself has a nonempty extension, try this extension first */
   if (name_has_ext) {
@@ -259,14 +273,14 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir,
  *
  * TODO: correctly interpret UNC paths
  */
-static wchar_t* search_path(const wchar_t *file,
-                            wchar_t *cwd,
-                            const wchar_t *path) {
+static WCHAR* search_path(const WCHAR *file,
+                            WCHAR *cwd,
+                            const WCHAR *path) {
   int file_has_dir;
-  wchar_t* result = NULL;
-  wchar_t *file_name_start;
-  wchar_t *dot;
-  const wchar_t *dir_start, *dir_end, *dir_path;
+  WCHAR* result = NULL;
+  WCHAR *file_name_start;
+  WCHAR *dot;
+  const WCHAR *dir_start, *dir_end, *dir_path;
   int dir_len;
   int name_has_ext;
 
@@ -283,7 +297,7 @@ static wchar_t* search_path(const wchar_t *file,
 
   /* Find the start of the filename so we can split the directory from the */
   /* name. */
-  for (file_name_start = (wchar_t*)file + file_len;
+  for (file_name_start = (WCHAR*)file + file_len;
        file_name_start > file
            && file_name_start[-1] != L'\\'
            && file_name_start[-1] != L'/'
@@ -365,10 +379,10 @@ static wchar_t* search_path(const wchar_t *file,
  * Quotes command line arguments
  * Returns a pointer to the end (next char to be written) of the buffer
  */
-wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) {
+WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
   int len = wcslen(source),
       i, quote_hit;
-  wchar_t* start;
+  WCHAR* start;
 
   /*
    * Check if the string must be quoted;
@@ -438,61 +452,92 @@ wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) {
 }
 
 
-wchar_t* make_program_args(char** args, int verbatim_arguments) {
-  wchar_t* dst;
-  wchar_t* ptr;
+uv_err_t make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
   char** arg;
-  size_t size = 0;
-  size_t len;
+  WCHAR* dst = NULL;
+  WCHAR* temp_buffer = NULL;
+  size_t dst_len = 0;
+  size_t temp_buffer_len = 0;
+  WCHAR* pos;
   int arg_count = 0;
-  wchar_t* buffer;
-  int arg_size;
-  int buffer_size = 0;
+  uv_err_t err = uv_ok_;
 
   /* Count the required size. */
   for (arg = args; *arg; arg++) {
-    arg_size = uv_utf8_to_utf16(*arg, NULL, 0) * sizeof(wchar_t);
-    size += arg_size;
-    buffer_size = arg_size > buffer_size ? arg_size : buffer_size;
+    DWORD arg_len;
+
+    arg_len = MultiByteToWideChar(CP_UTF8,
+                                  0,
+                                  *arg,
+                                  -1,
+                                  NULL,
+                                  0);
+    if (arg_len == 0) {
+      return uv__new_sys_error(GetLastError());
+    }
+
+    dst_len += arg_len;
+
+    if (arg_len > temp_buffer_len)
+      temp_buffer_len = arg_len;
+
     arg_count++;
   }
 
-  /* Adjust for potential quotes. Also assume the worst-case scenario
+  /* Adjust for potential quotes. Also assume the worst-case scenario */
   /* that every character needs escaping, so we need twice as much space. */
-  size = size * 2 + arg_count * 2;
+  dst_len = dst_len * 2 + arg_count * 2;
 
-  dst = (wchar_t*)malloc(size);
-  if (!dst) {
-    uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+  /* Allocate buffer for the final command line. */
+  dst = (WCHAR*) malloc(dst_len * sizeof(WCHAR));
+  if (dst == NULL) {
+    err = uv__new_artificial_error(UV_ENOMEM);
+    goto error;
   }
 
-  buffer = (wchar_t*)malloc(buffer_size);
-  if (!buffer) {
-    uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+  /* Allocate temporary working buffer. */
+  temp_buffer = (WCHAR*) malloc(temp_buffer_len * sizeof(WCHAR));
+  if (temp_buffer == NULL) {
+    err = uv__new_artificial_error(UV_ENOMEM);
+    goto error;
   }
 
-  ptr = dst;
+  pos = dst;
   for (arg = args; *arg; arg++) {
-    len = uv_utf8_to_utf16(*arg, buffer, (size_t)(size - (ptr - dst)));
-    if (!len) {
+    DWORD arg_len;
+
+    /* Convert argument to wide char. */
+    arg_len = MultiByteToWideChar(CP_UTF8,
+                                  0,
+                                  *arg,
+                                  -1,
+                                  temp_buffer,
+                                  dst + dst_len - pos);
+    if (arg_len == 0) {
       goto error;
     }
+
     if (verbatim_arguments) {
-      wcscpy(ptr, buffer);
-      ptr += len - 1;
+      /* Copy verbatim. */
+      wcscpy(pos, temp_buffer);
+      pos += arg_len - 1;
     } else {
-      ptr = quote_cmd_arg(buffer, ptr);
+      /* Quote/escape, if needed. */
+      pos = quote_cmd_arg(temp_buffer, pos);
     }
-    *ptr++ = *(arg + 1) ? L' ' : L'\0';
+
+    *pos++ = *(arg + 1) ? L' ' : L'\0';
   }
 
-  free(buffer);
-  return dst;
+  free(temp_buffer);
+
+  *dst_ptr = dst;
+  return uv_ok_;
 
 error:
   free(dst);
-  free(buffer);
-  return NULL;
+  free(temp_buffer);
+  return err;
 }
 
 
@@ -526,11 +571,11 @@ static void check_required_vars_contains_var(env_var_t* required, int size,
  * these get defined if the input environment block does not contain any
  * values for them.
  */
-wchar_t* make_program_env(char** env_block) {
-  wchar_t* dst;
-  wchar_t* ptr;
+WCHAR* make_program_env(char** env_block) {
+  WCHAR* dst;
+  WCHAR* ptr;
   char** env;
-  int env_len = 1 * sizeof(wchar_t); /* room for closing null */
+  int env_len = 1 * sizeof(WCHAR); /* room for closing null */
   int len;
   int i;
   DWORD var_size;
@@ -545,18 +590,18 @@ wchar_t* make_program_env(char** env_block) {
     check_required_vars_contains_var(required_vars,
                                      ARRAY_SIZE(required_vars),
                                      *env);
-    env_len += (uv_utf8_to_utf16(*env, NULL, 0) * sizeof(wchar_t));
+    env_len += (uv_utf8_to_utf16(*env, NULL, 0) * sizeof(WCHAR));
   }
 
   for (i = 0; i < ARRAY_SIZE(required_vars); ++i) {
     if (!required_vars[i].supplied) {
-      env_len += required_vars[i].len * sizeof(wchar_t);
+      env_len += required_vars[i].len * sizeof(WCHAR);
       var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
       if (var_size == 0) {
         uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
       }
       required_vars[i].value_len = (int)var_size;
-      env_len += (int)var_size * sizeof(wchar_t);
+      env_len += (int)var_size * sizeof(WCHAR);
     }
   }
 
@@ -600,74 +645,17 @@ wchar_t* make_program_env(char** env_block) {
  * a child process has exited.
  */
 static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
-  uv_process_t* process = (uv_process_t*)data;
-  uv_loop_t* loop = process->loop;
-
-  assert(didTimeout == FALSE);
-  assert(process);
-
-  /* Post completed */
-  POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
-}
-
-
-/*
- * Called on Windows thread-pool thread to indicate that
- * UnregisterWaitEx has completed.
- */
-static void CALLBACK close_wait_callback(void* data, BOOLEAN didTimeout) {
-  uv_process_t* process = (uv_process_t*)data;
+  uv_process_t* process = (uv_process_t*) data;
   uv_loop_t* loop = process->loop;
 
   assert(didTimeout == FALSE);
   assert(process);
+  assert(!process->exit_cb_pending);
 
-  /* Post completed */
-  POST_COMPLETION_FOR_REQ(loop, &process->close_req);
-}
-
-
-/*
- * Called on windows thread pool when CreateProcess failed. It writes an error
- * message to the process' intended stderr and then posts a PROCESS_EXIT
- * packet to the completion port.
- */
-static DWORD WINAPI spawn_failure(void* data) {
-  char syscall[] = "CreateProcessW: ";
-  char unknown[] = "unknown error\n";
-  uv_process_t* process = (uv_process_t*) data;
-  uv_loop_t* loop = process->loop;
-  HANDLE child_stderr = uv__stdio_handle(process->child_stdio_buffer, 2);
-  char* buf = NULL;
-  DWORD count, written;
-
-  if (child_stderr != INVALID_HANDLE_VALUE) {
-    WriteFile(child_stderr, syscall, sizeof(syscall) - 1, &written, NULL);
-
-    count = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                           FORMAT_MESSAGE_FROM_SYSTEM |
-                           FORMAT_MESSAGE_IGNORE_INSERTS,
-                           NULL,
-                           process->spawn_errno,
-                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                           (LPSTR) &buf,
-                           0,
-                           NULL);
-
-    if (buf != NULL && count > 0) {
-      WriteFile(child_stderr, buf, count, &written, NULL);
-      LocalFree(buf);
-    } else {
-      WriteFile(child_stderr, unknown, sizeof(unknown) - 1, &written, NULL);
-    }
-
-    FlushFileBuffers(child_stderr);
-  }
+  process->exit_cb_pending = 1;
 
   /* Post completed */
   POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
-
-  return 0;
 }
 
 
@@ -675,8 +663,13 @@ static DWORD WINAPI spawn_failure(void* data) {
 void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
   DWORD exit_code;
 
-  /* FIXME: race condition. */
+  assert(handle->exit_cb_pending);
+  handle->exit_cb_pending = 0;
+
+  /* If we're closing, don't call the exit callback. Just schedule a close */
+  /* callback now. */
   if (handle->flags & UV_HANDLE_CLOSING) {
+    uv_want_endgame(loop, (uv_handle_t*) handle);
     return;
   }
 
@@ -686,71 +679,68 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
     handle->wait_handle = INVALID_HANDLE_VALUE;
   }
 
-  if (handle->process_handle == INVALID_HANDLE_VALUE ||
-      !GetExitCodeProcess(handle->process_handle, &exit_code)) {
-    /* The process never even started in the first place, or we were unable */
-    /* to obtain the exit code. */
-    exit_code = 127;
-  }
-
   /* Set the handle to inactive: no callbacks will be made after the exit */
   /* callback.*/
   uv__handle_stop(handle);
 
+  if (handle->spawn_error.code != UV_OK) {
+    /* Spawning failed. */
+    exit_code = (DWORD) -1;
+  } else if (!GetExitCodeProcess(handle->process_handle, &exit_code)) {
+    /* Unable to to obtain the exit code. This should never happen. */
+    exit_code = (DWORD) -1;
+  }
+
   /* Fire the exit callback. */
   if (handle->exit_cb) {
+    loop->last_err = handle->spawn_error;
     handle->exit_cb(handle, exit_code, handle->exit_signal);
   }
 }
 
 
-/* Called on main thread after UnregisterWaitEx finishes. */
-void uv_process_proc_close(uv_loop_t* loop, uv_process_t* handle) {
-  uv_want_endgame(loop, (uv_handle_t*)handle);
-}
-
-
 void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
   uv__handle_start(handle);
 
   if (handle->wait_handle != INVALID_HANDLE_VALUE) {
-    handle->close_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
-    UnregisterWaitEx(handle->wait_handle, handle->close_handle);
-    handle->wait_handle = NULL;
+    /* This blocks until either the wait was cancelled, or the callback has */
+    /* completed. */
+    BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
+    if (!r) {
+      /* This should never happen, and if it happens, we can't recover... */
+      uv_fatal_error(GetLastError(), "UnregisterWaitEx");
+    }
 
-    RegisterWaitForSingleObject(&handle->wait_handle, handle->close_handle,
-        close_wait_callback, (void*)handle, INFINITE,
-        WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
-  } else {
+    handle->wait_handle = INVALID_HANDLE_VALUE;
+  }
+
+  if (!handle->exit_cb_pending) {
     uv_want_endgame(loop, (uv_handle_t*)handle);
   }
 }
 
 
 void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
-  if (handle->flags & UV_HANDLE_CLOSING) {
-    assert(!(handle->flags & UV_HANDLE_CLOSED));
-    uv__handle_stop(handle);
+  assert(!handle->exit_cb_pending);
+  assert(handle->flags & UV_HANDLE_CLOSING);
+  assert(!(handle->flags & UV_HANDLE_CLOSED));
 
-    /* Clean-up the process handle. */
-    CloseHandle(handle->process_handle);
+  uv__handle_stop(handle);
 
-    /* Clean up the child stdio ends that may have been left open. */
-    if (handle->child_stdio_buffer != NULL) {
-      uv__stdio_destroy(handle->child_stdio_buffer);
-    }
+  /* Clean-up the process handle. */
+  CloseHandle(handle->process_handle);
 
-    uv__handle_close(handle);
-  }
+  uv__handle_close(handle);
 }
 
 
 int uv_spawn(uv_loop_t* loop, uv_process_t* process,
     uv_process_options_t options) {
-  int i, size, err = 0, keep_child_stdio_open = 0;
-  wchar_t* path = NULL;
+  int i;
+  uv_err_t err = uv_ok_;
+  WCHAR* path = NULL;
   BOOL result;
-  wchar_t* application_path = NULL, *application = NULL, *arguments = NULL,
+  WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
            *env = NULL, *cwd = NULL;
   STARTUPINFOW startup;
   PROCESS_INFORMATION info;
@@ -761,6 +751,12 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
     return -1;
   }
 
+  if (options.file == NULL ||
+      options.args == NULL) {
+    uv__set_artificial_error(loop, UV_EINVAL);
+    return -1;
+  }
+
   assert(options.file != NULL);
   assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
                              UV_PROCESS_DETACHED |
@@ -768,57 +764,84 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
                              UV_PROCESS_SETUID)));
 
   uv_process_init(loop, process);
-
   process->exit_cb = options.exit_cb;
-  UTF8_TO_UTF16(options.file, application);
-  arguments = options.args ? make_program_args(options.args,
-      options.flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS) : NULL;
-  env = options.env ? make_program_env(options.env) : NULL;
+
+  err = uv_utf8_to_utf16_alloc(options.file, &application);
+  if (err.code != UV_OK)
+    goto done;
+
+  err = make_program_args(options.args,
+                          options.flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
+                          &arguments);
+  if (err.code != UV_OK)
+    goto done;
 
   if (options.cwd) {
-    UTF8_TO_UTF16(options.cwd, cwd);
+    /* Explicit cwd */
+    err = uv_utf8_to_utf16_alloc(options.cwd, &cwd);
+    if (err.code != UV_OK)
+      goto done;
+
   } else {
-    size  = GetCurrentDirectoryW(0, NULL) * sizeof(wchar_t);
-    if (size) {
-      cwd = (wchar_t*)malloc(size);
-      if (!cwd) {
-        uv__set_artificial_error(loop, UV_ENOMEM);
-        err = -1;
-        goto done;
-      }
+    /* Inherit cwd */
+    DWORD cwd_len, r;
 
-      GetCurrentDirectoryW(size, cwd);
-    } else {
-      uv__set_sys_error(loop, GetLastError());
-      err = -1;
+    cwd_len = GetCurrentDirectoryW(0, NULL);
+    if (!cwd_len) {
+      err = uv__new_sys_error(GetLastError());
+      goto done;
+    }
+
+    cwd = (WCHAR*) malloc(cwd_len * sizeof(WCHAR));
+    if (cwd == NULL) {
+      err = uv__new_artificial_error(UV_ENOMEM);
+      goto done;
+    }
+
+    r = GetCurrentDirectoryW(cwd_len, cwd);
+    if (r == 0 || r >= cwd_len) {
+      err = uv__new_sys_error(GetLastError());
       goto done;
     }
   }
 
-  /* Get PATH env. variable. */
-  size = GetEnvironmentVariableW(L"PATH", NULL, 0) + 1;
-  path = (wchar_t*)malloc(size * sizeof(wchar_t));
-  if (!path) {
-    uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+   /* Get PATH environment variable. */
+  {
+    DWORD path_len, r;
+
+    path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
+    if (path_len == 0) {
+      err = uv__new_sys_error(GetLastError());
+      goto done;
+    }
+
+
+    path = (WCHAR*) malloc(path_len * sizeof(WCHAR));
+    if (path == NULL) {
+      err = uv__new_artificial_error(UV_ENOMEM);
+      goto done;
+    }
+
+    r = GetEnvironmentVariableW(L"PATH", path, path_len);
+    if (r == 0 || r >= path_len) {
+      err = uv__new_sys_error(GetLastError());
+      goto done;
+    }
   }
-  GetEnvironmentVariableW(L"PATH", path, size * sizeof(wchar_t));
-  path[size - 1] = L'\0';
 
   application_path = search_path(application,
                                  cwd,
                                  path);
-
-  if (!application_path) {
-    /* CreateProcess will fail, but this allows us to pass this error to */
-    /* the user asynchronously. */
-    application_path = application;
+  if (application_path == NULL) {
+    /* Not found. */
+    err = uv__new_artificial_error(UV_ENOENT);
+    goto done;
   }
 
 
-  if (uv__stdio_create(loop, &options, &process->child_stdio_buffer) < 0) {
-     err = -1;
-     goto done;
-  }
+  err = uv__stdio_create(loop, &options, &process->child_stdio_buffer);
+  if (err.code != UV_OK)
+    goto done;
 
   startup.cb = sizeof(startup);
   startup.lpReserved = NULL;
@@ -871,60 +894,37 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
     CloseHandle(info.hThread);
 
   } else {
-    /* CreateProcessW failed, but this failure should be delivered */
-    /* asynchronously to retain unix compatibility. So pretend spawn */
-    /* succeeded, and start a thread instead that prints an error */
-    /* to the child's intended stderr. */
-    process->spawn_errno = GetLastError();
-    keep_child_stdio_open = 1;
-    if (!QueueUserWorkItem(spawn_failure, process, WT_EXECUTEDEFAULT)) {
-      uv_fatal_error(GetLastError(), "QueueUserWorkItem");
-    }
+    /* CreateProcessW failed. */
+    err = uv__new_sys_error(GetLastError());
   }
 
 done:
   free(application);
-  if (application_path != application) {
-    free(application_path);
-  }
+  free(application_path);
   free(arguments);
   free(cwd);
   free(env);
   free(path);
 
-  /* Under normal circumstances we should close the stdio handles now - the */
-  /* the child now has its own duplicates, or something went horribly wrong */
-  /* The only exception is when CreateProcess has failed, then we actually */
-  /* need to keep the stdio handles to report the error asynchronously. */
-  if (process->child_stdio_buffer == NULL) {
-    /* Something went wrong before child stdio was initialized. */
-  } else if (!keep_child_stdio_open) {
+  process->spawn_error = err;
+
+  if (process->child_stdio_buffer != NULL) {
+    /* Clean up child stdio handles. */
     uv__stdio_destroy(process->child_stdio_buffer);
     process->child_stdio_buffer = NULL;
-  } else {
-    /* We're keeping the handles open, the thread pool is going to have */
-    /* it's way with them. But at least make them non-inheritable. */
-    uv__stdio_noinherit(process->child_stdio_buffer);
   }
 
-  if (err == 0) {
-    /* Spawn was succesful. The handle will be active until the exit */
-    /* is made or the handle is closed, whichever happens first. */
-    uv__handle_start(process);
-  } else {
-    /* Spawn was not successful. Clean up. */
-    if (process->wait_handle != INVALID_HANDLE_VALUE) {
-      UnregisterWait(process->wait_handle);
-      process->wait_handle = INVALID_HANDLE_VALUE;
-    }
+  /* Make the handle active. It will remain active until the exit callback */
+  /* is made or the handle is closed, whichever happens first. */
+  uv__handle_start(process);
 
-    if (process->process_handle != INVALID_HANDLE_VALUE) {
-      CloseHandle(process->process_handle);
-      process->process_handle = INVALID_HANDLE_VALUE;
-    }
+  /* If an error happened, queue the exit req. */
+  if (err.code != UV_OK) {
+    process->exit_cb_pending = 1;
+    uv_insert_pending_req(loop, (uv_req_t*) &process->exit_req);
   }
 
-  return err;
+  return 0;
 }
 
 
index a0d91cb..353fe90 100644 (file)
@@ -80,7 +80,6 @@
 
 
 INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) {
-  loop->counters.req_init++;
   req->type = UV_UNKNOWN_REQ;
   SET_REQ_SUCCESS(req);
 }
@@ -188,6 +187,10 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) {
         uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
         break;
 
+      case UV_SIGNAL_REQ:
+        uv_process_signal_req(loop, (uv_signal_t*) req->data, req);
+        break;
+
       case UV_POLL_REQ:
         uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
         break;
@@ -200,10 +203,6 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) {
         uv_process_proc_exit(loop, (uv_process_t*) req->data);
         break;
 
-      case UV_PROCESS_CLOSE:
-        uv_process_proc_close(loop, (uv_process_t*) req->data);
-        break;
-
       case UV_FS:
         uv_process_fs_req(loop, (uv_fs_t*) req);
         break;
diff --git a/deps/uv/src/win/signal.c b/deps/uv/src/win/signal.c
new file mode 100644 (file)
index 0000000..3407c6c
--- /dev/null
@@ -0,0 +1,349 @@
+/* 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 <assert.h>
+#include <signal.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+RB_HEAD(uv_signal_tree_s, uv_signal_s);
+
+static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
+static ssize_t volatile uv__signal_control_handler_refs = 0;
+static CRITICAL_SECTION uv__signal_lock;
+
+
+void uv_signals_init() {
+  InitializeCriticalSection(&uv__signal_lock);
+}
+
+
+static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
+  /* Compare signums first so all watchers with the same signnum end up */
+  /* adjacent. */
+  if (w1->signum < w2->signum) return -1;
+  if (w1->signum > w2->signum) return 1;
+
+  /* Sort by loop pointer, so we can easily look up the first item after */
+  /* { .signum = x, .loop = NULL } */
+  if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
+  if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
+
+  if ((uintptr_t) w1 < (uintptr_t) w2) return -1;
+  if ((uintptr_t) w1 > (uintptr_t) w2) return 1;
+
+  return 0;
+}
+
+
+RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare);
+
+
+/*
+ * Dispatches signal {signum} to all active uv_signal_t watchers in all loops.
+ * Returns 1 if the signal was dispatched to any watcher, or 0 if there were
+ * no active signal watchers observing this signal.
+ */
+int uv__signal_dispatch(int signum) {
+  uv_signal_t lookup;
+  uv_signal_t* handle;
+  int dispatched = 0;
+
+  EnterCriticalSection(&uv__signal_lock);
+
+  lookup.signum = signum;
+  lookup.loop = NULL;
+
+  for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
+       handle != NULL && handle->signum == signum;
+       handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
+    unsigned long previous = InterlockedExchange(&handle->pending_signum, signum);
+
+    if (!previous) {
+      POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
+    }
+
+    dispatched = 1;
+  }
+
+  LeaveCriticalSection(&uv__signal_lock);
+
+  return dispatched;
+}
+
+
+static BOOL WINAPI uv__signal_control_handler(DWORD type) {
+  switch (type) {
+    case CTRL_C_EVENT:
+      return uv__signal_dispatch(SIGINT);
+
+    case CTRL_BREAK_EVENT:
+      return uv__signal_dispatch(SIGBREAK);
+
+    case CTRL_CLOSE_EVENT:
+      if (uv__signal_dispatch(SIGHUP)) {
+        /* Windows will terminate the process after the control handler */
+        /* returns. After that it will just terminate our process. Therefore */
+        /* block the signal handler so the main loop has some time to pick */
+        /* up the signal and do something for a few seconds. */
+        Sleep(INFINITE);
+        return TRUE;
+      }
+      return FALSE;
+
+    case CTRL_LOGOFF_EVENT:
+    case CTRL_SHUTDOWN_EVENT:
+      /* These signals are only sent to services. Services have their own */
+      /* notification mechanism, so there's no point in handling these. */
+
+    default:
+      /* We don't handle these. */
+      return FALSE;
+  }
+}
+
+
+static uv_err_t uv__signal_register_control_handler() {
+  /* When this function is called, the uv__signal_lock must be held. */
+
+  /* If the console control handler has already been hooked, just add a */
+  /* reference. */
+  if (uv__signal_control_handler_refs > 0)
+    return uv_ok_;
+
+  if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
+    return uv__new_sys_error(GetLastError());
+
+  uv__signal_control_handler_refs++;
+
+  return uv_ok_;
+}
+
+
+static void uv__signal_unregister_control_handler() {
+  /* When this function is called, the uv__signal_lock must be held. */
+  BOOL r;
+
+  /* Don't unregister if the number of console control handlers exceeds one. */
+  /* Just remove a reference in that case. */
+  if (uv__signal_control_handler_refs > 1) {
+    uv__signal_control_handler_refs--;
+    return;
+  }
+
+  assert(uv__signal_control_handler_refs == 1);
+
+  r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE);
+  /* This should never fail; if it does it is probably a bug in libuv. */
+  assert(r);
+
+  uv__signal_control_handler_refs--;
+}
+
+
+static uv_err_t uv__signal_register(int signum) {
+  switch (signum) {
+    case SIGINT:
+    case SIGBREAK:
+    case SIGHUP:
+      return uv__signal_register_control_handler();
+
+    case SIGILL:
+    case SIGABRT_COMPAT:
+    case SIGFPE:
+    case SIGSEGV:
+    case SIGTERM:
+    case SIGABRT:
+      /* Signal is never raised. */
+      return uv_ok_;
+
+    default:
+      /* Invalid signal. */
+      return uv__new_artificial_error(UV_EINVAL);
+  }
+}
+
+
+static void uv__signal_unregister(int signum) {
+  switch (signum) {
+    case SIGINT:
+    case SIGBREAK:
+    case SIGHUP:
+      uv__signal_unregister_control_handler();
+      return;
+
+    case SIGILL:
+    case SIGABRT_COMPAT:
+    case SIGFPE:
+    case SIGSEGV:
+    case SIGTERM:
+    case SIGABRT:
+      /* Nothing is registered for this signal. */
+      return;
+
+    default:
+      /* Libuv bug. */
+      assert(0 && "Invalid signum");
+      return;
+  }
+}
+
+
+int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
+  uv_req_t* req;
+
+  uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
+  handle->pending_signum = 0;
+  handle->signum = 0;
+  handle->signal_cb = NULL;
+
+  req = &handle->signal_req;
+  uv_req_init(loop, req);
+  req->type = UV_SIGNAL_REQ;
+  req->data = handle;
+
+  uv__handle_start(handle);
+
+  return 0;
+}
+
+
+int uv_signal_stop(uv_signal_t* handle) {
+  uv_signal_t* removed_handle;
+
+  /* If the watcher wasn't started, this is a no-op. */
+  if (handle->signum == 0)
+    return 0;
+
+  EnterCriticalSection(&uv__signal_lock);
+
+  uv__signal_unregister(handle->signum);
+
+  removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
+  assert(removed_handle == handle);
+
+  LeaveCriticalSection(&uv__signal_lock);
+
+  handle->signum = 0;
+  uv__handle_stop(handle);
+
+  return 0;
+}
+
+
+int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
+  uv_err_t err;
+
+  /* If the user supplies signum == 0, then return an error already. If the */
+  /* signum is otherwise invalid then uv__signal_register will find out */
+  /* eventually. */
+  if (signum == 0) {
+    uv__set_artificial_error(handle->loop, UV_EINVAL);
+    return -1;
+  }
+
+  /* Short circuit: if the signal watcher is already watching {signum} don't */
+  /* go through the process of deregistering and registering the handler. */
+  /* Additionally, this avoids pending signals getting lost in the (small) */
+  /* time frame that handle->signum == 0. */
+  if (signum == handle->signum) {
+    handle->signal_cb = signal_cb;
+    return 0;
+  }
+
+  /* If the signal handler was already active, stop it first. */
+  if (handle->signum != 0) {
+    int r = uv_signal_stop(handle);
+    /* uv_signal_stop is infallible. */
+    assert(r == 0);
+  }
+
+  EnterCriticalSection(&uv__signal_lock);
+
+  err = uv__signal_register(signum);
+  if (err.code != UV_OK) {
+    /* Uh-oh, didn't work. */
+    handle->loop->last_err = err;
+    LeaveCriticalSection(&uv__signal_lock);
+    return -1;
+  }
+
+  handle->signum = signum;
+  RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
+
+  LeaveCriticalSection(&uv__signal_lock);
+
+  handle->signal_cb = signal_cb;
+  uv__handle_start(handle);
+
+  return 0;
+}
+
+
+void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
+    uv_req_t* req) {
+  unsigned long dispatched_signum;
+
+  assert(handle->type == UV_SIGNAL);
+  assert(req->type == UV_SIGNAL_REQ);
+
+  dispatched_signum = InterlockedExchange(&handle->pending_signum, 0);
+  assert(dispatched_signum != 0);
+
+  /* Check if the pending signal equals the signum that we are watching for. */
+  /* These can get out of sync when the handler is stopped and restarted */
+  /* while the signal_req is pending. */
+  if (dispatched_signum == handle->signum)
+    handle->signal_cb(handle, dispatched_signum);
+
+  if (handle->flags & UV_HANDLE_CLOSING) {
+    /* When it is closing, it must be stopped at this point. */
+    assert(handle->signum == 0);
+    uv_want_endgame(loop, (uv_handle_t*) handle);
+  }
+}
+
+
+void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
+  uv_signal_stop(handle);
+
+  if (handle->pending_signum == 0) {
+    uv__handle_start(handle);
+    uv_want_endgame(loop, (uv_handle_t*) handle);
+  }
+}
+
+
+void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
+  assert(handle->flags & UV_HANDLE_CLOSING);
+  assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+  assert(handle->signum == 0);
+  assert(handle->pending_signum == 0);
+
+  handle->flags |= UV_HANDLE_CLOSED;
+
+  uv__handle_stop(handle);
+  uv__handle_close(handle);
+}
index 7e2311c..3cde668 100644 (file)
@@ -36,8 +36,6 @@ INLINE static void uv_stream_init(uv_loop_t* loop,
   uv__handle_init(loop, (uv_handle_t*) handle, type);
   handle->write_queue_size = 0;
   handle->activecnt = 0;
-
-  loop->counters.stream_init++;
 }
 
 
index 2a25358..fdca452 100644 (file)
@@ -149,8 +149,6 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
   handle->func_connectex = NULL;
   handle->processed_accepts = 0;
 
-  loop->counters.tcp_init++;
-
   return 0;
 }
 
index 94b7b21..e9eab9a 100644 (file)
@@ -71,8 +71,6 @@ int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
   handle->timer_cb = NULL;
   handle->repeat = 0;
 
-  loop->counters.timer_init++;
-
   return 0;
 }
 
index 66103e6..8575f4f 100644 (file)
@@ -89,54 +89,70 @@ void uv_console_init() {
 
 
 int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
-  HANDLE win_handle;
-  CONSOLE_SCREEN_BUFFER_INFO info;
-
-  loop->counters.tty_init++;
+  HANDLE handle = INVALID_HANDLE_VALUE;
+  DWORD original_console_mode = 0;
+  CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
 
-  win_handle = (HANDLE) _get_osfhandle(fd);
-  if (win_handle == INVALID_HANDLE_VALUE) {
-    uv__set_sys_error(loop, ERROR_INVALID_HANDLE);
+  handle = (HANDLE) _get_osfhandle(fd);
+  if (handle == INVALID_HANDLE_VALUE) {
+    uv__set_artificial_error(loop, UV_EBADF);
     return -1;
   }
 
-  if (!GetConsoleMode(win_handle, &tty->original_console_mode)) {
-    uv__set_sys_error(loop, GetLastError());
-    return -1;
-  }
+  if (readable) {
+     /* Try to obtain the original console mode fromt he input handle. */
+    if (!GetConsoleMode(handle, &original_console_mode)) {
+      uv__set_sys_error(loop, GetLastError());
+      return -1;
+    }
 
-  /* Initialize virtual window size; if it fails, assume that this is stdin. */
-  if (GetConsoleScreenBufferInfo(win_handle, &info)) {
+  } else {
+    /* Obtain the screen buffer info with the output handle. */
+    if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
+      uv__set_sys_error(loop, GetLastError());
+      return -1;
+    }
+
+    /* Update the virtual window. We must hold the tty_output_lock because the */
+    /* virtual window state is shared between all uv_tty handles. */
     EnterCriticalSection(&uv_tty_output_lock);
-    uv_tty_update_virtual_window(&info);
+    uv_tty_update_virtual_window(&screen_buffer_info);
     LeaveCriticalSection(&uv_tty_output_lock);
   }
 
+
   uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
   uv_connection_init((uv_stream_t*) tty);
 
-  tty->handle = win_handle;
-  tty->read_line_handle = NULL;
-  tty->read_line_buffer = uv_null_buf_;
-  tty->read_raw_wait = NULL;
+  tty->handle = handle;
   tty->reqs_pending = 0;
   tty->flags |= UV_HANDLE_BOUND;
 
-  /* Init keycode-to-vt100 mapper state. */
-  tty->last_key_len = 0;
-  tty->last_key_offset = 0;
-  tty->last_utf16_high_surrogate = 0;
-  memset(&tty->last_input_record, 0, sizeof tty->last_input_record);
-
-  /* Init utf8-to-utf16 conversion state. */
-  tty->utf8_bytes_left = 0;
-  tty->utf8_codepoint = 0;
+  if (readable) {
+    /* Initialize TTY input specific fields. */
+    tty->original_console_mode = original_console_mode;
+    tty->flags |= UV_HANDLE_TTY_READABLE;
+    tty->read_line_handle = NULL;
+    tty->read_line_buffer = uv_null_buf_;
+    tty->read_raw_wait = NULL;
+
+    /* Init keycode-to-vt100 mapper state. */
+    tty->last_key_len = 0;
+    tty->last_key_offset = 0;
+    tty->last_utf16_high_surrogate = 0;
+    memset(&tty->last_input_record, 0, sizeof tty->last_input_record);
+  } else {
+    /* TTY output specific fields. */
+    /* Init utf8-to-utf16 conversion state. */
+    tty->utf8_bytes_left = 0;
+    tty->utf8_codepoint = 0;
 
-  /* Initialize eol conversion state */
-  tty->previous_eol = 0;
+    /* Initialize eol conversion state */
+    tty->previous_eol = 0;
 
-  /* Init ANSI parser state. */
-  tty->ansi_parser_state = ANSI_NORMAL;
+    /* Init ANSI parser state. */
+    tty->ansi_parser_state = ANSI_NORMAL;
+  }
 
   return 0;
 }
@@ -148,6 +164,11 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) {
   uv_alloc_cb alloc_cb;
   uv_read_cb read_cb;
 
+  if (!(tty->flags & UV_HANDLE_TTY_READABLE)) {
+    uv__set_artificial_error(tty->loop, UV_EINVAL);
+    return -1;
+  }
+
   if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
     return 0;
   }
@@ -444,6 +465,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
   off_t buf_used;
 
   assert(handle->type == UV_TTY);
+  assert(handle->flags & UV_HANDLE_TTY_READABLE);
   handle->flags &= ~UV_HANDLE_READ_PENDING;
 
   if (!(handle->flags & UV_HANDLE_READING) ||
@@ -683,6 +705,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
   uv_buf_t buf;
 
   assert(handle->type == UV_TTY);
+  assert(handle->flags & UV_HANDLE_TTY_READABLE);
 
   buf = handle->read_line_buffer;
 
@@ -726,6 +749,8 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
 
 void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
     uv_req_t* req) {
+  assert(handle->type == UV_TTY);
+  assert(handle->flags & UV_HANDLE_TTY_READABLE);
 
   /* If the read_line_buffer member is zero, it must have been an raw read. */
   /* Otherwise it was a line-buffered read. */
@@ -742,6 +767,11 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
     uv_read_cb read_cb) {
   uv_loop_t* loop = handle->loop;
 
+  if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
+    uv__set_artificial_error(handle->loop, UV_EINVAL);
+    return -1;
+  }
+
   handle->flags |= UV_HANDLE_READING;
   INCREASE_ACTIVE_COUNT(loop, handle);
   handle->read_cb = read_cb;
@@ -769,6 +799,10 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
 
 int uv_tty_read_stop(uv_tty_t* handle) {
   uv_loop_t* loop = handle->loop;
+  if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
+    uv__set_artificial_error(handle->loop, UV_EINVAL);
+    return -1;
+  }
 
   if (handle->flags & UV_HANDLE_READING) {
     handle->flags &= ~UV_HANDLE_READING;
@@ -1678,6 +1712,11 @@ int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
     uv_buf_t bufs[], int bufcnt, uv_write_cb cb) {
   DWORD error;
 
+  if (handle->flags & UV_HANDLE_TTY_READABLE) {
+    uv__set_artificial_error(handle->loop, UV_EINVAL);
+    return -1;
+  }
+
   if ((handle->flags & UV_HANDLE_SHUTTING) ||
       (handle->flags & UV_HANDLE_CLOSING)) {
     uv__set_sys_error(loop, WSAESHUTDOWN);
@@ -1729,11 +1768,16 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
 
 
 void uv_tty_close(uv_tty_t* handle) {
-  handle->flags |= UV_HANDLE_SHUTTING;
-
-  uv_tty_read_stop(handle);
   CloseHandle(handle->handle);
 
+  if (handle->flags & UV_HANDLE_TTY_READABLE) {
+    /* Readable TTY handle */
+    uv_tty_read_stop(handle);
+  } else {
+    /* Writable TTY handle */
+    handle->flags |= UV_HANDLE_SHUTTING;
+  }
+
   uv__handle_start(handle);
 
   if (handle->reqs_pending == 0) {
@@ -1743,7 +1787,7 @@ void uv_tty_close(uv_tty_t* handle) {
 
 
 void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
-  if ((handle->flags && UV_HANDLE_CONNECTION) &&
+  if (!(handle->flags && UV_HANDLE_TTY_READABLE) &&
       handle->shutdown_req != NULL &&
       handle->write_reqs_pending == 0) {
     UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req);
@@ -1768,11 +1812,13 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
       handle->reqs_pending == 0) {
     /* The console handle duplicate used for line reading should be destroyed */
     /* by uv_tty_read_stop. */
-    assert(handle->read_line_handle == NULL);
+    assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
+           handle->read_line_handle == NULL);
 
     /* The wait handle used for raw reading should be unregistered when the */
     /* wait callback runs. */
-    assert(handle->read_raw_wait == NULL);
+    assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
+           handle->read_raw_wait == NULL);
 
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     uv__handle_stop(handle);
index 3f19fe3..9ad2f69 100644 (file)
@@ -135,8 +135,6 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
   handle->recv_req.type = UV_UDP_RECV;
   handle->recv_req.data = handle;
 
-  loop->counters.udp_init++;
-
   return 0;
 }
 
index 49a3adc..e1a3504 100644 (file)
@@ -74,7 +74,7 @@ void uv__util_init() {
 }
 
 
-int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size,
+int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
     char* utf8Buffer, size_t utf8Size) {
   return WideCharToMultiByte(CP_UTF8,
                              0,
@@ -87,7 +87,7 @@ int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size,
 }
 
 
-int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer,
+int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
     size_t utf16Size) {
   return MultiByteToWideChar(CP_UTF8,
                              0,
@@ -113,7 +113,7 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
     utf16_buffer_len = (int) *size_ptr;
   }
 
-  utf16_buffer = (wchar_t*) malloc(sizeof(WCHAR) * utf16_buffer_len);
+  utf16_buffer = (WCHAR*) malloc(sizeof(WCHAR) * utf16_buffer_len);
   if (!utf16_buffer) {
     return -1;
   }
@@ -340,7 +340,7 @@ char** uv_setup_args(int argc, char** argv) {
 uv_err_t uv_set_process_title(const char* title) {
   uv_err_t err;
   int length;
-  wchar_t* title_w = NULL;
+  WCHAR* title_w = NULL;
 
   uv__once_init();
 
@@ -352,7 +352,7 @@ uv_err_t uv_set_process_title(const char* title) {
   }
 
   /* Convert to wide-char string */
-  title_w = (wchar_t*)malloc(sizeof(wchar_t) * length);
+  title_w = (WCHAR*)malloc(sizeof(WCHAR) * length);
   if (!title_w) {
     uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
   }
@@ -387,7 +387,7 @@ done:
 
 
 static int uv__get_process_title() {
-  wchar_t title_w[MAX_TITLE_LENGTH];
+  WCHAR title_w[MAX_TITLE_LENGTH];
   int length;
 
   if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {
index e6b8a63..ea5b597 100644 (file)
@@ -26,7 +26,7 @@
 #include <stdlib.h>
 
 #define NUM_SYNC_REQS         (10 * 1e5)
-#define NUM_ASYNC_REQS        (1 * 1e5)
+#define NUM_ASYNC_REQS        (1 * (int) 1e5)
 #define MAX_CONCURRENT_REQS   32
 
 #define sync_stat(req, path)                                                  \
index b9cf74f..8ccf10e 100644 (file)
@@ -36,6 +36,7 @@ BENCHMARK_IMPL(sizes) {
   LOGF("uv_idle_t: %u bytes\n", (unsigned int) sizeof(uv_idle_t));
   LOGF("uv_async_t: %u bytes\n", (unsigned int) sizeof(uv_async_t));
   LOGF("uv_timer_t: %u bytes\n", (unsigned int) sizeof(uv_timer_t));
+  LOGF("uv_fs_poll_t: %u bytes\n", (unsigned int) sizeof(uv_fs_poll_t));
   LOGF("uv_fs_event_t: %u bytes\n", (unsigned int) sizeof(uv_fs_event_t));
   LOGF("uv_process_t: %u bytes\n", (unsigned int) sizeof(uv_process_t));
   LOGF("uv_poll_t: %u bytes\n", (unsigned int) sizeof(uv_poll_t));
index ad36719..2f44ff3 100644 (file)
@@ -103,8 +103,8 @@ int process_start(char *name, char *part, process_info_t *p) {
     goto error;
 
   if (part) {
-    if (_snwprintf((wchar_t*)args,
-                   sizeof(args) / sizeof(wchar_t),
+    if (_snwprintf((WCHAR*)args,
+                   sizeof(args) / sizeof(WCHAR),
                    L"\"%s\" %S %S",
                    image,
                    name,
@@ -112,8 +112,8 @@ int process_start(char *name, char *part, process_info_t *p) {
       goto error;
     }
   } else {
-    if (_snwprintf((wchar_t*)args,
-                   sizeof(args) / sizeof(wchar_t),
+    if (_snwprintf((WCHAR*)args,
+                   sizeof(args) / sizeof(WCHAR),
                    L"\"%s\" %S",
                    image,
                    name) < 0) {
index 5f878a4..b34acc8 100644 (file)
@@ -42,7 +42,7 @@ const char* fmt(double d) {
   char* p;
 
   p = (char *) calloc(1, 32) + 31; /* leaks memory */
-  v = d;
+  v = (uint64_t) d;
 
 #if 0 /* works but we don't care about fractional precision */
   if (d - v >= 0.01) {
diff --git a/deps/uv/test/test-counters-init.c b/deps/uv/test/test-counters-init.c
deleted file mode 100644 (file)
index 6318684..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/* 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.
- */
-#define UNIX (defined(__unix__) || defined(__POSIX__) || defined(__APPLE__))
-#include "task.h"
-#include "uv.h"
-#include <fcntl.h>
-
-#if UNIX
-#include <unistd.h> /* unlink, rmdir, etc. */
-#else
-# include <direct.h>
-# include <io.h>
-# define unlink _unlink
-# define rmdir _rmdir
-# define stat _stati64
-# define open _open
-# define write _write
-# define lseek _lseek
-# define close _close
-#endif
-
-static char exepath[1024];
-static size_t exepath_size = 1024;
-static char* args[3];
-static uv_fs_t open_req;
-static uv_tcp_t tcp;
-static uv_udp_t udp;
-static uv_pipe_t uvpipe;
-static uv_tty_t tty;
-static uv_prepare_t prepare;
-static uv_check_t check;
-static uv_idle_t idle;
-static uv_async_t async;
-static uv_timer_t timer;
-static uv_fs_event_t fs_event;
-static uv_process_t process;
-static uv_process_options_t options;
-static uv_fs_t fs_req;
-
-static void exit_cb(uv_process_t* process, int exit_status, int term_signal) {
-  ASSERT(exit_status == 1);
-  ASSERT(term_signal == 0);
-  uv_close((uv_handle_t*)process, NULL);
-}
-
-static void init_process_options(char* test, uv_exit_cb exit_cb) {
-  int r = uv_exepath(exepath, &exepath_size);
-  ASSERT(r == 0);
-  exepath[exepath_size] = '\0';
-  args[0] = exepath;
-  args[1] = test;
-  args[2] = NULL;
-  options.file = exepath;
-  options.args = args;
-  options.exit_cb = exit_cb;
-}
-
-static void create_dir(uv_loop_t* loop, const char* name) {
-  int r;
-  uv_fs_t req;
-  r = uv_fs_rmdir(loop, &req, name, NULL);
-  r = uv_fs_mkdir(loop, &req, name, 0755, NULL);
-  ASSERT(r == 0 || uv_last_error(loop).code == UV_EEXIST);
-  uv_fs_req_cleanup(&req);
-}
-
-static void create_cb(uv_fs_t* req) {
-  ASSERT(req == &open_req);
-  ASSERT(req->fs_type == UV_FS_OPEN);
-  ASSERT(req->result != -1);
-  uv_fs_req_cleanup(req);
-  unlink("test_file");
-}
-
-TEST_IMPL(counters_init) {
-  int r;
-  uint64_t eio_init_prev;
-  uint64_t req_init_prev;
-  uint64_t handle_init_prev;
-  uint64_t stream_init_prev;
-  uint64_t tcp_init_prev;
-  uint64_t udp_init_prev;
-  uint64_t pipe_init_prev;
-  uint64_t tty_init_prev;
-  uint64_t prepare_init_prev;
-  uint64_t check_init_prev;
-  uint64_t idle_init_prev;
-  uint64_t async_init_prev;
-  uint64_t timer_init_prev;
-  uint64_t process_init_prev;
-  uint64_t fs_event_init_prev;
-
-  /* req_init and eio_init test by uv_fs_open() */
-  unlink("test_file");
-  req_init_prev = uv_default_loop()->counters.req_init;
-  eio_init_prev = uv_default_loop()->counters.eio_init;
-  r = uv_fs_open(uv_default_loop(), &open_req, "test_file", O_WRONLY | O_CREAT,
-                 S_IREAD | S_IWRITE, create_cb);
-  ASSERT(r == 0);
-  ASSERT(open_req.result == 0);
-  ASSERT(uv_default_loop()->counters.req_init == ++req_init_prev);
-#ifndef _WIN32
-  ASSERT(uv_default_loop()->counters.eio_init == ++eio_init_prev);
-#endif
-
-  /* tcp_init, stream_init and handle_init test by uv_tcp_init() */
-  tcp_init_prev = uv_default_loop()->counters.tcp_init;
-  stream_init_prev = uv_default_loop()->counters.stream_init;
-  handle_init_prev = uv_default_loop()->counters.handle_init;
-  r = uv_tcp_init(uv_default_loop(), &tcp);
-  ASSERT(r == 0);
-  ASSERT(uv_default_loop()->counters.tcp_init == ++tcp_init_prev);
-  ASSERT(uv_default_loop()->counters.stream_init == ++stream_init_prev);
-  ASSERT(uv_default_loop()->counters.handle_init == ++handle_init_prev);
-  uv_close((uv_handle_t*)&tcp, NULL);
-
-  /* udp_init test by uv_udp_init() */
-  udp_init_prev = uv_default_loop()->counters.udp_init;
-  r = uv_udp_init(uv_default_loop(), &udp);
-  ASSERT(r == 0);
-  ASSERT(uv_default_loop()->counters.udp_init == ++udp_init_prev);
-  uv_close((uv_handle_t*)&udp, NULL);
-
-  /* pipe_init uv_pipe_init() */
-  pipe_init_prev = uv_default_loop()->counters.pipe_init;
-  uv_pipe_init(uv_default_loop(), &uvpipe, 0);
-  ASSERT(r == 0);
-  ASSERT(uv_default_loop()->counters.pipe_init == ++pipe_init_prev);
-  uv_close((uv_handle_t*)&uvpipe, NULL);
-
-  /* tty_init test by uv_tty_init()*/
-  tty_init_prev = uv_default_loop()->counters.tty_init;
-  r = uv_tty_init(uv_default_loop(), &tty, 1, 0);
-  /* uv_tty_init() always returns -1 in run_test in Windows
-     so that we avoid to check return value.
-   */
-#ifndef _WIN32
-  ASSERT(r == 0);
-  uv_close((uv_handle_t*)&tty, NULL);
-#endif
-  ASSERT(uv_default_loop()->counters.tty_init == ++tty_init_prev);
-
-  /* prepare_init test by uv_prepare_init() */
-  prepare_init_prev = uv_default_loop()->counters.prepare_init;
-  r = uv_prepare_init(uv_default_loop(), &prepare);
-  ASSERT(r == 0);
-  ASSERT(uv_default_loop()->counters.prepare_init == ++prepare_init_prev);
-  uv_close((uv_handle_t*)&prepare, NULL);
-
-  /* check_init test by uv_check_init() */
-  check_init_prev = uv_default_loop()->counters.check_init;
-  r = uv_check_init(uv_default_loop(), &check);
-  ASSERT(r == 0);
-  ASSERT(uv_default_loop()->counters.check_init == ++check_init_prev);
-  uv_close((uv_handle_t*)&check, NULL);
-
-  /* idle_init test by uv_idle_init() */
-  idle_init_prev = uv_default_loop()->counters.idle_init;
-  r = uv_idle_init(uv_default_loop(), &idle);
-  ASSERT(r == 0);
-  ASSERT(uv_default_loop()->counters.idle_init == ++idle_init_prev);
-  uv_close((uv_handle_t*)&idle, NULL);
-
-  /* async_init test by uv_async_init() */
-  async_init_prev = uv_default_loop()->counters.async_init;
-  r = uv_async_init(uv_default_loop(), &async, NULL);
-  ASSERT(r == 0);
-  ASSERT(uv_default_loop()->counters.async_init == ++async_init_prev);
-  uv_close((uv_handle_t*)&async, NULL);
-
-  /* timer_init test by uv_timer_init() */
-  timer_init_prev = uv_default_loop()->counters.timer_init;
-  r = uv_timer_init(uv_default_loop(), &timer);
-  ASSERT(r == 0);
-  ASSERT(uv_default_loop()->counters.timer_init == ++timer_init_prev);
-  uv_close((uv_handle_t*)&timer, NULL);
-
-  /* process_init test by uv_spawn() */
-  process_init_prev = uv_default_loop()->counters.process_init;
-  init_process_options("spawn_helper1", exit_cb);
-  r = uv_spawn(uv_default_loop(), &process, options);
-  ASSERT(r == 0);
-  ASSERT(uv_default_loop()->counters.process_init == ++process_init_prev);
-  r = uv_run(uv_default_loop());
-  ASSERT(r == 0);
-
-  /* fs_event_init test by uv_fs_event_init() */
-  create_dir(uv_default_loop(), "watch_dir");
-  fs_event_init_prev = uv_default_loop()->counters.fs_event_init;
-  r = uv_fs_event_init(uv_default_loop(), &fs_event, "watch_dir", NULL, 0);
-  ASSERT(r == 0);
-  ASSERT(uv_default_loop()->counters.fs_event_init == ++fs_event_init_prev);
-  uv_fs_rmdir(uv_default_loop(), &fs_req, "watch_dir", NULL);
-  uv_fs_req_cleanup(&fs_req);
-
-  return 0;
-}
index 990444e..672672a 100644 (file)
@@ -50,7 +50,6 @@ static void close_cb(uv_handle_t* handle) {
 static void do_accept(uv_timer_t* timer_handle, int status) {
   uv_tcp_t* server;
   uv_tcp_t* accepted_handle = (uv_tcp_t*)malloc(sizeof *accepted_handle);
-  uint64_t tcpcnt;
   int r;
 
   ASSERT(timer_handle != NULL);
@@ -60,15 +59,10 @@ static void do_accept(uv_timer_t* timer_handle, int status) {
   r = uv_tcp_init(uv_default_loop(), accepted_handle);
   ASSERT(r == 0);
 
-  /* Test to that uv_default_loop()->counters.tcp_init does not increase across the uv_accept. */
-  tcpcnt = uv_default_loop()->counters.tcp_init;
-
   server = (uv_tcp_t*)timer_handle->data;
   r = uv_accept((uv_stream_t*)server, (uv_stream_t*)accepted_handle);
   ASSERT(r == 0);
 
-  ASSERT(uv_default_loop()->counters.tcp_init == tcpcnt);
-
   do_accept_called++;
 
   /* Immediately close the accepted handle. */
@@ -115,9 +109,6 @@ static void start_server() {
 
   r = uv_tcp_init(uv_default_loop(), server);
   ASSERT(r == 0);
-  ASSERT(uv_default_loop()->counters.tcp_init == 1);
-  ASSERT(uv_default_loop()->counters.handle_init == 1);
-
   r = uv_tcp_bind(server, addr);
   ASSERT(r == 0);
 
index 8d201c9..47e47ee 100644 (file)
@@ -123,6 +123,7 @@ TEST_DECLARE   (getsockname_tcp)
 TEST_DECLARE   (getsockname_udp)
 TEST_DECLARE   (fail_always)
 TEST_DECLARE   (pass_always)
+TEST_DECLARE   (spawn_fails)
 TEST_DECLARE   (spawn_exit_code)
 TEST_DECLARE   (spawn_stdout)
 TEST_DECLARE   (spawn_stdin)
@@ -174,11 +175,12 @@ TEST_DECLARE   (thread_rwlock)
 TEST_DECLARE   (thread_create)
 TEST_DECLARE   (strlcpy)
 TEST_DECLARE   (strlcat)
-TEST_DECLARE   (counters_init)
 TEST_DECLARE   (dlerror)
 TEST_DECLARE   (poll_duplex)
 TEST_DECLARE   (poll_unidirectional)
 TEST_DECLARE   (poll_close)
+TEST_DECLARE   (we_get_signal)
+TEST_DECLARE   (we_get_signals)
 #ifdef _WIN32
 TEST_DECLARE   (spawn_detect_pipe_name_collisions_on_windows)
 TEST_DECLARE   (argument_escaping)
@@ -350,6 +352,7 @@ TASK_LIST_START
   TEST_ENTRY  (poll_unidirectional)
   TEST_ENTRY  (poll_close)
 
+  TEST_ENTRY  (spawn_fails)
   TEST_ENTRY  (spawn_exit_code)
   TEST_ENTRY  (spawn_stdout)
   TEST_ENTRY  (spawn_stdin)
@@ -364,6 +367,10 @@ TASK_LIST_START
   TEST_ENTRY  (spawn_stdout_to_file)
   TEST_ENTRY  (fs_poll)
   TEST_ENTRY  (kill)
+
+  TEST_ENTRY  (we_get_signal)
+  TEST_ENTRY  (we_get_signals)
+
 #ifdef _WIN32
   TEST_ENTRY  (spawn_detect_pipe_name_collisions_on_windows)
   TEST_ENTRY  (argument_escaping)
@@ -411,7 +418,6 @@ TASK_LIST_START
   TEST_ENTRY  (thread_create)
   TEST_ENTRY  (strlcpy)
   TEST_ENTRY  (strlcat)
-  TEST_ENTRY  (counters_init)
   TEST_ENTRY  (dlerror)
 #if 0
   /* These are for testing the test runner. */
diff --git a/deps/uv/test/test-signal.c b/deps/uv/test/test-signal.c
new file mode 100644 (file)
index 0000000..b39bc24
--- /dev/null
@@ -0,0 +1,162 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#ifdef _WIN32
+
+TEST_IMPL(we_get_signal) {
+  return 0;
+}
+
+
+TEST_IMPL(we_get_signals) {
+  return 0;
+}
+
+#else /* !_WIN32 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+/* This test does not pretend to be cross-platform. */
+#include <pthread.h>
+#include <signal.h>
+#include <unistd.h>
+
+#define NSIGNALS  10
+
+struct timer_ctx {
+  unsigned int ncalls;
+  uv_timer_t handle;
+  int signum;
+};
+
+struct signal_ctx {
+  enum { CLOSE, STOP } stop_or_close;
+  unsigned int ncalls;
+  uv_signal_t handle;
+  int signum;
+};
+
+
+static void signal_cb(uv_signal_t* handle, int signum) {
+  struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle);
+  ASSERT(signum == ctx->signum);
+
+  if (++ctx->ncalls == NSIGNALS) {
+    if (ctx->stop_or_close == STOP)
+      uv_signal_stop(handle);
+    else if (ctx->stop_or_close == CLOSE)
+      uv_close((uv_handle_t*)handle, NULL);
+    else
+      ASSERT(0);
+  }
+}
+
+
+static void timer_cb(uv_timer_t* handle, int status) {
+  struct timer_ctx* ctx = container_of(handle, struct timer_ctx, handle);
+
+  raise(ctx->signum);
+
+  if (++ctx->ncalls == NSIGNALS)
+    uv_close((uv_handle_t*)handle, NULL);
+}
+
+
+static void start_watcher(uv_loop_t* loop, int signum, struct signal_ctx* ctx) {
+  ctx->ncalls = 0;
+  ctx->signum = signum;
+  ctx->stop_or_close = CLOSE;
+  ASSERT(0 == uv_signal_init(loop, &ctx->handle));
+  ASSERT(0 == uv_signal_start(&ctx->handle, signal_cb, signum));
+}
+
+
+static void start_timer(uv_loop_t* loop, int signum, struct timer_ctx* ctx) {
+  ctx->ncalls = 0;
+  ctx->signum = signum;
+  ASSERT(0 == uv_timer_init(loop, &ctx->handle));
+  ASSERT(0 == uv_timer_start(&ctx->handle, timer_cb, 5, 5));
+}
+
+
+TEST_IMPL(we_get_signal) {
+  struct signal_ctx sc;
+  struct timer_ctx tc;
+  uv_loop_t* loop;
+
+  loop = uv_default_loop();
+  start_timer(loop, SIGCHLD, &tc);
+  start_watcher(loop, SIGCHLD, &sc);
+  sc.stop_or_close = STOP; /* stop, don't close the signal handle */
+  ASSERT(0 == uv_run(loop));
+  ASSERT(tc.ncalls == NSIGNALS);
+  ASSERT(sc.ncalls == NSIGNALS);
+
+  start_timer(loop, SIGCHLD, &tc);
+  ASSERT(0 == uv_run(loop));
+  ASSERT(tc.ncalls == NSIGNALS);
+  ASSERT(sc.ncalls == NSIGNALS);
+
+  sc.ncalls = 0;
+  sc.stop_or_close = CLOSE; /* now close it when it's done */
+  uv_signal_start(&sc.handle, signal_cb, SIGCHLD);
+
+  start_timer(loop, SIGCHLD, &tc);
+  ASSERT(0 == uv_run(loop));
+  ASSERT(tc.ncalls == NSIGNALS);
+  ASSERT(sc.ncalls == NSIGNALS);
+
+  return 0;
+}
+
+
+TEST_IMPL(we_get_signals) {
+  struct signal_ctx sc[4];
+  struct timer_ctx tc[2];
+  uv_loop_t* loop;
+  unsigned int i;
+
+  loop = uv_default_loop();
+  start_watcher(loop, SIGUSR1, sc + 0);
+  start_watcher(loop, SIGUSR1, sc + 1);
+  start_watcher(loop, SIGUSR2, sc + 2);
+  start_watcher(loop, SIGUSR2, sc + 3);
+  start_timer(loop, SIGUSR1, tc + 0);
+  start_timer(loop, SIGUSR2, tc + 1);
+  ASSERT(0 == uv_run(loop));
+
+  for (i = 0; i < ARRAY_SIZE(sc); i++)
+    ASSERT(sc[i].ncalls == NSIGNALS);
+
+  for (i = 0; i < ARRAY_SIZE(tc); i++)
+    ASSERT(tc[i].ncalls == NSIGNALS);
+
+  return 0;
+}
+
+#endif /* _WIN32 */
index 06b211b..8cbb01c 100644 (file)
@@ -65,7 +65,7 @@ static void exit_cb_failure_expected(uv_process_t* process, int exit_status,
     int term_signal) {
   printf("exit_cb\n");
   exit_cb_called++;
-  ASSERT(exit_status == 127);
+  ASSERT(exit_status == -1);
   ASSERT(term_signal == 0);
   uv_close((uv_handle_t*)process, close_cb);
 }
@@ -145,6 +145,17 @@ static void timer_cb(uv_timer_t* handle, int status) {
 }
 
 
+TEST_IMPL(spawn_fails) {
+  init_process_options("", exit_cb_failure_expected);
+  options.file = options.args[0] = "program-that-had-better-not-exist";
+  ASSERT(0 == uv_spawn(uv_default_loop(), &process, options));
+  ASSERT(0 != uv_is_active((uv_handle_t*)&process));
+  ASSERT(0 == uv_run(uv_default_loop()));
+  ASSERT(uv_last_error(uv_default_loop()).code == UV_ENOENT);
+  return 0;
+}
+
+
 TEST_IMPL(spawn_exit_code) {
   int r;
 
@@ -578,11 +589,11 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
 }
 
 
-wchar_t* make_program_args(char** args, int verbatim_arguments);
-wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target);
+uv_err_t make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr);
+WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target);
 
 TEST_IMPL(argument_escaping) {
-  const wchar_t* test_str[] = {
+  const WCHAR* test_str[] = {
     L"HelloWorld",
     L"Hello World",
     L"Hello\"World",
@@ -594,12 +605,13 @@ TEST_IMPL(argument_escaping) {
     L"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\""
   };
   const int count = sizeof(test_str) / sizeof(*test_str);
-  wchar_t** test_output;
-  wchar_t* command_line;
-  wchar_t** cracked;
+  WCHAR** test_output;
+  WCHAR* command_line;
+  WCHAR** cracked;
   size_t total_size = 0;
   int i;
   int num_args;
+  uv_err_t result;
 
   char* verbatim[] = {
     "cmd.exe",
@@ -607,18 +619,18 @@ TEST_IMPL(argument_escaping) {
     "c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"",
     NULL
   };
-  wchar_t* verbatim_output;
-  wchar_t* non_verbatim_output;
+  WCHAR* verbatim_output;
+  WCHAR* non_verbatim_output;
 
-  test_output = calloc(count, sizeof(wchar_t*));
+  test_output = calloc(count, sizeof(WCHAR*));
   for (i = 0; i < count; ++i) {
-    test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(wchar_t));
+    test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(WCHAR));
     quote_cmd_arg(test_str[i], test_output[i]);
     wprintf(L"input : %s\n", test_str[i]);
     wprintf(L"output: %s\n", test_output[i]);
     total_size += wcslen(test_output[i]) + 1;
   }
-  command_line = calloc(total_size + 1, sizeof(wchar_t));
+  command_line = calloc(total_size + 1, sizeof(WCHAR));
   for (i = 0; i < count; ++i) {
     wcscat(command_line, test_output[i]);
     wcscat(command_line, L" ");
@@ -638,8 +650,10 @@ TEST_IMPL(argument_escaping) {
     free(test_output[i]);
   }
 
-  verbatim_output = make_program_args(verbatim, 1);
-  non_verbatim_output = make_program_args(verbatim, 0);
+  result = make_program_args(verbatim, 1, &verbatim_output);
+  ASSERT(result.code == UV_OK);
+  result = make_program_args(verbatim, 0, &non_verbatim_output);
+  ASSERT(result.code == UV_OK);
 
   wprintf(L"    verbatim_output: %s\n", verbatim_output);
   wprintf(L"non_verbatim_output: %s\n", non_verbatim_output);
@@ -653,7 +667,7 @@ TEST_IMPL(argument_escaping) {
   return 0;
 }
 
-wchar_t* make_program_env(char** env_block);
+WCHAR* make_program_env(char** env_block);
 
 TEST_IMPL(environment_creation) {
   int i;
@@ -666,22 +680,22 @@ TEST_IMPL(environment_creation) {
     NULL
   };
 
-  wchar_t expected[512];
-  wchar_t* ptr = expected;
-  wchar_t* result;
-  wchar_t* str;
+  WCHAR expected[512];
+  WCHAR* ptr = expected;
+  WCHAR* result;
+  WCHAR* str;
 
   for (i = 0; i < sizeof(environment) / sizeof(environment[0]) - 1; i++) {
     ptr += uv_utf8_to_utf16(environment[i], ptr, expected + sizeof(expected) - ptr);
   }
 
   memcpy(ptr, L"SYSTEMROOT=", sizeof(L"SYSTEMROOT="));
-  ptr += sizeof(L"SYSTEMROOT=")/sizeof(wchar_t) - 1;
+  ptr += sizeof(L"SYSTEMROOT=")/sizeof(WCHAR) - 1;
   ptr += GetEnvironmentVariableW(L"SYSTEMROOT", ptr, expected + sizeof(expected) - ptr);
   ++ptr;
 
   memcpy(ptr, L"SYSTEMDRIVE=", sizeof(L"SYSTEMDRIVE="));
-  ptr += sizeof(L"SYSTEMDRIVE=")/sizeof(wchar_t) - 1;
+  ptr += sizeof(L"SYSTEMDRIVE=")/sizeof(WCHAR) - 1;
   ptr += GetEnvironmentVariableW(L"SYSTEMDRIVE", ptr, expected + sizeof(expected) - ptr);
   ++ptr;
   *ptr = '\0';
index 45559c0..709d7dd 100644 (file)
@@ -107,7 +107,7 @@ TEST_IMPL(tcp_unexpected_read) {
    * start busy looping when the server sends a message and the client isn't
    * reading.
    */
-  ASSERT(ticks <= 10);
+  ASSERT(ticks <= 20);
 
   return 0;
 }
index 1fa285f..7b0fe1a 100644 (file)
@@ -59,6 +59,7 @@
           'sources': [
             'include/uv-private/uv-win.h',
             'src/win/async.c',
+            'src/win/atomicops-inl.h',
             'src/win/core.c',
             'src/win/dl.c',
             'src/win/error.c',
@@ -76,6 +77,7 @@
             'src/win/process-stdio.c',
             'src/win/req.c',
             'src/win/req-inl.h',
+            'src/win/signal.c',
             'src/win/stream.c',
             'src/win/stream-inl.h',
             'src/win/tcp.c',
             'include/uv-private/eio.h',
             'include/uv-private/ev.h',
             'include/uv-private/uv-unix.h',
+            'include/uv-private/uv-linux.h',
+            'include/uv-private/uv-sunos.h',
+            'include/uv-private/uv-darwin.h',
+            'include/uv-private/uv-bsd.h',
             'src/unix/async.c',
             'src/unix/core.c',
             'src/unix/dl.c',
             'src/unix/pipe.c',
             'src/unix/poll.c',
             'src/unix/process.c',
+            'src/unix/signal.c',
             'src/unix/stream.c',
             'src/unix/tcp.c',
             'src/unix/thread.c',
         'test/test-semaphore.c',
         'test/test-shutdown-close.c',
         'test/test-shutdown-eof.c',
+        'test/test-signal.c',
         'test/test-spawn.c',
         'test/test-fs-poll.c',
         'test/test-stdio-over-pipes.c',
         'test/test-tcp-unexpected-read.c',
         'test/test-threadpool.c',
         'test/test-mutexes.c',
+        'test/test-signal.c',
         'test/test-thread.c',
         'test/test-timer-again.c',
         'test/test-timer.c',
         'test/test-udp-options.c',
         'test/test-udp-send-and-recv.c',
         'test/test-udp-multicast-join.c',
-        'test/test-counters-init.c',
         'test/test-dlerror.c',
         'test/test-udp-multicast-ttl.c',
       ],