Selaa lähdekoodia

libuv 2019-01-15 (f84c5e69)

Code extracted from:

    https://github.com/libuv/libuv.git

at commit f84c5e693b80cb0c62bcefba147e7a66e2b839c9 (v1.x).
libuv upstream 6 vuotta sitten
vanhempi
sitoutus
4fcb0d0213
94 muutettua tiedostoa jossa 3158 lisäystä ja 2961 poistoa
  1. 0 69
      include/pthread-barrier.h
  2. 70 16
      include/uv.h
  3. 0 0
      include/uv/aix.h
  4. 0 0
      include/uv/android-ifaddrs.h
  5. 0 0
      include/uv/bsd.h
  6. 0 0
      include/uv/darwin.h
  7. 6 0
      include/uv/errno.h
  8. 0 0
      include/uv/linux.h
  9. 0 0
      include/uv/os390.h
  10. 0 0
      include/uv/posix.h
  11. 0 0
      include/uv/stdint-msvc2008.h
  12. 0 0
      include/uv/sunos.h
  13. 0 0
      include/uv/threadpool.h
  14. 0 0
      include/uv/tree.h
  15. 32 14
      include/uv/unix.h
  16. 2 2
      include/uv/version.h
  17. 36 27
      include/uv/win.h
  18. 2 2
      src/fs-poll.c
  19. 291 0
      src/idna.c
  20. 31 0
      src/idna.h
  21. 3 10
      src/inet.c
  22. 17 0
      src/strscpy.c
  23. 18 0
      src/strscpy.h
  24. 81 15
      src/threadpool.c
  25. 15 6
      src/timer.c
  26. 8 2
      src/unix/aix-common.c
  27. 41 22
      src/unix/aix.c
  28. 1 1
      src/unix/android-ifaddrs.c
  29. 14 9
      src/unix/bsd-ifaddrs.c
  30. 93 0
      src/unix/bsd-proctitle.c
  31. 105 31
      src/unix/core.c
  32. 1 1
      src/unix/cygwin.c
  33. 68 79
      src/unix/darwin-proctitle.c
  34. 0 79
      src/unix/freebsd.c
  35. 201 139
      src/unix/fs.c
  36. 37 35
      src/unix/fsevents.c
  37. 21 0
      src/unix/getaddrinfo.c
  38. 1 0
      src/unix/getnameinfo.c
  39. 2 1
      src/unix/ibmi.c
  40. 1 44
      src/unix/internal.h
  41. 41 42
      src/unix/kqueue.c
  42. 50 67
      src/unix/linux-core.c
  43. 5 3
      src/unix/linux-inotify.c
  44. 0 133
      src/unix/linux-syscalls.c
  45. 0 34
      src/unix/linux-syscalls.h
  46. 3 3
      src/unix/loop.c
  47. 2 69
      src/unix/netbsd.c
  48. 0 69
      src/unix/openbsd.c
  49. 20 9
      src/unix/os390-syscalls.c
  50. 0 4
      src/unix/os390-syscalls.h
  51. 22 16
      src/unix/os390.c
  52. 23 8
      src/unix/pipe.c
  53. 3 0
      src/unix/poll.c
  54. 2 2
      src/unix/process.c
  55. 4 0
      src/unix/proctitle.c
  56. 34 25
      src/unix/signal.c
  57. 124 138
      src/unix/stream.c
  58. 12 3
      src/unix/sunos.c
  59. 12 9
      src/unix/tcp.c
  60. 69 77
      src/unix/thread.c
  61. 20 25
      src/unix/tty.c
  62. 15 8
      src/unix/udp.c
  63. 37 7
      src/uv-common.c
  64. 91 36
      src/uv-common.h
  65. 9 7
      src/uv-data-getter-setters.c
  66. 5 5
      src/win/async.c
  67. 4 4
      src/win/atomicops-inl.h
  68. 39 19
      src/win/core.c
  69. 7 4
      src/win/dl.c
  70. 2 2
      src/win/error.c
  71. 14 11
      src/win/fs-event.c
  72. 133 51
      src/win/fs.c
  73. 22 18
      src/win/getaddrinfo.c
  74. 29 21
      src/win/getnameinfo.c
  75. 13 12
      src/win/handle-inl.h
  76. 8 4
      src/win/handle.c
  77. 24 90
      src/win/internal.h
  78. 1 1
      src/win/loop-watcher.c
  79. 399 316
      src/win/pipe.c
  80. 27 28
      src/win/poll.c
  81. 30 29
      src/win/process-stdio.c
  82. 40 30
      src/win/process.c
  83. 0 25
      src/win/req.c
  84. 25 25
      src/win/signal.c
  85. 14 22
      src/win/stream.c
  86. 106 107
      src/win/tcp.c
  87. 19 227
      src/win/thread.c
  88. 0 195
      src/win/timer.c
  89. 87 90
      src/win/tty.c
  90. 46 49
      src/win/udp.c
  91. 250 48
      src/win/util.c
  92. 5 55
      src/win/winapi.c
  93. 9 71
      src/win/winapi.h
  94. 4 4
      src/win/winsock.c

+ 0 - 69
include/pthread-barrier.h

@@ -1,69 +0,0 @@
-/*
-Copyright (c) 2016, Kari Tristan Helgason <[email protected]>
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-
-#ifndef _UV_PTHREAD_BARRIER_
-#define _UV_PTHREAD_BARRIER_
-#include <errno.h>
-#include <pthread.h>
-#if !defined(__MVS__)
-#include <semaphore.h> /* sem_t */
-#endif
-
-#define PTHREAD_BARRIER_SERIAL_THREAD  0x12345
-#define UV__PTHREAD_BARRIER_FALLBACK   1
-
-/*
- * To maintain ABI compatibility with
- * libuv v1.x struct is padded according
- * to target platform
- */
-#if defined(__ANDROID__)
-# define UV_BARRIER_STRUCT_PADDING \
-  sizeof(pthread_mutex_t) + \
-  sizeof(pthread_cond_t) + \
-  sizeof(unsigned int) - \
-  sizeof(void *)
-#elif defined(__APPLE__)
-# define UV_BARRIER_STRUCT_PADDING \
-  sizeof(pthread_mutex_t) + \
-  2 * sizeof(sem_t) + \
-  2 * sizeof(unsigned int) - \
-  sizeof(void *)
-#else
-# define UV_BARRIER_STRUCT_PADDING 0
-#endif
-
-typedef struct {
-  pthread_mutex_t  mutex;
-  pthread_cond_t   cond;
-  unsigned         threshold;
-  unsigned         in;
-  unsigned         out;
-} _uv_barrier;
-
-typedef struct {
-  _uv_barrier* b;
-  char _pad[UV_BARRIER_STRUCT_PADDING];
-} pthread_barrier_t;
-
-int pthread_barrier_init(pthread_barrier_t* barrier,
-                         const void* barrier_attr,
-                         unsigned count);
-
-int pthread_barrier_wait(pthread_barrier_t* barrier);
-int pthread_barrier_destroy(pthread_barrier_t *barrier);
-
-#endif /* _UV_PTHREAD_BARRIER_ */

+ 70 - 16
include/uv.h

@@ -45,21 +45,21 @@ extern "C" {
 # define UV_EXTERN /* nothing */
 #endif
 
-#include "uv-errno.h"
-#include "uv-version.h"
+#include "uv/errno.h"
+#include "uv/version.h"
 #include <stddef.h>
 #include <stdio.h>
 
 #if defined(_MSC_VER) && _MSC_VER < 1600
-# include "stdint-msvc2008.h"
+# include "uv/stdint-msvc2008.h"
 #else
 # include <stdint.h>
 #endif
 
 #if defined(_WIN32)
-# include "uv-win.h"
+# include "uv/win.h"
 #else
-# include "uv-unix.h"
+# include "uv/unix.h"
 #endif
 
 /* Expand this list if necessary. */
@@ -142,6 +142,7 @@ extern "C" {
   XX(EHOSTDOWN, "host is down")                                               \
   XX(EREMOTEIO, "remote I/O error")                                           \
   XX(ENOTTY, "inappropriate ioctl for device")                                \
+  XX(EFTYPE, "inappropriate file type or format")                             \
 
 #define UV_HANDLE_TYPE_MAP(XX)                                                \
   XX(ASYNC, async)                                                            \
@@ -233,6 +234,7 @@ typedef struct uv_cpu_info_s uv_cpu_info_t;
 typedef struct uv_interface_address_s uv_interface_address_t;
 typedef struct uv_dirent_s uv_dirent_t;
 typedef struct uv_passwd_s uv_passwd_t;
+typedef struct uv_utsname_s uv_utsname_t;
 
 typedef enum {
   UV_LOOP_BLOCK_SIGNAL
@@ -369,7 +371,10 @@ typedef enum {
 UV_EXTERN int uv_translate_sys_error(int sys_errno);
 
 UV_EXTERN const char* uv_strerror(int err);
+UV_EXTERN char* uv_strerror_r(int err, char* buf, size_t buflen);
+
 UV_EXTERN const char* uv_err_name(int err);
+UV_EXTERN char* uv_err_name_r(int err, char* buf, size_t buflen);
 
 
 #define UV_REQ_FIELDS                                                         \
@@ -503,7 +508,7 @@ UV_EXTERN int uv_try_write(uv_stream_t* handle,
 struct uv_write_s {
   UV_REQ_FIELDS
   uv_write_cb cb;
-  uv_stream_t* send_handle;
+  uv_stream_t* send_handle; /* TODO: make private and unix-only in v2.x. */
   uv_stream_t* handle;
   UV_WRITE_PRIVATE_FIELDS
 };
@@ -865,7 +870,13 @@ typedef enum {
    * flags may be specified to create a duplex data stream.
    */
   UV_READABLE_PIPE  = 0x10,
-  UV_WRITABLE_PIPE  = 0x20
+  UV_WRITABLE_PIPE  = 0x20,
+
+  /*
+   * Open the child pipe handle in overlapped mode on Windows.
+   * On Unix it is silently ignored.
+   */
+  UV_OVERLAPPED_PIPE = 0x40
 } uv_stdio_flags;
 
 typedef struct uv_stdio_container_s {
@@ -952,12 +963,23 @@ enum uv_process_flags {
    * the child's process handle.
    */
   UV_PROCESS_DETACHED = (1 << 3),
+  /*
+   * Hide the subprocess window that would normally be created. This option is
+   * only meaningful on Windows systems. On Unix it is silently ignored.
+   */
+  UV_PROCESS_WINDOWS_HIDE = (1 << 4),
   /*
    * Hide the subprocess console window that would normally be created. This
    * option is only meaningful on Windows systems. On Unix it is silently
    * ignored.
    */
-  UV_PROCESS_WINDOWS_HIDE = (1 << 4)
+  UV_PROCESS_WINDOWS_HIDE_CONSOLE = (1 << 5),
+  /*
+   * Hide the subprocess GUI window that would normally be created. This
+   * option is only meaningful on Windows systems. On Unix it is silently
+   * ignored.
+   */
+  UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6)
 };
 
 /*
@@ -997,16 +1019,18 @@ UV_EXTERN int uv_queue_work(uv_loop_t* loop,
 UV_EXTERN int uv_cancel(uv_req_t* req);
 
 
+struct uv_cpu_times_s {
+  uint64_t user;
+  uint64_t nice;
+  uint64_t sys;
+  uint64_t idle;
+  uint64_t irq;
+};
+
 struct uv_cpu_info_s {
   char* model;
   int speed;
-  struct uv_cpu_times_s {
-    uint64_t user;
-    uint64_t nice;
-    uint64_t sys;
-    uint64_t idle;
-    uint64_t irq;
-  } cpu_times;
+  struct uv_cpu_times_s cpu_times;
 };
 
 struct uv_interface_address_s {
@@ -1031,6 +1055,16 @@ struct uv_passwd_s {
   char* homedir;
 };
 
+struct uv_utsname_s {
+  char sysname[256];
+  char release[256];
+  char version[256];
+  char machine[256];
+  /* This struct does not contain the nodename and domainname fields present in
+     the utsname type. domainname is a GNU extension. Both fields are referred
+     to as meaningless in the docs. */
+};
+
 typedef enum {
   UV_DIRENT_UNKNOWN,
   UV_DIRENT_FILE,
@@ -1053,6 +1087,7 @@ UV_EXTERN int uv_set_process_title(const char* title);
 UV_EXTERN int uv_resident_set_memory(size_t* rss);
 UV_EXTERN int uv_uptime(double* uptime);
 UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd);
+UV_EXTERN int uv_open_osfhandle(uv_os_fd_t os_fd);
 
 typedef struct {
   long tv_sec;
@@ -1087,6 +1122,16 @@ UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
 UV_EXTERN uv_pid_t uv_os_getpid(void);
 UV_EXTERN uv_pid_t uv_os_getppid(void);
 
+#define UV_PRIORITY_LOW 19
+#define UV_PRIORITY_BELOW_NORMAL 10
+#define UV_PRIORITY_NORMAL 0
+#define UV_PRIORITY_ABOVE_NORMAL -7
+#define UV_PRIORITY_HIGH -14
+#define UV_PRIORITY_HIGHEST -20
+
+UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority);
+UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);
+
 UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
 UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
 
@@ -1101,6 +1146,8 @@ UV_EXTERN int uv_os_unsetenv(const char* name);
 
 UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size);
 
+UV_EXTERN int uv_os_uname(uv_utsname_t* buffer);
+
 
 typedef enum {
   UV_FS_UNKNOWN = -1,
@@ -1133,7 +1180,8 @@ typedef enum {
   UV_FS_CHOWN,
   UV_FS_FCHOWN,
   UV_FS_REALPATH,
-  UV_FS_COPYFILE
+  UV_FS_COPYFILE,
+  UV_FS_LCHOWN
 } uv_fs_type;
 
 /* uv_fs_t is a subclass of uv_req_t. */
@@ -1336,6 +1384,12 @@ UV_EXTERN int uv_fs_fchown(uv_loop_t* loop,
                            uv_uid_t uid,
                            uv_gid_t gid,
                            uv_fs_cb cb);
+UV_EXTERN int uv_fs_lchown(uv_loop_t* loop,
+                           uv_fs_t* req,
+                           const char* path,
+                           uv_uid_t uid,
+                           uv_gid_t gid,
+                           uv_fs_cb cb);
 
 
 enum uv_fs_event {

+ 0 - 0
include/uv-aix.h → include/uv/aix.h


+ 0 - 0
include/android-ifaddrs.h → include/uv/android-ifaddrs.h


+ 0 - 0
include/uv-bsd.h → include/uv/bsd.h


+ 0 - 0
include/uv-darwin.h → include/uv/darwin.h


+ 6 - 0
include/uv-errno.h → include/uv/errno.h

@@ -433,5 +433,11 @@
 # define UV__ENOTTY (-4029)
 #endif
 
+#if defined(EFTYPE) && !defined(_WIN32)
+# define UV__EFTYPE UV__ERR(EFTYPE)
+#else
+# define UV__EFTYPE (-4028)
+#endif
+
 
 #endif /* UV_ERRNO_H_ */

+ 0 - 0
include/uv-linux.h → include/uv/linux.h


+ 0 - 0
include/uv-os390.h → include/uv/os390.h


+ 0 - 0
include/uv-posix.h → include/uv/posix.h


+ 0 - 0
include/stdint-msvc2008.h → include/uv/stdint-msvc2008.h


+ 0 - 0
include/uv-sunos.h → include/uv/sunos.h


+ 0 - 0
include/uv-threadpool.h → include/uv/threadpool.h


+ 0 - 0
include/tree.h → include/uv/tree.h


+ 32 - 14
include/uv-unix.h → include/uv/unix.h

@@ -42,32 +42,30 @@
 #include <pthread.h>
 #include <signal.h>
 
-#include "uv-threadpool.h"
+#include "uv/threadpool.h"
 
 #if defined(__linux__)
-# include "uv-linux.h"
+# include "uv/linux.h"
 #elif defined (__MVS__)
-# include "uv-os390.h"
+# include "uv/os390.h"
 #elif defined(__PASE__)
-# include "uv-posix.h"
+# include "uv/posix.h"
 #elif defined(_AIX)
-# include "uv-aix.h"
+# include "uv/aix.h"
 #elif defined(__sun)
-# include "uv-sunos.h"
+# include "uv/sunos.h"
 #elif defined(__APPLE__)
-# include "uv-darwin.h"
+# include "uv/darwin.h"
 #elif defined(__DragonFly__)       || \
       defined(__FreeBSD__)         || \
       defined(__FreeBSD_kernel__)  || \
       defined(__OpenBSD__)         || \
       defined(__NetBSD__)
-# include "uv-bsd.h"
+# include "uv/bsd.h"
 #elif defined(__CYGWIN__) || defined(__MSYS__)
-# include "uv-posix.h"
-#endif
-
-#ifndef PTHREAD_BARRIER_SERIAL_THREAD
-# include "pthread-barrier.h"
+# include "uv/posix.h"
+#elif defined(__GNU__)
+# include "uv/posix.h"
 #endif
 
 #ifndef NI_MAXHOST
@@ -136,8 +134,28 @@ typedef pthread_rwlock_t uv_rwlock_t;
 typedef UV_PLATFORM_SEM_T uv_sem_t;
 typedef pthread_cond_t uv_cond_t;
 typedef pthread_key_t uv_key_t;
-typedef pthread_barrier_t uv_barrier_t;
 
+/* Note: guard clauses should match uv_barrier_init's in src/unix/thread.c. */
+#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD)
+/* TODO(bnoordhuis) Merge into uv_barrier_t in v2. */
+struct _uv_barrier {
+  uv_mutex_t mutex;
+  uv_cond_t cond;
+  unsigned threshold;
+  unsigned in;
+  unsigned out;
+};
+
+typedef struct {
+  struct _uv_barrier* b;
+# if defined(PTHREAD_BARRIER_SERIAL_THREAD)
+  /* TODO(bnoordhuis) Remove padding in v2. */
+  char pad[sizeof(pthread_barrier_t) - sizeof(struct _uv_barrier*)];
+# endif
+} uv_barrier_t;
+#else
+typedef pthread_barrier_t uv_barrier_t;
+#endif
 
 /* Platform-specific definitions for uv_spawn support. */
 typedef gid_t uv_gid_t;

+ 2 - 2
include/uv-version.h → include/uv/version.h

@@ -31,8 +31,8 @@
  */
 
 #define UV_VERSION_MAJOR 1
-#define UV_VERSION_MINOR 20
-#define UV_VERSION_PATCH 3
+#define UV_VERSION_MINOR 24
+#define UV_VERSION_PATCH 2
 #define UV_VERSION_IS_RELEASE 0
 #define UV_VERSION_SUFFIX "dev"
 

+ 36 - 27
include/uv-win.h → include/uv/win.h

@@ -25,6 +25,7 @@
 
 #if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
 typedef intptr_t ssize_t;
+# define SSIZE_MAX INTPTR_MAX
 # define _SSIZE_T_
 # define _SSIZE_T_DEFINED
 #endif
@@ -53,13 +54,13 @@ typedef struct pollfd {
 #include <sys/stat.h>
 
 #if defined(_MSC_VER) && _MSC_VER < 1600
-# include "stdint-msvc2008.h"
+# include "uv/stdint-msvc2008.h"
 #else
 # include <stdint.h>
 #endif
 
-#include "tree.h"
-#include "uv-threadpool.h"
+#include "uv/tree.h"
+#include "uv/threadpool.h"
 
 #define MAX_PIPENAME_LEN 256
 
@@ -86,8 +87,16 @@ typedef struct pollfd {
 #define SIGKILL               9
 #define SIGWINCH             28
 
-/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many */
-/* unix-like platforms. However MinGW doesn't define it, so we do. */
+/* Redefine NSIG to take SIGWINCH into consideration */
+#if defined(NSIG) && NSIG <= SIGWINCH
+# undef NSIG
+#endif
+#ifndef NSIG
+# define NSIG SIGWINCH + 1
+#endif
+
+/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many unix-like
+ * platforms. However MinGW doesn't define it, so we do. */
 #ifndef SIGABRT_COMPAT
 # define SIGABRT_COMPAT       6
 #endif
@@ -244,7 +253,7 @@ typedef union {
     CRITICAL_SECTION waiters_count_lock;
     HANDLE signal_event;
     HANDLE broadcast_event;
-  } fallback;
+  } unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */
 } uv_cond_t;
 
 typedef union {
@@ -308,8 +317,6 @@ typedef struct {
   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;                                                                \
@@ -321,8 +328,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   uv_req_t* pending_reqs_tail;                                                \
   /* Head of a single-linked list of closed handles */                        \
   uv_handle_t* endgame_handles;                                               \
-  /* The head of the timers tree */                                           \
-  struct uv_timer_tree_s timers;                                              \
+  /* TODO(bnoordhuis) Stop heap-allocating |timer_heap| in libuv v2.x. */     \
+  void* timer_heap;                                                           \
     /* Lists of active loop (prepare / check / idle) watchers */              \
   uv_prepare_t* prepare_handles;                                              \
   uv_check_t* check_handles;                                                  \
@@ -368,10 +375,10 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   } u;                                                                        \
   struct uv_req_s* next_req;
 
-#define UV_WRITE_PRIVATE_FIELDS                                               \
-  int ipc_header;                                                             \
-  uv_buf_t write_buffer;                                                      \
-  HANDLE event_handle;                                                        \
+#define UV_WRITE_PRIVATE_FIELDS \
+  int coalesced;                \
+  uv_buf_t write_buffer;        \
+  HANDLE event_handle;          \
   HANDLE wait_handle;
 
 #define UV_CONNECT_PRIVATE_FIELDS                                             \
@@ -459,16 +466,17 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
 
 #define uv_pipe_connection_fields                                             \
   uv_timer_t* eof_timer;                                                      \
-  uv_write_t ipc_header_write_req;                                            \
-  int ipc_pid;                                                                \
-  uint64_t remaining_ipc_rawdata_bytes;                                       \
-  struct {                                                                    \
-    void* queue[2];                                                           \
-    int queue_len;                                                            \
-  } pending_ipc_info;                                                         \
+  uv_write_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \
+  DWORD ipc_remote_pid;                                                       \
+  union {                                                                     \
+    uint32_t payload_remaining;                                               \
+    uint64_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \
+  } ipc_data_frame;                                                           \
+  void* ipc_xfer_queue[2];                                                    \
+  int ipc_xfer_queue_length;                                                  \
   uv_write_t* non_overlapped_writes_tail;                                     \
-  uv_mutex_t readfile_mutex;                                                  \
-  volatile HANDLE readfile_thread;
+  CRITICAL_SECTION readfile_thread_lock;                                      \
+  volatile HANDLE readfile_thread_handle;
 
 #define UV_PIPE_PRIVATE_FIELDS                                                \
   HANDLE handle;                                                              \
@@ -478,8 +486,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
     struct { uv_pipe_connection_fields } conn;                                \
   } pipe;
 
-/* TODO: put the parser states in an union - TTY handles are always */
-/* half-duplex so read-state can safely overlap write-state. */
+/* TODO: put the parser states in an union - TTY handles are always half-duplex
+ * so read-state can safely overlap write-state. */
 #define UV_TTY_PRIVATE_FIELDS                                                 \
   HANDLE handle;                                                              \
   union {                                                                     \
@@ -528,8 +536,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   unsigned char events;
 
 #define UV_TIMER_PRIVATE_FIELDS                                               \
-  RB_ENTRY(uv_timer_s) tree_entry;                                            \
-  uint64_t due;                                                               \
+  void* heap_node[3];                                                         \
+  int unused;                                                                 \
+  uint64_t timeout;                                                           \
   uint64_t repeat;                                                            \
   uint64_t start_id;                                                          \
   uv_timer_cb timer_cb;

+ 2 - 2
src/fs-poll.c

@@ -83,7 +83,7 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
   if (err < 0)
     goto error;
 
-  ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;
+  ctx->timer_handle.flags |= UV_HANDLE_INTERNAL;
   uv__handle_unref(&ctx->timer_handle);
 
   err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
@@ -248,7 +248,7 @@ static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) {
 #include "win/handle-inl.h"
 
 void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) {
-  assert(handle->flags & UV__HANDLE_CLOSING);
+  assert(handle->flags & UV_HANDLE_CLOSING);
   assert(!(handle->flags & UV_HANDLE_CLOSED));
   uv__handle_close(handle);
 }

+ 291 - 0
src/idna.c

@@ -0,0 +1,291 @@
+/* Copyright (c) 2011, 2018 Ben Noordhuis <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Derived from https://github.com/bnoordhuis/punycode
+ * but updated to support IDNA 2008.
+ */
+
+#include "uv.h"
+#include "idna.h"
+#include <string.h>
+
+static unsigned uv__utf8_decode1_slow(const char** p,
+                                      const char* pe,
+                                      unsigned a) {
+  unsigned b;
+  unsigned c;
+  unsigned d;
+  unsigned min;
+
+  if (a > 0xF7)
+    return -1;
+
+  switch (*p - pe) {
+  default:
+    if (a > 0xEF) {
+      min = 0x10000;
+      a = a & 7;
+      b = (unsigned char) *(*p)++;
+      c = (unsigned char) *(*p)++;
+      d = (unsigned char) *(*p)++;
+      break;
+    }
+    /* Fall through. */
+  case 2:
+    if (a > 0xDF) {
+      min = 0x800;
+      b = 0x80 | (a & 15);
+      c = (unsigned char) *(*p)++;
+      d = (unsigned char) *(*p)++;
+      a = 0;
+      break;
+    }
+    /* Fall through. */
+  case 1:
+    if (a > 0xBF) {
+      min = 0x80;
+      b = 0x80;
+      c = 0x80 | (a & 31);
+      d = (unsigned char) *(*p)++;
+      a = 0;
+      break;
+    }
+    return -1;  /* Invalid continuation byte. */
+  }
+
+  if (0x80 != (0xC0 & (b ^ c ^ d)))
+    return -1;  /* Invalid sequence. */
+
+  b &= 63;
+  c &= 63;
+  d &= 63;
+  a = (a << 18) | (b << 12) | (c << 6) | d;
+
+  if (a < min)
+    return -1;  /* Overlong sequence. */
+
+  if (a > 0x10FFFF)
+    return -1;  /* Four-byte sequence > U+10FFFF. */
+
+  if (a >= 0xD800 && a <= 0xDFFF)
+    return -1;  /* Surrogate pair. */
+
+  return a;
+}
+
+unsigned uv__utf8_decode1(const char** p, const char* pe) {
+  unsigned a;
+
+  a = (unsigned char) *(*p)++;
+
+  if (a < 128)
+    return a;  /* ASCII, common case. */
+
+  return uv__utf8_decode1_slow(p, pe, a);
+}
+
+#define foreach_codepoint(c, p, pe) \
+  for (; (void) (*p <= pe && (c = uv__utf8_decode1(p, pe))), *p <= pe;)
+
+static int uv__idna_toascii_label(const char* s, const char* se,
+                                  char** d, char* de) {
+  static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
+  const char* ss;
+  unsigned c;
+  unsigned h;
+  unsigned k;
+  unsigned n;
+  unsigned m;
+  unsigned q;
+  unsigned t;
+  unsigned x;
+  unsigned y;
+  unsigned bias;
+  unsigned delta;
+  unsigned todo;
+  int first;
+
+  h = 0;
+  ss = s;
+  todo = 0;
+
+  foreach_codepoint(c, &s, se) {
+    if (c < 128)
+      h++;
+    else if (c == (unsigned) -1)
+      return UV_EINVAL;
+    else
+      todo++;
+  }
+
+  if (todo > 0) {
+    if (*d < de) *(*d)++ = 'x';
+    if (*d < de) *(*d)++ = 'n';
+    if (*d < de) *(*d)++ = '-';
+    if (*d < de) *(*d)++ = '-';
+  }
+
+  x = 0;
+  s = ss;
+  foreach_codepoint(c, &s, se) {
+    if (c > 127)
+      continue;
+
+    if (*d < de)
+      *(*d)++ = c;
+
+    if (++x == h)
+      break;  /* Visited all ASCII characters. */
+  }
+
+  if (todo == 0)
+    return h;
+
+  /* Only write separator when we've written ASCII characters first. */
+  if (h > 0)
+    if (*d < de)
+      *(*d)++ = '-';
+
+  n = 128;
+  bias = 72;
+  delta = 0;
+  first = 1;
+
+  while (todo > 0) {
+    m = -1;
+    s = ss;
+    foreach_codepoint(c, &s, se)
+      if (c >= n)
+        if (c < m)
+          m = c;
+
+    x = m - n;
+    y = h + 1;
+
+    if (x > ~delta / y)
+      return UV_E2BIG;  /* Overflow. */
+
+    delta += x * y;
+    n = m;
+
+    s = ss;
+    foreach_codepoint(c, &s, se) {
+      if (c < n)
+        if (++delta == 0)
+          return UV_E2BIG;  /* Overflow. */
+
+      if (c != n)
+        continue;
+
+      for (k = 36, q = delta; /* empty */; k += 36) {
+        t = 1;
+
+        if (k > bias)
+          t = k - bias;
+
+        if (t > 26)
+          t = 26;
+
+        if (q < t)
+          break;
+
+        /* TODO(bnoordhuis) Since 1 <= t <= 26 and therefore
+         * 10 <= y <= 35, we can optimize the long division
+         * into a table-based reciprocal multiplication.
+         */
+        x = q - t;
+        y = 36 - t;  /* 10 <= y <= 35 since 1 <= t <= 26. */
+        q = x / y;
+        t = t + x % y;  /* 1 <= t <= 35 because of y. */
+
+        if (*d < de)
+          *(*d)++ = alphabet[t];
+      }
+
+      if (*d < de)
+        *(*d)++ = alphabet[q];
+
+      delta /= 2;
+
+      if (first) {
+        delta /= 350;
+        first = 0;
+      }
+
+      /* No overflow check is needed because |delta| was just
+       * divided by 2 and |delta+delta >= delta + delta/h|.
+       */
+      h++;
+      delta += delta / h;
+
+      for (bias = 0; delta > 35 * 26 / 2; bias += 36)
+        delta /= 35;
+
+      bias += 36 * delta / (delta + 38);
+      delta = 0;
+      todo--;
+    }
+
+    delta++;
+    n++;
+  }
+
+  return 0;
+}
+
+#undef foreach_codepoint
+
+long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
+  const char* si;
+  const char* st;
+  unsigned c;
+  char* ds;
+  int rc;
+
+  ds = d;
+
+  for (si = s; si < se; /* empty */) {
+    st = si;
+    c = uv__utf8_decode1(&si, se);
+
+    if (c != '.')
+      if (c != 0x3002)  /* 。 */
+        if (c != 0xFF0E)  /* . */
+          if (c != 0xFF61)  /* 。 */
+            continue;
+
+    rc = uv__idna_toascii_label(s, st, &d, de);
+
+    if (rc < 0)
+      return rc;
+
+    if (d < de)
+      *d++ = '.';
+
+    s = si;
+  }
+
+  if (s < se) {
+    rc = uv__idna_toascii_label(s, se, &d, de);
+
+    if (rc < 0)
+      return rc;
+  }
+
+  if (d < de)
+    *d++ = '\0';
+
+  return d - ds;  /* Number of bytes written. */
+}

+ 31 - 0
src/idna.h

@@ -0,0 +1,31 @@
+/* Copyright (c) 2011, 2018 Ben Noordhuis <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UV_SRC_IDNA_H_
+#define UV_SRC_IDNA_H_
+
+/* Decode a single codepoint. Returns the codepoint or UINT32_MAX on error.
+ * |p| is updated on success _and_ error, i.e., bad multi-byte sequences are
+ * skipped in their entirety, not just the first bad byte.
+ */
+unsigned uv__utf8_decode1(const char** p, const char* pe);
+
+/* Convert a UTF-8 domain name to IDNA 2008 / Punycode. A return value >= 0
+ * is the number of bytes written to |d|, including the trailing nul byte.
+ * A return value < 0 is a libuv error code. |s| and |d| can not overlap.
+ */
+long uv__idna_toascii(const char* s, const char* se, char* d, char* de);
+
+#endif  /* UV_SRC_IDNA_H_ */

+ 3 - 10
src/inet.c

@@ -19,7 +19,7 @@
 #include <string.h>
 
 #if defined(_MSC_VER) && _MSC_VER < 1600
-# include "stdint-msvc2008.h"
+# include "uv/stdint-msvc2008.h"
 #else
 # include <stdint.h>
 #endif
@@ -59,8 +59,7 @@ static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
   if (l <= 0 || (size_t) l >= size) {
     return UV_ENOSPC;
   }
-  strncpy(dst, tmp, size);
-  dst[size - 1] = '\0';
+  uv__strscpy(dst, tmp, size);
   return 0;
 }
 
@@ -142,14 +141,8 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
   if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
     *tp++ = ':';
   *tp++ = '\0';
-
-  /*
-   * Check for overflow, copy, and we're done.
-   */
-  if ((size_t)(tp - tmp) > size) {
+  if (UV_E2BIG == uv__strscpy(dst, tmp, size))
     return UV_ENOSPC;
-  }
-  strcpy(dst, tmp);
   return 0;
 }
 

+ 17 - 0
src/strscpy.c

@@ -0,0 +1,17 @@
+#include "strscpy.h"
+#include <limits.h>  /* SSIZE_MAX */
+
+ssize_t uv__strscpy(char* d, const char* s, size_t n) {
+  size_t i;
+
+  for (i = 0; i < n; i++)
+    if ('\0' == (d[i] = s[i]))
+      return i > SSIZE_MAX ? UV_E2BIG : (ssize_t) i;
+
+  if (i == 0)
+    return 0;
+
+  d[--i] = '\0';
+
+  return UV_E2BIG;
+}

+ 18 - 0
src/strscpy.h

@@ -0,0 +1,18 @@
+#ifndef UV_STRSCPY_H_
+#define UV_STRSCPY_H_
+
+/* Include uv.h for its definitions of size_t and ssize_t.
+ * size_t can be obtained directly from <stddef.h> but ssize_t requires
+ * some hoop jumping on Windows that I didn't want to duplicate here.
+ */
+#include "uv.h"
+
+/* Copies up to |n-1| bytes from |d| to |s| and always zero-terminates
+ * the result, except when |n==0|. Returns the number of bytes copied
+ * or UV_E2BIG if |d| is too small.
+ *
+ * See https://www.kernel.org/doc/htmldocs/kernel-api/API-strscpy.html
+ */
+ssize_t uv__strscpy(char* d, const char* s, size_t n);
+
+#endif  /* UV_STRSCPY_H_ */

+ 81 - 15
src/threadpool.c

@@ -33,12 +33,18 @@ static uv_once_t once = UV_ONCE_INIT;
 static uv_cond_t cond;
 static uv_mutex_t mutex;
 static unsigned int idle_threads;
+static unsigned int slow_io_work_running;
 static unsigned int nthreads;
 static uv_thread_t* threads;
 static uv_thread_t default_threads[4];
 static QUEUE exit_message;
 static QUEUE wq;
+static QUEUE run_slow_work_message;
+static QUEUE slow_io_pending_wq;
 
+static unsigned int slow_work_thread_threshold(void) {
+  return (nthreads + 1) / 2;
+}
 
 static void uv__cancelled(struct uv__work* w) {
   abort();
@@ -51,34 +57,67 @@ static void uv__cancelled(struct uv__work* w) {
 static void worker(void* arg) {
   struct uv__work* w;
   QUEUE* q;
+  int is_slow_work;
 
   uv_sem_post((uv_sem_t*) arg);
   arg = NULL;
 
+  uv_mutex_lock(&mutex);
   for (;;) {
-    uv_mutex_lock(&mutex);
-
-    while (QUEUE_EMPTY(&wq)) {
+    /* `mutex` should always be locked at this point. */
+
+    /* Keep waiting while either no work is present or only slow I/O
+       and we're at the threshold for that. */
+    while (QUEUE_EMPTY(&wq) ||
+           (QUEUE_HEAD(&wq) == &run_slow_work_message &&
+            QUEUE_NEXT(&run_slow_work_message) == &wq &&
+            slow_io_work_running >= slow_work_thread_threshold())) {
       idle_threads += 1;
       uv_cond_wait(&cond, &mutex);
       idle_threads -= 1;
     }
 
     q = QUEUE_HEAD(&wq);
-
-    if (q == &exit_message)
+    if (q == &exit_message) {
       uv_cond_signal(&cond);
-    else {
+      uv_mutex_unlock(&mutex);
+      break;
+    }
+
+    QUEUE_REMOVE(q);
+    QUEUE_INIT(q);  /* Signal uv_cancel() that the work req is executing. */
+
+    is_slow_work = 0;
+    if (q == &run_slow_work_message) {
+      /* If we're at the slow I/O threshold, re-schedule until after all
+         other work in the queue is done. */
+      if (slow_io_work_running >= slow_work_thread_threshold()) {
+        QUEUE_INSERT_TAIL(&wq, q);
+        continue;
+      }
+
+      /* If we encountered a request to run slow I/O work but there is none
+         to run, that means it's cancelled => Start over. */
+      if (QUEUE_EMPTY(&slow_io_pending_wq))
+        continue;
+
+      is_slow_work = 1;
+      slow_io_work_running++;
+
+      q = QUEUE_HEAD(&slow_io_pending_wq);
       QUEUE_REMOVE(q);
-      QUEUE_INIT(q);  /* Signal uv_cancel() that the work req is
-                             executing. */
+      QUEUE_INIT(q);
+
+      /* If there is more slow I/O work, schedule it to be run as well. */
+      if (!QUEUE_EMPTY(&slow_io_pending_wq)) {
+        QUEUE_INSERT_TAIL(&wq, &run_slow_work_message);
+        if (idle_threads > 0)
+          uv_cond_signal(&cond);
+      }
     }
 
     uv_mutex_unlock(&mutex);
 
-    if (q == &exit_message)
-      break;
-
     w = QUEUE_DATA(q, struct uv__work, wq);
     w->work(w);
 
@@ -88,12 +127,32 @@ static void worker(void* arg) {
     QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
     uv_async_send(&w->loop->wq_async);
     uv_mutex_unlock(&w->loop->wq_mutex);
+
+    /* Lock `mutex` since that is expected at the start of the next
+     * iteration. */
+    uv_mutex_lock(&mutex);
+    if (is_slow_work) {
+      /* `slow_io_work_running` is protected by `mutex`. */
+      slow_io_work_running--;
+    }
   }
 }
 
 
-static void post(QUEUE* q) {
+static void post(QUEUE* q, enum uv__work_kind kind) {
   uv_mutex_lock(&mutex);
+  if (kind == UV__WORK_SLOW_IO) {
+    /* Insert into a separate queue. */
+    QUEUE_INSERT_TAIL(&slow_io_pending_wq, q);
+    if (!QUEUE_EMPTY(&run_slow_work_message)) {
+      /* Running slow I/O tasks is already scheduled => Nothing to do here.
+         The worker that runs said other task will schedule this one as well. */
+      uv_mutex_unlock(&mutex);
+      return;
+    }
+    q = &run_slow_work_message;
+  }
+
   QUEUE_INSERT_TAIL(&wq, q);
   if (idle_threads > 0)
     uv_cond_signal(&cond);
@@ -108,7 +167,7 @@ UV_DESTRUCTOR(static void cleanup(void)) {
   if (nthreads == 0)
     return;
 
-  post(&exit_message);
+  post(&exit_message, UV__WORK_CPU);
 
   for (i = 0; i < nthreads; i++)
     if (uv_thread_join(threads + i))
@@ -156,6 +215,8 @@ static void init_threads(void) {
     abort();
 
   QUEUE_INIT(&wq);
+  QUEUE_INIT(&slow_io_pending_wq);
+  QUEUE_INIT(&run_slow_work_message);
 
   if (uv_sem_init(&sem, 0))
     abort();
@@ -194,13 +255,14 @@ static void init_once(void) {
 
 void uv__work_submit(uv_loop_t* loop,
                      struct uv__work* w,
+                     enum uv__work_kind kind,
                      void (*work)(struct uv__work* w),
                      void (*done)(struct uv__work* w, int status)) {
   uv_once(&once, init_once);
   w->loop = loop;
   w->work = work;
   w->done = done;
-  post(&w->wq);
+  post(&w->wq, kind);
 }
 
 
@@ -284,7 +346,11 @@ int uv_queue_work(uv_loop_t* loop,
   req->loop = loop;
   req->work_cb = work_cb;
   req->after_work_cb = after_work_cb;
-  uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done);
+  uv__work_submit(loop,
+                  &req->work_req,
+                  UV__WORK_CPU,
+                  uv__queue_work,
+                  uv__queue_done);
   return 0;
 }
 

+ 15 - 6
src/unix/timer.c → src/timer.c

@@ -19,13 +19,22 @@
  */
 
 #include "uv.h"
-#include "internal.h"
+#include "uv-common.h"
 #include "heap-inl.h"
 
 #include <assert.h>
 #include <limits.h>
 
 
+static struct heap *timer_heap(const uv_loop_t* loop) {
+#ifdef _WIN32
+  return (struct heap*) loop->timer_heap;
+#else
+  return (struct heap*) &loop->timer_heap;
+#endif
+}
+
+
 static int timer_less_than(const struct heap_node* ha,
                            const struct heap_node* hb) {
   const uv_timer_t* a;
@@ -81,7 +90,7 @@ int uv_timer_start(uv_timer_t* handle,
   /* start_id is the second index to be compared in uv__timer_cmp() */
   handle->start_id = handle->loop->timer_counter++;
 
-  heap_insert((struct heap*) &handle->loop->timer_heap,
+  heap_insert(timer_heap(handle->loop),
               (struct heap_node*) &handle->heap_node,
               timer_less_than);
   uv__handle_start(handle);
@@ -94,7 +103,7 @@ int uv_timer_stop(uv_timer_t* handle) {
   if (!uv__is_active(handle))
     return 0;
 
-  heap_remove((struct heap*) &handle->loop->timer_heap,
+  heap_remove(timer_heap(handle->loop),
               (struct heap_node*) &handle->heap_node,
               timer_less_than);
   uv__handle_stop(handle);
@@ -131,7 +140,7 @@ int uv__next_timeout(const uv_loop_t* loop) {
   const uv_timer_t* handle;
   uint64_t diff;
 
-  heap_node = heap_min((const struct heap*) &loop->timer_heap);
+  heap_node = heap_min(timer_heap(loop));
   if (heap_node == NULL)
     return -1; /* block indefinitely */
 
@@ -143,7 +152,7 @@ int uv__next_timeout(const uv_loop_t* loop) {
   if (diff > INT_MAX)
     diff = INT_MAX;
 
-  return diff;
+  return (int) diff;
 }
 
 
@@ -152,7 +161,7 @@ void uv__run_timers(uv_loop_t* loop) {
   uv_timer_t* handle;
 
   for (;;) {
-    heap_node = heap_min((struct heap*) &loop->timer_heap);
+    heap_node = heap_min(timer_heap(loop));
     if (heap_node == NULL)
       break;
 

+ 8 - 2
src/unix/aix-common.c

@@ -166,8 +166,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
 }
 
 
-int uv_interface_addresses(uv_interface_address_t** addresses,
-  int* count) {
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   uv_interface_address_t* address;
   int sockfd, inet6, size = 1;
   struct ifconf ifc;
@@ -175,6 +174,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
   struct sockaddr_dl* sa_addr;
 
   *count = 0;
+  *addresses = NULL;
 
   if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
     return UV__ERR(errno);
@@ -217,6 +217,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
     (*count)++;
   }
 
+  if (*count == 0) {
+    uv__close(sockfd);
+    return 0;
+  }
+
   /* Alloc the return interface structs */
   *addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
   if (!(*addresses)) {
@@ -290,3 +295,4 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses,
 
   uv__free(addresses);
 }
+

+ 41 - 22
src/unix/aix.c

@@ -358,19 +358,15 @@ void uv_loadavg(double avg[3]) {
 
 
 #ifdef HAVE_SYS_AHAFS_EVPRODS_H
-static char *uv__rawname(char *cp) {
-  static char rawbuf[FILENAME_MAX+1];
-  char *dp = rindex(cp, '/');
+static char* uv__rawname(const char* cp, char (*dst)[FILENAME_MAX+1]) {
+  char* dp;
 
+  dp = rindex(cp, '/');
   if (dp == 0)
     return 0;
 
-  *dp = 0;
-  strcpy(rawbuf, cp);
-  *dp = '/';
-  strcat(rawbuf, "/r");
-  strcat(rawbuf, dp+1);
-  return rawbuf;
+  snprintf(*dst, sizeof(*dst), "%.*s/r%s", (int) (dp - cp), cp, dp + 1);
+  return *dst;
 }
 
 
@@ -399,6 +395,7 @@ static int uv__path_is_a_directory(char* filename) {
  * Returns 0 if AHAFS is mounted, or an error code < 0 on failure
  */
 static int uv__is_ahafs_mounted(void){
+  char rawbuf[FILENAME_MAX+1];
   int rv, i = 2;
   struct vmount *p;
   int size_multiplier = 10;
@@ -432,7 +429,7 @@ static int uv__is_ahafs_mounted(void){
     obj = vmt2dataptr(vmt, VMT_OBJECT);     /* device */
     stub = vmt2dataptr(vmt, VMT_STUB);      /* mount point */
 
-    if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) {
+    if (EQ(obj, dev) || EQ(uv__rawname(obj, &rawbuf), dev) || EQ(stub, dev)) {
       uv__free(p);  /* Found a match */
       return 0;
     }
@@ -453,7 +450,8 @@ static int uv__makedir_p(const char *dir) {
   size_t len;
   int err;
 
-  snprintf(tmp, sizeof(tmp),"%s",dir);
+  /* TODO(bnoordhuis) Check uv__strscpy() return value. */
+  uv__strscpy(tmp, dir, sizeof(tmp));
   len = strlen(tmp);
   if (tmp[len - 1] == '/')
     tmp[len - 1] = 0;
@@ -557,7 +555,7 @@ static int uv__setup_ahafs(const char* filename, int *fd) {
     sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
 
   rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1);
-  if (rc < 0)
+  if (rc < 0 && errno != EBUSY)
     return UV__ERR(errno);
 
   return 0;
@@ -702,9 +700,9 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int
     else
       p++;
   }
-  strncpy(fname, p, sizeof(fname) - 1);
-  /* Just in case */
-  fname[sizeof(fname) - 1] = '\0';
+
+  /* TODO(bnoordhuis) Check uv__strscpy() return value. */
+  uv__strscpy(fname, p, sizeof(fname));
 
   handle->cb(handle, fname, events, 0);
 }
@@ -730,12 +728,19 @@ int uv_fs_event_start(uv_fs_event_t* handle,
   char cwd[PATH_MAX];
   char absolute_path[PATH_MAX];
   char readlink_cwd[PATH_MAX];
+  struct timeval zt;
+  fd_set pollfd;
 
 
   /* Figure out whether filename is absolute or not */
-  if (filename[0] == '/') {
+  if (filename[0] == '\0') {
+    /* Missing a pathname */
+    return UV_ENOENT;
+  }
+  else if (filename[0] == '/') {
     /* We have absolute pathname */
-    snprintf(absolute_path, sizeof(absolute_path), "%s", filename);
+    /* TODO(bnoordhuis) Check uv__strscpy() return value. */
+    uv__strscpy(absolute_path, filename, sizeof(absolute_path));
   } else {
     /* We have a relative pathname, compose the absolute pathname */
     snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid());
@@ -769,6 +774,15 @@ int uv_fs_event_start(uv_fs_event_t* handle,
 
   uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
 
+  /* AHAFS wants someone to poll for it to start mointoring.
+   *  so kick-start it so that we don't miss an event in the
+   *  eventuality of an event that occurs in the current loop. */
+  do {
+    memset(&zt, 0, sizeof(zt));
+    FD_ZERO(&pollfd);
+    FD_SET(fd, &pollfd);
+    rc = select(fd + 1, &pollfd, NULL, NULL, &zt);
+  } while (rc == -1 && errno == EINTR);
   return 0;
 #else
   return UV_ENOSYS;
@@ -886,16 +900,20 @@ int uv_set_process_title(const char* title) {
 
 int uv_get_process_title(char* buffer, size_t size) {
   size_t len;
-  len = strlen(process_argv[0]);
   if (buffer == NULL || size == 0)
     return UV_EINVAL;
-  else if (size <= len)
-    return UV_ENOBUFS;
 
   uv_once(&process_title_mutex_once, init_process_title_mutex_once);
   uv_mutex_lock(&process_title_mutex);
 
-  memcpy(buffer, process_argv[0], len + 1);
+  len = strlen(process_argv[0]);
+  if (size <= len) {
+    uv_mutex_unlock(&process_title_mutex);
+    return UV_ENOBUFS;
+  }
+
+  memcpy(buffer, process_argv[0], len);
+  buffer[len] = '\0';
 
   uv_mutex_unlock(&process_title_mutex);
 
@@ -982,7 +1000,8 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
     return UV_ENOMEM;
   }
 
-  strcpy(cpu_id.name, FIRST_CPU);
+  /* TODO(bnoordhuis) Check uv__strscpy() return value. */
+  uv__strscpy(cpu_id.name, FIRST_CPU, sizeof(cpu_id.name));
   result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus);
   if (result == -1) {
     uv__free(ps_cpus);

+ 1 - 1
src/unix/android-ifaddrs.c

@@ -23,7 +23,7 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
-#include "android-ifaddrs.h"
+#include "uv/android-ifaddrs.h"
 #include "uv-common.h"
 
 #include <string.h>

+ 14 - 9
src/unix/bsd-ifaddrs.c

@@ -52,13 +52,10 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
    */
   if (ent->ifa_addr->sa_family == AF_LINK)
     return 1;
-#elif defined(__NetBSD__)
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
   if (ent->ifa_addr->sa_family != PF_INET &&
       ent->ifa_addr->sa_family != PF_INET6)
     return 1;
-#elif defined(__OpenBSD__)
-  if (ent->ifa_addr->sa_family != PF_INET)
-    return 1;
 #endif
   return 0;
 }
@@ -69,11 +66,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   uv_interface_address_t* address;
   int i;
 
+  *count = 0;
+  *addresses = NULL;
+
   if (getifaddrs(&addrs) != 0)
     return UV__ERR(errno);
 
-  *count = 0;
-
   /* Count the number of interfaces */
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
     if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
@@ -81,6 +79,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
     (*count)++;
   }
 
+  if (*count == 0) {
+    freeifaddrs(addrs);
+    return 0;
+  }
+
   *addresses = uv__malloc(*count * sizeof(**addresses));
 
   if (*addresses == NULL) {
@@ -121,15 +124,17 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
     address = *addresses;
 
     for (i = 0; i < *count; i++) {
-      if (strcmp(address->name, ent->ifa_name) == 0) {
 #if defined(__CYGWIN__) || defined(__MSYS__)
-        memset(address->phys_addr, 0, sizeof(address->phys_addr));
+      memset(address->phys_addr, 0, sizeof(address->phys_addr));
 #else
+      if (strcmp(address->name, ent->ifa_name) == 0) {
         struct sockaddr_dl* sa_addr;
         sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
         memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
-#endif
+      } else {
+        memset(address->phys_addr, 0, sizeof(address->phys_addr));
       }
+#endif
       address++;
     }
   }

+ 93 - 0
src/unix/bsd-proctitle.c

@@ -0,0 +1,93 @@
+/* Copyright libuv project 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 <sys/types.h>
+#include <unistd.h>
+
+
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
+static char* process_title;
+
+
+static void init_process_title_mutex_once(void) {
+  if (uv_mutex_init(&process_title_mutex))
+    abort();
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+  process_title = argc > 0 ? uv__strdup(argv[0]) : NULL;
+  return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+  char* new_title;
+
+  new_title = uv__strdup(title);
+  if (new_title == NULL)
+    return UV_ENOMEM;
+
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+  uv_mutex_lock(&process_title_mutex);
+
+  uv__free(process_title);
+  process_title = new_title;
+  setproctitle("%s", title);
+
+  uv_mutex_unlock(&process_title_mutex);
+
+  return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+  size_t len;
+
+  if (buffer == NULL || size == 0)
+    return UV_EINVAL;
+
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+  uv_mutex_lock(&process_title_mutex);
+
+  if (process_title != NULL) {
+    len = strlen(process_title) + 1;
+
+    if (size < len) {
+      uv_mutex_unlock(&process_title_mutex);
+      return UV_ENOBUFS;
+    }
+
+    memcpy(buffer, process_title, len);
+  } else {
+    len = 0;
+  }
+
+  uv_mutex_unlock(&process_title_mutex);
+
+  buffer[len] = '\0';
+
+  return 0;
+}

+ 105 - 31
src/unix/core.c

@@ -40,6 +40,7 @@
 #include <sys/uio.h> /* writev */
 #include <sys/resource.h> /* getrusage */
 #include <pwd.h>
+#include <sys/utsname.h>
 
 #ifdef __sun
 # include <netdb.h> /* MAXHOSTNAMELEN on Solaris */
@@ -116,7 +117,7 @@ uint64_t uv_hrtime(void) {
 void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
   assert(!uv__is_closing(handle));
 
-  handle->flags |= UV_CLOSING;
+  handle->flags |= UV_HANDLE_CLOSING;
   handle->close_cb = close_cb;
 
   switch (handle->type) {
@@ -174,8 +175,8 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
 
   case UV_SIGNAL:
     uv__signal_close((uv_signal_t*) handle);
-    /* Signal handles may not be closed immediately. The signal code will */
-    /* itself close uv__make_close_pending whenever appropriate. */
+    /* Signal handles may not be closed immediately. The signal code will
+     * itself close uv__make_close_pending whenever appropriate. */
     return;
 
   default:
@@ -214,8 +215,8 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
 }
 
 void uv__make_close_pending(uv_handle_t* handle) {
-  assert(handle->flags & UV_CLOSING);
-  assert(!(handle->flags & UV_CLOSED));
+  assert(handle->flags & UV_HANDLE_CLOSING);
+  assert(!(handle->flags & UV_HANDLE_CLOSED));
   handle->next_closing = handle->loop->closing_handles;
   handle->loop->closing_handles = handle;
 }
@@ -241,15 +242,17 @@ int uv__getiovmax(void) {
 
 
 static void uv__finish_close(uv_handle_t* handle) {
-  /* Note: while the handle is in the UV_CLOSING state now, it's still possible
-   * for it to be active in the sense that uv__is_active() returns true.
+  /* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still
+   * possible for it to be active in the sense that uv__is_active() returns
+   * true.
+   *
    * A good example is when the user calls uv_shutdown(), immediately followed
    * by uv_close(). The handle is considered active at this point because the
    * completion of the shutdown req is still pending.
    */
-  assert(handle->flags & UV_CLOSING);
-  assert(!(handle->flags & UV_CLOSED));
-  handle->flags |= UV_CLOSED;
+  assert(handle->flags & UV_HANDLE_CLOSING);
+  assert(!(handle->flags & UV_HANDLE_CLOSED));
+  handle->flags |= UV_HANDLE_CLOSED;
 
   switch (handle->type) {
     case UV_PREPARE:
@@ -634,27 +637,6 @@ int uv__cloexec_fcntl(int fd, int set) {
 }
 
 
-/* This function is not execve-safe, there is a race window
- * between the call to dup() and fcntl(FD_CLOEXEC).
- */
-int uv__dup(int fd) {
-  int err;
-
-  fd = dup(fd);
-
-  if (fd == -1)
-    return UV__ERR(errno);
-
-  err = uv__cloexec(fd, 1);
-  if (err) {
-    uv__close(fd);
-    return err;
-  }
-
-  return fd;
-}
-
-
 ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
   struct cmsghdr* cmsg;
   ssize_t rc;
@@ -927,6 +909,11 @@ int uv__io_active(const uv__io_t* w, unsigned int events) {
 }
 
 
+int uv__fd_exists(uv_loop_t* loop, int fd) {
+  return (unsigned) fd < loop->nwatchers && loop->watchers[fd] != NULL;
+}
+
+
 int uv_getrusage(uv_rusage_t* rusage) {
   struct rusage usage;
 
@@ -1331,6 +1318,9 @@ uv_os_fd_t uv_get_osfhandle(int fd) {
   return fd;
 }
 
+int uv_open_osfhandle(uv_os_fd_t os_fd) {
+  return os_fd;
+}
 
 uv_pid_t uv_os_getpid(void) {
   return getpid();
@@ -1340,3 +1330,87 @@ uv_pid_t uv_os_getpid(void) {
 uv_pid_t uv_os_getppid(void) {
   return getppid();
 }
+
+
+int uv_os_getpriority(uv_pid_t pid, int* priority) {
+  int r;
+
+  if (priority == NULL)
+    return UV_EINVAL;
+
+  errno = 0;
+  r = getpriority(PRIO_PROCESS, (int) pid);
+
+  if (r == -1 && errno != 0)
+    return UV__ERR(errno);
+
+  *priority = r;
+  return 0;
+}
+
+
+int uv_os_setpriority(uv_pid_t pid, int priority) {
+  if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
+    return UV_EINVAL;
+
+  if (setpriority(PRIO_PROCESS, (int) pid, priority) != 0)
+    return UV__ERR(errno);
+
+  return 0;
+}
+
+
+int uv_os_uname(uv_utsname_t* buffer) {
+  struct utsname buf;
+  int r;
+
+  if (buffer == NULL)
+    return UV_EINVAL;
+
+  if (uname(&buf) == -1) {
+    r = UV__ERR(errno);
+    goto error;
+  }
+
+  r = uv__strscpy(buffer->sysname, buf.sysname, sizeof(buffer->sysname));
+  if (r == UV_E2BIG)
+    goto error;
+
+#ifdef _AIX
+  r = snprintf(buffer->release,
+               sizeof(buffer->release),
+               "%s.%s",
+               buf.version,
+               buf.release);
+  if (r >= sizeof(buffer->release)) {
+    r = UV_E2BIG;
+    goto error;
+  }
+#else
+  r = uv__strscpy(buffer->release, buf.release, sizeof(buffer->release));
+  if (r == UV_E2BIG)
+    goto error;
+#endif
+
+  r = uv__strscpy(buffer->version, buf.version, sizeof(buffer->version));
+  if (r == UV_E2BIG)
+    goto error;
+
+#if defined(_AIX) || defined(__PASE__)
+  r = uv__strscpy(buffer->machine, "ppc64", sizeof(buffer->machine));
+#else
+  r = uv__strscpy(buffer->machine, buf.machine, sizeof(buffer->machine));
+#endif
+
+  if (r == UV_E2BIG)
+    goto error;
+
+  return 0;
+
+error:
+  buffer->sysname[0] = '\0';
+  buffer->release[0] = '\0';
+  buffer->version[0] = '\0';
+  buffer->machine[0] = '\0';
+  return r;
+}

+ 1 - 1
src/unix/cygwin.c

@@ -38,7 +38,7 @@ int uv_uptime(double* uptime) {
 int uv_resident_set_memory(size_t* rss) {
   /* FIXME: read /proc/meminfo? */
   *rss = 0;
-  return UV_ENOSYS;
+  return 0;
 }
 
 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {

+ 68 - 79
src/unix/darwin-proctitle.c

@@ -33,61 +33,56 @@
 # include <ApplicationServices/ApplicationServices.h>
 #endif
 
+#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
 
-static int uv__pthread_setname_np(const char* name) {
-  int (*dynamic_pthread_setname_np)(const char* name);
-  char namebuf[64];  /* MAXTHREADNAMESIZE */
-  int err;
-
-  /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */
-  *(void **)(&dynamic_pthread_setname_np) =
-      dlsym(RTLD_DEFAULT, "pthread_setname_np");
-
-  if (dynamic_pthread_setname_np == NULL)
-    return UV_ENOSYS;
-
-  strncpy(namebuf, name, sizeof(namebuf) - 1);
-  namebuf[sizeof(namebuf) - 1] = '\0';
 
-  err = dynamic_pthread_setname_np(namebuf);
-  if (err)
-    return UV__ERR(err);
+static int (*dynamic_pthread_setname_np)(const char* name);
+#if !TARGET_OS_IPHONE
+static CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
+                                                 const char*,
+                                                 CFStringEncoding);
+static CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
+static void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
+static void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
+static CFTypeRef (*pLSGetCurrentApplicationASN)(void);
+static OSStatus (*pLSSetApplicationInformationItem)(int,
+                                                    CFTypeRef,
+                                                    CFStringRef,
+                                                    CFStringRef,
+                                                    CFDictionaryRef*);
+static void* application_services_handle;
+static void* core_foundation_handle;
+static CFBundleRef launch_services_bundle;
+static CFStringRef* display_name_key;
+static CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
+static CFBundleRef (*pCFBundleGetMainBundle)(void);
+static CFBundleRef hi_services_bundle;
+static OSStatus (*pSetApplicationIsDaemon)(int);
+static CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
+static void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
+                                                                     void*);
+
+
+UV_DESTRUCTOR(static void uv__set_process_title_platform_fini(void)) {
+  if (core_foundation_handle != NULL) {
+    dlclose(core_foundation_handle);
+    core_foundation_handle = NULL;
+  }
 
-  return 0;
+  if (application_services_handle != NULL) {
+    dlclose(application_services_handle);
+    application_services_handle = NULL;
+  }
 }
+#endif  /* !TARGET_OS_IPHONE */
 
 
-int uv__set_process_title(const char* title) {
-#if TARGET_OS_IPHONE
-  return uv__pthread_setname_np(title);
-#else
-  CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
-                                            const char*,
-                                            CFStringEncoding);
-  CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
-  void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
-  void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
-  CFTypeRef (*pLSGetCurrentApplicationASN)(void);
-  OSStatus (*pLSSetApplicationInformationItem)(int,
-                                               CFTypeRef,
-                                               CFStringRef,
-                                               CFStringRef,
-                                               CFDictionaryRef*);
-  void* application_services_handle;
-  void* core_foundation_handle;
-  CFBundleRef launch_services_bundle;
-  CFStringRef* display_name_key;
-  CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
-  CFBundleRef (*pCFBundleGetMainBundle)(void);
-  CFBundleRef hi_services_bundle;
-  OSStatus (*pSetApplicationIsDaemon)(int);
-  CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
-  void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
-                                                                void*);
-  CFTypeRef asn;
-  int err;
-
-  err = UV_ENOENT;
+void uv__set_process_title_platform_init(void) {
+  /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */
+  *(void **)(&dynamic_pthread_setname_np) =
+      dlsym(RTLD_DEFAULT, "pthread_setname_np");
+
+#if !TARGET_OS_IPHONE
   application_services_handle = dlopen("/System/Library/Frameworks/"
                                        "ApplicationServices.framework/"
                                        "Versions/A/ApplicationServices",
@@ -116,8 +111,6 @@ int uv__set_process_title(const char* title) {
     goto out;
   }
 
-#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
-
   launch_services_bundle =
       pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
 
@@ -148,13 +141,14 @@ int uv__set_process_title(const char* title) {
                                      "CFBundleGetInfoDictionary");
   *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
                                  "CFBundleGetMainBundle");
+
   if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
     goto out;
 
   /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
   hi_services_bundle =
       pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices"));
-  err = UV_ENOENT;
+
   if (hi_services_bundle == NULL)
     goto out;
 
@@ -168,42 +162,37 @@ int uv__set_process_title(const char* title) {
       pCFBundleGetFunctionPointerForName(
           launch_services_bundle,
           S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
+
   if (pSetApplicationIsDaemon == NULL ||
       pLSApplicationCheckIn == NULL ||
       pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
     goto out;
   }
 
-  if (pSetApplicationIsDaemon(1) != noErr)
-    goto out;
-
-  pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
-
-  /* Check into process manager?! */
-  pLSApplicationCheckIn(-2,
-                        pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
-
-  asn = pLSGetCurrentApplicationASN();
-
-  err = UV_EINVAL;
-  if (pLSSetApplicationInformationItem(-2,  /* Magic value. */
-                                       asn,
-                                       *display_name_key,
-                                       S(title),
-                                       NULL) != noErr) {
-    goto out;
-  }
-
-  uv__pthread_setname_np(title);  /* Don't care if it fails. */
-  err = 0;
+  return;
 
 out:
-  if (core_foundation_handle != NULL)
-    dlclose(core_foundation_handle);
+  uv__set_process_title_platform_fini();
+#endif  /* !TARGET_OS_IPHONE */
+}
 
-  if (application_services_handle != NULL)
-    dlclose(application_services_handle);
 
-  return err;
+void uv__set_process_title(const char* title) {
+#if !TARGET_OS_IPHONE
+  if (core_foundation_handle != NULL && pSetApplicationIsDaemon(1) != noErr) {
+    CFTypeRef asn;
+    pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
+    pLSApplicationCheckIn(/* Magic value */ -2,
+                          pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
+    asn = pLSGetCurrentApplicationASN();
+    pLSSetApplicationInformationItem(/* Magic value */ -2, asn,
+                                     *display_name_key, S(title), NULL);
+  }
 #endif  /* !TARGET_OS_IPHONE */
+
+  if (dynamic_pthread_setname_np != NULL) {
+    char namebuf[64];  /* MAXTHREADNAMESIZE */
+    uv__strscpy(namebuf, title, sizeof(namebuf));
+    dynamic_pthread_setname_np(namebuf);
+  }
 }

+ 0 - 79
src/unix/freebsd.c

@@ -47,15 +47,6 @@
 # define CP_INTR 4
 #endif
 
-static uv_mutex_t process_title_mutex;
-static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
-static char *process_title;
-
-
-static void init_process_title_mutex_once(void) {
-  uv_mutex_init(&process_title_mutex);
-}
-
 
 int uv__platform_loop_init(uv_loop_t* loop) {
   return uv__kqueue_init(loop);
@@ -159,76 +150,6 @@ void uv_loadavg(double avg[3]) {
 }
 
 
-char** uv_setup_args(int argc, char** argv) {
-  process_title = argc ? uv__strdup(argv[0]) : NULL;
-  return argv;
-}
-
-
-int uv_set_process_title(const char* title) {
-  int oid[4];
-  char* new_title;
-
-  new_title = uv__strdup(title);
-
-  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
-  uv_mutex_lock(&process_title_mutex);
-
-  if (process_title == NULL) {
-    uv_mutex_unlock(&process_title_mutex);
-    return UV_ENOMEM;
-  }
-
-  uv__free(process_title);
-  process_title = new_title;
-
-  oid[0] = CTL_KERN;
-  oid[1] = KERN_PROC;
-  oid[2] = KERN_PROC_ARGS;
-  oid[3] = getpid();
-
-  sysctl(oid,
-         ARRAY_SIZE(oid),
-         NULL,
-         NULL,
-         process_title,
-         strlen(process_title) + 1);
-
-  uv_mutex_unlock(&process_title_mutex);
-
-  return 0;
-}
-
-
-int uv_get_process_title(char* buffer, size_t size) {
-  size_t len;
-
-  if (buffer == NULL || size == 0)
-    return UV_EINVAL;
-
-  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
-  uv_mutex_lock(&process_title_mutex);
-
-  if (process_title) {
-    len = strlen(process_title) + 1;
-
-    if (size < len) {
-      uv_mutex_unlock(&process_title_mutex);
-      return UV_ENOBUFS;
-    }
-
-    memcpy(buffer, process_title, len);
-  } else {
-    len = 0;
-  }
-
-  uv_mutex_unlock(&process_title_mutex);
-
-  buffer[len] = '\0';
-
-  return 0;
-}
-
 int uv_resident_set_memory(size_t* rss) {
   struct kinfo_proc kinfo;
   size_t page_size;

+ 201 - 139
src/unix/fs.c

@@ -43,7 +43,6 @@
 #include <pthread.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <utime.h>
 #include <poll.h>
 
 #if defined(__DragonFly__)        ||                                      \
@@ -62,11 +61,20 @@
 
 #if defined(__APPLE__)
 # include <copyfile.h>
+# include <sys/sysctl.h>
 #elif defined(__linux__) && !defined(FICLONE)
 # include <sys/ioctl.h>
 # define FICLONE _IOW(0x94, 9, int)
 #endif
 
+#if defined(_AIX) && !defined(_AIX71)
+# include <utime.h>
+#endif
+
+#if defined(_AIX) && _XOPEN_SOURCE <= 600
+extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
+#endif
+
 #define INIT(subtype)                                                         \
   do {                                                                        \
     if (req == NULL)                                                          \
@@ -120,7 +128,11 @@
   do {                                                                        \
     if (cb != NULL) {                                                         \
       uv__req_register(loop, req);                                            \
-      uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done);        \
+      uv__work_submit(loop,                                                   \
+                      &req->work_req,                                         \
+                      UV__WORK_FAST_IO,                                       \
+                      uv__fs_work,                                            \
+                      uv__fs_done);                                           \
       return 0;                                                               \
     }                                                                         \
     else {                                                                    \
@@ -143,7 +155,7 @@ static ssize_t uv__fs_fsync(uv_fs_t* req) {
   int r;
 
   r = fcntl(req->file, F_FULLFSYNC);
-  if (r != 0 && errno == ENOTTY)
+  if (r != 0)
     r = fsync(req->file);
   return r;
 #else
@@ -165,59 +177,17 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
 
 
 static ssize_t uv__fs_futime(uv_fs_t* req) {
-#if defined(__linux__)
+#if defined(__linux__)                                                        \
+    || defined(_AIX71)
   /* utimesat() has nanosecond resolution but we stick to microseconds
    * for the sake of consistency with other platforms.
    */
-  static int no_utimesat;
   struct timespec ts[2];
-  struct timeval tv[2];
-  char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)];
-  int r;
-
-  if (no_utimesat)
-    goto skip;
-
   ts[0].tv_sec  = req->atime;
   ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
   ts[1].tv_sec  = req->mtime;
   ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
-
-  r = uv__utimesat(req->file, NULL, ts, 0);
-  if (r == 0)
-    return r;
-
-  if (errno != ENOSYS)
-    return r;
-
-  no_utimesat = 1;
-
-skip:
-
-  tv[0].tv_sec  = req->atime;
-  tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
-  tv[1].tv_sec  = req->mtime;
-  tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
-  snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file);
-
-  r = utimes(path, tv);
-  if (r == 0)
-    return r;
-
-  switch (errno) {
-  case ENOENT:
-    if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF)
-      break;
-    /* Fall through. */
-
-  case EACCES:
-  case ENOTDIR:
-    errno = ENOSYS;
-    break;
-  }
-
-  return r;
-
+  return futimens(req->file, ts);
 #elif defined(__APPLE__)                                                      \
     || defined(__DragonFly__)                                                 \
     || defined(__FreeBSD__)                                                   \
@@ -235,13 +205,6 @@ skip:
 # else
   return futimes(req->file, tv);
 # endif
-#elif defined(_AIX71)
-  struct timespec ts[2];
-  ts[0].tv_sec  = req->atime;
-  ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
-  ts[1].tv_sec  = req->mtime;
-  ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
-  return futimens(req->file, ts);
 #elif defined(__MVS__)
   attrib_t atr;
   memset(&atr, 0, sizeof(atr));
@@ -304,17 +267,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
 #if defined(__linux__)
   static int no_preadv;
 #endif
+  unsigned int iovmax;
   ssize_t result;
 
-#if defined(_AIX)
-  struct stat buf;
-  if(fstat(req->file, &buf))
-    return -1;
-  if(S_ISDIR(buf.st_mode)) {
-    errno = EISDIR;
-    return -1;
-  }
-#endif /* defined(_AIX) */
+  iovmax = uv__getiovmax();
+  if (req->nbufs > iovmax)
+    req->nbufs = iovmax;
+
   if (req->off < 0) {
     if (req->nbufs == 1)
       result = read(req->file, req->bufs[0].base, req->bufs[0].len);
@@ -333,25 +292,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
     if (no_preadv) retry:
 # endif
     {
-      off_t nread;
-      size_t index;
-
-      nread = 0;
-      index = 0;
-      result = 1;
-      do {
-        if (req->bufs[index].len > 0) {
-          result = pread(req->file,
-                         req->bufs[index].base,
-                         req->bufs[index].len,
-                         req->off + nread);
-          if (result > 0)
-            nread += result;
-        }
-        index++;
-      } while (index < req->nbufs && result > 0);
-      if (nread > 0)
-        result = nread;
+      result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
     }
 # if defined(__linux__)
     else {
@@ -369,6 +310,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
   }
 
 done:
+  /* Early cleanup of bufs allocation, since we're done with it. */
+  if (req->bufs != req->bufsml)
+    uv__free(req->bufs);
+
+  req->bufs = NULL;
+  req->nbufs = 0;
+
   return result;
 }
 
@@ -415,29 +363,55 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) {
   return n;
 }
 
+#if defined(_POSIX_PATH_MAX)
+# define UV__FS_PATH_MAX _POSIX_PATH_MAX
+#elif defined(PATH_MAX)
+# define UV__FS_PATH_MAX PATH_MAX
+#else
+# define UV__FS_PATH_MAX_FALLBACK 8192
+# define UV__FS_PATH_MAX UV__FS_PATH_MAX_FALLBACK
+#endif
 
 static ssize_t uv__fs_pathmax_size(const char* path) {
   ssize_t pathmax;
 
   pathmax = pathconf(path, _PC_PATH_MAX);
 
-  if (pathmax == -1) {
-#if defined(PATH_MAX)
-    return PATH_MAX;
-#else
-#error "PATH_MAX undefined in the current platform"
-#endif
-  }
+  if (pathmax == -1)
+    pathmax = UV__FS_PATH_MAX;
 
   return pathmax;
 }
 
 static ssize_t uv__fs_readlink(uv_fs_t* req) {
+  ssize_t maxlen;
   ssize_t len;
   char* buf;
+  char* newbuf;
 
-  len = uv__fs_pathmax_size(req->path);
-  buf = uv__malloc(len + 1);
+#if defined(UV__FS_PATH_MAX_FALLBACK)
+  /* We may not have a real PATH_MAX.  Read size of link.  */
+  struct stat st;
+  int ret;
+  ret = lstat(req->path, &st);
+  if (ret != 0)
+    return -1;
+  if (!S_ISLNK(st.st_mode)) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  maxlen = st.st_size;
+
+  /* According to readlink(2) lstat can report st_size == 0
+     for some symlinks, such as those in /proc or /sys.  */
+  if (maxlen == 0)
+    maxlen = uv__fs_pathmax_size(req->path);
+#else
+  maxlen = uv__fs_pathmax_size(req->path);
+#endif
+
+  buf = uv__malloc(maxlen);
 
   if (buf == NULL) {
     errno = ENOMEM;
@@ -445,17 +419,28 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
   }
 
 #if defined(__MVS__)
-  len = os390_readlink(req->path, buf, len);
+  len = os390_readlink(req->path, buf, maxlen);
 #else
-  len = readlink(req->path, buf, len);
+  len = readlink(req->path, buf, maxlen);
 #endif
 
-
   if (len == -1) {
     uv__free(buf);
     return -1;
   }
 
+  /* Uncommon case: resize to make room for the trailing nul byte. */
+  if (len == maxlen) {
+    newbuf = uv__realloc(buf, len + 1);
+
+    if (newbuf == NULL) {
+      uv__free(buf);
+      return -1;
+    }
+
+    buf = newbuf;
+  }
+
   buf[len] = '\0';
   req->ptr = buf;
 
@@ -463,9 +448,15 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
 }
 
 static ssize_t uv__fs_realpath(uv_fs_t* req) {
-  ssize_t len;
   char* buf;
 
+#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L
+  buf = realpath(req->path, NULL);
+  if (buf == NULL)
+    return -1;
+#else
+  ssize_t len;
+
   len = uv__fs_pathmax_size(req->path);
   buf = uv__malloc(len + 1);
 
@@ -478,6 +469,7 @@ static ssize_t uv__fs_realpath(uv_fs_t* req) {
     uv__free(buf);
     return -1;
   }
+#endif
 
   req->ptr = buf;
 
@@ -698,10 +690,48 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
 
 
 static ssize_t uv__fs_utime(uv_fs_t* req) {
+#if defined(__linux__)                                                         \
+    || defined(_AIX71)                                                         \
+    || defined(__sun)
+  /* utimesat() has nanosecond resolution but we stick to microseconds
+   * for the sake of consistency with other platforms.
+   */
+  struct timespec ts[2];
+  ts[0].tv_sec  = req->atime;
+  ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
+  ts[1].tv_sec  = req->mtime;
+  ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
+  return utimensat(AT_FDCWD, req->path, ts, 0);
+#elif defined(__APPLE__)                                                      \
+    || defined(__DragonFly__)                                                 \
+    || defined(__FreeBSD__)                                                   \
+    || defined(__FreeBSD_kernel__)                                            \
+    || defined(__NetBSD__)                                                    \
+    || defined(__OpenBSD__)
+  struct timeval tv[2];
+  tv[0].tv_sec  = req->atime;
+  tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
+  tv[1].tv_sec  = req->mtime;
+  tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
+  return utimes(req->path, tv);
+#elif defined(_AIX)                                                           \
+    && !defined(_AIX71)
   struct utimbuf buf;
   buf.actime = req->atime;
   buf.modtime = req->mtime;
-  return utime(req->path, &buf); /* TODO use utimes() where available */
+  return utime(req->path, &buf);
+#elif defined(__MVS__)
+  attrib_t atr;
+  memset(&atr, 0, sizeof(atr));
+  atr.att_mtimechg = 1;
+  atr.att_atimechg = 1;
+  atr.att_mtime = req->mtime;
+  atr.att_atime = req->atime;
+  return __lchattr((char*) req->path, &atr, sizeof(atr));
+#else
+  errno = ENOSYS;
+  return -1;
+#endif
 }
 
 
@@ -739,25 +769,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
     if (no_pwritev) retry:
 # endif
     {
-      off_t written;
-      size_t index;
-
-      written = 0;
-      index = 0;
-      r = 0;
-      do {
-        if (req->bufs[index].len > 0) {
-          r = pwrite(req->file,
-                     req->bufs[index].base,
-                     req->bufs[index].len,
-                     req->off + written);
-          if (r > 0)
-            written += r;
-        }
-        index++;
-      } while (index < req->nbufs && r >= 0);
-      if (written > 0)
-        r = written;
+      r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
     }
 # if defined(__linux__)
     else {
@@ -786,26 +798,41 @@ done:
 static ssize_t uv__fs_copyfile(uv_fs_t* req) {
 #if defined(__APPLE__) && !TARGET_OS_IPHONE
   /* On macOS, use the native copyfile(3). */
+  static int can_clone;
   copyfile_flags_t flags;
+  char buf[64];
+  size_t len;
+  int major;
 
   flags = COPYFILE_ALL;
 
   if (req->flags & UV_FS_COPYFILE_EXCL)
     flags |= COPYFILE_EXCL;
 
-#ifdef COPYFILE_CLONE
-  if (req->flags & UV_FS_COPYFILE_FICLONE)
-    flags |= COPYFILE_CLONE;
-#endif
-
+  /* Check OS version. Cloning is only supported on macOS >= 10.12. */
   if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
-#ifdef COPYFILE_CLONE_FORCE
-    flags |= COPYFILE_CLONE_FORCE;
-#else
-    return UV_ENOSYS;
-#endif
+    if (can_clone == 0) {
+      len = sizeof(buf);
+      if (sysctlbyname("kern.osrelease", buf, &len, NULL, 0))
+        return UV__ERR(errno);
+
+      if (1 != sscanf(buf, "%d", &major))
+        abort();
+
+      can_clone = -1 + 2 * (major >= 16);  /* macOS >= 10.12 */
+    }
+
+    if (can_clone < 0)
+      return UV_ENOSYS;
   }
 
+  /* copyfile() simply ignores COPYFILE_CLONE if it's not supported. */
+  if (req->flags & UV_FS_COPYFILE_FICLONE)
+    flags |= 1 << 24;  /* COPYFILE_CLONE */
+
+  if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE)
+    flags |= 1 << 25;  /* COPYFILE_CLONE_FORCE */
+
   return copyfile(req->path, req->new_path, NULL, flags);
 #else
   uv_fs_t fs_req;
@@ -865,9 +892,11 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
       /* If an error occurred that the sendfile fallback also won't handle, or
          this is a force clone then exit. Otherwise, fall through to try using
          sendfile(). */
-      if ((errno != ENOTTY && errno != EOPNOTSUPP && errno != EXDEV) ||
-          req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
-        err = -errno;
+      if (errno != ENOTTY && errno != EOPNOTSUPP && errno != EXDEV) {
+        err = UV__ERR(errno);
+        goto out;
+      } else if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
+        err = UV_ENOTSUP;
         goto out;
       }
     } else {
@@ -927,7 +956,11 @@ out:
     }
   }
 
-  return result;
+  if (result == 0)
+    return 0;
+
+  errno = UV__ERR(result);
+  return -1;
 #endif
 }
 
@@ -1043,9 +1076,21 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) {
   return ret;
 }
 
+static size_t uv__fs_buf_offset(uv_buf_t* bufs, size_t size) {
+  size_t offset;
+  /* Figure out which bufs are done */
+  for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset)
+    size -= bufs[offset].len;
 
-typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req);
-static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) {
+  /* Fix a partial read/write */
+  if (size > 0) {
+    bufs[offset].base += size;
+    bufs[offset].len -= size;
+  }
+  return offset;
+}
+
+static ssize_t uv__fs_write_all(uv_fs_t* req) {
   unsigned int iovmax;
   unsigned int nbufs;
   uv_buf_t* bufs;
@@ -1062,7 +1107,10 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process)
     if (req->nbufs > iovmax)
       req->nbufs = iovmax;
 
-    result = process(req);
+    do
+      result = uv__fs_write(req);
+    while (result < 0 && errno == EINTR);
+
     if (result <= 0) {
       if (total == 0)
         total = result;
@@ -1072,14 +1120,12 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process)
     if (req->off >= 0)
       req->off += result;
 
+    req->nbufs = uv__fs_buf_offset(req->bufs, result);
     req->bufs += req->nbufs;
     nbufs -= req->nbufs;
     total += result;
   }
 
-  if (errno == EINTR && total == -1)
-    return total;
-
   if (bufs != req->bufsml)
     uv__free(bufs);
 
@@ -1096,7 +1142,8 @@ static void uv__fs_work(struct uv__work* w) {
   ssize_t r;
 
   req = container_of(w, uv_fs_t, work_req);
-  retry_on_eintr = !(req->fs_type == UV_FS_CLOSE);
+  retry_on_eintr = !(req->fs_type == UV_FS_CLOSE ||
+                     req->fs_type == UV_FS_READ);
 
   do {
     errno = 0;
@@ -1114,6 +1161,7 @@ static void uv__fs_work(struct uv__work* w) {
     X(COPYFILE, uv__fs_copyfile(req));
     X(FCHMOD, fchmod(req->file, req->mode));
     X(FCHOWN, fchown(req->file, req->uid, req->gid));
+    X(LCHOWN, lchown(req->path, req->uid, req->gid));
     X(FDATASYNC, uv__fs_fdatasync(req));
     X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
     X(FSYNC, uv__fs_fsync(req));
@@ -1124,7 +1172,7 @@ static void uv__fs_work(struct uv__work* w) {
     X(MKDIR, mkdir(req->path, req->mode));
     X(MKDTEMP, uv__fs_mkdtemp(req));
     X(OPEN, uv__fs_open(req));
-    X(READ, uv__fs_buf_iter(req, uv__fs_read));
+    X(READ, uv__fs_read(req));
     X(SCANDIR, uv__fs_scandir(req));
     X(READLINK, uv__fs_readlink(req));
     X(REALPATH, uv__fs_realpath(req));
@@ -1135,7 +1183,7 @@ static void uv__fs_work(struct uv__work* w) {
     X(SYMLINK, symlink(req->path, req->new_path));
     X(UNLINK, unlink(req->path));
     X(UTIME, uv__fs_utime(req));
-    X(WRITE, uv__fs_buf_iter(req, uv__fs_write));
+    X(WRITE, uv__fs_write_all(req));
     default: abort();
     }
 #undef X
@@ -1240,6 +1288,20 @@ int uv_fs_fchown(uv_loop_t* loop,
 }
 
 
+int uv_fs_lchown(uv_loop_t* loop,
+                 uv_fs_t* req,
+                 const char* path,
+                 uv_uid_t uid,
+                 uv_gid_t gid,
+                 uv_fs_cb cb) {
+  INIT(LCHOWN);
+  PATH;
+  req->uid = uid;
+  req->gid = gid;
+  POST;
+}
+
+
 int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
   INIT(FDATASYNC);
   req->file = file;

+ 37 - 35
src/unix/fsevents.c

@@ -255,42 +255,55 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
       path = paths[i];
       len = strlen(path);
 
+      if (handle->realpath_len == 0)
+        continue; /* This should be unreachable */
+
       /* Filter out paths that are outside handle's request */
-      if (strncmp(path, handle->realpath, handle->realpath_len) != 0)
+      if (len < handle->realpath_len)
+        continue;
+
+      if (handle->realpath_len != len &&
+          path[handle->realpath_len] != '/')
+        /* Make sure that realpath actually named a directory,
+         * or that we matched the whole string */
         continue;
 
-      if (handle->realpath_len > 1 || *handle->realpath != '/') {
+      if (memcmp(path, handle->realpath, handle->realpath_len) != 0)
+        continue;
+
+      if (!(handle->realpath_len == 1 && handle->realpath[0] == '/')) {
+        /* Remove common prefix, unless the watched folder is "/" */
         path += handle->realpath_len;
         len -= handle->realpath_len;
 
-        /* Skip forward slash */
-        if (*path != '\0') {
+        /* Ignore events with path equal to directory itself */
+        if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir))
+          continue;
+
+        if (len == 0) {
+          /* Since we're using fsevents to watch the file itself,
+           * realpath == path, and we now need to get the basename of the file back
+           * (for commonality with other codepaths and platforms). */
+          while (len < handle->realpath_len && path[-1] != '/') {
+            path--;
+            len++;
+          }
+          /* Created and Removed seem to be always set, but don't make sense */
+          flags &= ~kFSEventsRenamed;
+        } else {
+          /* Skip forward slash */
           path++;
           len--;
         }
       }
 
-#ifdef MAC_OS_X_VERSION_10_7
-      /* Ignore events with path equal to directory itself */
-      if (len == 0)
-        continue;
-#else
-      if (len == 0 && (flags & kFSEventStreamEventFlagItemIsDir))
-        continue;
-#endif /* MAC_OS_X_VERSION_10_7 */
-
       /* Do not emit events from subdirectories (without option set) */
-      if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) {
+      if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != '\0') {
         pos = strchr(path + 1, '/');
         if (pos != NULL)
           continue;
       }
 
-#ifndef MAC_OS_X_VERSION_10_7
-      path = "";
-      len = 0;
-#endif /* MAC_OS_X_VERSION_10_7 */
-
       event = uv__malloc(sizeof(*event) + len);
       if (event == NULL)
         break;
@@ -299,22 +312,11 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
       memcpy(event->path, path, len + 1);
       event->events = UV_RENAME;
 
-#ifdef MAC_OS_X_VERSION_10_7
-      if (0 != (flags & kFSEventsModified) &&
-          0 == (flags & kFSEventsRenamed)) {
-        event->events = UV_CHANGE;
-      }
-#else
-      if (0 != (flags & kFSEventsModified) &&
-          0 != (flags & kFSEventStreamEventFlagItemIsDir) &&
-          0 == (flags & kFSEventStreamEventFlagItemRenamed)) {
-        event->events = UV_CHANGE;
-      }
-      if (0 == (flags & kFSEventStreamEventFlagItemIsDir) &&
-          0 == (flags & kFSEventStreamEventFlagItemRenamed)) {
-        event->events = UV_CHANGE;
+      if (0 == (flags & kFSEventsRenamed)) {
+        if (0 != (flags & kFSEventsModified) ||
+            0 == (flags & kFSEventStreamEventFlagItemIsDir))
+          event->events = UV_CHANGE;
       }
-#endif /* MAC_OS_X_VERSION_10_7 */
 
       QUEUE_INSERT_TAIL(&head, &event->member);
     }
@@ -836,7 +838,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
 
   handle->cf_cb->data = handle;
   uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
-  handle->cf_cb->flags |= UV__HANDLE_INTERNAL;
+  handle->cf_cb->flags |= UV_HANDLE_INTERNAL;
   uv_unref((uv_handle_t*) handle->cf_cb);
 
   err = uv_mutex_init(&handle->cf_mutex);

+ 21 - 0
src/unix/getaddrinfo.c

@@ -27,6 +27,7 @@
 
 #include "uv.h"
 #include "internal.h"
+#include "idna.h"
 
 #include <errno.h>
 #include <stddef.h> /* NULL */
@@ -141,15 +142,34 @@ int uv_getaddrinfo(uv_loop_t* loop,
                    const char* hostname,
                    const char* service,
                    const struct addrinfo* hints) {
+  char hostname_ascii[256];
   size_t hostname_len;
   size_t service_len;
   size_t hints_len;
   size_t len;
   char* buf;
+  long rc;
 
   if (req == NULL || (hostname == NULL && service == NULL))
     return UV_EINVAL;
 
+  /* FIXME(bnoordhuis) IDNA does not seem to work z/OS,
+   * probably because it uses EBCDIC rather than ASCII.
+   */
+#ifdef __MVS__
+  (void) &hostname_ascii;
+#else
+  if (hostname != NULL) {
+    rc = uv__idna_toascii(hostname,
+                          hostname + strlen(hostname),
+                          hostname_ascii,
+                          hostname_ascii + sizeof(hostname_ascii));
+    if (rc < 0)
+      return rc;
+    hostname = hostname_ascii;
+  }
+#endif
+
   hostname_len = hostname ? strlen(hostname) + 1 : 0;
   service_len = service ? strlen(service) + 1 : 0;
   hints_len = hints ? sizeof(*hints) : 0;
@@ -186,6 +206,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
   if (cb) {
     uv__work_submit(loop,
                     &req->work_req,
+                    UV__WORK_SLOW_IO,
                     uv__getaddrinfo_work,
                     uv__getaddrinfo_done);
     return 0;

+ 1 - 0
src/unix/getnameinfo.c

@@ -109,6 +109,7 @@ int uv_getnameinfo(uv_loop_t* loop,
   if (getnameinfo_cb) {
     uv__work_submit(loop,
                     &req->work_req,
+                    UV__WORK_SLOW_IO,
                     uv__getnameinfo_work,
                     uv__getnameinfo_done);
     return 0;

+ 2 - 1
src/unix/ibmi.c

@@ -72,7 +72,8 @@ void uv_loadavg(double avg[3]) {
 
 
 int uv_resident_set_memory(size_t* rss) {
-  return UV_ENOSYS;
+  *rss = 0;
+  return 0;
 }
 
 

+ 1 - 44
src/unix/internal.h

@@ -127,26 +127,6 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
 
 typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
 
-/* handle flags */
-enum {
-  UV_CLOSING              = 0x01,   /* uv_close() called but not finished. */
-  UV_CLOSED               = 0x02,   /* close(2) finished. */
-  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_STREAM_BLOCKING      = 0x80,   /* Synchronous writes. */
-  UV_STREAM_READ_PARTIAL  = 0x100,  /* read(2) read less than requested. */
-  UV_STREAM_READ_EOF      = 0x200,  /* read(2) read EOF. */
-  UV_TCP_NODELAY          = 0x400,  /* Disable Nagle. */
-  UV_TCP_KEEPALIVE        = 0x800,  /* Turn on keep-alive. */
-  UV_TCP_SINGLE_ACCEPT    = 0x1000, /* Only accept() when idle. */
-  UV_HANDLE_IPV6          = 0x10000, /* Handle is bound to a IPv6 socket. */
-  UV_UDP_PROCESSING       = 0x20000, /* Handle is running the send callback queue. */
-  UV_HANDLE_BOUND         = 0x40000  /* Handle is bound to an address and port */
-};
-
 /* loop flags */
 enum {
   UV_LOOP_BLOCK_SIGPROF = 1
@@ -205,7 +185,6 @@ int uv__nonblock_fcntl(int fd, int set);
 int uv__close(int fd); /* preserves errno */
 int uv__close_nocheckstdio(int fd);
 int uv__socket(int domain, int type, int protocol);
-int uv__dup(int fd);
 ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
 void uv__make_close_pending(uv_handle_t* handle);
 int uv__getiovmax(void);
@@ -219,6 +198,7 @@ int uv__io_active(const uv__io_t* w, unsigned int events);
 int uv__io_check_fd(uv_loop_t* loop, int fd);
 void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
 int uv__io_fork(uv_loop_t* loop);
+int uv__fd_exists(uv_loop_t* loop, int fd);
 
 /* async */
 void uv__async_stop(uv_loop_t* loop);
@@ -251,10 +231,6 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay);
 /* pipe */
 int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
 
-/* timer */
-void uv__run_timers(uv_loop_t* loop);
-int uv__next_timeout(const uv_loop_t* loop);
-
 /* signal */
 void uv__signal_close(uv_signal_t* handle);
 void uv__signal_global_once_init(void);
@@ -279,7 +255,6 @@ void uv__prepare_close(uv_prepare_t* handle);
 void uv__process_close(uv_process_t* handle);
 void uv__stream_close(uv_stream_t* handle);
 void uv__tcp_close(uv_tcp_t* handle);
-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);
 uv_handle_type uv__handle_type(int fd);
@@ -309,24 +284,6 @@ int uv__fsevents_init(uv_fs_event_t* handle);
 int uv__fsevents_close(uv_fs_event_t* handle);
 void uv__fsevents_loop_delete(uv_loop_t* loop);
 
-/* OSX < 10.7 has no file events, polyfill them */
-#ifndef MAC_OS_X_VERSION_10_7
-
-static const int kFSEventStreamCreateFlagFileEvents = 0x00000010;
-static const int kFSEventStreamEventFlagItemCreated = 0x00000100;
-static const int kFSEventStreamEventFlagItemRemoved = 0x00000200;
-static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400;
-static const int kFSEventStreamEventFlagItemRenamed = 0x00000800;
-static const int kFSEventStreamEventFlagItemModified = 0x00001000;
-static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000;
-static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000;
-static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000;
-static const int kFSEventStreamEventFlagItemIsFile = 0x00010000;
-static const int kFSEventStreamEventFlagItemIsDir = 0x00020000;
-static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000;
-
-#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */
-
 #endif /* defined(__APPLE__) */
 
 UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {

+ 41 - 42
src/unix/kqueue.c

@@ -261,8 +261,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
       w = loop->watchers[fd];
 
       if (w == NULL) {
-        /* File descriptor that we've stopped watching, disarm it. */
-        /* TODO batch up */
+        /* File descriptor that we've stopped watching, disarm it.
+         * TODO: batch up. */
         struct kevent events[1];
 
         EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
@@ -452,49 +452,48 @@ int uv_fs_event_start(uv_fs_event_t* handle,
                       uv_fs_event_cb cb,
                       const char* path,
                       unsigned int flags) {
-#if defined(__APPLE__)
-  struct stat statbuf;
-#endif /* defined(__APPLE__) */
   int fd;
 
   if (uv__is_active(handle))
     return UV_EINVAL;
 
-  /* TODO open asynchronously - but how do we report back errors? */
-  fd = open(path, O_RDONLY);
-  if (fd == -1)
-    return UV__ERR(errno);
-
-  uv__handle_start(handle);
-  uv__io_init(&handle->event_watcher, uv__fs_event, fd);
-  handle->path = uv__strdup(path);
-  handle->cb = cb;
-
 #if defined(__APPLE__)
-  if (uv__has_forked_with_cfrunloop)
-    goto fallback;
-
   /* Nullify field to perform checks later */
   handle->cf_cb = NULL;
   handle->realpath = NULL;
   handle->realpath_len = 0;
   handle->cf_flags = flags;
 
-  if (fstat(fd, &statbuf))
-    goto fallback;
-  /* FSEvents works only with directories */
-  if (!(statbuf.st_mode & S_IFDIR))
-    goto fallback;
-
-  /* The fallback fd is no longer needed */
-  uv__close(fd);
-  handle->event_watcher.fd = -1;
-
-  return uv__fsevents_init(handle);
-
-fallback:
+  if (!uv__has_forked_with_cfrunloop) {
+    int r;
+    /* The fallback fd is not used */
+    handle->event_watcher.fd = -1;
+    handle->path = uv__strdup(path);
+    if (handle->path == NULL)
+      return UV_ENOMEM;
+    handle->cb = cb;
+    r = uv__fsevents_init(handle);
+    if (r == 0) {
+      uv__handle_start(handle);
+    } else {
+      uv__free(handle->path);
+      handle->path = NULL;
+    }
+    return r;
+  }
 #endif /* defined(__APPLE__) */
 
+  /* TODO open asynchronously - but how do we report back errors? */
+  fd = open(path, O_RDONLY);
+  if (fd == -1)
+    return UV__ERR(errno);
+
+  handle->path = uv__strdup(path);
+  if (handle->path == NULL)
+    return UV_ENOMEM;
+  handle->cb = cb;
+  uv__handle_start(handle);
+  uv__io_init(&handle->event_watcher, uv__fs_event, fd);
   uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
 
   return 0;
@@ -502,29 +501,29 @@ fallback:
 
 
 int uv_fs_event_stop(uv_fs_event_t* handle) {
+  int r;
+  r = 0;
+
   if (!uv__is_active(handle))
     return 0;
 
   uv__handle_stop(handle);
 
 #if defined(__APPLE__)
-  if (uv__has_forked_with_cfrunloop || uv__fsevents_close(handle))
-#endif /* defined(__APPLE__) */
-  {
-    uv__io_close(handle->loop, &handle->event_watcher);
-  }
-
-  uv__free(handle->path);
-  handle->path = NULL;
+  if (!uv__has_forked_with_cfrunloop)
+    r = uv__fsevents_close(handle);
+#endif
 
   if (handle->event_watcher.fd != -1) {
-    /* When FSEvents is used, we don't use the event_watcher's fd under certain
-     * confitions. (see uv_fs_event_start) */
+    uv__io_close(handle->loop, &handle->event_watcher);
     uv__close(handle->event_watcher.fd);
     handle->event_watcher.fd = -1;
   }
 
-  return 0;
+  uv__free(handle->path);
+  handle->path = NULL;
+
+  return r;
 }
 
 

+ 50 - 67
src/unix/linux-core.c

@@ -20,7 +20,7 @@
 
 /* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their
  * EPOLL* counterparts.  We use the POLL* variants in this file because that
- * is what libuv uses elsewhere and it avoids a dependency on <sys/epoll.h>.
+ * is what libuv uses elsewhere.
  */
 
 #include "uv.h"
@@ -34,6 +34,7 @@
 #include <errno.h>
 
 #include <net/if.h>
+#include <sys/epoll.h>
 #include <sys/param.h>
 #include <sys/prctl.h>
 #include <sys/sysinfo.h>
@@ -51,7 +52,7 @@
 
 #ifdef HAVE_IFADDRS_H
 # if defined(__ANDROID__)
-#  include "android-ifaddrs.h"
+#  include "uv/android-ifaddrs.h"
 # else
 #  include <ifaddrs.h>
 # endif
@@ -84,13 +85,13 @@ static unsigned long read_cpufreq(unsigned int cpunum);
 int uv__platform_loop_init(uv_loop_t* loop) {
   int fd;
 
-  fd = uv__epoll_create1(UV__EPOLL_CLOEXEC);
+  fd = epoll_create1(EPOLL_CLOEXEC);
 
   /* epoll_create1() can fail either because it's not implemented (old kernel)
    * or because it doesn't understand the EPOLL_CLOEXEC flag.
    */
   if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
-    fd = uv__epoll_create(256);
+    fd = epoll_create(256);
 
     if (fd != -1)
       uv__cloexec(fd, 1);
@@ -134,20 +135,20 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
 
 
 void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
-  struct uv__epoll_event* events;
-  struct uv__epoll_event dummy;
+  struct epoll_event* events;
+  struct epoll_event dummy;
   uintptr_t i;
   uintptr_t nfds;
 
   assert(loop->watchers != NULL);
 
-  events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers];
+  events = (struct epoll_event*) loop->watchers[loop->nwatchers];
   nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
   if (events != NULL)
     /* Invalidate events with same file descriptor */
     for (i = 0; i < nfds; i++)
-      if ((int) events[i].data == fd)
-        events[i].data = -1;
+      if (events[i].data.fd == fd)
+        events[i].data.fd = -1;
 
   /* Remove the file descriptor from the epoll.
    * This avoids a problem where the same file description remains open
@@ -160,25 +161,26 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
      * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
      */
     memset(&dummy, 0, sizeof(dummy));
-    uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy);
+    epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
   }
 }
 
 
 int uv__io_check_fd(uv_loop_t* loop, int fd) {
-  struct uv__epoll_event e;
+  struct epoll_event e;
   int rc;
 
+  memset(&e, 0, sizeof(e));
   e.events = POLLIN;
-  e.data = -1;
+  e.data.fd = -1;
 
   rc = 0;
-  if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e))
+  if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e))
     if (errno != EEXIST)
       rc = UV__ERR(errno);
 
   if (rc == 0)
-    if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e))
+    if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e))
       abort();
 
   return rc;
@@ -195,16 +197,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
    * that being the largest value I have seen in the wild (and only once.)
    */
   static const int max_safe_timeout = 1789569;
-  static int no_epoll_pwait;
-  static int no_epoll_wait;
-  struct uv__epoll_event events[1024];
-  struct uv__epoll_event* pe;
-  struct uv__epoll_event e;
+  struct epoll_event events[1024];
+  struct epoll_event* pe;
+  struct epoll_event e;
   int real_timeout;
   QUEUE* q;
   uv__io_t* w;
   sigset_t sigset;
-  uint64_t sigmask;
+  sigset_t* psigset;
   uint64_t base;
   int have_signals;
   int nevents;
@@ -219,6 +219,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
     return;
   }
 
+  memset(&e, 0, sizeof(e));
+
   while (!QUEUE_EMPTY(&loop->watcher_queue)) {
     q = QUEUE_HEAD(&loop->watcher_queue);
     QUEUE_REMOVE(q);
@@ -230,35 +232,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
     assert(w->fd < (int) loop->nwatchers);
 
     e.events = w->pevents;
-    e.data = w->fd;
+    e.data.fd = w->fd;
 
     if (w->events == 0)
-      op = UV__EPOLL_CTL_ADD;
+      op = EPOLL_CTL_ADD;
     else
-      op = UV__EPOLL_CTL_MOD;
+      op = EPOLL_CTL_MOD;
 
     /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
      * events, skip the syscall and squelch the events after epoll_wait().
      */
-    if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
+    if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
       if (errno != EEXIST)
         abort();
 
-      assert(op == UV__EPOLL_CTL_ADD);
+      assert(op == EPOLL_CTL_ADD);
 
       /* We've reactivated a file descriptor that's been watched before. */
-      if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e))
+      if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e))
         abort();
     }
 
     w->events = w->pevents;
   }
 
-  sigmask = 0;
+  psigset = NULL;
   if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
     sigemptyset(&sigset);
     sigaddset(&sigset, SIGPROF);
-    sigmask |= 1 << (SIGPROF - 1);
+    psigset = &sigset;
   }
 
   assert(timeout >= -1);
@@ -273,30 +275,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
     if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
       timeout = max_safe_timeout;
 
-    if (sigmask != 0 && no_epoll_pwait != 0)
-      if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
-        abort();
-
-    if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
-      nfds = uv__epoll_pwait(loop->backend_fd,
-                             events,
-                             ARRAY_SIZE(events),
-                             timeout,
-                             sigmask);
-      if (nfds == -1 && errno == ENOSYS)
-        no_epoll_pwait = 1;
-    } else {
-      nfds = uv__epoll_wait(loop->backend_fd,
-                            events,
-                            ARRAY_SIZE(events),
-                            timeout);
-      if (nfds == -1 && errno == ENOSYS)
-        no_epoll_wait = 1;
-    }
-
-    if (sigmask != 0 && no_epoll_pwait != 0)
-      if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
-        abort();
+    nfds = epoll_pwait(loop->backend_fd,
+                       events,
+                       ARRAY_SIZE(events),
+                       timeout,
+                       psigset);
 
     /* Update loop->time unconditionally. It's tempting to skip the update when
      * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
@@ -317,12 +300,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
     }
 
     if (nfds == -1) {
-      if (errno == ENOSYS) {
-        /* epoll_wait() or epoll_pwait() failed, try the other system call. */
-        assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
-        continue;
-      }
-
       if (errno != EINTR)
         abort();
 
@@ -344,7 +321,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
     loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
     for (i = 0; i < nfds; i++) {
       pe = events + i;
-      fd = pe->data;
+      fd = pe->data.fd;
 
       /* Skip invalidated events, see uv__platform_invalidate_fd */
       if (fd == -1)
@@ -361,7 +338,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
          * Ignore all errors because we may be racing with another thread
          * when the file descriptor is closed.
          */
-        uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe);
+        epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe);
         continue;
       }
 
@@ -388,7 +365,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
        * free when we switch over to edge-triggered I/O.
        */
       if (pe->events == POLLERR || pe->events == POLLHUP)
-        pe->events |= w->pevents & (POLLIN | POLLOUT | UV__POLLPRI);
+        pe->events |=
+          w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
 
       if (pe->events != 0) {
         /* Run signal watchers last.  This also affects child process watchers
@@ -851,9 +829,10 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
   return !exclude_type;
 }
 
-int uv_interface_addresses(uv_interface_address_t** addresses,
-  int* count) {
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
 #ifndef HAVE_IFADDRS_H
+  *count = 0;
+  *addresses = NULL;
   return UV_ENOSYS;
 #else
   struct ifaddrs *addrs, *ent;
@@ -861,12 +840,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
   int i;
   struct sockaddr_ll *sll;
 
-  if (getifaddrs(&addrs))
-    return UV__ERR(errno);
-
   *count = 0;
   *addresses = NULL;
 
+  if (getifaddrs(&addrs))
+    return UV__ERR(errno);
+
   /* Count the number of interfaces */
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
     if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
@@ -875,8 +854,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
     (*count)++;
   }
 
-  if (*count == 0)
+  if (*count == 0) {
+    freeifaddrs(addrs);
     return 0;
+  }
 
   *addresses = uv__malloc(*count * sizeof(**addresses));
   if (!(*addresses)) {
@@ -920,6 +901,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
       if (strcmp(address->name, ent->ifa_name) == 0) {
         sll = (struct sockaddr_ll*)ent->ifa_addr;
         memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
+      } else {
+        memset(address->phys_addr, 0, sizeof(address->phys_addr));
       }
       address++;
     }

+ 5 - 3
src/unix/linux-inotify.c

@@ -19,7 +19,7 @@
  */
 
 #include "uv.h"
-#include "tree.h"
+#include "uv/tree.h"
 #include "internal.h"
 
 #include <stdint.h>
@@ -278,6 +278,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
                       const char* path,
                       unsigned int flags) {
   struct watcher_list* w;
+  size_t len;
   int events;
   int err;
   int wd;
@@ -306,12 +307,13 @@ int uv_fs_event_start(uv_fs_event_t* handle,
   if (w)
     goto no_insert;
 
-  w = uv__malloc(sizeof(*w) + strlen(path) + 1);
+  len = strlen(path) + 1;
+  w = uv__malloc(sizeof(*w) + len);
   if (w == NULL)
     return UV_ENOMEM;
 
   w->wd = wd;
-  w->path = strcpy((char*)(w + 1), path);
+  w->path = memcpy(w + 1, path, len);
   QUEUE_INIT(&w->watchers);
   w->iterating = 0;
   RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w);

+ 0 - 133
src/unix/linux-syscalls.c

@@ -77,56 +77,6 @@
 # endif
 #endif /* __NR_eventfd2 */
 
-#ifndef __NR_epoll_create
-# if defined(__x86_64__)
-#  define __NR_epoll_create 213
-# elif defined(__i386__)
-#  define __NR_epoll_create 254
-# elif defined(__arm__)
-#  define __NR_epoll_create (UV_SYSCALL_BASE + 250)
-# endif
-#endif /* __NR_epoll_create */
-
-#ifndef __NR_epoll_create1
-# if defined(__x86_64__)
-#  define __NR_epoll_create1 291
-# elif defined(__i386__)
-#  define __NR_epoll_create1 329
-# elif defined(__arm__)
-#  define __NR_epoll_create1 (UV_SYSCALL_BASE + 357)
-# endif
-#endif /* __NR_epoll_create1 */
-
-#ifndef __NR_epoll_ctl
-# if defined(__x86_64__)
-#  define __NR_epoll_ctl 233 /* used to be 214 */
-# elif defined(__i386__)
-#  define __NR_epoll_ctl 255
-# elif defined(__arm__)
-#  define __NR_epoll_ctl (UV_SYSCALL_BASE + 251)
-# endif
-#endif /* __NR_epoll_ctl */
-
-#ifndef __NR_epoll_wait
-# if defined(__x86_64__)
-#  define __NR_epoll_wait 232 /* used to be 215 */
-# elif defined(__i386__)
-#  define __NR_epoll_wait 256
-# elif defined(__arm__)
-#  define __NR_epoll_wait (UV_SYSCALL_BASE + 252)
-# endif
-#endif /* __NR_epoll_wait */
-
-#ifndef __NR_epoll_pwait
-# if defined(__x86_64__)
-#  define __NR_epoll_pwait 281
-# elif defined(__i386__)
-#  define __NR_epoll_pwait 319
-# elif defined(__arm__)
-#  define __NR_epoll_pwait (UV_SYSCALL_BASE + 346)
-# endif
-#endif /* __NR_epoll_pwait */
-
 #ifndef __NR_inotify_init
 # if defined(__x86_64__)
 #  define __NR_inotify_init 253
@@ -285,76 +235,6 @@ int uv__eventfd2(unsigned int count, int flags) {
 }
 
 
-int uv__epoll_create(int size) {
-#if defined(__NR_epoll_create)
-  return syscall(__NR_epoll_create, size);
-#else
-  return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__epoll_create1(int flags) {
-#if defined(__NR_epoll_create1)
-  return syscall(__NR_epoll_create1, flags);
-#else
-  return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) {
-#if defined(__NR_epoll_ctl)
-  return syscall(__NR_epoll_ctl, epfd, op, fd, events);
-#else
-  return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__epoll_wait(int epfd,
-                   struct uv__epoll_event* events,
-                   int nevents,
-                   int timeout) {
-#if defined(__NR_epoll_wait)
-  int result;
-  result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout);
-#if MSAN_ACTIVE
-  if (result > 0)
-    __msan_unpoison(events, sizeof(events[0]) * result);
-#endif
-  return result;
-#else
-  return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__epoll_pwait(int epfd,
-                    struct uv__epoll_event* events,
-                    int nevents,
-                    int timeout,
-                    uint64_t sigmask) {
-#if defined(__NR_epoll_pwait)
-  int result;
-  result = syscall(__NR_epoll_pwait,
-                   epfd,
-                   events,
-                   nevents,
-                   timeout,
-                   &sigmask,
-                   sizeof(sigmask));
-#if MSAN_ACTIVE
-  if (result > 0)
-    __msan_unpoison(events, sizeof(events[0]) * result);
-#endif
-  return result;
-#else
-  return errno = ENOSYS, -1;
-#endif
-}
-
-
 int uv__inotify_init(void) {
 #if defined(__NR_inotify_init)
   return syscall(__NR_inotify_init);
@@ -431,19 +311,6 @@ int uv__recvmmsg(int fd,
 }
 
 
-int uv__utimesat(int dirfd,
-                 const char* path,
-                 const struct timespec times[2],
-                 int flags)
-{
-#if defined(__NR_utimensat)
-  return syscall(__NR_utimensat, dirfd, path, times, flags);
-#else
-  return errno = ENOSYS, -1;
-#endif
-}
-
-
 ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
 #if defined(__NR_preadv)
   return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));

+ 0 - 34
src/unix/linux-syscalls.h

@@ -66,12 +66,6 @@
 # define UV__SOCK_NONBLOCK    UV__O_NONBLOCK
 #endif
 
-/* epoll flags */
-#define UV__EPOLL_CLOEXEC     UV__O_CLOEXEC
-#define UV__EPOLL_CTL_ADD     1
-#define UV__EPOLL_CTL_DEL     2
-#define UV__EPOLL_CTL_MOD     3
-
 /* inotify flags */
 #define UV__IN_ACCESS         0x001
 #define UV__IN_MODIFY         0x002
@@ -86,18 +80,6 @@
 #define UV__IN_DELETE_SELF    0x400
 #define UV__IN_MOVE_SELF      0x800
 
-#if defined(__x86_64__)
-struct uv__epoll_event {
-  uint32_t events;
-  uint64_t data;
-} __attribute__((packed));
-#else
-struct uv__epoll_event {
-  uint32_t events;
-  uint64_t data;
-};
-#endif
-
 struct uv__inotify_event {
   int32_t wd;
   uint32_t mask;
@@ -113,18 +95,6 @@ struct uv__mmsghdr {
 
 int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
 int uv__eventfd(unsigned int count);
-int uv__epoll_create(int size);
-int uv__epoll_create1(int flags);
-int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev);
-int uv__epoll_wait(int epfd,
-                   struct uv__epoll_event* events,
-                   int nevents,
-                   int timeout);
-int uv__epoll_pwait(int epfd,
-                    struct uv__epoll_event* events,
-                    int nevents,
-                    int timeout,
-                    uint64_t sigmask);
 int uv__eventfd2(unsigned int count, int flags);
 int uv__inotify_init(void);
 int uv__inotify_init1(int flags);
@@ -140,10 +110,6 @@ int uv__sendmmsg(int fd,
                  struct uv__mmsghdr* mmsg,
                  unsigned int vlen,
                  unsigned int flags);
-int uv__utimesat(int dirfd,
-                 const char* path,
-                 const struct timespec times[2],
-                 int flags);
 ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
 ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
 int uv__dup3(int oldfd, int newfd, int flags);

+ 3 - 3
src/unix/loop.c

@@ -20,7 +20,7 @@
  */
 
 #include "uv.h"
-#include "tree.h"
+#include "uv/tree.h"
 #include "internal.h"
 #include "heap-inl.h"
 #include <stdlib.h>
@@ -74,7 +74,7 @@ int uv_loop_init(uv_loop_t* loop) {
     goto fail_signal_init;
 
   uv__handle_unref(&loop->child_watcher);
-  loop->child_watcher.flags |= UV__HANDLE_INTERNAL;
+  loop->child_watcher.flags |= UV_HANDLE_INTERNAL;
   QUEUE_INIT(&loop->process_handles);
 
   err = uv_rwlock_init(&loop->cloexec_lock);
@@ -90,7 +90,7 @@ int uv_loop_init(uv_loop_t* loop) {
     goto fail_async_init;
 
   uv__handle_unref(&loop->wq_async);
-  loop->wq_async.flags |= UV__HANDLE_INTERNAL;
+  loop->wq_async.flags |= UV_HANDLE_INTERNAL;
 
   return 0;
 

+ 2 - 69
src/unix/netbsd.c

@@ -40,15 +40,6 @@
 #include <unistd.h>
 #include <time.h>
 
-static uv_mutex_t process_title_mutex;
-static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
-static char *process_title;
-
-
-static void init_process_title_mutex_once(void) {
-  uv_mutex_init(&process_title_mutex);
-}
-
 
 int uv__platform_loop_init(uv_loop_t* loop) {
   return uv__kqueue_init(loop);
@@ -96,7 +87,8 @@ int uv_exepath(char* buffer, size_t* size) {
   /* Copy string from the intermediate buffer to outer one with appropriate
    * length.
    */
-  strlcpy(buffer, int_buf, *size);
+  /* TODO(bnoordhuis) Check uv__strscpy() return value. */
+  uv__strscpy(buffer, int_buf, *size);
 
   /* Set new size. */
   *size = strlen(buffer);
@@ -134,65 +126,6 @@ uint64_t uv_get_total_memory(void) {
 }
 
 
-char** uv_setup_args(int argc, char** argv) {
-  process_title = argc ? uv__strdup(argv[0]) : NULL;
-  return argv;
-}
-
-
-int uv_set_process_title(const char* title) {
-  char* new_title;
-
-  new_title = uv__strdup(title);
-
-  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
-  uv_mutex_lock(&process_title_mutex);
-
-  if (process_title == NULL) {
-    uv_mutex_unlock(&process_title_mutex);
-    return UV_ENOMEM;
-  }
-
-  uv__free(process_title);
-  process_title = new_title;
-  setproctitle("%s", title);
-
-  uv_mutex_unlock(&process_title_mutex);
-
-  return 0;
-}
-
-
-int uv_get_process_title(char* buffer, size_t size) {
-  size_t len;
-
-  if (buffer == NULL || size == 0)
-    return UV_EINVAL;
-
-  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
-  uv_mutex_lock(&process_title_mutex);
-
-  if (process_title) {
-    len = strlen(process_title) + 1;
-
-    if (size < len) {
-      uv_mutex_unlock(&process_title_mutex);
-      return UV_ENOBUFS;
-    }
-
-    memcpy(buffer, process_title, len);
-  } else {
-    len = 0;
-  }
-
-  uv_mutex_unlock(&process_title_mutex);
-
-  buffer[len] = '\0';
-
-  return 0;
-}
-
-
 int uv_resident_set_memory(size_t* rss) {
   kvm_t *kd = NULL;
   struct kinfo_proc2 *kinfo = NULL;

+ 0 - 69
src/unix/openbsd.c

@@ -36,16 +36,6 @@
 #include <unistd.h>
 
 
-static uv_mutex_t process_title_mutex;
-static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
-static char *process_title;
-
-
-static void init_process_title_mutex_once(void) {
-  uv_mutex_init(&process_title_mutex);
-}
-
-
 int uv__platform_loop_init(uv_loop_t* loop) {
   return uv__kqueue_init(loop);
 }
@@ -146,65 +136,6 @@ uint64_t uv_get_total_memory(void) {
 }
 
 
-char** uv_setup_args(int argc, char** argv) {
-  process_title = argc ? uv__strdup(argv[0]) : NULL;
-  return argv;
-}
-
-
-int uv_set_process_title(const char* title) {
-  char* new_title;
-
-  new_title = uv__strdup(title);
-
-  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
-  uv_mutex_lock(&process_title_mutex);
-
-  if (process_title == NULL) {
-    uv_mutex_unlock(&process_title_mutex);
-    return UV_ENOMEM;
-  }
-
-  uv__free(process_title);
-  process_title = new_title;
-  setproctitle("%s", title);
-
-  uv_mutex_unlock(&process_title_mutex);
-
-  return 0;
-}
-
-
-int uv_get_process_title(char* buffer, size_t size) {
-  size_t len;
-
-  if (buffer == NULL || size == 0)
-    return UV_EINVAL;
-
-  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
-  uv_mutex_lock(&process_title_mutex);
-
-  if (process_title) {
-    len = strlen(process_title) + 1;
-
-    if (size < len) {
-      uv_mutex_unlock(&process_title_mutex);
-      return UV_ENOBUFS;
-    }
-
-    memcpy(buffer, process_title, len);
-  } else {
-    len = 0;
-  }
-
-  uv_mutex_unlock(&process_title_mutex);
-
-  buffer[len] = '\0';
-
-  return 0;
-}
-
-
 int uv_resident_set_memory(size_t* rss) {
   struct kinfo_proc kinfo;
   size_t page_size = getpagesize();

+ 20 - 9
src/unix/os390-syscalls.c

@@ -141,7 +141,7 @@ static void init_message_queue(uv__os390_epoll* lst) {
   } msg;
 
   /* initialize message queue */
-  lst->msg_queue = msgget(IPC_PRIVATE, 0622 | IPC_CREAT);
+  lst->msg_queue = msgget(IPC_PRIVATE, 0600 | IPC_CREAT);
   if (lst->msg_queue == -1)
     abort();
 
@@ -255,12 +255,13 @@ int epoll_ctl(uv__os390_epoll* lst,
     lst->items[fd].events = event->events;
     lst->items[fd].revents = 0;
   } else if (op == EPOLL_CTL_MOD) {
-    if (fd >= lst->size || lst->items[fd].fd == -1) {
+    if (fd >= lst->size - 1 || lst->items[fd].fd == -1) {
       uv_mutex_unlock(&global_epoll_lock);
       errno = ENOENT;
       return -1;
     }
     lst->items[fd].events = event->events;
+    lst->items[fd].revents = 0;
   } else
     abort();
 
@@ -275,8 +276,9 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
   struct pollfd* pfds;
   int pollret;
   int reventcount;
+  int nevents;
 
-  size = _SET_FDS_MSGS(size, 1, lst->size - 1);
+  _SET_FDS_MSGS(size, 1, lst->size - 1);
   pfds = lst->items;
   pollret = poll(pfds, size, timeout);
   if (pollret <= 0)
@@ -285,19 +287,28 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
   pollret = _NFDS(pollret) + _NMSGS(pollret);
 
   reventcount = 0;
+  nevents = 0;
   for (int i = 0; 
        i < lst->size && i < maxevents && reventcount < pollret; ++i) {
     struct epoll_event ev;
+    struct pollfd* pfd;
 
-    if (pfds[i].fd == -1 || pfds[i].revents == 0)
+    pfd = &pfds[i];
+    if (pfd->fd == -1 || pfd->revents == 0)
       continue;
 
-    ev.fd = pfds[i].fd;
-    ev.events = pfds[i].revents;
-    events[reventcount++] = ev;
+    ev.fd = pfd->fd;
+    ev.events = pfd->revents;
+    if (pfd->revents & POLLIN && pfd->revents & POLLOUT)
+      reventcount += 2;
+    else if (pfd->revents & (POLLIN | POLLOUT))
+      ++reventcount;
+
+    pfd->revents = 0;
+    events[nevents++] = ev;
   }
 
-  return reventcount;
+  return nevents;
 }
 
 
@@ -493,7 +504,7 @@ ssize_t os390_readlink(const char* path, char* buf, size_t len) {
 
 
 size_t strnlen(const char* str, size_t maxlen) {
-  void* p = memchr(str, 0, maxlen);
+  char* p = memchr(str, 0, maxlen);
   if (p == NULL)
     return maxlen;
   else

+ 0 - 4
src/unix/os390-syscalls.h

@@ -36,10 +36,6 @@
 #define MAX_ITEMS_PER_EPOLL       1024
 
 #define UV__O_CLOEXEC             0x80000
-#define UV__EPOLL_CLOEXEC         UV__O_CLOEXEC
-#define UV__EPOLL_CTL_ADD         EPOLL_CTL_ADD
-#define UV__EPOLL_CTL_DEL         EPOLL_CTL_DEL
-#define UV__EPOLL_CTL_MOD         EPOLL_CTL_MOD
 
 struct epoll_event {
   int events;

+ 22 - 16
src/unix/os390.c

@@ -229,15 +229,15 @@ static int getexe(const int pid, char* buf, size_t len) {
   assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A');
 
   /* Get the offset from the lowest 3 bytes */
-  Output_path = (char*)(&Output_buf) +
-                (Output_buf.Output_data.offsetPath & 0x00FFFFFF);
+  Output_path = (struct Output_path_type*) ((char*) (&Output_buf) +
+      (Output_buf.Output_data.offsetPath & 0x00FFFFFF));
 
   if (Output_path->len >= len) {
     errno = ENOBUFS;
     return -1;
   }
 
-  strncpy(buf, Output_path->path, len);
+  uv__strscpy(buf, Output_path->path, len);
 
   return 0;
 }
@@ -357,13 +357,11 @@ uint64_t uv_get_total_memory(void) {
 
 
 int uv_resident_set_memory(size_t* rss) {
-  char* psa;
   char* ascb;
   char* rax;
   size_t nframes;
 
-  psa = PSA_PTR;
-  ascb  = *(char* __ptr32 *)(psa + PSAAOLD);
+  ascb  = *(char* __ptr32 *)(PSA_PTR + PSAAOLD);
   rax = *(char* __ptr32 *)(ascb + ASCBRSME);
   nframes = *(unsigned int*)(rax + RAXFMCT);
 
@@ -512,7 +510,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
     /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
 
     address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
-
+    memset(address->phys_addr, 0, sizeof(address->phys_addr));
     address++;
   }
 
@@ -531,12 +529,14 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   struct ifreq* p;
   int count_v6;
 
+  *count = 0;
+  *addresses = NULL;
+
   /* get the ipv6 addresses first */
   uv_interface_address_t* addresses_v6;
   uv__interface_addresses_v6(&addresses_v6, &count_v6);
 
   /* now get the ipv4 addresses */
-  *count = 0;
 
   /* Assume maximum buffer size allowable */
   maxsize = 16384;
@@ -578,6 +578,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
     (*count)++;
   }
 
+  if (*count == 0) {
+    uv__close(sockfd);
+    return 0;
+  }
+
   /* Alloc the return interface structs */
   *addresses = uv__malloc((*count + count_v6) *
                           sizeof(uv_interface_address_t));
@@ -624,6 +629,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
     }
 
     address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
+    memset(address->phys_addr, 0, sizeof(address->phys_addr));
     address++;
   }
 
@@ -662,7 +668,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
 
   /* Remove the file descriptor from the epoll. */
   if (loop->ep != NULL)
-    epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy);
+    epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, &dummy);
 }
 
 
@@ -751,7 +757,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
   memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok,
          sizeof(handle->rfis_rftok));
 
-  /* 
+  /*
    * This call will take "/" as the path argument in case we
    * don't care to supply the correct path. The system will simply
    * ignore it.
@@ -838,9 +844,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
     e.fd = w->fd;
 
     if (w->events == 0)
-      op = UV__EPOLL_CTL_ADD;
+      op = EPOLL_CTL_ADD;
     else
-      op = UV__EPOLL_CTL_MOD;
+      op = EPOLL_CTL_MOD;
 
     /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
      * events, skip the syscall and squelch the events after epoll_wait().
@@ -849,10 +855,10 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
       if (errno != EEXIST)
         abort();
 
-      assert(op == UV__EPOLL_CTL_ADD);
+      assert(op == EPOLL_CTL_ADD);
 
       /* We've reactivated a file descriptor that's been watched before. */
-      if (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e))
+      if (epoll_ctl(loop->ep, EPOLL_CTL_MOD, w->fd, &e))
         abort();
     }
 
@@ -934,7 +940,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
          * Ignore all errors because we may be racing with another thread
          * when the file descriptor is closed.
          */
-        epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, pe);
+        epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, pe);
         continue;
       }
 
@@ -987,7 +993,7 @@ void uv__set_process_title(const char* title) {
 }
 
 int uv__io_fork(uv_loop_t* loop) {
-  /* 
+  /*
     Nullify the msg queue but don't close it because
     it is still being used by the parent.
   */

+ 23 - 8
src/unix/pipe.c

@@ -66,8 +66,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
   sockfd = err;
 
   memset(&saddr, 0, sizeof saddr);
-  strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1);
-  saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
+  uv__strscpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path));
   saddr.sun_family = AF_UNIX;
 
   if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
@@ -132,7 +131,20 @@ void uv__pipe_close(uv_pipe_t* handle) {
 
 
 int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
+  int flags;
+  int mode;
   int err;
+  flags = 0;
+
+  if (uv__fd_exists(handle->loop, fd))
+    return UV_EEXIST;
+
+  do
+    mode = fcntl(fd, F_GETFL);
+  while (mode == -1 && errno == EINTR);
+
+  if (mode == -1)
+    return UV__ERR(errno); /* according to docs, must be EBADF */
 
   err = uv__nonblock(fd, 1);
   if (err)
@@ -144,9 +156,13 @@ int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
     return err;
 #endif /* defined(__APPLE__) */
 
-  return uv__stream_open((uv_stream_t*)handle,
-                         fd,
-                         UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+  mode &= O_ACCMODE;
+  if (mode != O_WRONLY)
+    flags |= UV_HANDLE_READABLE;
+  if (mode != O_RDONLY)
+    flags |= UV_HANDLE_WRITABLE;
+
+  return uv__stream_open((uv_stream_t*)handle, fd, flags);
 }
 
 
@@ -169,8 +185,7 @@ void uv_pipe_connect(uv_connect_t* req,
   }
 
   memset(&saddr, 0, sizeof saddr);
-  strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1);
-  saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
+  uv__strscpy(saddr.sun_path, name, sizeof(saddr.sun_path));
   saddr.sun_family = AF_UNIX;
 
   do {
@@ -196,7 +211,7 @@ void uv_pipe_connect(uv_connect_t* req,
   if (new_sock) {
     err = uv__stream_open((uv_stream_t*)handle,
                           uv__stream_fd(handle),
-                          UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+                          UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
   }
 
   if (err == 0)

+ 3 - 0
src/unix/poll.c

@@ -68,6 +68,9 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
 int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
   int err;
 
+  if (uv__fd_exists(loop, fd))
+    return UV_EEXIST;
+
   err = uv__io_check_fd(loop, fd);
   if (err)
     return err;

+ 2 - 2
src/unix/process.c

@@ -239,9 +239,9 @@ static int uv__process_open_stream(uv_stdio_container_t* container,
 
   flags = 0;
   if (container->flags & UV_WRITABLE_PIPE)
-    flags |= UV_STREAM_READABLE;
+    flags |= UV_HANDLE_READABLE;
   if (container->flags & UV_READABLE_PIPE)
-    flags |= UV_STREAM_WRITABLE;
+    flags |= UV_HANDLE_WRITABLE;
 
   return uv__stream_open(container->data.stream, pipefds[0], flags);
 }

+ 4 - 0
src/unix/proctitle.c

@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+extern void uv__set_process_title_platform_init(void);
 extern void uv__set_process_title(const char* title);
 
 static uv_mutex_t process_title_mutex;
@@ -38,6 +39,9 @@ static struct {
 
 static void init_process_title_mutex_once(void) {
   uv_mutex_init(&process_title_mutex);
+#ifdef __APPLE__
+  uv__set_process_title_platform_init();
+#endif
 }
 
 

+ 34 - 25
src/unix/signal.c

@@ -54,8 +54,7 @@ static void uv__signal_unregister_handler(int signum);
 static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT;
 static struct uv__signal_tree_s uv__signal_tree =
     RB_INITIALIZER(uv__signal_tree);
-static int uv__signal_lock_pipefd[2];
-
+static int uv__signal_lock_pipefd[2] = { -1, -1 };
 
 RB_GENERATE_STATIC(uv__signal_tree_s,
                    uv_signal_s, tree_entry,
@@ -64,7 +63,7 @@ RB_GENERATE_STATIC(uv__signal_tree_s,
 static void uv__signal_global_reinit(void);
 
 static void uv__signal_global_init(void) {
-  if (!uv__signal_lock_pipefd[0])
+  if (uv__signal_lock_pipefd[0] == -1)
     /* pthread_atfork can register before and after handlers, one
      * for each child. This only registers one for the child. That
      * state is both persistent and cumulative, so if we keep doing
@@ -74,15 +73,11 @@ static void uv__signal_global_init(void) {
     if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit))
       abort();
 
-  if (uv__make_pipe(uv__signal_lock_pipefd, 0))
-    abort();
-
-  if (uv__signal_unlock())
-    abort();
+  uv__signal_global_reinit();
 }
 
 
-static void uv__signal_global_reinit(void) {
+UV_DESTRUCTOR(static void uv__signal_global_fini(void)) {
   /* We can only use signal-safe functions here.
    * That includes read/write and close, fortunately.
    * We do all of this directly here instead of resetting
@@ -90,11 +85,26 @@ static void uv__signal_global_reinit(void) {
    * uv__signal_global_once_init is only called from uv_loop_init
    * and this needs to function in existing loops.
    */
-  uv__close(uv__signal_lock_pipefd[0]);
-  uv__signal_lock_pipefd[0] = -1;
-  uv__close(uv__signal_lock_pipefd[1]);
-  uv__signal_lock_pipefd[1] = -1;
-  uv__signal_global_init();
+  if (uv__signal_lock_pipefd[0] != -1) {
+    uv__close(uv__signal_lock_pipefd[0]);
+    uv__signal_lock_pipefd[0] = -1;
+  }
+
+  if (uv__signal_lock_pipefd[1] != -1) {
+    uv__close(uv__signal_lock_pipefd[1]);
+    uv__signal_lock_pipefd[1] = -1;
+  }
+}
+
+
+static void uv__signal_global_reinit(void) {
+  uv__signal_global_fini();
+
+  if (uv__make_pipe(uv__signal_lock_pipefd, 0))
+    abort();
+
+  if (uv__signal_unlock())
+    abort();
 }
 
 
@@ -103,7 +113,6 @@ void uv__signal_global_once_init(void) {
 }
 
 
-
 static int uv__signal_lock(void) {
   int r;
   char data;
@@ -387,7 +396,7 @@ static int uv__signal_start(uv_signal_t* handle,
    */
   first_handle = uv__signal_first_handle(signum);
   if (first_handle == NULL ||
-      (!oneshot && (first_handle->flags & UV__SIGNAL_ONE_SHOT))) {
+      (!oneshot && (first_handle->flags & UV_SIGNAL_ONE_SHOT))) {
     err = uv__signal_register_handler(signum, oneshot);
     if (err) {
       /* Registering the signal handler failed. Must be an invalid signal. */
@@ -398,7 +407,7 @@ static int uv__signal_start(uv_signal_t* handle,
 
   handle->signum = signum;
   if (oneshot)
-    handle->flags |= UV__SIGNAL_ONE_SHOT;
+    handle->flags |= UV_SIGNAL_ONE_SHOT;
 
   RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
 
@@ -455,20 +464,20 @@ static void uv__signal_event(uv_loop_t* loop,
       handle = msg->handle;
 
       if (msg->signum == handle->signum) {
-        assert(!(handle->flags & UV_CLOSING));
+        assert(!(handle->flags & UV_HANDLE_CLOSING));
         handle->signal_cb(handle, handle->signum);
       }
 
       handle->dispatched_signals++;
 
-      if (handle->flags & UV__SIGNAL_ONE_SHOT)
+      if (handle->flags & UV_SIGNAL_ONE_SHOT)
         uv__signal_stop(handle);
 
       /* If uv_close was called while there were caught signals that were not
        * yet dispatched, the uv__finish_close was deferred. Make close pending
        * now if this has happened.
        */
-      if ((handle->flags & UV_CLOSING) &&
+      if ((handle->flags & UV_HANDLE_CLOSING) &&
           (handle->caught_signals == handle->dispatched_signals)) {
         uv__make_close_pending((uv_handle_t*) handle);
       }
@@ -496,11 +505,11 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
   if (w1->signum < w2->signum) return -1;
   if (w1->signum > w2->signum) return 1;
 
-  /* Handlers without UV__SIGNAL_ONE_SHOT set will come first, so if the first
+  /* Handlers without UV_SIGNAL_ONE_SHOT set will come first, so if the first
    * handler returned is a one-shot handler, the rest will be too.
    */
-  f1 = w1->flags & UV__SIGNAL_ONE_SHOT;
-  f2 = w2->flags & UV__SIGNAL_ONE_SHOT;
+  f1 = w1->flags & UV_SIGNAL_ONE_SHOT;
+  f2 = w2->flags & UV_SIGNAL_ONE_SHOT;
   if (f1 < f2) return -1;
   if (f1 > f2) return 1;
 
@@ -549,8 +558,8 @@ static void uv__signal_stop(uv_signal_t* handle) {
   if (first_handle == NULL) {
     uv__signal_unregister_handler(handle->signum);
   } else {
-    rem_oneshot = handle->flags & UV__SIGNAL_ONE_SHOT;
-    first_oneshot = first_handle->flags & UV__SIGNAL_ONE_SHOT;
+    rem_oneshot = handle->flags & UV_SIGNAL_ONE_SHOT;
+    first_oneshot = first_handle->flags & UV_SIGNAL_ONE_SHOT;
     if (first_oneshot && !rem_oneshot) {
       ret = uv__signal_register_handler(handle->signum, 1);
       assert(ret == 0);

+ 124 - 138
src/unix/stream.c

@@ -58,11 +58,19 @@ struct uv__stream_select_s {
   fd_set* swrite;
   size_t swrite_sz;
 };
-# define WRITE_RETRY_ON_ERROR(send_handle) \
+
+/* Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
+ * EPROTOTYPE can be returned while trying to write to a socket that is
+ * shutting down. If we retry the write, we should get the expected EPIPE
+ * instead.
+ */
+# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR || errno == EPROTOTYPE)
+# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
     (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \
-     (errno == EMSGSIZE && send_handle))
+     (errno == EMSGSIZE && send_handle != NULL))
 #else
-# define WRITE_RETRY_ON_ERROR(send_handle) \
+# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR)
+# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
     (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
 #endif /* defined(__APPLE__) */
 
@@ -220,7 +228,7 @@ static void uv__stream_osx_select(void* arg) {
       uv_sem_wait(&s->async_sem);
 
       /* Should be processed at this stage */
-      assert((s->events == 0) || (stream->flags & UV_CLOSING));
+      assert((s->events == 0) || (stream->flags & UV_HANDLE_CLOSING));
     }
   }
 }
@@ -248,7 +256,7 @@ static void uv__stream_osx_select_cb(uv_async_t* handle) {
   if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT))
     uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT);
 
-  if (stream->flags & UV_CLOSING)
+  if (stream->flags & UV_HANDLE_CLOSING)
     return;
 
   /* NOTE: It is important to do it here, otherwise `select()` might be called
@@ -342,7 +350,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
   if (err)
     goto failed_async_init;
 
-  s->async.flags |= UV__HANDLE_INTERNAL;
+  s->async.flags |= UV_HANDLE_INTERNAL;
   uv__handle_unref(&s->async);
 
   err = uv_sem_init(&s->close_sem, 0);
@@ -407,12 +415,14 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
   stream->flags |= flags;
 
   if (stream->type == UV_TCP) {
-    if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1))
+    if ((stream->flags & UV_HANDLE_TCP_NODELAY) && uv__tcp_nodelay(fd, 1))
       return UV__ERR(errno);
 
     /* TODO Use delay the user passed in. */
-    if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60))
+    if ((stream->flags & UV_HANDLE_TCP_KEEPALIVE) &&
+        uv__tcp_keepalive(fd, 1, 60)) {
       return UV__ERR(errno);
+    }
   }
 
 #if defined(__APPLE__)
@@ -447,7 +457,7 @@ void uv__stream_flush_write_queue(uv_stream_t* stream, int error) {
 
 void uv__stream_destroy(uv_stream_t* stream) {
   assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT));
-  assert(stream->flags & UV_CLOSED);
+  assert(stream->flags & UV_HANDLE_CLOSED);
 
   if (stream->connect_req) {
     uv__req_unregister(stream->loop, stream->connect_req);
@@ -522,7 +532,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
   stream = container_of(w, uv_stream_t, io_watcher);
   assert(events & POLLIN);
   assert(stream->accepted_fd == -1);
-  assert(!(stream->flags & UV_CLOSING));
+  assert(!(stream->flags & UV_HANDLE_CLOSING));
 
   uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
 
@@ -565,7 +575,8 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
       return;
     }
 
-    if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) {
+    if (stream->type == UV_TCP &&
+        (stream->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) {
       /* Give other processes a chance to accept connections. */
       struct timespec timeout = { 0, 1 };
       nanosleep(&timeout, NULL);
@@ -590,7 +601,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
     case UV_TCP:
       err = uv__stream_open(client,
                             server->accepted_fd,
-                            UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+                            UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
       if (err) {
         /* TODO handle error */
         uv__close(server->accepted_fd);
@@ -674,14 +685,14 @@ static void uv__drain(uv_stream_t* stream) {
   uv__stream_osx_interrupt_select(stream);
 
   /* Shutdown? */
-  if ((stream->flags & UV_STREAM_SHUTTING) &&
-      !(stream->flags & UV_CLOSING) &&
-      !(stream->flags & UV_STREAM_SHUT)) {
+  if ((stream->flags & UV_HANDLE_SHUTTING) &&
+      !(stream->flags & UV_HANDLE_CLOSING) &&
+      !(stream->flags & UV_HANDLE_SHUT)) {
     assert(stream->shutdown_req);
 
     req = stream->shutdown_req;
     stream->shutdown_req = NULL;
-    stream->flags &= ~UV_STREAM_SHUTTING;
+    stream->flags &= ~UV_HANDLE_SHUTTING;
     uv__req_unregister(stream->loop, req);
 
     err = 0;
@@ -689,7 +700,7 @@ static void uv__drain(uv_stream_t* stream) {
       err = UV__ERR(errno);
 
     if (err == 0)
-      stream->flags |= UV_STREAM_SHUT;
+      stream->flags |= UV_HANDLE_SHUT;
 
     if (req->cb != NULL)
       req->cb(req, err);
@@ -697,6 +708,14 @@ static void uv__drain(uv_stream_t* stream) {
 }
 
 
+static ssize_t uv__writev(int fd, struct iovec* vec, size_t n) {
+  if (n == 1)
+    return write(fd, vec->iov_base, vec->iov_len);
+  else
+    return writev(fd, vec, n);
+}
+
+
 static size_t uv__write_req_size(uv_write_t* req) {
   size_t size;
 
@@ -709,6 +728,37 @@ static size_t uv__write_req_size(uv_write_t* req) {
 }
 
 
+/* Returns 1 if all write request data has been written, or 0 if there is still
+ * more data to write.
+ *
+ * Note: the return value only says something about the *current* request.
+ * There may still be other write requests sitting in the queue.
+ */
+static int uv__write_req_update(uv_stream_t* stream,
+                                uv_write_t* req,
+                                size_t n) {
+  uv_buf_t* buf;
+  size_t len;
+
+  assert(n <= stream->write_queue_size);
+  stream->write_queue_size -= n;
+
+  buf = req->bufs + req->write_index;
+
+  while (n > 0) {
+    len = n < buf->len ? n : buf->len;
+    buf->base += len;
+    buf->len -= len;
+    buf += (buf->len == 0);  /* Advance to next buffer if this one is empty. */
+    n -= len;
+  }
+
+  req->write_index = buf - req->bufs;
+
+  return req->write_index == req->nbufs;
+}
+
+
 static void uv__write_req_finish(uv_write_t* req) {
   uv_stream_t* stream = req->handle;
 
@@ -829,102 +879,32 @@ start:
       *pi = fd_to_send;
     }
 
-    do {
+    do
       n = sendmsg(uv__stream_fd(stream), &msg, 0);
-    }
-#if defined(__APPLE__)
-    /*
-     * Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
-     * EPROTOTYPE can be returned while trying to write to a socket that is
-     * shutting down. If we retry the write, we should get the expected EPIPE
-     * instead.
-     */
-    while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
-#else
-    while (n == -1 && errno == EINTR);
-#endif
-  } else {
-    do {
-      if (iovcnt == 1) {
-        n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len);
-      } else {
-        n = writev(uv__stream_fd(stream), iov, iovcnt);
-      }
-    }
-#if defined(__APPLE__)
-    /*
-     * Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
-     * EPROTOTYPE can be returned while trying to write to a socket that is
-     * shutting down. If we retry the write, we should get the expected EPIPE
-     * instead.
-     */
-    while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
-#else
-    while (n == -1 && errno == EINTR);
-#endif
-  }
+    while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
 
-  if (n < 0) {
-    if (!WRITE_RETRY_ON_ERROR(req->send_handle)) {
-      err = UV__ERR(errno);
-      goto error;
-    } else if (stream->flags & UV_STREAM_BLOCKING) {
-      /* If this is a blocking stream, try again. */
-      goto start;
-    }
+    /* Ensure the handle isn't sent again in case this is a partial write. */
+    if (n >= 0)
+      req->send_handle = NULL;
   } else {
-    /* Successful write */
-
-    while (n >= 0) {
-      uv_buf_t* buf = &(req->bufs[req->write_index]);
-      size_t len = buf->len;
-
-      assert(req->write_index < req->nbufs);
-
-      if ((size_t)n < len) {
-        buf->base += n;
-        buf->len -= n;
-        stream->write_queue_size -= n;
-        n = 0;
-
-        /* There is more to write. */
-        if (stream->flags & UV_STREAM_BLOCKING) {
-          /*
-           * If we're blocking then we should not be enabling the write
-           * watcher - instead we need to try again.
-           */
-          goto start;
-        } else {
-          /* Break loop and ensure the watcher is pending. */
-          break;
-        }
-
-      } else {
-        /* Finished writing the buf at index req->write_index. */
-        req->write_index++;
-
-        assert((size_t)n >= len);
-        n -= len;
-
-        assert(stream->write_queue_size >= len);
-        stream->write_queue_size -= len;
+    do
+      n = uv__writev(uv__stream_fd(stream), iov, iovcnt);
+    while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
+  }
 
-        if (req->write_index == req->nbufs) {
-          /* Then we're done! */
-          assert(n == 0);
-          uv__write_req_finish(req);
-          /* TODO: start trying to write the next request. */
-          return;
-        }
-      }
-    }
+  if (n == -1 && !IS_TRANSIENT_WRITE_ERROR(errno, req->send_handle)) {
+    err = UV__ERR(errno);
+    goto error;
   }
 
-  /* Either we've counted n down to zero or we've got EAGAIN. */
-  assert(n == 0 || n == -1);
+  if (n > 0 && uv__write_req_update(stream, req, n)) {
+    uv__write_req_finish(req);
+    return;  /* TODO(bnoordhuis) Start trying to write the next request. */
+  }
 
-  /* Only non-blocking streams should use the write_watcher. */
-  assert(!(stream->flags & UV_STREAM_BLOCKING));
+  /* If this is a blocking stream, try again. */
+  if (stream->flags & UV_HANDLE_BLOCKING_WRITES)
+    goto start;
 
   /* We're not done. */
   uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
@@ -947,10 +927,16 @@ error:
 static void uv__write_callbacks(uv_stream_t* stream) {
   uv_write_t* req;
   QUEUE* q;
+  QUEUE pq;
+
+  if (QUEUE_EMPTY(&stream->write_completed_queue))
+    return;
+
+  QUEUE_MOVE(&stream->write_completed_queue, &pq);
 
-  while (!QUEUE_EMPTY(&stream->write_completed_queue)) {
+  while (!QUEUE_EMPTY(&pq)) {
     /* Pop a req off write_completed_queue. */
-    q = QUEUE_HEAD(&stream->write_completed_queue);
+    q = QUEUE_HEAD(&pq);
     req = QUEUE_DATA(q, uv_write_t, queue);
     QUEUE_REMOVE(q);
     uv__req_unregister(stream->loop, req);
@@ -966,8 +952,6 @@ static void uv__write_callbacks(uv_stream_t* stream) {
     if (req->cb)
       req->cb(req, req->error);
   }
-
-  assert(QUEUE_EMPTY(&stream->write_completed_queue));
 }
 
 
@@ -1015,13 +999,13 @@ uv_handle_type uv__handle_type(int fd) {
 
 
 static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
-  stream->flags |= UV_STREAM_READ_EOF;
+  stream->flags |= UV_HANDLE_READ_EOF;
   uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
   if (!uv__io_active(&stream->io_watcher, POLLOUT))
     uv__handle_stop(stream);
   uv__stream_osx_interrupt_select(stream);
   stream->read_cb(stream, UV_EOF, buf);
-  stream->flags &= ~UV_STREAM_READING;
+  stream->flags &= ~UV_HANDLE_READING;
 }
 
 
@@ -1121,6 +1105,7 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
 #ifdef __clang__
 # pragma clang diagnostic push
 # pragma clang diagnostic ignored "-Wgnu-folding-constant"
+# pragma clang diagnostic ignored "-Wvla-extension"
 #endif
 
 static void uv__read(uv_stream_t* stream) {
@@ -1132,7 +1117,7 @@ static void uv__read(uv_stream_t* stream) {
   int err;
   int is_ipc;
 
-  stream->flags &= ~UV_STREAM_READ_PARTIAL;
+  stream->flags &= ~UV_HANDLE_READ_PARTIAL;
 
   /* Prevent loop starvation when the data comes in as fast as (or faster than)
    * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
@@ -1141,11 +1126,11 @@ static void uv__read(uv_stream_t* stream) {
 
   is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc;
 
-  /* XXX: Maybe instead of having UV_STREAM_READING we just test if
+  /* XXX: Maybe instead of having UV_HANDLE_READING we just test if
    * tcp->read_cb is NULL or not?
    */
   while (stream->read_cb
-      && (stream->flags & UV_STREAM_READING)
+      && (stream->flags & UV_HANDLE_READING)
       && (count-- > 0)) {
     assert(stream->alloc_cb != NULL);
 
@@ -1186,7 +1171,7 @@ static void uv__read(uv_stream_t* stream) {
       /* Error */
       if (errno == EAGAIN || errno == EWOULDBLOCK) {
         /* Wait for the next one. */
-        if (stream->flags & UV_STREAM_READING) {
+        if (stream->flags & UV_HANDLE_READING) {
           uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
           uv__stream_osx_interrupt_select(stream);
         }
@@ -1199,8 +1184,8 @@ static void uv__read(uv_stream_t* stream) {
       } else {
         /* Error. User should call uv_close(). */
         stream->read_cb(stream, UV__ERR(errno), &buf);
-        if (stream->flags & UV_STREAM_READING) {
-          stream->flags &= ~UV_STREAM_READING;
+        if (stream->flags & UV_HANDLE_READING) {
+          stream->flags &= ~UV_HANDLE_READING;
           uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
           if (!uv__io_active(&stream->io_watcher, POLLOUT))
             uv__handle_stop(stream);
@@ -1250,7 +1235,7 @@ static void uv__read(uv_stream_t* stream) {
 
       /* Return if we didn't fill the buffer, there is no more data to read. */
       if (nread < buflen) {
-        stream->flags |= UV_STREAM_READ_PARTIAL;
+        stream->flags |= UV_HANDLE_READ_PARTIAL;
         return;
       }
     }
@@ -1271,9 +1256,9 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
          stream->type == UV_TTY ||
          stream->type == UV_NAMED_PIPE);
 
-  if (!(stream->flags & UV_STREAM_WRITABLE) ||
-      stream->flags & UV_STREAM_SHUT ||
-      stream->flags & UV_STREAM_SHUTTING ||
+  if (!(stream->flags & UV_HANDLE_WRITABLE) ||
+      stream->flags & UV_HANDLE_SHUT ||
+      stream->flags & UV_HANDLE_SHUTTING ||
       uv__is_closing(stream)) {
     return UV_ENOTCONN;
   }
@@ -1285,7 +1270,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;
-  stream->flags |= UV_STREAM_SHUTTING;
+  stream->flags |= UV_HANDLE_SHUTTING;
 
   uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
   uv__stream_osx_interrupt_select(stream);
@@ -1302,7 +1287,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
   assert(stream->type == UV_TCP ||
          stream->type == UV_NAMED_PIPE ||
          stream->type == UV_TTY);
-  assert(!(stream->flags & UV_CLOSING));
+  assert(!(stream->flags & UV_HANDLE_CLOSING));
 
   if (stream->connect_req) {
     uv__stream_connect(stream);
@@ -1311,7 +1296,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
 
   assert(uv__stream_fd(stream) >= 0);
 
-  /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */
+  /* Ignore POLLHUP here. Even if it's set, there may still be data to read. */
   if (events & (POLLIN | POLLERR | POLLHUP))
     uv__read(stream);
 
@@ -1325,9 +1310,9 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
    * report the EOF yet because there is still data to read.
    */
   if ((events & POLLHUP) &&
-      (stream->flags & UV_STREAM_READING) &&
-      (stream->flags & UV_STREAM_READ_PARTIAL) &&
-      !(stream->flags & UV_STREAM_READ_EOF)) {
+      (stream->flags & UV_HANDLE_READING) &&
+      (stream->flags & UV_HANDLE_READ_PARTIAL) &&
+      !(stream->flags & UV_HANDLE_READ_EOF)) {
     uv_buf_t buf = { NULL, 0 };
     uv__stream_eof(stream, &buf);
   }
@@ -1417,7 +1402,7 @@ int uv_write2(uv_write_t* req,
   if (uv__stream_fd(stream) < 0)
     return UV_EBADF;
 
-  if (!(stream->flags & UV_STREAM_WRITABLE))
+  if (!(stream->flags & UV_HANDLE_WRITABLE))
     return -EPIPE;
 
   if (send_handle) {
@@ -1487,7 +1472,7 @@ int uv_write2(uv_write_t* req,
      * if this assert fires then somehow the blocking stream isn't being
      * sufficiently flushed in uv__write.
      */
-    assert(!(stream->flags & UV_STREAM_BLOCKING));
+    assert(!(stream->flags & UV_HANDLE_BLOCKING_WRITES));
     uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
     uv__stream_osx_interrupt_select(stream);
   }
@@ -1568,16 +1553,16 @@ int uv_read_start(uv_stream_t* stream,
   assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
       stream->type == UV_TTY);
 
-  if (stream->flags & UV_CLOSING)
+  if (stream->flags & UV_HANDLE_CLOSING)
     return UV_EINVAL;
 
-  if (!(stream->flags & UV_STREAM_READABLE))
+  if (!(stream->flags & UV_HANDLE_READABLE))
     return -ENOTCONN;
 
-  /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just
+  /* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just
    * expresses the desired state of the user.
    */
-  stream->flags |= UV_STREAM_READING;
+  stream->flags |= UV_HANDLE_READING;
 
   /* TODO: try to do the read inline? */
   /* TODO: keep track of tcp state. If we've gotten a EOF then we should
@@ -1598,10 +1583,10 @@ int uv_read_start(uv_stream_t* stream,
 
 
 int uv_read_stop(uv_stream_t* stream) {
-  if (!(stream->flags & UV_STREAM_READING))
+  if (!(stream->flags & UV_HANDLE_READING))
     return 0;
 
-  stream->flags &= ~UV_STREAM_READING;
+  stream->flags &= ~UV_HANDLE_READING;
   uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
   if (!uv__io_active(&stream->io_watcher, POLLOUT))
     uv__handle_stop(stream);
@@ -1614,12 +1599,12 @@ int uv_read_stop(uv_stream_t* stream) {
 
 
 int uv_is_readable(const uv_stream_t* stream) {
-  return !!(stream->flags & UV_STREAM_READABLE);
+  return !!(stream->flags & UV_HANDLE_READABLE);
 }
 
 
 int uv_is_writable(const uv_stream_t* stream) {
-  return !!(stream->flags & UV_STREAM_WRITABLE);
+  return !!(stream->flags & UV_HANDLE_WRITABLE);
 }
 
 
@@ -1668,6 +1653,7 @@ void uv__stream_close(uv_stream_t* handle) {
   uv__io_close(handle->loop, &handle->io_watcher);
   uv_read_stop(handle);
   uv__handle_stop(handle);
+  handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
 
   if (handle->io_watcher.fd != -1) {
     /* Don't close stdio file descriptors.  Nothing good comes from it. */

+ 12 - 3
src/unix/sunos.c

@@ -692,6 +692,8 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
 
 #ifdef SUNOS_NO_IFADDRS
 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+  *count = 0;
+  *addresses = NULL;
   return UV_ENOSYS;
 }
 #else  /* SUNOS_NO_IFADDRS */
@@ -705,13 +707,14 @@ static int uv__set_phys_addr(uv_interface_address_t* address,
 
   struct sockaddr_dl* sa_addr;
   int sockfd;
-  int i;
+  size_t i;
   struct arpreq arpreq;
 
   /* This appears to only work as root */
   sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
   memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
   for (i = 0; i < sizeof(address->phys_addr); i++) {
+    /* Check that all bytes of phys_addr are zero. */
     if (address->phys_addr[i] != 0)
       return 0;
   }
@@ -758,11 +761,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   struct ifaddrs* addrs;
   struct ifaddrs* ent;
 
+  *count = 0;
+  *addresses = NULL;
+
   if (getifaddrs(&addrs))
     return UV__ERR(errno);
 
-  *count = 0;
-
   /* Count the number of interfaces */
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
     if (uv__ifaddr_exclude(ent))
@@ -770,6 +774,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
     (*count)++;
   }
 
+  if (*count == 0) {
+    freeifaddrs(addrs);
+    return 0;
+  }
+
   *addresses = uv__malloc(*count * sizeof(**addresses));
   if (!(*addresses)) {
     freeifaddrs(addrs);

+ 12 - 9
src/unix/tcp.c

@@ -216,7 +216,7 @@ int uv__tcp_connect(uv_connect_t* req,
 
   err = maybe_new_socket(handle,
                          addr->sa_family,
-                         UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+                         UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
   if (err)
     return err;
 
@@ -263,13 +263,16 @@ int uv__tcp_connect(uv_connect_t* req,
 int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
   int err;
 
+  if (uv__fd_exists(handle->loop, sock))
+    return UV_EEXIST;
+
   err = uv__nonblock(sock, 1);
   if (err)
     return err;
 
   return uv__stream_open((uv_stream_t*)handle,
                          sock,
-                         UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+                         UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
 }
 
 
@@ -331,7 +334,7 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
   }
 
   if (single_accept)
-    tcp->flags |= UV_TCP_SINGLE_ACCEPT;
+    tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
 
   flags = 0;
 #if defined(__MVS__)
@@ -398,9 +401,9 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
   }
 
   if (on)
-    handle->flags |= UV_TCP_NODELAY;
+    handle->flags |= UV_HANDLE_TCP_NODELAY;
   else
-    handle->flags &= ~UV_TCP_NODELAY;
+    handle->flags &= ~UV_HANDLE_TCP_NODELAY;
 
   return 0;
 }
@@ -416,9 +419,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
   }
 
   if (on)
-    handle->flags |= UV_TCP_KEEPALIVE;
+    handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
   else
-    handle->flags &= ~UV_TCP_KEEPALIVE;
+    handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
 
   /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
    *      uv_tcp_t with an int that's almost never used...
@@ -430,9 +433,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
 
 int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
   if (enable)
-    handle->flags &= ~UV_TCP_SINGLE_ACCEPT;
+    handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT;
   else
-    handle->flags |= UV_TCP_SINGLE_ACCEPT;
+    handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
   return 0;
 }
 

+ 69 - 77
src/unix/thread.c

@@ -44,108 +44,119 @@
 #undef NANOSEC
 #define NANOSEC ((uint64_t) 1e9)
 
+#if defined(PTHREAD_BARRIER_SERIAL_THREAD)
+STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t));
+#endif
 
-#if defined(UV__PTHREAD_BARRIER_FALLBACK)
-/* TODO: support barrier_attr */
-int pthread_barrier_init(pthread_barrier_t* barrier,
-                         const void* barrier_attr,
-                         unsigned count) {
+/* Note: guard clauses should match uv_barrier_t's in include/uv/uv-unix.h. */
+#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD)
+int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
+  struct _uv_barrier* b;
   int rc;
-  _uv_barrier* b;
 
   if (barrier == NULL || count == 0)
-    return EINVAL;
-
-  if (barrier_attr != NULL)
-    return ENOTSUP;
+    return UV_EINVAL;
 
   b = uv__malloc(sizeof(*b));
   if (b == NULL)
-    return ENOMEM;
+    return UV_ENOMEM;
 
   b->in = 0;
   b->out = 0;
   b->threshold = count;
 
-  if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
+  rc = uv_mutex_init(&b->mutex);
+  if (rc != 0)
     goto error2;
-  if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
+
+  rc = uv_cond_init(&b->cond);
+  if (rc != 0)
     goto error;
 
   barrier->b = b;
   return 0;
 
 error:
-  pthread_mutex_destroy(&b->mutex);
+  uv_mutex_destroy(&b->mutex);
 error2:
   uv__free(b);
   return rc;
 }
 
-int pthread_barrier_wait(pthread_barrier_t* barrier) {
-  int rc;
-  _uv_barrier* b;
+
+int uv_barrier_wait(uv_barrier_t* barrier) {
+  struct _uv_barrier* b;
+  int last;
 
   if (barrier == NULL || barrier->b == NULL)
-    return EINVAL;
+    return UV_EINVAL;
 
   b = barrier->b;
-  /* Lock the mutex*/
-  if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
-    return rc;
+  uv_mutex_lock(&b->mutex);
 
-  /* Increment the count. If this is the first thread to reach the threshold,
-     wake up waiters, unlock the mutex, then return
-     PTHREAD_BARRIER_SERIAL_THREAD. */
   if (++b->in == b->threshold) {
     b->in = 0;
-    b->out = b->threshold - 1;
-    rc = pthread_cond_signal(&b->cond);
-    assert(rc == 0);
-
-    pthread_mutex_unlock(&b->mutex);
-    return PTHREAD_BARRIER_SERIAL_THREAD;
+    b->out = b->threshold;
+    uv_cond_signal(&b->cond);
+  } else {
+    do
+      uv_cond_wait(&b->cond, &b->mutex);
+    while (b->in != 0);
   }
-  /* Otherwise, wait for other threads until in is set to 0,
-     then return 0 to indicate this is not the first thread. */
-  do {
-    if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0)
-      break;
-  } while (b->in != 0);
-
-  /* mark thread exit */
-  b->out--;
-  pthread_cond_signal(&b->cond);
-  pthread_mutex_unlock(&b->mutex);
-  return rc;
+
+  last = (--b->out == 0);
+  if (!last)
+    uv_cond_signal(&b->cond);  /* Not needed for last thread. */
+
+  uv_mutex_unlock(&b->mutex);
+  return last;
 }
 
-int pthread_barrier_destroy(pthread_barrier_t* barrier) {
-  int rc;
-  _uv_barrier* b;
 
-  if (barrier == NULL || barrier->b == NULL)
-    return EINVAL;
+void uv_barrier_destroy(uv_barrier_t* barrier) {
+  struct _uv_barrier* b;
 
   b = barrier->b;
+  uv_mutex_lock(&b->mutex);
 
-  if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
-    return rc;
+  assert(b->in == 0);
+  assert(b->out == 0);
 
-  if (b->in > 0 || b->out > 0)
-    rc = EBUSY;
-
-  pthread_mutex_unlock(&b->mutex);
+  if (b->in != 0 || b->out != 0)
+    abort();
 
-  if (rc)
-    return rc;
+  uv_mutex_unlock(&b->mutex);
+  uv_mutex_destroy(&b->mutex);
+  uv_cond_destroy(&b->cond);
 
-  pthread_cond_destroy(&b->cond);
-  pthread_mutex_destroy(&b->mutex);
   uv__free(barrier->b);
   barrier->b = NULL;
-  return 0;
 }
+
+#else
+
+int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
+  return UV__ERR(pthread_barrier_init(barrier, NULL, count));
+}
+
+
+int uv_barrier_wait(uv_barrier_t* barrier) {
+  int rc;
+
+  rc = pthread_barrier_wait(barrier);
+  if (rc != 0)
+    if (rc != PTHREAD_BARRIER_SERIAL_THREAD)
+      abort();
+
+  return rc == PTHREAD_BARRIER_SERIAL_THREAD;
+}
+
+
+void uv_barrier_destroy(uv_barrier_t* barrier) {
+  if (pthread_barrier_destroy(barrier))
+    abort();
+}
+
 #endif
 
 
@@ -771,25 +782,6 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
 }
 
 
-int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
-  return UV__ERR(pthread_barrier_init(barrier, NULL, count));
-}
-
-
-void uv_barrier_destroy(uv_barrier_t* barrier) {
-  if (pthread_barrier_destroy(barrier))
-    abort();
-}
-
-
-int uv_barrier_wait(uv_barrier_t* barrier) {
-  int r = pthread_barrier_wait(barrier);
-  if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
-    abort();
-  return r == PTHREAD_BARRIER_SERIAL_THREAD;
-}
-
-
 int uv_key_create(uv_key_t* key) {
   return UV__ERR(pthread_key_create(key, NULL));
 }

+ 20 - 25
src/unix/tty.c

@@ -92,13 +92,15 @@ static int uv__tty_is_slave(const int fd) {
   return result;
 }
 
-int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
+int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
   uv_handle_type type;
   int flags;
   int newfd;
   int r;
   int saved_flags;
+  int mode;
   char path[256];
+  (void)unused; /* deprecated parameter is no longer needed */
 
   /* File descriptors that refer to files cannot be monitored with epoll.
    * That restriction also applies to character devices like /dev/random
@@ -111,6 +113,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
   flags = 0;
   newfd = -1;
 
+  /* Save the fd flags in case we need to restore them due to an error. */
+  do
+    saved_flags = fcntl(fd, F_GETFL);
+  while (saved_flags == -1 && errno == EINTR);
+
+  if (saved_flags == -1)
+    return UV__ERR(errno);
+  mode = saved_flags & O_ACCMODE;
+
   /* Reopen the file descriptor when it refers to a tty. This lets us put the
    * tty in non-blocking mode without affecting other processes that share it
    * with us.
@@ -128,14 +139,14 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
      * slave device.
      */
     if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
-      r = uv__open_cloexec(path, O_RDWR);
+      r = uv__open_cloexec(path, mode);
     else
       r = -1;
 
     if (r < 0) {
       /* fallback to using blocking writes */
-      if (!readable)
-        flags |= UV_STREAM_BLOCKING;
+      if (mode != O_RDONLY)
+        flags |= UV_HANDLE_BLOCKING_WRITES;
       goto skip;
     }
 
@@ -154,22 +165,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
     fd = newfd;
   }
 
-#if defined(__APPLE__)
-  /* Save the fd flags in case we need to restore them due to an error. */
-  do
-    saved_flags = fcntl(fd, F_GETFL);
-  while (saved_flags == -1 && errno == EINTR);
-
-  if (saved_flags == -1) {
-    if (newfd != -1)
-      uv__close(newfd);
-    return UV__ERR(errno);
-  }
-#endif
-
-  /* Pacify the compiler. */
-  (void) &saved_flags;
-
 skip:
   uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
 
@@ -177,7 +172,7 @@ skip:
    * the handle queue, since it was added by uv__handle_init in uv_stream_init.
    */
 
-  if (!(flags & UV_STREAM_BLOCKING))
+  if (!(flags & UV_HANDLE_BLOCKING_WRITES))
     uv__nonblock(fd, 1);
 
 #if defined(__APPLE__)
@@ -194,10 +189,10 @@ skip:
   }
 #endif
 
-  if (readable)
-    flags |= UV_STREAM_READABLE;
-  else
-    flags |= UV_STREAM_WRITABLE;
+  if (mode != O_WRONLY)
+    flags |= UV_HANDLE_READABLE;
+  if (mode != O_RDONLY)
+    flags |= UV_HANDLE_WRITABLE;
 
   uv__stream_open((uv_stream_t*) tty, fd, flags);
   tty->mode = UV_TTY_MODE_NORMAL;

+ 15 - 8
src/unix/udp.c

@@ -92,8 +92,8 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
   uv_udp_send_t* req;
   QUEUE* q;
 
-  assert(!(handle->flags & UV_UDP_PROCESSING));
-  handle->flags |= UV_UDP_PROCESSING;
+  assert(!(handle->flags & UV_HANDLE_UDP_PROCESSING));
+  handle->flags |= UV_HANDLE_UDP_PROCESSING;
 
   while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
     q = QUEUE_HEAD(&handle->write_completed_queue);
@@ -128,7 +128,7 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
       uv__handle_stop(handle);
   }
 
-  handle->flags &= ~UV_UDP_PROCESSING;
+  handle->flags &= ~UV_HANDLE_UDP_PROCESSING;
 }
 
 
@@ -427,7 +427,7 @@ int uv__udp_send(uv_udp_send_t* req,
   QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
   uv__handle_start(handle);
 
-  if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) {
+  if (empty_queue && !(handle->flags & UV_HANDLE_UDP_PROCESSING)) {
     uv__udp_sendmsg(handle);
 
     /* `uv__udp_sendmsg` may not be able to do non-blocking write straight
@@ -624,6 +624,9 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
   if (handle->io_watcher.fd != -1)
     return UV_EBUSY;
 
+  if (uv__fd_exists(handle->loop, sock))
+    return UV_EEXIST;
+
   err = uv__nonblock(sock, 1);
   if (err)
     return err;
@@ -757,14 +760,16 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
  * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
  * and use the general uv__setsockopt_maybe_char call otherwise.
  */
-#if defined(__sun) || defined(_AIX) || defined(__MVS__)
+#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
+    defined(__MVS__)
   if (handle->flags & UV_HANDLE_IPV6)
     return uv__setsockopt(handle,
                           IP_MULTICAST_TTL,
                           IPV6_MULTICAST_HOPS,
                           &ttl,
                           sizeof(ttl));
-#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
+#endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
+    defined(__MVS__) */
 
   return uv__setsockopt_maybe_char(handle,
                                    IP_MULTICAST_TTL,
@@ -780,14 +785,16 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
  * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
  * and use the general uv__setsockopt_maybe_char call otherwise.
  */
-#if defined(__sun) || defined(_AIX) || defined(__MVS__)
+#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
+    defined(__MVS__) 
   if (handle->flags & UV_HANDLE_IPV6)
     return uv__setsockopt(handle,
                           IP_MULTICAST_LOOP,
                           IPV6_MULTICAST_LOOP,
                           &on,
                           sizeof(on));
-#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
+#endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) ||
+    defined(__MVS__) */
 
   return uv__setsockopt_maybe_char(handle,
                                    IP_MULTICAST_LOOP,

+ 37 - 7
src/uv-common.c

@@ -72,7 +72,9 @@ char* uv__strndup(const char* s, size_t n) {
 }
 
 void* uv__malloc(size_t size) {
-  return uv__allocator.local_malloc(size);
+  if (size > 0)
+    return uv__allocator.local_malloc(size);
+  return NULL;
 }
 
 void uv__free(void* ptr) {
@@ -91,7 +93,10 @@ void* uv__calloc(size_t count, size_t size) {
 }
 
 void* uv__realloc(void* ptr, size_t size) {
-  return uv__allocator.local_realloc(ptr, size);
+  if (size > 0)
+    return uv__allocator.local_realloc(ptr, size);
+  uv__free(ptr);
+  return NULL;
 }
 
 int uv_replace_allocator(uv_malloc_func malloc_func,
@@ -155,6 +160,18 @@ static const char* uv__unknown_err_code(int err) {
   return copy != NULL ? copy : "Unknown system error";
 }
 
+#define UV_ERR_NAME_GEN_R(name, _) \
+case UV_## name: \
+  uv__strscpy(buf, #name, buflen); break;
+char* uv_err_name_r(int err, char* buf, size_t buflen) {
+  switch (err) {
+    UV_ERRNO_MAP(UV_ERR_NAME_GEN_R)
+    default: snprintf(buf, buflen, "Unknown system error %d", err);
+  }
+  return buf;
+}
+#undef UV_ERR_NAME_GEN_R
+
 
 #define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
 const char* uv_err_name(int err) {
@@ -166,6 +183,19 @@ const char* uv_err_name(int err) {
 #undef UV_ERR_NAME_GEN
 
 
+#define UV_STRERROR_GEN_R(name, msg) \
+case UV_ ## name: \
+  snprintf(buf, buflen, "%s", msg); break;
+char* uv_strerror_r(int err, char* buf, size_t buflen) {
+  switch (err) {
+    UV_ERRNO_MAP(UV_STRERROR_GEN_R)
+    default: snprintf(buf, buflen, "Unknown system error %d", err);
+  }
+  return buf;
+}
+#undef UV_STRERROR_GEN_R
+
+
 #define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;
 const char* uv_strerror(int err) {
   switch (err) {
@@ -357,7 +387,7 @@ void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
     QUEUE_REMOVE(q);
     QUEUE_INSERT_TAIL(&loop->handle_queue, q);
 
-    if (h->flags & UV__HANDLE_INTERNAL) continue;
+    if (h->flags & UV_HANDLE_INTERNAL) continue;
     walk_cb(h, arg);
   }
 }
@@ -386,9 +416,9 @@ static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
 
     fprintf(stream,
             "[%c%c%c] %-8s %p\n",
-            "R-"[!(h->flags & UV__HANDLE_REF)],
-            "A-"[!(h->flags & UV__HANDLE_ACTIVE)],
-            "I-"[!(h->flags & UV__HANDLE_INTERNAL)],
+            "R-"[!(h->flags & UV_HANDLE_REF)],
+            "A-"[!(h->flags & UV_HANDLE_ACTIVE)],
+            "I-"[!(h->flags & UV_HANDLE_INTERNAL)],
             type,
             (void*)h);
   }
@@ -632,7 +662,7 @@ int uv_loop_close(uv_loop_t* loop) {
 
   QUEUE_FOREACH(q, &loop->handle_queue) {
     h = QUEUE_DATA(q, uv_handle_t, handle_queue);
-    if (!(h->flags & UV__HANDLE_INTERNAL))
+    if (!(h->flags & UV_HANDLE_INTERNAL))
       return UV_EBUSY;
   }
 

+ 91 - 36
src/uv-common.h

@@ -32,14 +32,15 @@
 #include <stddef.h>
 
 #if defined(_MSC_VER) && _MSC_VER < 1600
-# include "stdint-msvc2008.h"
+# include "uv/stdint-msvc2008.h"
 #else
 # include <stdint.h>
 #endif
 
 #include "uv.h"
-#include "tree.h"
+#include "uv/tree.h"
 #include "queue.h"
+#include "strscpy.h"
 
 #if EDOM > 0
 # define UV__ERR(x) (-(x))
@@ -59,22 +60,67 @@ extern int snprintf(char*, size_t, const char*, ...);
 #define STATIC_ASSERT(expr)                                                   \
   void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)])
 
-#ifndef _WIN32
+/* Handle flags. Some flags are specific to Windows or UNIX. */
 enum {
-  UV__SIGNAL_ONE_SHOT = 0x80000,  /* On signal reception remove sighandler */
-  UV__HANDLE_INTERNAL = 0x8000,
-  UV__HANDLE_ACTIVE   = 0x4000,
-  UV__HANDLE_REF      = 0x2000,
-  UV__HANDLE_CLOSING  = 0 /* no-op on unix */
+  /* Used by all handles. */
+  UV_HANDLE_CLOSING                     = 0x00000001,
+  UV_HANDLE_CLOSED                      = 0x00000002,
+  UV_HANDLE_ACTIVE                      = 0x00000004,
+  UV_HANDLE_REF                         = 0x00000008,
+  UV_HANDLE_INTERNAL                    = 0x00000010,
+  UV_HANDLE_ENDGAME_QUEUED              = 0x00000020,
+
+  /* Used by streams. */
+  UV_HANDLE_LISTENING                   = 0x00000040,
+  UV_HANDLE_CONNECTION                  = 0x00000080,
+  UV_HANDLE_SHUTTING                    = 0x00000100,
+  UV_HANDLE_SHUT                        = 0x00000200,
+  UV_HANDLE_READ_PARTIAL                = 0x00000400,
+  UV_HANDLE_READ_EOF                    = 0x00000800,
+
+  /* Used by streams and UDP handles. */
+  UV_HANDLE_READING                     = 0x00001000,
+  UV_HANDLE_BOUND                       = 0x00002000,
+  UV_HANDLE_READABLE                    = 0x00004000,
+  UV_HANDLE_WRITABLE                    = 0x00008000,
+  UV_HANDLE_READ_PENDING                = 0x00010000,
+  UV_HANDLE_SYNC_BYPASS_IOCP            = 0x00020000,
+  UV_HANDLE_ZERO_READ                   = 0x00040000,
+  UV_HANDLE_EMULATE_IOCP                = 0x00080000,
+  UV_HANDLE_BLOCKING_WRITES             = 0x00100000,
+  UV_HANDLE_CANCELLATION_PENDING        = 0x00200000,
+
+  /* Used by uv_tcp_t and uv_udp_t handles */
+  UV_HANDLE_IPV6                        = 0x00400000,
+
+  /* Only used by uv_tcp_t handles. */
+  UV_HANDLE_TCP_NODELAY                 = 0x01000000,
+  UV_HANDLE_TCP_KEEPALIVE               = 0x02000000,
+  UV_HANDLE_TCP_SINGLE_ACCEPT           = 0x04000000,
+  UV_HANDLE_TCP_ACCEPT_STATE_CHANGING   = 0x08000000,
+  UV_HANDLE_TCP_SOCKET_CLOSED           = 0x10000000,
+  UV_HANDLE_SHARED_TCP_SOCKET           = 0x20000000,
+
+  /* Only used by uv_udp_t handles. */
+  UV_HANDLE_UDP_PROCESSING              = 0x01000000,
+
+  /* Only used by uv_pipe_t handles. */
+  UV_HANDLE_NON_OVERLAPPED_PIPE         = 0x01000000,
+  UV_HANDLE_PIPESERVER                  = 0x02000000,
+
+  /* Only used by uv_tty_t handles. */
+  UV_HANDLE_TTY_READABLE                = 0x01000000,
+  UV_HANDLE_TTY_RAW                     = 0x02000000,
+  UV_HANDLE_TTY_SAVED_POSITION          = 0x04000000,
+  UV_HANDLE_TTY_SAVED_ATTRIBUTES        = 0x08000000,
+
+  /* Only used by uv_signal_t handles. */
+  UV_SIGNAL_ONE_SHOT_DISPATCHED         = 0x01000000,
+  UV_SIGNAL_ONE_SHOT                    = 0x02000000,
+
+  /* Only used by uv_poll_t handles. */
+  UV_HANDLE_POLL_SLOW                   = 0x01000000
 };
-#else
-# define UV__SIGNAL_ONE_SHOT_DISPATCHED   0x200
-# define UV__SIGNAL_ONE_SHOT              0x100
-# define UV__HANDLE_INTERNAL              0x80
-# define UV__HANDLE_ACTIVE                0x40
-# define UV__HANDLE_REF                   0x20
-# define UV__HANDLE_CLOSING               0x01
-#endif
 
 int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
 
@@ -119,8 +165,15 @@ void uv__fs_poll_close(uv_fs_poll_t* handle);
 
 int uv__getaddrinfo_translate_error(int sys_err);    /* EAI_* error. */
 
+enum uv__work_kind {
+  UV__WORK_CPU,
+  UV__WORK_FAST_IO,
+  UV__WORK_SLOW_IO
+};
+
 void uv__work_submit(uv_loop_t* loop,
                      struct uv__work *w,
+                     enum uv__work_kind kind,
                      void (*work)(struct uv__work *w),
                      void (*done)(struct uv__work *w, int status));
 
@@ -132,6 +185,10 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value);
 
 void uv__fs_scandir_cleanup(uv_fs_t* req);
 
+int uv__next_timeout(const uv_loop_t* loop);
+void uv__run_timers(uv_loop_t* loop);
+void uv__timer_close(uv_timer_t* handle);
+
 #define uv__has_active_reqs(loop)                                             \
   ((loop)->active_reqs.count > 0)
 
@@ -164,49 +221,47 @@ void uv__fs_scandir_cleanup(uv_fs_t* req);
   while (0)
 
 #define uv__is_active(h)                                                      \
-  (((h)->flags & UV__HANDLE_ACTIVE) != 0)
+  (((h)->flags & UV_HANDLE_ACTIVE) != 0)
 
 #define uv__is_closing(h)                                                     \
-  (((h)->flags & (UV_CLOSING |  UV_CLOSED)) != 0)
+  (((h)->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED)) != 0)
 
 #define uv__handle_start(h)                                                   \
   do {                                                                        \
-    assert(((h)->flags & UV__HANDLE_CLOSING) == 0);                           \
-    if (((h)->flags & UV__HANDLE_ACTIVE) != 0) break;                         \
-    (h)->flags |= UV__HANDLE_ACTIVE;                                          \
-    if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(h);         \
+    if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break;                          \
+    (h)->flags |= UV_HANDLE_ACTIVE;                                           \
+    if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_add(h);          \
   }                                                                           \
   while (0)
 
 #define uv__handle_stop(h)                                                    \
   do {                                                                        \
-    assert(((h)->flags & UV__HANDLE_CLOSING) == 0);                           \
-    if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break;                         \
-    (h)->flags &= ~UV__HANDLE_ACTIVE;                                         \
-    if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h);          \
+    if (((h)->flags & UV_HANDLE_ACTIVE) == 0) break;                          \
+    (h)->flags &= ~UV_HANDLE_ACTIVE;                                          \
+    if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_rm(h);           \
   }                                                                           \
   while (0)
 
 #define uv__handle_ref(h)                                                     \
   do {                                                                        \
-    if (((h)->flags & UV__HANDLE_REF) != 0) break;                            \
-    (h)->flags |= UV__HANDLE_REF;                                             \
-    if (((h)->flags & UV__HANDLE_CLOSING) != 0) break;                        \
-    if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_add(h);      \
+    if (((h)->flags & UV_HANDLE_REF) != 0) break;                             \
+    (h)->flags |= UV_HANDLE_REF;                                              \
+    if (((h)->flags & UV_HANDLE_CLOSING) != 0) break;                         \
+    if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_add(h);       \
   }                                                                           \
   while (0)
 
 #define uv__handle_unref(h)                                                   \
   do {                                                                        \
-    if (((h)->flags & UV__HANDLE_REF) == 0) break;                            \
-    (h)->flags &= ~UV__HANDLE_REF;                                            \
-    if (((h)->flags & UV__HANDLE_CLOSING) != 0) break;                        \
-    if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_rm(h);       \
+    if (((h)->flags & UV_HANDLE_REF) == 0) break;                             \
+    (h)->flags &= ~UV_HANDLE_REF;                                             \
+    if (((h)->flags & UV_HANDLE_CLOSING) != 0) break;                         \
+    if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_rm(h);        \
   }                                                                           \
   while (0)
 
 #define uv__has_ref(h)                                                        \
-  (((h)->flags & UV__HANDLE_REF) != 0)
+  (((h)->flags & UV_HANDLE_REF) != 0)
 
 #if defined(_WIN32)
 # define uv__handle_platform_init(h) ((h)->u.fd = -1)
@@ -218,7 +273,7 @@ void uv__fs_scandir_cleanup(uv_fs_t* req);
   do {                                                                        \
     (h)->loop = (loop_);                                                      \
     (h)->type = (type_);                                                      \
-    (h)->flags = UV__HANDLE_REF;  /* Ref the loop when active. */             \
+    (h)->flags = UV_HANDLE_REF;  /* Ref the loop when active. */              \
     QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue);            \
     uv__handle_platform_init(h);                                              \
   }                                                                           \

+ 9 - 7
src/uv-data-getter-setters.c

@@ -3,11 +3,11 @@
 const char* uv_handle_type_name(uv_handle_type type) {
   switch (type) {
 #define XX(uc,lc) case UV_##uc: return #lc;
-    UV_HANDLE_TYPE_MAP(XX)
+  UV_HANDLE_TYPE_MAP(XX)
 #undef XX
-    case UV_FILE: return "file";
-    case UV_HANDLE_TYPE_MAX:
-    case UV_UNKNOWN_HANDLE: return NULL;
+  case UV_FILE: return "file";
+  case UV_HANDLE_TYPE_MAX:
+  case UV_UNKNOWN_HANDLE: return NULL;
   }
   return NULL;
 }
@@ -31,10 +31,12 @@ void uv_handle_set_data(uv_handle_t* handle, void* data) {
 const char* uv_req_type_name(uv_req_type type) {
   switch (type) {
 #define XX(uc,lc) case UV_##uc: return #lc;
-    UV_REQ_TYPE_MAP(XX)
+  UV_REQ_TYPE_MAP(XX)
 #undef XX
-    case UV_REQ_TYPE_MAX:
-    case UV_UNKNOWN_REQ: return NULL;
+  case UV_REQ_TYPE_MAX:
+  case UV_UNKNOWN_REQ:
+  default: /* UV_REQ_TYPE_PRIVATE */
+     return NULL;
   }
   return NULL;
 }

+ 5 - 5
src/win/async.c

@@ -29,7 +29,7 @@
 
 
 void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
-  if (handle->flags & UV__HANDLE_CLOSING &&
+  if (handle->flags & UV_HANDLE_CLOSING &&
       !handle->async_sent) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     uv__handle_close(handle);
@@ -71,9 +71,9 @@ int uv_async_send(uv_async_t* handle) {
     return -1;
   }
 
-  /* The user should make sure never to call uv_async_send to a closing */
-  /* or closed handle. */
-  assert(!(handle->flags & UV__HANDLE_CLOSING));
+  /* The user should make sure never to call uv_async_send to a closing or
+   * closed handle. */
+  assert(!(handle->flags & UV_HANDLE_CLOSING));
 
   if (!uv__atomic_exchange_set(&handle->async_sent)) {
     POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
@@ -90,7 +90,7 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
 
   handle->async_sent = 0;
 
-  if (handle->flags & UV__HANDLE_CLOSING) {
+  if (handle->flags & UV_HANDLE_CLOSING) {
     uv_want_endgame(loop, (uv_handle_t*)handle);
   } else if (handle->async_cb != NULL) {
     handle->async_cb(handle);

+ 4 - 4
src/win/atomicops-inl.h

@@ -29,10 +29,10 @@
 /* Atomic set operation on char */
 #ifdef _MSC_VER /* MSVC */
 
-/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is  slightly less */
-/* efficient than InterlockedExchange, but InterlockedExchange8 does not */
-/* exist, and interlocked operations on larger targets might require the */
-/* target to be aligned. */
+/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less
+ * efficient than InterlockedExchange, but InterlockedExchange8 does not exist,
+ * and interlocked operations on larger targets might require the target to be
+ * aligned. */
 #pragma intrinsic(_InterlockedOr8)
 
 static char INLINE uv__atomic_exchange_set(char volatile* target) {

+ 39 - 19
src/win/core.c

@@ -33,6 +33,7 @@
 #include "internal.h"
 #include "queue.h"
 #include "handle-inl.h"
+#include "heap-inl.h"
 #include "req-inl.h"
 
 /* uv_once initialization guards */
@@ -221,6 +222,7 @@ static void uv_init(void) {
 
 
 int uv_loop_init(uv_loop_t* loop) {
+  struct heap* timer_heap;
   int err;
 
   /* Initialize libuv itself first */
@@ -246,7 +248,13 @@ int uv_loop_init(uv_loop_t* loop) {
 
   loop->endgame_handles = NULL;
 
-  RB_INIT(&loop->timers);
+  loop->timer_heap = timer_heap = uv__malloc(sizeof(*timer_heap));
+  if (timer_heap == NULL) {
+    err = UV_ENOMEM;
+    goto fail_timers_alloc;
+  }
+
+  heap_init(timer_heap);
 
   loop->check_handles = NULL;
   loop->prepare_handles = NULL;
@@ -273,7 +281,7 @@ int uv_loop_init(uv_loop_t* loop) {
     goto fail_async_init;
 
   uv__handle_unref(&loop->wq_async);
-  loop->wq_async.flags |= UV__HANDLE_INTERNAL;
+  loop->wq_async.flags |= UV_HANDLE_INTERNAL;
 
   err = uv__loops_add(loop);
   if (err)
@@ -285,6 +293,10 @@ fail_async_init:
   uv_mutex_destroy(&loop->wq_mutex);
 
 fail_mutex_init:
+  uv__free(timer_heap);
+  loop->timer_heap = NULL;
+
+fail_timers_alloc:
   CloseHandle(loop->iocp);
   loop->iocp = INVALID_HANDLE_VALUE;
 
@@ -292,6 +304,13 @@ fail_mutex_init:
 }
 
 
+void uv_update_time(uv_loop_t* loop) {
+  uint64_t new_time = uv__hrtime(1000);
+  assert(new_time >= loop->time);
+  loop->time = new_time;
+}
+
+
 void uv__once_init(void) {
   uv_once(&uv_init_guard_, uv_init);
 }
@@ -320,6 +339,9 @@ void uv__loop_close(uv_loop_t* loop) {
   uv_mutex_unlock(&loop->wq_mutex);
   uv_mutex_destroy(&loop->wq_mutex);
 
+  uv__free(loop->timer_heap);
+  loop->timer_heap = NULL;
+
   CloseHandle(loop->iocp);
 }
 
@@ -359,7 +381,7 @@ int uv_backend_timeout(const uv_loop_t* loop) {
 }
 
 
-static void uv_poll(uv_loop_t* loop, DWORD timeout) {
+static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
   DWORD bytes;
   ULONG_PTR key;
   OVERLAPPED* overlapped;
@@ -410,7 +432,7 @@ static void uv_poll(uv_loop_t* loop, DWORD timeout) {
 }
 
 
-static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
+static void uv__poll(uv_loop_t* loop, DWORD timeout) {
   BOOL success;
   uv_req_t* req;
   OVERLAPPED_ENTRY overlappeds[128];
@@ -422,12 +444,12 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
   timeout_time = loop->time + timeout;
 
   for (repeat = 0; ; repeat++) {
-    success = pGetQueuedCompletionStatusEx(loop->iocp,
-                                           overlappeds,
-                                           ARRAY_SIZE(overlappeds),
-                                           &count,
-                                           timeout,
-                                           FALSE);
+    success = GetQueuedCompletionStatusEx(loop->iocp,
+                                          overlappeds,
+                                          ARRAY_SIZE(overlappeds),
+                                          &count,
+                                          timeout,
+                                          FALSE);
 
     if (success) {
       for (i = 0; i < count; i++) {
@@ -485,12 +507,6 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
   DWORD timeout;
   int r;
   int ran_pending;
-  void (*poll)(uv_loop_t* loop, DWORD timeout);
-
-  if (pGetQueuedCompletionStatusEx)
-    poll = &uv_poll_ex;
-  else
-    poll = &uv_poll;
 
   r = uv__loop_alive(loop);
   if (!r)
@@ -498,7 +514,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
 
   while (r != 0 && loop->stop_flag == 0) {
     uv_update_time(loop);
-    uv_process_timers(loop);
+    uv__run_timers(loop);
 
     ran_pending = uv_process_reqs(loop);
     uv_idle_invoke(loop);
@@ -508,7 +524,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
     if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
       timeout = uv_backend_timeout(loop);
 
-    (*poll)(loop, timeout);
+    if (pGetQueuedCompletionStatusEx)
+      uv__poll(loop, timeout);
+    else
+      uv__poll_wine(loop, timeout);
+
 
     uv_check_invoke(loop);
     uv_process_endgames(loop);
@@ -522,7 +542,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
        * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
        * the check.
        */
-      uv_process_timers(loop);
+      uv__run_timers(loop);
     }
 
     r = uv__loop_alive(loop);

+ 7 - 4
src/win/dl.c

@@ -64,7 +64,8 @@ void uv_dlclose(uv_lib_t* lib) {
 
 
 int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
-  *ptr = (void*) GetProcAddress(lib->handle, name);
+  /* Cast though integer to suppress pedantic warning about forbidden cast. */
+  *ptr = (void*)(uintptr_t) GetProcAddress(lib->handle, name);
   return uv__dlerror(lib, "", *ptr ? 0 : GetLastError());
 }
 
@@ -75,8 +76,9 @@ const char* uv_dlerror(const uv_lib_t* lib) {
 
 
 static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
-  DWORD_PTR args[1] = { (DWORD_PTR) errorno };
-  LPSTR fallback_error = "error: %1!d!";
+  static const CHAR fallback_error[] = "error: %1!d!";
+  DWORD_PTR args[1];
+  args[0] = (DWORD_PTR) errorno;
 
   FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
                  FORMAT_MESSAGE_ARGUMENT_ARRAY |
@@ -107,7 +109,8 @@ static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) {
                        MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
                        (LPSTR) &lib->errmsg, 0, NULL);
 
-  if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
+  if (!res && (GetLastError() == ERROR_MUI_FILE_NOT_FOUND ||
+               GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND)) {
     res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                          FORMAT_MESSAGE_FROM_SYSTEM |
                          FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,

+ 2 - 2
src/win/error.c

@@ -46,8 +46,8 @@ void uv_fatal_error(const int errorno, const char* syscall) {
     errmsg = "Unknown error";
   }
 
-  /* FormatMessage messages include a newline character already, */
-  /* so don't add another. */
+  /* FormatMessage messages include a newline character already, so don't add
+   * another. */
   if (syscall) {
     fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
   } else {

+ 14 - 11
src/win/fs-event.c

@@ -83,7 +83,7 @@ static void uv_relative_path(const WCHAR* filename,
 static int uv_split_path(const WCHAR* filename, WCHAR** dir,
     WCHAR** file) {
   size_t len, i;
- 
+
   if (filename == NULL) {
     if (dir != NULL)
       *dir = NULL;
@@ -215,11 +215,11 @@ int uv_fs_event_start(uv_fs_event_t* handle,
         uv__free(long_path);
         long_path = NULL;
       }
-    }
 
-    if (long_path) {
-      uv__free(pathw);
-      pathw = long_path;
+      if (long_path) {
+        uv__free(pathw);
+        pathw = long_path;
+      }
     }
 
     dir_to_watch = pathw;
@@ -230,8 +230,11 @@ int uv_fs_event_start(uv_fs_event_t* handle,
      */
 
     /* Convert to short path. */
-    short_path = short_path_buffer;
-    if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) {
+    if (GetShortPathNameW(pathw,
+                          short_path_buffer,
+                          ARRAY_SIZE(short_path_buffer))) {
+      short_path = short_path_buffer;
+    } else {
       short_path = NULL;
     }
 
@@ -419,7 +422,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
    * - We are not active, just ignore the callback
    */
   if (!uv__is_active(handle)) {
-    if (handle->flags & UV__HANDLE_CLOSING) {
+    if (handle->flags & UV_HANDLE_CLOSING) {
       uv_want_endgame(loop, (uv_handle_t*) handle);
     }
     return;
@@ -543,7 +546,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
         }
 
         offset = file_info->NextEntryOffset;
-      } while (offset && !(handle->flags & UV__HANDLE_CLOSING));
+      } while (offset && !(handle->flags & UV_HANDLE_CLOSING));
     } else {
       handle->cb(handle, NULL, UV_CHANGE, 0);
     }
@@ -552,7 +555,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
     handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
   }
 
-  if (!(handle->flags & UV__HANDLE_CLOSING)) {
+  if (!(handle->flags & UV_HANDLE_CLOSING)) {
     uv_fs_event_queue_readdirchanges(loop, handle);
   } else {
     uv_want_endgame(loop, (uv_handle_t*)handle);
@@ -573,7 +576,7 @@ void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
 
 
 void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
-  if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) {
+  if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
 
     if (handle->buffer) {

+ 133 - 51
src/win/fs.c

@@ -55,7 +55,11 @@
   do {                                                                        \
     if (cb != NULL) {                                                         \
       uv__req_register(loop, req);                                            \
-      uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done);        \
+      uv__work_submit(loop,                                                   \
+                      &req->work_req,                                         \
+                      UV__WORK_FAST_IO,                                       \
+                      uv__fs_work,                                            \
+                      uv__fs_done);                                           \
       return 0;                                                               \
     } else {                                                                  \
       uv__fs_work(&req->work_req);                                            \
@@ -92,14 +96,17 @@
     return;                                                                 \
   }
 
+#define MILLIONu (1000U * 1000U)
+#define BILLIONu (1000U * 1000U * 1000U)
+
 #define FILETIME_TO_UINT(filetime)                                          \
-   (*((uint64_t*) &(filetime)) - 116444736000000000ULL)
+   (*((uint64_t*) &(filetime)) - (uint64_t) 116444736 * BILLIONu)
 
 #define FILETIME_TO_TIME_T(filetime)                                        \
-   (FILETIME_TO_UINT(filetime) / 10000000ULL)
+   (FILETIME_TO_UINT(filetime) / (10u * MILLIONu))
 
 #define FILETIME_TO_TIME_NS(filetime, secs)                                 \
-   ((FILETIME_TO_UINT(filetime) - (secs * 10000000ULL)) * 100)
+   ((FILETIME_TO_UINT(filetime) - (secs * (uint64_t) 10 * MILLIONu)) * 100U)
 
 #define FILETIME_TO_TIMESPEC(ts, filetime)                                  \
    do {                                                                     \
@@ -109,8 +116,8 @@
 
 #define TIME_T_TO_FILETIME(time, filetime_ptr)                              \
   do {                                                                      \
-    uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) +                \
-                                  116444736000000000ULL;                    \
+    uint64_t bigtime = ((uint64_t) ((time) * (uint64_t) 10 * MILLIONu)) +   \
+                       (uint64_t) 116444736 * BILLIONu;                     \
     (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF;                   \
     (filetime_ptr)->dwHighDateTime = bigtime >> 32;                         \
   } while(0)
@@ -326,12 +333,11 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
         reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
         sizeof(WCHAR);
 
-    /* Real symlinks can contain pretty much everything, but the only thing */
-    /* we really care about is undoing the implicit conversion to an NT */
-    /* namespaced path that CreateSymbolicLink will perform on absolute */
-    /* paths. If the path is win32-namespaced then the user must have */
-    /* explicitly made it so, and we better just return the unmodified */
-    /* reparse data. */
+    /* Real symlinks can contain pretty much everything, but the only thing we
+     * really care about is undoing the implicit conversion to an NT namespaced
+     * path that CreateSymbolicLink will perform on absolute paths. If the path
+     * is win32-namespaced then the user must have explicitly made it so, and
+     * we better just return the unmodified reparse data. */
     if (w_target_len >= 4 &&
         w_target[0] == L'\\' &&
         w_target[1] == L'?' &&
@@ -352,8 +358,8 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
                  (w_target[5] == L'N' || w_target[5] == L'n') &&
                  (w_target[6] == L'C' || w_target[6] == L'c') &&
                  w_target[7] == L'\\') {
-        /* \??\UNC\<server>\<share>\ - make sure the final path looks like */
-        /* \\<server>\<share>\ */
+        /* \??\UNC\<server>\<share>\ - make sure the final path looks like
+         * \\<server>\<share>\ */
         w_target += 6;
         w_target[0] = L'\\';
         w_target_len -= 6;
@@ -368,11 +374,11 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
     w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
         sizeof(WCHAR);
 
-    /* Only treat junctions that look like \??\<drive>:\ as symlink. */
-    /* Junctions can also be used as mount points, like \??\Volume{<guid>}, */
-    /* but that's confusing for programs since they wouldn't be able to */
-    /* actually understand such a path when returned by uv_readlink(). */
-    /* UNC paths are never valid for junctions so we don't care about them. */
+    /* Only treat junctions that look like \??\<drive>:\ as symlink. Junctions
+     * can also be used as mount points, like \??\Volume{<guid>}, but that's
+     * confusing for programs since they wouldn't be able to actually
+     * understand such a path when returned by uv_readlink(). UNC paths are
+     * never valid for junctions so we don't care about them. */
     if (!(w_target_len >= 6 &&
           w_target[0] == L'\\' &&
           w_target[1] == L'?' &&
@@ -409,8 +415,8 @@ void fs__open(uv_fs_t* req) {
   int fd, current_umask;
   int flags = req->fs.info.file_flags;
 
-  /* Obtain the active umask. umask() never fails and returns the previous */
-  /* umask. */
+  /* Obtain the active umask. umask() never fails and returns the previous
+   * umask. */
   current_umask = umask(0);
   umask(current_umask);
 
@@ -502,6 +508,33 @@ void fs__open(uv_fs_t* req) {
   }
 
   if (flags & UV_FS_O_DIRECT) {
+    /*
+     * FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually exclusive.
+     * Windows returns 87, ERROR_INVALID_PARAMETER if these are combined.
+     *
+     * FILE_APPEND_DATA is included in FILE_GENERIC_WRITE:
+     *
+     * FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE |
+     *                      FILE_WRITE_DATA |
+     *                      FILE_WRITE_ATTRIBUTES |
+     *                      FILE_WRITE_EA |
+     *                      FILE_APPEND_DATA |
+     *                      SYNCHRONIZE
+     *
+     * Note: Appends are also permitted by FILE_WRITE_DATA.
+     *
+     * In order for direct writes and direct appends to succeed, we therefore
+     * exclude FILE_APPEND_DATA if FILE_WRITE_DATA is specified, and otherwise
+     * fail if the user's sole permission is a direct append, since this
+     * particular combination is invalid.
+     */
+    if (access & FILE_APPEND_DATA) {
+      if (access & FILE_WRITE_DATA) {
+        access &= ~FILE_APPEND_DATA;
+      } else {
+        goto einval;
+      }
+    }
     attributes |= FILE_FLAG_NO_BUFFERING;
   }
 
@@ -530,8 +563,8 @@ void fs__open(uv_fs_t* req) {
     DWORD error = GetLastError();
     if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) &&
         !(flags & UV_FS_O_EXCL)) {
-      /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was */
-      /* specified, it means the path referred to a directory. */
+      /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was
+       * specified, it means the path referred to a directory. */
       SET_REQ_UV_ERROR(req, UV_EISDIR, error);
     } else {
       SET_REQ_WIN32_ERROR(req, GetLastError());
@@ -756,9 +789,9 @@ void fs__unlink(uv_fs_t* req) {
   }
 
   if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
-    /* Do not allow deletion of directories, unless it is a symlink. When */
-    /* the path refers to a non-symlink directory, report EPERM as mandated */
-    /* by POSIX.1. */
+    /* Do not allow deletion of directories, unless it is a symlink. When the
+     * path refers to a non-symlink directory, report EPERM as mandated by
+     * POSIX.1. */
 
     /* Check if it is a reparse point. If it's not, it's a normal directory. */
     if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
@@ -767,8 +800,8 @@ void fs__unlink(uv_fs_t* req) {
       return;
     }
 
-    /* Read the reparse point and check if it is a valid symlink. */
-    /* If not, don't unlink. */
+    /* Read the reparse point and check if it is a valid symlink. If not, don't
+     * unlink. */
     if (fs__readlink_handle(handle, NULL, NULL) < 0) {
       DWORD error = GetLastError();
       if (error == ERROR_SYMLINK_NOT_SUPPORTED)
@@ -783,9 +816,8 @@ void fs__unlink(uv_fs_t* req) {
     /* Remove read-only attribute */
     FILE_BASIC_INFORMATION basic = { 0 };
 
-    basic.FileAttributes = info.dwFileAttributes
-                           & ~(FILE_ATTRIBUTE_READONLY)
-                           | FILE_ATTRIBUTE_ARCHIVE;
+    basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) |
+                           FILE_ATTRIBUTE_ARCHIVE;
 
     status = pNtSetInformationFile(handle,
                                    &iosb,
@@ -1196,7 +1228,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
 
   /* st_blocks contains the on-disk allocation size in 512-byte units. */
   statbuf->st_blocks =
-      file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL;
+      (uint64_t) file_info.StandardInformation.AllocationSize.QuadPart >> 9;
 
   statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
 
@@ -1490,6 +1522,7 @@ static void fs__chmod(uv_fs_t* req) {
 
 static void fs__fchmod(uv_fs_t* req) {
   int fd = req->file.fd;
+  int clear_archive_flag;
   HANDLE handle;
   NTSTATUS nt_status;
   IO_STATUS_BLOCK io_status;
@@ -1497,7 +1530,11 @@ static void fs__fchmod(uv_fs_t* req) {
 
   VERIFY_FD(fd, req);
 
-  handle = uv__get_osfhandle(fd);
+  handle = ReOpenFile(uv__get_osfhandle(fd), FILE_WRITE_ATTRIBUTES, 0, 0);
+  if (handle == INVALID_HANDLE_VALUE) {
+    SET_REQ_WIN32_ERROR(req, GetLastError());
+    return;
+  }
 
   nt_status = pNtQueryInformationFile(handle,
                                       &io_status,
@@ -1507,7 +1544,27 @@ static void fs__fchmod(uv_fs_t* req) {
 
   if (!NT_SUCCESS(nt_status)) {
     SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
-    return;
+    goto fchmod_cleanup;
+  }
+
+  /* Test if the Archive attribute is cleared */
+  if ((file_info.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == 0) {
+      /* Set Archive flag, otherwise setting or clearing the read-only
+         flag will not work */
+      file_info.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
+      nt_status = pNtSetInformationFile(handle,
+                                        &io_status,
+                                        &file_info,
+                                        sizeof file_info,
+                                        FileBasicInformation);
+      if (!NT_SUCCESS(nt_status)) {
+        SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
+        goto fchmod_cleanup;
+      }
+      /* Remeber to clear the flag later on */
+      clear_archive_flag = 1;
+  } else {
+      clear_archive_flag = 0;
   }
 
   if (req->fs.info.mode & _S_IWRITE) {
@@ -1524,10 +1581,28 @@ static void fs__fchmod(uv_fs_t* req) {
 
   if (!NT_SUCCESS(nt_status)) {
     SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
-    return;
+    goto fchmod_cleanup;
+  }
+
+  if (clear_archive_flag) {
+      file_info.FileAttributes &= ~FILE_ATTRIBUTE_ARCHIVE;
+      if (file_info.FileAttributes == 0) {
+          file_info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+      }
+      nt_status = pNtSetInformationFile(handle,
+                                        &io_status,
+                                        &file_info,
+                                        sizeof file_info,
+                                        FileBasicInformation);
+      if (!NT_SUCCESS(nt_status)) {
+        SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
+        goto fchmod_cleanup;
+      }
   }
 
   SET_REQ_SUCCESS(req);
+fchmod_cleanup:
+  CloseHandle(handle);
 }
 
 
@@ -1787,17 +1862,13 @@ static void fs__symlink(uv_fs_t* req) {
     fs__create_junction(req, pathw, new_pathw);
     return;
   }
-  if (!pCreateSymbolicLinkW) {
-    SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
-    return;
-  }
 
   if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR)
     flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag;
   else
     flags = uv__file_symlink_usermode_flag;
 
-  if (pCreateSymbolicLinkW(new_pathw, pathw, flags)) {
+  if (CreateSymbolicLinkW(new_pathw, pathw, flags)) {
     SET_REQ_RESULT(req, 0);
     return;
   }
@@ -1848,13 +1919,13 @@ static void fs__readlink(uv_fs_t* req) {
 }
 
 
-static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
+static ssize_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
   int r;
   DWORD w_realpath_len;
   WCHAR* w_realpath_ptr = NULL;
   WCHAR* w_realpath_buf;
 
-  w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
+  w_realpath_len = GetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
   if (w_realpath_len == 0) {
     return -1;
   }
@@ -1866,10 +1937,8 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
   }
   w_realpath_ptr = w_realpath_buf;
 
-  if (pGetFinalPathNameByHandleW(handle,
-                                w_realpath_ptr,
-                                w_realpath_len,
-                                VOLUME_NAME_DOS) == 0) {
+  if (GetFinalPathNameByHandleW(
+          handle, w_realpath_ptr, w_realpath_len, VOLUME_NAME_DOS) == 0) {
     uv__free(w_realpath_buf);
     SetLastError(ERROR_INVALID_HANDLE);
     return -1;
@@ -1901,11 +1970,6 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
 static void fs__realpath(uv_fs_t* req) {
   HANDLE handle;
 
-  if (!pGetFinalPathNameByHandleW) {
-    SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
-    return;
-  }
-
   handle = CreateFileW(req->file.pathw,
                        0,
                        0,
@@ -1940,6 +2004,10 @@ static void fs__fchown(uv_fs_t* req) {
 }
 
 
+static void fs__lchown(uv_fs_t* req) {
+  req->result = 0;
+}
+
 static void uv__fs_work(struct uv__work* w) {
   uv_fs_t* req;
 
@@ -1977,6 +2045,7 @@ static void uv__fs_work(struct uv__work* w) {
     XX(REALPATH, realpath)
     XX(CHOWN, chown)
     XX(FCHOWN, fchown);
+    XX(LCHOWN, lchown);
     default:
       assert(!"bad uv_fs_type");
   }
@@ -2262,6 +2331,19 @@ int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid,
 }
 
 
+int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
+    uv_gid_t gid, uv_fs_cb cb) {
+  int err;
+
+  INIT(UV_FS_LCHOWN);
+  err = fs__capture_path(req, path, NULL, cb != NULL);
+  if (err) {
+    return uv_translate_sys_error(err);
+  }
+  POST;
+}
+
+
 int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
   int err;
 

+ 22 - 18
src/win/getaddrinfo.c

@@ -24,6 +24,7 @@
 #include "uv.h"
 #include "internal.h"
 #include "req-inl.h"
+#include "idna.h"
 
 /* EAI_* constants. */
 #include <winsock2.h>
@@ -71,8 +72,8 @@ int uv__getaddrinfo_translate_error(int sys_err) {
 #endif
 
 
-/* adjust size value to be multiple of 4. Use to keep pointer aligned */
-/* Do we need different versions of this for different architectures? */
+/* Adjust size value to be multiple of 4. Use to keep pointer aligned.
+ * Do we need different versions of this for different architectures? */
 #define ALIGNED_SIZE(X)     ((((X) + 3) >> 2) << 2)
 
 #ifndef NDIS_IF_MAX_STRING_SIZE
@@ -124,8 +125,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
   }
 
   if (req->retcode == 0) {
-    /* convert addrinfoW to addrinfo */
-    /* first calculate required length */
+    /* Convert addrinfoW to addrinfo. First calculate required length. */
     addrinfow_ptr = req->addrinfow;
     while (addrinfow_ptr != NULL) {
       addrinfo_len += addrinfo_struct_len +
@@ -260,11 +260,13 @@ int uv_getaddrinfo(uv_loop_t* loop,
                    const char* node,
                    const char* service,
                    const struct addrinfo* hints) {
+  char hostname_ascii[256];
   int nodesize = 0;
   int servicesize = 0;
   int hintssize = 0;
   char* alloc_ptr = NULL;
   int err;
+  long rc;
 
   if (req == NULL || (node == NULL && service == NULL)) {
     return UV_EINVAL;
@@ -278,12 +280,19 @@ int uv_getaddrinfo(uv_loop_t* loop,
 
   /* calculate required memory size for all input values */
   if (node != NULL) {
-    nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) *
-                            sizeof(WCHAR));
+    rc = uv__idna_toascii(node,
+                          node + strlen(node),
+                          hostname_ascii,
+                          hostname_ascii + sizeof(hostname_ascii));
+    if (rc < 0)
+      return rc;
+    nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii,
+                                                -1, NULL, 0) * sizeof(WCHAR));
     if (nodesize == 0) {
       err = GetLastError();
       goto error;
     }
+    node = hostname_ascii;
   }
 
   if (service != NULL) {
@@ -313,8 +322,8 @@ int uv_getaddrinfo(uv_loop_t* loop,
   /* save alloc_ptr now so we can free if error */
   req->alloc = (void*)alloc_ptr;
 
-  /* convert node string to UTF16 into allocated memory and save pointer in */
-  /* the request. */
+  /* Convert node string to UTF16 into allocated memory and save pointer in the
+   * request. */
   if (node != NULL) {
     req->node = (WCHAR*)alloc_ptr;
     if (MultiByteToWideChar(CP_UTF8,
@@ -331,8 +340,8 @@ int uv_getaddrinfo(uv_loop_t* loop,
     req->node = NULL;
   }
 
-  /* convert service string to UTF16 into allocated memory and save pointer */
-  /* in the req. */
+  /* Convert service string to UTF16 into allocated memory and save pointer in
+   * the req. */
   if (service != NULL) {
     req->service = (WCHAR*)alloc_ptr;
     if (MultiByteToWideChar(CP_UTF8,
@@ -369,6 +378,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
   if (getaddrinfo_cb) {
     uv__work_submit(loop,
                     &req->work_req,
+                    UV__WORK_SLOW_IO,
                     uv__getaddrinfo_work,
                     uv__getaddrinfo_done);
     return 0;
@@ -392,21 +402,15 @@ int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
   DWORD bufsize;
   int r;
 
-  uv__once_init();
-
   if (buffer == NULL || size == NULL || *size == 0)
     return UV_EINVAL;
 
-  if (pConvertInterfaceIndexToLuid == NULL)
-    return UV_ENOSYS;
-  r = pConvertInterfaceIndexToLuid(ifindex, &luid);
+  r = ConvertInterfaceIndexToLuid(ifindex, &luid);
 
   if (r != 0)
     return uv_translate_sys_error(r);
 
-  if (pConvertInterfaceLuidToNameW == NULL)
-    return UV_ENOSYS;
-  r = pConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
+  r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
 
   if (r != 0)
     return uv_translate_sys_error(r);

+ 29 - 21
src/win/getnameinfo.c

@@ -42,7 +42,7 @@ static void uv__getnameinfo_work(struct uv__work* w) {
   uv_getnameinfo_t* req;
   WCHAR host[NI_MAXHOST];
   WCHAR service[NI_MAXSERV];
-  int ret = 0;
+  int ret;
 
   req = container_of(w, uv_getnameinfo_t, work_req);
   if (GetNameInfoW((struct sockaddr*)&req->storage,
@@ -53,27 +53,34 @@ static void uv__getnameinfo_work(struct uv__work* w) {
                    ARRAY_SIZE(service),
                    req->flags)) {
     ret = WSAGetLastError();
+    req->retcode = uv__getaddrinfo_translate_error(ret);
+    return;
+  }
+
+  ret = WideCharToMultiByte(CP_UTF8,
+                            0,
+                            host,
+                            -1,
+                            req->host,
+                            sizeof(req->host),
+                            NULL,
+                            NULL);
+  if (ret == 0) {
+    req->retcode = uv_translate_sys_error(GetLastError());
+    return;
+  }
+
+  ret = WideCharToMultiByte(CP_UTF8,
+                            0,
+                            service,
+                            -1,
+                            req->service,
+                            sizeof(req->service),
+                            NULL,
+                            NULL);
+  if (ret == 0) {
+    req->retcode = uv_translate_sys_error(GetLastError());
   }
-  req->retcode = uv__getaddrinfo_translate_error(ret);
-
-  /* convert results to UTF-8 */
-  WideCharToMultiByte(CP_UTF8,
-                      0,
-                      host,
-                      -1,
-                      req->host,
-                      sizeof(req->host),
-                      NULL,
-                      NULL);
-
-  WideCharToMultiByte(CP_UTF8,
-                      0,
-                      service,
-                      -1,
-                      req->service,
-                      sizeof(req->service),
-                      NULL,
-                      NULL);
 }
 
 
@@ -138,6 +145,7 @@ int uv_getnameinfo(uv_loop_t* loop,
   if (getnameinfo_cb) {
     uv__work_submit(loop,
                     &req->work_req,
+                    UV__WORK_SLOW_IO,
                     uv__getnameinfo_work,
                     uv__getnameinfo_done);
     return 0;

+ 13 - 12
src/win/handle-inl.h

@@ -32,7 +32,7 @@
 #define DECREASE_ACTIVE_COUNT(loop, handle)                             \
   do {                                                                  \
     if (--(handle)->activecnt == 0 &&                                   \
-        !((handle)->flags & UV__HANDLE_CLOSING)) {                      \
+        !((handle)->flags & UV_HANDLE_CLOSING)) {                       \
       uv__handle_stop((handle));                                        \
     }                                                                   \
     assert((handle)->activecnt >= 0);                                   \
@@ -53,7 +53,7 @@
     assert(handle->reqs_pending > 0);                                   \
     handle->reqs_pending--;                                             \
                                                                         \
-    if (handle->flags & UV__HANDLE_CLOSING &&                           \
+    if (handle->flags & UV_HANDLE_CLOSING &&                            \
         handle->reqs_pending == 0) {                                    \
       uv_want_endgame(loop, (uv_handle_t*)handle);                      \
     }                                                                   \
@@ -62,14 +62,14 @@
 
 #define uv__handle_closing(handle)                                      \
   do {                                                                  \
-    assert(!((handle)->flags & UV__HANDLE_CLOSING));                    \
+    assert(!((handle)->flags & UV_HANDLE_CLOSING));                     \
                                                                         \
-    if (!(((handle)->flags & UV__HANDLE_ACTIVE) &&                      \
-          ((handle)->flags & UV__HANDLE_REF)))                          \
+    if (!(((handle)->flags & UV_HANDLE_ACTIVE) &&                       \
+          ((handle)->flags & UV_HANDLE_REF)))                           \
       uv__active_handle_add((uv_handle_t*) (handle));                   \
                                                                         \
-    (handle)->flags |= UV__HANDLE_CLOSING;                              \
-    (handle)->flags &= ~UV__HANDLE_ACTIVE;                              \
+    (handle)->flags |= UV_HANDLE_CLOSING;                               \
+    (handle)->flags &= ~UV_HANDLE_ACTIVE;                               \
   } while (0)
 
 
@@ -126,7 +126,8 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
         break;
 
       case UV_TIMER:
-        uv_timer_endgame(loop, (uv_timer_t*) handle);
+        uv__timer_close((uv_timer_t*) handle);
+        uv__handle_close(handle);
         break;
 
       case UV_PREPARE:
@@ -164,10 +165,10 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
 
 INLINE static HANDLE uv__get_osfhandle(int fd)
 {
-  /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */
-  /* But  it also correctly checks the FD and returns INVALID_HANDLE_VALUE */
-  /* for invalid FDs in release builds (or if you let the assert continue).  */
-  /* So this wrapper function disables asserts when calling _get_osfhandle. */
+  /* _get_osfhandle() raises an assert in debug builds if the FD is invalid.
+   * But it also correctly checks the FD and returns INVALID_HANDLE_VALUE for
+   * invalid FDs in release builds (or if you let the assert continue). So this
+   * wrapper function disables asserts when calling _get_osfhandle. */
 
   HANDLE handle;
   UV_BEGIN_DISABLE_CRT_ASSERT();

+ 8 - 4
src/win/handle.c

@@ -59,15 +59,15 @@ uv_handle_type uv_guess_handle(uv_file file) {
 
 
 int uv_is_active(const uv_handle_t* handle) {
-  return (handle->flags & UV__HANDLE_ACTIVE) &&
-        !(handle->flags & UV__HANDLE_CLOSING);
+  return (handle->flags & UV_HANDLE_ACTIVE) &&
+        !(handle->flags & UV_HANDLE_CLOSING);
 }
 
 
 void uv_close(uv_handle_t* handle, uv_close_cb cb) {
   uv_loop_t* loop = handle->loop;
 
-  if (handle->flags & UV__HANDLE_CLOSING) {
+  if (handle->flags & UV_HANDLE_CLOSING) {
     assert(0);
     return;
   }
@@ -150,10 +150,14 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
 
 
 int uv_is_closing(const uv_handle_t* handle) {
-  return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED));
+  return !!(handle->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED));
 }
 
 
 uv_os_fd_t uv_get_osfhandle(int fd) {
   return uv__get_osfhandle(fd);
 }
+
+int uv_open_osfhandle(uv_os_fd_t os_fd) {
+  return _open_osfhandle((intptr_t) os_fd, 0);
+}

+ 24 - 90
src/win/internal.h

@@ -25,7 +25,7 @@
 #include "uv.h"
 #include "../uv-common.h"
 
-#include "tree.h"
+#include "uv/tree.h"
 #include "winapi.h"
 #include "winsock.h"
 
@@ -57,78 +57,20 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
 #define UV_END_DISABLE_CRT_ASSERT()
 #endif
 
-/*
- * Handles
- * (also see handle-inl.h)
- */
-
-/* Used by all handles. */
-#define UV_HANDLE_CLOSED                        0x00000002
-#define UV_HANDLE_ENDGAME_QUEUED                0x00000008
-
-/* uv-common.h: #define UV__HANDLE_CLOSING      0x00000001 */
-/* uv-common.h: #define UV__HANDLE_ACTIVE       0x00000040 */
-/* uv-common.h: #define UV__HANDLE_REF          0x00000020 */
-/* uv-common.h: #define UV_HANDLE_INTERNAL      0x00000080 */
-
-/* Used by streams and UDP handles. */
-#define UV_HANDLE_READING                       0x00000100
-#define UV_HANDLE_BOUND                         0x00000200
-#define UV_HANDLE_LISTENING                     0x00000800
-#define UV_HANDLE_CONNECTION                    0x00001000
-#define UV_HANDLE_READABLE                      0x00008000
-#define UV_HANDLE_WRITABLE                      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_BLOCKING_WRITES               0x00200000
-#define UV_HANDLE_CANCELLATION_PENDING          0x00400000
-
-/* Used by uv_tcp_t and uv_udp_t handles */
-#define UV_HANDLE_IPV6                          0x01000000
-
-/* Only used by uv_tcp_t handles. */
-#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
-#define UV_HANDLE_PIPE_READ_CANCELABLE          0x04000000
-
-/* Only used by uv_tty_t handles. */
-#define UV_HANDLE_TTY_READABLE                  0x01000000
-#define UV_HANDLE_TTY_RAW                       0x02000000
-#define UV_HANDLE_TTY_SAVED_POSITION            0x04000000
-#define UV_HANDLE_TTY_SAVED_ATTRIBUTES          0x08000000
-
-/* Only used by uv_poll_t handles. */
-#define UV_HANDLE_POLL_SLOW                     0x02000000
-
-
-/*
- * Requests: see req-inl.h
- */
-
-
-/*
- * Streams: see stream-inl.h
- */
-
-
 /*
  * TCP
  */
 
+typedef enum {
+  UV__IPC_SOCKET_XFER_NONE = 0,
+  UV__IPC_SOCKET_XFER_TCP_CONNECTION,
+  UV__IPC_SOCKET_XFER_TCP_SERVER
+} uv__ipc_socket_xfer_type_t;
+
 typedef struct {
   WSAPROTOCOL_INFOW socket_info;
-  int delayed_error;
-} uv__ipc_socket_info_ex;
+  uint32_t delayed_error;
+} uv__ipc_socket_xfer_info_t;
 
 int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
 int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
@@ -150,11 +92,13 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
 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, uv__ipc_socket_info_ex* socket_info_ex,
-    int tcp_connection);
-
-int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
-    LPWSAPROTOCOL_INFOW protocol_info);
+int uv__tcp_xfer_export(uv_tcp_t* handle,
+                        int pid,
+                        uv__ipc_socket_xfer_type_t* xfer_type,
+                        uv__ipc_socket_xfer_info_t* xfer_info);
+int uv__tcp_xfer_import(uv_tcp_t* tcp,
+                        uv__ipc_socket_xfer_type_t xfer_type,
+                        uv__ipc_socket_xfer_info_t* xfer_info);
 
 
 /*
@@ -178,14 +122,14 @@ 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);
 int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
     uv_read_cb read_cb);
-int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
-    const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
-int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
-    const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle,
-    uv_write_cb cb);
-void uv__pipe_pause_read(uv_pipe_t* handle);
-void uv__pipe_unpause_read(uv_pipe_t* handle);
-void uv__pipe_stop_read(uv_pipe_t* handle);
+void uv__pipe_read_stop(uv_pipe_t* handle);
+int uv__pipe_write(uv_loop_t* loop,
+                   uv_write_t* req,
+                   uv_pipe_t* handle,
+                   const uv_buf_t bufs[],
+                   size_t nbufs,
+                   uv_stream_t* send_handle,
+                   uv_write_cb cb);
 
 void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
     uv_req_t* req);
@@ -247,15 +191,6 @@ int 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__next_timeout(const uv_loop_t* loop);
-void uv_process_timers(uv_loop_t* loop);
-
-
 /*
  * Loop watchers
  */
@@ -332,7 +267,6 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
 void uv__util_init(void);
 
 uint64_t uv__hrtime(double scale);
-int uv_current_pid(void);
 __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
 int uv__getpwuid_r(uv_passwd_t* pwd);
 int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);

+ 1 - 1
src/win/loop-watcher.c

@@ -27,7 +27,7 @@
 
 
 void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
-  if (handle->flags & UV__HANDLE_CLOSING) {
+  if (handle->flags & UV_HANDLE_CLOSING) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     handle->flags |= UV_HANDLE_CLOSED;
     uv__handle_close(handle);

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 399 - 316
src/win/pipe.c


+ 27 - 28
src/win/poll.c

@@ -75,7 +75,7 @@ static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) {
 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;
+  int result;
 
   /* Find a yet unsubmitted req to submit. */
   if (handle->submitted_events_1 == 0) {
@@ -91,16 +91,16 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
     handle->mask_events_1 = handle->events;
     handle->mask_events_2 = 0;
   } else {
-    /* Just wait until there's an unsubmitted req. */
-    /* This will happen almost immediately as one of the 2 outstanding */
-    /* requests is about to return. When this happens, */
-    /* uv__fast_poll_process_poll_req will be called, and the pending */
-    /* events, if needed, will be processed in a subsequent request. */
+    /* Just wait until there's an unsubmitted req. This will happen almost
+     * immediately as one of the 2 outstanding requests is about to return.
+     * When this happens, uv__fast_poll_process_poll_req will be called, and
+     * the pending events, if needed, will be processed in a subsequent
+     * request. */
     return;
   }
 
-  /* Setting Exclusive to TRUE makes the other poll request return if there */
-  /* is any. */
+  /* 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;
@@ -136,7 +136,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
 
 static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
   AFD_POLL_INFO afd_poll_info;
-  DWORD result;
+  int result;
 
   afd_poll_info.Exclusive = TRUE;
   afd_poll_info.NumberOfHandles = 1;
@@ -218,7 +218,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
   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) &&
+  } 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);
@@ -228,7 +228,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_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(!(handle->flags & UV_HANDLE_CLOSING));
   assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
 
   handle->events = events;
@@ -257,8 +257,8 @@ static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
     uv_want_endgame(loop, (uv_handle_t*) handle);
     return 0;
   } else {
-    /* Cancel outstanding poll requests by executing another, unique poll */
-    /* request that forces the outstanding ones to return. */
+    /* Cancel outstanding poll requests by executing another, unique poll
+     * request that forces the outstanding ones to return. */
     return uv__fast_poll_cancel_poll_req(loop, handle);
   }
 }
@@ -316,9 +316,8 @@ static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
     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. */
+  /* 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);
@@ -357,8 +356,8 @@ static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
     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. */
+  /* 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;
 
@@ -462,7 +461,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
   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) &&
+  } 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);
@@ -472,7 +471,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_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(!(handle->flags & UV_HANDLE_CLOSING));
   assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
 
   handle->events = events;
@@ -522,10 +521,10 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
   if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
     return uv_translate_sys_error(WSAGetLastError());
 
-  /* 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. */
+/* 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
@@ -557,9 +556,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
     return uv_translate_sys_error(WSAGetLastError());
   }
 
-  /* 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. */
+  /* 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) {
@@ -634,7 +633,7 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
 
 
 void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
-  assert(handle->flags & UV__HANDLE_CLOSING);
+  assert(handle->flags & UV_HANDLE_CLOSING);
   assert(!(handle->flags & UV_HANDLE_CLOSED));
 
   assert(handle->submitted_events_1 == 0);

+ 30 - 29
src/win/process-stdio.c

@@ -103,12 +103,12 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
   DWORD client_access = 0;
   HANDLE child_pipe = INVALID_HANDLE_VALUE;
   int err;
+  int overlap;
 
   if (flags & UV_READABLE_PIPE) {
-    /* The server needs inbound access too, otherwise CreateNamedPipe() */
-    /* won't give us the FILE_READ_ATTRIBUTES permission. We need that to */
-    /* probe the state of the write buffer when we're trying to shutdown */
-    /* the pipe. */
+    /* The server needs inbound access too, otherwise CreateNamedPipe() won't
+     * give us the FILE_READ_ATTRIBUTES permission. We need that to probe the
+     * state of the write buffer when we're trying to shutdown the pipe. */
     server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
     client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
   }
@@ -131,12 +131,13 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
   sa.lpSecurityDescriptor = NULL;
   sa.bInheritHandle = TRUE;
 
+  overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE);
   child_pipe = CreateFileA(pipe_name,
                            client_access,
                            0,
                            &sa,
                            OPEN_EXISTING,
-                           server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0,
+                           overlap ? FILE_FLAG_OVERLAPPED : 0,
                            NULL);
   if (child_pipe == INVALID_HANDLE_VALUE) {
     err = GetLastError();
@@ -159,8 +160,8 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
   }
 #endif
 
-  /* Do a blocking ConnectNamedPipe.  This should not block because we have */
-  /* both ends of the pipe created. */
+  /* Do a blocking ConnectNamedPipe. This should not block because we have both
+   * ends of the pipe created. */
   if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
     if (GetLastError() != ERROR_PIPE_CONNECTED) {
       err = GetLastError();
@@ -194,11 +195,11 @@ static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
   HANDLE current_process;
 
 
-  /* _get_osfhandle will sometimes return -2 in case of an error. This seems */
-  /* to happen when fd <= 2 and the process' corresponding stdio handle is */
-  /* set to NULL. Unfortunately DuplicateHandle will happily duplicate */
-  /* (HANDLE) -2, so this situation goes unnoticed until someone tries to */
-  /* use the duplicate. Therefore we filter out known-invalid handles here. */
+  /* _get_osfhandle will sometimes return -2 in case of an error. This seems to
+   * happen when fd <= 2 and the process' corresponding stdio handle is set to
+   * NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so
+   * this situation goes unnoticed until someone tries to use the duplicate.
+   * Therefore we filter out known-invalid handles here. */
   if (handle == INVALID_HANDLE_VALUE ||
       handle == NULL ||
       handle == (HANDLE) -2) {
@@ -284,8 +285,8 @@ int uv__stdio_create(uv_loop_t* loop,
     return ERROR_OUTOFMEMORY;
   }
 
-  /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */
-  /* clean up on failure. */
+  /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean
+   * up on failure. */
   CHILD_STDIO_COUNT(buffer) = count;
   for (i = 0; i < count; i++) {
     CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
@@ -303,12 +304,12 @@ int uv__stdio_create(uv_loop_t* loop,
     switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
             UV_INHERIT_STREAM)) {
       case UV_IGNORE:
-        /* Starting a process with no stdin/stout/stderr can confuse it. */
-        /* So no matter what the user specified, we make sure the first */
-        /* three FDs are always open in their typical modes, e.g. stdin */
-        /* be readable and stdout/err should be writable. For FDs > 2, don't */
-        /* do anything - all handles in the stdio buffer are initialized with */
-        /* INVALID_HANDLE_VALUE, which should be okay. */
+        /* Starting a process with no stdin/stout/stderr can confuse it. So no
+         * matter what the user specified, we make sure the first three FDs are
+         * always open in their typical modes, e. g. stdin be readable and
+         * stdout/err should be writable. For FDs > 2, don't do anything - all
+         * handles in the stdio buffer are initialized with.
+         * INVALID_HANDLE_VALUE, which should be okay. */
         if (i <= 2) {
           DWORD access = (i == 0) ? FILE_GENERIC_READ :
                                     FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
@@ -323,14 +324,14 @@ int uv__stdio_create(uv_loop_t* loop,
         break;
 
       case UV_CREATE_PIPE: {
-        /* Create a pair of two connected pipe ends; one end is turned into */
-        /* an uv_pipe_t for use by the parent. The other one is given to */
-        /* the child. */
+        /* Create a pair of two connected pipe ends; one end is turned into an
+         * uv_pipe_t for use by the parent. The other one is given to the
+         * child. */
         uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
         HANDLE child_pipe = INVALID_HANDLE_VALUE;
 
-        /* Create a new, connected pipe pair. stdio[i].stream should point */
-        /* to an uninitialized, but not connected pipe handle. */
+        /* Create a new, connected pipe pair. stdio[i]. stream should point to
+         * an uninitialized, but not connected pipe handle. */
         assert(fdopt.data.stream->type == UV_NAMED_PIPE);
         assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
         assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
@@ -354,8 +355,8 @@ int uv__stdio_create(uv_loop_t* loop,
         /* Make an inheritable duplicate of the handle. */
         err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
         if (err) {
-          /* If fdopt.data.fd is not valid and fd fd <= 2, then ignore the */
-          /* error. */
+          /* If fdopt. data. fd is not valid and fd <= 2, then ignore the
+           * error. */
           if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
             CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
             CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
@@ -418,8 +419,8 @@ int uv__stdio_create(uv_loop_t* loop,
 
         if (stream_handle == NULL ||
             stream_handle == INVALID_HANDLE_VALUE) {
-          /* The handle is already closed, or not yet created, or the */
-          /* stream type is not supported. */
+          /* The handle is already closed, or not yet created, or the stream
+           * type is not supported. */
           err = ERROR_NOT_SUPPORTED;
           goto error;
         }

+ 40 - 30
src/win/process.c

@@ -360,8 +360,8 @@ static WCHAR* search_path(const WCHAR *file,
     return NULL;
   }
 
-  /* Find the start of the filename so we can split the directory from the */
-  /* name. */
+  /* Find the start of the filename so we can split the directory from the
+   * name. */
   for (file_name_start = (WCHAR*)file + file_len;
        file_name_start > file
            && file_name_start[-1] != L'\\'
@@ -556,8 +556,8 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
     arg_count++;
   }
 
-  /* Adjust for potential quotes. Also assume the worst-case scenario */
-  /* that every character needs escaping, so we need twice as much space. */
+  /* Adjust for potential quotes. Also assume the worst-case scenario that
+   * every character needs escaping, so we need twice as much space. */
   dst_len = dst_len * 2 + arg_count * 2;
 
   /* Allocate buffer for the final command line. */
@@ -739,7 +739,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
     }
   }
   *ptr_copy = NULL;
-  assert(env_len == ptr - dst_copy);
+  assert(env_len == (size_t) (ptr - dst_copy));
 
   /* sort our (UTF-16) copy */
   qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
@@ -799,7 +799,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
         var_size = GetEnvironmentVariableW(required_vars[i].wide,
                                            ptr,
                                            (int) (env_len - (ptr - dst)));
-        if (var_size != len-1) { /* race condition? */
+        if (var_size != (DWORD) (len - 1)) { /* TODO: handle race condition? */
           uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
         }
       }
@@ -815,7 +815,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
   }
 
   /* Terminate with an extra NULL. */
-  assert(env_len == (ptr - dst));
+  assert(env_len == (size_t) (ptr - dst));
   *ptr = L'\0';
 
   uv__free(dst_copy);
@@ -831,8 +831,13 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
  */
 static WCHAR* find_path(WCHAR *env) {
   for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
-    if (wcsncmp(env, L"PATH=", 5) == 0)
+    if ((env[0] == L'P' || env[0] == L'p') &&
+        (env[1] == L'A' || env[1] == L'a') &&
+        (env[2] == L'T' || env[2] == L't') &&
+        (env[3] == L'H' || env[3] == L'h') &&
+        (env[4] == L'=')) {
       return &env[5];
+    }
   }
 
   return NULL;
@@ -865,9 +870,9 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
   assert(handle->exit_cb_pending);
   handle->exit_cb_pending = 0;
 
-  /* If we're closing, don't call the exit callback. Just schedule a close */
-  /* callback now. */
-  if (handle->flags & UV__HANDLE_CLOSING) {
+  /* If we're closing, don't call the exit callback. Just schedule a close
+   * callback now. */
+  if (handle->flags & UV_HANDLE_CLOSING) {
     uv_want_endgame(loop, (uv_handle_t*) handle);
     return;
   }
@@ -878,14 +883,14 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
     handle->wait_handle = INVALID_HANDLE_VALUE;
   }
 
-  /* Set the handle to inactive: no callbacks will be made after the exit */
-  /* callback.*/
+  /* Set the handle to inactive: no callbacks will be made after the exit
+   * callback. */
   uv__handle_stop(handle);
 
   if (GetExitCodeProcess(handle->process_handle, &status)) {
     exit_code = status;
   } else {
-    /* Unable to to obtain the exit code. This should never happen. */
+    /* Unable to obtain the exit code. This should never happen. */
     exit_code = uv_translate_sys_error(GetLastError());
   }
 
@@ -900,8 +905,8 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
   uv__handle_closing(handle);
 
   if (handle->wait_handle != INVALID_HANDLE_VALUE) {
-    /* This blocks until either the wait was cancelled, or the callback has */
-    /* completed. */
+    /* This blocks until either the wait was cancelled, or the callback has
+     * completed. */
     BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
     if (!r) {
       /* This should never happen, and if it happens, we can't recover... */
@@ -919,7 +924,7 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
 
 void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
   assert(!handle->exit_cb_pending);
-  assert(handle->flags & UV__HANDLE_CLOSING);
+  assert(handle->flags & UV_HANDLE_CLOSING);
   assert(!(handle->flags & UV_HANDLE_CLOSED));
 
   /* Clean-up the process handle. */
@@ -959,6 +964,8 @@ int uv_spawn(uv_loop_t* loop,
                               UV_PROCESS_SETGID |
                               UV_PROCESS_SETUID |
                               UV_PROCESS_WINDOWS_HIDE |
+                              UV_PROCESS_WINDOWS_HIDE_CONSOLE |
+                              UV_PROCESS_WINDOWS_HIDE_GUI |
                               UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
 
   err = uv_utf8_to_utf16_alloc(options->file, &application);
@@ -1060,7 +1067,8 @@ int uv_spawn(uv_loop_t* loop,
 
   process_flags = CREATE_UNICODE_ENVIRONMENT;
 
-  if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
+  if ((options->flags & UV_PROCESS_WINDOWS_HIDE_CONSOLE) ||
+      (options->flags & UV_PROCESS_WINDOWS_HIDE)) {
     /* Avoid creating console window if stdio is not inherited. */
     for (i = 0; i < options->stdio_count; i++) {
       if (options->stdio[i].flags & UV_INHERIT_FD)
@@ -1068,7 +1076,9 @@ int uv_spawn(uv_loop_t* loop,
       if (i == options->stdio_count - 1)
         process_flags |= CREATE_NO_WINDOW;
     }
-
+  }
+  if ((options->flags & UV_PROCESS_WINDOWS_HIDE_GUI) ||
+      (options->flags & UV_PROCESS_WINDOWS_HIDE)) {
     /* Use SW_HIDE to avoid any potential process window. */
     startup.wShowWindow = SW_HIDE;
   } else {
@@ -1104,14 +1114,13 @@ int uv_spawn(uv_loop_t* loop,
     goto done;
   }
 
-  /* Spawn succeeded */
-  /* Beyond this point, failure is reported asynchronously. */
+  /* Spawn succeeded. Beyond this point, failure is reported asynchronously. */
 
   process->process_handle = info.hProcess;
   process->pid = info.dwProcessId;
 
-  /* If the process isn't spawned as detached, assign to the global job */
-  /* object so windows will kill it when the parent process dies. */
+  /* If the process isn't spawned as detached, assign to the global job object
+   * so windows will kill it when the parent process dies. */
   if (!(options->flags & UV_PROCESS_DETACHED)) {
     uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
 
@@ -1138,7 +1147,8 @@ int uv_spawn(uv_loop_t* loop,
     if (fdopt->flags & UV_CREATE_PIPE &&
         fdopt->data.stream->type == UV_NAMED_PIPE &&
         ((uv_pipe_t*) fdopt->data.stream)->ipc) {
-      ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId;
+      ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_remote_pid =
+          info.dwProcessId;
     }
   }
 
@@ -1154,8 +1164,8 @@ int uv_spawn(uv_loop_t* loop,
 
   assert(!err);
 
-  /* Make the handle active. It will remain active until the exit callback */
-  /* is made or the handle is closed, whichever happens first. */
+  /* Make the handle active. It will remain active until the exit callback is
+   * made or the handle is closed, whichever happens first. */
   uv__handle_start(process);
 
   /* Cleanup, whether we succeeded or failed. */
@@ -1186,16 +1196,16 @@ static int uv__kill(HANDLE process_handle, int signum) {
     case SIGTERM:
     case SIGKILL:
     case SIGINT: {
-      /* Unconditionally terminate the process. On Windows, killed processes */
-      /* normally return 1. */
+      /* Unconditionally terminate the process. On Windows, killed processes
+       * normally return 1. */
       DWORD status;
       int err;
 
       if (TerminateProcess(process_handle, 1))
         return 0;
 
-      /* If the process already exited before TerminateProcess was called, */
-      /* TerminateProcess will fail with ERROR_ACCESS_DENIED. */
+      /* If the process already exited before TerminateProcess was called,.
+       * TerminateProcess will fail with ERROR_ACCESS_DENIED. */
       err = GetLastError();
       if (err == ERROR_ACCESS_DENIED &&
           GetExitCodeProcess(process_handle, &status) &&

+ 0 - 25
src/win/req.c

@@ -1,25 +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 <assert.h>
-
-#include "uv.h"
-#include "internal.h"

+ 25 - 25
src/win/signal.c

@@ -47,13 +47,13 @@ void uv_signals_init(void) {
 
 
 static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
-  /* Compare signums first so all watchers with the same signnum end up */
-  /* adjacent. */
+  /* Compare signums first so all watchers with the same signnum end up
+   * adjacent. */
   if (w1->signum < w2->signum) return -1;
   if (w1->signum > w2->signum) return 1;
 
-  /* Sort by loop pointer, so we can easily look up the first item after */
-  /* { .signum = x, .loop = NULL } */
+  /* Sort by loop pointer, so we can easily look up the first item after
+   * { .signum = x, .loop = NULL }. */
   if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
   if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
 
@@ -90,7 +90,7 @@ int uv__signal_dispatch(int signum) {
     unsigned long previous = InterlockedExchange(
             (volatile LONG*) &handle->pending_signum, signum);
 
-    if (handle->flags & UV__SIGNAL_ONE_SHOT_DISPATCHED)
+    if (handle->flags & UV_SIGNAL_ONE_SHOT_DISPATCHED)
       continue;
 
     if (!previous) {
@@ -98,8 +98,8 @@ int uv__signal_dispatch(int signum) {
     }
 
     dispatched = 1;
-    if (handle->flags & UV__SIGNAL_ONE_SHOT)
-      handle->flags |= UV__SIGNAL_ONE_SHOT_DISPATCHED;
+    if (handle->flags & UV_SIGNAL_ONE_SHOT)
+      handle->flags |= UV_SIGNAL_ONE_SHOT_DISPATCHED;
   }
 
   LeaveCriticalSection(&uv__signal_lock);
@@ -118,10 +118,10 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) {
 
     case CTRL_CLOSE_EVENT:
       if (uv__signal_dispatch(SIGHUP)) {
-        /* Windows will terminate the process after the control handler */
-        /* returns. After that it will just terminate our process. Therefore */
-        /* block the signal handler so the main loop has some time to pick */
-        /* up the signal and do something for a few seconds. */
+        /* Windows will terminate the process after the control handler
+         * returns. After that it will just terminate our process. Therefore
+         * block the signal handler so the main loop has some time to pick up
+         * the signal and do something for a few seconds. */
         Sleep(INFINITE);
         return TRUE;
       }
@@ -129,8 +129,8 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) {
 
     case CTRL_LOGOFF_EVENT:
     case CTRL_SHUTDOWN_EVENT:
-      /* These signals are only sent to services. Services have their own */
-      /* notification mechanism, so there's no point in handling these. */
+      /* These signals are only sent to services. Services have their own
+       * notification mechanism, so there's no point in handling these. */
 
     default:
       /* We don't handle these. */
@@ -190,13 +190,13 @@ int uv__signal_start(uv_signal_t* handle,
                             int signum,
                             int oneshot) {
   /* Test for invalid signal values. */
-  if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG))
+  if (signum <= 0 || signum >= NSIG)
     return UV_EINVAL;
 
-  /* Short circuit: if the signal watcher is already watching {signum} don't */
-  /* go through the process of deregistering and registering the handler. */
-  /* Additionally, this avoids pending signals getting lost in the (small) */
-  /* time frame that handle->signum == 0. */
+  /* Short circuit: if the signal watcher is already watching {signum} don't go
+   * through the process of deregistering and registering the handler.
+   * Additionally, this avoids pending signals getting lost in the (small) time
+   * frame that handle->signum == 0. */
   if (signum == handle->signum) {
     handle->signal_cb = signal_cb;
     return 0;
@@ -213,7 +213,7 @@ int uv__signal_start(uv_signal_t* handle,
 
   handle->signum = signum;
   if (oneshot)
-    handle->flags |= UV__SIGNAL_ONE_SHOT;
+    handle->flags |= UV_SIGNAL_ONE_SHOT;
 
   RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
 
@@ -237,16 +237,16 @@ void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
           (volatile LONG*) &handle->pending_signum, 0);
   assert(dispatched_signum != 0);
 
-  /* Check if the pending signal equals the signum that we are watching for. */
-  /* These can get out of sync when the handler is stopped and restarted */
-  /* while the signal_req is pending. */
+  /* Check if the pending signal equals the signum that we are watching for.
+   * These can get out of sync when the handler is stopped and restarted while
+   * the signal_req is pending. */
   if (dispatched_signum == handle->signum)
     handle->signal_cb(handle, dispatched_signum);
 
-  if (handle->flags & UV__SIGNAL_ONE_SHOT)
+  if (handle->flags & UV_SIGNAL_ONE_SHOT)
     uv_signal_stop(handle);
 
-  if (handle->flags & UV__HANDLE_CLOSING) {
+  if (handle->flags & UV_HANDLE_CLOSING) {
     /* When it is closing, it must be stopped at this point. */
     assert(handle->signum == 0);
     uv_want_endgame(loop, (uv_handle_t*) handle);
@@ -265,7 +265,7 @@ void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
 
 
 void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
-  assert(handle->flags & UV__HANDLE_CLOSING);
+  assert(handle->flags & UV_HANDLE_CLOSING);
   assert(!(handle->flags & UV_HANDLE_CLOSED));
 
   assert(handle->signum == 0);

+ 14 - 22
src/win/stream.c

@@ -105,12 +105,10 @@ int uv_read_stop(uv_stream_t* handle) {
   err = 0;
   if (handle->type == UV_TTY) {
     err = uv_tty_read_stop((uv_tty_t*) handle);
+  } else if (handle->type == UV_NAMED_PIPE) {
+    uv__pipe_read_stop((uv_pipe_t*) handle);
   } else {
-    if (handle->type == UV_NAMED_PIPE) {
-      uv__pipe_stop_read((uv_pipe_t*) handle);
-    } else {
-      handle->flags &= ~UV_HANDLE_READING;
-    }
+    handle->flags &= ~UV_HANDLE_READING;
     DECREASE_ACTIVE_COUNT(handle->loop, handle);
   }
 
@@ -136,7 +134,8 @@ int uv_write(uv_write_t* req,
       err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb);
       break;
     case UV_NAMED_PIPE:
-      err = uv_pipe_write(loop, req, (uv_pipe_t*) handle, bufs, nbufs, cb);
+      err = uv__pipe_write(
+          loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb);
       break;
     case UV_TTY:
       err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
@@ -158,25 +157,18 @@ int uv_write2(uv_write_t* req,
   uv_loop_t* loop = handle->loop;
   int err;
 
-  if (!(handle->flags & UV_HANDLE_WRITABLE)) {
-    return UV_EPIPE;
+  if (send_handle == NULL) {
+    return uv_write(req, handle, bufs, nbufs, cb);
   }
 
-  err = ERROR_INVALID_PARAMETER;
-  switch (handle->type) {
-    case UV_NAMED_PIPE:
-      err = uv_pipe_write2(loop,
-                           req,
-                           (uv_pipe_t*) handle,
-                           bufs,
-                           nbufs,
-                           send_handle,
-                           cb);
-      break;
-    default:
-      assert(0);
+  if (handle->type != UV_NAMED_PIPE || !((uv_pipe_t*) handle)->ipc) {
+    return UV_EINVAL;
+  } else if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+    return UV_EPIPE;
   }
 
+  err = uv__pipe_write(
+      loop, req, (uv_pipe_t*) handle, bufs, nbufs, send_handle, cb);
   return uv_translate_sys_error(err);
 }
 
@@ -184,7 +176,7 @@ int uv_write2(uv_write_t* req,
 int uv_try_write(uv_stream_t* stream,
                  const uv_buf_t bufs[],
                  unsigned int nbufs) {
-  if (stream->flags & UV__HANDLE_CLOSING)
+  if (stream->flags & UV_HANDLE_CLOSING)
     return UV_EBADF;
   if (!(stream->flags & UV_HANDLE_WRITABLE))
     return UV_EPIPE;

+ 106 - 107
src/win/tcp.c

@@ -99,8 +99,8 @@ static int uv_tcp_set_socket(uv_loop_t* loop,
   if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0))
     return GetLastError();
 
-  /* Associate it with the I/O completion port. */
-  /* Use uv_handle_t pointer as completion key. */
+  /* Associate it with the I/O completion port. Use uv_handle_t pointer as
+   * completion key. */
   if (CreateIoCompletionPort((HANDLE)socket,
                              loop->iocp,
                              (ULONG_PTR)socket,
@@ -118,15 +118,12 @@ static int uv_tcp_set_socket(uv_loop_t* loop,
     non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4;
   }
 
-  if (pSetFileCompletionNotificationModes &&
-      !(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) {
-    if (pSetFileCompletionNotificationModes((HANDLE) socket,
-        FILE_SKIP_SET_EVENT_ON_HANDLE |
-        FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
-      handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
-    } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
+  if (!(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) {
+    UCHAR sfcnm_flags =
+        FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
+    if (!SetFileCompletionNotificationModes((HANDLE) socket, sfcnm_flags))
       return GetLastError();
-    }
+    handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
   }
 
   if (handle->flags & UV_HANDLE_TCP_NODELAY) {
@@ -220,7 +217,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
     UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
 
     err = 0;
-    if (handle->flags & UV__HANDLE_CLOSING) {
+    if (handle->flags & UV_HANDLE_CLOSING) {
       err = ERROR_OPERATION_ABORTED;
     } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
       err = WSAGetLastError();
@@ -236,7 +233,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
     return;
   }
 
-  if (handle->flags & UV__HANDLE_CLOSING &&
+  if (handle->flags & UV_HANDLE_CLOSING &&
       handle->reqs_pending == 0) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
 
@@ -326,9 +323,9 @@ static int uv_tcp_try_bind(uv_tcp_t* handle,
 
     on = (flags & UV_TCP_IPV6ONLY) != 0;
 
-    /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
-    /* available, or when run on XP/2003 which have no support for dualstack */
-    /* sockets. For now we're silently ignoring the error. */
+    /* TODO: how to handle errors? This may fail if there is no ipv4 stack
+     * available, or when run on XP/2003 which have no support for dualstack
+     * sockets. For now we're silently ignoring the error. */
     setsockopt(handle->socket,
                IPPROTO_IPV6,
                IPV6_V6ONLY,
@@ -626,9 +623,9 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
       uv_tcp_queue_accept(handle, req);
     }
 
-    /* Initialize other unused requests too, because uv_tcp_endgame */
-    /* doesn't know how how many requests were initialized, so it will */
-    /* try to clean up {uv_simultaneous_server_accepts} requests. */
+    /* Initialize other unused requests too, because uv_tcp_endgame doesn't
+     * know how many requests were initialized, so it will try to clean up
+     * {uv_simultaneous_server_accepts} requests. */
     for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) {
       req = &handle->tcp.serv.accept_reqs[i];
       UV_REQ_INIT(req, UV_ACCEPT);
@@ -683,7 +680,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
   req->next_pending = NULL;
   req->accept_socket = INVALID_SOCKET;
 
-  if (!(server->flags & UV__HANDLE_CLOSING)) {
+  if (!(server->flags & UV_HANDLE_CLOSING)) {
     /* Check if we're in a middle of changing the number of pending accepts. */
     if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
       uv_tcp_queue_accept(server, req);
@@ -721,8 +718,8 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_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. */
+  /* If reading was stopped and then started again, there could still be a read
+   * request pending. */
   if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
     if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
         !handle->read_req.event_handle) {
@@ -948,6 +945,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
     uv_req_t* req) {
   DWORD bytes, flags, err;
   uv_buf_t buf;
+  int count;
 
   assert(handle->type == UV_TCP);
 
@@ -965,8 +963,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
       err = GET_REQ_SOCK_ERROR(req);
 
       if (err == WSAECONNABORTED) {
-        /*
-         * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
+        /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
          */
         err = WSAECONNRESET;
       }
@@ -1003,7 +1000,8 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
     }
 
     /* Do nonblocking reads until the buffer is empty */
-    while (handle->flags & UV_HANDLE_READING) {
+    count = 32;
+    while ((handle->flags & UV_HANDLE_READING) && (count-- > 0)) {
       buf = uv_buf_init(NULL, 0);
       handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
       if (buf.base == NULL || buf.len == 0) {
@@ -1046,8 +1044,8 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
           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. */
             err = WSAECONNRESET;
           }
 
@@ -1119,10 +1117,9 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
 
   assert(handle->type == UV_TCP);
 
-  /* If handle->accepted_socket is not a valid socket, then */
-  /* uv_queue_accept must have failed. This is a serious error. We stop */
-  /* accepting connections and report this error to the connection */
-  /* callback. */
+  /* If handle->accepted_socket is not a valid socket, then uv_queue_accept
+   * must have failed. This is a serious error. We stop accepting connections
+   * and report this error to the connection callback. */
   if (req->accept_socket == INVALID_SOCKET) {
     if (handle->flags & UV_HANDLE_LISTENING) {
       handle->flags &= ~UV_HANDLE_LISTENING;
@@ -1147,9 +1144,9 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
       handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
     }
   } else {
-    /* Error related to accepted socket is ignored because the server */
-    /* socket may still be healthy. If the server socket is broken */
-    /* uv_queue_accept will detect it. */
+    /* Error related to accepted socket is ignored because the server socket
+     * may still be healthy. If the server socket is broken uv_queue_accept
+     * will detect it. */
     closesocket(req->accept_socket);
     req->accept_socket = INVALID_SOCKET;
     if (handle->flags & UV_HANDLE_LISTENING) {
@@ -1171,7 +1168,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
 
   err = 0;
   if (REQ_SUCCESS(req)) {
-    if (handle->flags & UV__HANDLE_CLOSING) {
+    if (handle->flags & UV_HANDLE_CLOSING) {
       /* use UV_ECANCELED for consistency with Unix */
       err = ERROR_OPERATION_ABORTED;
     } else if (setsockopt(handle->socket,
@@ -1194,40 +1191,76 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
 }
 
 
-int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
-    int tcp_connection) {
+int uv__tcp_xfer_export(uv_tcp_t* handle,
+                        int target_pid,
+                        uv__ipc_socket_xfer_type_t* xfer_type,
+                        uv__ipc_socket_xfer_info_t* xfer_info) {
+  if (handle->flags & UV_HANDLE_CONNECTION) {
+    *xfer_type = UV__IPC_SOCKET_XFER_TCP_CONNECTION;
+  } else {
+    *xfer_type = UV__IPC_SOCKET_XFER_TCP_SERVER;
+    /* 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. Thus, before sharing the socket with another process,
+     * we call listen here in the parent process. */
+    if (!(handle->flags & UV_HANDLE_LISTENING)) {
+      if (!(handle->flags & UV_HANDLE_BOUND)) {
+        return ERROR_NOT_SUPPORTED;
+      }
+      if (handle->delayed_error == 0 &&
+          listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
+        handle->delayed_error = WSAGetLastError();
+      }
+    }
+  }
+
+  if (WSADuplicateSocketW(handle->socket, target_pid, &xfer_info->socket_info))
+    return WSAGetLastError();
+  xfer_info->delayed_error = handle->delayed_error;
+
+  /* Mark the local copy of the handle as 'shared' so we behave in a way that's
+   * friendly to the process(es) that we share the socket with. */
+  handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
+
+  return 0;
+}
+
+
+int uv__tcp_xfer_import(uv_tcp_t* tcp,
+                        uv__ipc_socket_xfer_type_t xfer_type,
+                        uv__ipc_socket_xfer_info_t* xfer_info) {
   int err;
-  SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO,
-                             FROM_PROTOCOL_INFO,
-                             FROM_PROTOCOL_INFO,
-                             &socket_info_ex->socket_info,
-                             0,
-                             WSA_FLAG_OVERLAPPED);
+  SOCKET socket;
+
+  assert(xfer_type == UV__IPC_SOCKET_XFER_TCP_SERVER ||
+         xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION);
+
+  socket = WSASocketW(FROM_PROTOCOL_INFO,
+                      FROM_PROTOCOL_INFO,
+                      FROM_PROTOCOL_INFO,
+                      &xfer_info->socket_info,
+                      0,
+                      WSA_FLAG_OVERLAPPED);
 
   if (socket == INVALID_SOCKET) {
     return WSAGetLastError();
   }
 
-  err = uv_tcp_set_socket(tcp->loop,
-                          tcp,
-                          socket,
-                          socket_info_ex->socket_info.iAddressFamily,
-                          1);
+  err = uv_tcp_set_socket(
+      tcp->loop, tcp, socket, xfer_info->socket_info.iAddressFamily, 1);
   if (err) {
     closesocket(socket);
     return err;
   }
 
-  if (tcp_connection) {
+  tcp->delayed_error = xfer_info->delayed_error;
+  tcp->flags |= UV_HANDLE_BOUND | UV_HANDLE_SHARED_TCP_SOCKET;
+
+  if (xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION) {
     uv_connection_init((uv_stream_t*)tcp);
     tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
   }
 
-  tcp->flags |= UV_HANDLE_BOUND;
-  tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
-
-  tcp->delayed_error = socket_info_ex->delayed_error;
-
   tcp->loop->active_tcp_streams++;
   return 0;
 }
@@ -1273,39 +1306,6 @@ 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
-     * with another process, we call listen here in the parent process.
-     */
-
-    if (!(handle->flags & UV_HANDLE_LISTENING)) {
-      if (!(handle->flags & UV_HANDLE_BOUND)) {
-        return ERROR_INVALID_PARAMETER;
-      }
-
-      if (!(handle->delayed_error)) {
-        if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
-          handle->delayed_error = WSAGetLastError();
-        }
-      }
-    }
-  }
-
-  if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) {
-    return WSAGetLastError();
-  }
-
-  handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
-
-  return 0;
-}
-
-
 int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
   if (handle->flags & UV_HANDLE_CONNECTION) {
     return UV_EINVAL;
@@ -1346,8 +1346,8 @@ static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
   non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 :
                                                 uv_tcp_non_ifs_lsp_ipv4;
 
-  /* If there are non-ifs LSPs then try to obtain a base handle for the */
-  /* socket. This will always fail on Windows XP/3k. */
+  /* If there are non-ifs LSPs then try to obtain a base handle for the socket.
+   * This will always fail on Windows XP/3k. */
   if (non_ifs_lsp) {
     DWORD bytes;
     if (WSAIoctl(socket,
@@ -1379,38 +1379,37 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
   int close_socket = 1;
 
   if (tcp->flags & UV_HANDLE_READ_PENDING) {
-    /* In order for winsock to do a graceful close there must not be any */
-    /* any pending reads, or the socket must be shut down for writing */
+    /* In order for winsock to do a graceful close there must not be any any
+     * pending reads, or the socket must be shut down for writing */
     if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
       /* Just do shutdown on non-shared sockets, which ensures graceful close. */
       shutdown(tcp->socket, SD_SEND);
 
     } else if (uv_tcp_try_cancel_io(tcp) == 0) {
-      /* In case of a shared socket, we try to cancel all outstanding I/O, */
-      /* If that works, don't close the socket yet - wait for the read req to */
-      /* return and close the socket in uv_tcp_endgame. */
+      /* In case of a shared socket, we try to cancel all outstanding I/O,. If
+       * that works, don't close the socket yet - wait for the read req to
+       * return and close the socket in uv_tcp_endgame. */
       close_socket = 0;
 
     } else {
-      /* When cancelling isn't possible - which could happen when an LSP is */
-      /* present on an old Windows version, we will have to close the socket */
-      /* with a read pending. That is not nice because trailing sent bytes */
-      /* may not make it to the other side. */
+      /* When cancelling isn't possible - which could happen when an LSP is
+       * present on an old Windows version, we will have to close the socket
+       * with a read pending. That is not nice because trailing sent bytes may
+       * not make it to the other side. */
     }
 
   } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
              tcp->tcp.serv.accept_reqs != NULL) {
-    /* Under normal circumstances closesocket() will ensure that all pending */
-    /* accept reqs are canceled. However, when the socket is shared the */
-    /* presence of another reference to the socket in another process will */
-    /* keep the accept reqs going, so we have to ensure that these are */
-    /* canceled. */
+    /* Under normal circumstances closesocket() will ensure that all pending
+     * accept reqs are canceled. However, when the socket is shared the
+     * presence of another reference to the socket in another process will keep
+     * the accept reqs going, so we have to ensure that these are canceled. */
     if (uv_tcp_try_cancel_io(tcp) != 0) {
-      /* When cancellation is not possible, there is another option: we can */
-      /* close the incoming sockets, which will also cancel the accept */
-      /* operations. However this is not cool because we might inadvertently */
-      /* close a socket that just accepted a new connection, which will */
-      /* cause the connection to be aborted. */
+      /* When cancellation is not possible, there is another option: we can
+       * close the incoming sockets, which will also cancel the accept
+       * operations. However this is not cool because we might inadvertently
+       * close a socket that just accepted a new connection, which will cause
+       * the connection to be aborted. */
       unsigned int i;
       for (i = 0; i < uv_simultaneous_server_accepts; i++) {
         uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];

+ 19 - 227
src/win/thread.c

@@ -23,29 +23,15 @@
 #include <limits.h>
 #include <stdlib.h>
 
+#if defined(__MINGW64_VERSION_MAJOR)
+/* MemoryBarrier expands to __mm_mfence in some cases (x86+sse2), which may
+ * require this header in some versions of mingw64. */
+#include <intrin.h>
+#endif
+
 #include "uv.h"
 #include "internal.h"
 
-
-#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL)
-
-static int uv_cond_fallback_init(uv_cond_t* cond);
-static void uv_cond_fallback_destroy(uv_cond_t* cond);
-static void uv_cond_fallback_signal(uv_cond_t* cond);
-static void uv_cond_fallback_broadcast(uv_cond_t* cond);
-static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex);
-static int uv_cond_fallback_timedwait(uv_cond_t* cond,
-    uv_mutex_t* mutex, uint64_t timeout);
-
-static int uv_cond_condvar_init(uv_cond_t* cond);
-static void uv_cond_condvar_destroy(uv_cond_t* cond);
-static void uv_cond_condvar_signal(uv_cond_t* cond);
-static void uv_cond_condvar_broadcast(uv_cond_t* cond);
-static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex);
-static int uv_cond_condvar_timedwait(uv_cond_t* cond,
-    uv_mutex_t* mutex, uint64_t timeout);
-
-
 static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
   DWORD result;
   HANDLE existing_event, created_event;
@@ -69,8 +55,8 @@ static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
     guard->ran = 1;
 
   } else {
-    /* We lost the race. Destroy the event we created and wait for the */
-    /* existing one to become signaled. */
+    /* We lost the race. Destroy the event we created and wait for the existing
+     * one to become signaled. */
     CloseHandle(created_event);
     result = WaitForSingleObject(existing_event, INFINITE);
     assert(result == WAIT_OBJECT_0);
@@ -138,7 +124,7 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
   ctx->arg = arg;
 
   /* Create the thread in suspended state so we have a chance to pass
-   * its own creation handle to it */   
+   * its own creation handle to it */
   thread = (HANDLE) _beginthreadex(NULL,
                                    0,
                                    uv__thread_start,
@@ -377,220 +363,35 @@ int uv_sem_trywait(uv_sem_t* sem) {
 }
 
 
-/* This condition variable implementation is based on the SetEvent solution
- * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
- * We could not use the SignalObjectAndWait solution (section 3.4) because
- * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and
- * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs.
- */
-
-static int uv_cond_fallback_init(uv_cond_t* cond) {
-  int err;
-
-  /* Initialize the count to 0. */
-  cond->fallback.waiters_count = 0;
-
-  InitializeCriticalSection(&cond->fallback.waiters_count_lock);
-
-  /* Create an auto-reset event. */
-  cond->fallback.signal_event = CreateEvent(NULL,  /* no security */
-                                            FALSE, /* auto-reset event */
-                                            FALSE, /* non-signaled initially */
-                                            NULL); /* unnamed */
-  if (!cond->fallback.signal_event) {
-    err = GetLastError();
-    goto error2;
-  }
-
-  /* Create a manual-reset event. */
-  cond->fallback.broadcast_event = CreateEvent(NULL,  /* no security */
-                                               TRUE,  /* manual-reset */
-                                               FALSE, /* non-signaled */
-                                               NULL); /* unnamed */
-  if (!cond->fallback.broadcast_event) {
-    err = GetLastError();
-    goto error;
-  }
-
-  return 0;
-
-error:
-  CloseHandle(cond->fallback.signal_event);
-error2:
-  DeleteCriticalSection(&cond->fallback.waiters_count_lock);
-  return uv_translate_sys_error(err);
-}
-
-
-static int uv_cond_condvar_init(uv_cond_t* cond) {
-  pInitializeConditionVariable(&cond->cond_var);
-  return 0;
-}
-
-
 int uv_cond_init(uv_cond_t* cond) {
-  uv__once_init();
-
-  if (HAVE_CONDVAR_API())
-    return uv_cond_condvar_init(cond);
-  else
-    return uv_cond_fallback_init(cond);
-}
-
-
-static void uv_cond_fallback_destroy(uv_cond_t* cond) {
-  if (!CloseHandle(cond->fallback.broadcast_event))
-    abort();
-  if (!CloseHandle(cond->fallback.signal_event))
-    abort();
-  DeleteCriticalSection(&cond->fallback.waiters_count_lock);
-}
-
-
-static void uv_cond_condvar_destroy(uv_cond_t* cond) {
-  /* nothing to do */
+  InitializeConditionVariable(&cond->cond_var);
+  return 0;
 }
 
 
 void uv_cond_destroy(uv_cond_t* cond) {
-  if (HAVE_CONDVAR_API())
-    uv_cond_condvar_destroy(cond);
-  else
-    uv_cond_fallback_destroy(cond);
-}
-
-
-static void uv_cond_fallback_signal(uv_cond_t* cond) {
-  int have_waiters;
-
-  /* Avoid race conditions. */
-  EnterCriticalSection(&cond->fallback.waiters_count_lock);
-  have_waiters = cond->fallback.waiters_count > 0;
-  LeaveCriticalSection(&cond->fallback.waiters_count_lock);
-
-  if (have_waiters)
-    SetEvent(cond->fallback.signal_event);
-}
-
-
-static void uv_cond_condvar_signal(uv_cond_t* cond) {
-  pWakeConditionVariable(&cond->cond_var);
+  /* nothing to do */
+  (void) &cond;
 }
 
 
 void uv_cond_signal(uv_cond_t* cond) {
-  if (HAVE_CONDVAR_API())
-    uv_cond_condvar_signal(cond);
-  else
-    uv_cond_fallback_signal(cond);
-}
-
-
-static void uv_cond_fallback_broadcast(uv_cond_t* cond) {
-  int have_waiters;
-
-  /* Avoid race conditions. */
-  EnterCriticalSection(&cond->fallback.waiters_count_lock);
-  have_waiters = cond->fallback.waiters_count > 0;
-  LeaveCriticalSection(&cond->fallback.waiters_count_lock);
-
-  if (have_waiters)
-    SetEvent(cond->fallback.broadcast_event);
-}
-
-
-static void uv_cond_condvar_broadcast(uv_cond_t* cond) {
-  pWakeAllConditionVariable(&cond->cond_var);
+  WakeConditionVariable(&cond->cond_var);
 }
 
 
 void uv_cond_broadcast(uv_cond_t* cond) {
-  if (HAVE_CONDVAR_API())
-    uv_cond_condvar_broadcast(cond);
-  else
-    uv_cond_fallback_broadcast(cond);
-}
-
-
-static int uv_cond_wait_helper(uv_cond_t* cond, uv_mutex_t* mutex,
-    DWORD dwMilliseconds) {
-  DWORD result;
-  int last_waiter;
-  HANDLE handles[2] = {
-    cond->fallback.signal_event,
-    cond->fallback.broadcast_event
-  };
-
-  /* Avoid race conditions. */
-  EnterCriticalSection(&cond->fallback.waiters_count_lock);
-  cond->fallback.waiters_count++;
-  LeaveCriticalSection(&cond->fallback.waiters_count_lock);
-
-  /* It's ok to release the <mutex> here since Win32 manual-reset events */
-  /* maintain state when used with <SetEvent>. This avoids the "lost wakeup" */
-  /* bug. */
-  uv_mutex_unlock(mutex);
-
-  /* Wait for either event to become signaled due to <uv_cond_signal> being */
-  /* called or <uv_cond_broadcast> being called. */
-  result = WaitForMultipleObjects(2, handles, FALSE, dwMilliseconds);
-
-  EnterCriticalSection(&cond->fallback.waiters_count_lock);
-  cond->fallback.waiters_count--;
-  last_waiter = result == WAIT_OBJECT_0 + 1
-      && cond->fallback.waiters_count == 0;
-  LeaveCriticalSection(&cond->fallback.waiters_count_lock);
-
-  /* Some thread called <pthread_cond_broadcast>. */
-  if (last_waiter) {
-    /* We're the last waiter to be notified or to stop waiting, so reset the */
-    /* the manual-reset event. */
-    ResetEvent(cond->fallback.broadcast_event);
-  }
-
-  /* Reacquire the <mutex>. */
-  uv_mutex_lock(mutex);
-
-  if (result == WAIT_OBJECT_0 || result == WAIT_OBJECT_0 + 1)
-    return 0;
-
-  if (result == WAIT_TIMEOUT)
-    return UV_ETIMEDOUT;
-
-  abort();
-  return -1; /* Satisfy the compiler. */
-}
-
-
-static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
-  if (uv_cond_wait_helper(cond, mutex, INFINITE))
-    abort();
-}
-
-
-static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
-  if (!pSleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
-    abort();
+  WakeAllConditionVariable(&cond->cond_var);
 }
 
 
 void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
-  if (HAVE_CONDVAR_API())
-    uv_cond_condvar_wait(cond, mutex);
-  else
-    uv_cond_fallback_wait(cond, mutex);
-}
-
-
-static int uv_cond_fallback_timedwait(uv_cond_t* cond,
-    uv_mutex_t* mutex, uint64_t timeout) {
-  return uv_cond_wait_helper(cond, mutex, (DWORD)(timeout / 1e6));
+  if (!SleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
+    abort();
 }
 
-
-static int uv_cond_condvar_timedwait(uv_cond_t* cond,
-    uv_mutex_t* mutex, uint64_t timeout) {
-  if (pSleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
+int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
+  if (SleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
     return 0;
   if (GetLastError() != ERROR_TIMEOUT)
     abort();
@@ -598,15 +399,6 @@ static int uv_cond_condvar_timedwait(uv_cond_t* cond,
 }
 
 
-int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex,
-    uint64_t timeout) {
-  if (HAVE_CONDVAR_API())
-    return uv_cond_condvar_timedwait(cond, mutex, timeout);
-  else
-    return uv_cond_fallback_timedwait(cond, mutex, timeout);
-}
-
-
 int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
   int err;
 

+ 0 - 195
src/win/timer.c

@@ -1,195 +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 <assert.h>
-#include <limits.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "tree.h"
-#include "handle-inl.h"
-
-
-/* The number of milliseconds in one second. */
-#define UV__MILLISEC 1000
-
-
-void uv_update_time(uv_loop_t* loop) {
-  uint64_t new_time = uv__hrtime(UV__MILLISEC);
-  assert(new_time >= loop->time);
-  loop->time = new_time;
-}
-
-
-static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
-  if (a->due < b->due)
-    return -1;
-  if (a->due > b->due)
-    return 1;
-  /*
-   *  compare start_id when both has the same due. start_id is
-   *  allocated with loop->timer_counter in uv_timer_start().
-   */
-  if (a->start_id < b->start_id)
-    return -1;
-  if (a->start_id > b->start_id)
-    return 1;
-  return 0;
-}
-
-
-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) {
-  uv__handle_init(loop, (uv_handle_t*) handle, UV_TIMER);
-  handle->timer_cb = NULL;
-  handle->repeat = 0;
-
-  return 0;
-}
-
-
-void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) {
-  if (handle->flags & UV__HANDLE_CLOSING) {
-    assert(!(handle->flags & UV_HANDLE_CLOSED));
-    uv__handle_close(handle);
-  }
-}
-
-
-static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) {
-  uint64_t clamped_timeout;
-
-  clamped_timeout = loop_time + timeout;
-  if (clamped_timeout < timeout)
-    clamped_timeout = (uint64_t) -1;
-
-  return clamped_timeout;
-}
-
-
-int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout,
-    uint64_t repeat) {
-  uv_loop_t* loop = handle->loop;
-  uv_timer_t* old;
-
-  if (timer_cb == NULL)
-    return UV_EINVAL;
-
-  if (uv__is_active(handle))
-    uv_timer_stop(handle);
-
-  handle->timer_cb = timer_cb;
-  handle->due = get_clamped_due_time(loop->time, timeout);
-  handle->repeat = repeat;
-  uv__handle_start(handle);
-
-  /* start_id is the second index to be compared in uv__timer_cmp() */
-  handle->start_id = handle->loop->timer_counter++;
-
-  old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle);
-  assert(old == NULL);
-
-  return 0;
-}
-
-
-int uv_timer_stop(uv_timer_t* handle) {
-  uv_loop_t* loop = handle->loop;
-
-  if (!uv__is_active(handle))
-    return 0;
-
-  RB_REMOVE(uv_timer_tree_s, &loop->timers, handle);
-  uv__handle_stop(handle);
-
-  return 0;
-}
-
-
-int uv_timer_again(uv_timer_t* handle) {
-  /* If timer_cb is NULL that means that the timer was never started. */
-  if (!handle->timer_cb) {
-    return UV_EINVAL;
-  }
-
-  if (handle->repeat) {
-    uv_timer_stop(handle);
-    uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
-  }
-
-  return 0;
-}
-
-
-void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
-  assert(handle->type == UV_TIMER);
-  handle->repeat = repeat;
-}
-
-
-uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
-  assert(handle->type == UV_TIMER);
-  return handle->repeat;
-}
-
-
-DWORD uv__next_timeout(const uv_loop_t* loop) {
-  uv_timer_t* timer;
-  int64_t delta;
-
-  /* Check if there are any running timers
-   * Need to cast away const first, since RB_MIN doesn't know what we are
-   * going to do with this return value, it can't be marked const
-   */
-  timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers);
-  if (timer) {
-    delta = timer->due - loop->time;
-    if (delta >= UINT_MAX - 1) {
-      /* A timeout value of UINT_MAX means infinite, so that's no good. */
-      return UINT_MAX - 1;
-    } else if (delta < 0) {
-      /* Negative timeout values are not allowed */
-      return 0;
-    } else {
-      return (DWORD)delta;
-    }
-  } else {
-    /* No timers */
-    return INFINITE;
-  }
-}
-
-
-void uv_process_timers(uv_loop_t* loop) {
-  uv_timer_t* timer;
-
-  /* Call timer callbacks */
-  for (timer = RB_MIN(uv_timer_tree_s, &loop->timers);
-       timer != NULL && timer->due <= loop->time;
-       timer = RB_MIN(uv_timer_tree_s, &loop->timers)) {
-
-    uv_timer_stop(timer);
-    uv_timer_again(timer);
-    timer->timer_cb((uv_timer_t*) timer);
-  }
-}

+ 87 - 90
src/win/tty.c

@@ -25,7 +25,7 @@
 #include <stdlib.h>
 
 #if defined(_MSC_VER) && _MSC_VER < 1600
-# include "stdint-msvc2008.h"
+# include "uv/stdint-msvc2008.h"
 #else
 # include <stdint.h>
 #endif
@@ -164,7 +164,7 @@ void uv_console_init(void) {
                                        OPEN_EXISTING,
                                        0,
                                        0);
-  if (uv__tty_console_handle != NULL) {
+  if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
     QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
                       NULL,
                       WT_EXECUTELONGFUNCTION);
@@ -172,9 +172,12 @@ void uv_console_init(void) {
 }
 
 
-int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
+int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
+  BOOL readable;
+  DWORD NumberOfEvents;
   HANDLE handle;
   CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
+  (void)unused;
 
   uv__once_init();
   handle = (HANDLE) uv__get_osfhandle(fd);
@@ -199,14 +202,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
     fd = -1;
   }
 
+  readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents);
   if (!readable) {
     /* Obtain the screen buffer info with the output handle. */
     if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
       return uv_translate_sys_error(GetLastError());
     }
 
-    /* Obtain the the tty_output_lock because the virtual window state is */
-    /* shared between all uv_tty_t handles. */
+    /* Obtain the tty_output_lock because the virtual window state is shared
+     * between all uv_tty_t handles. */
     uv_sem_wait(&uv_tty_output_lock);
 
     if (uv__vterm_state == UV_UNCHECKED)
@@ -356,6 +360,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
     }
   } else {
     was_reading = 0;
+    alloc_cb = NULL;
+    read_cb = NULL;
   }
 
   uv_sem_wait(&uv_tty_output_lock);
@@ -382,12 +388,6 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
 }
 
 
-int uv_is_tty(uv_file file) {
-  DWORD result;
-  return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0;
-}
-
-
 int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
   CONSOLE_SCREEN_BUFFER_INFO info;
 
@@ -484,8 +484,8 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
     bytes = MAX_INPUT_BUFFER_LENGTH;
   }
 
-  /* At last, unicode! */
-  /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */
+  /* At last, unicode! One utf-16 codeunit never takes more than 3 utf-8
+   * codeunits to encode. */
   chars = bytes / 3;
 
   status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS);
@@ -620,10 +620,10 @@ static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
       }
 
   switch (code) {
-    /* These mappings are the same as Cygwin's. Unmodified and alt-modified */
-    /* keypad keys comply with linux console, modifiers comply with xterm */
-    /* modifier usage. F1..f12 and shift-f1..f10 comply with linux console, */
-    /* f6..f12 with and without modifiers comply with rxvt. */
+    /* These mappings are the same as Cygwin's. Unmodified and alt-modified
+     * keypad keys comply with linux console, modifiers comply with xterm
+     * modifier usage. F1. f12 and shift-f1. f10 comply with linux console, f6.
+     * f12 with and without modifiers comply with rxvt. */
     VK_CASE(VK_INSERT,  "[2~",  "[2;2~", "[2;5~", "[2;6~")
     VK_CASE(VK_END,     "[4~",  "[4;2~", "[4;5~", "[4;6~")
     VK_CASE(VK_DOWN,    "[B",   "[1;2B", "[1;5B", "[1;6B")
@@ -706,8 +706,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
     goto out;
   }
 
-  /* Windows sends a lot of events that we're not interested in, so buf */
-  /* will be allocated on demand, when there's actually something to emit. */
+  /* Windows sends a lot of events that we're not interested in, so buf will be
+   * allocated on demand, when there's actually something to emit. */
   buf = uv_null_buf_;
   buf_used = 0;
 
@@ -733,16 +733,17 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
         continue;
       }
 
-      /* Ignore keyup events, unless the left alt key was held and a valid */
-      /* unicode character was emitted. */
-      if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) ||
-          KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) {
+      /* Ignore keyup events, unless the left alt key was held and a valid
+       * unicode character was emitted. */
+      if (!KEV.bKeyDown &&
+          KEV.wVirtualKeyCode != VK_MENU &&
+          KEV.uChar.UnicodeChar != 0) {
         continue;
       }
 
-      /* Ignore keypresses to numpad number keys if the left alt is held */
-      /* because the user is composing a character, or windows simulating */
-      /* this. */
+      /* Ignore keypresses to numpad number keys if the left alt is held
+       * because the user is composing a character, or windows simulating this.
+       */
       if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
           !(KEV.dwControlKeyState & ENHANCED_KEY) &&
           (KEV.wVirtualKeyCode == VK_INSERT ||
@@ -779,8 +780,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
           continue;
         }
 
-        /* Prefix with \u033 if alt was held, but alt was not used as part */
-        /* a compose sequence. */
+        /* Prefix with \u033 if alt was held, but alt was not used as part a
+         * compose sequence. */
         if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
             && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
             RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
@@ -793,8 +794,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
         if (KEV.uChar.UnicodeChar >= 0xDC00 &&
             KEV.uChar.UnicodeChar < 0xE000) {
           /* UTF-16 surrogate pair */
-          WCHAR utf16_buffer[2] = { handle->tty.rd.last_utf16_high_surrogate,
-                                    KEV.uChar.UnicodeChar};
+          WCHAR utf16_buffer[2];
+          utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate;
+          utf16_buffer[1] = KEV.uChar.UnicodeChar;
           char_len = WideCharToMultiByte(CP_UTF8,
                                          0,
                                          utf16_buffer,
@@ -818,8 +820,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
         /* Whatever happened, the last character wasn't a high surrogate. */
         handle->tty.rd.last_utf16_high_surrogate = 0;
 
-        /* If the utf16 character(s) couldn't be converted something must */
-        /* be wrong. */
+        /* If the utf16 character(s) couldn't be converted something must be
+         * wrong. */
         if (!char_len) {
           handle->flags &= ~UV_HANDLE_READING;
           DECREASE_ACTIVE_COUNT(loop, handle);
@@ -943,21 +945,15 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
       handle->read_cb((uv_stream_t*) handle,
                       uv_translate_sys_error(GET_REQ_ERROR(req)),
                       &buf);
-    } else {
-      /* The read was cancelled, or whatever we don't care */
-      handle->read_cb((uv_stream_t*) handle, 0, &buf);
     }
-
   } else {
-    if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
-      /* Read successful */
-      /* TODO: read unicode, convert to utf-8 */
+    if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING) &&
+        req->u.io.overlapped.InternalHigh != 0) {
+      /* Read successful. TODO: read unicode, convert to utf-8 */
       DWORD bytes = req->u.io.overlapped.InternalHigh;
       handle->read_cb((uv_stream_t*) handle, bytes, &buf);
-    } else {
-      handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
-      handle->read_cb((uv_stream_t*) handle, 0, &buf);
     }
+    handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
   }
 
   /* Wait for more input events. */
@@ -975,9 +971,9 @@ void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
   assert(handle->type == UV_TTY);
   assert(handle->flags & UV_HANDLE_TTY_READABLE);
 
-  /* If the read_line_buffer member is zero, it must have been an raw read. */
-  /* Otherwise it was a line-buffered read. */
-  /* FIXME: This is quite obscure. Use a flag or something. */
+  /* If the read_line_buffer member is zero, it must have been an raw read.
+   * Otherwise it was a line-buffered read. FIXME: This is quite obscure. Use a
+   * flag or something. */
   if (handle->tty.rd.read_line_buffer.len == 0) {
     uv_process_tty_read_raw_req(loop, handle, req);
   } else {
@@ -999,14 +995,14 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
   handle->read_cb = read_cb;
   handle->alloc_cb = alloc_cb;
 
-  /* If reading was stopped and then started again, there could still be a */
-  /* read request pending. */
+  /* If reading was stopped and then started again, there could still be a read
+   * request pending. */
   if (handle->flags & UV_HANDLE_READ_PENDING) {
     return 0;
   }
 
-  /* Maybe the user stopped reading half-way while processing key events. */
-  /* Short-circuit if this could be the case. */
+  /* Maybe the user stopped reading half-way while processing key events.
+   * Short-circuit if this could be the case. */
   if (handle->tty.rd.last_key_len > 0) {
     SET_REQ_SUCCESS(&handle->read_req);
     uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
@@ -1033,9 +1029,10 @@ int uv_tty_read_stop(uv_tty_t* handle) {
     return 0;
 
   if (handle->flags & UV_HANDLE_TTY_RAW) {
-    /* Cancel raw read */
-    /* Write some bullshit event to force the console wait to return. */
+    /* Cancel raw read. Write some bullshit event to force the console wait to
+     * return. */
     memset(&record, 0, sizeof record);
+    record.EventType = FOCUS_EVENT;
     if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
       return GetLastError();
     }
@@ -1116,8 +1113,8 @@ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
     uv_tty_virtual_offset = info->dwCursorPosition.Y;
   } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
              uv_tty_virtual_height + 1) {
-    /* If suddenly find the cursor outside of the virtual window, it must */
-    /* have somehow scrolled. Update the virtual window offset. */
+    /* If suddenly find the cursor outside of the virtual window, it must have
+     * somehow scrolled. Update the virtual window offset. */
     uv_tty_virtual_offset = info->dwCursorPosition.Y -
                             uv_tty_virtual_height + 1;
   }
@@ -1304,8 +1301,8 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
     x2 = 0;
     x2r = 1;
   } else {
-    /* Clear to end of row. We pretend the console is 65536 characters wide, */
-    /* uv_tty_make_real_coord will clip it to the actual console width. */
+    /* Clear to end of row. We pretend the console is 65536 characters wide,
+     * uv_tty_make_real_coord will clip it to the actual console width. */
     x2 = 0xffff;
     x2r = 0;
   }
@@ -1613,8 +1610,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                              const uv_buf_t bufs[],
                              unsigned int nbufs,
                              DWORD* error) {
-  /* We can only write 8k characters at a time. Windows can't handle */
-  /* much more characters in a single console write anyway. */
+  /* We can only write 8k characters at a time. Windows can't handle much more
+   * characters in a single console write anyway. */
   WCHAR utf16_buf[MAX_CONSOLE_CHAR];
   WCHAR* utf16_buffer;
   DWORD utf16_buf_used = 0;
@@ -1650,9 +1647,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
   unsigned char previous_eol = handle->tty.wr.previous_eol;
   unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
 
-  /* Store the error here. If we encounter an error, stop trying to do i/o */
-  /* but keep parsing the buffer so we leave the parser in a consistent */
-  /* state. */
+  /* Store the error here. If we encounter an error, stop trying to do i/o but
+   * keep parsing the buffer so we leave the parser in a consistent state. */
   *error = ERROR_SUCCESS;
 
   utf16_buffer = utf16_buf;
@@ -1700,9 +1696,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
     for (j = 0; j < buf.len; j++) {
       unsigned char c = buf.base[j];
 
-      /* Run the character through the utf8 decoder We happily accept non */
-      /* shortest form encodings and invalid code points - there's no real */
-      /* harm that can be done. */
+      /* Run the character through the utf8 decoder We happily accept non
+       * shortest form encodings and invalid code points - there's no real harm
+       * that can be done. */
       if (utf8_bytes_left == 0) {
         /* Read utf-8 start byte */
         DWORD first_zero_bit;
@@ -1742,8 +1738,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
         /* Start byte where continuation was expected. */
         utf8_bytes_left = 0;
         utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
-        /* Patch buf offset so this character will be parsed again as a */
-        /* start byte. */
+        /* Patch buf offset so this character will be parsed again as a start
+         * byte. */
         j--;
       }
 
@@ -1776,8 +1772,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
           case '_':
           case 'P':
           case ']':
-            /* Not supported, but we'll have to parse until we see a stop */
-            /* code, e.g. ESC \ or BEL. */
+            /* Not supported, but we'll have to parse until we see a stop code,
+             * e. g. ESC \ or BEL. */
             ansi_parser_state = ANSI_ST_CONTROL;
             continue;
 
@@ -1859,8 +1855,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
               continue;
 
             } else {
-              /* If ANSI_IN_ARG is not set, add another argument and */
-              /* default it to 0. */
+              /* If ANSI_IN_ARG is not set, add another argument and default it
+               * to 0. */
+
               /* Check for too many arguments */
               if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
                 ansi_parser_state |= ANSI_IGNORE;
@@ -1874,9 +1871,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
 
           } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
                      handle->tty.wr.ansi_csi_argc == 0) {
-            /* Ignores '?' if it is the first character after CSI[ */
-            /* This is an extension character from the VT100 codeset */
-            /* that is supported and used by most ANSI terminals today. */
+            /* Ignores '?' if it is the first character after CSI[. This is an
+             * extension character from the VT100 codeset that is supported and
+             * used by most ANSI terminals today. */
             continue;
 
           } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
@@ -2006,8 +2003,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
             continue;
 
           } else {
-            /* We don't support commands that use private mode characters or */
-            /* intermediaries. Ignore the rest of the sequence. */
+            /* We don't support commands that use private mode characters or
+             * intermediaries. Ignore the rest of the sequence. */
             ansi_parser_state |= ANSI_IGNORE;
             continue;
           }
@@ -2020,8 +2017,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
         }
 
       } else if (ansi_parser_state & ANSI_ST_CONTROL) {
-        /* Unsupported control code */
-        /* Ignore everything until we see BEL or ESC \ */
+        /* Unsupported control code.
+         * Ignore everything until we see `BEL` or `ESC \`. */
         if (ansi_parser_state & ANSI_IN_STRING) {
           if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
             if (utf8_codepoint == '"') {
@@ -2055,9 +2052,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
         abort();
       }
 
-      /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */
-      /* windows console doesn't really support UTF-16, so just emit the */
-      /* replacement character. */
+      /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the windows
+       * console doesn't really support UTF-16, so just emit the replacement
+       * character. */
       if (utf8_codepoint > 0xffff) {
         utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
       }
@@ -2071,10 +2068,10 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
           utf16_buf[utf16_buf_used++] = L'\r';
           utf16_buf[utf16_buf_used++] = L'\n';
         } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
-          /* \n was followed by \r; do not print the \r, since */
-          /* the source was either \r\n\r (so the second \r is */
-          /* redundant) or was \n\r (so the \n was processed */
-          /* by the last case and an \r automatically inserted). */
+          /* \n was followed by \r; do not print the \r, since the source was
+           * either \r\n\r (so the second \r is redundant) or was \n\r (so the
+           * \n was processed by the last case and an \r automatically
+           * inserted). */
         } else {
           /* \r without \n; print \r as-is. */
           ENSURE_BUFFER_SPACE(1);
@@ -2182,14 +2179,14 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
 
 void uv_tty_close(uv_tty_t* handle) {
   assert(handle->u.fd == -1 || handle->u.fd > 2);
+  if (handle->flags & UV_HANDLE_READING)
+    uv_tty_read_stop(handle);
+
   if (handle->u.fd == -1)
     CloseHandle(handle->handle);
   else
     close(handle->u.fd);
 
-  if (handle->flags & UV_HANDLE_READING)
-    uv_tty_read_stop(handle);
-
   handle->u.fd = -1;
   handle->handle = INVALID_HANDLE_VALUE;
   handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
@@ -2209,7 +2206,7 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
 
     /* TTY shutdown is really just a no-op */
     if (handle->stream.conn.shutdown_req->cb) {
-      if (handle->flags & UV__HANDLE_CLOSING) {
+      if (handle->flags & UV_HANDLE_CLOSING) {
         handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
       } else {
         handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
@@ -2222,10 +2219,10 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
     return;
   }
 
-  if (handle->flags & UV__HANDLE_CLOSING &&
+  if (handle->flags & UV_HANDLE_CLOSING &&
       handle->reqs_pending == 0) {
-    /* The wait handle used for raw reading should be unregistered when the */
-    /* wait callback runs. */
+    /* The wait handle used for raw reading should be unregistered when the
+     * wait callback runs. */
     assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
            handle->tty.rd.read_raw_wait == NULL);
 

+ 46 - 49
src/win/udp.c

@@ -74,8 +74,8 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
     return GetLastError();
   }
 
-  /* Associate it with the I/O completion port. */
-  /* Use uv_handle_t pointer as completion key. */
+  /* Associate it with the I/O completion port. Use uv_handle_t pointer as
+   * completion key. */
   if (CreateIoCompletionPort((HANDLE)socket,
                              loop->iocp,
                              (ULONG_PTR)socket,
@@ -83,31 +83,28 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
     return GetLastError();
   }
 
-  if (pSetFileCompletionNotificationModes) {
-    /* All known Windows that support SetFileCompletionNotificationModes */
-    /* have a bug that makes it impossible to use this function in */
-    /* conjunction with datagram sockets. We can work around that but only */
-    /* if the user is using the default UDP driver (AFD) and has no other */
-    /* LSPs stacked on top. Here we check whether that is the case. */
-    opt_len = (int) sizeof info;
-    if (getsockopt(socket,
-                   SOL_SOCKET,
-                   SO_PROTOCOL_INFOW,
-                   (char*) &info,
-                   &opt_len) == SOCKET_ERROR) {
-      return GetLastError();
-    }
+  /* All known Windows that support SetFileCompletionNotificationModes have a
+   * bug that makes it impossible to use this function in conjunction with
+   * datagram sockets. We can work around that but only if the user is using
+   * the default UDP driver (AFD) and has no other. LSPs stacked on top. Here
+   * we check whether that is the case. */
+  opt_len = (int) sizeof info;
+  if (getsockopt(
+          socket, SOL_SOCKET, SO_PROTOCOL_INFOW, (char*) &info, &opt_len) ==
+      SOCKET_ERROR) {
+    return GetLastError();
+  }
 
-    if (info.ProtocolChain.ChainLen == 1) {
-      if (pSetFileCompletionNotificationModes((HANDLE)socket,
-          FILE_SKIP_SET_EVENT_ON_HANDLE |
-          FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
-        handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
-        handle->func_wsarecv = uv_wsarecv_workaround;
-        handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
-      } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
-        return GetLastError();
-      }
+  if (info.ProtocolChain.ChainLen == 1) {
+    if (SetFileCompletionNotificationModes(
+            (HANDLE) socket,
+            FILE_SKIP_SET_EVENT_ON_HANDLE |
+                FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
+      handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
+      handle->func_wsarecv = uv_wsarecv_workaround;
+      handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
+    } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
+      return GetLastError();
     }
   }
 
@@ -191,7 +188,7 @@ void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
 
 
 void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
-  if (handle->flags & UV__HANDLE_CLOSING &&
+  if (handle->flags & UV_HANDLE_CLOSING &&
       handle->reqs_pending == 0) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     uv__handle_close(handle);
@@ -245,12 +242,12 @@ static int uv_udp_maybe_bind(uv_udp_t* handle,
     handle->flags |= UV_HANDLE_IPV6;
 
   if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
-    /* On windows IPV6ONLY is on by default. */
-    /* If the user doesn't specify it libuv turns it off. */
+    /* On windows IPV6ONLY is on by default. If the user doesn't specify it
+     * libuv turns it off. */
 
-    /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
-    /* available, or when run on XP/2003 which have no support for dualstack */
-    /* sockets. For now we're silently ignoring the error. */
+    /* TODO: how to handle errors? This may fail if there is no ipv4 stack
+     * available, or when run on XP/2003 which have no support for dualstack
+     * sockets. For now we're silently ignoring the error. */
     setsockopt(handle->socket,
                IPPROTO_IPV6,
                IPV6_V6ONLY,
@@ -369,7 +366,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
   int err;
 
   if (handle->flags & UV_HANDLE_READING) {
-    return WSAEALREADY;
+    return UV_EALREADY;
   }
 
   err = uv_udp_maybe_bind(handle,
@@ -377,7 +374,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
                           sizeof(uv_addr_ip4_any_),
                           0);
   if (err)
-    return err;
+    return uv_translate_sys_error(err);
 
   handle->flags |= UV_HANDLE_READING;
   INCREASE_ACTIVE_COUNT(loop, handle);
@@ -386,8 +383,8 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
   handle->recv_cb = recv_cb;
   handle->alloc_cb = alloc_cb;
 
-  /* If reading was stopped and then started again, there could still be a */
-  /* recv request pending. */
+  /* If reading was stopped and then started again, there could still be a recv
+   * request pending. */
   if (!(handle->flags & UV_HANDLE_READ_PENDING))
     uv_udp_queue_recv(loop, handle);
 
@@ -467,19 +464,19 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
   if (!REQ_SUCCESS(req)) {
     DWORD err = GET_REQ_SOCK_ERROR(req);
     if (err == WSAEMSGSIZE) {
-      /* Not a real error, it just indicates that the received packet */
-      /* was bigger than the receive buffer. */
+      /* Not a real error, it just indicates that the received packet was
+       * bigger than the receive buffer. */
     } else if (err == WSAECONNRESET || err == WSAENETRESET) {
-      /* A previous sendto operation failed; ignore this error. If */
-      /* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */
-      /* MSG_PEEK flag to clear out the error queue. For nonzero reads, */
-      /* immediately queue a new receive. */
+      /* A previous sendto operation failed; ignore this error. If zero-reading
+       * we need to call WSARecv/WSARecvFrom _without_ the. MSG_PEEK flag to
+       * clear out the error queue. For nonzero reads, immediately queue a new
+       * receive. */
       if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
         goto done;
       }
     } else {
-      /* A real error occurred. Report the error to the user only if we're */
-      /* currently reading. */
+      /* A real error occurred. Report the error to the user only if we're
+       * currently reading. */
       if (handle->flags & UV_HANDLE_READING) {
         uv_udp_recv_stop(handle);
         buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
@@ -503,8 +500,8 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
     struct sockaddr_storage from;
     int from_len;
 
-    /* Do a nonblocking receive */
-    /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
+    /* Do a nonblocking receive.
+     * TODO: try to read multiple datagrams at once. FIONREAD maybe? */
     buf = uv_buf_init(NULL, 0);
     handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
     if (buf.base == NULL || buf.len == 0) {
@@ -741,7 +738,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
     return UV_EINVAL;
   }
 
-  if (!(handle->flags & UV_HANDLE_BOUND))
+  if (handle->socket == INVALID_SOCKET)
     return UV_EBADF;
 
   if (addr_st.ss_family == AF_INET) {
@@ -772,7 +769,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
 int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
   BOOL optval = (BOOL) value;
 
-  if (!(handle->flags & UV_HANDLE_BOUND))
+  if (handle->socket == INVALID_SOCKET)
     return UV_EBADF;
 
   if (setsockopt(handle->socket,
@@ -818,7 +815,7 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
       return UV_EINVAL;                                                       \
     }                                                                         \
                                                                               \
-    if (!(handle->flags & UV_HANDLE_BOUND))                                   \
+    if (handle->socket == INVALID_SOCKET)                                     \
       return UV_EBADF;                                                        \
                                                                               \
     if (!(handle->flags & UV_HANDLE_IPV6)) {                                  \

+ 250 - 48
src/win/util.c

@@ -74,10 +74,6 @@
 static char *process_title;
 static CRITICAL_SECTION process_title_lock;
 
-/* Cached copy of the process id, written once. */
-static DWORD current_pid = 0;
-
-
 /* Interval (in seconds) of the high-resolution clock. */
 static double hrtime_interval_ = 0;
 
@@ -149,8 +145,8 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
 
   uv__free(utf16_buffer);
 
-  /* utf8_len *does* include the terminating null at this point, but the */
-  /* returned size shouldn't. */
+  /* utf8_len *does* include the terminating null at this point, but the
+   * returned size shouldn't. */
   *size_ptr = utf8_len - 1;
   return 0;
 
@@ -173,16 +169,16 @@ int uv_cwd(char* buffer, size_t* size) {
   if (utf16_len == 0) {
     return uv_translate_sys_error(GetLastError());
   } else if (utf16_len > MAX_PATH) {
-    /* This should be impossible;  however the CRT has a code path to deal */
-    /* with this scenario, so I added a check anyway. */
+    /* This should be impossible; however the CRT has a code path to deal with
+     * this scenario, so I added a check anyway. */
     return UV_EIO;
   }
 
   /* utf16_len contains the length, *not* including the terminating null. */
   utf16_buffer[utf16_len] = L'\0';
 
-  /* The returned directory should not have a trailing slash, unless it */
-  /* points at a drive root, like c:\. Remove it if needed.*/
+  /* The returned directory should not have a trailing slash, unless it points
+   * at a drive root, like c:\. Remove it if needed. */
   if (utf16_buffer[utf16_len - 1] == L'\\' &&
       !(utf16_len == 3 && utf16_buffer[1] == L':')) {
     utf16_len--;
@@ -239,9 +235,9 @@ int uv_chdir(const char* dir) {
                           utf16_buffer,
                           MAX_PATH) == 0) {
     DWORD error = GetLastError();
-    /* The maximum length of the current working directory is 260 chars, */
-    /* including terminating null. If it doesn't fit, the path name must be */
-    /* too long. */
+    /* The maximum length of the current working directory is 260 chars,
+     * including terminating null. If it doesn't fit, the path name must be too
+     * long. */
     if (error == ERROR_INSUFFICIENT_BUFFER) {
       return UV_ENAMETOOLONG;
     } else {
@@ -253,9 +249,9 @@ int uv_chdir(const char* dir) {
     return uv_translate_sys_error(GetLastError());
   }
 
-  /* Windows stores the drive-local path in an "hidden" environment variable, */
-  /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */
-  /* update this, so we'll have to do it. */
+  /* Windows stores the drive-local path in an "hidden" environment variable,
+   * which has the form "=C:=C:\Windows". SetCurrentDirectory does not update
+   * this, so we'll have to do it. */
   utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
   if (utf16_len == 0) {
     return uv_translate_sys_error(GetLastError());
@@ -263,8 +259,8 @@ int uv_chdir(const char* dir) {
     return UV_EIO;
   }
 
-  /* The returned directory should not have a trailing slash, unless it */
-  /* points at a drive root, like c:\. Remove it if needed. */
+  /* The returned directory should not have a trailing slash, unless it points
+   * at a drive root, like c:\. Remove it if needed. */
   if (utf16_buffer[utf16_len - 1] == L'\\' &&
       !(utf16_len == 3 && utf16_buffer[1] == L':')) {
     utf16_len--;
@@ -272,8 +268,8 @@ int uv_chdir(const char* dir) {
   }
 
   if (utf16_len < 2 || utf16_buffer[1] != L':') {
-    /* Doesn't look like a drive letter could be there - probably an UNC */
-    /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */
+    /* Doesn't look like a drive letter could be there - probably an UNC path.
+     * TODO: Need to handle win32 namespaces like \\?\C:\ ? */
     drive_letter = 0;
   } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
     drive_letter = utf16_buffer[0];
@@ -359,14 +355,6 @@ uv_pid_t uv_os_getppid(void) {
 }
 
 
-int uv_current_pid(void) {
-  if (current_pid == 0) {
-    current_pid = GetCurrentProcessId();
-  }
-  return current_pid;
-}
-
-
 char** uv_setup_args(int argc, char** argv) {
   return argv;
 }
@@ -828,6 +816,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
   int is_vista_or_greater;
   ULONG flags;
 
+  *addresses_ptr = NULL;
+  *count_ptr = 0;
+
   is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
   if (is_vista_or_greater) {
     flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
@@ -842,17 +833,17 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
   }
 
 
-  /* Fetch the size of the adapters reported by windows, and then get the */
-  /* list itself. */
+  /* Fetch the size of the adapters reported by windows, and then get the list
+   * itself. */
   win_address_buf_size = 0;
   win_address_buf = NULL;
 
   for (;;) {
     ULONG r;
 
-    /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */
-    /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */
-    /* win_address_buf_size. */
+    /* If win_address_buf is 0, then GetAdaptersAddresses will fail with.
+     * ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in
+     * win_address_buf_size. */
     r = GetAdaptersAddresses(AF_UNSPEC,
                              flags,
                              NULL,
@@ -866,8 +857,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
 
     switch (r) {
       case ERROR_BUFFER_OVERFLOW:
-        /* This happens when win_address_buf is NULL or too small to hold */
-        /* all adapters. */
+        /* This happens when win_address_buf is NULL or too small to hold all
+         * adapters. */
         win_address_buf = uv__malloc(win_address_buf_size);
         if (win_address_buf == NULL)
           return UV_ENOMEM;
@@ -901,15 +892,15 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
         return UV_ENOBUFS;
 
       default:
-        /* Other (unspecified) errors can happen, but we don't have any */
-        /* special meaning for them. */
+        /* Other (unspecified) errors can happen, but we don't have any special
+         * meaning for them. */
         assert(r != ERROR_SUCCESS);
         return uv_translate_sys_error(r);
     }
   }
 
-  /* Count the number of enabled interfaces and compute how much space is */
-  /* needed to store their info. */
+  /* Count the number of enabled interfaces and compute how much space is
+   * needed to store their info. */
   count = 0;
   uv_address_buf_size = 0;
 
@@ -919,9 +910,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
     IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
     int name_size;
 
-    /* Interfaces that are not 'up' should not be reported. Also skip */
-    /* interfaces that have no associated unicast address, as to avoid */
-    /* allocating space for the name for this interface. */
+    /* Interfaces that are not 'up' should not be reported. Also skip
+     * interfaces that have no associated unicast address, as to avoid
+     * allocating space for the name for this interface. */
     if (adapter->OperStatus != IfOperStatusUp ||
         adapter->FirstUnicastAddress == NULL)
       continue;
@@ -941,8 +932,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
     }
     uv_address_buf_size += name_size;
 
-    /* Count the number of addresses associated with this interface, and */
-    /* compute the size. */
+    /* Count the number of addresses associated with this interface, and
+     * compute the size. */
     for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
                            adapter->FirstUnicastAddress;
          unicast_address != NULL;
@@ -959,8 +950,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
     return UV_ENOMEM;
   }
 
-  /* Compute the start of the uv_interface_address_t array, and the place in */
-  /* the buffer where the interface names will be stored. */
+  /* Compute the start of the uv_interface_address_t array, and the place in
+   * the buffer where the interface names will be stored. */
   uv_address = uv_address_buf;
   name_buf = (char*) (uv_address_buf + count);
 
@@ -1199,8 +1190,8 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
     return UV_EIO;
   }
 
-  /* The returned directory should not have a trailing slash, unless it */
-  /* points at a drive root, like c:\. Remove it if needed.*/
+  /* The returned directory should not have a trailing slash, unless it points
+   * at a drive root, like c:\. Remove it if needed. */
   if (path[len - 1] == L'\\' &&
       !(len == 3 && path[1] == L':')) {
     len--;
@@ -1542,3 +1533,214 @@ int uv_os_gethostname(char* buffer, size_t* size) {
   *size = len;
   return 0;
 }
+
+
+static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
+  int r;
+
+  if (pid == 0)
+    *handle = GetCurrentProcess();
+  else
+    *handle = OpenProcess(access, FALSE, pid);
+
+  if (*handle == NULL) {
+    r = GetLastError();
+
+    if (r == ERROR_INVALID_PARAMETER)
+      return UV_ESRCH;
+    else
+      return uv_translate_sys_error(r);
+  }
+
+  return 0;
+}
+
+
+int uv_os_getpriority(uv_pid_t pid, int* priority) {
+  HANDLE handle;
+  int r;
+
+  if (priority == NULL)
+    return UV_EINVAL;
+
+  r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);
+
+  if (r != 0)
+    return r;
+
+  r = GetPriorityClass(handle);
+
+  if (r == 0) {
+    r = uv_translate_sys_error(GetLastError());
+  } else {
+    /* Map Windows priority classes to Unix nice values. */
+    if (r == REALTIME_PRIORITY_CLASS)
+      *priority = UV_PRIORITY_HIGHEST;
+    else if (r == HIGH_PRIORITY_CLASS)
+      *priority = UV_PRIORITY_HIGH;
+    else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
+      *priority = UV_PRIORITY_ABOVE_NORMAL;
+    else if (r == NORMAL_PRIORITY_CLASS)
+      *priority = UV_PRIORITY_NORMAL;
+    else if (r == BELOW_NORMAL_PRIORITY_CLASS)
+      *priority = UV_PRIORITY_BELOW_NORMAL;
+    else  /* IDLE_PRIORITY_CLASS */
+      *priority = UV_PRIORITY_LOW;
+
+    r = 0;
+  }
+
+  CloseHandle(handle);
+  return r;
+}
+
+
+int uv_os_setpriority(uv_pid_t pid, int priority) {
+  HANDLE handle;
+  int priority_class;
+  int r;
+
+  /* Map Unix nice values to Windows priority classes. */
+  if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
+    return UV_EINVAL;
+  else if (priority < UV_PRIORITY_HIGH)
+    priority_class = REALTIME_PRIORITY_CLASS;
+  else if (priority < UV_PRIORITY_ABOVE_NORMAL)
+    priority_class = HIGH_PRIORITY_CLASS;
+  else if (priority < UV_PRIORITY_NORMAL)
+    priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
+  else if (priority < UV_PRIORITY_BELOW_NORMAL)
+    priority_class = NORMAL_PRIORITY_CLASS;
+  else if (priority < UV_PRIORITY_LOW)
+    priority_class = BELOW_NORMAL_PRIORITY_CLASS;
+  else
+    priority_class = IDLE_PRIORITY_CLASS;
+
+  r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle);
+
+  if (r != 0)
+    return r;
+
+  if (SetPriorityClass(handle, priority_class) == 0)
+    r = uv_translate_sys_error(GetLastError());
+
+  CloseHandle(handle);
+  return r;
+}
+
+
+int uv_os_uname(uv_utsname_t* buffer) {
+  /* Implementation loosely based on
+     https://github.com/gagern/gnulib/blob/master/lib/uname.c */
+  OSVERSIONINFOW os_info;
+  SYSTEM_INFO system_info;
+  int processor_level;
+  int r;
+
+  if (buffer == NULL)
+    return UV_EINVAL;
+
+  uv__once_init();
+  os_info.dwOSVersionInfoSize = sizeof(os_info);
+  os_info.szCSDVersion[0] = L'\0';
+
+  /* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx()
+     if RtlGetVersion() is not available. */
+  if (pRtlGetVersion) {
+    pRtlGetVersion(&os_info);
+  } else {
+    /* Silence GetVersionEx() deprecation warning. */
+    #pragma warning(suppress : 4996)
+    if (GetVersionExW(&os_info) == 0) {
+      r = uv_translate_sys_error(GetLastError());
+      goto error;
+    }
+  }
+
+  /* Populate the version field. */
+  if (WideCharToMultiByte(CP_UTF8,
+                          0,
+                          os_info.szCSDVersion,
+                          -1,
+                          buffer->version,
+                          sizeof(buffer->version),
+                          NULL,
+                          NULL) == 0) {
+    r = uv_translate_sys_error(GetLastError());
+    goto error;
+  }
+
+  /* Populate the sysname field. */
+#ifdef __MINGW32__
+  r = snprintf(buffer->sysname,
+               sizeof(buffer->sysname),
+               "MINGW32_NT-%u.%u",
+               (unsigned int) os_info.dwMajorVersion,
+               (unsigned int) os_info.dwMinorVersion);
+  assert(r < sizeof(buffer->sysname));
+#else
+  uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
+#endif
+
+  /* Populate the release field. */
+  r = snprintf(buffer->release,
+               sizeof(buffer->release),
+               "%d.%d.%d",
+               (unsigned int) os_info.dwMajorVersion,
+               (unsigned int) os_info.dwMinorVersion,
+               (unsigned int) os_info.dwBuildNumber);
+  assert(r < sizeof(buffer->release));
+
+  /* Populate the machine field. */
+  GetSystemInfo(&system_info);
+
+  switch (system_info.wProcessorArchitecture) {
+    case PROCESSOR_ARCHITECTURE_AMD64:
+      uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine));
+      break;
+    case PROCESSOR_ARCHITECTURE_IA64:
+      uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine));
+      break;
+    case PROCESSOR_ARCHITECTURE_INTEL:
+      uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine));
+
+      if (system_info.wProcessorLevel > 3) {
+        processor_level = system_info.wProcessorLevel < 6 ?
+                          system_info.wProcessorLevel : 6;
+        buffer->machine[1] = '0' + processor_level;
+      }
+
+      break;
+    case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
+      uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine));
+      break;
+    case PROCESSOR_ARCHITECTURE_MIPS:
+      uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine));
+      break;
+    case PROCESSOR_ARCHITECTURE_ALPHA:
+    case PROCESSOR_ARCHITECTURE_ALPHA64:
+      uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine));
+      break;
+    case PROCESSOR_ARCHITECTURE_PPC:
+      uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine));
+      break;
+    case PROCESSOR_ARCHITECTURE_SHX:
+      uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine));
+      break;
+    case PROCESSOR_ARCHITECTURE_ARM:
+      uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine));
+      break;
+    default:
+      uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine));
+      break;
+  }
+
+  return 0;
+
+error:
+  buffer->sysname[0] = '\0';
+  buffer->release[0] = '\0';
+  buffer->version[0] = '\0';
+  buffer->machine[0] = '\0';
+  return r;
+}

+ 5 - 55
src/win/winapi.c

@@ -26,6 +26,7 @@
 
 
 /* Ntdll function pointers */
+sRtlGetVersion pRtlGetVersion;
 sRtlNtStatusToDosError pRtlNtStatusToDosError;
 sNtDeviceIoControlFile pNtDeviceIoControlFile;
 sNtQueryInformationFile pNtQueryInformationFile;
@@ -34,20 +35,8 @@ sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
 sNtQueryDirectoryFile pNtQueryDirectoryFile;
 sNtQuerySystemInformation pNtQuerySystemInformation;
 
-
 /* Kernel32 function pointers */
 sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
-sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
-sCreateSymbolicLinkW pCreateSymbolicLinkW;
-sCancelIoEx pCancelIoEx;
-sInitializeConditionVariable pInitializeConditionVariable;
-sSleepConditionVariableCS pSleepConditionVariableCS;
-sSleepConditionVariableSRW pSleepConditionVariableSRW;
-sWakeAllConditionVariable pWakeAllConditionVariable;
-sWakeConditionVariable pWakeConditionVariable;
-sCancelSynchronousIo pCancelSynchronousIo;
-sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
-
 
 /* Powrprof.dll function pointer */
 sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
@@ -55,22 +44,21 @@ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
 /* User32.dll function pointer */
 sSetWinEventHook pSetWinEventHook;
 
-/* iphlpapi.dll function pointer */
-sConvertInterfaceIndexToLuid pConvertInterfaceIndexToLuid = NULL;
-sConvertInterfaceLuidToNameW pConvertInterfaceLuidToNameW = NULL;
 
 void uv_winapi_init(void) {
   HMODULE ntdll_module;
-  HMODULE kernel32_module;
   HMODULE powrprof_module;
   HMODULE user32_module;
-  HMODULE iphlpapi_module;
+  HMODULE kernel32_module;
 
   ntdll_module = GetModuleHandleA("ntdll.dll");
   if (ntdll_module == NULL) {
     uv_fatal_error(GetLastError(), "GetModuleHandleA");
   }
 
+  pRtlGetVersion = (sRtlGetVersion) GetProcAddress(ntdll_module,
+                                                   "RtlGetVersion");
+
   pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
       ntdll_module,
       "RtlNtStatusToDosError");
@@ -127,37 +115,6 @@ void uv_winapi_init(void) {
       kernel32_module,
       "GetQueuedCompletionStatusEx");
 
-  pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes)
-    GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes");
-
-  pCreateSymbolicLinkW = (sCreateSymbolicLinkW)
-    GetProcAddress(kernel32_module, "CreateSymbolicLinkW");
-
-  pCancelIoEx = (sCancelIoEx)
-    GetProcAddress(kernel32_module, "CancelIoEx");
-
-  pInitializeConditionVariable = (sInitializeConditionVariable)
-    GetProcAddress(kernel32_module, "InitializeConditionVariable");
-
-  pSleepConditionVariableCS = (sSleepConditionVariableCS)
-    GetProcAddress(kernel32_module, "SleepConditionVariableCS");
-
-  pSleepConditionVariableSRW = (sSleepConditionVariableSRW)
-    GetProcAddress(kernel32_module, "SleepConditionVariableSRW");
-
-  pWakeAllConditionVariable = (sWakeAllConditionVariable)
-    GetProcAddress(kernel32_module, "WakeAllConditionVariable");
-
-  pWakeConditionVariable = (sWakeConditionVariable)
-    GetProcAddress(kernel32_module, "WakeConditionVariable");
-
-  pCancelSynchronousIo = (sCancelSynchronousIo)
-    GetProcAddress(kernel32_module, "CancelSynchronousIo");
-
-  pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW)
-    GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW");
-
-
   powrprof_module = LoadLibraryA("powrprof.dll");
   if (powrprof_module != NULL) {
     pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
@@ -170,11 +127,4 @@ void uv_winapi_init(void) {
       GetProcAddress(user32_module, "SetWinEventHook");
   }
 
-  iphlpapi_module = LoadLibraryA("iphlpapi.dll");
-  if (iphlpapi_module != NULL) {
-    pConvertInterfaceIndexToLuid = (sConvertInterfaceIndexToLuid)
-      GetProcAddress(iphlpapi_module, "ConvertInterfaceIndexToLuid");
-    pConvertInterfaceLuidToNameW = (sConvertInterfaceLuidToNameW)
-      GetProcAddress(iphlpapi_module, "ConvertInterfaceLuidToNameW");
-  }
 }

+ 9 - 71
src/win/winapi.h

@@ -4076,8 +4076,8 @@
 # define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L)
 #endif
 
-/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the */
-/* DDK got it wrong! */
+/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the DDK
+ * got it wrong! */
 #ifdef NTSTATUS_FROM_WIN32
 # undef NTSTATUS_FROM_WIN32
 #endif
@@ -4109,6 +4109,9 @@
 #endif
 
 /* from winternl.h */
+#if !defined(__UNICODE_STRING_DEFINED) && defined(__MINGW32_)
+#define __UNICODE_STRING_DEFINED
+#endif
 typedef struct _UNICODE_STRING {
   USHORT Length;
   USHORT MaximumLength;
@@ -4516,6 +4519,9 @@ typedef VOID (NTAPI *PIO_APC_ROUTINE)
               PIO_STATUS_BLOCK IoStatusBlock,
               ULONG Reserved);
 
+typedef NTSTATUS (NTAPI *sRtlGetVersion)
+                 (PRTL_OSVERSIONINFOW lpVersionInformation);
+
 typedef ULONG (NTAPI *sRtlNtStatusToDosError)
               (NTSTATUS Status);
 
@@ -4650,48 +4656,6 @@ typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
               DWORD dwMilliseconds,
               BOOL fAlertable);
 
-typedef BOOL (WINAPI* sSetFileCompletionNotificationModes)
-             (HANDLE FileHandle,
-              UCHAR Flags);
-
-typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW)
-                (LPCWSTR lpSymlinkFileName,
-                 LPCWSTR lpTargetFileName,
-                 DWORD dwFlags);
-
-typedef BOOL (WINAPI* sCancelIoEx)
-             (HANDLE hFile,
-              LPOVERLAPPED lpOverlapped);
-
-typedef VOID (WINAPI* sInitializeConditionVariable)
-             (PCONDITION_VARIABLE ConditionVariable);
-
-typedef BOOL (WINAPI* sSleepConditionVariableCS)
-             (PCONDITION_VARIABLE ConditionVariable,
-              PCRITICAL_SECTION CriticalSection,
-              DWORD dwMilliseconds);
-
-typedef BOOL (WINAPI* sSleepConditionVariableSRW)
-             (PCONDITION_VARIABLE ConditionVariable,
-              PSRWLOCK SRWLock,
-              DWORD dwMilliseconds,
-              ULONG Flags);
-
-typedef VOID (WINAPI* sWakeAllConditionVariable)
-             (PCONDITION_VARIABLE ConditionVariable);
-
-typedef VOID (WINAPI* sWakeConditionVariable)
-             (PCONDITION_VARIABLE ConditionVariable);
-
-typedef BOOL (WINAPI* sCancelSynchronousIo)
-             (HANDLE hThread);
-
-typedef DWORD (WINAPI* sGetFinalPathNameByHandleW)
-             (HANDLE hFile,
-              LPWSTR lpszFilePath,
-              DWORD cchFilePath,
-              DWORD dwFlags);
-
 /* from powerbase.h */
 #ifndef DEVICE_NOTIFY_CALLBACK
 # define DEVICE_NOTIFY_CALLBACK 2
@@ -4746,6 +4710,7 @@ typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook)
 
 
 /* Ntdll function pointers */
+extern sRtlGetVersion pRtlGetVersion;
 extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
 extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
 extern sNtQueryInformationFile pNtQueryInformationFile;
@@ -4754,20 +4719,8 @@ extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
 extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
 extern sNtQuerySystemInformation pNtQuerySystemInformation;
 
-
 /* Kernel32 function pointers */
 extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
-extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
-extern sCreateSymbolicLinkW pCreateSymbolicLinkW;
-extern sCancelIoEx pCancelIoEx;
-extern sInitializeConditionVariable pInitializeConditionVariable;
-extern sSleepConditionVariableCS pSleepConditionVariableCS;
-extern sSleepConditionVariableSRW pSleepConditionVariableSRW;
-extern sWakeAllConditionVariable pWakeAllConditionVariable;
-extern sWakeConditionVariable pWakeConditionVariable;
-extern sCancelSynchronousIo pCancelSynchronousIo;
-extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
-
 
 /* Powrprof.dll function pointer */
 extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
@@ -4775,19 +4728,4 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi
 /* User32.dll function pointer */
 extern sSetWinEventHook pSetWinEventHook;
 
-/* iphlpapi.dll function pointer */
-union _NET_LUID_LH;
-typedef DWORD (WINAPI *sConvertInterfaceIndexToLuid)(
-    ULONG InterfaceIndex,
-    union _NET_LUID_LH *InterfaceLuid);
-
-typedef DWORD (WINAPI *sConvertInterfaceLuidToNameW)(
-    const union _NET_LUID_LH *InterfaceLuid,
-    PWSTR InterfaceName,
-    size_t Length);
-
-extern sConvertInterfaceIndexToLuid pConvertInterfaceIndexToLuid;
-extern sConvertInterfaceLuidToNameW pConvertInterfaceLuidToNameW;
-
-
 #endif /* UV_WIN_WINAPI_H_ */

+ 4 - 4
src/win/winsock.c

@@ -256,8 +256,8 @@ int uv_ntstatus_to_winsock_error(NTSTATUS status) {
     default:
       if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
           (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
-        /* It's a windows error that has been previously mapped to an */
-        /* ntstatus code. */
+        /* It's a windows error that has been previously mapped to an ntstatus
+         * code. */
         return (DWORD) (status & 0xffff);
       } else {
         /* The default fallback for unmappable ntstatus codes. */
@@ -519,8 +519,8 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
                                   sizeof *info_out);
 
   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 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);
 

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä