deps: upgrade libuv to a478847
authorBen Noordhuis <info@bnoordhuis.nl>
Thu, 17 May 2012 05:13:29 +0000 (07:13 +0200)
committerBen Noordhuis <info@bnoordhuis.nl>
Tue, 22 May 2012 14:14:24 +0000 (16:14 +0200)
The event loop's reference counting scheme in this version of libuv has changed.
Update the libuv bindings to reflect that fact.

85 files changed:
deps/uv/common.gypi
deps/uv/config-unix.mk
deps/uv/include/uv-private/uv-unix.h
deps/uv/include/uv-private/uv-win.h
deps/uv/include/uv.h
deps/uv/src/unix/async.c
deps/uv/src/unix/cares.c
deps/uv/src/unix/check.c [deleted file]
deps/uv/src/unix/core.c
deps/uv/src/unix/dl.c
deps/uv/src/unix/ev/ev.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/loop.c
deps/uv/src/unix/pipe.c
deps/uv/src/unix/poll.c [new file with mode: 0644]
deps/uv/src/unix/prepare.c [deleted file]
deps/uv/src/unix/process.c
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.c
deps/uv/src/uv-common.h
deps/uv/src/win/async.c
deps/uv/src/win/cares.c
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/fs.c
deps/uv/src/win/getaddrinfo.c
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 [new file with mode: 0644]
deps/uv/src/win/process.c
deps/uv/src/win/req.c
deps/uv/src/win/stream.c
deps/uv/src/win/tcp.c
deps/uv/src/win/thread.c
deps/uv/src/win/threadpool.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/src/win/winapi.c
deps/uv/src/win/winapi.h
deps/uv/src/win/winsock.c
deps/uv/src/win/winsock.h
deps/uv/test/benchmark-sizes.c
deps/uv/test/benchmark-udp-packet-storm.c
deps/uv/test/runner.c
deps/uv/test/test-callback-order.c [moved from deps/uv/src/unix/idle.c with 53% similarity]
deps/uv/test/test-dlerror.c
deps/uv/test/test-eio-overflow.c
deps/uv/test/test-fs.c
deps/uv/test/test-list.h
deps/uv/test/test-loop-handles.c
deps/uv/test/test-poll.c [new file with mode: 0644]
deps/uv/test/test-ref.c
deps/uv/test/test-stdio-over-pipes.c
deps/uv/test/test-tcp-close.c
deps/uv/test/test-tcp-connect-timeout.c [new file with mode: 0644]
deps/uv/test/test-tcp-write-error.c
deps/uv/test/test-timer-again.c
deps/uv/test/test-timer.c
deps/uv/test/test-udp-options.c
deps/uv/uv.gyp
lib/net.js
lib/tty.js
src/fs_event_wrap.cc
src/handle_wrap.cc
src/handle_wrap.h
src/node.cc
src/pipe_wrap.cc
src/stream_wrap.h
src/timer_wrap.cc
src/tty_wrap.cc

index 0d7ec83..c2df528 100644 (file)
@@ -24,7 +24,7 @@
               }],
             ],
             'Optimization': 0, # /Od, no optimization
-            'MinimalRebuild': 'true',
+            'MinimalRebuild': 'false',
             'OmitFramePointers': 'false',
             'BasicRuntimeChecks': 3, # /RTC1
           },
@@ -57,9 +57,6 @@
             'OmitFramePointers': 'true',
             'EnableFunctionLevelLinking': 'true',
             'EnableIntrinsicFunctions': 'true',
-            'AdditionalOptions': [
-              '/MP', # compile across multiple CPUs
-            ],
           },
           'VCLibrarianTool': {
             'AdditionalOptions': [
@@ -84,6 +81,9 @@
         'ExceptionHandling': 1, # /EHsc
         'SuppressStartupBanner': 'true',
         'WarnAsError': 'false',
+        'AdditionalOptions': [
+           '/MP', # compile across multiple CPUs
+         ],
       },
       'VCLibrarianTool': {
       },
index cdcf5ea..860059e 100644 (file)
@@ -29,15 +29,13 @@ CPPFLAGS += -D_FILE_OFFSET_BITS=64
 
 OBJS += src/unix/async.o
 OBJS += src/unix/cares.o
-OBJS += src/unix/check.o
 OBJS += src/unix/core.o
 OBJS += src/unix/dl.o
 OBJS += src/unix/error.o
 OBJS += src/unix/fs.o
-OBJS += src/unix/idle.o
 OBJS += src/unix/loop.o
 OBJS += src/unix/pipe.o
-OBJS += src/unix/prepare.o
+OBJS += src/unix/poll.o
 OBJS += src/unix/process.o
 OBJS += src/unix/stream.o
 OBJS += src/unix/tcp.o
index e190b85..efd57f0 100644 (file)
 #include <termios.h>
 #include <pthread.h>
 
+#if __sun
+# include <sys/port.h>
+# include <port.h>
+#endif
+
 /* Note: May be cast to struct iovec. See writev(2). */
 typedef struct {
   char* base;
@@ -45,6 +50,8 @@ typedef struct {
 
 typedef int uv_file;
 
+typedef int uv_os_sock_t;
+
 #define UV_ONCE_INIT PTHREAD_ONCE_INIT
 
 typedef pthread_once_t uv_once_t;
@@ -57,8 +64,11 @@ typedef gid_t uv_gid_t;
 typedef uid_t uv_uid_t;
 
 /* Platform-specific definitions for uv_dlopen support. */
-typedef void* uv_lib_t;
 #define UV_DYNAMIC /* empty */
+typedef struct {
+  void* handle;
+  char* errmsg;
+} uv_lib_t;
 
 #define UV_HANDLE_TYPE_PRIVATE /* empty */
 #define UV_REQ_TYPE_PRIVATE /* empty */
@@ -71,6 +81,10 @@ typedef void* uv_lib_t;
   } inotify_watchers;                                 \
   ev_io inotify_read_watcher;                         \
   int inotify_fd;
+#elif defined(PORT_SOURCE_FILE)
+# define UV_LOOP_PRIVATE_PLATFORM_FIELDS              \
+  ev_io fs_event_watcher;                             \
+  int fs_fd;
 #else
 # define UV_LOOP_PRIVATE_PLATFORM_FIELDS
 #endif
@@ -90,7 +104,10 @@ typedef void* uv_lib_t;
   uv_async_t uv_eio_want_poll_notifier; \
   uv_async_t uv_eio_done_poll_notifier; \
   uv_idle_t uv_eio_poller; \
-  uv_handle_t* endgame_handles; \
+  uv_handle_t* pending_handles; \
+  ngx_queue_t prepare_handles; \
+  ngx_queue_t check_handles; \
+  ngx_queue_t idle_handles; \
   UV_LOOP_PRIVATE_PLATFORM_FIELDS
 
 #define UV_REQ_BUFSML_SIZE (4)
@@ -127,7 +144,7 @@ typedef void* uv_lib_t;
 #define UV_HANDLE_PRIVATE_FIELDS \
   int fd; \
   int flags; \
-  uv_handle_t* endgame_next; /* that's what uv-win calls it */ \
+  uv_handle_t* next_pending; \
 
 
 #define UV_STREAM_PRIVATE_FIELDS \
@@ -162,22 +179,27 @@ typedef void* uv_lib_t;
   const char* pipe_fname; /* strdup'ed */
 
 
+/* UV_POLL */
+#define UV_POLL_PRIVATE_FIELDS        \
+  ev_io io_watcher;
+
+
 /* UV_PREPARE */ \
 #define UV_PREPARE_PRIVATE_FIELDS \
-  ev_prepare prepare_watcher; \
-  uv_prepare_cb prepare_cb;
+  uv_prepare_cb prepare_cb; \
+  ngx_queue_t queue;
 
 
 /* UV_CHECK */
 #define UV_CHECK_PRIVATE_FIELDS \
-  ev_check check_watcher; \
-  uv_check_cb check_cb;
+  uv_check_cb check_cb; \
+  ngx_queue_t queue;
 
 
 /* UV_IDLE */
 #define UV_IDLE_PRIVATE_FIELDS \
-  ev_idle idle_watcher; \
-  uv_idle_cb idle_cb;
+  uv_idle_cb idle_cb; \
+  ngx_queue_t queue;
 
 
 /* UV_ASYNC */
@@ -229,6 +251,7 @@ typedef void* uv_lib_t;
 
 #elif defined(__APPLE__)  \
   || defined(__FreeBSD__) \
+  || defined(__DragonFly__) \
   || defined(__OpenBSD__) \
   || defined(__NetBSD__)
 
@@ -239,9 +262,6 @@ typedef void* uv_lib_t;
 
 #elif defined(__sun)
 
-#include <sys/port.h>
-#include <port.h>
-
 #ifdef PORT_SOURCE_FILE
 # define UV_FS_EVENT_PRIVATE_FIELDS \
   ev_io event_watcher; \
index c55802c..da76e52 100644 (file)
 #include <sys/stat.h>
 
 #include "tree.h"
+#include "ngx-queue.h"
 
 #define MAX_PIPENAME_LEN 256
 
+#ifndef S_IFLNK
+# define S_IFLNK          0xA000
+#endif
+
 /*
  * Guids and typedefs for winsock extension functions
  * Mingw32 doesn't have these :-(
@@ -128,6 +133,26 @@ typedef int (WSAAPI* LPFN_WSARECVFROM)
              LPWSAOVERLAPPED overlapped,
              LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
 
+#ifndef _NTDEF_
+  typedef LONG NTSTATUS;
+  typedef NTSTATUS *PNTSTATUS;
+#endif
+
+typedef struct _AFD_POLL_HANDLE_INFO {
+  HANDLE Handle;
+  ULONG Events;
+  NTSTATUS Status;
+} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO;
+
+typedef struct _AFD_POLL_INFO {
+  LARGE_INTEGER Timeout;
+  ULONG NumberOfHandles;
+  ULONG Exclusive;
+  AFD_POLL_HANDLE_INFO Handles[1];
+} AFD_POLL_INFO, *PAFD_POLL_INFO;
+
+#define UV_MSAFD_PROVIDER_COUNT 3
+
 
 /**
  * It should be possible to cast uv_buf_t[] to WSABUF[]
@@ -140,6 +165,8 @@ typedef struct uv_buf_t {
 
 typedef int uv_file;
 
+typedef SOCKET uv_os_sock_t;
+
 typedef HANDLE uv_thread_t;
 
 typedef CRITICAL_SECTION uv_mutex_t;
@@ -170,16 +197,17 @@ typedef unsigned char uv_uid_t;
 typedef unsigned char uv_gid_t;
 
 /* Platform-specific definitions for uv_dlopen support. */
-typedef HMODULE uv_lib_t;
 #define UV_DYNAMIC FAR WINAPI
+typedef struct {
+  HMODULE handle;
+  char* errmsg;
+} uv_lib_t;
 
 RB_HEAD(uv_timer_tree_s, uv_timer_s);
 
 #define UV_LOOP_PRIVATE_FIELDS                                                \
     /* The loop's I/O completion port */                                      \
   HANDLE iocp;                                                                \
-  /* Reference count that keeps the event loop alive */                       \
-  int refs;                                                                   \
   /* The current time according to the event loop. in msecs. */               \
   int64_t time;                                                               \
   /* Tail of a single-linked circular queue of pending reqs. If the queue */  \
@@ -201,6 +229,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   uv_prepare_t* next_prepare_handle;                                          \
   uv_check_t* next_check_handle;                                              \
   uv_idle_t* next_idle_handle;                                                \
+  /* This handle holds the peer sockets for the fast variant of uv_poll_t */  \
+  SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT];                          \
+  /* State used by uv_ares. */                                                \
   ares_channel ares_chan;                                                     \
   int ares_active_sockets;                                                    \
   uv_timer_t ares_polling_timer;                                              \
@@ -218,7 +249,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   UV_ARES_EVENT_REQ,                      \
   UV_ARES_CLEANUP_REQ,                    \
   UV_FS_EVENT_REQ,                        \
-  UV_GETADDRINFO_REQ,                     \
+  UV_POLL_REQ,                            \
   UV_PROCESS_EXIT,                        \
   UV_PROCESS_CLOSE,                       \
   UV_READ,                                \
@@ -281,6 +312,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
 
 #define UV_STREAM_PRIVATE_FIELDS          \
   unsigned int reqs_pending;              \
+  int activecnt;                          \
   uv_read_t read_req;                     \
   union {                                 \
     struct { uv_stream_connection_fields };  \
@@ -308,6 +340,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
 #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;      \
@@ -368,6 +401,21 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   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;                            \
@@ -400,7 +448,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   unsigned int flags;
 
 #define UV_GETADDRINFO_PRIVATE_FIELDS     \
-  struct uv_req_s getadddrinfo_req;       \
   uv_getaddrinfo_cb getaddrinfo_cb;       \
   void* alloc;                            \
   wchar_t* node;                          \
index 97d419d..a9e895e 100644 (file)
@@ -143,6 +143,7 @@ typedef enum {
   XX(FS_EVENT, fs_event)        \
   XX(IDLE, idle)                \
   XX(NAMED_PIPE, pipe)          \
+  XX(POLL, poll)                \
   XX(PREPARE, prepare)          \
   XX(PROCESS, process)          \
   XX(TCP, tcp)                  \
@@ -189,6 +190,7 @@ typedef struct uv_tcp_s uv_tcp_t;
 typedef struct uv_udp_s uv_udp_t;
 typedef struct uv_pipe_s uv_pipe_t;
 typedef struct uv_tty_s uv_tty_t;
+typedef struct uv_poll_s uv_poll_t;
 typedef struct uv_timer_s uv_timer_t;
 typedef struct uv_prepare_s uv_prepare_t;
 typedef struct uv_check_s uv_check_t;
@@ -222,10 +224,6 @@ typedef struct uv_work_s uv_work_t;
 UV_EXTERN uv_loop_t* uv_loop_new(void);
 UV_EXTERN void uv_loop_delete(uv_loop_t*);
 
-/* This is a debugging tool. It's NOT part of the official API. */
-UV_EXTERN int uv_loop_refcount(const uv_loop_t*);
-
-
 /*
  * Returns the default loop.
  */
@@ -246,8 +244,8 @@ UV_EXTERN int uv_run_once (uv_loop_t*);
  * Manually modify the event loop's reference count. Useful if the user wants
  * to have a handle or timeout that doesn't keep the loop alive.
  */
-UV_EXTERN void uv_ref(uv_loop_t*);
-UV_EXTERN void uv_unref(uv_loop_t*);
+UV_EXTERN void uv_ref(uv_handle_t*);
+UV_EXTERN void uv_unref(uv_handle_t*);
 
 UV_EXTERN void uv_update_time(uv_loop_t*);
 UV_EXTERN int64_t uv_now(uv_loop_t*);
@@ -288,6 +286,7 @@ typedef void (*uv_connect_cb)(uv_connect_t* req, int status);
 typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status);
 typedef void (*uv_connection_cb)(uv_stream_t* server, int status);
 typedef void (*uv_close_cb)(uv_handle_t* handle);
+typedef void (*uv_poll_cb)(uv_poll_t* handle, int status, int events);
 typedef void (*uv_timer_cb)(uv_timer_t* handle, int status);
 /* TODO: do these really need a status argument? */
 typedef void (*uv_async_cb)(uv_async_t* handle, int status);
@@ -333,12 +332,18 @@ UV_EXTERN uv_err_t uv_last_error(uv_loop_t*);
 UV_EXTERN const char* uv_strerror(uv_err_t err);
 UV_EXTERN const char* uv_err_name(uv_err_t err);
 
+#ifndef UV_LEAN_AND_MEAN
+# define UV_REQ_EXTRA_FIELDS ngx_queue_t active_queue;
+#else
+# define UV_REQ_EXTRA_FIELDS
+#endif
 
 #define UV_REQ_FIELDS \
   /* read-only */ \
   uv_req_type type; \
   /* public */ \
   void* data; \
+  UV_REQ_EXTRA_FIELDS \
   /* private */ \
   UV_REQ_PRIVATE_FIELDS
 
@@ -371,6 +376,12 @@ struct uv_shutdown_s {
 };
 
 
+#ifndef UV_LEAN_AND_MEAN
+# define UV_HANDLE_EXTRA_FIELDS ngx_queue_t active_queue;
+#else
+# define UV_HANDLE_EXTRA_FIELDS
+#endif
+
 #define UV_HANDLE_FIELDS \
   /* read-only */ \
   uv_loop_t* loop; \
@@ -378,6 +389,7 @@ struct uv_shutdown_s {
   /* public */ \
   uv_close_cb close_cb; \
   void* data; \
+  UV_HANDLE_EXTRA_FIELDS \
   /* private */ \
   UV_HANDLE_PRIVATE_FIELDS
 
@@ -927,6 +939,74 @@ UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
 
 
 /*
+ * uv_poll_t is a subclass of uv_handle_t.
+ *
+ * The uv_poll watcher is used to watch file descriptors for readability and
+ * writability, similar to the purpose of poll(2).
+ *
+ * The purpose of uv_poll is to enable integrating external libraries that
+ * rely on the event loop to signal it about the socket status changes, like
+ * c-ares or libssh2. Using uv_poll_t for any other other purpose is not
+ * recommended; uv_tcp_t, uv_udp_t, etc. provide an implementation that is
+ * much faster and more scalable than what can be achieved with uv_poll_t,
+ * especially on Windows.
+ *
+ * It is possible that uv_poll occasionally signals that a file descriptor is
+ * readable or writable even when it isn't. The user should therefore always
+ * be prepared to handle EAGAIN or equivalent when it attempts to read from or
+ * write to the fd.
+ *
+ * It is not okay to have multiple active uv_poll watchers for the same socket.
+ * This can cause libuv to busyloop or otherwise malfunction.
+ *
+ * The user should not close a file descriptor while it is being polled by an
+ * active uv_poll watcher. This can cause the poll watcher to report an error,
+ * but it might also start polling another socket. However the fd can be safely
+ * closed immediately after a call to uv_poll_stop() or uv_close().
+ *
+ * On windows only sockets can be polled with uv_poll. On unix any file
+ * descriptor that would be accepted by poll(2) can be used with uv_poll.
+ */
+struct uv_poll_s {
+  UV_HANDLE_FIELDS
+  uv_poll_cb poll_cb;
+  UV_POLL_PRIVATE_FIELDS
+};
+
+enum uv_poll_event {
+  UV_READABLE = 1,
+  UV_WRITABLE = 2
+};
+
+/* Initialize the poll watcher using a file descriptor. */
+UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd);
+
+/* Initialize the poll watcher using a socket descriptor. On unix this is */
+/* identical to uv_poll_init. On windows it takes a SOCKET handle. */
+UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
+    uv_os_sock_t socket);
+
+/*
+ * Starts polling the file descriptor. `events` is a bitmask consisting made up
+ * of UV_READABLE and UV_WRITABLE. As soon as an event is detected the callback
+ * will be called with `status` set to 0, and the detected events set en the
+ * `events` field.
+ *
+ * If an error happens while polling status may be set to -1 and the error
+ * code can be retrieved with uv_last_error. The user should not close the
+ * socket while uv_poll is active. If the user does that anyway, the callback
+ * *may* be called reporting an error status, but this is not guaranteed.
+ *
+ * Calling uv_poll_start on an uv_poll watcher that is already active is fine.
+ * Doing so will update the events mask that is being watched for.
+ */
+UV_EXTERN int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb);
+
+/* Stops polling the file descriptor. */
+UV_EXTERN int uv_poll_stop(uv_poll_t* handle);
+
+
+/*
  * uv_prepare_t is a subclass of uv_handle_t.
  *
  * libev wrapper. Every active prepare handle gets its callback called
@@ -1361,6 +1441,12 @@ UV_EXTERN int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
  */
 #define UV_FS_SYMLINK_DIR          0x0001
 
+/*
+ * This flag can be used with uv_fs_symlink on Windows
+ * to specify whether the symlink is to be created using junction points.
+ */
+#define UV_FS_SYMLINK_JUNCTION     0x0002
+
 UV_EXTERN int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
     const char* new_path, int flags, uv_fs_cb cb);
 
@@ -1461,23 +1547,26 @@ UV_EXTERN extern uint64_t uv_hrtime(void);
 
 
 /*
- * Opens a shared library. The filename is in utf-8. On success, -1 is returned
- * and the variable pointed by library receives a handle to the library.
+ * Opens a shared library. The filename is in utf-8. Returns 0 on success and
+ * -1 on error. Call `uv_dlerror(uv_lib_t*)` to get the error message.
  */
-UV_EXTERN uv_err_t uv_dlopen(const char* filename, uv_lib_t* library);
-UV_EXTERN uv_err_t uv_dlclose(uv_lib_t library);
+UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib);
+
+/*
+ * Close the shared libary.
+ */
+UV_EXTERN void uv_dlclose(uv_lib_t* lib);
 
 /*
  * Retrieves a data pointer from a dynamic library. It is legal for a symbol to
- * map to NULL.
+ * map to NULL. Returns 0 on success and -1 if the symbol was not found.
  */
-UV_EXTERN uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr);
+UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr);
 
 /*
- * Retrieves and frees an error message of dynamic linking loaders.
+ * Returns the last uv_dlopen() or uv_dlsym() error message.
  */
-UV_EXTERN const char *uv_dlerror(uv_lib_t library);
-UV_EXTERN void uv_dlerror_free(uv_lib_t library, const char *msg);
+UV_EXTERN const char* uv_dlerror(uv_lib_t* lib);
 
 /*
  * The mutex functions return 0 on success, -1 on error
@@ -1543,6 +1632,7 @@ struct uv_counters_s {
   uint64_t udp_init;
   uint64_t pipe_init;
   uint64_t tty_init;
+  uint64_t poll_init;
   uint64_t prepare_init;
   uint64_t check_init;
   uint64_t idle_init;
@@ -1563,6 +1653,13 @@ struct uv_loop_s {
   uv_err_t last_err;
   /* User data - use this for whatever. */
   void* data;
+#ifndef UV_LEAN_AND_MEAN
+  ngx_queue_t active_reqs;
+  ngx_queue_t active_handles;
+#else
+  unsigned int active_reqs;
+  unsigned int active_handles;
+#endif
 };
 
 
index 638774c..db9ce18 100644 (file)
@@ -40,7 +40,8 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* async, uv_async_cb async_cb) {
 
   /* Note: This does not have symmetry with the other libev wrappers. */
   ev_async_start(loop->ev, &async->async_watcher);
-  ev_unref(loop->ev);
+  uv__handle_unref(async);
+  uv__handle_start(async);
 
   return 0;
 }
@@ -54,5 +55,6 @@ int uv_async_send(uv_async_t* async) {
 
 void uv__async_close(uv_async_t* handle) {
   ev_async_stop(handle->loop->ev, &handle->async_watcher);
-  ev_ref(handle->loop->ev);
+  uv__handle_ref(handle);
+  uv__handle_stop(handle);
 }
index 03667fd..a579eaa 100644 (file)
@@ -37,20 +37,6 @@ static void uv__ares_timeout(uv_timer_t* handle, int status) {
 }
 
 
-static void uv__ares_timer_start(uv_loop_t* loop) {
-  if (uv_is_active((uv_handle_t*)&loop->timer)) return;
-  uv_timer_start(&loop->timer, uv__ares_timeout, 1000, 1000);
-  uv_ref(loop);
-}
-
-
-static void uv__ares_timer_stop(uv_loop_t* loop) {
-  if (!uv_is_active((uv_handle_t*)&loop->timer)) return;
-  uv_timer_stop(&loop->timer);
-  uv_unref(loop);
-}
-
-
 static void uv__ares_io(struct ev_loop* ev, struct ev_io* watcher,
     int revents) {
   uv_loop_t* loop = ev_userdata(ev);
@@ -104,9 +90,9 @@ static void uv__ares_sockstate_cb(void* data, ares_socket_t sock,
       /* New socket */
 
       /* If this is the first socket then start the timer. */
-      if (!uv_is_active((uv_handle_t*)&loop->timer)) {
+      if (!uv__is_active(&loop->timer)) {
         assert(uv_ares_handles_empty(loop));
-        uv__ares_timer_start(loop);
+        uv_timer_start(&loop->timer, uv__ares_timeout, 1000, 1000);
       }
 
       h = uv__ares_task_create(loop, sock);
@@ -140,7 +126,7 @@ static void uv__ares_sockstate_cb(void* data, ares_socket_t sock,
     free(h);
 
     if (uv_ares_handles_empty(loop)) {
-      uv__ares_timer_stop(loop);
+      uv_timer_stop(&loop->timer);
     }
   }
 }
@@ -176,7 +162,6 @@ int uv_ares_init_options(uv_loop_t* loop, ares_channel *channelptr,
    * first socket is opened.
    */
   uv_timer_init(loop, &loop->timer);
-  uv_unref(loop);
   loop->timer.data = loop;
 
   return rc;
@@ -187,7 +172,7 @@ int uv_ares_init_options(uv_loop_t* loop, ares_channel *channelptr,
 void uv_ares_destroy(uv_loop_t* loop, ares_channel channel) {
   /* only allow destroy if did init */
   if (loop->channel) {
-    uv__ares_timer_stop(loop);
+    uv_timer_stop(&loop->timer);
     ares_destroy(channel);
     loop->channel = NULL;
   }
diff --git a/deps/uv/src/unix/check.c b/deps/uv/src/unix/check.c
deleted file mode 100644 (file)
index a975210..0000000
+++ /dev/null
@@ -1,80 +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.
- */
-
-#include "uv.h"
-#include "internal.h"
-
-
-static void uv__check(EV_P_ ev_check* w, int revents) {
-  uv_check_t* check = container_of(w, uv_check_t, check_watcher);
-
-  if (check->check_cb) {
-    check->check_cb(check, 0);
-  }
-}
-
-
-int uv_check_init(uv_loop_t* loop, uv_check_t* check) {
-  uv__handle_init(loop, (uv_handle_t*)check, UV_CHECK);
-  loop->counters.check_init++;
-
-  ev_check_init(&check->check_watcher, uv__check);
-  check->check_cb = NULL;
-
-  return 0;
-}
-
-
-int uv_check_start(uv_check_t* check, uv_check_cb cb) {
-  int was_active = ev_is_active(&check->check_watcher);
-
-  check->check_cb = cb;
-
-  ev_check_start(check->loop->ev, &check->check_watcher);
-
-  if (!was_active) {
-    ev_unref(check->loop->ev);
-  }
-
-  return 0;
-}
-
-
-int uv_check_stop(uv_check_t* check) {
-  int was_active = ev_is_active(&check->check_watcher);
-
-  ev_check_stop(check->loop->ev, &check->check_watcher);
-
-  if (was_active) {
-    ev_ref(check->loop->ev);
-  }
-
-  return 0;
-}
-
-
-int uv__check_active(const uv_check_t* handle) {
-  return ev_is_active(&handle->check_watcher);
-}
-
-
-void uv__check_close(uv_check_t* handle) {
-  uv_check_stop(handle);
-}
index 9602b64..db0cc48 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 #include "uv.h"
-#include "unix/internal.h"
+#include "internal.h"
 
 #include <stddef.h> /* NULL */
 #include <stdio.h> /* printf */
@@ -107,14 +107,16 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
     uv__fs_event_close((uv_fs_event_t*)handle);
     break;
 
+  case UV_POLL:
+    uv__poll_close((uv_poll_t*)handle);
+    break;
+
   default:
     assert(0);
   }
 
   handle->flags |= UV_CLOSING;
-  handle->endgame_next = handle->loop->endgame_handles;
-  handle->loop->endgame_handles = handle;
-  uv_unref(handle->loop);
+  uv__make_pending(handle);
 }
 
 
@@ -161,24 +163,73 @@ void uv_loop_delete(uv_loop_t* loop) {
 }
 
 
-int uv_loop_refcount(const uv_loop_t* loop) {
-  return ev_loop_refcount(loop->ev);
+static void uv__run_pending(uv_loop_t* loop) {
+  uv_handle_t* p;
+  uv_handle_t* q;
+
+  if (!loop->pending_handles)
+    return;
+
+  for (p = loop->pending_handles, loop->pending_handles = NULL; p; p = q) {
+    q = p->next_pending;
+    p->next_pending = NULL;
+    p->flags &= ~UV__PENDING;
+
+    if (p->flags & UV_CLOSING) {
+      uv__finish_close(p);
+      continue;
+    }
+
+    switch (p->type) {
+    case UV_NAMED_PIPE:
+    case UV_TCP:
+    case UV_TTY:
+      uv__stream_pending((uv_stream_t*)p);
+      break;
+    default:
+      abort();
+    }
+  }
 }
 
 
-void uv__run(uv_loop_t* loop) {
-  ev_run(loop->ev, EVRUN_ONCE);
+static void uv__poll(uv_loop_t* loop, int block) {
+  /* bump the loop's refcount, otherwise libev does
+   * a zero timeout poll and we end up busy looping
+   */
+  ev_ref(loop->ev);
+  ev_run(loop->ev, block ? EVRUN_ONCE : EVRUN_NOWAIT);
+  ev_unref(loop->ev);
+}
 
-  while (loop->endgame_handles)
-    uv__finish_close(loop->endgame_handles);
+
+static int uv__should_block(uv_loop_t* loop) {
+  return ngx_queue_empty(&loop->idle_handles)
+      && !ngx_queue_empty(&loop->active_handles);
 }
 
 
-int uv_run(uv_loop_t* loop) {
-  do
-    uv__run(loop);
-  while (uv_loop_refcount(loop) > 0);
+static int uv__run(uv_loop_t* loop) {
+  uv__run_idle(loop);
+  uv__run_pending(loop);
+
+  if (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) {
+    uv__run_prepare(loop);
+    /* Need to poll even if there are no active handles left, otherwise
+     * uv_work_t reqs won't complete...
+     */
+    uv__poll(loop, uv__should_block(loop));
+    uv__run_check(loop);
+  }
+
+  return uv__has_pending_handles(loop)
+      || uv__has_active_handles(loop)
+      || uv__has_active_reqs(loop);
+}
+
 
+int uv_run(uv_loop_t* loop) {
+  while (uv__run(loop));
   return 0;
 }
 
@@ -195,38 +246,24 @@ void uv__handle_init(uv_loop_t* loop, uv_handle_t* handle,
 
   handle->loop = loop;
   handle->type = type;
-  handle->flags = 0;
-  handle->endgame_next = NULL;
-  uv_ref(loop); /* unref'd in uv_close() */
+  handle->flags = UV__REF; /* ref the loop when active */
+  handle->next_pending = NULL;
 }
 
 
 void uv__finish_close(uv_handle_t* handle) {
-  uv_loop_t* loop = handle->loop;
-
+  assert(!uv__is_active(handle));
   assert(handle->flags & UV_CLOSING);
   assert(!(handle->flags & UV_CLOSED));
   handle->flags |= UV_CLOSED;
 
   switch (handle->type) {
     case UV_PREPARE:
-      assert(!ev_is_active(&((uv_prepare_t*)handle)->prepare_watcher));
-      break;
-
     case UV_CHECK:
-      assert(!ev_is_active(&((uv_check_t*)handle)->check_watcher));
-      break;
-
     case UV_IDLE:
-      assert(!ev_is_active(&((uv_idle_t*)handle)->idle_watcher));
-      break;
-
     case UV_ASYNC:
-      assert(!ev_is_active(&((uv_async_t*)handle)->async_watcher));
-      break;
-
     case UV_TIMER:
-      assert(!ev_is_active(&((uv_timer_t*)handle)->timer_watcher));
+    case UV_PROCESS:
       break;
 
     case UV_NAMED_PIPE:
@@ -242,11 +279,10 @@ void uv__finish_close(uv_handle_t* handle) {
       uv__udp_finish_close((uv_udp_t*)handle);
       break;
 
-    case UV_PROCESS:
-      assert(!ev_is_active(&((uv_process_t*)handle)->child_watcher));
+    case UV_FS_EVENT:
       break;
 
-    case UV_FS_EVENT:
+    case UV_POLL:
       break;
 
     default:
@@ -255,21 +291,11 @@ void uv__finish_close(uv_handle_t* handle) {
   }
 
 
-  loop->endgame_handles = handle->endgame_next;
-
   if (handle->close_cb) {
     handle->close_cb(handle);
   }
-}
-
 
-void uv_ref(uv_loop_t* loop) {
-  ev_ref(loop->ev);
-}
-
-
-void uv_unref(uv_loop_t* loop) {
-  ev_unref(loop->ev);
+  uv__handle_unref(handle);
 }
 
 
@@ -284,54 +310,43 @@ int64_t uv_now(uv_loop_t* loop) {
 
 
 int uv_is_active(const uv_handle_t* handle) {
-  switch (handle->type) {
-  case UV_CHECK:
-    return uv__check_active((const uv_check_t*)handle);
-  case UV_IDLE:
-    return uv__idle_active((const uv_idle_t*)handle);
-  case UV_PREPARE:
-    return uv__prepare_active((const uv_prepare_t*)handle);
-  case UV_TIMER:
-    return uv__timer_active((const uv_timer_t*)handle);
-  default:
-    return 1;
-  }
+  return uv__is_active(handle);
 }
 
 
-static int uv_getaddrinfo_done(eio_req* req) {
-  uv_getaddrinfo_t* handle = req->data;
-  struct addrinfo *res = handle->res;
+static int uv_getaddrinfo_done(eio_req* req_) {
+  uv_getaddrinfo_t* req = req_->data;
+  struct addrinfo *res = req->res;
 #if __sun
   size_t hostlen = strlen(handle->hostname);
 #endif
 
-  handle->res = NULL;
+  req->res = NULL;
 
-  uv_unref(handle->loop);
+  uv__req_unregister(req->loop, req);
 
-  free(handle->hints);
-  free(handle->service);
-  free(handle->hostname);
+  free(req->hints);
+  free(req->service);
+  free(req->hostname);
 
-  if (handle->retcode == 0) {
+  if (req->retcode == 0) {
     /* OK */
 #if EAI_NODATA /* FreeBSD deprecated EAI_NODATA */
-  } else if (handle->retcode == EAI_NONAME || handle->retcode == EAI_NODATA) {
+  } else if (req->retcode == EAI_NONAME || req->retcode == EAI_NODATA) {
 #else
-  } else if (handle->retcode == EAI_NONAME) {
+  } else if (req->retcode == EAI_NONAME) {
 #endif
-    uv__set_sys_error(handle->loop, ENOENT); /* FIXME compatibility hack */
+    uv__set_sys_error(req->loop, ENOENT); /* FIXME compatibility hack */
 #if __sun
-  } else if (handle->retcode == EAI_MEMORY && hostlen >= MAXHOSTNAMELEN) {
-    uv__set_sys_error(handle->loop, ENOENT);
+  } else if (req->retcode == EAI_MEMORY && hostlen >= MAXHOSTNAMELEN) {
+    uv__set_sys_error(req->loop, ENOENT);
 #endif
   } else {
-    handle->loop->last_err.code = UV_EADDRINFO;
-    handle->loop->last_err.sys_errno_ = handle->retcode;
+    req->loop->last_err.code = UV_EADDRINFO;
+    req->loop->last_err.sys_errno_ = req->retcode;
   }
 
-  handle->cb(handle, handle->retcode, res);
+  req->cb(req, req->retcode, res);
 
   return 0;
 }
@@ -387,8 +402,6 @@ int uv_getaddrinfo(uv_loop_t* loop,
   /* TODO check handle->hostname == NULL */
   /* TODO check handle->service == NULL */
 
-  uv_ref(loop);
-
   req = eio_custom(getaddrinfo_thread_proc, EIO_PRI_DEFAULT,
       uv_getaddrinfo_done, handle, &loop->uv_eio_channel);
   assert(req);
index 88c9525..9eb6600 100644 (file)
 #include <string.h>
 #include <locale.h>
 
-/* The dl family of functions don't set errno. We need a good way to communicate
- * errors to the caller but there is only dlerror() and that returns a string -
- * a string that may or may not be safe to keep a reference to...
- */
-static const uv_err_t uv_inval_ = { UV_EINVAL, EINVAL };
-
+static int uv__dlerror(uv_lib_t* lib);
 
-uv_err_t uv_dlopen(const char* filename, uv_lib_t* library) {
-  void* handle = dlopen(filename, RTLD_LAZY);
-  if (handle == NULL) {
-    return uv_inval_;
-  }
 
-  *library = handle;
-  return uv_ok_;
+int uv_dlopen(const char* filename, uv_lib_t* lib) {
+  lib->errmsg = NULL;
+  lib->handle = dlopen(filename, RTLD_LAZY);
+  return uv__dlerror(lib);
 }
 
 
-uv_err_t uv_dlclose(uv_lib_t library) {
-  if (dlclose(library) != 0) {
-    return uv_inval_;
+void uv_dlclose(uv_lib_t* lib) {
+  if (lib->errmsg) {
+    free(lib->errmsg);
+    lib->errmsg = NULL;
   }
 
-  return uv_ok_;
+  if (lib->handle) {
+    /* Ignore errors. No good way to signal them without leaking memory. */
+    dlclose(lib->handle);
+    lib->handle = NULL;
+  }
 }
 
 
-uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr) {
-  void* address;
-
-  /* Reset error status. */
-  dlerror();
+int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
+  dlerror(); /* Reset error status. */
+  *ptr = dlsym(lib->handle, name);
+  return uv__dlerror(lib);
+}
 
-  address = dlsym(library, name);
 
-  if (dlerror()) {
-    return uv_inval_;
-  }
-
-  *ptr = (void*) address;
-  return uv_ok_;
+const char* uv_dlerror(uv_lib_t* lib) {
+  return lib->errmsg ? lib->errmsg : "no error";
 }
 
 
-const char *uv_dlerror(uv_lib_t library) {
-  const char* buf = NULL;
-  /* Make uv_dlerror() be independent of locale */
-  char* loc = setlocale(LC_MESSAGES, NULL);
-  if(strcmp(loc, "C") == 0) {
-    return strdup(dlerror());
-  } else {
-    setlocale(LC_MESSAGES, "C");
-    buf = dlerror();
-    setlocale(LC_MESSAGES, loc);
-    return strdup(buf);
-  }
-}
+static int uv__dlerror(uv_lib_t* lib) {
+  char* errmsg;
 
+  if (lib->errmsg)
+    free(lib->errmsg);
 
-void uv_dlerror_free(uv_lib_t library, const char *msg) {
-  free((void*)msg);
+  errmsg = dlerror();
+
+  if (errmsg) {
+    lib->errmsg = strdup(errmsg);
+    return -1;
+  }
+  else {
+    lib->errmsg = NULL;
+    return 0;
+  }
 }
index b6e190f..a432bfb 100644 (file)
@@ -2554,6 +2554,7 @@ void
 ev_unref (EV_P)
 {
   --activecnt;
+  if (activecnt < 0) abort();
 }
 
 void
index 3417fa6..e62832d 100644 (file)
@@ -49,7 +49,6 @@
       uv__set_sys_error(loop, ENOMEM); \
       return -1; \
     } \
-    uv_ref(loop); \
   } else { \
     /* sync */ \
     req->result = func(args); \
@@ -75,10 +74,17 @@ static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, uv_fs_type fs_type,
   req->path = path ? strdup(path) : NULL;
   req->errorno = 0;
   req->eio = NULL;
+
+  /* synchronous requests don't increase the reference count */
+  if (!req->cb)
+    uv__req_unregister(req->loop, req);
 }
 
 
 void uv_fs_req_cleanup(uv_fs_t* req) {
+  if (req->cb)
+    uv__req_unregister(req->loop, req);
+
   free(req->path);
   req->path = NULL;
 
@@ -169,10 +175,9 @@ static int uv__fs_after(eio_req* eio) {
       break;
   }
 
-  uv_unref(req->loop);
   req->eio = NULL; /* Freed by libeio */
-
   req->cb(req);
+
   return 0;
 }
 
@@ -189,7 +194,6 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
 
   if (cb) {
     /* async */
-    uv_ref(loop);
     req->eio = eio_open(path, flags, mode, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel);
     if (!req->eio) {
       uv__set_sys_error(loop, ENOMEM);
@@ -219,7 +223,6 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf,
 
   if (cb) {
     /* async */
-    uv_ref(loop);
     req->eio = eio_read(fd, buf, length, offset, EIO_PRI_DEFAULT,
         uv__fs_after, req,  &loop->uv_eio_channel);
 
@@ -257,7 +260,6 @@ int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf,
 
   if (cb) {
     /* async */
-    uv_ref(loop);
     req->eio = eio_write(file, buf, length, offset, EIO_PRI_DEFAULT,
         uv__fs_after, req,  &loop->uv_eio_channel);
     if (!req->eio) {
@@ -305,7 +307,6 @@ int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
 
   if (cb) {
     /* async */
-    uv_ref(loop);
     req->eio = eio_readdir(path, flags, EIO_PRI_DEFAULT, uv__fs_after, req,  &loop->uv_eio_channel);
     if (!req->eio) {
       uv__set_sys_error(loop, ENOMEM);
@@ -375,7 +376,6 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
 
   if (cb) {
     /* async */
-    uv_ref(loop);
     req->eio = eio_stat(pathdup, EIO_PRI_DEFAULT, uv__fs_after, req,  &loop->uv_eio_channel);
 
     free(pathdup);
@@ -409,7 +409,6 @@ int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
 
   if (cb) {
     /* async */
-    uv_ref(loop);
     req->eio = eio_fstat(file, EIO_PRI_DEFAULT, uv__fs_after, req,  &loop->uv_eio_channel);
 
     if (!req->eio) {
@@ -495,7 +494,6 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
 }
 
 
-#if HAVE_FUTIMES
 static int _futime(const uv_file fd, double atime, double mtime) {
 #if __linux__
   /* utimesat() has nanosecond resolution but we stick to microseconds
@@ -507,30 +505,24 @@ static int _futime(const uv_file fd, double atime, double mtime) {
   ts[1].tv_sec = mtime;
   ts[1].tv_nsec = (unsigned long)(mtime * 1000000) % 1000000 * 1000;
   return uv__utimesat(fd, NULL, ts, 0);
-#else
+#elif HAVE_FUTIMES
   struct timeval tv[2];
   tv[0].tv_sec = atime;
   tv[0].tv_usec = (unsigned long)(atime * 1000000) % 1000000;
   tv[1].tv_sec = mtime;
   tv[1].tv_usec = (unsigned long)(mtime * 1000000) % 1000000;
   return futimes(fd, tv);
-#endif /* __linux__ */
+#else /* !HAVE_FUTIMES */
+  errno = ENOSYS;
+  return -1;
+#endif
 }
-#endif /* HAVE_FUTIMES */
 
 
 int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime,
     double mtime, uv_fs_cb cb) {
   const char* path = NULL;
-
-  uv_fs_req_init(loop, req, UV_FS_FUTIME, path, cb);
-
-#if HAVE_FUTIMES
   WRAP_EIO(UV_FS_FUTIME, eio_futime, _futime, ARGS3(file, atime, mtime))
-#else
-  uv__set_sys_error(loop, ENOSYS);
-  return -1;
-#endif
 }
 
 
@@ -552,7 +544,6 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
 
   if (cb) {
     /* async */
-    uv_ref(loop);
     req->eio = eio_lstat(pathdup, EIO_PRI_DEFAULT, uv__fs_after, req,  &loop->uv_eio_channel);
 
     free(pathdup);
@@ -602,7 +593,6 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
 
   if (cb) {
     if ((req->eio = eio_readlink(path, EIO_PRI_DEFAULT, uv__fs_after, req,  &loop->uv_eio_channel))) {
-      uv_ref(loop);
       return 0;
     } else {
       uv__set_sys_error(loop, ENOMEM);
@@ -674,7 +664,7 @@ static void uv__work(eio_req* eio) {
 
 static int uv__after_work(eio_req *eio) {
   uv_work_t* req = eio->data;
-  uv_unref(req->loop);
+  uv__req_unregister(req->loop, req);
   if (req->after_work_cb) {
     req->after_work_cb(req);
   }
@@ -689,13 +679,16 @@ int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb,
   uv_eio_init(loop);
 
   uv__req_init(loop, req, UV_WORK);
-  uv_ref(loop);
   req->loop = loop;
   req->data = data;
   req->work_cb = work_cb;
   req->after_work_cb = after_work_cb;
 
-  req->eio = eio_custom(uv__work, EIO_PRI_DEFAULT, uv__after_work, req,  &loop->uv_eio_channel);
+  req->eio = eio_custom(uv__work,
+                        EIO_PRI_DEFAULT,
+                        uv__after_work,
+                        req,
+                        &loop->uv_eio_channel);
 
   if (!req->eio) {
     uv__set_sys_error(loop, ENOMEM);
index e8701a3..eca88f8 100644 (file)
 enum {
   UV_CLOSING       = 0x01,   /* uv_close() called but not finished. */
   UV_CLOSED        = 0x02,   /* close(2) finished. */
-  UV_READING       = 0x04,   /* uv_read_start() called. */
-  UV_SHUTTING      = 0x08,   /* uv_shutdown() called but not complete. */
-  UV_SHUT          = 0x10,   /* Write side closed. */
-  UV_READABLE      = 0x20,   /* The stream is readable */
-  UV_WRITABLE      = 0x40,   /* The stream is writable */
+  UV_STREAM_READING   = 0x04,   /* uv_read_start() called. */
+  UV_STREAM_SHUTTING  = 0x08,   /* uv_shutdown() called but not complete. */
+  UV_STREAM_SHUT      = 0x10,   /* Write side closed. */
+  UV_STREAM_READABLE  = 0x20,   /* The stream is readable */
+  UV_STREAM_WRITABLE  = 0x40,   /* The stream is writable */
   UV_TCP_NODELAY   = 0x080,  /* Disable Nagle. */
   UV_TCP_KEEPALIVE = 0x100,  /* Turn on keep-alive. */
-  UV_TIMER_ACTIVE  = 0x080,
-  UV_TIMER_REPEAT  = 0x100
+  UV_TIMER_REPEAT  = 0x100,
+  UV__PENDING      = 0x800
 };
 
+inline static int uv__has_pending_handles(const uv_loop_t* loop) {
+  return loop->pending_handles != NULL;
+}
+
+inline static void uv__make_pending(uv_handle_t* h) {
+  if (h->flags & UV__PENDING) return;
+  h->next_pending = h->loop->pending_handles;
+  h->loop->pending_handles = h;
+  h->flags |= UV__PENDING;
+}
+#define uv__make_pending(h) uv__make_pending((uv_handle_t*)(h))
+
 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;
+#ifndef UV_LEAN_AND_MEAN
+  ngx_queue_insert_tail(&loop->active_reqs, &req->active_queue);
+#else
+  loop->active_reqs++;
+#endif
 }
 #define uv__req_init(loop, req, type) \
   uv__req_init((loop), (uv_req_t*)(req), (type))
@@ -112,10 +129,14 @@ int uv__nonblock(int fd, int set) __attribute__((unused));
 int uv__cloexec(int fd, int set) __attribute__((unused));
 int uv__socket(int domain, int type, int protocol);
 int uv__dup(int fd);
+int uv_async_stop(uv_async_t* handle);
 
 /* loop */
 int uv__loop_init(uv_loop_t* loop, int default_loop);
 void uv__loop_delete(uv_loop_t* loop);
+void uv__run_idle(uv_loop_t* loop);
+void uv__run_check(uv_loop_t* loop);
+void uv__run_prepare(uv_loop_t* loop);
 
 /* error */
 uv_err_code uv_translate_sys_error(int sys_errno);
@@ -141,12 +162,11 @@ int uv__tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay);
 int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
 void uv__pipe_accept(EV_P_ ev_io* watcher, int revents);
 
-/* various */
-int uv__check_active(const uv_check_t* handle);
-int uv__idle_active(const uv_idle_t* handle);
-int uv__prepare_active(const uv_prepare_t* handle);
-int uv__timer_active(const uv_timer_t* handle);
+/* poll */
+void uv__poll_close(uv_poll_t* handle);
+int uv__poll_active(const uv_poll_t* handle);
 
+/* various */
 void uv__async_close(uv_async_t* handle);
 void uv__check_close(uv_check_t* handle);
 void uv__fs_event_close(uv_fs_event_t* handle);
@@ -159,6 +179,8 @@ void uv__timer_close(uv_timer_t* handle);
 void uv__udp_close(uv_udp_t* handle);
 void uv__udp_finish_close(uv_udp_t* handle);
 
+void uv__stream_pending(uv_stream_t* handle);
+
 #define UV__F_IPC        (1 << 0)
 #define UV__F_NONBLOCK   (1 << 1)
 int uv__make_socketpair(int fds[2], int flags);
index 4046323..ee1bbd1 100644 (file)
@@ -42,12 +42,10 @@ static void uv__fs_event_start(uv_fs_event_t* handle) {
              handle->fd,
              EV_LIBUV_KQUEUE_HACK);
   ev_io_start(handle->loop->ev, &handle->event_watcher);
-  ev_unref(handle->loop->ev);
 }
 
 
 static void uv__fs_event_stop(uv_fs_event_t* handle) {
-  ev_ref(handle->loop->ev);
   ev_io_stop(handle->loop->ev, &handle->event_watcher);
 }
 
@@ -104,6 +102,7 @@ int uv_fs_event_init(uv_loop_t* loop,
   }
 
   uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+  uv__handle_start(handle); /* FIXME shouldn't start automatically */
   handle->filename = strdup(filename);
   handle->fflags = 0;
   handle->cb = cb;
@@ -116,6 +115,7 @@ int uv_fs_event_init(uv_loop_t* loop,
 
 void uv__fs_event_close(uv_fs_event_t* handle) {
   uv__fs_event_stop(handle);
+  uv__handle_stop(handle);
   free(handle->filename);
   close(handle->fd);
   handle->fd = -1;
index 24ddbcb..564e47a 100644 (file)
@@ -90,7 +90,6 @@ static int init_inotify(uv_loop_t* loop) {
              loop->inotify_fd,
              EV_READ);
   ev_io_start(loop->ev, &loop->inotify_read_watcher);
-  ev_unref(loop->ev);
 
   return 0;
 }
@@ -193,6 +192,7 @@ int uv_fs_event_init(uv_loop_t* loop,
   if (wd == -1) return uv__set_sys_error(loop, errno);
 
   uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+  uv__handle_start(handle); /* FIXME shouldn't start automatically */
   handle->filename = strdup(filename);
   handle->cb = cb;
   handle->fd = wd;
@@ -209,4 +209,5 @@ void uv__fs_event_close(uv_fs_event_t* handle) {
 
   free(handle->filename);
   handle->filename = NULL;
+  uv__handle_stop(handle);
 }
index 5580aba..aca2a88 100644 (file)
@@ -33,15 +33,31 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
 #else
   int flags = EVFLAG_AUTO;
 #endif
+
+  memset(loop, 0, sizeof(*loop));
+
+#ifndef UV_LEAN_AND_MEAN
+  ngx_queue_init(&loop->active_handles);
+  ngx_queue_init(&loop->active_reqs);
+#endif
+
   RB_INIT(&loop->uv_ares_handles_);
-  loop->endgame_handles = NULL;
+  ngx_queue_init(&loop->idle_handles);
+  ngx_queue_init(&loop->check_handles);
+  ngx_queue_init(&loop->prepare_handles);
+  loop->pending_handles = NULL;
+  loop->channel = NULL;
   loop->ev = (default_loop ? ev_default_loop : ev_loop_new)(flags);
   ev_set_userdata(loop->ev, loop);
   eio_channel_init(&loop->uv_eio_channel, loop);
+
 #if __linux__
   RB_INIT(&loop->inotify_watchers);
   loop->inotify_fd = -1;
 #endif
+#if HAVE_PORTS_FS
+  loop->fs_fd = -1;
+#endif
   return 0;
 }
 
@@ -55,4 +71,45 @@ void uv__loop_delete(uv_loop_t* loop) {
   close(loop->inotify_fd);
   loop->inotify_fd = -1;
 #endif
+#if HAVE_PORTS_FS
+  if (loop->fs_fd != -1)
+    close(loop->fs_fd);
+#endif
 }
+
+
+#define X(name, type) \
+  int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) {              \
+    uv__handle_init(loop, (uv_handle_t*)handle, type);                        \
+    loop->counters.name##_init++;                                             \
+    handle->name##_cb = NULL;                                                 \
+    return 0;                                                                 \
+  }                                                                           \
+  int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) {           \
+    if (uv__is_active(handle)) return 0;                                      \
+    ngx_queue_insert_head(&handle->loop->name##_handles, &handle->queue);     \
+    handle->name##_cb = cb;                                                   \
+    uv__handle_start(handle);                                                 \
+    return 0;                                                                 \
+  }                                                                           \
+  int uv_##name##_stop(uv_##name##_t* handle) {                               \
+    if (!uv__is_active(handle)) return 0;                                     \
+    ngx_queue_remove(&handle->queue);                                         \
+    uv__handle_stop(handle);                                                  \
+    return 0;                                                                 \
+  }                                                                           \
+  void uv__run_##name(uv_loop_t* loop) {                                      \
+    uv_##name##_t* h;                                                         \
+    ngx_queue_t* q;                                                           \
+    ngx_queue_foreach(q, &loop->name##_handles) {                             \
+      h = ngx_queue_data(q, uv_##name##_t, queue);                            \
+      if (h->name##_cb) h->name##_cb(h, 0);                                   \
+    }                                                                         \
+  }                                                                           \
+  void uv__##name##_close(uv_##name##_t* handle) {                            \
+    uv_##name##_stop(handle);                                                 \
+  }
+X(idle, UV_IDLE)
+X(check, UV_CHECK)
+X(prepare, UV_PREPARE)
+#undef X
index 7d0b2ec..91afb08 100644 (file)
@@ -33,6 +33,8 @@
 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;
   handle->ipc = ipc;
   return 0;
@@ -163,7 +165,9 @@ void uv__pipe_close(uv_pipe_t* handle) {
 
 
 void uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
-  uv__stream_open((uv_stream_t*)handle, fd, UV_READABLE | UV_WRITABLE);
+  uv__stream_open((uv_stream_t*)handle,
+                  fd,
+                  UV_STREAM_READABLE | UV_STREAM_WRITABLE);
 }
 
 
@@ -204,24 +208,24 @@ void uv_pipe_connect(uv_connect_t* req,
     goto out;
   }
 
-  uv__stream_open((uv_stream_t*)handle, sockfd, UV_READABLE | UV_WRITABLE);
-
+  uv__stream_open((uv_stream_t*)handle,
+                  sockfd,
+                  UV_STREAM_READABLE | UV_STREAM_WRITABLE);
   ev_io_start(handle->loop->ev, &handle->read_watcher);
   ev_io_start(handle->loop->ev, &handle->write_watcher);
-
   status = 0;
 
 out:
   handle->delayed_error = status; /* Passed to callback. */
   handle->connect_req = req;
+
+  uv__req_init(handle->loop, req, UV_CONNECT);
   req->handle = (uv_stream_t*)handle;
-  req->type = UV_CONNECT;
   req->cb = cb;
   ngx_queue_init(&req->queue);
 
   /* Run callback on next tick. */
-  ev_feed_event(handle->loop->ev, &handle->read_watcher, EV_CUSTOM);
-  assert(ev_is_pending(&handle->read_watcher));
+  uv__make_pending(handle);
 
   /* Mimic the Windows pipe implementation, always
    * return 0 and let the callback handle errors.
diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c
new file mode 100644 (file)
index 0000000..45def2c
--- /dev/null
@@ -0,0 +1,123 @@
+/* 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 <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+
+static void uv__poll_io(EV_P_ ev_io* watcher, int ev_events) {
+  uv_poll_t* handle = watcher->data;
+  int events;
+
+  if (ev_events & EV_ERROR) {
+    /* An error happened. Libev has implicitly stopped the watcher, but we */
+    /* need to fix the refcount. */
+    uv__handle_stop(handle);
+    uv__set_sys_error(handle->loop, EBADF);
+    handle->poll_cb(handle, -1, 0);
+    return;
+  }
+
+  assert(ev_events & (EV_READ | EV_WRITE));
+  assert((ev_events & ~(EV_READ | EV_WRITE)) == 0);
+
+  events = 0;
+  if (ev_events & EV_READ)
+    events |= UV_READABLE;
+  if (ev_events & EV_WRITE)
+    events |= UV_WRITABLE;
+
+  handle->poll_cb(handle, 0, 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;
+
+  ev_init(&handle->io_watcher, uv__poll_io);
+  handle->io_watcher.data = handle;
+
+  return 0;
+}
+
+
+int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
+    uv_os_sock_t socket) {
+  return uv_poll_init(loop, handle, socket);
+}
+
+
+static void uv__poll_stop(uv_poll_t* handle) {
+  ev_io_stop(handle->loop->ev, &handle->io_watcher);
+  uv__handle_stop(handle);
+}
+
+
+int uv_poll_stop(uv_poll_t* handle) {
+  assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+  uv__poll_stop(handle);
+  return 0;
+}
+
+
+int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb poll_cb) {
+  int ev_events;
+
+  assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
+  assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+
+  if (events == 0) {
+    uv__poll_stop(handle);
+    return 0;
+  }
+
+  ev_events = 0;
+  if (events & UV_READABLE)
+    ev_events |= EV_READ;
+  if (events & UV_WRITABLE)
+    ev_events |= EV_WRITE;
+
+  ev_io_set(&handle->io_watcher, handle->fd, ev_events);
+  ev_io_start(handle->loop->ev, &handle->io_watcher);
+
+  handle->poll_cb = poll_cb;
+  uv__handle_start(handle);
+
+  return 0;
+}
+
+
+void uv__poll_close(uv_poll_t* handle) {
+  uv__poll_stop(handle);
+}
+
+
+int uv__poll_active(const uv_poll_t* handle) {
+  return ev_is_active(&handle->io_watcher);
+}
diff --git a/deps/uv/src/unix/prepare.c b/deps/uv/src/unix/prepare.c
deleted file mode 100644 (file)
index 6c18fbd..0000000
+++ /dev/null
@@ -1,79 +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.
- */
-
-#include "uv.h"
-#include "internal.h"
-
-
-static void uv__prepare(EV_P_ ev_prepare* w, int revents) {
-  uv_prepare_t* prepare = container_of(w, uv_prepare_t, prepare_watcher);
-
-  if (prepare->prepare_cb) {
-    prepare->prepare_cb(prepare, 0);
-  }
-}
-
-
-int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* prepare) {
-  uv__handle_init(loop, (uv_handle_t*)prepare, UV_PREPARE);
-  loop->counters.prepare_init++;
-
-  ev_prepare_init(&prepare->prepare_watcher, uv__prepare);
-  prepare->prepare_cb = NULL;
-
-  return 0;
-}
-
-
-int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb) {
-  int was_active = ev_is_active(&prepare->prepare_watcher);
-
-  prepare->prepare_cb = cb;
-
-  ev_prepare_start(prepare->loop->ev, &prepare->prepare_watcher);
-
-  if (!was_active) {
-    ev_unref(prepare->loop->ev);
-  }
-
-  return 0;
-}
-
-
-int uv_prepare_stop(uv_prepare_t* prepare) {
-  int was_active = ev_is_active(&prepare->prepare_watcher);
-
-  ev_prepare_stop(prepare->loop->ev, &prepare->prepare_watcher);
-
-  if (was_active) {
-    ev_ref(prepare->loop->ev);
-  }
-  return 0;
-}
-
-
-int uv__prepare_active(const uv_prepare_t* handle) {
-  return ev_is_active(&handle->prepare_watcher);
-}
-
-
-void uv__prepare_close(uv_prepare_t* handle) {
-  uv_prepare_stop(handle);
-}
index 10872cc..bccaf17 100644 (file)
@@ -25,7 +25,6 @@
 #include <assert.h>
 #include <errno.h>
 #include <sys/wait.h>
-#include <fcntl.h> /* O_CLOEXEC, O_NONBLOCK */
 #include <poll.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -108,10 +107,10 @@ int uv__make_pipe(int fds[2], int flags) {
 #if __linux__
   int fl;
 
-  fl = O_CLOEXEC;
+  fl = UV__O_CLOEXEC;
 
   if (flags & UV__F_NONBLOCK)
-    fl |= O_NONBLOCK;
+    fl |= UV__O_NONBLOCK;
 
   if (uv__pipe2(fds, fl) == 0)
     return 0;
@@ -182,6 +181,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
 
   uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
   loop->counters.process_init++;
+  uv__handle_start(process);
 
   process->exit_cb = options.exit_cb;
 
@@ -318,7 +318,8 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
     assert(stdin_pipe[0] >= 0);
     close(stdin_pipe[0]);
     uv__nonblock(stdin_pipe[1], 1);
-    flags = UV_WRITABLE | (options.stdin_stream->ipc ? UV_READABLE : 0);
+    flags = UV_STREAM_WRITABLE |
+            (options.stdin_stream->ipc ? UV_STREAM_READABLE : 0);
     uv__stream_open((uv_stream_t*)options.stdin_stream, stdin_pipe[1],
         flags);
   }
@@ -328,7 +329,8 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
     assert(stdout_pipe[1] >= 0);
     close(stdout_pipe[1]);
     uv__nonblock(stdout_pipe[0], 1);
-    flags = UV_READABLE | (options.stdout_stream->ipc ? UV_WRITABLE : 0);
+    flags = UV_STREAM_READABLE |
+            (options.stdout_stream->ipc ? UV_STREAM_WRITABLE : 0);
     uv__stream_open((uv_stream_t*)options.stdout_stream, stdout_pipe[0],
         flags);
   }
@@ -338,7 +340,8 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
     assert(stderr_pipe[1] >= 0);
     close(stderr_pipe[1]);
     uv__nonblock(stderr_pipe[0], 1);
-    flags = UV_READABLE | (options.stderr_stream->ipc ? UV_WRITABLE : 0);
+    flags = UV_STREAM_READABLE |
+            (options.stderr_stream->ipc ? UV_STREAM_WRITABLE : 0);
     uv__stream_open((uv_stream_t*)options.stderr_stream, stderr_pipe[0],
         flags);
   }
@@ -382,4 +385,5 @@ 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);
+  uv__handle_stop(handle);
 }
index b71f9bd..76e2581 100644 (file)
@@ -62,6 +62,7 @@ void uv__stream_init(uv_loop_t* loop,
   stream->close_cb = NULL;
   stream->connection_cb = NULL;
   stream->connect_req = NULL;
+  stream->shutdown_req = NULL;
   stream->accepted_fd = -1;
   stream->fd = -1;
   stream->delayed_error = 0;
@@ -128,11 +129,20 @@ void uv__stream_destroy(uv_stream_t* stream) {
 
   assert(stream->flags & UV_CLOSED);
 
+  if (stream->connect_req) {
+    uv__req_unregister(stream->loop, stream->connect_req);
+    uv__set_artificial_error(stream->loop, UV_EINTR);
+    stream->connect_req->cb(stream->connect_req, -1);
+    stream->connect_req = NULL;
+  }
+
   while (!ngx_queue_empty(&stream->write_queue)) {
     q = ngx_queue_head(&stream->write_queue);
     ngx_queue_remove(q);
 
     req = ngx_queue_data(q, uv_write_t, queue);
+    uv__req_unregister(stream->loop, req);
+
     if (req->bufs != req->bufsml)
       free(req->bufs);
 
@@ -147,18 +157,19 @@ void uv__stream_destroy(uv_stream_t* stream) {
     ngx_queue_remove(q);
 
     req = ngx_queue_data(q, uv_write_t, queue);
+    uv__req_unregister(stream->loop, req);
+
     if (req->cb) {
       uv__set_sys_error(stream->loop, req->error);
       req->cb(req, req->error ? -1 : 0);
     }
   }
 
-  if (stream->flags & UV_SHUTTING) {
-    uv_shutdown_t* req = stream->shutdown_req;
-    if (req && req->cb) {
-      uv__set_artificial_error(stream->loop, UV_EINTR);
-      req->cb(req, -1);
-    }
+  if (stream->shutdown_req) {
+    uv__req_unregister(stream->loop, stream->shutdown_req);
+    uv__set_artificial_error(stream->loop, UV_EINTR);
+    stream->shutdown_req->cb(stream->shutdown_req, -1);
+    stream->shutdown_req = NULL;
   }
 }
 
@@ -234,7 +245,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
   }
 
   if (uv__stream_open(streamClient, streamServer->accepted_fd,
-        UV_READABLE | UV_WRITABLE)) {
+        UV_STREAM_READABLE | UV_STREAM_WRITABLE)) {
     /* TODO handle error */
     close(streamServer->accepted_fd);
     streamServer->accepted_fd = -1;
@@ -252,15 +263,26 @@ out:
 
 
 int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
+  int r;
+
   switch (stream->type) {
     case UV_TCP:
-      return uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
+      r = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
+      break;
+
     case UV_NAMED_PIPE:
-      return uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
+      r = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
+      break;
+
     default:
       assert(0);
       return -1;
   }
+
+  if (r == 0)
+    uv__handle_start(stream);
+
+  return r;
 }
 
 
@@ -293,13 +315,14 @@ static void uv__drain(uv_stream_t* stream) {
   ev_io_stop(stream->loop->ev, &stream->write_watcher);
 
   /* Shutdown? */
-  if ((stream->flags & UV_SHUTTING) &&
+  if ((stream->flags & UV_STREAM_SHUTTING) &&
       !(stream->flags & UV_CLOSING) &&
-      !(stream->flags & UV_SHUT)) {
+      !(stream->flags & UV_STREAM_SHUT)) {
     assert(stream->shutdown_req);
 
     req = stream->shutdown_req;
     stream->shutdown_req = NULL;
+    uv__req_unregister(stream->loop, req);
 
     if (shutdown(stream->fd, SHUT_WR)) {
       /* Error. Report it. User should call uv_close(). */
@@ -309,7 +332,7 @@ static void uv__drain(uv_stream_t* stream) {
       }
     } else {
       uv__set_sys_error(stream->loop, 0);
-      ((uv_handle_t*) stream)->flags |= UV_SHUT;
+      ((uv_handle_t*) stream)->flags |= UV_STREAM_SHUT;
       if (req->cb) {
         req->cb(req, 0);
       }
@@ -499,24 +522,21 @@ start:
 
 
 static void uv__write_callbacks(uv_stream_t* stream) {
-  int callbacks_made = 0;
-  ngx_queue_t* q;
   uv_write_t* req;
+  ngx_queue_t* q;
 
   while (!ngx_queue_empty(&stream->write_completed_queue)) {
     /* Pop a req off write_completed_queue. */
     q = ngx_queue_head(&stream->write_completed_queue);
-    assert(q);
-    req = ngx_queue_data(q, struct uv_write_s, queue);
+    req = ngx_queue_data(q, uv_write_t, queue);
     ngx_queue_remove(q);
+    uv__req_unregister(stream->loop, req);
 
     /* NOTE: call callback AFTER freeing the request data. */
     if (req->cb) {
       uv__set_sys_error(stream->loop, req->error);
       req->cb(req, req->error ? -1 : 0);
     }
-
-    callbacks_made++;
   }
 
   assert(ngx_queue_empty(&stream->write_completed_queue));
@@ -558,11 +578,11 @@ static void uv__read(uv_stream_t* stream) {
   char cmsg_space[64];
   struct ev_loop* ev = stream->loop->ev;
 
-  /* XXX: Maybe instead of having UV_READING we just test if
+  /* XXX: Maybe instead of having UV_STREAM_READING we just test if
    * tcp->read_cb is NULL or not?
    */
   while ((stream->read_cb || stream->read2_cb) &&
-         stream->flags & UV_READING) {
+         stream->flags & UV_STREAM_READING) {
     assert(stream->alloc_cb);
     buf = stream->alloc_cb((uv_handle_t*)stream, 64 * 1024);
 
@@ -598,7 +618,7 @@ static void uv__read(uv_stream_t* stream) {
       /* Error */
       if (errno == EAGAIN || errno == EWOULDBLOCK) {
         /* Wait for the next one. */
-        if (stream->flags & UV_READING) {
+        if (stream->flags & UV_STREAM_READING) {
           ev_io_start(ev, &stream->read_watcher);
         }
         uv__set_sys_error(stream->loop, EAGAIN);
@@ -628,6 +648,8 @@ static void uv__read(uv_stream_t* stream) {
       /* EOF */
       uv__set_artificial_error(stream->loop, UV_EOF);
       ev_io_stop(ev, &stream->read_watcher);
+      if (!ev_is_active(&stream->write_watcher))
+        uv__handle_stop(stream);
 
       if (stream->read_cb) {
         stream->read_cb(stream, -1, buf);
@@ -691,8 +713,8 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
          "uv_shutdown (unix) only supports uv_handle_t right now");
   assert(stream->fd >= 0);
 
-  if (!(stream->flags & UV_WRITABLE) ||
-      stream->flags & UV_SHUT ||
+  if (!(stream->flags & UV_STREAM_WRITABLE) ||
+      stream->flags & UV_STREAM_SHUT ||
       stream->flags & UV_CLOSED ||
       stream->flags & UV_CLOSING) {
     uv__set_sys_error(stream->loop, EINVAL);
@@ -704,9 +726,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
   req->handle = stream;
   req->cb = cb;
   stream->shutdown_req = req;
-
-  ((uv_handle_t*)stream)->flags |= UV_SHUTTING;
-
+  stream->flags |= UV_STREAM_SHUTTING;
 
   ev_io_start(stream->loop->ev, &stream->write_watcher);
 
@@ -714,6 +734,11 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
 }
 
 
+void uv__stream_pending(uv_stream_t* handle) {
+  uv__stream_io(handle->loop->ev, &handle->write_watcher, EV_WRITE);
+}
+
+
 void uv__stream_io(EV_P_ ev_io* watcher, int revents) {
   uv_stream_t* stream = watcher->data;
 
@@ -767,32 +792,24 @@ static void uv__stream_connect(uv_stream_t* stream) {
     getsockopt(stream->fd, SOL_SOCKET, SO_ERROR, &error, &errorsize);
   }
 
-  if (!error) {
+  if (error == EINPROGRESS)
+    return;
+
+  if (error == 0)
     ev_io_start(stream->loop->ev, &stream->read_watcher);
 
-    /* Successful connection */
-    stream->connect_req = NULL;
-    if (req->cb) {
-      req->cb(req, 0);
-    }
+  stream->connect_req = NULL;
+  uv__req_unregister(stream->loop, req);
 
-  } else if (error == EINPROGRESS) {
-    /* Still connecting. */
-    return;
-  } else {
-    /* Error */
+  if (req->cb) {
     uv__set_sys_error(stream->loop, error);
-
-    stream->connect_req = NULL;
-    if (req->cb) {
-      req->cb(req, -1);
-    }
+    req->cb(req, error ? -1 : 0);
   }
 }
 
 
 int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr,
-    socklen_t addrlen, uv_connect_cb cb) { 
+    socklen_t addrlen, uv_connect_cb cb) {
   int sockfd;
   int r;
 
@@ -802,7 +819,9 @@ int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr,
       return -1;
     }
 
-    if (uv__stream_open(stream, sockfd, UV_READABLE | UV_WRITABLE)) {
+    if (uv__stream_open(stream,
+                        sockfd,
+                        UV_STREAM_READABLE | UV_STREAM_WRITABLE)) {
       close(sockfd);
       return -2;
     }
@@ -853,9 +872,8 @@ int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr,
   assert(stream->write_watcher.data == stream);
   ev_io_start(stream->loop->ev, &stream->write_watcher);
 
-  if (stream->delayed_error) {
-    ev_feed_event(stream->loop->ev, &stream->write_watcher, EV_WRITE);
-  }
+  if (stream->delayed_error)
+    uv__make_pending(stream);
 
   return 0;
 }
@@ -956,10 +974,10 @@ int uv__read_start_common(uv_stream_t* stream, uv_alloc_cb alloc_cb,
     return -1;
   }
 
-  /* The UV_READING flag is irrelevant of the state of the tcp - it just
+  /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just
    * expresses the desired state of the user.
    */
-  ((uv_handle_t*)stream)->flags |= UV_READING;
+  stream->flags |= UV_STREAM_READING;
 
   /* TODO: try to do the read inline? */
   /* TODO: keep track of tcp state. If we've gotten a EOF then we should
@@ -976,6 +994,8 @@ int uv__read_start_common(uv_stream_t* stream, uv_alloc_cb alloc_cb,
   assert(stream->read_watcher.cb == uv__stream_io);
 
   ev_io_start(stream->loop->ev, &stream->read_watcher);
+  uv__handle_start(stream);
+
   return 0;
 }
 
@@ -994,7 +1014,8 @@ int uv_read2_start(uv_stream_t* stream, uv_alloc_cb alloc_cb,
 
 int uv_read_stop(uv_stream_t* stream) {
   ev_io_stop(stream->loop->ev, &stream->read_watcher);
-  stream->flags &= ~UV_READING;
+  uv__handle_stop(stream);
+  stream->flags &= ~UV_STREAM_READING;
   stream->read_cb = NULL;
   stream->read2_cb = NULL;
   stream->alloc_cb = NULL;
@@ -1003,12 +1024,12 @@ int uv_read_stop(uv_stream_t* stream) {
 
 
 int uv_is_readable(const uv_stream_t* stream) {
-  return stream->flags & UV_READABLE;
+  return stream->flags & UV_STREAM_READABLE;
 }
 
 
 int uv_is_writable(const uv_stream_t* stream) {
-  return stream->flags & UV_WRITABLE;
+  return stream->flags & UV_STREAM_WRITABLE;
 }
 
 
index 0057e68..f341297 100644 (file)
 #if HAVE_PORTS_FS
 # include <sys/port.h>
 # include <port.h>
+
+# define PORT_FIRED 0x69
+# define PORT_UNUSED 0x0
+# define PORT_LOADED 0x99
+# define PORT_DELETED -1
 #endif
 
 #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
@@ -109,36 +114,41 @@ void uv_loadavg(double avg[3]) {
 
 #if HAVE_PORTS_FS
 static void uv__fs_event_rearm(uv_fs_event_t *handle) {
-  if (port_associate(handle->fd,
+  if (handle->fd == -1)
+    return;
+
+  if (port_associate(handle->loop->fs_fd,
                      PORT_SOURCE_FILE,
                      (uintptr_t) &handle->fo,
                      FILE_ATTRIB | FILE_MODIFIED,
-                     NULL) == -1) {
+                     handle) == -1) {
     uv__set_sys_error(handle->loop, errno);
   }
+  handle->fd = PORT_LOADED;
 }
 
 
 static void uv__fs_event_read(EV_P_ ev_io* w, int revents) {
   uv_fs_event_t *handle;
+  uv_loop_t *loop_;
   timespec_t timeout;
   port_event_t pe;
   int events;
   int r;
 
-  handle = container_of(w, uv_fs_event_t, event_watcher);
+  loop_ = container_of(w, uv_loop_t, fs_event_watcher);
 
   do {
     /* TODO use port_getn() */
     do {
       memset(&timeout, 0, sizeof timeout);
-      r = port_get(handle->fd, &pe, &timeout);
+      r = port_get(loop_->fs_fd, &pe, &timeout);
     }
     while (r == -1 && errno == EINTR);
 
     if (r == -1 && errno == ETIME)
       break;
-
+    handle = (uv_fs_event_t *)pe.portev_user;
     assert((r == 0) && "unexpected port_get() error");
 
     events = 0;
@@ -147,12 +157,12 @@ static void uv__fs_event_read(EV_P_ ev_io* w, int revents) {
     if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED))
       events |= UV_RENAME;
     assert(events != 0);
-
+    handle->fd = PORT_FIRED;
     handle->cb(handle, NULL, events, 0);
   }
-  while (handle->fd != -1);
+  while (handle->fd != PORT_DELETED);
 
-  if (handle->fd != -1)
+  if (handle->fd != PORT_DELETED)
     uv__fs_event_rearm(handle);
 }
 
@@ -163,39 +173,45 @@ int uv_fs_event_init(uv_loop_t* loop,
                      uv_fs_event_cb cb,
                      int flags) {
   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) {
   if ((portfd = port_create()) == -1) {
     uv__set_sys_error(loop, errno);
     return -1;
   }
+    loop->fs_fd = portfd;
+    first_run = 1;
+  }
 
   uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+  uv__handle_start(handle); /* FIXME shouldn't start automatically */
   handle->filename = strdup(filename);
-  handle->fd = portfd;
+  handle->fd = PORT_UNUSED;
   handle->cb = cb;
 
   memset(&handle->fo, 0, sizeof handle->fo);
   handle->fo.fo_name = handle->filename;
   uv__fs_event_rearm(handle);
 
-  ev_io_init(&handle->event_watcher, uv__fs_event_read, portfd, EV_READ);
-  ev_io_start(loop->ev, &handle->event_watcher);
-  ev_unref(loop->ev);
+  if (first_run) {
+    ev_io_init(&loop->fs_event_watcher, uv__fs_event_read, portfd, EV_READ);
+    ev_io_start(loop->ev, &loop->fs_event_watcher);
+  }
 
   return 0;
 }
 
 
 void uv__fs_event_close(uv_fs_event_t* handle) {
-  ev_ref(handle->loop->ev);
-  ev_io_stop(handle->loop->ev, &handle->event_watcher);
-  close(handle->fd);
-  handle->fd = -1;
+  if (handle->fd == PORT_FIRED) {
+    port_dissociate(handle->loop->fs_fd, PORT_SOURCE_FILE, (uintptr_t)&handle->fo);
+  }
+  handle->fd = PORT_DELETED;
   free(handle->filename);
   handle->filename = NULL;
   handle->fo.fo_name = NULL;
index be03847..a28db55 100644 (file)
@@ -50,7 +50,9 @@ static int uv__bind(uv_tcp_t* tcp,
       goto out;
     }
 
-    if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_READABLE | UV_WRITABLE)) {
+    if (uv__stream_open((uv_stream_t*)tcp,
+                        tcp->fd,
+                        UV_STREAM_READABLE | UV_STREAM_WRITABLE)) {
       close(tcp->fd);
       tcp->fd = -1;
       status = -2;
@@ -181,7 +183,7 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
       return -1;
     }
 
-    if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_READABLE)) {
+    if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_STREAM_READABLE)) {
       close(tcp->fd);
       tcp->fd = -1;
       return -1;
index 6a00229..8463088 100644 (file)
@@ -31,16 +31,14 @@ static int uv__timer_repeating(const uv_timer_t* timer) {
 static void uv__timer_cb(EV_P_ ev_timer* w, int revents) {
   uv_timer_t* timer = container_of(w, uv_timer_t, timer_watcher);
 
-  assert(uv__timer_active(timer));
+  if (!uv__is_active(timer))
+    return;
 
-  if (!uv__timer_repeating(timer)) {
-    timer->flags &= ~UV_TIMER_ACTIVE;
-    ev_ref(EV_A);
-  }
+  if (!uv__timer_repeating(timer))
+    uv__handle_stop(timer);
 
-  if (timer->timer_cb) {
+  if (timer->timer_cb)
     timer->timer_cb(timer, 0);
-  }
 }
 
 
@@ -56,12 +54,11 @@ int uv_timer_init(uv_loop_t* loop, uv_timer_t* timer) {
 
 int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout,
     int64_t repeat) {
-  if (uv__timer_active(timer)) {
+  if (uv__is_active(timer)) {
     return -1;
   }
 
   timer->timer_cb = cb;
-  timer->flags |= UV_TIMER_ACTIVE;
 
   if (repeat)
     timer->flags |= UV_TIMER_REPEAT;
@@ -70,26 +67,22 @@ int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout,
 
   ev_timer_set(&timer->timer_watcher, timeout / 1000.0, repeat / 1000.0);
   ev_timer_start(timer->loop->ev, &timer->timer_watcher);
-  ev_unref(timer->loop->ev);
+  uv__handle_start(timer);
 
   return 0;
 }
 
 
 int uv_timer_stop(uv_timer_t* timer) {
-  if (uv__timer_active(timer)) {
-    ev_ref(timer->loop->ev);
-  }
-
-  timer->flags &= ~(UV_TIMER_ACTIVE | UV_TIMER_REPEAT);
+  timer->flags &= ~UV_TIMER_REPEAT;
   ev_timer_stop(timer->loop->ev, &timer->timer_watcher);
-
+  uv__handle_stop(timer);
   return 0;
 }
 
 
 int uv_timer_again(uv_timer_t* timer) {
-  if (!uv__timer_active(timer)) {
+  if (!uv__is_active(timer)) {
     uv__set_artificial_error(timer->loop, UV_EINVAL);
     return -1;
   }
@@ -117,11 +110,6 @@ int64_t uv_timer_get_repeat(uv_timer_t* timer) {
 }
 
 
-int uv__timer_active(const uv_timer_t* timer) {
-  return timer->flags & UV_TIMER_ACTIVE;
-}
-
-
 void uv__timer_close(uv_timer_t* handle) {
   uv_timer_stop(handle);
 }
index c142966..572d19c 100644 (file)
@@ -38,10 +38,10 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
 
   if (readable) {
     uv__nonblock(fd, 1);
-    uv__stream_open((uv_stream_t*)tty, fd, UV_READABLE);
+    uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_READABLE);
   } else {
     /* Note: writable tty we set to blocking mode. */
-    uv__stream_open((uv_stream_t*)tty, fd, UV_WRITABLE);
+    uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_WRITABLE);
     tty->blocking = 1;
   }
 
index 105bdc0..c67dcc2 100644 (file)
@@ -46,16 +46,20 @@ static void uv__udp_start_watcher(uv_udp_t* handle,
   ev_set_cb(w, cb);
   ev_io_set(w, handle->fd, flags);
   ev_io_start(handle->loop->ev, w);
-  ev_unref(handle->loop->ev);
+  uv__handle_start(handle);
 }
 
 
 static void uv__udp_stop_watcher(uv_udp_t* handle, ev_io* w) {
   if (!ev_is_active(w)) return;
-  ev_ref(handle->loop->ev);
   ev_io_stop(handle->loop->ev, w);
   ev_io_set(w, -1, 0);
   ev_set_cb(w, NULL);
+
+  if (!ev_is_active(&handle->read_watcher) &&
+      !ev_is_active(&handle->write_watcher)) {
+    uv__handle_stop(handle);
+  }
 }
 
 
@@ -108,6 +112,8 @@ void uv__udp_finish_close(uv_udp_t* handle) {
     ngx_queue_remove(q);
 
     req = ngx_queue_data(q, uv_udp_send_t, queue);
+    uv__req_unregister(handle->loop, req);
+
     if (req->send_cb) {
       /* FIXME proper error code like UV_EABORTED */
       uv__set_artificial_error(handle->loop, UV_EINTR);
@@ -185,12 +191,10 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
 
   while (!ngx_queue_empty(&handle->write_completed_queue)) {
     q = ngx_queue_head(&handle->write_completed_queue);
-    assert(q != NULL);
-
     ngx_queue_remove(q);
 
     req = ngx_queue_data(q, uv_udp_send_t, queue);
-    assert(req != NULL);
+    uv__req_unregister(handle->loop, req);
 
     if (req->bufs != req->bufsml)
       free(req->bufs);
index 517d119..b36eea3 100644 (file)
 #include <stdio.h>
 
 
-static void uv_eio_do_poll(uv_idle_t* watcher, int status) {
-  assert(watcher == &(watcher->loop->uv_eio_poller));
+static uv_once_t uv__eio_init_once_guard = UV_ONCE_INIT;
 
-  /* printf("uv_eio_poller\n"); */
 
-  if (eio_poll(&watcher->loop->uv_eio_channel) != -1 && uv_is_active((uv_handle_t*) watcher)) {
-    /* printf("uv_eio_poller stop\n"); */
+static void uv_eio_do_poll(uv_idle_t* watcher, int status) {
+  uv_loop_t* loop = watcher->loop;
+  assert(watcher == &loop->uv_eio_poller);
+  if (eio_poll(&loop->uv_eio_channel) != -1)
     uv_idle_stop(watcher);
-    uv_unref(watcher->loop);
-  }
 }
 
 
 /* Called from the main thread. */
 static void uv_eio_want_poll_notifier_cb(uv_async_t* watcher, int status) {
   uv_loop_t* loop = watcher->loop;
-
   assert(watcher == &loop->uv_eio_want_poll_notifier);
-
-  /* printf("want poll notifier\n"); */
-
-  if (eio_poll(&watcher->loop->uv_eio_channel) == -1 && !uv_is_active((uv_handle_t*) &loop->uv_eio_poller)) {
-    /* printf("uv_eio_poller start\n"); */
+  if (eio_poll(&loop->uv_eio_channel) == -1)
     uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll);
-    uv_ref(loop);
-  }
 }
 
 
 static void uv_eio_done_poll_notifier_cb(uv_async_t* watcher, int revents) {
   uv_loop_t* loop = watcher->loop;
-
   assert(watcher == &loop->uv_eio_done_poll_notifier);
-
-  /* printf("done poll notifier\n"); */
-
-  if (eio_poll(&watcher->loop->uv_eio_channel) != -1 && uv_is_active((uv_handle_t*) &loop->uv_eio_poller)) {
-    /* printf("uv_eio_poller stop\n"); */
+  if (eio_poll(&loop->uv_eio_channel) != -1)
     uv_idle_stop(&loop->uv_eio_poller);
-    uv_unref(loop);
-  }
 }
 
 
@@ -77,13 +61,8 @@ static void uv_eio_done_poll_notifier_cb(uv_async_t* watcher, int revents) {
  */
 static void uv_eio_want_poll(eio_channel *channel) {
   /* Signal the main thread that eio_poll need to be processed. */
-
-  /*
-   * TODO need to select the correct uv_loop_t and async_send to
-   * uv_eio_want_poll_notifier.
-   */
-
-  uv_async_send(&((uv_loop_t *)channel->data)->uv_eio_want_poll_notifier);
+  uv_loop_t* loop = channel->data;
+  uv_async_send(&loop->uv_eio_want_poll_notifier);
 }
 
 
@@ -92,7 +71,8 @@ static void uv_eio_done_poll(eio_channel *channel) {
    * Signal the main thread that we should stop calling eio_poll().
    * from the idle watcher.
    */
-  uv_async_send(&((uv_loop_t *)channel->data)->uv_eio_done_poll_notifier);
+  uv_loop_t* loop = channel->data;
+  uv_async_send(&loop->uv_eio_done_poll_notifier);
 }
 
 
@@ -100,25 +80,20 @@ static void uv__eio_init(void) {
   eio_init(uv_eio_want_poll, uv_eio_done_poll);
 }
 
-static uv_once_t uv__eio_init_once_guard = UV_ONCE_INIT;
-
 
 void uv_eio_init(uv_loop_t* loop) {
-  if (loop->counters.eio_init == 0) {
-    loop->counters.eio_init++;
+  if (loop->counters.eio_init) return;
+  loop->counters.eio_init = 1;
 
-    uv_idle_init(loop, &loop->uv_eio_poller);
-    uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll);
+  uv_idle_init(loop, &loop->uv_eio_poller);
+  uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll);
 
-    loop->uv_eio_want_poll_notifier.data = loop;
-    uv_async_init(loop, &loop->uv_eio_want_poll_notifier,
-        uv_eio_want_poll_notifier_cb);
-    uv_unref(loop);
+  loop->uv_eio_want_poll_notifier.data = loop;
+  uv_async_init(loop, &loop->uv_eio_want_poll_notifier,
+      uv_eio_want_poll_notifier_cb);
 
-    uv_async_init(loop, &loop->uv_eio_done_poll_notifier,
-        uv_eio_done_poll_notifier_cb);
-    uv_unref(loop);
+  uv_async_init(loop, &loop->uv_eio_done_poll_notifier,
+      uv_eio_done_poll_notifier_cb);
 
-    uv_once(&uv__eio_init_once_guard, uv__eio_init);
-  }
+  uv_once(&uv__eio_init_once_guard, uv__eio_init);
 }
index c8192bd..08aaebf 100644 (file)
@@ -352,3 +352,13 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
 
   return 0;
 }
+
+
+void uv_ref(uv_handle_t* handle) {
+  uv__handle_ref(handle);
+}
+
+
+void uv_unref(uv_handle_t* handle) {
+  uv__handle_unref(handle);
+}
index e82f584..efc0760 100644 (file)
 #ifndef UV_COMMON_H_
 #define UV_COMMON_H_
 
+#include <assert.h>
+
 #include "uv.h"
 #include "tree.h"
 
+
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
+#ifdef _MSC_VER
+# define UNUSED /* empty */
+#else
+# define UNUSED __attribute__((unused))
+#endif
+
+
+#ifndef _WIN32
+enum {
+  UV__ACTIVE       = 0x4000,
+  UV__REF          = 0x8000
+};
+#else
+# define UV__REF     0x00000020
+# define UV__ACTIVE  0x00000040
+#endif
 
 struct uv_ares_task_s {
   UV_HANDLE_FIELDS
@@ -83,5 +102,105 @@ int uv__tcp_connect6(uv_connect_t* req,
                     struct sockaddr_in6 address,
                     uv_connect_cb cb);
 
+#ifndef UV_LEAN_AND_MEAN
+
+UNUSED static int uv__has_active_handles(const uv_loop_t* loop) {
+  return !ngx_queue_empty(&loop->active_handles);
+}
+
+UNUSED static int uv__has_active_reqs(const uv_loop_t* loop) {
+  return !ngx_queue_empty(&loop->active_reqs);
+}
+
+UNUSED static void uv__active_handle_add(uv_handle_t* h) {
+  ngx_queue_insert_tail(&h->loop->active_handles, &h->active_queue);
+}
+
+UNUSED static void uv__active_handle_rm(uv_handle_t* h) {
+  assert(uv__has_active_handles(h->loop));
+  ngx_queue_remove(&h->active_queue);
+}
+
+UNUSED static void uv__req_register(uv_loop_t* loop, uv_req_t* req) {
+  ngx_queue_insert_tail(&loop->active_reqs, &req->active_queue);
+}
+
+UNUSED static void uv__req_unregister(uv_loop_t* loop, uv_req_t* req) {
+  assert(uv__has_active_reqs(loop));
+  ngx_queue_remove(&req->active_queue);
+}
+
+#else /* UV_LEAN_AND_MEAN */
+
+UNUSED static int uv__has_active_handles(const uv_loop_t* loop) {
+  return loop->active_handles > 0;
+}
+
+UNUSED static int uv__has_active_reqs(const uv_loop_t* loop) {
+  return loop->active_reqs > 0;
+}
+
+UNUSED static void uv__active_handle_add(uv_handle_t* h) {
+  h->loop->active_handles++;
+}
+
+UNUSED static void uv__active_handle_rm(uv_handle_t* h) {
+  assert(h->loop->active_handles > 0);
+  h->loop->active_handles--;
+}
+
+UNUSED static void uv__req_register(uv_loop_t* loop, uv_req_t* req) {
+  loop->active_reqs++;
+  (void) req;
+}
+
+UNUSED static void uv__req_unregister(uv_loop_t* loop, uv_req_t* req) {
+  assert(loop->active_reqs > 0);
+  loop->active_reqs--;
+  (void) req;
+}
+
+#endif /* UV_LEAN_AND_MEAN */
+
+#define uv__active_handle_add(h) uv__active_handle_add((uv_handle_t*)(h))
+#define uv__active_handle_rm(h) uv__active_handle_rm((uv_handle_t*)(h))
+
+#define uv__req_register(loop, req) uv__req_register((loop), (uv_req_t*)(req))
+#define uv__req_unregister(loop, req) uv__req_unregister((loop), (uv_req_t*)(req))
+
+UNUSED static int uv__is_active(const uv_handle_t* h) {
+  return !!(h->flags & UV__ACTIVE);
+}
+#define uv__is_active(h) uv__is_active((const uv_handle_t*)(h))
+
+UNUSED static void uv__handle_start(uv_handle_t* h) {
+  if (h->flags & UV__ACTIVE) return;
+  if (!(h->flags & UV__REF)) return;
+  h->flags |= UV__ACTIVE;
+  uv__active_handle_add(h);
+}
+#define uv__handle_start(h) uv__handle_start((uv_handle_t*)(h))
+
+UNUSED static void uv__handle_stop(uv_handle_t* h) {
+  if (!(h->flags & UV__ACTIVE)) return;
+  if (!(h->flags & UV__REF)) return;
+  uv__active_handle_rm(h);
+  h->flags &= ~UV__ACTIVE;
+}
+#define uv__handle_stop(h) uv__handle_stop((uv_handle_t*)(h))
+
+UNUSED static void uv__handle_ref(uv_handle_t* h) {
+  if (h->flags & UV__REF) return;
+  if (h->flags & UV__ACTIVE) uv__active_handle_add(h);
+  h->flags |= UV__REF;
+}
+#define uv__handle_ref(h) uv__handle_ref((uv_handle_t*)(h))
+
+UNUSED static void uv__handle_unref(uv_handle_t* h) {
+  if (!(h->flags & UV__REF)) return;
+  if (h->flags & UV__ACTIVE) uv__active_handle_rm(h);
+  h->flags &= ~UV__REF;
+}
+#define uv__handle_unref(h) uv__handle_unref((uv_handle_t*)(h))
 
 #endif /* UV_COMMON_H_ */
index b68a868..9df75e0 100644 (file)
@@ -59,12 +59,11 @@ void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
       !handle->async_sent) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     handle->flags |= UV_HANDLE_CLOSED;
+    uv__handle_stop(handle);
 
     if (handle->close_cb) {
       handle->close_cb((uv_handle_t*)handle);
     }
-
-    uv_unref(loop);
   }
 }
 
@@ -72,12 +71,8 @@ void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
 int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
   uv_req_t* req;
 
-  loop->counters.handle_init++;
-  loop->counters.async_init++;
-
+  uv_handle_init(loop, (uv_handle_t*) handle);
   handle->type = UV_ASYNC;
-  handle->loop = loop;
-  handle->flags = 0;
   handle->async_sent = 0;
   handle->async_cb = async_cb;
 
@@ -86,12 +81,23 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
   req->type = UV_WAKEUP;
   req->data = handle;
 
-  uv_ref(loop);
+  loop->counters.async_init++;
+
+  uv__handle_start(handle);
 
   return 0;
 }
 
 
+void uv_async_close(uv_loop_t* loop, uv_async_t* handle) {
+  if (!((uv_async_t*)handle)->async_sent) {
+    uv_want_endgame(loop, (uv_handle_t*) handle);
+  }
+
+  uv__handle_start(handle);
+}
+
+
 int uv_async_send(uv_async_t* handle) {
   uv_loop_t* loop = handle->loop;
 
index 1592d12..359bc21 100644 (file)
@@ -22,7 +22,6 @@
 #include <assert.h>
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
 
@@ -108,8 +107,6 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read,
   uv_loop_t* loop = (uv_loop_t*) data;
   uv_ares_task_t* uv_handle_ares = uv_find_ares_handle(loop, sock);
 
-  int timeoutms = 0;
-
   if (read == 0 && write == 0) {
     /* if read and write are 0, cleanup existing data */
     /* The code assumes that c-ares does a callback with read = 0 and */
@@ -134,6 +131,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read,
       }
       /* remove handle from list */
       uv_remove_ares_handle(uv_handle_ares);
+      uv__handle_stop(uv_handle_ares);
 
       /* Post request to cleanup the Task */
       uv_ares_req = &uv_handle_ares->ares_req;
@@ -180,7 +178,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read,
 
       /* add handle to list */
       uv_add_ares_handle(loop, uv_handle_ares);
-      uv_ref(loop);
+      uv__handle_start(uv_handle_ares);
 
       /*
        * we have a single polling timer for all ares sockets.
@@ -231,7 +229,7 @@ void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle,
   unsigned int signaled = WaitForSingleObject(handle->h_close_event, 0);
 
   if (signaled != WAIT_TIMEOUT) {
-    uv_unref(loop);
+    uv__handle_stop(loop);
 
     /* close event handle and free uv handle memory */
     CloseHandle(handle->h_close_event);
index 1358cb2..27f3438 100644 (file)
@@ -27,7 +27,6 @@
 #include <string.h>
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
 
@@ -65,10 +64,16 @@ static void uv_loop_init(uv_loop_t* loop) {
     uv_fatal_error(GetLastError(), "CreateIoCompletionPort");
   }
 
-  loop->refs = 0;
-
   uv_update_time(loop);
 
+#ifndef UV_LEAN_AND_MEAN
+  ngx_queue_init(&loop->active_handles);
+  ngx_queue_init(&loop->active_reqs);
+#else
+  loop->active_handles = 0;
+  loop->active_reqs = 0;
+#endif
+
   loop->pending_reqs_tail = NULL;
 
   loop->endgame_handles = NULL;
@@ -84,6 +89,8 @@ static void uv_loop_init(uv_loop_t* loop) {
   loop->next_check_handle = NULL;
   loop->next_idle_handle = NULL;
 
+  memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
+
   loop->ares_active_sockets = 0;
   loop->ares_chan = NULL;
 
@@ -130,26 +137,19 @@ uv_loop_t* uv_loop_new(void) {
 
 void uv_loop_delete(uv_loop_t* loop) {
   if (loop != &uv_default_loop_) {
+    int i;
+    for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
+      SOCKET sock = loop->poll_peer_sockets[i];
+      if (sock != 0 && sock != INVALID_SOCKET) {
+        closesocket(sock);
+      }
+    }
+
     free(loop);
   }
 }
 
 
-int uv_loop_refcount(const uv_loop_t* loop) {
-  return loop->refs;
-}
-
-
-void uv_ref(uv_loop_t* loop) {
-  loop->refs++;
-}
-
-
-void uv_unref(uv_loop_t* loop) {
-  loop->refs--;
-}
-
-
 static void uv_poll(uv_loop_t* loop, int block) {
   BOOL success;
   DWORD bytes, timeout;
@@ -216,6 +216,19 @@ static void uv_poll_ex(uv_loop_t* loop, int block) {
   }
 }
 
+#ifndef UV_LEAN_AND_MEAN
+# define UV_LOOP_ALIVE(loop)                                                  \
+      (!ngx_queue_empty(&(loop)->active_handles) ||                           \
+       !ngx_queue_empty(&(loop)->active_reqs) ||                              \
+       (loop)->endgame_handles != NULL)
+#else
+# define UV_LOOP_ALIVE(loop)                                                  \
+      ((loop)->active_handles > 0 &&                                          \
+       (loop)->active_reqs > 0 &&                                             \
+       (loop)->endgame_handles != NULL)
+#endif
+
+
 #define UV_LOOP_ONCE(loop, poll)                                              \
   do {                                                                        \
     uv_update_time((loop));                                                   \
@@ -230,7 +243,7 @@ static void uv_poll_ex(uv_loop_t* loop, int block) {
     uv_process_reqs((loop));                                                  \
     uv_process_endgames((loop));                                              \
                                                                               \
-    if ((loop)->refs <= 0) {                                                  \
+    if (!UV_LOOP_ALIVE((loop))) {                                             \
       break;                                                                  \
     }                                                                         \
                                                                               \
@@ -239,13 +252,13 @@ static void uv_poll_ex(uv_loop_t* loop, int block) {
     poll((loop), (loop)->idle_handles == NULL &&                              \
                  (loop)->pending_reqs_tail == NULL &&                         \
                  (loop)->endgame_handles == NULL &&                           \
-                 (loop)->refs > 0);                                           \
+                 UV_LOOP_ALIVE((loop)));                                      \
                                                                               \
     uv_check_invoke((loop));                                                  \
   } while (0);
 
 #define UV_LOOP(loop, poll)                                                   \
-  while ((loop)->refs > 0) {                                                  \
+  while (UV_LOOP_ALIVE((loop))) {                                             \
     UV_LOOP_ONCE(loop, poll)                                                  \
   }
 
@@ -267,6 +280,6 @@ int uv_run(uv_loop_t* loop) {
     UV_LOOP(loop, uv_poll);
   }
 
-  assert(loop->refs == 0);
+  assert(!UV_LOOP_ALIVE((loop)));
   return 0;
 }
index 08374d3..88ddd74 100644 (file)
 #include "uv.h"
 #include "internal.h"
 
-__declspec( thread ) DWORD saved_errno = 0;
+static int uv__dlerror(uv_lib_t* lib, int errorno);
 
-uv_err_t uv_dlopen(const char* filename, uv_lib_t* library) {
+
+int uv_dlopen(const char* filename, uv_lib_t* lib) {
   wchar_t filename_w[32768];
-  HMODULE handle;
 
-  if (!uv_utf8_to_utf16(filename,
-                        filename_w,
-                        sizeof(filename_w) / sizeof(wchar_t))) {
-    saved_errno = GetLastError();
-    return uv__new_sys_error(saved_errno);
+  lib->handle = NULL;
+  lib->errmsg = NULL;
+
+  if (!uv_utf8_to_utf16(filename, filename_w, ARRAY_SIZE(filename_w))) {
+    return uv__dlerror(lib, GetLastError());
   }
 
-  handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
-  if (handle == NULL) {
-    saved_errno = GetLastError();
-    return uv__new_sys_error(saved_errno);
+  lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+  if (lib->handle == NULL) {
+    return uv__dlerror(lib, GetLastError());
   }
 
-  *library = handle;
-  return uv_ok_;
+  return 0;
 }
 
 
-uv_err_t uv_dlclose(uv_lib_t library) {
-  if (!FreeLibrary(library)) {
-    saved_errno = GetLastError();
-    return uv__new_sys_error(saved_errno);
+void uv_dlclose(uv_lib_t* lib) {
+  if (lib->errmsg) {
+    LocalFree((void*)lib->errmsg);
+    lib->errmsg = NULL;
   }
 
-  return uv_ok_;
+  if (lib->handle) {
+    /* Ignore errors. No good way to signal them without leaking memory. */
+    FreeLibrary(lib->handle);
+    lib->handle = NULL;
+  }
 }
 
 
-uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr) {
-  FARPROC proc = GetProcAddress(library, name);
-  if (proc == NULL) {
-    saved_errno = GetLastError();
-    return uv__new_sys_error(saved_errno);
-  }
-
-  *ptr = (void*) proc;
-  return uv_ok_;
+int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
+  *ptr = (void*) GetProcAddress(lib->handle, name);
+  return uv__dlerror(lib, *ptr ? 0 : GetLastError());
 }
 
 
-const char *uv_dlerror(uv_lib_t library) {
-  char* buf = NULL;
-  FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
-                 FORMAT_MESSAGE_IGNORE_INSERTS, NULL, saved_errno,
-                 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPSTR)&buf, 0, NULL);
-  return buf;
+const char* uv_dlerror(uv_lib_t* lib) {
+  return lib->errmsg ? lib->errmsg : "no error";
 }
 
 
-void uv_dlerror_free(uv_lib_t library, const char *msg) {
-  LocalFree((LPVOID)msg);
+static int uv__dlerror(uv_lib_t* lib, int errorno) {
+  if (lib->errmsg) {
+    LocalFree((void*)lib->errmsg);
+    lib->errmsg = NULL;
+  }
+
+  if (errorno) {
+    FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+                   FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+                   MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+                   (LPSTR)&lib->errmsg, 0, NULL);
+  }
+
+  return errorno ? -1 : 0;
 }
index 2940412..bdbb3b2 100644 (file)
@@ -26,7 +26,6 @@
 #include <string.h>
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
 
index 1003201..61f9de2 100644 (file)
  * IN THE SOFTWARE.
  */
 
+#include "uv.h"
+#include "internal.h"
+
 #include <assert.h>
 #include <malloc.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
-#include "uv.h"
-#include "internal.h"
 
 
 const unsigned int uv_directory_watcher_buffer_size = 4096;
@@ -33,9 +34,8 @@ const unsigned int uv_directory_watcher_buffer_size = 4096;
 
 static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle,
     const char* filename, uv_fs_event_cb cb) {
+  uv_handle_init(loop, (uv_handle_t*) handle);
   handle->type = UV_FS_EVENT;
-  handle->loop = loop;
-  handle->flags = 0;
   handle->cb = cb;
   handle->dir_handle = INVALID_HANDLE_VALUE;
   handle->buffer = NULL;
@@ -53,10 +53,9 @@ static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle,
     uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
   }
 
-  loop->counters.handle_init++;
-  loop->counters.fs_event_init++;
+  uv__handle_start(handle);
 
-  uv_ref(loop);
+  loop->counters.fs_event_init++;
 }
 
 
@@ -109,7 +108,7 @@ static int uv_split_path(const wchar_t* filename, wchar_t** dir,
         return -1;
       }
     }
-    
+
     *file = wcsdup(filename);
   } else {
     if (dir) {
@@ -152,7 +151,7 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
     uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
   }
 
-  if (!uv_utf8_to_utf16(filename, filenamew, 
+  if (!uv_utf8_to_utf16(filename, filenamew,
       name_size / sizeof(wchar_t))) {
     uv__set_sys_error(loop, GetLastError());
     return -1;
@@ -172,11 +171,11 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
     handle->dirw = filenamew;
     dir_to_watch = filenamew;
   } else {
-    /* 
+    /*
      * filename is a file.  So we split filename into dir & file parts, and
      * watch the dir directory.
      */
-    
+
     /* Convert to short path. */
     if (!GetShortPathNameW(filenamew, short_path, ARRAY_SIZE(short_path))) {
       last_error = GetLastError();
@@ -226,7 +225,7 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle,
     goto error;
   }
 
-  handle->buffer = (char*)_aligned_malloc(uv_directory_watcher_buffer_size, 
+  handle->buffer = (char*)_aligned_malloc(uv_directory_watcher_buffer_size,
     sizeof(DWORD));
   if (!handle->buffer) {
     uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
@@ -317,7 +316,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
         assert(!filename);
         assert(!long_filenamew);
 
-        /* 
+        /*
          * Fire the event only if we were asked to watch a directory,
          * or if the filename filter matches.
          */
@@ -328,8 +327,8 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
             file_info->FileNameLength / sizeof(wchar_t)) == 0) {
 
           if (handle->dirw) {
-            /* 
-             * We attempt to convert the file name to its long form for 
+            /*
+             * We attempt to convert the file name to its long form for
              * events that still point to valid files on disk.
              * For removed and renamed events, we do not provide the file name.
              */
@@ -382,7 +381,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
                 }
               }
 
-              /* 
+              /*
                * If we couldn't get the long name - just use the name
                * provided by ReadDirectoryChangesW.
                */
@@ -471,6 +470,8 @@ void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
   if (!handle->req_pending) {
     uv_want_endgame(loop, (uv_handle_t*)handle);
   }
+
+  uv__handle_start(handle);
 }
 
 
@@ -479,6 +480,7 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
       !handle->req_pending) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     handle->flags |= UV_HANDLE_CLOSED;
+    uv__handle_stop(handle);
 
     if (handle->buffer) {
       _aligned_free(handle->buffer);
@@ -508,7 +510,5 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
     if (handle->close_cb) {
       handle->close_cb((uv_handle_t*)handle);
     }
-
-    uv_unref(loop);
   }
 }
index 3cbb66f..924554b 100644 (file)
@@ -59,7 +59,7 @@
     return -1;                                                              \
   }                                                                         \
   req->flags |= UV_FS_ASYNC_QUEUED;                                         \
-  uv_ref((loop));
+  uv__req_register(loop, req);
 
 #define SET_UV_LAST_ERROR_FROM_REQ(req)                                     \
   uv__set_error(req->loop, req->errorno, req->sys_errno_);
     return;                                                                 \
   }
 
+#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
+#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
+  ((c) >= L'A' && (c) <= L'Z'))
+
+const wchar_t JUNCTION_PREFIX[] = L"\\??\\";
+const wchar_t JUNCTION_PREFIX_LEN = 4;
+
+const wchar_t LONG_PATH_PREFIX[] = L"\\\\?\\";
+const wchar_t LONG_PATH_PREFIX_LEN = 4;
+
 
 void uv_fs_init() {
   _fmode = _O_BINARY;
@@ -128,6 +138,61 @@ static void uv_fs_req_init_sync(uv_loop_t* loop, uv_fs_t* req,
 }
 
 
+static int is_path_dir(const wchar_t* path) {
+  DWORD attr = GetFileAttributesW(path);
+  
+  if (attr != INVALID_FILE_ATTRIBUTES) {
+    return attr & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0;
+  } else {
+    return 0;
+  }
+}
+
+
+static int get_reparse_point(HANDLE handle, int* target_length) {
+  void* buffer = NULL;
+  REPARSE_DATA_BUFFER* reparse_data;
+  DWORD bytes_returned;
+  int rv = 0;
+
+  buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+  if (!buffer) {
+    uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+  }
+
+  if (!DeviceIoControl(handle,
+                       FSCTL_GET_REPARSE_POINT,
+                       NULL,
+                       0,
+                       buffer,
+                       MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
+                       &bytes_returned,
+                       NULL)) {
+    free(buffer);
+    return 0;
+  }
+
+  reparse_data = (REPARSE_DATA_BUFFER*)buffer;
+  
+  if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+    rv = 1;
+    if (target_length) {
+      *target_length = reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
+        sizeof(wchar_t);
+    }
+  } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+    rv = 1;
+    if (target_length) {
+      *target_length = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
+        sizeof(wchar_t);
+    }
+  }
+
+  free(buffer);
+  return rv;
+}
+
+
 void fs__open(uv_fs_t* req, const wchar_t* path, int flags, int mode) {
   DWORD access;
   DWORD share;
@@ -224,10 +289,8 @@ void fs__open(uv_fs_t* req, const wchar_t* path, int flags, int mode) {
     goto end;
   }
 
-  /* Figure out whether path is a file or a directory. */
-  if (GetFileAttributesW(path) & FILE_ATTRIBUTE_DIRECTORY) {
-    attributes |= FILE_FLAG_BACKUP_SEMANTICS;
-  }
+  /* Setting this flag makes it possible to open a directory. */
+  attributes |= FILE_FLAG_BACKUP_SEMANTICS;
 
   file = CreateFileW(path,
                      access,
@@ -349,20 +412,53 @@ void fs__write(uv_fs_t* req, uv_file file, void *buf, size_t length,
 }
 
 
-void fs__unlink(uv_fs_t* req, const wchar_t* path) {
-  int result = _wunlink(path);
+void fs__rmdir(uv_fs_t* req, const wchar_t* path) {
+  int result = _wrmdir(path);
   SET_REQ_RESULT(req, result);
 }
 
 
-void fs__mkdir(uv_fs_t* req, const wchar_t* path, int mode) {
-  int result = _wmkdir(path);
-  SET_REQ_RESULT(req, result);
+void fs__unlink(uv_fs_t* req, const wchar_t* path) {
+  int result;
+  HANDLE handle;
+  BY_HANDLE_FILE_INFORMATION info;
+  int is_dir_symlink;
+
+  handle = CreateFileW(path,
+                       0,
+                       0,
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+                       NULL);
+
+  if (handle == INVALID_HANDLE_VALUE) {
+    SET_REQ_WIN32_ERROR(req, GetLastError());
+    return;
+  }
+
+  if (!GetFileInformationByHandle(handle, &info)) {
+    SET_REQ_WIN32_ERROR(req, GetLastError());
+    CloseHandle(handle);
+    return;
+  }
+
+  is_dir_symlink = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
+    get_reparse_point(handle, NULL);
+
+  CloseHandle(handle);
+
+  if (is_dir_symlink) {
+    fs__rmdir(req, path);
+  } else {
+    result = _wunlink(path);
+    SET_REQ_RESULT(req, result);
+  }
 }
 
 
-void fs__rmdir(uv_fs_t* req, const wchar_t* path) {
-  int result = _wrmdir(path);
+void fs__mkdir(uv_fs_t* req, const wchar_t* path, int mode) {
+  int result = _wmkdir(path);
   SET_REQ_RESULT(req, result);
 }
 
@@ -474,18 +570,26 @@ void fs__readdir(uv_fs_t* req, const wchar_t* path, int flags) {
 }
 
 
-static void fs__stat(uv_fs_t* req, const wchar_t* path) {
+static void fs__stat(uv_fs_t* req, const wchar_t* path, int link) {
   HANDLE handle;
+  int target_length;
+  int symlink = 0;
   BY_HANDLE_FILE_INFORMATION info;
+  DWORD flags;
 
   req->ptr = NULL;
+  flags = FILE_FLAG_BACKUP_SEMANTICS;
+
+  if (link) {
+    flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+  }
 
   handle = CreateFileW(path,
                        FILE_READ_ATTRIBUTES,
                        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                        NULL,
                        OPEN_EXISTING,
-                       FILE_FLAG_BACKUP_SEMANTICS,
+                       flags,
                        NULL);
   if (handle == INVALID_HANDLE_VALUE) {
     SET_REQ_WIN32_ERROR(req, GetLastError());
@@ -502,32 +606,37 @@ static void fs__stat(uv_fs_t* req, const wchar_t* path) {
 
   /* TODO: set st_dev and st_ino? */
 
-  if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
-    req->stat.st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6));
+  if (link && get_reparse_point(handle, &target_length)) {
+    req->stat.st_mode = S_IFLNK;
+    /* Adjust for long path */
+    req->stat.st_size = target_length - JUNCTION_PREFIX_LEN;
   } else {
-    req->stat.st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) +
-      ((_S_IREAD|_S_IWRITE) >> 6));
-  }
+    if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+      req->stat.st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6));
+    } else {
+      req->stat.st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) +
+        ((_S_IREAD|_S_IWRITE) >> 6));
+    }
 
-  if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
-    req->stat.st_mode |= _S_IFDIR;
-  } else {
-    req->stat.st_mode |= _S_IFREG;
+    if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+      req->stat.st_mode |= _S_IFDIR;
+    } else {
+      req->stat.st_mode |= _S_IFREG;
+    }
+
+    req->stat.st_size = ((int64_t) info.nFileSizeHigh << 32) +
+                        (int64_t) info.nFileSizeLow;
   }
 
   uv_filetime_to_time_t(&info.ftLastWriteTime, &(req->stat.st_mtime));
   uv_filetime_to_time_t(&info.ftLastAccessTime, &(req->stat.st_atime));
   uv_filetime_to_time_t(&info.ftCreationTime, &(req->stat.st_ctime));
 
-  req->stat.st_size = ((int64_t) info.nFileSizeHigh << 32) +
-                      (int64_t) info.nFileSizeLow;
-
   req->stat.st_nlink = (info.nNumberOfLinks <= SHRT_MAX) ?
                        (short) info.nNumberOfLinks : SHRT_MAX;
 
   req->ptr = &req->stat;
   req->result = 0;
-
   CloseHandle(handle);
 }
 
@@ -573,12 +682,28 @@ void fs__fsync(uv_fs_t* req, uv_file file) {
 
 
 void fs__ftruncate(uv_fs_t* req, uv_file file, int64_t offset) {
-  int result;
+  HANDLE handle;
+  NTSTATUS status;
+  IO_STATUS_BLOCK io_status;
+  FILE_END_OF_FILE_INFORMATION eof_info;
 
   VERIFY_UV_FILE(file, req);
 
-  result = _chsize_s(file, offset);
-  SET_REQ_RESULT(req, result);
+  handle = (HANDLE)_get_osfhandle(file);
+
+  eof_info.EndOfFile.QuadPart = offset;
+
+  status = pNtSetInformationFile(handle,
+                                 &io_status,
+                                 &eof_info,
+                                 sizeof eof_info,
+                                 FileEndOfFileInformation);
+
+  if (NT_SUCCESS(status)) {
+    SET_REQ_RESULT(req, 0);
+  } else {
+    SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+  }
 }
 
 
@@ -706,23 +831,193 @@ void fs__link(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path) {
 }
 
 
+void fs__create_junction(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path) {
+  HANDLE handle = INVALID_HANDLE_VALUE;
+  REPARSE_DATA_BUFFER *buffer = NULL;
+  int created = 0;
+  int target_len;
+  int is_absolute, is_long_path;
+  int needed_buf_size, used_buf_size, used_data_size, path_buf_len;
+  int start, len, i;
+  int add_slash;
+  DWORD bytes;
+  wchar_t* path_buf;
+
+  target_len = wcslen(path);
+  is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0;
+
+  if (is_long_path) {
+    is_absolute = 1;
+  } else {
+    is_absolute = target_len >= 3 && IS_LETTER(path[0]) &&
+      path[1] == L':' && IS_SLASH(path[2]);
+  }
+
+  if (!is_absolute) {
+    /* Not supporting relative paths */
+    SET_REQ_UV_ERROR(req, EINVAL, ERROR_NOT_SUPPORTED);
+    return;
+  }
+
+  // Do a pessimistic calculation of the required buffer size
+  needed_buf_size =
+      FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
+      JUNCTION_PREFIX_LEN * sizeof(wchar_t) +
+      2 * (target_len + 2) * sizeof(wchar_t);
+
+  // Allocate the buffer
+  buffer = (REPARSE_DATA_BUFFER*)malloc(needed_buf_size);
+  if (!buffer) {
+    uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+  }
+
+  // Grab a pointer to the part of the buffer where filenames go
+  path_buf = (wchar_t*)&(buffer->MountPointReparseBuffer.PathBuffer);
+  path_buf_len = 0;
+
+  // Copy the substitute (internal) target path
+  start = path_buf_len;
+
+  wcsncpy((wchar_t*)&path_buf[path_buf_len], JUNCTION_PREFIX,
+    JUNCTION_PREFIX_LEN);
+  path_buf_len += JUNCTION_PREFIX_LEN;
+
+  add_slash = 0;
+  for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
+    if (IS_SLASH(path[i])) {
+      add_slash = 1;
+      continue;
+    }
+
+    if (add_slash) {
+      path_buf[path_buf_len++] = L'\\';
+      add_slash = 0;
+    }
+
+    path_buf[path_buf_len++] = path[i];
+  }
+  path_buf[path_buf_len++] = L'\\';
+  len = path_buf_len - start;
+
+  // Set the info about the substitute name
+  buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(wchar_t);
+  buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(wchar_t);
+
+  // Insert null terminator
+  path_buf[path_buf_len++] = L'\0';
+
+  // Copy the print name of the target path
+  start = path_buf_len;
+  add_slash = 0;
+  for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
+    if (IS_SLASH(path[i])) {
+      add_slash = 1;
+      continue;
+    }
+
+    if (add_slash) {
+      path_buf[path_buf_len++] = L'\\';
+      add_slash = 0;
+    }
+
+    path_buf[path_buf_len++] = path[i];
+  }
+  len = path_buf_len - start;
+  if (len == 2) {
+    path_buf[path_buf_len++] = L'\\';
+    len++;
+  }
+
+  // Set the info about the print name
+  buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(wchar_t);
+  buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(wchar_t);
+
+  // Insert another null terminator
+  path_buf[path_buf_len++] = L'\0';
+
+  // Calculate how much buffer space was actually used
+  used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
+    path_buf_len * sizeof(wchar_t);
+  used_data_size = used_buf_size -
+    FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
+
+  // Put general info in the data buffer
+  buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+  buffer->ReparseDataLength = used_data_size;
+  buffer->Reserved = 0;
+
+  // Create a new directory
+  if (!CreateDirectoryW(new_path, NULL)) {
+    SET_REQ_WIN32_ERROR(req, GetLastError());
+    goto error;
+  }
+  created = 1;
+
+  // Open the directory
+  handle = CreateFileW(new_path,
+                       GENERIC_ALL,
+                       0,
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_FLAG_BACKUP_SEMANTICS |
+                         FILE_FLAG_OPEN_REPARSE_POINT,
+                       NULL);
+  if (handle == INVALID_HANDLE_VALUE) {
+    SET_REQ_WIN32_ERROR(req, GetLastError());
+    goto error;
+  }
+
+  // Create the actual reparse point
+  if (!DeviceIoControl(handle,
+                       FSCTL_SET_REPARSE_POINT,
+                       buffer,
+                       used_buf_size,
+                       NULL,
+                       0,
+                       &bytes,
+                       NULL)) {
+    SET_REQ_WIN32_ERROR(req, GetLastError());
+    goto error;
+  }
+
+  // Clean up
+  CloseHandle(handle);
+  free(buffer);
+
+  SET_REQ_RESULT(req, 0);
+  return;
+
+error:
+  free(buffer);
+
+  if (handle != INVALID_HANDLE_VALUE) {
+    CloseHandle(handle);
+  }
+
+  if (created) {
+    RemoveDirectoryW(new_path);
+  }
+}
+
+
 void fs__symlink(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path,
                  int flags) {
   int result;
-  if (pCreateSymbolicLinkW) {
+
+  if (flags & UV_FS_SYMLINK_JUNCTION) {
+    fs__create_junction(req, path, new_path);
+  } else if (pCreateSymbolicLinkW) {
     result = pCreateSymbolicLinkW(new_path,
                                   path,
                                   flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1;
     if (result == -1) {
       SET_REQ_WIN32_ERROR(req, GetLastError());
-      return;
+    } else {
+      SET_REQ_RESULT(req, result);
     }
   } else {
     SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
-    return;
   }
-
-  SET_REQ_RESULT(req, result);
 }
 
 
@@ -772,22 +1067,31 @@ void fs__readlink(uv_fs_t* req, const wchar_t* path) {
   }
 
   reparse_data = (REPARSE_DATA_BUFFER*)buffer;
-  if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
+  if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+    substitute_name = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
+      (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
+        sizeof(wchar_t));
+    substitute_name_length =
+      reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
+        sizeof(wchar_t);
+  } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+    substitute_name = reparse_data->MountPointReparseBuffer.PathBuffer +
+      (reparse_data->MountPointReparseBuffer.SubstituteNameOffset /
+        sizeof(wchar_t));
+    substitute_name_length =
+      reparse_data->MountPointReparseBuffer.SubstituteNameLength /
+        sizeof(wchar_t);
+  } else {
     result = -1;
     /* something is seriously wrong */
     SET_REQ_WIN32_ERROR(req, GetLastError());
     goto done;
   }
 
-  substitute_name = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
-    (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t));
-  substitute_name_length =
-    reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
-
   /* Strip off the leading \??\ from the substitute name buffer.*/
-  if (memcmp(substitute_name, L"\\??\\", 8) == 0) {
-    substitute_name += 4;
-    substitute_name_length -= 4;
+  if (wcsncmp(substitute_name, JUNCTION_PREFIX, JUNCTION_PREFIX_LEN) == 0) {
+    substitute_name += JUNCTION_PREFIX_LEN;
+    substitute_name_length -= JUNCTION_PREFIX_LEN;
   }
 
   utf8size = uv_utf16_to_utf8(substitute_name,
@@ -870,8 +1174,10 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
       fs__readdir(req, req->pathw, req->file_flags);
       break;
     case UV_FS_STAT:
+      fs__stat(req, req->pathw, 0);
+      break;
     case UV_FS_LSTAT:
-      fs__stat(req, req->pathw);
+      fs__stat(req, req->pathw, 1);
       break;
     case UV_FS_FSTAT:
       fs__fstat(req, req->file);
@@ -1246,7 +1552,7 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
   } else {
     uv_fs_req_init_sync(loop, req, UV_FS_STAT);
     UTF8_TO_UTF16(path2 ? path2 : path, pathw);
-    fs__stat(req, pathw);
+    fs__stat(req, pathw, 0);
     if (path2) {
       free(path2);
     }
@@ -1290,7 +1596,7 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
   } else {
     uv_fs_req_init_sync(loop, req, UV_FS_LSTAT);
     UTF8_TO_UTF16(path2 ? path2 : path, pathw);
-    fs__stat(req, pathw);
+    fs__stat(req, pathw, 1);
     if (path2) {
       free(path2);
     }
@@ -1505,6 +1811,7 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime,
 
 void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) {
   assert(req->cb);
+  uv__req_unregister(loop, req);
   SET_UV_LAST_ERROR_FROM_REQ(req);
   req->cb(req);
 }
@@ -1538,10 +1845,6 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
     req->path = NULL;
   }
 
-  if (req->flags & UV_FS_ASYNC_QUEUED) {
-    uv_unref(loop);
-  }
-
   req->flags |= UV_FS_CLEANEDUP;
 }
 
index 5353c0b..bdfe1bb 100644 (file)
@@ -77,23 +77,21 @@ static uv_err_code uv_translate_eai_error(int eai_errno) {
 
 /* getaddrinfo worker thread implementation */
 static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) {
-  uv_getaddrinfo_t* handle = (uv_getaddrinfo_t*) parameter;
-  uv_loop_t* loop = handle->loop;
+  uv_getaddrinfo_t* req = (uv_getaddrinfo_t*) parameter;
+  uv_loop_t* loop = req->loop;
   int ret;
 
-  assert(handle != NULL);
+  assert(req != NULL);
 
-  if (handle != NULL) {
-    /* call OS function on this thread */
-    ret = GetAddrInfoW(handle->node,
-                       handle->service,
-                       handle->hints,
-                       &handle->res);
-    handle->retcode = ret;
+  /* call OS function on this thread */
+  ret = GetAddrInfoW(req->node,
+                     req->service,
+                     req->hints,
+                     &req->res);
+  req->retcode = ret;
 
-    /* post getaddrinfo completed */
-    POST_COMPLETION_FOR_REQ(loop, &handle->getadddrinfo_req);
-  }
+  /* post getaddrinfo completed */
+  POST_COMPLETION_FOR_REQ(loop, req);
 
   return 0;
 }
@@ -108,8 +106,7 @@ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) {
  * and copy all structs and referenced strings into the one block.
  * Each size calculation is adjusted to avoid unaligned pointers.
  */
-void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle,
-    uv_req_t* req) {
+void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
   int addrinfo_len = 0;
   int name_len = 0;
   size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
@@ -120,15 +117,15 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle,
   int status = 0;
 
   /* release input parameter memory */
-  if (handle->alloc != NULL) {
-    free(handle->alloc);
-    handle->alloc = NULL;
+  if (req->alloc != NULL) {
+    free(req->alloc);
+    req->alloc = NULL;
   }
 
-  if (handle->retcode == 0) {
+  if (req->retcode == 0) {
     /* convert addrinfoW to addrinfo */
     /* first calculate required length */
-    addrinfow_ptr = handle->res;
+    addrinfow_ptr = req->res;
     while (addrinfow_ptr != NULL) {
       addrinfo_len += addrinfo_struct_len +
           ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
@@ -150,7 +147,7 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle,
     /* do conversions */
     if (alloc_ptr != NULL) {
       cur_ptr = alloc_ptr;
-      addrinfow_ptr = handle->res;
+      addrinfow_ptr = req->res;
 
       while (addrinfow_ptr != NULL) {
         /* copy addrinfo struct data */
@@ -206,21 +203,21 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle,
     }
   } else {
     /* GetAddrInfo failed */
-    uv__set_artificial_error(loop, uv_translate_eai_error(handle->retcode));
+    uv__set_artificial_error(loop, uv_translate_eai_error(req->retcode));
     status = -1;
   }
 
   /* return memory to system */
-  if (handle->res != NULL) {
-    FreeAddrInfoW(handle->res);
-    handle->res = NULL;
+  if (req->res != NULL) {
+    FreeAddrInfoW(req->res);
+    req->res = NULL;
   }
 
 complete:
-  /* finally do callback with converted result */
-  handle->getaddrinfo_cb(handle, status, (struct addrinfo*)alloc_ptr);
+  uv__req_unregister(loop, req);
 
-  uv_unref(loop);
+  /* finally do callback with converted result */
+  req->getaddrinfo_cb(req, status, (struct addrinfo*)alloc_ptr);
 }
 
 
@@ -237,7 +234,7 @@ void uv_freeaddrinfo(struct addrinfo* ai) {
 /*
  * Entry point for getaddrinfo
  * we convert the UTF-8 strings to UNICODE
- * and save the UNICODE string pointers in the handle
+ * and save the UNICODE string pointers in the req
  * We also copy hints so that caller does not need to keep memory until the
  * callback.
  * return UV_OK if a callback will be made
@@ -248,7 +245,7 @@ void uv_freeaddrinfo(struct addrinfo* ai) {
  * Each size calculation is adjusted to avoid unaligned pointers.
  */
 int uv_getaddrinfo(uv_loop_t* loop,
-                   uv_getaddrinfo_t* handle,
+                   uv_getaddrinfo_t* req,
                    uv_getaddrinfo_cb getaddrinfo_cb,
                    const char* node,
                    const char* service,
@@ -258,18 +255,18 @@ int uv_getaddrinfo(uv_loop_t* loop,
   int hintssize = 0;
   char* alloc_ptr = NULL;
 
-  if (handle == NULL || getaddrinfo_cb == NULL ||
+  if (req == NULL || getaddrinfo_cb == NULL ||
      (node == NULL && service == NULL)) {
     uv__set_sys_error(loop, WSAEINVAL);
     goto error;
   }
 
-  uv_req_init(loop, (uv_req_t*)handle);
+  uv_req_init(loop, (uv_req_t*)req);
 
-  handle->getaddrinfo_cb = getaddrinfo_cb;
-  handle->res = NULL;
-  handle->type = UV_GETADDRINFO;
-  handle->loop = loop;
+  req->getaddrinfo_cb = getaddrinfo_cb;
+  req->res = NULL;
+  req->type = UV_GETADDRINFO;
+  req->loop = loop;
 
   /* calculate required memory size for all input values */
   if (node != NULL) {
@@ -300,12 +297,12 @@ int uv_getaddrinfo(uv_loop_t* loop,
   }
 
   /* save alloc_ptr now so we can free if error */
-  handle->alloc = (void*)alloc_ptr;
+  req->alloc = (void*)alloc_ptr;
 
   /* convert node string to UTF16 into allocated memory and save pointer in */
-  /* handle */
+  /* the reques. */
   if (node != NULL) {
-    handle->node = (wchar_t*)alloc_ptr;
+    req->node = (wchar_t*)alloc_ptr;
     if (uv_utf8_to_utf16(node,
                          (wchar_t*) alloc_ptr,
                          nodesize / sizeof(wchar_t)) == 0) {
@@ -314,13 +311,13 @@ int uv_getaddrinfo(uv_loop_t* loop,
     }
     alloc_ptr += nodesize;
   } else {
-    handle->node = NULL;
+    req->node = NULL;
   }
 
   /* convert service string to UTF16 into allocated memory and save pointer */
-  /* in handle */
+  /* in the req. */
   if (service != NULL) {
-    handle->service = (wchar_t*)alloc_ptr;
+    req->service = (wchar_t*)alloc_ptr;
     if (uv_utf8_to_utf16(service,
                          (wchar_t*) alloc_ptr,
                          servicesize / sizeof(wchar_t)) == 0) {
@@ -329,44 +326,39 @@ int uv_getaddrinfo(uv_loop_t* loop,
     }
     alloc_ptr += servicesize;
   } else {
-    handle->service = NULL;
+    req->service = NULL;
   }
 
-  /* copy hints to allocated memory and save pointer in handle */
+  /* copy hints to allocated memory and save pointer in req */
   if (hints != NULL) {
-    handle->hints = (struct addrinfoW*)alloc_ptr;
-    handle->hints->ai_family = hints->ai_family;
-    handle->hints->ai_socktype = hints->ai_socktype;
-    handle->hints->ai_protocol = hints->ai_protocol;
-    handle->hints->ai_flags = hints->ai_flags;
-    handle->hints->ai_addrlen = 0;
-    handle->hints->ai_canonname = NULL;
-    handle->hints->ai_addr = NULL;
-    handle->hints->ai_next = NULL;
+    req->hints = (struct addrinfoW*)alloc_ptr;
+    req->hints->ai_family = hints->ai_family;
+    req->hints->ai_socktype = hints->ai_socktype;
+    req->hints->ai_protocol = hints->ai_protocol;
+    req->hints->ai_flags = hints->ai_flags;
+    req->hints->ai_addrlen = 0;
+    req->hints->ai_canonname = NULL;
+    req->hints->ai_addr = NULL;
+    req->hints->ai_next = NULL;
   } else {
-    handle->hints = NULL;
+    req->hints = NULL;
   }
 
-  /* init request for Post handling */
-  uv_req_init(loop, &handle->getadddrinfo_req);
-  handle->getadddrinfo_req.data = handle;
-  handle->getadddrinfo_req.type = UV_GETADDRINFO_REQ;
-
   /* Ask thread to run. Treat this as a long operation */
   if (QueueUserWorkItem(&getaddrinfo_thread_proc,
-                        handle,
+                        req,
                         WT_EXECUTELONGFUNCTION) == 0) {
     uv__set_sys_error(loop, GetLastError());
     goto error;
   }
 
-  uv_ref(loop);
+  uv__req_register(loop, req);
 
   return 0;
 
 error:
-  if (handle != NULL && handle->alloc != NULL) {
-    free(handle->alloc);
+  if (req != NULL && req->alloc != NULL) {
+    free(req->alloc);
   }
   return -1;
 }
index 797b071..b501143 100644 (file)
@@ -57,27 +57,23 @@ uv_handle_type uv_guess_handle(uv_file file) {
 
 
 int uv_is_active(const uv_handle_t* handle) {
-  switch (handle->type) {
-    case UV_TIMER:
-    case UV_IDLE:
-    case UV_PREPARE:
-    case UV_CHECK:
-      return (handle->flags & UV_HANDLE_ACTIVE) ? 1 : 0;
+  return (handle->flags & UV__ACTIVE) && !(handle->flags & UV_HANDLE_CLOSING);
+}
 
-    default:
-      return 1;
-  }
+
+void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle) {
+  handle->loop = loop;
+  handle->flags = UV__REF;
+
+  loop->counters.handle_init++;
 }
 
 
 void uv_close(uv_handle_t* handle, uv_close_cb cb) {
-  uv_pipe_t* pipe;
-  uv_udp_t* udp;
-  uv_process_t* process;
-
   uv_loop_t* loop = handle->loop;
 
   if (handle->flags & UV_HANDLE_CLOSING) {
+    assert(0);
     return;
   }
 
@@ -87,16 +83,11 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
   /* Handle-specific close actions */
   switch (handle->type) {
     case UV_TCP:
-      uv_tcp_close((uv_tcp_t*)handle);
+      uv_tcp_close(loop, (uv_tcp_t*)handle);
       return;
 
     case UV_NAMED_PIPE:
-      pipe = (uv_pipe_t*)handle;
-      pipe->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING);
-      close_pipe(pipe, NULL, NULL);
-      if (pipe->reqs_pending == 0) {
-        uv_want_endgame(loop, handle);
-      }
+      uv_pipe_close(loop, (uv_pipe_t*) handle);
       return;
 
     case UV_TTY:
@@ -104,47 +95,47 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
       return;
 
     case UV_UDP:
-      udp = (uv_udp_t*) handle;
-      uv_udp_recv_stop(udp);
-      closesocket(udp->socket);
-      if (udp->reqs_pending == 0) {
-        uv_want_endgame(loop, handle);
-      }
+      uv_udp_close(loop, (uv_udp_t*) handle);
+      return;
+
+    case UV_POLL:
+      uv_poll_close(loop, (uv_poll_t*) handle);
       return;
 
     case UV_TIMER:
       uv_timer_stop((uv_timer_t*)handle);
+      uv__handle_start(handle);
       uv_want_endgame(loop, handle);
       return;
 
     case UV_PREPARE:
       uv_prepare_stop((uv_prepare_t*)handle);
+      uv__handle_start(handle);
       uv_want_endgame(loop, handle);
       return;
 
     case UV_CHECK:
       uv_check_stop((uv_check_t*)handle);
+      uv__handle_start(handle);
       uv_want_endgame(loop, handle);
       return;
 
     case UV_IDLE:
       uv_idle_stop((uv_idle_t*)handle);
+      uv__handle_start(handle);
       uv_want_endgame(loop, handle);
       return;
 
     case UV_ASYNC:
-      if (!((uv_async_t*)handle)->async_sent) {
-        uv_want_endgame(loop, handle);
-      }
+      uv_async_close(loop, (uv_async_t*) handle);
       return;
 
     case UV_PROCESS:
-      process = (uv_process_t*)handle;
-      uv_process_close(loop, process);
+      uv_process_close(loop, (uv_process_t*) handle);
       return;
 
     case UV_FS_EVENT:
-      uv_fs_event_close(loop, (uv_fs_event_t*)handle);
+      uv_fs_event_close(loop, (uv_fs_event_t*) handle);
       return;
 
     default:
@@ -172,7 +163,7 @@ void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
 void uv_process_endgames(uv_loop_t* loop) {
   uv_handle_t* handle;
 
-  while (loop->endgame_handles && loop->refs > 0) {
+  while (loop->endgame_handles) {
     handle = loop->endgame_handles;
     loop->endgame_handles = handle->endgame_next;
 
@@ -195,6 +186,10 @@ void uv_process_endgames(uv_loop_t* loop) {
         uv_udp_endgame(loop, (uv_udp_t*) handle);
         break;
 
+      case UV_POLL:
+        uv_poll_endgame(loop, (uv_poll_t*) handle);
+        break;
+
       case UV_TIMER:
         uv_timer_endgame(loop, (uv_timer_t*) handle);
         break;
index 7cc469d..362e23f 100644 (file)
 
 
 /*
- * Timers
- */
-void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle);
-
-DWORD uv_get_poll_timeout(uv_loop_t* loop);
-void uv_process_timers(uv_loop_t* loop);
-
-
-/*
  * Handles
  */
 
-/* Private uv_handle flags */
+/* Used by all handles. */
 #define UV_HANDLE_CLOSING                       0x00000001
 #define UV_HANDLE_CLOSED                        0x00000002
-#define UV_HANDLE_BOUND                         0x00000004
-#define UV_HANDLE_LISTENING                     0x00000008
-#define UV_HANDLE_CONNECTION                    0x00000010
-#define UV_HANDLE_CONNECTED                     0x00000020
-#define UV_HANDLE_READING                       0x00000040
-#define UV_HANDLE_ACTIVE                        0x00000040
-#define UV_HANDLE_EOF                           0x00000080
-#define UV_HANDLE_SHUTTING                      0x00000100
-#define UV_HANDLE_SHUT                          0x00000200
-#define UV_HANDLE_ENDGAME_QUEUED                0x00000400
-#define UV_HANDLE_BIND_ERROR                    0x00001000
-#define UV_HANDLE_IPV6                          0x00002000
-#define UV_HANDLE_PIPESERVER                    0x00004000
-#define UV_HANDLE_READ_PENDING                  0x00008000
-#define UV_HANDLE_UV_ALLOCED                    0x00010000
-#define UV_HANDLE_SYNC_BYPASS_IOCP              0x00020000
-#define UV_HANDLE_ZERO_READ                     0x00040000
-#define UV_HANDLE_TTY_RAW                       0x00080000
+#define UV_HANDLE_ENDGAME_QUEUED                0x00000004
+#define UV_HANDLE_ACTIVE                        0x00000010
+
+/* Keep in sync with uv-common.h: */
+#define UV__REF                                 0x00000020
+#define UV__ACTIVE                              0x00000040
+/* reserved: #define UV_HANDLE_INTERNAL         0x00000080 */
+
+/* Used by streams and UDP handles. */
+#define UV_HANDLE_READING                       0x00000100
+#define UV_HANDLE_BOUND                         0x00000200
+#define UV_HANDLE_BIND_ERROR                    0x00000400
+#define UV_HANDLE_LISTENING                     0x00000800
+#define UV_HANDLE_CONNECTION                    0x00001000
+#define UV_HANDLE_CONNECTED                     0x00002000
+#define UV_HANDLE_EOF                           0x00004000
+#define UV_HANDLE_SHUTTING                      0x00008000
+#define UV_HANDLE_SHUT                          0x00010000
+#define UV_HANDLE_READ_PENDING                  0x00020000
+#define UV_HANDLE_SYNC_BYPASS_IOCP              0x00040000
+#define UV_HANDLE_ZERO_READ                     0x00080000
 #define UV_HANDLE_EMULATE_IOCP                  0x00100000
-#define UV_HANDLE_NON_OVERLAPPED_PIPE           0x00200000
-#define UV_HANDLE_TTY_SAVED_POSITION            0x00400000
-#define UV_HANDLE_TTY_SAVED_ATTRIBUTES          0x00800000
-#define UV_HANDLE_SHARED_TCP_SOCKET             0x01000000
+
+/* Only used by uv_tcp_t handles. */
+#define UV_HANDLE_IPV6                          0x01000000
 #define UV_HANDLE_TCP_NODELAY                   0x02000000
 #define UV_HANDLE_TCP_KEEPALIVE                 0x04000000
 #define UV_HANDLE_TCP_SINGLE_ACCEPT             0x08000000
 #define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING     0x10000000
 #define UV_HANDLE_TCP_SOCKET_CLOSED             0x20000000
+#define UV_HANDLE_SHARED_TCP_SOCKET             0x40000000
+
+/* Only used by uv_pipe_t handles. */
+#define UV_HANDLE_NON_OVERLAPPED_PIPE           0x01000000
+#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
+
+/* Only used by uv_poll_t handles. */
+#define UV_HANDLE_POLL_SLOW                     0x02000000
+
 
 void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle);
 void uv_process_endgames(uv_loop_t* loop);
@@ -95,6 +102,41 @@ void uv_process_endgames(uv_loop_t* loop);
 #define UV_SUCCEEDED_WITH_IOCP(result)                        \
   ((result) || (GetLastError() == ERROR_IO_PENDING))
 
+#define DECREASE_ACTIVE_COUNT(loop, handle)                             \
+  do {                                                                  \
+    if (--(handle)->activecnt == 0 &&                                   \
+        !((handle)->flags & UV_HANDLE_CLOSING)) {                       \
+      uv__handle_stop((handle));                                        \
+    }                                                                   \
+    assert((handle)->activecnt >= 0);                                   \
+  } while (0)
+
+#define INCREASE_ACTIVE_COUNT(loop, handle)                             \
+  do {                                                                  \
+    if ((handle)->activecnt++ == 0) {                                   \
+      uv__handle_start((handle));                                       \
+    }                                                                   \
+    assert((handle)->activecnt > 0);                                    \
+  } while (0)
+
+#define REGISTER_HANDLE_REQ(loop, handle, req)                          \
+  do {                                                                  \
+    INCREASE_ACTIVE_COUNT((loop), (handle));                            \
+    uv__req_register((loop), (req));                                    \
+  } while (0)
+
+#define UNREGISTER_HANDLE_REQ(loop, handle, req)                        \
+  do {                                                                  \
+    DECREASE_ACTIVE_COUNT((loop), (handle));                            \
+    uv__req_unregister((loop), (req));                                  \
+  } while (0)
+
+
+/*
+ * Handles
+ */
+void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle);
+
 
 /*
  * Requests
@@ -142,6 +184,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
 void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
     uv_connect_t* req);
 
+void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
 void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
 
 int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
@@ -150,8 +193,6 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
 int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
     LPWSAPROTOCOL_INFOW protocol_info);
 
-void uv_tcp_close(uv_tcp_t* tcp);
-
 
 /*
  * UDP
@@ -160,6 +201,7 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
 void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
     uv_udp_send_t* req);
 
+void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle);
 void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
 
 
@@ -168,8 +210,6 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
  */
 int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
     char* name, size_t nameSize);
-void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err);
-void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
 
 int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
 int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
@@ -193,6 +233,10 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
 void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
     uv_shutdown_t* req);
 
+void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
+void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle);
+void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
+
 
 /*
  * TTY
@@ -221,6 +265,25 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
 
 
 /*
+ * Poll watchers
+ */
+void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+    uv_req_t* req);
+
+void uv_poll_close(uv_loop_t* loop, uv_poll_t* handle);
+void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
+
+
+/*
+ * Timers
+ */
+void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle);
+
+DWORD uv_get_poll_timeout(uv_loop_t* loop);
+void uv_process_timers(uv_loop_t* loop);
+
+
+/*
  * Loop watchers
  */
 void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle);
@@ -233,6 +296,7 @@ void uv_idle_invoke(uv_loop_t* loop);
 /*
  * Async watcher
  */
+void uv_async_close(uv_loop_t* loop, uv_async_t* handle);
 void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle);
 
 void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
@@ -261,8 +325,7 @@ void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle,
 /*
  * Getaddrinfo
  */
-void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle,
-    uv_req_t* req);
+void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req);
 
 
 /*
@@ -339,6 +402,9 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
     int* addr_len, WSAOVERLAPPED *overlapped,
     LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
 
+int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info,
+    OVERLAPPED* overlapped);
+
 /* Whether ipv6 is supported */
 extern int uv_allow_ipv6;
 
index c597cd9..46d184c 100644 (file)
@@ -22,7 +22,6 @@
 #include <assert.h>
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
 
@@ -30,25 +29,19 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
   if (handle->flags & UV_HANDLE_CLOSING) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     handle->flags |= UV_HANDLE_CLOSED;
+    uv__handle_stop(handle);
 
     if (handle->close_cb) {
       handle->close_cb(handle);
     }
-
-    uv_unref(loop);
   }
 }
 
 
 #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);                              \
     handle->type = UV_##NAME;                                                 \
-    handle->loop = loop;                                                      \
-    handle->flags = 0;                                                        \
-                                                                              \
-    uv_ref(loop);                                                             \
-                                                                              \
-    loop->counters.handle_init++;                                             \
     loop->counters.name##_init++;                                             \
                                                                               \
     return 0;                                                                 \
@@ -77,6 +70,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
                                                                               \
     handle->name##_cb = cb;                                                   \
     handle->flags |= UV_HANDLE_ACTIVE;                                        \
+    uv__handle_start(handle);                                                 \
                                                                               \
     return 0;                                                                 \
   }                                                                           \
@@ -108,6 +102,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
     }                                                                         \
                                                                               \
     handle->flags &= ~UV_HANDLE_ACTIVE;                                       \
+    uv__handle_stop(handle);                                                  \
                                                                               \
     return 0;                                                                 \
   }                                                                           \
index 35da85e..2b48e38 100644 (file)
@@ -25,7 +25,6 @@
 #include <stdio.h>
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
 
@@ -280,7 +279,6 @@ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
 
 
 void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
-  unsigned int uv_alloced;
   DWORD result;
   uv_shutdown_t* req;
   NTSTATUS nt_status;
@@ -296,12 +294,14 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
     handle->shutdown_req = NULL;
 
     if (handle->flags & UV_HANDLE_CLOSING) {
+      UNREGISTER_HANDLE_REQ(loop, handle, req);
+
       /* Already closing. Cancel the shutdown. */
       if (req->cb) {
         uv__set_sys_error(loop, WSAEINTR);
         req->cb(req, -1);
       }
-      uv_unref(loop);
+
       DECREASE_PENDING_REQ_COUNT(handle);
       return;
     }
@@ -315,12 +315,14 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
 
     if (nt_status != STATUS_SUCCESS) {
       /* Failure */
+      UNREGISTER_HANDLE_REQ(loop, handle, req);
+
       handle->flags &= ~UV_HANDLE_SHUTTING;
       if (req->cb) {
         uv__set_sys_error(loop, pRtlNtStatusToDosError(nt_status));
         req->cb(req, -1);
       }
-      uv_unref(loop);
+
       DECREASE_PENDING_REQ_COUNT(handle);
       return;
     }
@@ -340,12 +342,14 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
 
     } else {
       /* Failure. */
+      UNREGISTER_HANDLE_REQ(loop, handle, req);
+
       handle->flags &= ~UV_HANDLE_SHUTTING;
       if (req->cb) {
         uv__set_sys_error(loop, GetLastError());
         req->cb(req, -1);
       }
-      uv_unref(loop);
+
       DECREASE_PENDING_REQ_COUNT(handle);
       return;
     }
@@ -355,6 +359,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
       handle->reqs_pending == 0) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     handle->flags |= UV_HANDLE_CLOSED;
+    uv__handle_stop(handle);
 
     if (handle->flags & UV_HANDLE_CONNECTION) {
       if (handle->pending_ipc_info.socket_info) {
@@ -380,19 +385,9 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
       handle->accept_reqs = NULL;
     }
 
-    /* Remember the state of this flag because the close callback is */
-    /* allowed to clobber or free the handle's memory */
-    uv_alloced = handle->flags & UV_HANDLE_UV_ALLOCED;
-
     if (handle->close_cb) {
       handle->close_cb((uv_handle_t*)handle);
     }
-
-    if (uv_alloced) {
-      free(handle);
-    }
-
-    uv_unref(loop);
   }
 }
 
@@ -573,7 +568,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
         goto error;
       }
 
-      uv_ref(loop);
+      REGISTER_HANDLE_REQ(loop, handle, req);
       handle->reqs_pending++;
 
       return;
@@ -596,7 +591,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
   SET_REQ_SUCCESS(req);
   uv_insert_pending_req(loop, (uv_req_t*) req);
   handle->reqs_pending++;
-  uv_ref(loop);
+  REGISTER_HANDLE_REQ(loop, handle, req);
   return;
 
 error:
@@ -613,14 +608,14 @@ error:
   SET_REQ_ERROR(req, errorno);
   uv_insert_pending_req(loop, (uv_req_t*) req);
   handle->reqs_pending++;
-  uv_ref(loop);
+  REGISTER_HANDLE_REQ(loop, handle, req);
   return;
 }
 
 
 /* Cleans up uv_pipe_t (server or connection) and all resources associated */
 /* with it. */
-void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) {
+void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
   int i;
   HANDLE pipeHandle;
 
@@ -652,6 +647,27 @@ void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) {
 }
 
 
+void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
+  if (handle->flags & UV_HANDLE_READING) {
+    handle->flags &= ~UV_HANDLE_READING;
+    DECREASE_ACTIVE_COUNT(loop, handle);
+  }
+
+  if (handle->flags & UV_HANDLE_LISTENING) {
+    handle->flags &= ~UV_HANDLE_LISTENING;
+    DECREASE_ACTIVE_COUNT(loop, handle);
+  }
+
+  uv_pipe_cleanup(loop, handle);
+
+  if (handle->reqs_pending == 0) {
+    uv_want_endgame(loop, (uv_handle_t*) handle);
+  }
+
+  uv__handle_start(handle);
+}
+
+
 static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
     uv_pipe_accept_t* req, BOOL firstInstance) {
   assert(handle->flags & UV_HANDLE_LISTENING);
@@ -717,7 +733,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
       return -1;
     }
 
-    return uv_tcp_import((uv_tcp_t*)client, server->pending_ipc_info.socket_info, 
+    return uv_tcp_import((uv_tcp_t*)client, server->pending_ipc_info.socket_info,
                          server->pending_ipc_info.tcp_connection);
   } else {
     pipe_client = (uv_pipe_t*)client;
@@ -753,17 +769,19 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
 /* Starts listening for connections for the given pipe. */
 int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
   uv_loop_t* loop = handle->loop;
-
   int i;
 
+  if (handle->flags & UV_HANDLE_LISTENING) {
+    handle->connection_cb = cb;
+  }
+
   if (!(handle->flags & UV_HANDLE_BOUND)) {
     uv__set_artificial_error(loop, UV_EINVAL);
     return -1;
   }
 
-  if (handle->flags & UV_HANDLE_LISTENING ||
-      handle->flags & UV_HANDLE_READING) {
-    uv__set_artificial_error(loop, UV_EALREADY);
+  if (handle->flags & UV_HANDLE_READING) {
+    uv__set_artificial_error(loop, UV_EISCONN);
     return -1;
   }
 
@@ -773,6 +791,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
   }
 
   handle->flags |= UV_HANDLE_LISTENING;
+  INCREASE_ACTIVE_COUNT(loop, handle);
   handle->connection_cb = cb;
 
   /* First pipe handle should have already been created in uv_pipe_bind */
@@ -955,17 +974,13 @@ static int uv_pipe_read_start_impl(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
     return -1;
   }
 
-  if (handle->flags & UV_HANDLE_READING) {
-    uv__set_artificial_error(loop, UV_EALREADY);
-    return -1;
-  }
-
   if (handle->flags & UV_HANDLE_EOF) {
     uv__set_artificial_error(loop, UV_EOF);
     return -1;
   }
 
   handle->flags |= UV_HANDLE_READING;
+  INCREASE_ACTIVE_COUNT(loop, handle);
   handle->read_cb = read_cb;
   handle->read2_cb = read2_cb;
   handle->alloc_cb = alloc_cb;
@@ -1154,10 +1169,10 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
       /* Request queued by the kernel. */
       ipc_header_req->queued_bytes = ipc_frame.header.flags & UV_IPC_TCP_SERVER ?
         sizeof(ipc_frame) : sizeof(ipc_frame.header);
-      handle->write_queue_size += req->queued_bytes;
+      handle->write_queue_size += ipc_header_req->queued_bytes;
     }
 
-    uv_ref(loop);
+    REGISTER_HANDLE_REQ(loop, handle, ipc_header_req);
     handle->reqs_pending++;
     handle->write_reqs_pending++;
 
@@ -1212,7 +1227,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
     }
   }
 
-  uv_ref(loop);
+  REGISTER_HANDLE_REQ(loop, handle, req);
   handle->reqs_pending++;
   handle->write_reqs_pending++;
 
@@ -1435,6 +1450,8 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
   assert(handle->write_queue_size >= req->queued_bytes);
   handle->write_queue_size -= req->queued_bytes;
 
+  UNREGISTER_HANDLE_REQ(loop, handle, req);
+
   if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
     if (req->wait_handle != INVALID_HANDLE_VALUE) {
       UnregisterWait(req->wait_handle);
@@ -1476,7 +1493,6 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
     uv_want_endgame(loop, (uv_handle_t*)handle);
   }
 
-  uv_unref(loop);
   DECREASE_PENDING_REQ_COUNT(handle);
 }
 
@@ -1513,6 +1529,8 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
     uv_connect_t* req) {
   assert(handle->type == UV_NAMED_PIPE);
 
+  UNREGISTER_HANDLE_REQ(loop, handle, req);
+
   if (req->cb) {
     if (REQ_SUCCESS(req)) {
       uv_pipe_connection_init(handle);
@@ -1523,7 +1541,6 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
     }
   }
 
-  uv_unref(loop);
   DECREASE_PENDING_REQ_COUNT(handle);
 }
 
@@ -1532,6 +1549,8 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
     uv_shutdown_t* req) {
   assert(handle->type == UV_NAMED_PIPE);
 
+  UNREGISTER_HANDLE_REQ(loop, handle, req);
+
   /* Initialize and optionally start the eof timer. */
   /* This makes no sense if we've already seen EOF. */
   if (!(handle->flags & UV_HANDLE_EOF)) {
@@ -1548,7 +1567,6 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
     req->cb(req, 0);
   }
 
-  uv_unref(loop);
   DECREASE_PENDING_REQ_COUNT(handle);
 }
 
@@ -1564,7 +1582,7 @@ static void eof_timer_init(uv_pipe_t* pipe) {
   r = uv_timer_init(pipe->loop, pipe->eof_timer);
   assert(r == 0); /* timers can't fail */
   pipe->eof_timer->data = pipe;
-  uv_unref(pipe->loop);
+  uv_unref((uv_handle_t*) pipe->eof_timer);
 }
 
 
@@ -1598,7 +1616,7 @@ static void eof_timer_cb(uv_timer_t* timer, int status) {
   /* or in uv_process_pipe_shutdown_req if a read is pending, */
   /* and we always immediately stop the timer in */
   /* uv_process_pipe_read_req. */
-  assert(pipe->flags & UV_HANDLE_READ_PENDING) ;
+  assert(pipe->flags & UV_HANDLE_READ_PENDING);
 
   /* If there are many packets coming off the iocp then the timer callback */
   /* may be called before the read request is coming off the queue. */
@@ -1627,7 +1645,6 @@ static void eof_timer_destroy(uv_pipe_t* pipe) {
   assert(pipe->flags && UV_HANDLE_CONNECTION);
 
   if (pipe->eof_timer) {
-    uv_ref(pipe->loop);
     uv_close((uv_handle_t*) pipe->eof_timer, eof_timer_close_cb);
     pipe->eof_timer = NULL;
   }
diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c
new file mode 100644 (file)
index 0000000..c6d68ff
--- /dev/null
@@ -0,0 +1,620 @@
+/* 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 <io.h>
+
+
+static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
+  {0xe70f1aa0, 0xab8b, 0x11cf,
+      {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
+  {0xf9eab0c0, 0x26d4, 0x11d0,
+      {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
+  {0x9fc48064, 0x7298, 0x43e4,
+      {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
+};
+
+typedef struct uv_single_fd_set_s {
+  unsigned int fd_count;
+  SOCKET fd_array[1];
+} uv_single_fd_set_t;
+
+
+static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+  uv_req_t* req;
+  AFD_POLL_INFO* afd_poll_info;
+  DWORD result;
+
+  /* Find a yet unsubmitted req to submit. */
+  if (handle->submitted_events_1 == 0) {
+    req = &handle->poll_req_1;
+    afd_poll_info = &handle->afd_poll_info_1;
+    handle->submitted_events_1 = handle->events;
+    handle->mask_events_1 = 0;
+    handle->mask_events_2 = handle->events;
+  } else if (handle->submitted_events_2 == 0) {
+    req = &handle->poll_req_2;
+    afd_poll_info = &handle->afd_poll_info_2;
+    handle->submitted_events_2 = handle->events;
+    handle->mask_events_1 = handle->events;
+    handle->mask_events_2 = 0;
+  } else {
+    assert(0);
+  }
+
+  /* Setting Exclusive to TRUE makes the other poll request return if there */
+  /* is any. */
+  afd_poll_info->Exclusive = TRUE;
+  afd_poll_info->NumberOfHandles = 1;
+  afd_poll_info->Timeout.QuadPart = INT64_MAX;
+  afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
+  afd_poll_info->Handles[0].Status = 0;
+  afd_poll_info->Handles[0].Events = 0;
+
+  if (handle->events & UV_READABLE) {
+    afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE |
+        AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT;
+  }
+  if (handle->events & UV_WRITABLE) {
+    afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
+  }
+
+  memset(&req->overlapped, 0, sizeof req->overlapped);
+
+  result = uv_msafd_poll((SOCKET) handle->peer_socket,
+                         afd_poll_info,
+                         &req->overlapped);
+  if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
+    /* Queue this req, reporting an error. */
+    SET_REQ_ERROR(req, WSAGetLastError());
+    uv_insert_pending_req(loop, req);
+  }
+}
+
+
+static int uv__fast_poll_cancel_poll_reqs(uv_loop_t* loop, uv_poll_t* handle) {
+  AFD_POLL_INFO afd_poll_info;
+  DWORD result;
+  HANDLE event;
+  OVERLAPPED overlapped;
+
+  event = CreateEvent(NULL, TRUE, FALSE, NULL);
+  if (event == NULL) {
+    uv__set_sys_error(loop, GetLastError());
+    return -1;
+  }
+
+  afd_poll_info.Exclusive = TRUE;
+  afd_poll_info.NumberOfHandles = 1;
+  afd_poll_info.Timeout.QuadPart = INT64_MAX;
+  afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
+  afd_poll_info.Handles[0].Status = 0;
+  afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
+
+  memset(&overlapped, 0, sizeof overlapped);
+  overlapped.hEvent = (HANDLE) ((uintptr_t) event & 1);
+
+  result = uv_msafd_poll(handle->socket,
+                         &afd_poll_info,
+                         &overlapped);
+
+  if (result == SOCKET_ERROR) {
+    DWORD error = WSAGetLastError();
+    if (error != WSA_IO_PENDING) {
+      uv__set_sys_error(loop, WSAGetLastError());
+      CloseHandle(event);
+      return -1;
+    }
+  }
+
+  CloseHandle(event);
+  return 0;
+}
+
+
+static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+    uv_req_t* req) {
+  unsigned char mask_events;
+  AFD_POLL_INFO* afd_poll_info;
+
+  if (req == &handle->poll_req_1) {
+    afd_poll_info = &handle->afd_poll_info_1;
+    handle->submitted_events_1 = 0;
+    mask_events = handle->mask_events_1;
+  } else if (req == &handle->poll_req_2) {
+    afd_poll_info = &handle->afd_poll_info_2;
+    handle->submitted_events_2 = 0;
+    mask_events = handle->mask_events_2;
+  } else {
+    assert(0);
+  }
+
+  /* Report an error unless the select was just interrupted. */
+  if (!REQ_SUCCESS(req)) {
+    DWORD error = GET_REQ_SOCK_ERROR(req);
+    if (error != WSAEINTR && handle->events != 0) {
+      handle->events = 0; /* Stop the watcher */
+      uv__set_sys_error(loop, error);
+      handle->poll_cb(handle, -1, 0);
+    }
+
+  } else if (afd_poll_info->NumberOfHandles >= 1) {
+    unsigned char events = 0;
+
+    if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE |
+        AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) {
+      events |= UV_READABLE;
+    }
+    if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND |
+        AFD_POLL_CONNECT_FAIL)) != 0) {
+      events |= UV_WRITABLE;
+    }
+
+    events &= handle->events & ~mask_events;
+
+    if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
+      /* Stop polling. */
+      handle->events = 0;
+    }
+
+    if (events != 0) {
+      handle->poll_cb(handle, 0, events);
+    }
+  }
+
+  if ((handle->events & ~(handle->submitted_events_1 |
+      handle->submitted_events_2)) != 0) {
+    uv__fast_poll_submit_poll_req(loop, handle);
+  } else if ((handle->flags & UV_HANDLE_CLOSING) &&
+             handle->submitted_events_1 == 0 &&
+             handle->submitted_events_2 == 0) {
+    uv_want_endgame(loop, (uv_handle_t*) handle);
+  }
+}
+
+
+static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
+  assert(handle->type == UV_POLL);
+  assert(!(handle->flags & UV_HANDLE_CLOSING));
+  assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
+
+  handle->events = events;
+
+  if (handle->events != 0) {
+    uv__handle_start(handle);
+  } else {
+    uv__handle_stop(handle);
+  }
+
+  if ((handle->events & ~(handle->submitted_events_1 |
+      handle->submitted_events_2)) != 0) {
+    uv__fast_poll_submit_poll_req(handle->loop, handle);
+  }
+
+  return 0;
+}
+
+
+static void uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+  handle->events = 0;
+  uv__handle_start(handle);
+
+  if (handle->submitted_events_1 == 0 &&
+      handle->submitted_events_2 == 0) {
+    uv_want_endgame(loop, (uv_handle_t*) handle);
+  } else {
+    /* Try to cancel outstanding poll requests. */
+    if (pCancelIoEx) {
+      /* Use CancelIoEx to cancel poll requests if available. */
+      if (handle->submitted_events_1)
+        pCancelIoEx((HANDLE) handle->socket, &handle->poll_req_1.overlapped);
+      if (handle->submitted_events_2)
+        pCancelIoEx((HANDLE) handle->socket, &handle->poll_req_2.overlapped);
+    } else if (handle->submitted_events_1 | handle->submitted_events_2) {
+      /* Execute another unique poll to force the others to return. */
+      uv__fast_poll_cancel_poll_reqs(loop, handle);
+    }
+  }
+}
+
+
+static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
+    WSAPROTOCOL_INFOW* protocol_info) {
+  SOCKET sock = 0;
+
+  sock = WSASocketW(protocol_info->iAddressFamily,
+                    protocol_info->iSocketType,
+                    protocol_info->iProtocol,
+                    protocol_info,
+                    0,
+                    WSA_FLAG_OVERLAPPED);
+  if (sock == INVALID_SOCKET) {
+    return INVALID_SOCKET;
+  }
+
+  if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
+    goto error;
+  };
+
+  if (CreateIoCompletionPort((HANDLE) sock,
+                             iocp,
+                             (ULONG_PTR) sock,
+                             0) == NULL) {
+    goto error;
+  }
+
+  return sock;
+
+ error:
+  closesocket(sock);
+  return INVALID_SOCKET;
+}
+
+
+static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
+    WSAPROTOCOL_INFOW* protocol_info) {
+  int index, i;
+  SOCKET peer_socket;
+
+  index = -1;
+  for (i = 0; i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
+    if (memcmp((void*) &protocol_info->ProviderId,
+               (void*) &uv_msafd_provider_ids[i],
+               sizeof protocol_info->ProviderId) == 0) {
+      index = i;
+    }
+  }
+
+  /* Check if the protocol uses an msafd socket. */
+  if (index < 0) {
+    return INVALID_SOCKET;
+  }
+
+  /* If we didn't (try) to create a peer socket yet, try to make one. Don't */
+  /* try again if the peer socket creation failed earlier for the same */
+  /* protocol. */
+  peer_socket = loop->poll_peer_sockets[index];
+  if (peer_socket == 0) {
+    peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
+    loop->poll_peer_sockets[index] = peer_socket;
+  }
+
+  return peer_socket;
+}
+
+
+static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
+  uv_req_t* req = (uv_req_t*) arg;
+  uv_poll_t* handle = (uv_poll_t*) req->data;
+  unsigned char events, reported_events;
+  int r;
+  uv_single_fd_set_t rfds, wfds, efds;
+  struct timeval timeout;
+
+  assert(handle->type == UV_POLL);
+  assert(req->type == UV_POLL_REQ);
+
+  if (req == &handle->poll_req_1) {
+    events = handle->submitted_events_1;
+  } else if (req == &handle->poll_req_2) {
+    events = handle->submitted_events_2;
+  } else {
+    assert(0);
+  }
+
+  if (handle->events & UV_READABLE) {
+    rfds.fd_count = 1;
+    rfds.fd_array[0] = handle->socket;
+  } else {
+    rfds.fd_count = 0;
+  }
+
+  if (handle->events & UV_WRITABLE) {
+    wfds.fd_count = 1;
+    wfds.fd_array[0] = handle->socket;
+    efds.fd_count = 1;
+    efds.fd_array[0] = handle->socket;
+  } else {
+    wfds.fd_count = 0;
+    efds.fd_count = 0;
+  }
+
+  /* Make the select() time out after 3 minutes. If select() hangs because */
+  /* the user closed the socket, we will at least not hang indefinitely. */
+  timeout.tv_sec = 3 * 60;
+  timeout.tv_usec = 0;
+
+  r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout);
+  if (r == SOCKET_ERROR) {
+    /* Queue this req, reporting an error. */
+    SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError());
+    POST_COMPLETION_FOR_REQ(handle->loop, req);
+    return 0;
+  }
+
+  reported_events = 0;
+
+  if (r > 0) {
+    if (rfds.fd_count > 0) {
+      assert(rfds.fd_count == 1);
+      assert(rfds.fd_array[0] == handle->socket);
+      reported_events |= UV_READABLE;
+    }
+
+    if (wfds.fd_count > 0) {
+      assert(wfds.fd_count == 1);
+      assert(wfds.fd_array[0] == handle->socket);
+      reported_events |= UV_WRITABLE;
+    } else if (efds.fd_count > 0) {
+      assert(efds.fd_count == 1);
+      assert(efds.fd_array[0] == handle->socket);
+      reported_events |= UV_WRITABLE;
+    }
+  }
+
+  SET_REQ_SUCCESS(req);
+  req->overlapped.InternalHigh = (DWORD) reported_events;
+  POST_COMPLETION_FOR_REQ(handle->loop, req);
+
+  return 0;
+}
+
+
+static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+  uv_req_t* req;
+
+  /* Find a yet unsubmitted req to submit. */
+  if (handle->submitted_events_1 == 0) {
+    req = &handle->poll_req_1;
+    handle->submitted_events_1 = handle->events;
+    handle->mask_events_1 = 0;
+    handle->mask_events_2 = handle->events;
+  } else if (handle->submitted_events_2 == 0) {
+    req = &handle->poll_req_2;
+    handle->submitted_events_2 = handle->events;
+    handle->mask_events_1 = handle->events;
+    handle->mask_events_2 = 0;
+  } else {
+    assert(0);
+  }
+
+  if (!QueueUserWorkItem(uv__slow_poll_thread_proc,
+                         (void*) req,
+                         WT_EXECUTELONGFUNCTION)) {
+    /* Make this req pending, reporting an error. */
+    SET_REQ_ERROR(req, GetLastError());
+    uv_insert_pending_req(loop, req);
+  }
+}
+
+
+
+static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+    uv_req_t* req) {
+  unsigned char mask_events;
+  if (req == &handle->poll_req_1) {
+    handle->submitted_events_1 = 0;
+    mask_events = handle->mask_events_1;
+  } else if (req == &handle->poll_req_2) {
+    handle->submitted_events_2 = 0;
+    mask_events = handle->mask_events_2;
+  } else {
+    assert(0);
+  }
+
+  if (!REQ_SUCCESS(req)) {
+    /* Error. */
+    if (handle->events != 0) {
+      handle->events = 0; /* Stop the watcher */
+      uv__set_sys_error(loop, GET_REQ_ERROR(req));
+      handle->poll_cb(handle, -1, 0);
+    }
+  } else {
+    /* Got some events. */
+    int events = req->overlapped.InternalHigh & handle->events & ~mask_events;
+    if (events != 0) {
+      handle->poll_cb(handle, 0, events);
+    }
+  }
+
+  if ((handle->events & ~(handle->submitted_events_1 |
+      handle->submitted_events_2)) != 0) {
+    uv__slow_poll_submit_poll_req(loop, handle);
+  } else if ((handle->flags & UV_HANDLE_CLOSING) &&
+             handle->submitted_events_1 == 0 &&
+             handle->submitted_events_2 == 0) {
+    uv_want_endgame(loop, (uv_handle_t*) handle);
+  }
+}
+
+
+static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
+  assert(handle->type == UV_POLL);
+  assert(!(handle->flags & UV_HANDLE_CLOSING));
+  assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
+
+  handle->events = events;
+
+  if (handle->events != 0) {
+    uv__handle_start(handle);
+  } else {
+    uv__handle_stop(handle);
+  }
+
+  if ((handle->events &
+      ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) {
+    uv__slow_poll_submit_poll_req(handle->loop, handle);
+  }
+
+  return 0;
+}
+
+
+static void uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+  handle->events = 0;
+  uv__handle_start(handle);
+
+  if (handle->submitted_events_1 == 0 &&
+      handle->submitted_events_2 == 0) {
+    uv_want_endgame(loop, (uv_handle_t*) handle);
+  }
+}
+
+
+int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
+  return uv_poll_init_socket(loop, handle, (SOCKET) _get_osfhandle(fd));
+}
+
+
+int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
+    uv_os_sock_t socket) {
+  WSAPROTOCOL_INFOW protocol_info;
+  int len;
+  SOCKET peer_socket, base_socket;
+  DWORD bytes;
+
+  /* Try to obtain a base handle for the socket. This increases this chances */
+  /* that we find an AFD handle and are able to use the fast poll mechanism. */
+  /* This will always fail on windows XP/2k3, since they don't support the */
+  /* SIO_BASE_HANDLE ioctl. */
+#ifndef NDEBUG
+  base_socket = INVALID_SOCKET;
+#endif
+
+  if (WSAIoctl(socket,
+               SIO_BASE_HANDLE,
+               NULL,
+               0,
+               &base_socket,
+               sizeof base_socket,
+               &bytes,
+               NULL,
+               NULL) == 0) {
+    assert(base_socket != 0 && base_socket != INVALID_SOCKET);
+    socket = base_socket;
+  }
+
+  uv_handle_init(loop, (uv_handle_t*) handle);
+  handle->type = UV_POLL;
+  handle->socket = socket;
+  handle->events = 0;
+
+  /* Obtain protocol information about the socket. */
+  len = sizeof protocol_info;
+  if (getsockopt(socket,
+                 SOL_SOCKET,
+                 SO_PROTOCOL_INFOW,
+                 (char*) &protocol_info,
+                 &len) != 0) {
+    uv__set_sys_error(loop, WSAGetLastError());
+    return -1;
+  }
+
+  /* Get the peer socket that is needed to enable fast poll. If the returned */
+  /* value is NULL, the protocol is not implemented by MSAFD and we'll have */
+  /* to use slow mode. */
+  peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
+
+  if (peer_socket != INVALID_SOCKET) {
+    /* Initialize fast poll specific fields. */
+    handle->peer_socket = peer_socket;
+  } else {
+    /* Initialize slow poll specific fields. */
+    handle->flags |= UV_HANDLE_POLL_SLOW;
+  }
+
+  /* Intialize 2 poll reqs. */
+  handle->submitted_events_1 = 0;
+  uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1));
+  handle->poll_req_1.type = UV_POLL_REQ;
+  handle->poll_req_1.data = handle;
+
+  handle->submitted_events_2 = 0;
+  uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2));
+  handle->poll_req_2.type = UV_POLL_REQ;
+  handle->poll_req_2.data = handle;
+
+  loop->counters.poll_init++;
+
+  return 0;
+}
+
+
+int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
+  if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+    if (uv__fast_poll_set(handle->loop, handle, events) < 0)
+      return -1;
+  } else {
+    if (uv__slow_poll_set(handle->loop, handle, events) < 0)
+      return -1;
+  }
+
+  handle->poll_cb = cb;
+
+  return 0;
+}
+
+
+int uv_poll_stop(uv_poll_t* handle) {
+  if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+    return uv__fast_poll_set(handle->loop, handle, 0);
+  } else {
+    return uv__slow_poll_set(handle->loop, handle, 0);
+  }
+}
+
+
+void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
+  if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+    uv__fast_poll_process_poll_req(loop, handle, req);
+  } else {
+    uv__slow_poll_process_poll_req(loop, handle, req);
+  }
+}
+
+
+void uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+  if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+    uv__fast_poll_close(loop, handle);
+  } else {
+    uv__slow_poll_close(loop, handle);
+  }
+}
+
+
+void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
+  assert(handle->flags & UV_HANDLE_CLOSING);
+  assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+  assert(handle->submitted_events_1 == 0);
+  assert(handle->submitted_events_2 == 0);
+
+  handle->flags |= UV_HANDLE_CLOSED;
+  uv__handle_stop(handle);
+
+  if (handle->close_cb) {
+    handle->close_cb((uv_handle_t*)handle);
+  }
+}
index aacb061..481b945 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
 #include <stdio.h>
@@ -55,9 +54,8 @@ typedef struct env_var {
 
 
 static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
+  uv_handle_init(loop, (uv_handle_t*) handle);
   handle->type = UV_PROCESS;
-  handle->loop = loop;
-  handle->flags = 0;
   handle->exit_cb = NULL;
   handle->pid = 0;
   handle->exit_signal = 0;
@@ -77,8 +75,6 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
 
   loop->counters.handle_init++;
   loop->counters.process_init++;
-
-  uv_ref(loop);
 }
 
 
@@ -689,30 +685,28 @@ static void close_child_stdio(uv_process_t* process) {
 void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
   DWORD exit_code;
 
+  /* FIXME: race condition. */
+  if (handle->flags & UV_HANDLE_CLOSING) {
+    return;
+  }
+
   /* Unregister from process notification. */
   if (handle->wait_handle != INVALID_HANDLE_VALUE) {
     UnregisterWait(handle->wait_handle);
     handle->wait_handle = INVALID_HANDLE_VALUE;
   }
 
-  if (handle->process_handle != INVALID_HANDLE_VALUE) {
-    /* Get the exit code. */
-    if (!GetExitCodeProcess(handle->process_handle, &exit_code)) {
-      exit_code = 127;
-    }
-
-    /* Clean-up the process handle. */
-    CloseHandle(handle->process_handle);
-    handle->process_handle = INVALID_HANDLE_VALUE;
-  } else {
-    /* We probably left the child stdio handles open to report the error */
-    /* asynchronously, so close them now. */
-    close_child_stdio(handle);
-
-    /* The process never even started in the first place. */
+  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);
+
   /* Fire the exit callback. */
   if (handle->exit_cb) {
     handle->exit_cb(handle, exit_code, handle->exit_signal);
@@ -726,21 +720,9 @@ void uv_process_proc_close(uv_loop_t* loop, uv_process_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));
-    handle->flags |= UV_HANDLE_CLOSED;
-
-    if (handle->close_cb) {
-      handle->close_cb((uv_handle_t*)handle);
-    }
-
-    uv_unref(loop);
-  }
-}
-
-
 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);
@@ -755,6 +737,25 @@ void uv_process_close(uv_loop_t* loop, uv_process_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));
+    handle->flags |= UV_HANDLE_CLOSED;
+    uv__handle_stop(handle);
+
+    /* Clean-up the process handle. */
+    CloseHandle(handle->process_handle);
+
+    /* Clean up the child stdio ends that may have been left open. */
+    close_child_stdio(handle);
+
+    if (handle->close_cb) {
+      handle->close_cb((uv_handle_t*)handle);
+    }
+  }
+}
+
+
 static int uv_create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
     HANDLE* child_pipe,  DWORD server_access, DWORD child_access,
     int overlapped) {
@@ -816,7 +817,7 @@ static int uv_create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
 done:
   if (err) {
     if (server_pipe->handle != INVALID_HANDLE_VALUE) {
-      close_pipe(server_pipe, NULL, NULL);
+      uv_pipe_cleanup(loop, server_pipe);
     }
 
     if (*child_pipe != INVALID_HANDLE_VALUE) {
@@ -1058,7 +1059,12 @@ done:
     }
   }
 
-  if (err) {
+  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;
index 65aa6c1..1aae709 100644 (file)
@@ -22,7 +22,6 @@
 #include <assert.h>
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
 
@@ -135,6 +134,10 @@ void uv_process_reqs(uv_loop_t* loop) {
         uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
         break;
 
+      case UV_POLL_REQ:
+        uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
+        break;
+
       case UV_ARES_EVENT_REQ:
         uv_process_ares_event_req(loop, (uv_ares_action_t*) req->data, req);
         break;
@@ -143,8 +146,8 @@ void uv_process_reqs(uv_loop_t* loop) {
         uv_process_ares_cleanup_req(loop, (uv_ares_task_t*) req->data, req);
         break;
 
-      case UV_GETADDRINFO_REQ:
-        uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req->data, req);
+      case UV_GETADDRINFO:
+        uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req);
         break;
 
       case UV_PROCESS_EXIT:
index 4275bce..dad8669 100644 (file)
 #include <assert.h>
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
 
 void uv_stream_init(uv_loop_t* loop, uv_stream_t* handle) {
+  uv_handle_init(loop, (uv_handle_t*) handle);
   handle->write_queue_size = 0;
-  handle->loop = loop;
-  handle->flags = 0;
+  handle->activecnt = 0;
 
-  loop->counters.handle_init++;
   loop->counters.stream_init++;
-
-  uv_ref(loop);
 }
 
 
@@ -109,8 +105,11 @@ int uv_read2_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
 int uv_read_stop(uv_stream_t* handle) {
   if (handle->type == UV_TTY) {
     return uv_tty_read_stop((uv_tty_t*) handle);
-  } else {
+  } else if (handle->flags & UV_HANDLE_READING) {
     handle->flags &= ~UV_HANDLE_READING;
+    DECREASE_ACTIVE_COUNT(handle->loop, handle);
+    return 0;
+  } else {
     return 0;
   }
 }
@@ -171,7 +170,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
   handle->flags |= UV_HANDLE_SHUTTING;
   handle->shutdown_req = req;
   handle->reqs_pending++;
-  uv_ref(loop);
+  REGISTER_HANDLE_REQ(loop, handle, req);
 
   uv_want_endgame(loop, (uv_handle_t*)handle);
 
index 51ef604..fd956a0 100644 (file)
@@ -22,7 +22,6 @@
 #include <assert.h>
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
 
@@ -143,12 +142,12 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle,
 
 
 int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
-  uv_stream_init(loop, (uv_stream_t*)handle);
+  uv_stream_init(loop, (uv_stream_t*) handle);
 
+  handle->type = UV_TCP;
   handle->accept_reqs = NULL;
   handle->pending_accepts = NULL;
   handle->socket = INVALID_SOCKET;
-  handle->type = UV_TCP;
   handle->reqs_pending = 0;
   handle->func_acceptex = NULL;
   handle->func_connectex = NULL;
@@ -170,6 +169,8 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
       handle->shutdown_req != NULL &&
       handle->write_reqs_pending == 0) {
 
+    UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req);
+
     if (handle->flags & UV_HANDLE_CLOSING) {
       status = -1;
       sys_error = WSAEINTR;
@@ -180,6 +181,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
       status = -1;
       sys_error = WSAGetLastError();
     }
+
     if (handle->shutdown_req->cb) {
       if (status == -1) {
         uv__set_sys_error(loop, sys_error);
@@ -188,8 +190,6 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
     }
 
     handle->shutdown_req = NULL;
-
-    uv_unref(loop);
     DECREASE_PENDING_REQ_COUNT(handle);
     return;
   }
@@ -198,6 +198,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
       handle->reqs_pending == 0) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     handle->flags |= UV_HANDLE_CLOSED;
+    uv__handle_stop(handle);
 
     if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) {
       closesocket(handle->socket);
@@ -240,8 +241,6 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
     }
 
     loop->active_tcp_streams--;
-
-    uv_unref(loop);
   }
 }
 
@@ -310,10 +309,10 @@ int uv__tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) {
 
 
 static void CALLBACK post_completion(void* context, BOOLEAN timed_out) {
-  uv_tcp_accept_t* req;
+  uv_req_t* req;
   uv_tcp_t* handle;
 
-  req = (uv_tcp_accept_t*) context;
+  req = (uv_req_t*) context;
   assert(req != NULL);
   handle = (uv_tcp_t*)req->data;
   assert(handle != NULL);
@@ -328,6 +327,25 @@ static void CALLBACK post_completion(void* context, BOOLEAN timed_out) {
 }
 
 
+static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) {
+  uv_write_t* req;
+  uv_tcp_t* handle;
+
+  req = (uv_write_t*) context;
+  assert(req != NULL);
+  handle = (uv_tcp_t*)req->handle;
+  assert(handle != NULL);
+  assert(!timed_out);
+
+  if (!PostQueuedCompletionStatus(handle->loop->iocp,
+                                  req->overlapped.InternalHigh,
+                                  0,
+                                  &req->overlapped)) {
+    uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+  }
+}
+
+
 static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
   uv_loop_t* loop = handle->loop;
   BOOL success;
@@ -381,7 +399,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
     if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
         req->wait_handle == INVALID_HANDLE_VALUE &&
         !RegisterWaitForSingleObject(&req->wait_handle,
-          req->overlapped.hEvent, post_completion, (void*) req,
+          req->event_handle, post_completion, (void*) req,
           INFINITE, WT_EXECUTEINWAITTHREAD)) {
       SET_REQ_ERROR(req, GetLastError());
       uv_insert_pending_req(loop, (uv_req_t*)req);
@@ -460,7 +478,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
     if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
         req->wait_handle == INVALID_HANDLE_VALUE &&
         !RegisterWaitForSingleObject(&req->wait_handle,
-          req->overlapped.hEvent, post_completion, (void*) req,
+          req->event_handle, post_completion, (void*) req,
           INFINITE, WT_EXECUTEINWAITTHREAD)) {
       SET_REQ_ERROR(req, GetLastError());
       uv_insert_pending_req(loop, (uv_req_t*)req);
@@ -481,6 +499,15 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
 
   assert(backlog > 0);
 
+  if (handle->flags & UV_HANDLE_LISTENING) {
+    handle->connection_cb = cb;
+  }
+
+  if (handle->flags & UV_HANDLE_READING) {
+    uv__set_artificial_error(loop, UV_EISCONN);
+    return -1;
+  }
+
   if (handle->flags & UV_HANDLE_BIND_ERROR) {
     uv__set_sys_error(loop, handle->bind_error);
     return -1;
@@ -505,6 +532,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
 
   handle->flags |= UV_HANDLE_LISTENING;
   handle->connection_cb = cb;
+  INCREASE_ACTIVE_COUNT(loop, handle);
 
   simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1
     : uv_simultaneous_server_accepts;
@@ -623,6 +651,7 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
   handle->flags |= UV_HANDLE_READING;
   handle->read_cb = read_cb;
   handle->alloc_cb = alloc_cb;
+  INCREASE_ACTIVE_COUNT(loop, handle);
 
   /* If reading was stopped and then started again, there could still be a */
   /* read request pending. */
@@ -683,12 +712,12 @@ int uv__tcp_connect(uv_connect_t* req,
   if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
     /* Process the req without IOCP. */
     handle->reqs_pending++;
-    uv_ref(loop);
+    REGISTER_HANDLE_REQ(loop, handle, req);
     uv_insert_pending_req(loop, (uv_req_t*)req);
   } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
     /* The req will be processed with IOCP. */
     handle->reqs_pending++;
-    uv_ref(loop);
+    REGISTER_HANDLE_REQ(loop, handle, req);
   } else {
     uv__set_sys_error(loop, WSAGetLastError());
     return -1;
@@ -744,11 +773,11 @@ int uv__tcp_connect6(uv_connect_t* req,
 
   if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
     handle->reqs_pending++;
-    uv_ref(loop);
+    REGISTER_HANDLE_REQ(loop, handle, req);
     uv_insert_pending_req(loop, (uv_req_t*)req);
   } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
     handle->reqs_pending++;
-    uv_ref(loop);
+    REGISTER_HANDLE_REQ(loop, handle, req);
   } else {
     uv__set_sys_error(loop, WSAGetLastError());
     return -1;
@@ -837,6 +866,7 @@ int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
       uv_fatal_error(GetLastError(), "CreateEvent");
     }
     req->overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+    req->wait_handle = INVALID_HANDLE_VALUE;
   }
 
   result = WSASend(handle->socket,
@@ -852,20 +882,19 @@ int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
     req->queued_bytes = 0;
     handle->reqs_pending++;
     handle->write_reqs_pending++;
+    REGISTER_HANDLE_REQ(loop, handle, req);
     uv_insert_pending_req(loop, (uv_req_t*) req);
-    uv_ref(loop);
   } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
     /* Request queued by the kernel. */
     req->queued_bytes = uv_count_bufs(bufs, bufcnt);
     handle->reqs_pending++;
     handle->write_reqs_pending++;
+    REGISTER_HANDLE_REQ(loop, handle, req);
     handle->write_queue_size += req->queued_bytes;
-    uv_ref(loop);
     if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
-        req->wait_handle == INVALID_HANDLE_VALUE &&
         !RegisterWaitForSingleObject(&req->wait_handle,
-          req->overlapped.hEvent, post_completion, (void*) req,
-          INFINITE, WT_EXECUTEINWAITTHREAD)) {
+          req->event_handle, post_write_completion, (void*) req,
+          INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
       SET_REQ_ERROR(req, GetLastError());
       uv_insert_pending_req(loop, (uv_req_t*)req);
     }
@@ -893,6 +922,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
     if ((handle->flags & UV_HANDLE_READING) ||
         !(handle->flags & UV_HANDLE_ZERO_READ)) {
       handle->flags &= ~UV_HANDLE_READING;
+      DECREASE_ACTIVE_COUNT(loop, handle);
       buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
             uv_buf_init(NULL, 0) : handle->read_buffer;
 
@@ -923,8 +953,12 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
         }
       } else {
         /* Connection closed */
-        handle->flags &= ~UV_HANDLE_READING;
+        if (handle->flags & UV_HANDLE_READING) {
+          handle->flags &= ~UV_HANDLE_READING;
+          DECREASE_ACTIVE_COUNT(loop, handle);
+        }
         handle->flags |= UV_HANDLE_EOF;
+
         uv__set_error(loop, UV_EOF, ERROR_SUCCESS);
         buf.base = 0;
         buf.len = 0;
@@ -955,7 +989,9 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
         } else {
           /* Connection closed */
           handle->flags &= ~UV_HANDLE_READING;
+          DECREASE_ACTIVE_COUNT(loop, handle);
           handle->flags |= UV_HANDLE_EOF;
+
           uv__set_error(loop, UV_EOF, ERROR_SUCCESS);
           handle->read_cb((uv_stream_t*)handle, -1, buf);
           break;
@@ -967,16 +1003,18 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
           uv__set_sys_error(loop, WSAEWOULDBLOCK);
           handle->read_cb((uv_stream_t*)handle, 0, buf);
         } else {
+          /* Ouch! serious error. */
+          handle->flags &= ~UV_HANDLE_READING;
+          DECREASE_ACTIVE_COUNT(loop, handle);
+
           if (err == WSAECONNABORTED) {
-            /*
-             * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
-             */
+            /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */
+            /* Unix. */
             uv__set_error(loop, UV_ECONNRESET, err);
           } else {
-            /* Ouch! serious error. */
             uv__set_sys_error(loop, err);
           }
-          handle->flags &= ~UV_HANDLE_READING;
+
           handle->read_cb((uv_stream_t*)handle, -1, buf);
         }
         break;
@@ -1002,14 +1040,14 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
   assert(handle->write_queue_size >= req->queued_bytes);
   handle->write_queue_size -= req->queued_bytes;
 
+  UNREGISTER_HANDLE_REQ(loop, handle, req);
+
   if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
     if (req->wait_handle != INVALID_HANDLE_VALUE) {
       UnregisterWait(req->wait_handle);
-      req->wait_handle = INVALID_HANDLE_VALUE;
     }
     if (req->event_handle) {
       CloseHandle(req->event_handle);
-      req->event_handle = NULL;
     }
   }
 
@@ -1025,7 +1063,6 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
   }
 
   DECREASE_PENDING_REQ_COUNT(handle);
-  uv_unref(loop);
 }
 
 
@@ -1042,6 +1079,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
   if (req->accept_socket == INVALID_SOCKET) {
     if (handle->flags & UV_HANDLE_LISTENING) {
       handle->flags &= ~UV_HANDLE_LISTENING;
+      DECREASE_ACTIVE_COUNT(loop, handle);
       if (handle->connection_cb) {
         uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req));
         handle->connection_cb((uv_stream_t*)handle, -1);
@@ -1079,28 +1117,27 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
     uv_connect_t* req) {
   assert(handle->type == UV_TCP);
 
-  if (req->cb) {
-    if (REQ_SUCCESS(req)) {
-      if (setsockopt(handle->socket,
-                      SOL_SOCKET,
-                      SO_UPDATE_CONNECT_CONTEXT,
-                      NULL,
-                      0) == 0) {
-        uv_connection_init((uv_stream_t*)handle);
-        loop->active_tcp_streams++;
-        ((uv_connect_cb)req->cb)(req, 0);
-      } else {
-        uv__set_sys_error(loop, WSAGetLastError());
-        ((uv_connect_cb)req->cb)(req, -1);
-      }
+  UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+  if (REQ_SUCCESS(req)) {
+    if (setsockopt(handle->socket,
+                    SOL_SOCKET,
+                    SO_UPDATE_CONNECT_CONTEXT,
+                    NULL,
+                    0) == 0) {
+      uv_connection_init((uv_stream_t*)handle);
+      loop->active_tcp_streams++;
+      ((uv_connect_cb)req->cb)(req, 0);
     } else {
-      uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req));
+      uv__set_sys_error(loop, WSAGetLastError());
       ((uv_connect_cb)req->cb)(req, -1);
     }
+  } else {
+    uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req));
+    ((uv_connect_cb)req->cb)(req, -1);
   }
 
   DECREASE_PENDING_REQ_COUNT(handle);
-  uv_unref(loop);
 }
 
 
@@ -1132,7 +1169,7 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
   if (uv_tcp_set_socket(tcp->loop, tcp, socket, 1) != 0) {
     return -1;
   }
-  
+
   tcp->loop->active_tcp_streams++;
   return 0;
 }
@@ -1172,11 +1209,10 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
 }
 
 
-
 int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
     LPWSAPROTOCOL_INFOW protocol_info) {
   if (!(handle->flags & UV_HANDLE_CONNECTION)) {
-    /* 
+    /*
      * We're about to share the socket with another process.  Because
      * this is a listening socket, we assume that the other process will
      * be accepting connections on it.  So, before sharing the socket
@@ -1240,7 +1276,7 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
 }
 
 
-void uv_tcp_close(uv_tcp_t* tcp) {
+void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
   int non_ifs_lsp;
   int close_socket = 1;
 
@@ -1259,7 +1295,7 @@ void uv_tcp_close(uv_tcp_t* tcp) {
         uv_tcp_non_ifs_lsp_ipv4;
 
       if (!non_ifs_lsp) {
-        /* 
+        /*
          * Shared socket with no non-IFS LSPs, request to cancel pending I/O.
          * The socket will be closed inside endgame.
          */
@@ -1269,13 +1305,23 @@ void uv_tcp_close(uv_tcp_t* tcp) {
     }
   }
 
-  tcp->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING);
+  if (tcp->flags & UV_HANDLE_READING) {
+    tcp->flags &= ~UV_HANDLE_READING;
+    DECREASE_ACTIVE_COUNT(loop, tcp);
+  }
+
+  if (tcp->flags & UV_HANDLE_LISTENING) {
+    tcp->flags &= ~UV_HANDLE_LISTENING;
+    DECREASE_ACTIVE_COUNT(loop, tcp);
+  }
 
   if (close_socket) {
     closesocket(tcp->socket);
     tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
   }
 
+  uv__handle_start(tcp);
+
   if (tcp->reqs_pending == 0) {
     uv_want_endgame(tcp->loop, (uv_handle_t*)tcp);
   }
index d6d3ce8..01b8140 100644 (file)
  * IN THE SOFTWARE.
  */
 
+#include <assert.h>
+
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
-#include <assert.h>
+
 
 #define HAVE_SRWLOCK_API() (pTryAcquireSRWLockShared != NULL)
 
index 4fb20d3..e066810 100644 (file)
@@ -61,13 +61,13 @@ int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb,
     return -1;
   }
 
-  uv_ref(loop);
+  uv__req_register(loop, req);
   return 0;
 }
 
 
 void uv_process_work_req(uv_loop_t* loop, uv_work_t* req) {
   assert(req->after_work_cb);
+  uv__req_unregister(loop, req);
   req->after_work_cb(req);
-  uv_unref(loop);
 }
index 555d71e..fbde888 100644 (file)
 #include "internal.h"
 #include "tree.h"
 
+
 #undef NANOSEC
 #define NANOSEC 1000000000
 
 
 /* The resolution of the high-resolution clock. */
-static int64_t uv_ticks_per_msec_ = 0;
 static uint64_t uv_hrtime_frequency_ = 0;
 static uv_once_t uv_hrtime_init_guard_ = UV_ONCE_INIT;
 
@@ -112,16 +112,12 @@ RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare);
 
 
 int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
-  loop->counters.handle_init++;
-  loop->counters.timer_init++;
-
+  uv_handle_init(loop, (uv_handle_t*) handle);
   handle->type = UV_TIMER;
-  handle->loop = loop;
-  handle->flags = 0;
   handle->timer_cb = NULL;
   handle->repeat = 0;
 
-  uv_ref(loop);
+  loop->counters.timer_init++;
 
   return 0;
 }
@@ -131,12 +127,11 @@ void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) {
   if (handle->flags & UV_HANDLE_CLOSING) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     handle->flags |= UV_HANDLE_CLOSED;
+    uv__handle_stop(handle);
 
     if (handle->close_cb) {
       handle->close_cb((uv_handle_t*)handle);
     }
-
-    uv_unref(loop);
   }
 }
 
@@ -153,6 +148,7 @@ int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, int64_t timeout,
   handle->due = loop->time + timeout;
   handle->repeat = repeat;
   handle->flags |= UV_HANDLE_ACTIVE;
+  uv__handle_start(handle);
 
   if (RB_INSERT(uv_timer_tree_s, &loop->timers, handle) != NULL) {
     uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT");
@@ -171,6 +167,7 @@ int uv_timer_stop(uv_timer_t* handle) {
   RB_REMOVE(uv_timer_tree_s, &loop->timers, handle);
 
   handle->flags &= ~UV_HANDLE_ACTIVE;
+  uv__handle_stop(handle);
 
   return 0;
 }
@@ -188,6 +185,7 @@ int uv_timer_again(uv_timer_t* handle) {
   if (handle->flags & UV_HANDLE_ACTIVE) {
     RB_REMOVE(uv_timer_tree_s, &loop->timers, handle);
     handle->flags &= ~UV_HANDLE_ACTIVE;
+    uv__handle_stop(handle);
   }
 
   if (handle->repeat) {
@@ -198,6 +196,7 @@ int uv_timer_again(uv_timer_t* handle) {
     }
 
     handle->flags |= UV_HANDLE_ACTIVE;
+    uv__handle_start(handle);
   }
 
   return 0;
@@ -269,6 +268,7 @@ void uv_process_timers(uv_loop_t* loop) {
     } else {
       /* If non-repeating, mark the timer as inactive. */
       timer->flags &= ~UV_HANDLE_ACTIVE;
+      uv__handle_stop(timer);
     }
 
     timer->timer_cb((uv_timer_t*) timer, 0);
index 5bf90be..bd46215 100644 (file)
@@ -25,7 +25,6 @@
 #include <stdint.h>
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
 
@@ -462,8 +461,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
 
   /* Fetch the number of events  */
   if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) {
-    handle->flags &= ~UV_HANDLE_READING;
     uv__set_sys_error(loop, GetLastError());
+    handle->flags &= ~UV_HANDLE_READING;
+    DECREASE_ACTIVE_COUNT(loop, handle);
     handle->read_cb((uv_stream_t*)handle, -1, uv_null_buf_);
     goto out;
   }
@@ -483,6 +483,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
                              &records_read)) {
         uv__set_sys_error(loop, GetLastError());
         handle->flags &= ~UV_HANDLE_READING;
+        DECREASE_ACTIVE_COUNT(loop, handle);
         handle->read_cb((uv_stream_t*) handle, -1, buf);
         goto out;
       }
@@ -583,6 +584,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
         if (!char_len) {
           uv__set_sys_error(loop, GetLastError());
           handle->flags &= ~UV_HANDLE_READING;
+          DECREASE_ACTIVE_COUNT(loop, handle);
           handle->read_cb((uv_stream_t*) handle, -1, buf);
           goto out;
         }
@@ -691,6 +693,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
         !(handle->flags & UV_HANDLE_TTY_RAW)) {
       /* Real error */
       handle->flags &= ~UV_HANDLE_READING;
+      DECREASE_ACTIVE_COUNT(loop, handle);
       uv__set_sys_error(loop, GET_REQ_ERROR(req));
       handle->read_cb((uv_stream_t*) handle, -1, buf);
     } else {
@@ -738,6 +741,7 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
   uv_loop_t* loop = handle->loop;
 
   handle->flags |= UV_HANDLE_READING;
+  INCREASE_ACTIVE_COUNT(loop, handle);
   handle->read_cb = read_cb;
   handle->alloc_cb = alloc_cb;
 
@@ -762,7 +766,12 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
 
 
 int uv_tty_read_stop(uv_tty_t* handle) {
-  handle->flags &= ~UV_HANDLE_READING;
+  uv_loop_t* loop = handle->loop;
+
+  if (handle->flags & UV_HANDLE_READING) {
+    handle->flags &= ~UV_HANDLE_READING;
+    DECREASE_ACTIVE_COUNT(loop, handle);
+  }
 
   /* Cancel raw read */
   if ((handle->flags & UV_HANDLE_READ_PENDING) &&
@@ -772,7 +781,7 @@ int uv_tty_read_stop(uv_tty_t* handle) {
     DWORD written;
     memset(&record, 0, sizeof record);
     if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
-      uv__set_sys_error(handle->loop, GetLastError());
+      uv__set_sys_error(loop, GetLastError());
       return -1;
     }
   }
@@ -960,9 +969,6 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
 
 static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
     DWORD* error) {
-  unsigned short argc = handle->ansi_csi_argc;
-  unsigned short* argv = handle->ansi_csi_argv;
-
   CONSOLE_SCREEN_BUFFER_INFO info;
   COORD start, end;
   DWORD count, written;
@@ -1683,7 +1689,7 @@ int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
 
   handle->reqs_pending++;
   handle->write_reqs_pending++;
-  uv_ref(loop);
+  REGISTER_HANDLE_REQ(loop, handle, req);
 
   req->queued_bytes = 0;
 
@@ -1703,6 +1709,7 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
   uv_write_t* req) {
 
   handle->write_queue_size -= req->queued_bytes;
+  UNREGISTER_HANDLE_REQ(loop, handle, req);
 
   if (req->cb) {
     uv__set_sys_error(loop, GET_REQ_ERROR(req));
@@ -1716,7 +1723,6 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
   }
 
   DECREASE_PENDING_REQ_COUNT(handle);
-  uv_unref(loop);
 }
 
 
@@ -1726,6 +1732,8 @@ void uv_tty_close(uv_tty_t* handle) {
   uv_tty_read_stop(handle);
   CloseHandle(handle->handle);
 
+  uv__handle_start(handle);
+
   if (handle->reqs_pending == 0) {
     uv_want_endgame(handle->loop, (uv_handle_t*) handle);
   }
@@ -1736,6 +1744,8 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
   if ((handle->flags && UV_HANDLE_CONNECTION) &&
       handle->shutdown_req != NULL &&
       handle->write_reqs_pending == 0) {
+    UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req);
+
     /* TTY shutdown is really just a no-op */
     if (handle->shutdown_req->cb) {
       if (handle->flags & UV_HANDLE_CLOSING) {
@@ -1748,7 +1758,6 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
 
     handle->shutdown_req = NULL;
 
-    uv_unref(loop);
     DECREASE_PENDING_REQ_COUNT(handle);
     return;
   }
@@ -1765,12 +1774,11 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
 
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     handle->flags |= UV_HANDLE_CLOSED;
+    uv__handle_stop(handle);
 
     if (handle->close_cb) {
       handle->close_cb((uv_handle_t*)handle);
     }
-
-    uv_unref(loop);
   }
 }
 
index 42069af..ddd08a2 100644 (file)
@@ -22,7 +22,6 @@
 #include <assert.h>
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
 
@@ -121,11 +120,12 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle,
 
 
 int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
+  uv_handle_init(loop, (uv_handle_t*) handle);
+
   handle->type = UV_UDP;
   handle->socket = INVALID_SOCKET;
   handle->reqs_pending = 0;
-  handle->loop = loop;
-  handle->flags = 0;
+  handle->activecnt = 0;
   handle->func_wsarecv = WSARecv;
   handle->func_wsarecvfrom = WSARecvFrom;
 
@@ -133,26 +133,34 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
   handle->recv_req.type = UV_UDP_RECV;
   handle->recv_req.data = handle;
 
-  uv_ref(loop);
-
-  loop->counters.handle_init++;
   loop->counters.udp_init++;
 
   return 0;
 }
 
 
+void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
+  uv_udp_recv_stop(handle);
+  closesocket(handle->socket);
+
+  uv__handle_start(handle);
+
+  if (handle->reqs_pending == 0) {
+    uv_want_endgame(loop, (uv_handle_t*) handle);
+  }
+}
+
+
 void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
   if (handle->flags & UV_HANDLE_CLOSING &&
       handle->reqs_pending == 0) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     handle->flags |= UV_HANDLE_CLOSED;
+    uv__handle_stop(handle);
 
     if (handle->close_cb) {
       handle->close_cb((uv_handle_t*)handle);
     }
-
-    uv_unref(loop);
   }
 }
 
@@ -350,6 +358,7 @@ int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
   }
 
   handle->flags |= UV_HANDLE_READING;
+  INCREASE_ACTIVE_COUNT(loop, handle);
   loop->active_udp_streams++;
 
   handle->recv_cb = recv_cb;
@@ -368,6 +377,7 @@ int uv_udp_recv_stop(uv_udp_t* handle) {
   if (handle->flags & UV_HANDLE_READING) {
     handle->flags &= ~UV_HANDLE_READING;
     handle->loop->active_udp_streams--;
+    DECREASE_ACTIVE_COUNT(loop, handle);
   }
 
   return 0;
@@ -399,13 +409,13 @@ static int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
     /* Request completed immediately. */
     req->queued_bytes = 0;
     handle->reqs_pending++;
-    uv_ref(loop);
+    REGISTER_HANDLE_REQ(loop, handle, req);
     uv_insert_pending_req(loop, (uv_req_t*)req);
   } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
     /* Request queued by the kernel. */
     req->queued_bytes = uv_count_bufs(bufs, bufcnt);
     handle->reqs_pending++;
-    uv_ref(loop);
+    REGISTER_HANDLE_REQ(loop, handle, req);
   } else {
     /* Send failed due to an error. */
     uv__set_sys_error(loop, WSAGetLastError());
@@ -561,6 +571,8 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
     uv_udp_send_t* req) {
   assert(handle->type == UV_UDP);
 
+  UNREGISTER_HANDLE_REQ(loop, handle, req);
+
   if (req->cb) {
     if (REQ_SUCCESS(req)) {
       req->cb(req, 0);
@@ -570,7 +582,6 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
     }
   }
 
-  uv_unref(loop);
   DECREASE_PENDING_REQ_COUNT(handle);
 }
 
index f4d5fdb..10c2271 100644 (file)
 
 #include "uv.h"
 #include "internal.h"
-#include "tlhelp32.h"
-#include "psapi.h"
-#include "iphlpapi.h"
+
+#include <iphlpapi.h>
+#include <psapi.h>
+#include <tlhelp32.h>
 
 
 /*
index ff6912d..4614a3a 100644 (file)
@@ -22,7 +22,6 @@
 #include <assert.h>
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
 
@@ -33,6 +32,7 @@ sNtSetInformationFile pNtSetInformationFile;
 sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
 sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
 sCreateSymbolicLinkW pCreateSymbolicLinkW;
+sCancelIoEx pCancelIoEx;
 sInitializeSRWLock pInitializeSRWLock;
 sAcquireSRWLockShared pAcquireSRWLockShared;
 sAcquireSRWLockExclusive pAcquireSRWLockExclusive;
@@ -94,6 +94,9 @@ void uv_winapi_init() {
   pCreateSymbolicLinkW = (sCreateSymbolicLinkW)
     GetProcAddress(kernel32_module, "CreateSymbolicLinkW");
 
+  pCancelIoEx = (sCancelIoEx)
+    GetProcAddress(kernel32_module, "CancelIoEx");
+
   pInitializeSRWLock = (sInitializeSRWLock)
     GetProcAddress(kernel32_module, "InitializeSRWLock");
 
index 073b9e8..4b1a249 100644 (file)
@@ -4141,6 +4141,10 @@ typedef struct _FILE_MODE_INFORMATION {
   ULONG Mode;
 } FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION;
 
+typedef struct _FILE_END_OF_FILE_INFORMATION {
+  LARGE_INTEGER  EndOfFile;
+} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION;
+
 #define FILE_SYNCHRONOUS_IO_ALERT               0x00000010
 #define FILE_SYNCHRONOUS_IO_NONALERT            0x00000020
 
@@ -4374,6 +4378,10 @@ typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW)
                  LPCWSTR lpTargetFileName,
                  DWORD dwFlags);
 
+typedef BOOL (WINAPI* sCancelIoEx)
+             (HANDLE hFile,
+              LPOVERLAPPED lpOverlapped);
+
 typedef VOID (WINAPI* sInitializeSRWLock)
              (PSRWLOCK SRWLock);
 
@@ -4408,6 +4416,7 @@ extern sNtSetInformationFile pNtSetInformationFile;
 extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
 extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
 extern sCreateSymbolicLinkW pCreateSymbolicLinkW;
+extern sCancelIoEx pCancelIoEx;
 extern sInitializeSRWLock pInitializeSRWLock;
 extern sAcquireSRWLockShared pAcquireSRWLockShared;
 extern sAcquireSRWLockExclusive pAcquireSRWLockExclusive;
index 667145d..2c3e49a 100644 (file)
@@ -22,9 +22,9 @@
 #include <assert.h>
 
 #include "uv.h"
-#include "../uv-common.h"
 #include "internal.h"
 
+
 /* Whether ipv6 is supported */
 int uv_allow_ipv6;
 
@@ -468,3 +468,90 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
     return SOCKET_ERROR;
   }
 }
+
+
+int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info,
+    OVERLAPPED* overlapped) {
+  IO_STATUS_BLOCK iosb;
+  IO_STATUS_BLOCK* iosb_ptr;
+  HANDLE event = NULL;
+  void* apc_context;
+  NTSTATUS status;
+  DWORD error;
+
+  if (overlapped != NULL) {
+    /* Overlapped operation. */
+    iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
+    event = overlapped->hEvent;
+
+    /* Do not report iocp completion if hEvent is tagged. */
+    if ((uintptr_t) event & 1) {
+      event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
+      apc_context = NULL;
+    } else {
+      apc_context = overlapped;
+    }
+
+  } else {
+    /* Blocking operation. */
+    iosb_ptr = &iosb;
+    event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (event == NULL) {
+      return SOCKET_ERROR;
+    }
+    apc_context = NULL;
+  }
+
+  iosb_ptr->Status = STATUS_PENDING;
+  status = pNtDeviceIoControlFile((HANDLE) socket,
+                                  event,
+                                  NULL,
+                                  apc_context,
+                                  iosb_ptr,
+                                  IOCTL_AFD_POLL,
+                                  info,
+                                  sizeof *info,
+                                  info,
+                                  sizeof *info);
+
+  if (overlapped == NULL) {
+    /* If this is a blocking operation, wait for the event to become */
+    /* signaled, and then grab the real status from the io status block. */
+    if (status == STATUS_PENDING) {
+      DWORD r = WaitForSingleObject(event, INFINITE);
+
+      if (r == WAIT_FAILED) {
+        DWORD saved_error = GetLastError();
+        CloseHandle(event);
+        WSASetLastError(saved_error);
+        return SOCKET_ERROR;
+      }
+
+      status = iosb.Status;
+    }
+
+    CloseHandle(event);
+  }
+
+  switch (status) {
+    case STATUS_SUCCESS:
+      error = ERROR_SUCCESS;
+      break;
+
+    case STATUS_PENDING:
+      error = WSA_IO_PENDING;
+      break;
+
+    default:
+      error = uv_ntstatus_to_winsock_error(status);
+      break;
+  }
+
+  WSASetLastError(error);
+
+  if (error == ERROR_SUCCESS) {
+    return 0;
+  } else {
+    return SOCKET_ERROR;
+  }
+}
index d070d58..957d08e 100644 (file)
 #endif
 
 #ifndef IPV6_V6ONLY
-  #define IPV6_V6ONLY 27
+define IPV6_V6ONLY 27
 #endif
 
 #ifndef IPV6_HOPLIMIT
-  #define IPV6_HOPLIMIT 21
+# define IPV6_HOPLIMIT 21
+#endif
+
+#ifndef SIO_BASE_HANDLE
+# define SIO_BASE_HANDLE 0x48000022
 #endif
 
 /*
 #define AFD_OVERLAPPED   0x00000002
 #define AFD_IMMEDIATE    0x00000004
 
+#define AFD_POLL_RECEIVE_BIT            0
+#define AFD_POLL_RECEIVE                (1 << AFD_POLL_RECEIVE_BIT)
+#define AFD_POLL_RECEIVE_EXPEDITED_BIT  1
+#define AFD_POLL_RECEIVE_EXPEDITED      (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT)
+#define AFD_POLL_SEND_BIT               2
+#define AFD_POLL_SEND                   (1 << AFD_POLL_SEND_BIT)
+#define AFD_POLL_DISCONNECT_BIT         3
+#define AFD_POLL_DISCONNECT             (1 << AFD_POLL_DISCONNECT_BIT)
+#define AFD_POLL_ABORT_BIT              4
+#define AFD_POLL_ABORT                  (1 << AFD_POLL_ABORT_BIT)
+#define AFD_POLL_LOCAL_CLOSE_BIT        5
+#define AFD_POLL_LOCAL_CLOSE            (1 << AFD_POLL_LOCAL_CLOSE_BIT)
+#define AFD_POLL_CONNECT_BIT            6
+#define AFD_POLL_CONNECT                (1 << AFD_POLL_CONNECT_BIT)
+#define AFD_POLL_ACCEPT_BIT             7
+#define AFD_POLL_ACCEPT                 (1 << AFD_POLL_ACCEPT_BIT)
+#define AFD_POLL_CONNECT_FAIL_BIT       8
+#define AFD_POLL_CONNECT_FAIL           (1 << AFD_POLL_CONNECT_FAIL_BIT)
+#define AFD_POLL_QOS_BIT                9
+#define AFD_POLL_QOS                    (1 << AFD_POLL_QOS_BIT)
+#define AFD_POLL_GROUP_QOS_BIT          10
+#define AFD_POLL_GROUP_QOS              (1 << AFD_POLL_GROUP_QOS_BIT)
+
+#define AFD_NUM_POLL_EVENTS             11
+#define AFD_POLL_ALL                    ((1 << AFD_NUM_POLL_EVENTS) - 1)
+
 typedef struct _AFD_RECV_DATAGRAM_INFO {
     LPWSABUF BufferArray;
     ULONG BufferCount;
@@ -105,6 +135,7 @@ typedef struct _AFD_RECV_INFO {
 
 #define AFD_RECEIVE            5
 #define AFD_RECEIVE_DATAGRAM   6
+#define AFD_POLL               9
 
 #define IOCTL_AFD_RECEIVE \
     _AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER)
@@ -112,8 +143,10 @@ typedef struct _AFD_RECV_INFO {
 #define IOCTL_AFD_RECEIVE_DATAGRAM \
     _AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER)
 
-#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+#define IOCTL_AFD_POLL \
+    _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED)
 
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
 typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP {
   /* FIXME: __C89_NAMELESS was removed */
   /* __C89_NAMELESS */ union {
index d75cb8e..09e06e8 100644 (file)
@@ -36,5 +36,6 @@ BENCHMARK_IMPL(sizes) {
   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_process_t: %u bytes\n", (unsigned int) sizeof(uv_process_t));
+  LOGF("uv_poll_t: %u bytes\n", (unsigned int) sizeof(uv_poll_t));
   return 0;
 }
index 5ffa4e0..5941287 100644 (file)
@@ -144,7 +144,7 @@ static int do_packet_storm(int n_senders, int n_receivers) {
   ASSERT(r == 0);
 
   /* Timer should not keep loop alive. */
-  uv_unref(loop);
+  uv_unref((uv_handle_t*)&timeout);
 
   for (i = 0; i < n_receivers; i++) {
     struct sockaddr_in addr;
index 34e566e..78b0f21 100644 (file)
@@ -28,6 +28,9 @@ char executable_path[PATHMAX] = { '\0' };
 
 
 static void log_progress(int total, int passed, int failed, const char* name) {
+  if (total == 0)
+    total = 1;
+
   LOGF("[%% %3d|+ %3d|- %3d]: %s", (passed + failed) / total * 100,
       passed, failed, name);
 }
similarity index 53%
rename from deps/uv/src/unix/idle.c
rename to deps/uv/test/test-callback-order.c
index 5b4cf57..a6c40cb 100644 (file)
@@ -1,4 +1,5 @@
 /* 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
  */
 
 #include "uv.h"
-#include "internal.h"
-
-
-static void uv__idle(EV_P_ ev_idle* w, int revents) {
-  uv_idle_t* idle = container_of(w, uv_idle_t, idle_watcher);
-
-  if (idle->idle_cb) {
-    idle->idle_cb(idle, 0);
-  }
-}
+#include "task.h"
 
+static int idle_cb_called;
+static int timer_cb_called;
 
-int uv_idle_init(uv_loop_t* loop, uv_idle_t* idle) {
-  uv__handle_init(loop, (uv_handle_t*)idle, UV_IDLE);
-  loop->counters.idle_init++;
+static uv_idle_t idle_handle;
+static uv_timer_t timer_handle;
 
-  ev_idle_init(&idle->idle_watcher, uv__idle);
-  idle->idle_cb = NULL;
 
-  return 0;
+/* idle_cb should run before timer_cb */
+static void idle_cb(uv_idle_t* handle, int status) {
+  ASSERT(idle_cb_called == 0);
+  ASSERT(timer_cb_called == 0);
+  uv_idle_stop(handle);
+  idle_cb_called++;
 }
 
 
-int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb) {
-  int was_active = ev_is_active(&idle->idle_watcher);
-
-  idle->idle_cb = cb;
-  ev_idle_start(idle->loop->ev, &idle->idle_watcher);
-
-  if (!was_active) {
-    ev_unref(idle->loop->ev);
-  }
-
-  return 0;
+static void timer_cb(uv_timer_t* handle, int status) {
+  ASSERT(idle_cb_called == 1);
+  ASSERT(timer_cb_called == 0);
+  uv_timer_stop(handle);
+  timer_cb_called++;
 }
 
 
-int uv_idle_stop(uv_idle_t* idle) {
-  int was_active = ev_is_active(&idle->idle_watcher);
+static void next_tick(uv_idle_t* handle, int status) {
+  uv_loop_t* loop = handle->loop;
+  uv_idle_stop(handle);
+  uv_idle_init(loop, &idle_handle);
+  uv_idle_start(&idle_handle, idle_cb);
+  uv_timer_init(loop, &timer_handle);
+  uv_timer_start(&timer_handle, timer_cb, 0, 0);
+}
 
-  ev_idle_stop(idle->loop->ev, &idle->idle_watcher);
 
-  if (was_active) {
-    ev_ref(idle->loop->ev);
-  }
+TEST_IMPL(callback_order) {
+  uv_loop_t* loop;
+  uv_idle_t idle;
 
-  return 0;
-}
+  loop = uv_default_loop();
+  uv_idle_init(loop, &idle);
+  uv_idle_start(&idle, next_tick);
 
+  ASSERT(idle_cb_called == 0);
+  ASSERT(timer_cb_called == 0);
 
-int uv__idle_active(const uv_idle_t* handle) {
-  return ev_is_active(&handle->idle_watcher);
-}
+  uv_run(loop);
 
+  ASSERT(idle_cb_called == 1);
+  ASSERT(timer_cb_called == 1);
 
-void uv__idle_close(uv_idle_t* handle) {
-  uv_idle_stop(handle);
+  return 0;
 }
index 763bfec..877ebf3 100644 (file)
 #include "task.h"
 #include <string.h>
 
-const char* path = "test/fixtures/load_error.node";
-const char* msg;
+
+TEST_IMPL(dlerror) {
+  const char* path = "test/fixtures/load_error.node";
+  const char* msg;
+  uv_lib_t lib;
+  int r;
 
 #ifdef __linux__
   const char* dlerror_desc = "file too short";
@@ -36,14 +40,19 @@ const char* msg;
   const char* dlerror_desc = "";
 #endif
 
-uv_lib_t lib;
-uv_err_t r;
-
-TEST_IMPL(dlerror) {
   r = uv_dlopen(path, &lib);
-  msg = uv_dlerror(lib);
+  ASSERT(r == -1);
+
+  msg = uv_dlerror(&lib);
   ASSERT(msg != NULL);
   ASSERT(strstr(msg, dlerror_desc) != NULL);
-  uv_dlerror_free(lib, msg);
+
+  /* Should return the same error twice in a row. */
+  msg = uv_dlerror(&lib);
+  ASSERT(msg != NULL);
+  ASSERT(strstr(msg, dlerror_desc) != NULL);
+
+  uv_dlclose(&lib);
+
   return 0;
 }
index de3d65b..c7a8f50 100644 (file)
@@ -68,7 +68,6 @@ void idle_cb(uv_idle_t* idle, int status) {
     int r;
 
     r = uv_idle_stop(idle);
-    uv_unref(uv_default_loop());
     ASSERT(r == 0);
   }
 }
index a8fe0ab..be962e8 100644 (file)
@@ -46,6 +46,7 @@
 #endif
 
 #define TOO_LONG_NAME_LENGTH 65536
+#define PATHMAX 1024
 
 typedef struct {
   const char* path;
@@ -1301,6 +1302,115 @@ TEST_IMPL(fs_symlink) {
 }
 
 
+TEST_IMPL(fs_symlink_dir) {
+  uv_fs_t req;
+  int r;
+  char src_path_buf[PATHMAX];
+  char* test_dir;
+
+  /* set-up */
+  unlink("test_dir/file1");
+  unlink("test_dir/file2");
+  rmdir("test_dir");
+  rmdir("test_dir_symlink");
+
+  loop = uv_default_loop();
+
+  uv_fs_mkdir(loop, &req, "test_dir", 0777, NULL);
+  uv_fs_req_cleanup(&req);
+
+#ifdef _WIN32
+  strcpy(src_path_buf, "\\\\?\\");
+  uv_cwd(src_path_buf + 4, sizeof(src_path_buf)/sizeof(src_path_buf[0]));
+  strcat(src_path_buf, "\\test_dir\\");
+  test_dir = src_path_buf;
+#else
+  test_dir = "test_dir";
+#endif
+
+  r = uv_fs_symlink(loop, &req, test_dir, "test_dir_symlink",
+    UV_FS_SYMLINK_JUNCTION, NULL);
+  ASSERT(r == 0);
+  ASSERT(req.result == 0);
+  uv_fs_req_cleanup(&req);
+
+  r = uv_fs_stat(loop, &req, "test_dir_symlink", NULL);
+  ASSERT(r == 0);
+  ASSERT(((struct stat*)req.ptr)->st_mode & S_IFDIR);
+  uv_fs_req_cleanup(&req);
+
+  r = uv_fs_lstat(loop, &req, "test_dir_symlink", NULL);
+  ASSERT(r == 0);
+  ASSERT(((struct stat*)req.ptr)->st_mode & S_IFLNK);
+#ifdef _WIN32
+  ASSERT(((struct stat*)req.ptr)->st_size == strlen(test_dir + 4));
+#else
+  ASSERT(((struct stat*)req.ptr)->st_size == strlen(test_dir));
+#endif
+  uv_fs_req_cleanup(&req);
+
+  r = uv_fs_readlink(loop, &req, "test_dir_symlink", NULL);
+  ASSERT(r == 0);
+#ifdef _WIN32
+  ASSERT(strcmp(req.ptr, test_dir + 4) == 0);
+#else
+  ASSERT(strcmp(req.ptr, test_dir) == 0);
+#endif
+  uv_fs_req_cleanup(&req);
+
+  r = uv_fs_open(loop, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT,
+      S_IWRITE | S_IREAD, NULL);
+  ASSERT(r != -1);
+  uv_fs_req_cleanup(&open_req1);
+  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  ASSERT(r == 0);
+  uv_fs_req_cleanup(&close_req);
+
+  r = uv_fs_open(loop, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT,
+      S_IWRITE | S_IREAD, NULL);
+  ASSERT(r != -1);
+  uv_fs_req_cleanup(&open_req1);
+  r = uv_fs_close(loop, &close_req, open_req1.result, NULL);
+  ASSERT(r == 0);
+  uv_fs_req_cleanup(&close_req);
+
+  r = uv_fs_readdir(loop, &readdir_req, "test_dir_symlink", 0, NULL);
+  ASSERT(r == 2);
+  ASSERT(readdir_req.result == 2);
+  ASSERT(readdir_req.ptr);
+  ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0
+      || memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0);
+  uv_fs_req_cleanup(&readdir_req);
+  ASSERT(!readdir_req.ptr);
+
+  /* unlink will remove the directory symlink */
+  r = uv_fs_unlink(loop, &req, "test_dir_symlink", NULL);
+  ASSERT(r == 0);
+  uv_fs_req_cleanup(&req);
+
+  r = uv_fs_readdir(loop, &readdir_req, "test_dir_symlink", 0, NULL);
+  ASSERT(r == -1);
+  uv_fs_req_cleanup(&readdir_req);
+
+  r = uv_fs_readdir(loop, &readdir_req, "test_dir", 0, NULL);
+  ASSERT(r == 2);
+  ASSERT(readdir_req.result == 2);
+  ASSERT(readdir_req.ptr);
+  ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0
+      || memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0);
+  uv_fs_req_cleanup(&readdir_req);
+  ASSERT(!readdir_req.ptr);
+
+  /* clean-up */
+  unlink("test_dir/file1");
+  unlink("test_dir/file2");
+  rmdir("test_dir");
+  rmdir("test_dir_symlink");
+
+  return 0;
+}
+
+
 TEST_IMPL(fs_utime) {
   utime_check_t checkme;
   const char* path = "test_file";
index 84782b2..86fbad4 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 TEST_DECLARE   (platform_output)
+TEST_DECLARE   (callback_order)
 TEST_DECLARE   (tty)
 TEST_DECLARE   (stdio_over_pipes)
 TEST_DECLARE   (ipc_listen_before_write)
@@ -42,6 +43,8 @@ TEST_DECLARE   (tcp_bind_error_fault)
 TEST_DECLARE   (tcp_bind_error_inval)
 TEST_DECLARE   (tcp_bind_localhost_ok)
 TEST_DECLARE   (tcp_listen_without_bind)
+TEST_DECLARE   (tcp_connect_error_fault)
+TEST_DECLARE   (tcp_connect_timeout)
 TEST_DECLARE   (tcp_close)
 TEST_DECLARE   (tcp_flags)
 TEST_DECLARE   (tcp_write_error)
@@ -89,7 +92,6 @@ TEST_DECLARE   (tcp_ref)
 TEST_DECLARE   (tcp_ref2)
 TEST_DECLARE   (tcp_ref3)
 TEST_DECLARE   (tcp_ref4)
-TEST_DECLARE   (tcp_ref5)
 TEST_DECLARE   (udp_ref)
 TEST_DECLARE   (udp_ref2)
 TEST_DECLARE   (udp_ref3)
@@ -97,7 +99,6 @@ TEST_DECLARE   (pipe_ref)
 TEST_DECLARE   (pipe_ref2)
 TEST_DECLARE   (pipe_ref3)
 TEST_DECLARE   (pipe_ref4)
-TEST_DECLARE   (pipe_ref5)
 TEST_DECLARE   (process_ref)
 TEST_DECLARE   (async)
 TEST_DECLARE   (get_currentexe)
@@ -133,6 +134,7 @@ TEST_DECLARE   (fs_chmod)
 TEST_DECLARE   (fs_chown)
 TEST_DECLARE   (fs_link)
 TEST_DECLARE   (fs_symlink)
+TEST_DECLARE   (fs_symlink_dir)
 TEST_DECLARE   (fs_utime)
 TEST_DECLARE   (fs_futime)
 TEST_DECLARE   (fs_file_open_append)
@@ -159,6 +161,8 @@ TEST_DECLARE   (strlcpy)
 TEST_DECLARE   (strlcat)
 TEST_DECLARE   (counters_init)
 TEST_DECLARE   (dlerror)
+TEST_DECLARE   (poll_duplex)
+TEST_DECLARE   (poll_unidirectional)
 #ifdef _WIN32
 TEST_DECLARE   (spawn_detect_pipe_name_collisions_on_windows)
 TEST_DECLARE   (argument_escaping)
@@ -178,6 +182,7 @@ HELPER_DECLARE (pipe_echo_server)
 TASK_LIST_START
   TEST_OUTPUT_ENTRY  (platform_output)
 
+  TEST_ENTRY  (callback_order)
   TEST_ENTRY  (pipe_connect_bad_name)
   TEST_ENTRY  (pipe_connect_to_file)
 
@@ -213,6 +218,8 @@ TASK_LIST_START
   TEST_ENTRY  (tcp_bind_error_inval)
   TEST_ENTRY  (tcp_bind_localhost_ok)
   TEST_ENTRY  (tcp_listen_without_bind)
+  TEST_ENTRY  (tcp_connect_error_fault)
+  TEST_ENTRY  (tcp_connect_timeout)
   TEST_ENTRY  (tcp_close)
   TEST_ENTRY  (tcp_flags)
   TEST_ENTRY  (tcp_write_error)
@@ -273,8 +280,6 @@ TASK_LIST_START
   TEST_HELPER (tcp_ref3, tcp4_echo_server)
   TEST_ENTRY  (tcp_ref4)
   TEST_HELPER (tcp_ref4, tcp4_echo_server)
-  TEST_ENTRY  (tcp_ref5)
-  TEST_HELPER (tcp_ref5, tcp4_echo_server)
   TEST_ENTRY  (udp_ref)
   TEST_ENTRY  (udp_ref2)
   TEST_ENTRY  (udp_ref3)
@@ -285,8 +290,6 @@ TASK_LIST_START
   TEST_HELPER (pipe_ref3, pipe_echo_server)
   TEST_ENTRY  (pipe_ref4)
   TEST_HELPER (pipe_ref4, pipe_echo_server)
-  TEST_ENTRY  (pipe_ref5)
-  TEST_HELPER (pipe_ref5, pipe_echo_server)
   TEST_ENTRY  (process_ref)
 
   TEST_ENTRY  (loop_handles)
@@ -314,6 +317,9 @@ TASK_LIST_START
   TEST_ENTRY  (getsockname_tcp)
   TEST_ENTRY  (getsockname_udp)
 
+  TEST_ENTRY  (poll_duplex)
+  TEST_ENTRY  (poll_unidirectional)
+
   TEST_ENTRY  (spawn_exit_code)
   TEST_ENTRY  (spawn_stdout)
   TEST_ENTRY  (spawn_stdin)
@@ -347,6 +353,7 @@ TASK_LIST_START
   TEST_ENTRY  (fs_utime)
   TEST_ENTRY  (fs_futime)
   TEST_ENTRY  (fs_symlink)
+  TEST_ENTRY  (fs_symlink_dir)
   TEST_ENTRY  (fs_stat_missing_path)
   TEST_ENTRY  (fs_read_file_eof)
   TEST_ENTRY  (fs_file_open_append)
index 866445d..45a41f1 100644 (file)
@@ -323,7 +323,7 @@ TEST_IMPL(loop_handles) {
   ASSERT(r == 0);
   r = uv_timer_start(&timer_handle, timer_cb, TIMEOUT, TIMEOUT);
   ASSERT(r == 0);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&timer_handle);
 
   r = uv_run(uv_default_loop());
   ASSERT(r == 0);
diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c
new file mode 100644 (file)
index 0000000..0033f01
--- /dev/null
@@ -0,0 +1,573 @@
+/* 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 <errno.h>
+
+#ifndef _WIN32
+# include <fcntl.h>
+# include <sys/socket.h>
+# include <unistd.h>
+#endif
+
+#include "uv.h"
+#include "task.h"
+
+
+#define NUM_CLIENTS 5
+#define TRANSFER_BYTES (1 << 16)
+
+#undef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b));
+
+
+typedef enum {
+  UNIDIRECTIONAL,
+  DUPLEX
+} test_mode_t;
+
+typedef struct connection_context_s {
+  uv_poll_t poll_handle;
+  uv_timer_t timer_handle;
+  uv_os_sock_t sock;
+  size_t read, sent;
+  int is_server_connection;
+  int open_handles;
+  int got_fin, sent_fin;
+  unsigned int events, delayed_events;
+} connection_context_t;
+
+typedef struct server_context_s {
+  uv_poll_t poll_handle;
+  uv_os_sock_t sock;
+  int connections;
+} server_context_t;
+
+
+static void delay_timer_cb(uv_timer_t* timer, int status);
+
+
+static test_mode_t test_mode = DUPLEX;
+
+static int closed_connections = 0;
+
+static int valid_writable_wakeups = 0;
+static int spurious_writable_wakeups = 0;
+
+
+static int got_eagain() {
+#ifdef _WIN32
+  return WSAGetLastError() == WSAEWOULDBLOCK;
+#else
+  return errno == EAGAIN
+      || errno == EINPROGRESS
+#ifdef EWOULDBLOCK
+      || errno == EWOULDBLOCK;
+#endif
+      ;
+#endif
+}
+
+
+static void set_nonblocking(uv_os_sock_t sock) {
+  int r;
+#ifdef _WIN32
+  unsigned long on = 1;
+  r = ioctlsocket(sock, FIONBIO, &on);
+  ASSERT(r == 0);
+#else
+  int flags = fcntl(sock, F_GETFL, 0);
+  ASSERT(flags >= 0);
+  r = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+  ASSERT(r >= 0);
+#endif
+}
+
+
+static uv_os_sock_t create_nonblocking_bound_socket(
+    struct sockaddr_in bind_addr) {
+  uv_os_sock_t sock;
+  int r;
+
+  sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+#ifdef _WIN32
+  ASSERT(sock != INVALID_SOCKET);
+#else
+  ASSERT(sock >= 0);
+#endif
+
+  set_nonblocking(sock);
+
+#ifndef _WIN32
+  {
+    /* Allow reuse of the port. */
+    int yes = 1;
+    r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
+    ASSERT(r == 0);
+  }
+#endif
+
+  r = bind(sock, (const struct sockaddr*) &bind_addr, sizeof bind_addr);
+  ASSERT(r == 0);
+
+  return sock;
+}
+
+
+static void close_socket(uv_os_sock_t sock) {
+  int r;
+#ifdef _WIN32
+  r = closesocket(sock);
+#else
+  r = close(sock);
+#endif
+  ASSERT(r == 0);
+}
+
+
+static connection_context_t* create_connection_context(
+    uv_os_sock_t sock, int is_server_connection) {
+  int r;
+  connection_context_t* context;
+
+  context = (connection_context_t*) malloc(sizeof *context);
+  ASSERT(context != NULL);
+
+  context->sock = sock;
+  context->is_server_connection = is_server_connection;
+  context->read = 0;
+  context->sent = 0;
+  context->open_handles = 0;
+  context->events = 0;
+  context->delayed_events = 0;
+  context->got_fin = 0;
+  context->sent_fin = 0;
+
+  r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock);
+  context->open_handles++;
+  context->poll_handle.data = context;
+  ASSERT(r == 0);
+
+  r = uv_timer_init(uv_default_loop(), &context->timer_handle);
+  context->open_handles++;
+  context->timer_handle.data = context;
+  ASSERT(r == 0);
+
+  return context;
+}
+
+
+static void connection_close_cb(uv_handle_t* handle) {
+  connection_context_t* context = (connection_context_t*) handle->data;
+
+  if (--context->open_handles == 0) {
+    if (test_mode == DUPLEX || context->is_server_connection) {
+      ASSERT(context->read == TRANSFER_BYTES);
+    } else {
+      ASSERT(context->read == 0);
+    }
+
+    if (test_mode == DUPLEX || !context->is_server_connection) {
+      ASSERT(context->sent == TRANSFER_BYTES);
+    } else {
+      ASSERT(context->sent == 0);
+    }
+
+    closed_connections++;
+
+    free(context);
+  }
+}
+
+
+static void destroy_connection_context(connection_context_t* context) {
+  uv_close((uv_handle_t*) &context->poll_handle, connection_close_cb);
+  uv_close((uv_handle_t*) &context->timer_handle, connection_close_cb);
+}
+
+
+static void connection_poll_cb(uv_poll_t* handle, int status, int events) {
+  connection_context_t* context = (connection_context_t*) handle->data;
+  int new_events;
+  int r;
+
+  ASSERT(status == 0);
+  ASSERT(events & context->events);
+  ASSERT(!(events & ~context->events));
+
+  new_events = context->events;
+
+  if (events & UV_READABLE) {
+    int action = rand() % 7;
+
+    switch (action) {
+      case 0:
+      case 1: {
+        /* Read a couple of bytes. */
+        static char buffer[74];
+        r = recv(context->sock, buffer, sizeof buffer, 0);
+        ASSERT(r >= 0);
+
+        if (r > 0) {
+          context->read += r;
+        } else {
+          /* Got FIN. */
+          context->got_fin = 1;
+          new_events &= ~UV_READABLE;
+        }
+
+        break;
+      }
+
+      case 2:
+      case 3: {
+        /* Read until EAGAIN. */
+        static char buffer[931];
+        r = recv(context->sock, buffer, sizeof buffer, 0);
+        ASSERT(r >= 0);
+
+        while (r > 0) {
+          context->read += r;
+          r = recv(context->sock, buffer, sizeof buffer, 0);
+        }
+
+        if (r == 0) {
+          /* Got FIN. */
+          context->got_fin = 1;
+          new_events &= ~UV_READABLE;
+        } else {
+          ASSERT(got_eagain());
+        }
+
+        break;
+      }
+
+      case 4:
+        /* Ignore. */
+        break;
+
+      case 5:
+        /* Stop reading for a while. Restart in timer callback. */
+        new_events &= ~UV_READABLE;
+        if (!uv_is_active((uv_handle_t*) &context->timer_handle)) {
+          context->delayed_events = UV_READABLE;
+          uv_timer_start(&context->timer_handle, delay_timer_cb, 10, 0);
+        } else {
+          context->delayed_events |= UV_READABLE;
+        }
+        break;
+
+      case 6:
+        /* Fudge with the event mask. */
+        uv_poll_start(&context->poll_handle, UV_WRITABLE, connection_poll_cb);
+        uv_poll_start(&context->poll_handle, UV_READABLE, connection_poll_cb);
+        context->events = UV_READABLE;
+        break;
+
+      default:
+        ASSERT(0);
+    }
+  }
+
+  if (events & UV_WRITABLE) {
+    if (context->sent < TRANSFER_BYTES &&
+        !(test_mode == UNIDIRECTIONAL && context->is_server_connection)) {
+      /* We have to send more bytes. */
+      int action = rand() % 7;
+
+      switch (action) {
+        case 0:
+        case 1: {
+          /* Send a couple of bytes. */
+          static char buffer[103];
+
+          int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer);
+          ASSERT(send_bytes > 0);
+
+          r = send(context->sock, buffer, send_bytes, 0);
+
+          if (r < 0) {
+            ASSERT(got_eagain());
+            spurious_writable_wakeups++;
+            break;
+          }
+
+          ASSERT(r > 0);
+          context->sent += r;
+          valid_writable_wakeups++;
+          break;
+        }
+
+        case 2:
+        case 3: {
+          /* Send until EAGAIN. */
+          static char buffer[1234];
+
+          int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer);
+          ASSERT(send_bytes > 0);
+
+          r = send(context->sock, buffer, send_bytes, 0);
+
+          if (r < 0) {
+            ASSERT(got_eagain());
+            spurious_writable_wakeups++;
+            break;
+          }
+
+          ASSERT(r > 0);
+          valid_writable_wakeups++;
+          context->sent += r;
+
+          while (context->sent < TRANSFER_BYTES) {
+            send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer);
+            ASSERT(send_bytes > 0);
+
+            r = send(context->sock, buffer, send_bytes, 0);
+
+            if (r <= 0) break;
+            context->sent += r;
+          }
+          ASSERT(r > 0 || got_eagain());
+          break;
+        }
+
+        case 4:
+          /* Ignore. */
+         break;
+
+        case 5:
+          /* Stop sending for a while. Restart in timer callback. */
+          new_events &= ~UV_WRITABLE;
+          if (!uv_is_active((uv_handle_t*) &context->timer_handle)) {
+            context->delayed_events = UV_WRITABLE;
+            uv_timer_start(&context->timer_handle, delay_timer_cb, 100, 0);
+          } else {
+            context->delayed_events |= UV_WRITABLE;
+          }
+          break;
+
+        case 6:
+          /* Fudge with the event mask. */
+          uv_poll_start(&context->poll_handle,
+                        UV_READABLE,
+                        connection_poll_cb);
+          uv_poll_start(&context->poll_handle,
+                        UV_WRITABLE,
+                        connection_poll_cb);
+          context->events = UV_WRITABLE;
+          break;
+
+        default:
+          ASSERT(0);
+      }
+
+    } else {
+      /* Nothing more to write. Send FIN. */
+      int r;
+#ifdef _WIN32
+      r = shutdown(context->sock, SD_SEND);
+#else
+      r = shutdown(context->sock, SHUT_WR);
+#endif
+      ASSERT(r == 0);
+      context->sent_fin = 1;
+      new_events &= ~UV_WRITABLE;
+    }
+  }
+
+  if (context->got_fin && context->sent_fin) {
+    /* Sent and received FIN. Close and destroy context. */
+    close_socket(context->sock);
+    destroy_connection_context(context);
+    context->events = 0;
+
+  } else if (new_events != context->events) {
+    /* Poll mask changed. Call uv_poll_start again. */
+    context->events = new_events;
+    uv_poll_start(handle, new_events, connection_poll_cb);
+  }
+
+  /* Assert that uv_is_active works correctly for poll handles. */
+  if (context->events != 0) {
+    ASSERT(uv_is_active((uv_handle_t*) handle));
+  } else {
+    ASSERT(!uv_is_active((uv_handle_t*) handle));
+  }
+}
+
+
+static void delay_timer_cb(uv_timer_t* timer, int status) {
+  connection_context_t* context = (connection_context_t*) timer->data;
+  int r;
+
+  /* Timer should auto stop. */
+  ASSERT(!uv_is_active((uv_handle_t*) timer));
+
+  /* Add the requested events to the poll mask. */
+  ASSERT(context->delayed_events != 0);
+  context->events |= context->delayed_events;
+  context->delayed_events = 0;
+
+  r = uv_poll_start(&context->poll_handle,
+                    context->events,
+                    connection_poll_cb);
+  ASSERT(r == 0);
+}
+
+
+static server_context_t* create_server_context(
+    uv_os_sock_t sock) {
+  int r;
+  server_context_t* context;
+
+  context = (server_context_t*) malloc(sizeof *context);
+  ASSERT(context != NULL);
+
+  context->sock = sock;
+  context->connections = 0;
+
+  r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock);
+  context->poll_handle.data = context;
+  ASSERT(r == 0);
+
+  return context;
+}
+
+
+static void server_close_cb(uv_handle_t* handle) {
+  server_context_t* context = (server_context_t*) handle->data;
+  free(context);
+}
+
+
+static void destroy_server_context(server_context_t* context) {
+  uv_close((uv_handle_t*) &context->poll_handle, server_close_cb);
+}
+
+
+static void server_poll_cb(uv_poll_t* handle, int status, int events) {
+  server_context_t* server_context = (server_context_t*)
+                                          handle->data;
+  connection_context_t* connection_context;
+  struct sockaddr_in addr;
+  socklen_t addr_len;
+  uv_os_sock_t sock;
+  int r;
+
+  addr_len = sizeof addr;
+  sock = accept(server_context->sock, (struct sockaddr*) &addr, &addr_len);
+#ifdef _WIN32
+  ASSERT(sock != INVALID_SOCKET);
+#else
+  ASSERT(sock >= 0);
+#endif
+
+  set_nonblocking(sock);
+
+  connection_context = create_connection_context(sock, 1);
+  connection_context->events = UV_READABLE | UV_WRITABLE;
+  r = uv_poll_start(&connection_context->poll_handle,
+                    UV_READABLE | UV_WRITABLE,
+                    connection_poll_cb);
+  ASSERT(r == 0);
+
+  if (++server_context->connections == NUM_CLIENTS) {
+    close_socket(server_context->sock);
+    destroy_server_context(server_context);
+  }
+}
+
+
+static void start_server() {
+  uv_os_sock_t sock;
+  server_context_t* context;
+  int r;
+
+  sock = create_nonblocking_bound_socket(uv_ip4_addr("127.0.0.1", TEST_PORT));
+  context = create_server_context(sock);
+
+  r = listen(sock, 100);
+  ASSERT(r == 0);
+
+  r = uv_poll_start(&context->poll_handle, UV_READABLE, server_poll_cb);
+  ASSERT(r == 0);
+}
+
+
+static void start_client() {
+  uv_os_sock_t sock;
+  connection_context_t* context;
+  struct sockaddr_in server_addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
+  int r;
+
+  sock = create_nonblocking_bound_socket(uv_ip4_addr("0.0.0.0", 0));
+  context = create_connection_context(sock, 0);
+
+  context->events = UV_READABLE | UV_WRITABLE;
+  r = uv_poll_start(&context->poll_handle,
+                    UV_READABLE | UV_WRITABLE,
+                    connection_poll_cb);
+  ASSERT(r == 0);
+
+  r = connect(sock, (struct sockaddr*) &server_addr, sizeof server_addr);
+  ASSERT(r == 0 || got_eagain());
+}
+
+
+static void start_poll_test() {
+  int i, r;
+
+#ifdef _WIN32
+  {
+    struct WSAData wsa_data;
+    r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+    ASSERT(r == 0);
+  }
+#endif
+
+  start_server();
+
+  for (i = 0; i < NUM_CLIENTS; i++)
+    start_client();
+
+  r = uv_run(uv_default_loop());
+  ASSERT(r == 0);
+
+  /* Assert that at most one percent of the writable wakeups was spurious. */
+  ASSERT(spurious_writable_wakeups == 0 ||
+         (valid_writable_wakeups + spurious_writable_wakeups) /
+         spurious_writable_wakeups > 100);
+
+  ASSERT(closed_connections == NUM_CLIENTS * 2);
+}
+
+
+TEST_IMPL(poll_duplex) {
+  test_mode = DUPLEX;
+  start_poll_test();
+  return 0;
+}
+
+
+TEST_IMPL(poll_unidirectional) {
+  test_mode = UNIDIRECTIONAL;
+  start_poll_test();
+  return 0;
+}
index cab3a70..cc59aa7 100644 (file)
@@ -32,30 +32,50 @@ static uv_connect_t connect_req;
 
 static char buffer[32767];
 
+static int req_cb_called;
+static int connect_cb_called;
+static int write_cb_called;
+static int shutdown_cb_called;
+
 
 static void fail_cb(void) {
   FATAL("fail_cb should not have been called");
 }
 
 
-static void write_unref_cb(uv_connect_t* req, int status) {
-  uv_buf_t buf = uv_buf_init(buffer, sizeof buffer);
+static void req_cb(uv_handle_t* req, int status) {
+  req_cb_called++;
+}
 
-  ASSERT(req == &connect_req);
-  ASSERT(status == 0);
 
-  uv_write(&write_req, req->handle, &buf, 1, (uv_write_cb) fail_cb);
-  uv_unref(uv_default_loop()); /* uv_write refs the loop */
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+  ASSERT(req == &shutdown_req);
+  shutdown_cb_called++;
 }
 
 
+static void write_cb(uv_write_t* req, int status) {
+  ASSERT(req == &write_req);
+  uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
+  write_cb_called++;
+}
+
 
-static void shutdown_unref_cb(uv_connect_t* req, int status) {
+static void connect_and_write(uv_connect_t* req, int status) {
+  uv_buf_t buf = uv_buf_init(buffer, sizeof buffer);
   ASSERT(req == &connect_req);
   ASSERT(status == 0);
+  uv_write(&write_req, req->handle, &buf, 1, write_cb);
+  connect_cb_called++;
+}
+
 
-  uv_shutdown(&shutdown_req, req->handle, (uv_shutdown_cb) fail_cb);
-  uv_unref(uv_default_loop()); /* uv_shutdown refs the loop */
+
+static void connect_and_shutdown(uv_connect_t* req, int status) {
+  ASSERT(req == &connect_req);
+  ASSERT(status == 0);
+  uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
+  connect_cb_called++;
 }
 
 
@@ -69,7 +89,7 @@ TEST_IMPL(idle_ref) {
   uv_idle_t h;
   uv_idle_init(uv_default_loop(), &h);
   uv_idle_start(&h, NULL);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
@@ -78,7 +98,7 @@ TEST_IMPL(idle_ref) {
 TEST_IMPL(async_ref) {
   uv_async_t h;
   uv_async_init(uv_default_loop(), &h, NULL);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
@@ -88,7 +108,7 @@ TEST_IMPL(prepare_ref) {
   uv_prepare_t h;
   uv_prepare_init(uv_default_loop(), &h);
   uv_prepare_start(&h, NULL);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
@@ -98,17 +118,16 @@ TEST_IMPL(check_ref) {
   uv_check_t h;
   uv_check_init(uv_default_loop(), &h);
   uv_check_start(&h, NULL);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
 
 
-static void prepare_cb(uv_prepare_t* handle, int status) {
-  ASSERT(handle != NULL);
+static void prepare_cb(uv_prepare_t* h, int status) {
+  ASSERT(h != NULL);
   ASSERT(status == 0);
-
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)h);
 }
 
 
@@ -124,7 +143,7 @@ TEST_IMPL(unref_in_prepare_cb) {
 TEST_IMPL(timer_ref) {
   uv_timer_t h;
   uv_timer_init(uv_default_loop(), &h);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
@@ -133,8 +152,8 @@ TEST_IMPL(timer_ref) {
 TEST_IMPL(timer_ref2) {
   uv_timer_t h;
   uv_timer_init(uv_default_loop(), &h);
-  uv_timer_start(&h, (uv_timer_cb) fail_cb, 42, 42);
-  uv_unref(uv_default_loop());
+  uv_timer_start(&h, (uv_timer_cb)fail_cb, 42, 42);
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
@@ -142,8 +161,8 @@ TEST_IMPL(timer_ref2) {
 
 TEST_IMPL(fs_event_ref) {
   uv_fs_event_t h;
-  uv_fs_event_init(uv_default_loop(), &h, ".", (uv_fs_event_cb) fail_cb, 0);
-  uv_unref(uv_default_loop());
+  uv_fs_event_init(uv_default_loop(), &h, ".", (uv_fs_event_cb)fail_cb, 0);
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
@@ -152,7 +171,7 @@ TEST_IMPL(fs_event_ref) {
 TEST_IMPL(tcp_ref) {
   uv_tcp_t h;
   uv_tcp_init(uv_default_loop(), &h);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
@@ -162,7 +181,7 @@ TEST_IMPL(tcp_ref2) {
   uv_tcp_t h;
   uv_tcp_init(uv_default_loop(), &h);
   uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
@@ -172,10 +191,11 @@ TEST_IMPL(tcp_ref3) {
   struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
   uv_tcp_t h;
   uv_tcp_init(uv_default_loop(), &h);
-  uv_tcp_connect(&connect_req, &h, addr, (uv_connect_cb)fail_cb);
-  uv_unref(uv_default_loop());
-  uv_unref(uv_default_loop()); /* connect req refs the loop */
+  uv_tcp_connect(&connect_req, &h, addr, connect_and_shutdown);
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
+  ASSERT(connect_cb_called == 1);
+  ASSERT(shutdown_cb_called == 1);
   return 0;
 }
 
@@ -184,20 +204,12 @@ TEST_IMPL(tcp_ref4) {
   struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
   uv_tcp_t h;
   uv_tcp_init(uv_default_loop(), &h);
-  uv_tcp_connect(&connect_req, &h, addr, write_unref_cb);
-  uv_unref(uv_default_loop());
-  uv_run(uv_default_loop());
-  return 0;
-}
-
-
-TEST_IMPL(tcp_ref5) {
-  struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
-  uv_tcp_t h;
-  uv_tcp_init(uv_default_loop(), &h);
-  uv_tcp_connect(&connect_req, &h, addr, shutdown_unref_cb);
-  uv_unref(uv_default_loop());
+  uv_tcp_connect(&connect_req, &h, addr, connect_and_write);
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
+  ASSERT(connect_cb_called == 1);
+  ASSERT(write_cb_called == 1);
+  ASSERT(shutdown_cb_called == 1);
   return 0;
 }
 
@@ -205,7 +217,7 @@ TEST_IMPL(tcp_ref5) {
 TEST_IMPL(udp_ref) {
   uv_udp_t h;
   uv_udp_init(uv_default_loop(), &h);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
@@ -217,7 +229,7 @@ TEST_IMPL(udp_ref2) {
   uv_udp_init(uv_default_loop(), &h);
   uv_udp_bind(&h, addr, 0);
   uv_udp_recv_start(&h, (uv_alloc_cb)fail_cb, (uv_udp_recv_cb)fail_cb);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
@@ -230,10 +242,10 @@ TEST_IMPL(udp_ref3) {
   uv_udp_t h;
 
   uv_udp_init(uv_default_loop(), &h);
-  uv_udp_send(&req, &h, &buf, 1, addr, (uv_udp_send_cb)fail_cb);
-  uv_unref(uv_default_loop());
-  uv_unref(uv_default_loop()); /* send req refs the loop */
+  uv_udp_send(&req, &h, &buf, 1, addr, (uv_udp_send_cb)req_cb);
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
+  ASSERT(req_cb_called == 1);
 
   return 0;
 }
@@ -242,7 +254,7 @@ TEST_IMPL(udp_ref3) {
 TEST_IMPL(pipe_ref) {
   uv_pipe_t h;
   uv_pipe_init(uv_default_loop(), &h, 0);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
@@ -252,7 +264,7 @@ TEST_IMPL(pipe_ref2) {
   uv_pipe_t h;
   uv_pipe_init(uv_default_loop(), &h, 0);
   uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
   return 0;
 }
@@ -261,10 +273,11 @@ TEST_IMPL(pipe_ref2) {
 TEST_IMPL(pipe_ref3) {
   uv_pipe_t h;
   uv_pipe_init(uv_default_loop(), &h, 0);
-  uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, (uv_connect_cb)fail_cb);
-  uv_unref(uv_default_loop());
-  uv_unref(uv_default_loop()); /* connect req refs the loop */
+  uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_shutdown);
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
+  ASSERT(connect_cb_called == 1);
+  ASSERT(shutdown_cb_called == 1);
   return 0;
 }
 
@@ -272,19 +285,12 @@ TEST_IMPL(pipe_ref3) {
 TEST_IMPL(pipe_ref4) {
   uv_pipe_t h;
   uv_pipe_init(uv_default_loop(), &h, 0);
-  uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, write_unref_cb);
-  uv_unref(uv_default_loop());
-  uv_run(uv_default_loop());
-  return 0;
-}
-
-
-TEST_IMPL(pipe_ref5) {
-  uv_pipe_t h;
-  uv_pipe_init(uv_default_loop(), &h, 0);
-  uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, shutdown_unref_cb);
-  uv_unref(uv_default_loop());
+  uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_write);
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
+  ASSERT(connect_cb_called == 1);
+  ASSERT(write_cb_called == 1);
+  ASSERT(shutdown_cb_called == 1);
   return 0;
 }
 
@@ -312,7 +318,7 @@ TEST_IMPL(process_ref) {
   r = uv_spawn(uv_default_loop(), &h, options);
   ASSERT(r == 0);
 
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&h);
   uv_run(uv_default_loop());
 
   r = uv_process_kill(&h, /* SIGTERM */ 15);
index 98173fe..0a3f04c 100644 (file)
@@ -203,8 +203,8 @@ int stdio_over_pipes_helper() {
   uv_pipe_open(&stdout_pipe, 1);
 
   /* Unref both stdio handles to make sure that all writes complete. */
-  uv_unref(loop);
-  uv_unref(loop);
+  uv_unref((uv_handle_t*)&stdin_pipe);
+  uv_unref((uv_handle_t*)&stdout_pipe);
 
   for (i = 0; i < ARRAY_SIZE(buffers); i++) {
     buf[i] = uv_buf_init((char*)buffers[i], strlen(buffers[i]));
@@ -222,8 +222,8 @@ int stdio_over_pipes_helper() {
   ASSERT(on_pipe_read_called == 0);
   ASSERT(close_cb_called == 0);
 
-  uv_ref(loop);
-  uv_ref(loop);
+  uv_ref((uv_handle_t*)&stdout_pipe);
+  uv_ref((uv_handle_t*)&stdin_pipe);
 
   r = uv_read_start((uv_stream_t*)&stdin_pipe, on_read_alloc,
     on_pipe_read);
index 5da8a84..33f7997 100644 (file)
@@ -88,7 +88,7 @@ static void start_server(uv_loop_t* loop, uv_tcp_t* handle) {
   r = uv_listen((uv_stream_t*)handle, 128, connection_cb);
   ASSERT(r == 0);
 
-  uv_unref(loop);
+  uv_unref((uv_handle_t*)handle);
 }
 
 
diff --git a/deps/uv/test/test-tcp-connect-timeout.c b/deps/uv/test/test-tcp-connect-timeout.c
new file mode 100644 (file)
index 0000000..32b0dff
--- /dev/null
@@ -0,0 +1,85 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int connect_cb_called;
+static int close_cb_called;
+
+static uv_connect_t connect_req;
+static uv_timer_t timer;
+static uv_tcp_t conn;
+
+static void connect_cb(uv_connect_t* req, int status);
+static void timer_cb(uv_timer_t* handle, int status);
+static void close_cb(uv_handle_t* handle);
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+  ASSERT(req == &connect_req);
+  ASSERT(status == -1);
+  connect_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle, int status) {
+  ASSERT(handle == &timer);
+  uv_close((uv_handle_t*)&conn, close_cb);
+  uv_close((uv_handle_t*)&timer, close_cb);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+  ASSERT(handle == (uv_handle_t*)&conn || handle == (uv_handle_t*)&timer);
+  close_cb_called++;
+}
+
+
+/* Verify that connecting to an unreachable address or port doesn't hang
+ * the event loop.
+ */
+TEST_IMPL(tcp_connect_timeout) {
+  struct sockaddr_in addr;
+  int r;
+
+  addr = uv_ip4_addr("8.8.8.8", 9999);
+
+  r = uv_timer_init(uv_default_loop(), &timer);
+  ASSERT(r == 0);
+
+  r = uv_timer_start(&timer, timer_cb, 50, 0);
+  ASSERT(r == 0);
+
+  r = uv_tcp_init(uv_default_loop(), &conn);
+  ASSERT(r == 0);
+
+  r = uv_tcp_connect(&connect_req, &conn, addr, connect_cb);
+  ASSERT(r == 0);
+
+  r = uv_run(uv_default_loop());
+  ASSERT(r == 0);
+
+  return 0;
+}
index c590767..32207dd 100644 (file)
@@ -100,7 +100,7 @@ static void connect_cb(uv_connect_t* req, int status) {
     r = uv_write(&(wr->req), req->handle, &wr->buf, 1, write_cb);
     ASSERT(r == 0);
  
-    if (req->handle->write_queue_size > 0) {
+    if (req->handle->write_queue_size >= size * 2) {
       break;
     }
   }
@@ -161,7 +161,7 @@ TEST_IMPL(tcp_write_error) {
   ASSERT(r == 0);
 
   ASSERT(write_cb_called > 0);
-  ASSERT(write_cb_error_called == 1);
+  ASSERT(write_cb_error_called >= 1);
   ASSERT(tcp_client.write_queue_size == 0);
 
   return 0;
index 9eeee1e..e492c36 100644 (file)
@@ -104,7 +104,7 @@ TEST_IMPL(timer_again) {
   r = uv_timer_again(&dummy);
   ASSERT(r == -1);
   ASSERT(uv_last_error(uv_default_loop()).code == UV_EINVAL);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&dummy);
 
   /* Start timer repeat_1. */
   r = uv_timer_init(uv_default_loop(), &repeat_1);
index 1a0aabd..c961aff 100644 (file)
@@ -114,7 +114,7 @@ TEST_IMPL(timer) {
   ASSERT(r == 0);
   r = uv_timer_stop(&never);
   ASSERT(r == 0);
-  uv_unref(uv_default_loop());
+  uv_unref((uv_handle_t*)&never);
 
   uv_run(uv_default_loop());
 
index 34e652b..4ff650d 100644 (file)
@@ -38,7 +38,7 @@ TEST_IMPL(udp_options) {
   r = uv_udp_init(loop, &h);
   ASSERT(r == 0);
 
-  uv_unref(loop); /* don't keep the loop alive */
+  uv_unref((uv_handle_t*)&h); /* don't keep the loop alive */
 
   r = uv_udp_bind(&h, uv_ip4_addr("0.0.0.0", TEST_PORT), 0);
   ASSERT(r == 0);
index d03ea56..24da3e2 100644 (file)
@@ -47,6 +47,8 @@
         'include/ares.h',
         'include/ares_version.h',
         'include/uv.h',
+        'include/uv-private/ngx-queue.h',
+        'include/uv-private/tree.h',
         'src/uv-common.c',
         'src/uv-common.h',
         'src/ares/ares_cancel.c',
             '_GNU_SOURCE',
           ],
           'sources': [
-            'include/uv-private/tree.h',
             'include/uv-private/uv-win.h',
             'src/ares/config_win32/ares_config.h',
             'src/ares/windows_port.c',
             'src/win/loop-watcher.c',
             'src/win/pipe.c',
             'src/win/thread.c',
+            'src/win/poll.c',
             'src/win/process.c',
             'src/win/req.c',
             'src/win/stream.c',
           'sources': [
             'include/uv-private/eio.h',
             'include/uv-private/ev.h',
-            'include/uv-private/ngx-queue.h',
             'include/uv-private/uv-unix.h',
             'src/unix/async.c',
             'src/unix/cares.c',
-            'src/unix/check.c',
             'src/unix/core.c',
             'src/unix/dl.c',
             'src/unix/eio/ecb.h',
             'src/unix/ev/ev_wrap.h',
             'src/unix/ev/event.h',
             'src/unix/fs.c',
-            'src/unix/idle.c',
             'src/unix/internal.h',
             'src/unix/loop.c',
             'src/unix/pipe.c',
-            'src/unix/prepare.c',
+            'src/unix/poll.c',
             'src/unix/process.c',
             'src/unix/stream.c',
             'src/unix/tcp.c',
         'test/test-async.c',
         'test/test-error.c',
         'test/test-callback-stack.c',
+        'test/test-callback-order.c',
         'test/test-connection-fail.c',
         'test/test-cwd-and-chdir.c',
         'test/test-delayed-accept.c',
         'test/test-pipe-bind-error.c',
         'test/test-pipe-connect-error.c',
         'test/test-platform-output.c',
+        'test/test-poll.c',
         'test/test-process-title.c',
         'test/test-ref.c',
         'test/test-shutdown-close.c',
         'test/test-tcp-close.c',
         'test/test-tcp-flags.c',
         'test/test-tcp-connect-error.c',
+        'test/test-tcp-connect-timeout.c',
         'test/test-tcp-connect6-error.c',
         'test/test-tcp-write-error.c',
         'test/test-tcp-write-to-half-open-connection.c',
index 5d86e64..4930536 100644 (file)
@@ -238,11 +238,6 @@ Object.defineProperty(Socket.prototype, 'bufferSize', {
 Socket.prototype.pause = function() {
   if (this._handle) {
     this._handle.readStop();
-
-    // this adds an undesireable boundary crossing for pipe streams.
-    // the .unref() method is omitted on TCP streams, because it is
-    // unnecessary.
-    if (this._handle.unref) this._handle.unref();
   }
 };
 
@@ -250,11 +245,6 @@ Socket.prototype.pause = function() {
 Socket.prototype.resume = function() {
   if (this._handle) {
     this._handle.readStart();
-
-    // this adds an undesireable boundary crossing for pipe streams.
-    // the .ref() method is omitted on TCP streams, because it is
-    // unnecessary.
-    if (this._handle.ref) this._handle.ref();
   }
 };
 
index 3aedcf4..414eed6 100644 (file)
@@ -55,12 +55,10 @@ inherits(ReadStream, net.Socket);
 exports.ReadStream = ReadStream;
 
 ReadStream.prototype.pause = function() {
-  this._handle.unref();
   return net.Socket.prototype.pause.call(this);
 };
 
 ReadStream.prototype.resume = function() {
-  this._handle.ref();
   return net.Socket.prototype.resume.call(this);
 };
 
index e77de8d..adac00c 100644 (file)
@@ -103,7 +103,7 @@ Handle<Value> FSEventWrap::Start(const Arguments& args) {
   if (r == 0) {
     // Check for persistent argument
     if (!args[1]->IsTrue()) {
-      uv_unref(uv_default_loop());
+      uv_unref(reinterpret_cast<uv_handle_t*>(&wrap->handle_));
     }
     wrap->initialized_ = true;
   } else {
index ba09e20..944631a 100644 (file)
@@ -57,31 +57,8 @@ Handle<Value> HandleWrap::Unref(const Arguments& args) {
 
   UNWRAP(HandleWrap)
 
-  // Calling unnecessarily is a no-op
-  if (wrap->unref) {
-    return v8::Undefined();
-  }
-
-  wrap->unref = true;
-  uv_unref(uv_default_loop());
-
-  return v8::Undefined();
-}
-
-
-// Adds a reference to keep uv alive because of this thing.
-Handle<Value> HandleWrap::Ref(const Arguments& args) {
-  HandleScope scope;
-
-  UNWRAP(HandleWrap)
-
-  // Calling multiple times is a no-op
-  if (!wrap->unref) {
-    return v8::Undefined();
-  }
-
-  wrap->unref = false;
-  uv_ref(uv_default_loop());
+  uv_unref(wrap->handle__);
+  wrap->unref_ = true;
 
   return v8::Undefined();
 }
@@ -93,16 +70,11 @@ Handle<Value> HandleWrap::Close(const Arguments& args) {
   HandleWrap *wrap = static_cast<HandleWrap*>(
       args.Holder()->GetPointerFromInternalField(0));
 
-  if (wrap) {
-    // guard against uninitialized handle or double close
-    if (wrap->handle__ == NULL) return v8::Null();
+  // guard against uninitialized handle or double close
+  if (wrap && wrap->handle__) {
     assert(!wrap->object_.IsEmpty());
     uv_close(wrap->handle__, OnClose);
     wrap->handle__ = NULL;
-
-    HandleWrap::Ref(args);
-
-    wrap->StateChange();
   }
 
   return v8::Null();
@@ -110,7 +82,7 @@ Handle<Value> HandleWrap::Close(const Arguments& args) {
 
 
 HandleWrap::HandleWrap(Handle<Object> object, uv_handle_t* h) {
-  unref = false;
+  unref_ = false;
   handle__ = h;
   if (h) {
     h->data = this;
index c6dd4c9..35853a0 100644 (file)
@@ -51,14 +51,12 @@ class HandleWrap {
     static void Initialize(v8::Handle<v8::Object> target);
     static v8::Handle<v8::Value> Close(const v8::Arguments& args);
     static v8::Handle<v8::Value> Unref(const v8::Arguments& args);
-    static v8::Handle<v8::Value> Ref(const v8::Arguments& args);
 
   protected:
     HandleWrap(v8::Handle<v8::Object> object, uv_handle_t* handle);
     virtual ~HandleWrap();
 
     virtual void SetHandle(uv_handle_t* h);
-    virtual void StateChange() {}
 
     v8::Persistent<v8::Object> object_;
 
@@ -69,7 +67,7 @@ class HandleWrap {
     // Using double underscore due to handle_ member in tcp_wrap. Probably
     // tcp_wrap should rename it's member to 'handle'.
     uv_handle_t* handle__;
-    bool unref;
+    bool unref_;
 };
 
 
index d6cb9ae..5db4d86 100644 (file)
@@ -229,12 +229,9 @@ static void Check(uv_check_t* watcher, int status) {
 static void Tick(void) {
   // Avoid entering a V8 scope.
   if (!need_tick_cb) return;
-
   need_tick_cb = false;
-  if (uv_is_active((uv_handle_t*) &tick_spinner)) {
-    uv_idle_stop(&tick_spinner);
-    uv_unref(uv_default_loop());
-  }
+
+  uv_idle_stop(&tick_spinner);
 
   HandleScope scope;
 
@@ -270,10 +267,7 @@ static void StartTickSpinner() {
   // there is nothing left to do in the event loop and libev will exit. The
   // ev_prepare callback isn't called before exiting. Thus we start this
   // tick_spinner to keep the event loop alive long enough to handle it.
-  if (!uv_is_active((uv_handle_t*) &tick_spinner)) {
-    uv_idle_start(&tick_spinner, Spin);
-    uv_ref(uv_default_loop());
-  }
+  uv_idle_start(&tick_spinner, Spin);
 }
 
 static Handle<Value> NeedTickCallback(const Arguments& args) {
@@ -825,20 +819,6 @@ static const char* get_uv_errno_message(int errorno) {
 }
 
 
-static bool get_uv_dlerror_message(uv_lib_t lib, char* error_msg, int size) {
-  int r;
-  const char *msg;
-  if ((msg = uv_dlerror(lib)) == NULL) {
-    r = snprintf(error_msg, size, "%s", "Unable to load shared library ");
-  } else {
-    r = snprintf(error_msg, size, "%s", msg);
-    uv_dlerror_free(lib, msg);
-  }
-  // return bool if the error message be written correctly
-  return (0 < r && r < size);
-}
-
-
 // hack alert! copy of ErrnoException, tuned for uv errors
 Local<Value> UVException(int errorno,
                          const char *syscall,
@@ -1365,7 +1345,7 @@ Handle<Value> GetActiveHandles(const Arguments& args) {
 
   ngx_queue_foreach(q, &handle_wrap_queue) {
     HandleWrap* w = container_of(q, HandleWrap, handle_wrap_queue_);
-    if (w->object_.IsEmpty() || w->unref) continue;
+    if (w->object_.IsEmpty() || w->unref_) continue;
     Local<Value> obj = w->object_->Get(owner_sym);
     if (obj->IsUndefined()) obj = *w->object_;
     ary->Set(i++, obj);
@@ -1726,7 +1706,6 @@ Handle<Value> DLOpen(const v8::Arguments& args) {
   char symbol[1024], *base, *pos;
   uv_lib_t lib;
   node_module_struct compat_mod;
-  uv_err_t err;
   int r;
 
   if (args.Length() < 2) {
@@ -1738,22 +1717,13 @@ Handle<Value> DLOpen(const v8::Arguments& args) {
   String::Utf8Value filename(args[0]); // Cast
   Local<Object> target = args[1]->ToObject(); // Cast
 
-  err = uv_dlopen(*filename, &lib);
-  if (err.code != UV_OK) {
-    // Retrieve uv_dlerror() message and throw exception with it
-    char dlerror_msg[1024];
-    if (!get_uv_dlerror_message(lib, dlerror_msg, sizeof dlerror_msg)) {
-      Local<Value> exception = Exception::Error(
-          String::New("Cannot retrieve an error message in process.dlopen"));
-      return ThrowException(exception);
-    }
-#ifdef __POSIX__
-    Local<Value> exception = Exception::Error(String::New(dlerror_msg));
-#else  // Windows needs to add the filename into the error message
-    Local<Value> exception = Exception::Error(
-        String::Concat(String::New(dlerror_msg), args[0]->ToString()));
+  if (uv_dlopen(*filename, &lib)) {
+    Local<String> errmsg = String::New(uv_dlerror(&lib));
+#ifdef _WIN32
+    // Windows needs to add the filename into the error message
+    errmsg = String::Concat(errmsg, args[0]->ToString());
 #endif
-    return ThrowException(exception);
+    return ThrowException(Exception::Error(errmsg));
   }
 
   String::Utf8Value path(args[0]);
@@ -1791,26 +1761,17 @@ Handle<Value> DLOpen(const v8::Arguments& args) {
 
   // Get the init() function from the dynamically shared object.
   node_module_struct *mod;
-  err = uv_dlsym(lib, symbol, reinterpret_cast<void**>(&mod));
-
-  if (err.code != UV_OK) {
+  if (uv_dlsym(&lib, symbol, reinterpret_cast<void**>(&mod))) {
     /* Start Compatibility hack: Remove once everyone is using NODE_MODULE macro */
     memset(&compat_mod, 0, sizeof compat_mod);
 
     mod = &compat_mod;
     mod->version = NODE_MODULE_VERSION;
 
-    err = uv_dlsym(lib, "init", reinterpret_cast<void**>(&mod->register_func));
-    if (err.code != UV_OK) {
-      uv_dlclose(lib);
-
-      const char* message;
-      if (err.code == UV_ENOENT)
-        message = "Module entry point not found.";
-      else
-        message = uv_strerror(err);
-
-      return ThrowException(Exception::Error(String::New(message)));
+    if (uv_dlsym(&lib, "init", reinterpret_cast<void**>(&mod->register_func))) {
+      Local<String> errmsg = String::New(uv_dlerror(&lib));
+      uv_dlclose(&lib);
+      return ThrowException(Exception::Error(errmsg));
     }
     /* End Compatibility hack */
   }
@@ -2779,24 +2740,23 @@ char** Init(int argc, char *argv[]) {
 
   uv_prepare_init(uv_default_loop(), &prepare_tick_watcher);
   uv_prepare_start(&prepare_tick_watcher, PrepareTick);
-  uv_unref(uv_default_loop());
+  uv_unref(reinterpret_cast<uv_handle_t*>(&prepare_tick_watcher));
 
   uv_check_init(uv_default_loop(), &check_tick_watcher);
   uv_check_start(&check_tick_watcher, node::CheckTick);
-  uv_unref(uv_default_loop());
+  uv_unref(reinterpret_cast<uv_handle_t*>(&check_tick_watcher));
 
   uv_idle_init(uv_default_loop(), &tick_spinner);
-  uv_unref(uv_default_loop());
 
   uv_check_init(uv_default_loop(), &gc_check);
   uv_check_start(&gc_check, node::Check);
-  uv_unref(uv_default_loop());
+  uv_unref(reinterpret_cast<uv_handle_t*>(&gc_check));
 
   uv_idle_init(uv_default_loop(), &gc_idle);
-  uv_unref(uv_default_loop());
+  uv_unref(reinterpret_cast<uv_handle_t*>(&gc_idle));
 
   uv_timer_init(uv_default_loop(), &gc_timer);
-  uv_unref(uv_default_loop());
+  uv_unref(reinterpret_cast<uv_handle_t*>(&gc_timer));
 
   V8::SetFatalErrorHandler(node::OnFatalError);
 
index 39b21a6..2ae74ec 100644 (file)
@@ -84,7 +84,6 @@ void PipeWrap::Initialize(Handle<Object> target) {
 
   NODE_SET_PROTOTYPE_METHOD(t, "close", HandleWrap::Close);
   NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref);
-  NODE_SET_PROTOTYPE_METHOD(t, "ref", HandleWrap::Ref);
 
   NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart);
   NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop);
index 43702f3..c51083c 100644 (file)
@@ -54,7 +54,6 @@ class StreamWrap : public HandleWrap {
 
  protected:
   StreamWrap(v8::Handle<v8::Object> object, uv_stream_t* stream);
-  virtual ~StreamWrap() { }
   virtual void SetHandle(uv_handle_t* h);
   void StateChange() { }
   void UpdateWriteQueueSize();
index acc8b5a..4332a68 100644 (file)
@@ -80,36 +80,12 @@ class TimerWrap : public HandleWrap {
 
   TimerWrap(Handle<Object> object)
       : HandleWrap(object, (uv_handle_t*) &handle_) {
-    active_ = false;
-
     int r = uv_timer_init(uv_default_loop(), &handle_);
     assert(r == 0);
-
     handle_.data = this;
-
-    // uv_timer_init adds a loop reference. (That is, it calls uv_ref.) This
-    // is not the behavior we want in Node. Timers should not increase the
-    // ref count of the loop except when active.
-    uv_unref(uv_default_loop());
   }
 
   ~TimerWrap() {
-    if (!active_) uv_ref(uv_default_loop());
-  }
-
-  void StateChange() {
-    bool was_active = active_;
-    active_ = uv_is_active((uv_handle_t*) &handle_);
-
-    if (!was_active && active_) {
-      // If our state is changing from inactive to active, we
-      // increase the loop's reference count.
-      uv_ref(uv_default_loop());
-    } else if (was_active && !active_) {
-      // If our state is changing from active to inactive, we
-      // decrease the loop's reference count.
-      uv_unref(uv_default_loop());
-    }
   }
 
   static Handle<Value> Start(const Arguments& args) {
@@ -122,11 +98,8 @@ class TimerWrap : public HandleWrap {
 
     int r = uv_timer_start(&wrap->handle_, OnTimeout, timeout, repeat);
 
-    // Error starting the timer.
     if (r) SetErrno(uv_last_error(uv_default_loop()));
 
-    wrap->StateChange();
-
     return scope.Close(Integer::New(r));
   }
 
@@ -139,8 +112,6 @@ class TimerWrap : public HandleWrap {
 
     if (r) SetErrno(uv_last_error(uv_default_loop()));
 
-    wrap->StateChange();
-
     return scope.Close(Integer::New(r));
   }
 
@@ -153,8 +124,6 @@ class TimerWrap : public HandleWrap {
 
     if (r) SetErrno(uv_last_error(uv_default_loop()));
 
-    wrap->StateChange();
-
     return scope.Close(Integer::New(r));
   }
 
@@ -188,17 +157,11 @@ class TimerWrap : public HandleWrap {
     TimerWrap* wrap = static_cast<TimerWrap*>(handle->data);
     assert(wrap);
 
-    wrap->StateChange();
-
     Local<Value> argv[1] = { Integer::New(status) };
     MakeCallback(wrap->object_, ontimeout_sym, ARRAY_SIZE(argv), argv);
   }
 
   uv_timer_t handle_;
-  // This member is set false initially. When the timer is turned
-  // on uv_ref is called. When the timer is turned off uv_unref is
-  // called. Used to mirror libev semantics.
-  bool active_;
 };
 
 
index 1a9ec56..de43a4f 100644 (file)
@@ -56,7 +56,6 @@ class TTYWrap : StreamWrap {
 
     NODE_SET_PROTOTYPE_METHOD(t, "close", HandleWrap::Close);
     NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref);
-    NODE_SET_PROTOTYPE_METHOD(t, "ref", HandleWrap::Ref);
 
     NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart);
     NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop);