Browse Source

libuv 2019-01-15 (f84c5e69)

Code extracted from:

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

at commit f84c5e693b80cb0c62bcefba147e7a66e2b839c9 (v1.x).
libuv upstream 6 years ago
parent
commit
4fcb0d0213
94 changed files with 3158 additions and 2961 deletions
  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 */
 # define UV_EXTERN /* nothing */
 #endif
 #endif
 
 
-#include "uv-errno.h"
-#include "uv-version.h"
+#include "uv/errno.h"
+#include "uv/version.h"
 #include <stddef.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdio.h>
 
 
 #if defined(_MSC_VER) && _MSC_VER < 1600
 #if defined(_MSC_VER) && _MSC_VER < 1600
-# include "stdint-msvc2008.h"
+# include "uv/stdint-msvc2008.h"
 #else
 #else
 # include <stdint.h>
 # include <stdint.h>
 #endif
 #endif
 
 
 #if defined(_WIN32)
 #if defined(_WIN32)
-# include "uv-win.h"
+# include "uv/win.h"
 #else
 #else
-# include "uv-unix.h"
+# include "uv/unix.h"
 #endif
 #endif
 
 
 /* Expand this list if necessary. */
 /* Expand this list if necessary. */
@@ -142,6 +142,7 @@ extern "C" {
   XX(EHOSTDOWN, "host is down")                                               \
   XX(EHOSTDOWN, "host is down")                                               \
   XX(EREMOTEIO, "remote I/O error")                                           \
   XX(EREMOTEIO, "remote I/O error")                                           \
   XX(ENOTTY, "inappropriate ioctl for device")                                \
   XX(ENOTTY, "inappropriate ioctl for device")                                \
+  XX(EFTYPE, "inappropriate file type or format")                             \
 
 
 #define UV_HANDLE_TYPE_MAP(XX)                                                \
 #define UV_HANDLE_TYPE_MAP(XX)                                                \
   XX(ASYNC, async)                                                            \
   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_interface_address_s uv_interface_address_t;
 typedef struct uv_dirent_s uv_dirent_t;
 typedef struct uv_dirent_s uv_dirent_t;
 typedef struct uv_passwd_s uv_passwd_t;
 typedef struct uv_passwd_s uv_passwd_t;
+typedef struct uv_utsname_s uv_utsname_t;
 
 
 typedef enum {
 typedef enum {
   UV_LOOP_BLOCK_SIGNAL
   UV_LOOP_BLOCK_SIGNAL
@@ -369,7 +371,10 @@ typedef enum {
 UV_EXTERN int uv_translate_sys_error(int sys_errno);
 UV_EXTERN int uv_translate_sys_error(int sys_errno);
 
 
 UV_EXTERN const char* uv_strerror(int err);
 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 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                                                         \
 #define UV_REQ_FIELDS                                                         \
@@ -503,7 +508,7 @@ UV_EXTERN int uv_try_write(uv_stream_t* handle,
 struct uv_write_s {
 struct uv_write_s {
   UV_REQ_FIELDS
   UV_REQ_FIELDS
   uv_write_cb cb;
   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_stream_t* handle;
   UV_WRITE_PRIVATE_FIELDS
   UV_WRITE_PRIVATE_FIELDS
 };
 };
@@ -865,7 +870,13 @@ typedef enum {
    * flags may be specified to create a duplex data stream.
    * flags may be specified to create a duplex data stream.
    */
    */
   UV_READABLE_PIPE  = 0x10,
   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;
 } uv_stdio_flags;
 
 
 typedef struct uv_stdio_container_s {
 typedef struct uv_stdio_container_s {
@@ -952,12 +963,23 @@ enum uv_process_flags {
    * the child's process handle.
    * the child's process handle.
    */
    */
   UV_PROCESS_DETACHED = (1 << 3),
   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
    * Hide the subprocess console window that would normally be created. This
    * option is only meaningful on Windows systems. On Unix it is silently
    * option is only meaningful on Windows systems. On Unix it is silently
    * ignored.
    * 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);
 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 {
 struct uv_cpu_info_s {
   char* model;
   char* model;
   int speed;
   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 {
 struct uv_interface_address_s {
@@ -1031,6 +1055,16 @@ struct uv_passwd_s {
   char* homedir;
   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 {
 typedef enum {
   UV_DIRENT_UNKNOWN,
   UV_DIRENT_UNKNOWN,
   UV_DIRENT_FILE,
   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_resident_set_memory(size_t* rss);
 UV_EXTERN int uv_uptime(double* uptime);
 UV_EXTERN int uv_uptime(double* uptime);
 UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd);
 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 {
 typedef struct {
   long tv_sec;
   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_getpid(void);
 UV_EXTERN uv_pid_t uv_os_getppid(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 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);
 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_gethostname(char* buffer, size_t* size);
 
 
+UV_EXTERN int uv_os_uname(uv_utsname_t* buffer);
+
 
 
 typedef enum {
 typedef enum {
   UV_FS_UNKNOWN = -1,
   UV_FS_UNKNOWN = -1,
@@ -1133,7 +1180,8 @@ typedef enum {
   UV_FS_CHOWN,
   UV_FS_CHOWN,
   UV_FS_FCHOWN,
   UV_FS_FCHOWN,
   UV_FS_REALPATH,
   UV_FS_REALPATH,
-  UV_FS_COPYFILE
+  UV_FS_COPYFILE,
+  UV_FS_LCHOWN
 } uv_fs_type;
 } uv_fs_type;
 
 
 /* uv_fs_t is a subclass of uv_req_t. */
 /* 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_uid_t uid,
                            uv_gid_t gid,
                            uv_gid_t gid,
                            uv_fs_cb cb);
                            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 {
 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)
 # define UV__ENOTTY (-4029)
 #endif
 #endif
 
 
+#if defined(EFTYPE) && !defined(_WIN32)
+# define UV__EFTYPE UV__ERR(EFTYPE)
+#else
+# define UV__EFTYPE (-4028)
+#endif
+
 
 
 #endif /* UV_ERRNO_H_ */
 #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 <pthread.h>
 #include <signal.h>
 #include <signal.h>
 
 
-#include "uv-threadpool.h"
+#include "uv/threadpool.h"
 
 
 #if defined(__linux__)
 #if defined(__linux__)
-# include "uv-linux.h"
+# include "uv/linux.h"
 #elif defined (__MVS__)
 #elif defined (__MVS__)
-# include "uv-os390.h"
+# include "uv/os390.h"
 #elif defined(__PASE__)
 #elif defined(__PASE__)
-# include "uv-posix.h"
+# include "uv/posix.h"
 #elif defined(_AIX)
 #elif defined(_AIX)
-# include "uv-aix.h"
+# include "uv/aix.h"
 #elif defined(__sun)
 #elif defined(__sun)
-# include "uv-sunos.h"
+# include "uv/sunos.h"
 #elif defined(__APPLE__)
 #elif defined(__APPLE__)
-# include "uv-darwin.h"
+# include "uv/darwin.h"
 #elif defined(__DragonFly__)       || \
 #elif defined(__DragonFly__)       || \
       defined(__FreeBSD__)         || \
       defined(__FreeBSD__)         || \
       defined(__FreeBSD_kernel__)  || \
       defined(__FreeBSD_kernel__)  || \
       defined(__OpenBSD__)         || \
       defined(__OpenBSD__)         || \
       defined(__NetBSD__)
       defined(__NetBSD__)
-# include "uv-bsd.h"
+# include "uv/bsd.h"
 #elif defined(__CYGWIN__) || defined(__MSYS__)
 #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
 #endif
 
 
 #ifndef NI_MAXHOST
 #ifndef NI_MAXHOST
@@ -136,8 +134,28 @@ typedef pthread_rwlock_t uv_rwlock_t;
 typedef UV_PLATFORM_SEM_T uv_sem_t;
 typedef UV_PLATFORM_SEM_T uv_sem_t;
 typedef pthread_cond_t uv_cond_t;
 typedef pthread_cond_t uv_cond_t;
 typedef pthread_key_t uv_key_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. */
 /* Platform-specific definitions for uv_spawn support. */
 typedef gid_t uv_gid_t;
 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_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_IS_RELEASE 0
 #define UV_VERSION_SUFFIX "dev"
 #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)
 #if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
 typedef intptr_t ssize_t;
 typedef intptr_t ssize_t;
+# define SSIZE_MAX INTPTR_MAX
 # define _SSIZE_T_
 # define _SSIZE_T_
 # define _SSIZE_T_DEFINED
 # define _SSIZE_T_DEFINED
 #endif
 #endif
@@ -53,13 +54,13 @@ typedef struct pollfd {
 #include <sys/stat.h>
 #include <sys/stat.h>
 
 
 #if defined(_MSC_VER) && _MSC_VER < 1600
 #if defined(_MSC_VER) && _MSC_VER < 1600
-# include "stdint-msvc2008.h"
+# include "uv/stdint-msvc2008.h"
 #else
 #else
 # include <stdint.h>
 # include <stdint.h>
 #endif
 #endif
 
 
-#include "tree.h"
-#include "uv-threadpool.h"
+#include "uv/tree.h"
+#include "uv/threadpool.h"
 
 
 #define MAX_PIPENAME_LEN 256
 #define MAX_PIPENAME_LEN 256
 
 
@@ -86,8 +87,16 @@ typedef struct pollfd {
 #define SIGKILL               9
 #define SIGKILL               9
 #define SIGWINCH             28
 #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
 #ifndef SIGABRT_COMPAT
 # define SIGABRT_COMPAT       6
 # define SIGABRT_COMPAT       6
 #endif
 #endif
@@ -244,7 +253,7 @@ typedef union {
     CRITICAL_SECTION waiters_count_lock;
     CRITICAL_SECTION waiters_count_lock;
     HANDLE signal_event;
     HANDLE signal_event;
     HANDLE broadcast_event;
     HANDLE broadcast_event;
-  } fallback;
+  } unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */
 } uv_cond_t;
 } uv_cond_t;
 
 
 typedef union {
 typedef union {
@@ -308,8 +317,6 @@ typedef struct {
   char* errmsg;
   char* errmsg;
 } uv_lib_t;
 } uv_lib_t;
 
 
-RB_HEAD(uv_timer_tree_s, uv_timer_s);
-
 #define UV_LOOP_PRIVATE_FIELDS                                                \
 #define UV_LOOP_PRIVATE_FIELDS                                                \
     /* The loop's I/O completion port */                                      \
     /* The loop's I/O completion port */                                      \
   HANDLE iocp;                                                                \
   HANDLE iocp;                                                                \
@@ -321,8 +328,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   uv_req_t* pending_reqs_tail;                                                \
   uv_req_t* pending_reqs_tail;                                                \
   /* Head of a single-linked list of closed handles */                        \
   /* Head of a single-linked list of closed handles */                        \
   uv_handle_t* endgame_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 */              \
     /* Lists of active loop (prepare / check / idle) watchers */              \
   uv_prepare_t* prepare_handles;                                              \
   uv_prepare_t* prepare_handles;                                              \
   uv_check_t* check_handles;                                                  \
   uv_check_t* check_handles;                                                  \
@@ -368,10 +375,10 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   } u;                                                                        \
   } u;                                                                        \
   struct uv_req_s* next_req;
   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;
   HANDLE wait_handle;
 
 
 #define UV_CONNECT_PRIVATE_FIELDS                                             \
 #define UV_CONNECT_PRIVATE_FIELDS                                             \
@@ -459,16 +466,17 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
 
 
 #define uv_pipe_connection_fields                                             \
 #define uv_pipe_connection_fields                                             \
   uv_timer_t* eof_timer;                                                      \
   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_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                                                \
 #define UV_PIPE_PRIVATE_FIELDS                                                \
   HANDLE handle;                                                              \
   HANDLE handle;                                                              \
@@ -478,8 +486,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
     struct { uv_pipe_connection_fields } conn;                                \
     struct { uv_pipe_connection_fields } conn;                                \
   } pipe;
   } 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                                                 \
 #define UV_TTY_PRIVATE_FIELDS                                                 \
   HANDLE handle;                                                              \
   HANDLE handle;                                                              \
   union {                                                                     \
   union {                                                                     \
@@ -528,8 +536,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   unsigned char events;
   unsigned char events;
 
 
 #define UV_TIMER_PRIVATE_FIELDS                                               \
 #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 repeat;                                                            \
   uint64_t start_id;                                                          \
   uint64_t start_id;                                                          \
   uv_timer_cb timer_cb;
   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)
   if (err < 0)
     goto error;
     goto error;
 
 
-  ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;
+  ctx->timer_handle.flags |= UV_HANDLE_INTERNAL;
   uv__handle_unref(&ctx->timer_handle);
   uv__handle_unref(&ctx->timer_handle);
 
 
   err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
   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"
 #include "win/handle-inl.h"
 
 
 void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) {
 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));
   assert(!(handle->flags & UV_HANDLE_CLOSED));
   uv__handle_close(handle);
   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>
 #include <string.h>
 
 
 #if defined(_MSC_VER) && _MSC_VER < 1600
 #if defined(_MSC_VER) && _MSC_VER < 1600
-# include "stdint-msvc2008.h"
+# include "uv/stdint-msvc2008.h"
 #else
 #else
 # include <stdint.h>
 # include <stdint.h>
 #endif
 #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) {
   if (l <= 0 || (size_t) l >= size) {
     return UV_ENOSPC;
     return UV_ENOSPC;
   }
   }
-  strncpy(dst, tmp, size);
-  dst[size - 1] = '\0';
+  uv__strscpy(dst, tmp, size);
   return 0;
   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))
   if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
     *tp++ = ':';
     *tp++ = ':';
   *tp++ = '\0';
   *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;
     return UV_ENOSPC;
-  }
-  strcpy(dst, tmp);
   return 0;
   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_cond_t cond;
 static uv_mutex_t mutex;
 static uv_mutex_t mutex;
 static unsigned int idle_threads;
 static unsigned int idle_threads;
+static unsigned int slow_io_work_running;
 static unsigned int nthreads;
 static unsigned int nthreads;
 static uv_thread_t* threads;
 static uv_thread_t* threads;
 static uv_thread_t default_threads[4];
 static uv_thread_t default_threads[4];
 static QUEUE exit_message;
 static QUEUE exit_message;
 static QUEUE wq;
 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) {
 static void uv__cancelled(struct uv__work* w) {
   abort();
   abort();
@@ -51,34 +57,67 @@ static void uv__cancelled(struct uv__work* w) {
 static void worker(void* arg) {
 static void worker(void* arg) {
   struct uv__work* w;
   struct uv__work* w;
   QUEUE* q;
   QUEUE* q;
+  int is_slow_work;
 
 
   uv_sem_post((uv_sem_t*) arg);
   uv_sem_post((uv_sem_t*) arg);
   arg = NULL;
   arg = NULL;
 
 
+  uv_mutex_lock(&mutex);
   for (;;) {
   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;
       idle_threads += 1;
       uv_cond_wait(&cond, &mutex);
       uv_cond_wait(&cond, &mutex);
       idle_threads -= 1;
       idle_threads -= 1;
     }
     }
 
 
     q = QUEUE_HEAD(&wq);
     q = QUEUE_HEAD(&wq);
-
-    if (q == &exit_message)
+    if (q == &exit_message) {
       uv_cond_signal(&cond);
       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_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);
     uv_mutex_unlock(&mutex);
 
 
-    if (q == &exit_message)
-      break;
-
     w = QUEUE_DATA(q, struct uv__work, wq);
     w = QUEUE_DATA(q, struct uv__work, wq);
     w->work(w);
     w->work(w);
 
 
@@ -88,12 +127,32 @@ static void worker(void* arg) {
     QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
     QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
     uv_async_send(&w->loop->wq_async);
     uv_async_send(&w->loop->wq_async);
     uv_mutex_unlock(&w->loop->wq_mutex);
     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);
   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);
   QUEUE_INSERT_TAIL(&wq, q);
   if (idle_threads > 0)
   if (idle_threads > 0)
     uv_cond_signal(&cond);
     uv_cond_signal(&cond);
@@ -108,7 +167,7 @@ UV_DESTRUCTOR(static void cleanup(void)) {
   if (nthreads == 0)
   if (nthreads == 0)
     return;
     return;
 
 
-  post(&exit_message);
+  post(&exit_message, UV__WORK_CPU);
 
 
   for (i = 0; i < nthreads; i++)
   for (i = 0; i < nthreads; i++)
     if (uv_thread_join(threads + i))
     if (uv_thread_join(threads + i))
@@ -156,6 +215,8 @@ static void init_threads(void) {
     abort();
     abort();
 
 
   QUEUE_INIT(&wq);
   QUEUE_INIT(&wq);
+  QUEUE_INIT(&slow_io_pending_wq);
+  QUEUE_INIT(&run_slow_work_message);
 
 
   if (uv_sem_init(&sem, 0))
   if (uv_sem_init(&sem, 0))
     abort();
     abort();
@@ -194,13 +255,14 @@ static void init_once(void) {
 
 
 void uv__work_submit(uv_loop_t* loop,
 void uv__work_submit(uv_loop_t* loop,
                      struct uv__work* w,
                      struct uv__work* w,
+                     enum uv__work_kind kind,
                      void (*work)(struct uv__work* w),
                      void (*work)(struct uv__work* w),
                      void (*done)(struct uv__work* w, int status)) {
                      void (*done)(struct uv__work* w, int status)) {
   uv_once(&once, init_once);
   uv_once(&once, init_once);
   w->loop = loop;
   w->loop = loop;
   w->work = work;
   w->work = work;
   w->done = done;
   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->loop = loop;
   req->work_cb = work_cb;
   req->work_cb = work_cb;
   req->after_work_cb = after_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;
   return 0;
 }
 }
 
 

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

@@ -19,13 +19,22 @@
  */
  */
 
 
 #include "uv.h"
 #include "uv.h"
-#include "internal.h"
+#include "uv-common.h"
 #include "heap-inl.h"
 #include "heap-inl.h"
 
 
 #include <assert.h>
 #include <assert.h>
 #include <limits.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,
 static int timer_less_than(const struct heap_node* ha,
                            const struct heap_node* hb) {
                            const struct heap_node* hb) {
   const uv_timer_t* a;
   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() */
   /* start_id is the second index to be compared in uv__timer_cmp() */
   handle->start_id = handle->loop->timer_counter++;
   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,
               (struct heap_node*) &handle->heap_node,
               timer_less_than);
               timer_less_than);
   uv__handle_start(handle);
   uv__handle_start(handle);
@@ -94,7 +103,7 @@ int uv_timer_stop(uv_timer_t* handle) {
   if (!uv__is_active(handle))
   if (!uv__is_active(handle))
     return 0;
     return 0;
 
 
-  heap_remove((struct heap*) &handle->loop->timer_heap,
+  heap_remove(timer_heap(handle->loop),
               (struct heap_node*) &handle->heap_node,
               (struct heap_node*) &handle->heap_node,
               timer_less_than);
               timer_less_than);
   uv__handle_stop(handle);
   uv__handle_stop(handle);
@@ -131,7 +140,7 @@ int uv__next_timeout(const uv_loop_t* loop) {
   const uv_timer_t* handle;
   const uv_timer_t* handle;
   uint64_t diff;
   uint64_t diff;
 
 
-  heap_node = heap_min((const struct heap*) &loop->timer_heap);
+  heap_node = heap_min(timer_heap(loop));
   if (heap_node == NULL)
   if (heap_node == NULL)
     return -1; /* block indefinitely */
     return -1; /* block indefinitely */
 
 
@@ -143,7 +152,7 @@ int uv__next_timeout(const uv_loop_t* loop) {
   if (diff > INT_MAX)
   if (diff > INT_MAX)
     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;
   uv_timer_t* handle;
 
 
   for (;;) {
   for (;;) {
-    heap_node = heap_min((struct heap*) &loop->timer_heap);
+    heap_node = heap_min(timer_heap(loop));
     if (heap_node == NULL)
     if (heap_node == NULL)
       break;
       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;
   uv_interface_address_t* address;
   int sockfd, inet6, size = 1;
   int sockfd, inet6, size = 1;
   struct ifconf ifc;
   struct ifconf ifc;
@@ -175,6 +174,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
   struct sockaddr_dl* sa_addr;
   struct sockaddr_dl* sa_addr;
 
 
   *count = 0;
   *count = 0;
+  *addresses = NULL;
 
 
   if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
   if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
     return UV__ERR(errno);
     return UV__ERR(errno);
@@ -217,6 +217,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
     (*count)++;
     (*count)++;
   }
   }
 
 
+  if (*count == 0) {
+    uv__close(sockfd);
+    return 0;
+  }
+
   /* Alloc the return interface structs */
   /* Alloc the return interface structs */
   *addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
   *addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
   if (!(*addresses)) {
   if (!(*addresses)) {
@@ -290,3 +295,4 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses,
 
 
   uv__free(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
 #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)
   if (dp == 0)
     return 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
  * Returns 0 if AHAFS is mounted, or an error code < 0 on failure
  */
  */
 static int uv__is_ahafs_mounted(void){
 static int uv__is_ahafs_mounted(void){
+  char rawbuf[FILENAME_MAX+1];
   int rv, i = 2;
   int rv, i = 2;
   struct vmount *p;
   struct vmount *p;
   int size_multiplier = 10;
   int size_multiplier = 10;
@@ -432,7 +429,7 @@ static int uv__is_ahafs_mounted(void){
     obj = vmt2dataptr(vmt, VMT_OBJECT);     /* device */
     obj = vmt2dataptr(vmt, VMT_OBJECT);     /* device */
     stub = vmt2dataptr(vmt, VMT_STUB);      /* mount point */
     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 */
       uv__free(p);  /* Found a match */
       return 0;
       return 0;
     }
     }
@@ -453,7 +450,8 @@ static int uv__makedir_p(const char *dir) {
   size_t len;
   size_t len;
   int err;
   int err;
 
 
-  snprintf(tmp, sizeof(tmp),"%s",dir);
+  /* TODO(bnoordhuis) Check uv__strscpy() return value. */
+  uv__strscpy(tmp, dir, sizeof(tmp));
   len = strlen(tmp);
   len = strlen(tmp);
   if (tmp[len - 1] == '/')
   if (tmp[len - 1] == '/')
     tmp[len - 1] = 0;
     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");
     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);
   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 UV__ERR(errno);
 
 
   return 0;
   return 0;
@@ -702,9 +700,9 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int
     else
     else
       p++;
       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);
   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 cwd[PATH_MAX];
   char absolute_path[PATH_MAX];
   char absolute_path[PATH_MAX];
   char readlink_cwd[PATH_MAX];
   char readlink_cwd[PATH_MAX];
+  struct timeval zt;
+  fd_set pollfd;
 
 
 
 
   /* Figure out whether filename is absolute or not */
   /* 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 */
     /* 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 {
   } else {
     /* We have a relative pathname, compose the absolute pathname */
     /* We have a relative pathname, compose the absolute pathname */
     snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid());
     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);
   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;
   return 0;
 #else
 #else
   return UV_ENOSYS;
   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) {
 int uv_get_process_title(char* buffer, size_t size) {
   size_t len;
   size_t len;
-  len = strlen(process_argv[0]);
   if (buffer == NULL || size == 0)
   if (buffer == NULL || size == 0)
     return UV_EINVAL;
     return UV_EINVAL;
-  else if (size <= len)
-    return UV_ENOBUFS;
 
 
   uv_once(&process_title_mutex_once, init_process_title_mutex_once);
   uv_once(&process_title_mutex_once, init_process_title_mutex_once);
   uv_mutex_lock(&process_title_mutex);
   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);
   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;
     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);
   result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus);
   if (result == -1) {
   if (result == -1) {
     uv__free(ps_cpus);
     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.
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 */
 
 
-#include "android-ifaddrs.h"
+#include "uv/android-ifaddrs.h"
 #include "uv-common.h"
 #include "uv-common.h"
 
 
 #include <string.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)
   if (ent->ifa_addr->sa_family == AF_LINK)
     return 1;
     return 1;
-#elif defined(__NetBSD__)
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
   if (ent->ifa_addr->sa_family != PF_INET &&
   if (ent->ifa_addr->sa_family != PF_INET &&
       ent->ifa_addr->sa_family != PF_INET6)
       ent->ifa_addr->sa_family != PF_INET6)
     return 1;
     return 1;
-#elif defined(__OpenBSD__)
-  if (ent->ifa_addr->sa_family != PF_INET)
-    return 1;
 #endif
 #endif
   return 0;
   return 0;
 }
 }
@@ -69,11 +66,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   uv_interface_address_t* address;
   uv_interface_address_t* address;
   int i;
   int i;
 
 
+  *count = 0;
+  *addresses = NULL;
+
   if (getifaddrs(&addrs) != 0)
   if (getifaddrs(&addrs) != 0)
     return UV__ERR(errno);
     return UV__ERR(errno);
 
 
-  *count = 0;
-
   /* Count the number of interfaces */
   /* Count the number of interfaces */
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
     if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
     if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
@@ -81,6 +79,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
     (*count)++;
     (*count)++;
   }
   }
 
 
+  if (*count == 0) {
+    freeifaddrs(addrs);
+    return 0;
+  }
+
   *addresses = uv__malloc(*count * sizeof(**addresses));
   *addresses = uv__malloc(*count * sizeof(**addresses));
 
 
   if (*addresses == NULL) {
   if (*addresses == NULL) {
@@ -121,15 +124,17 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
     address = *addresses;
     address = *addresses;
 
 
     for (i = 0; i < *count; i++) {
     for (i = 0; i < *count; i++) {
-      if (strcmp(address->name, ent->ifa_name) == 0) {
 #if defined(__CYGWIN__) || defined(__MSYS__)
 #if defined(__CYGWIN__) || defined(__MSYS__)
-        memset(address->phys_addr, 0, sizeof(address->phys_addr));
+      memset(address->phys_addr, 0, sizeof(address->phys_addr));
 #else
 #else
+      if (strcmp(address->name, ent->ifa_name) == 0) {
         struct sockaddr_dl* sa_addr;
         struct sockaddr_dl* sa_addr;
         sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
         sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
         memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_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++;
       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/uio.h> /* writev */
 #include <sys/resource.h> /* getrusage */
 #include <sys/resource.h> /* getrusage */
 #include <pwd.h>
 #include <pwd.h>
+#include <sys/utsname.h>
 
 
 #ifdef __sun
 #ifdef __sun
 # include <netdb.h> /* MAXHOSTNAMELEN on Solaris */
 # 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) {
 void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
   assert(!uv__is_closing(handle));
   assert(!uv__is_closing(handle));
 
 
-  handle->flags |= UV_CLOSING;
+  handle->flags |= UV_HANDLE_CLOSING;
   handle->close_cb = close_cb;
   handle->close_cb = close_cb;
 
 
   switch (handle->type) {
   switch (handle->type) {
@@ -174,8 +175,8 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
 
 
   case UV_SIGNAL:
   case UV_SIGNAL:
     uv__signal_close((uv_signal_t*) handle);
     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;
     return;
 
 
   default:
   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) {
 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->next_closing = handle->loop->closing_handles;
   handle->loop->closing_handles = handle;
   handle->loop->closing_handles = handle;
 }
 }
@@ -241,15 +242,17 @@ int uv__getiovmax(void) {
 
 
 
 
 static void uv__finish_close(uv_handle_t* handle) {
 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
    * 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
    * by uv_close(). The handle is considered active at this point because the
    * completion of the shutdown req is still pending.
    * 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) {
   switch (handle->type) {
     case UV_PREPARE:
     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) {
 ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
   struct cmsghdr* cmsg;
   struct cmsghdr* cmsg;
   ssize_t rc;
   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) {
 int uv_getrusage(uv_rusage_t* rusage) {
   struct rusage usage;
   struct rusage usage;
 
 
@@ -1331,6 +1318,9 @@ uv_os_fd_t uv_get_osfhandle(int fd) {
   return fd;
   return fd;
 }
 }
 
 
+int uv_open_osfhandle(uv_os_fd_t os_fd) {
+  return os_fd;
+}
 
 
 uv_pid_t uv_os_getpid(void) {
 uv_pid_t uv_os_getpid(void) {
   return getpid();
   return getpid();
@@ -1340,3 +1330,87 @@ uv_pid_t uv_os_getpid(void) {
 uv_pid_t uv_os_getppid(void) {
 uv_pid_t uv_os_getppid(void) {
   return getppid();
   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) {
 int uv_resident_set_memory(size_t* rss) {
   /* FIXME: read /proc/meminfo? */
   /* FIXME: read /proc/meminfo? */
   *rss = 0;
   *rss = 0;
-  return UV_ENOSYS;
+  return 0;
 }
 }
 
 
 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
 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>
 # include <ApplicationServices/ApplicationServices.h>
 #endif
 #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/"
   application_services_handle = dlopen("/System/Library/Frameworks/"
                                        "ApplicationServices.framework/"
                                        "ApplicationServices.framework/"
                                        "Versions/A/ApplicationServices",
                                        "Versions/A/ApplicationServices",
@@ -116,8 +111,6 @@ int uv__set_process_title(const char* title) {
     goto out;
     goto out;
   }
   }
 
 
-#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
-
   launch_services_bundle =
   launch_services_bundle =
       pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
       pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
 
 
@@ -148,13 +141,14 @@ int uv__set_process_title(const char* title) {
                                      "CFBundleGetInfoDictionary");
                                      "CFBundleGetInfoDictionary");
   *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
   *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
                                  "CFBundleGetMainBundle");
                                  "CFBundleGetMainBundle");
+
   if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
   if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
     goto out;
     goto out;
 
 
   /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
   /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
   hi_services_bundle =
   hi_services_bundle =
       pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices"));
       pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices"));
-  err = UV_ENOENT;
+
   if (hi_services_bundle == NULL)
   if (hi_services_bundle == NULL)
     goto out;
     goto out;
 
 
@@ -168,42 +162,37 @@ int uv__set_process_title(const char* title) {
       pCFBundleGetFunctionPointerForName(
       pCFBundleGetFunctionPointerForName(
           launch_services_bundle,
           launch_services_bundle,
           S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
           S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
+
   if (pSetApplicationIsDaemon == NULL ||
   if (pSetApplicationIsDaemon == NULL ||
       pLSApplicationCheckIn == NULL ||
       pLSApplicationCheckIn == NULL ||
       pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
       pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
     goto out;
     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:
 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 */
 #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
 # define CP_INTR 4
 #endif
 #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) {
 int uv__platform_loop_init(uv_loop_t* loop) {
   return uv__kqueue_init(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) {
 int uv_resident_set_memory(size_t* rss) {
   struct kinfo_proc kinfo;
   struct kinfo_proc kinfo;
   size_t page_size;
   size_t page_size;

+ 201 - 139
src/unix/fs.c

@@ -43,7 +43,6 @@
 #include <pthread.h>
 #include <pthread.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <fcntl.h>
-#include <utime.h>
 #include <poll.h>
 #include <poll.h>
 
 
 #if defined(__DragonFly__)        ||                                      \
 #if defined(__DragonFly__)        ||                                      \
@@ -62,11 +61,20 @@
 
 
 #if defined(__APPLE__)
 #if defined(__APPLE__)
 # include <copyfile.h>
 # include <copyfile.h>
+# include <sys/sysctl.h>
 #elif defined(__linux__) && !defined(FICLONE)
 #elif defined(__linux__) && !defined(FICLONE)
 # include <sys/ioctl.h>
 # include <sys/ioctl.h>
 # define FICLONE _IOW(0x94, 9, int)
 # define FICLONE _IOW(0x94, 9, int)
 #endif
 #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)                                                         \
 #define INIT(subtype)                                                         \
   do {                                                                        \
   do {                                                                        \
     if (req == NULL)                                                          \
     if (req == NULL)                                                          \
@@ -120,7 +128,11 @@
   do {                                                                        \
   do {                                                                        \
     if (cb != NULL) {                                                         \
     if (cb != NULL) {                                                         \
       uv__req_register(loop, req);                                            \
       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;                                                               \
       return 0;                                                               \
     }                                                                         \
     }                                                                         \
     else {                                                                    \
     else {                                                                    \
@@ -143,7 +155,7 @@ static ssize_t uv__fs_fsync(uv_fs_t* req) {
   int r;
   int r;
 
 
   r = fcntl(req->file, F_FULLFSYNC);
   r = fcntl(req->file, F_FULLFSYNC);
-  if (r != 0 && errno == ENOTTY)
+  if (r != 0)
     r = fsync(req->file);
     r = fsync(req->file);
   return r;
   return r;
 #else
 #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) {
 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
   /* utimesat() has nanosecond resolution but we stick to microseconds
    * for the sake of consistency with other platforms.
    * for the sake of consistency with other platforms.
    */
    */
-  static int no_utimesat;
   struct timespec ts[2];
   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_sec  = req->atime;
   ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
   ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
   ts[1].tv_sec  = req->mtime;
   ts[1].tv_sec  = req->mtime;
   ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
   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__)                                                      \
 #elif defined(__APPLE__)                                                      \
     || defined(__DragonFly__)                                                 \
     || defined(__DragonFly__)                                                 \
     || defined(__FreeBSD__)                                                   \
     || defined(__FreeBSD__)                                                   \
@@ -235,13 +205,6 @@ skip:
 # else
 # else
   return futimes(req->file, tv);
   return futimes(req->file, tv);
 # endif
 # 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__)
 #elif defined(__MVS__)
   attrib_t atr;
   attrib_t atr;
   memset(&atr, 0, sizeof(atr));
   memset(&atr, 0, sizeof(atr));
@@ -304,17 +267,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
 #if defined(__linux__)
 #if defined(__linux__)
   static int no_preadv;
   static int no_preadv;
 #endif
 #endif
+  unsigned int iovmax;
   ssize_t result;
   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->off < 0) {
     if (req->nbufs == 1)
     if (req->nbufs == 1)
       result = read(req->file, req->bufs[0].base, req->bufs[0].len);
       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:
     if (no_preadv) retry:
 # endif
 # 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__)
 # if defined(__linux__)
     else {
     else {
@@ -369,6 +310,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
   }
   }
 
 
 done:
 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;
   return result;
 }
 }
 
 
@@ -415,29 +363,55 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) {
   return n;
   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) {
 static ssize_t uv__fs_pathmax_size(const char* path) {
   ssize_t pathmax;
   ssize_t pathmax;
 
 
   pathmax = pathconf(path, _PC_PATH_MAX);
   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;
   return pathmax;
 }
 }
 
 
 static ssize_t uv__fs_readlink(uv_fs_t* req) {
 static ssize_t uv__fs_readlink(uv_fs_t* req) {
+  ssize_t maxlen;
   ssize_t len;
   ssize_t len;
   char* buf;
   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) {
   if (buf == NULL) {
     errno = ENOMEM;
     errno = ENOMEM;
@@ -445,17 +419,28 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
   }
   }
 
 
 #if defined(__MVS__)
 #if defined(__MVS__)
-  len = os390_readlink(req->path, buf, len);
+  len = os390_readlink(req->path, buf, maxlen);
 #else
 #else
-  len = readlink(req->path, buf, len);
+  len = readlink(req->path, buf, maxlen);
 #endif
 #endif
 
 
-
   if (len == -1) {
   if (len == -1) {
     uv__free(buf);
     uv__free(buf);
     return -1;
     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';
   buf[len] = '\0';
   req->ptr = buf;
   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) {
 static ssize_t uv__fs_realpath(uv_fs_t* req) {
-  ssize_t len;
   char* buf;
   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);
   len = uv__fs_pathmax_size(req->path);
   buf = uv__malloc(len + 1);
   buf = uv__malloc(len + 1);
 
 
@@ -478,6 +469,7 @@ static ssize_t uv__fs_realpath(uv_fs_t* req) {
     uv__free(buf);
     uv__free(buf);
     return -1;
     return -1;
   }
   }
+#endif
 
 
   req->ptr = buf;
   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) {
 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;
   struct utimbuf buf;
   buf.actime = req->atime;
   buf.actime = req->atime;
   buf.modtime = req->mtime;
   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:
     if (no_pwritev) retry:
 # endif
 # 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__)
 # if defined(__linux__)
     else {
     else {
@@ -786,26 +798,41 @@ done:
 static ssize_t uv__fs_copyfile(uv_fs_t* req) {
 static ssize_t uv__fs_copyfile(uv_fs_t* req) {
 #if defined(__APPLE__) && !TARGET_OS_IPHONE
 #if defined(__APPLE__) && !TARGET_OS_IPHONE
   /* On macOS, use the native copyfile(3). */
   /* On macOS, use the native copyfile(3). */
+  static int can_clone;
   copyfile_flags_t flags;
   copyfile_flags_t flags;
+  char buf[64];
+  size_t len;
+  int major;
 
 
   flags = COPYFILE_ALL;
   flags = COPYFILE_ALL;
 
 
   if (req->flags & UV_FS_COPYFILE_EXCL)
   if (req->flags & UV_FS_COPYFILE_EXCL)
     flags |= 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) {
   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);
   return copyfile(req->path, req->new_path, NULL, flags);
 #else
 #else
   uv_fs_t fs_req;
   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
       /* 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
          this is a force clone then exit. Otherwise, fall through to try using
          sendfile(). */
          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;
         goto out;
       }
       }
     } else {
     } else {
@@ -927,7 +956,11 @@ out:
     }
     }
   }
   }
 
 
-  return result;
+  if (result == 0)
+    return 0;
+
+  errno = UV__ERR(result);
+  return -1;
 #endif
 #endif
 }
 }
 
 
@@ -1043,9 +1076,21 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) {
   return ret;
   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 iovmax;
   unsigned int nbufs;
   unsigned int nbufs;
   uv_buf_t* bufs;
   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)
     if (req->nbufs > iovmax)
       req->nbufs = iovmax;
       req->nbufs = iovmax;
 
 
-    result = process(req);
+    do
+      result = uv__fs_write(req);
+    while (result < 0 && errno == EINTR);
+
     if (result <= 0) {
     if (result <= 0) {
       if (total == 0)
       if (total == 0)
         total = result;
         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)
     if (req->off >= 0)
       req->off += result;
       req->off += result;
 
 
+    req->nbufs = uv__fs_buf_offset(req->bufs, result);
     req->bufs += req->nbufs;
     req->bufs += req->nbufs;
     nbufs -= req->nbufs;
     nbufs -= req->nbufs;
     total += result;
     total += result;
   }
   }
 
 
-  if (errno == EINTR && total == -1)
-    return total;
-
   if (bufs != req->bufsml)
   if (bufs != req->bufsml)
     uv__free(bufs);
     uv__free(bufs);
 
 
@@ -1096,7 +1142,8 @@ static void uv__fs_work(struct uv__work* w) {
   ssize_t r;
   ssize_t r;
 
 
   req = container_of(w, uv_fs_t, work_req);
   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 {
   do {
     errno = 0;
     errno = 0;
@@ -1114,6 +1161,7 @@ static void uv__fs_work(struct uv__work* w) {
     X(COPYFILE, uv__fs_copyfile(req));
     X(COPYFILE, uv__fs_copyfile(req));
     X(FCHMOD, fchmod(req->file, req->mode));
     X(FCHMOD, fchmod(req->file, req->mode));
     X(FCHOWN, fchown(req->file, req->uid, req->gid));
     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(FDATASYNC, uv__fs_fdatasync(req));
     X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
     X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
     X(FSYNC, uv__fs_fsync(req));
     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(MKDIR, mkdir(req->path, req->mode));
     X(MKDTEMP, uv__fs_mkdtemp(req));
     X(MKDTEMP, uv__fs_mkdtemp(req));
     X(OPEN, uv__fs_open(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(SCANDIR, uv__fs_scandir(req));
     X(READLINK, uv__fs_readlink(req));
     X(READLINK, uv__fs_readlink(req));
     X(REALPATH, uv__fs_realpath(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(SYMLINK, symlink(req->path, req->new_path));
     X(UNLINK, unlink(req->path));
     X(UNLINK, unlink(req->path));
     X(UTIME, uv__fs_utime(req));
     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();
     default: abort();
     }
     }
 #undef X
 #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) {
 int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
   INIT(FDATASYNC);
   INIT(FDATASYNC);
   req->file = file;
   req->file = file;

+ 37 - 35
src/unix/fsevents.c

@@ -255,42 +255,55 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
       path = paths[i];
       path = paths[i];
       len = strlen(path);
       len = strlen(path);
 
 
+      if (handle->realpath_len == 0)
+        continue; /* This should be unreachable */
+
       /* Filter out paths that are outside handle's request */
       /* 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;
         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;
         path += handle->realpath_len;
         len -= 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++;
           path++;
           len--;
           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) */
       /* 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, '/');
         pos = strchr(path + 1, '/');
         if (pos != NULL)
         if (pos != NULL)
           continue;
           continue;
       }
       }
 
 
-#ifndef MAC_OS_X_VERSION_10_7
-      path = "";
-      len = 0;
-#endif /* MAC_OS_X_VERSION_10_7 */
-
       event = uv__malloc(sizeof(*event) + len);
       event = uv__malloc(sizeof(*event) + len);
       if (event == NULL)
       if (event == NULL)
         break;
         break;
@@ -299,22 +312,11 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
       memcpy(event->path, path, len + 1);
       memcpy(event->path, path, len + 1);
       event->events = UV_RENAME;
       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);
       QUEUE_INSERT_TAIL(&head, &event->member);
     }
     }
@@ -836,7 +838,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
 
 
   handle->cf_cb->data = handle;
   handle->cf_cb->data = handle;
   uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
   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);
   uv_unref((uv_handle_t*) handle->cf_cb);
 
 
   err = uv_mutex_init(&handle->cf_mutex);
   err = uv_mutex_init(&handle->cf_mutex);

+ 21 - 0
src/unix/getaddrinfo.c

@@ -27,6 +27,7 @@
 
 
 #include "uv.h"
 #include "uv.h"
 #include "internal.h"
 #include "internal.h"
+#include "idna.h"
 
 
 #include <errno.h>
 #include <errno.h>
 #include <stddef.h> /* NULL */
 #include <stddef.h> /* NULL */
@@ -141,15 +142,34 @@ int uv_getaddrinfo(uv_loop_t* loop,
                    const char* hostname,
                    const char* hostname,
                    const char* service,
                    const char* service,
                    const struct addrinfo* hints) {
                    const struct addrinfo* hints) {
+  char hostname_ascii[256];
   size_t hostname_len;
   size_t hostname_len;
   size_t service_len;
   size_t service_len;
   size_t hints_len;
   size_t hints_len;
   size_t len;
   size_t len;
   char* buf;
   char* buf;
+  long rc;
 
 
   if (req == NULL || (hostname == NULL && service == NULL))
   if (req == NULL || (hostname == NULL && service == NULL))
     return UV_EINVAL;
     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;
   hostname_len = hostname ? strlen(hostname) + 1 : 0;
   service_len = service ? strlen(service) + 1 : 0;
   service_len = service ? strlen(service) + 1 : 0;
   hints_len = hints ? sizeof(*hints) : 0;
   hints_len = hints ? sizeof(*hints) : 0;
@@ -186,6 +206,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
   if (cb) {
   if (cb) {
     uv__work_submit(loop,
     uv__work_submit(loop,
                     &req->work_req,
                     &req->work_req,
+                    UV__WORK_SLOW_IO,
                     uv__getaddrinfo_work,
                     uv__getaddrinfo_work,
                     uv__getaddrinfo_done);
                     uv__getaddrinfo_done);
     return 0;
     return 0;

+ 1 - 0
src/unix/getnameinfo.c

@@ -109,6 +109,7 @@ int uv_getnameinfo(uv_loop_t* loop,
   if (getnameinfo_cb) {
   if (getnameinfo_cb) {
     uv__work_submit(loop,
     uv__work_submit(loop,
                     &req->work_req,
                     &req->work_req,
+                    UV__WORK_SLOW_IO,
                     uv__getnameinfo_work,
                     uv__getnameinfo_work,
                     uv__getnameinfo_done);
                     uv__getnameinfo_done);
     return 0;
     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) {
 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;
 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 */
 /* loop flags */
 enum {
 enum {
   UV_LOOP_BLOCK_SIGPROF = 1
   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(int fd); /* preserves errno */
 int uv__close_nocheckstdio(int fd);
 int uv__close_nocheckstdio(int fd);
 int uv__socket(int domain, int type, int protocol);
 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);
 ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
 void uv__make_close_pending(uv_handle_t* handle);
 void uv__make_close_pending(uv_handle_t* handle);
 int uv__getiovmax(void);
 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);
 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 */
 void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
 int uv__io_fork(uv_loop_t* loop);
 int uv__io_fork(uv_loop_t* loop);
+int uv__fd_exists(uv_loop_t* loop, int fd);
 
 
 /* async */
 /* async */
 void uv__async_stop(uv_loop_t* loop);
 void uv__async_stop(uv_loop_t* loop);
@@ -251,10 +231,6 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay);
 /* pipe */
 /* pipe */
 int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
 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 */
 /* signal */
 void uv__signal_close(uv_signal_t* handle);
 void uv__signal_close(uv_signal_t* handle);
 void uv__signal_global_once_init(void);
 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__process_close(uv_process_t* handle);
 void uv__stream_close(uv_stream_t* handle);
 void uv__stream_close(uv_stream_t* handle);
 void uv__tcp_close(uv_tcp_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_close(uv_udp_t* handle);
 void uv__udp_finish_close(uv_udp_t* handle);
 void uv__udp_finish_close(uv_udp_t* handle);
 uv_handle_type uv__handle_type(int fd);
 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);
 int uv__fsevents_close(uv_fs_event_t* handle);
 void uv__fsevents_loop_delete(uv_loop_t* loop);
 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__) */
 #endif /* defined(__APPLE__) */
 
 
 UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
 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];
       w = loop->watchers[fd];
 
 
       if (w == NULL) {
       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];
         struct kevent events[1];
 
 
         EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
         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,
                       uv_fs_event_cb cb,
                       const char* path,
                       const char* path,
                       unsigned int flags) {
                       unsigned int flags) {
-#if defined(__APPLE__)
-  struct stat statbuf;
-#endif /* defined(__APPLE__) */
   int fd;
   int fd;
 
 
   if (uv__is_active(handle))
   if (uv__is_active(handle))
     return UV_EINVAL;
     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 defined(__APPLE__)
-  if (uv__has_forked_with_cfrunloop)
-    goto fallback;
-
   /* Nullify field to perform checks later */
   /* Nullify field to perform checks later */
   handle->cf_cb = NULL;
   handle->cf_cb = NULL;
   handle->realpath = NULL;
   handle->realpath = NULL;
   handle->realpath_len = 0;
   handle->realpath_len = 0;
   handle->cf_flags = flags;
   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__) */
 #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);
   uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
 
 
   return 0;
   return 0;
@@ -502,29 +501,29 @@ fallback:
 
 
 
 
 int uv_fs_event_stop(uv_fs_event_t* handle) {
 int uv_fs_event_stop(uv_fs_event_t* handle) {
+  int r;
+  r = 0;
+
   if (!uv__is_active(handle))
   if (!uv__is_active(handle))
     return 0;
     return 0;
 
 
   uv__handle_stop(handle);
   uv__handle_stop(handle);
 
 
 #if defined(__APPLE__)
 #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) {
   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);
     uv__close(handle->event_watcher.fd);
     handle->event_watcher.fd = -1;
     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
 /* 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
  * 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"
 #include "uv.h"
@@ -34,6 +34,7 @@
 #include <errno.h>
 #include <errno.h>
 
 
 #include <net/if.h>
 #include <net/if.h>
+#include <sys/epoll.h>
 #include <sys/param.h>
 #include <sys/param.h>
 #include <sys/prctl.h>
 #include <sys/prctl.h>
 #include <sys/sysinfo.h>
 #include <sys/sysinfo.h>
@@ -51,7 +52,7 @@
 
 
 #ifdef HAVE_IFADDRS_H
 #ifdef HAVE_IFADDRS_H
 # if defined(__ANDROID__)
 # if defined(__ANDROID__)
-#  include "android-ifaddrs.h"
+#  include "uv/android-ifaddrs.h"
 # else
 # else
 #  include <ifaddrs.h>
 #  include <ifaddrs.h>
 # endif
 # endif
@@ -84,13 +85,13 @@ static unsigned long read_cpufreq(unsigned int cpunum);
 int uv__platform_loop_init(uv_loop_t* loop) {
 int uv__platform_loop_init(uv_loop_t* loop) {
   int fd;
   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)
   /* epoll_create1() can fail either because it's not implemented (old kernel)
    * or because it doesn't understand the EPOLL_CLOEXEC flag.
    * or because it doesn't understand the EPOLL_CLOEXEC flag.
    */
    */
   if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
   if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
-    fd = uv__epoll_create(256);
+    fd = epoll_create(256);
 
 
     if (fd != -1)
     if (fd != -1)
       uv__cloexec(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) {
 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 i;
   uintptr_t nfds;
   uintptr_t nfds;
 
 
   assert(loop->watchers != NULL);
   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];
   nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
   if (events != NULL)
   if (events != NULL)
     /* Invalidate events with same file descriptor */
     /* Invalidate events with same file descriptor */
     for (i = 0; i < nfds; i++)
     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.
   /* Remove the file descriptor from the epoll.
    * This avoids a problem where the same file description remains open
    * 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.
      * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
      */
      */
     memset(&dummy, 0, sizeof(dummy));
     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) {
 int uv__io_check_fd(uv_loop_t* loop, int fd) {
-  struct uv__epoll_event e;
+  struct epoll_event e;
   int rc;
   int rc;
 
 
+  memset(&e, 0, sizeof(e));
   e.events = POLLIN;
   e.events = POLLIN;
-  e.data = -1;
+  e.data.fd = -1;
 
 
   rc = 0;
   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)
     if (errno != EEXIST)
       rc = UV__ERR(errno);
       rc = UV__ERR(errno);
 
 
   if (rc == 0)
   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();
       abort();
 
 
   return rc;
   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.)
    * that being the largest value I have seen in the wild (and only once.)
    */
    */
   static const int max_safe_timeout = 1789569;
   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;
   int real_timeout;
   QUEUE* q;
   QUEUE* q;
   uv__io_t* w;
   uv__io_t* w;
   sigset_t sigset;
   sigset_t sigset;
-  uint64_t sigmask;
+  sigset_t* psigset;
   uint64_t base;
   uint64_t base;
   int have_signals;
   int have_signals;
   int nevents;
   int nevents;
@@ -219,6 +219,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
     return;
     return;
   }
   }
 
 
+  memset(&e, 0, sizeof(e));
+
   while (!QUEUE_EMPTY(&loop->watcher_queue)) {
   while (!QUEUE_EMPTY(&loop->watcher_queue)) {
     q = QUEUE_HEAD(&loop->watcher_queue);
     q = QUEUE_HEAD(&loop->watcher_queue);
     QUEUE_REMOVE(q);
     QUEUE_REMOVE(q);
@@ -230,35 +232,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
     assert(w->fd < (int) loop->nwatchers);
     assert(w->fd < (int) loop->nwatchers);
 
 
     e.events = w->pevents;
     e.events = w->pevents;
-    e.data = w->fd;
+    e.data.fd = w->fd;
 
 
     if (w->events == 0)
     if (w->events == 0)
-      op = UV__EPOLL_CTL_ADD;
+      op = EPOLL_CTL_ADD;
     else
     else
-      op = UV__EPOLL_CTL_MOD;
+      op = EPOLL_CTL_MOD;
 
 
     /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
     /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
      * events, skip the syscall and squelch the events after epoll_wait().
      * 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)
       if (errno != EEXIST)
         abort();
         abort();
 
 
-      assert(op == UV__EPOLL_CTL_ADD);
+      assert(op == EPOLL_CTL_ADD);
 
 
       /* We've reactivated a file descriptor that's been watched before. */
       /* 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();
         abort();
     }
     }
 
 
     w->events = w->pevents;
     w->events = w->pevents;
   }
   }
 
 
-  sigmask = 0;
+  psigset = NULL;
   if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
   if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
     sigemptyset(&sigset);
     sigemptyset(&sigset);
     sigaddset(&sigset, SIGPROF);
     sigaddset(&sigset, SIGPROF);
-    sigmask |= 1 << (SIGPROF - 1);
+    psigset = &sigset;
   }
   }
 
 
   assert(timeout >= -1);
   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)
     if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
       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
     /* 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
      * 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 (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)
       if (errno != EINTR)
         abort();
         abort();
 
 
@@ -344,7 +321,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
     loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
     loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
     for (i = 0; i < nfds; i++) {
     for (i = 0; i < nfds; i++) {
       pe = events + i;
       pe = events + i;
-      fd = pe->data;
+      fd = pe->data.fd;
 
 
       /* Skip invalidated events, see uv__platform_invalidate_fd */
       /* Skip invalidated events, see uv__platform_invalidate_fd */
       if (fd == -1)
       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
          * Ignore all errors because we may be racing with another thread
          * when the file descriptor is closed.
          * 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;
         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.
        * free when we switch over to edge-triggered I/O.
        */
        */
       if (pe->events == POLLERR || pe->events == POLLHUP)
       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) {
       if (pe->events != 0) {
         /* Run signal watchers last.  This also affects child process watchers
         /* 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;
   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
 #ifndef HAVE_IFADDRS_H
+  *count = 0;
+  *addresses = NULL;
   return UV_ENOSYS;
   return UV_ENOSYS;
 #else
 #else
   struct ifaddrs *addrs, *ent;
   struct ifaddrs *addrs, *ent;
@@ -861,12 +840,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
   int i;
   int i;
   struct sockaddr_ll *sll;
   struct sockaddr_ll *sll;
 
 
-  if (getifaddrs(&addrs))
-    return UV__ERR(errno);
-
   *count = 0;
   *count = 0;
   *addresses = NULL;
   *addresses = NULL;
 
 
+  if (getifaddrs(&addrs))
+    return UV__ERR(errno);
+
   /* Count the number of interfaces */
   /* Count the number of interfaces */
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
     if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
     if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
@@ -875,8 +854,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
     (*count)++;
     (*count)++;
   }
   }
 
 
-  if (*count == 0)
+  if (*count == 0) {
+    freeifaddrs(addrs);
     return 0;
     return 0;
+  }
 
 
   *addresses = uv__malloc(*count * sizeof(**addresses));
   *addresses = uv__malloc(*count * sizeof(**addresses));
   if (!(*addresses)) {
   if (!(*addresses)) {
@@ -920,6 +901,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
       if (strcmp(address->name, ent->ifa_name) == 0) {
       if (strcmp(address->name, ent->ifa_name) == 0) {
         sll = (struct sockaddr_ll*)ent->ifa_addr;
         sll = (struct sockaddr_ll*)ent->ifa_addr;
         memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
         memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
+      } else {
+        memset(address->phys_addr, 0, sizeof(address->phys_addr));
       }
       }
       address++;
       address++;
     }
     }

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

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

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

@@ -77,56 +77,6 @@
 # endif
 # endif
 #endif /* __NR_eventfd2 */
 #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
 #ifndef __NR_inotify_init
 # if defined(__x86_64__)
 # if defined(__x86_64__)
 #  define __NR_inotify_init 253
 #  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) {
 int uv__inotify_init(void) {
 #if defined(__NR_inotify_init)
 #if defined(__NR_inotify_init)
   return syscall(__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) {
 ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
 #if defined(__NR_preadv)
 #if defined(__NR_preadv)
   return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
   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
 # define UV__SOCK_NONBLOCK    UV__O_NONBLOCK
 #endif
 #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 */
 /* inotify flags */
 #define UV__IN_ACCESS         0x001
 #define UV__IN_ACCESS         0x001
 #define UV__IN_MODIFY         0x002
 #define UV__IN_MODIFY         0x002
@@ -86,18 +80,6 @@
 #define UV__IN_DELETE_SELF    0x400
 #define UV__IN_DELETE_SELF    0x400
 #define UV__IN_MOVE_SELF      0x800
 #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 {
 struct uv__inotify_event {
   int32_t wd;
   int32_t wd;
   uint32_t mask;
   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__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
 int uv__eventfd(unsigned int count);
 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__eventfd2(unsigned int count, int flags);
 int uv__inotify_init(void);
 int uv__inotify_init(void);
 int uv__inotify_init1(int flags);
 int uv__inotify_init1(int flags);
@@ -140,10 +110,6 @@ int uv__sendmmsg(int fd,
                  struct uv__mmsghdr* mmsg,
                  struct uv__mmsghdr* mmsg,
                  unsigned int vlen,
                  unsigned int vlen,
                  unsigned int flags);
                  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__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);
 ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
 int uv__dup3(int oldfd, int newfd, int flags);
 int uv__dup3(int oldfd, int newfd, int flags);

+ 3 - 3
src/unix/loop.c

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

+ 2 - 69
src/unix/netbsd.c

@@ -40,15 +40,6 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <time.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) {
 int uv__platform_loop_init(uv_loop_t* loop) {
   return uv__kqueue_init(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
   /* Copy string from the intermediate buffer to outer one with appropriate
    * length.
    * length.
    */
    */
-  strlcpy(buffer, int_buf, *size);
+  /* TODO(bnoordhuis) Check uv__strscpy() return value. */
+  uv__strscpy(buffer, int_buf, *size);
 
 
   /* Set new size. */
   /* Set new size. */
   *size = strlen(buffer);
   *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) {
 int uv_resident_set_memory(size_t* rss) {
   kvm_t *kd = NULL;
   kvm_t *kd = NULL;
   struct kinfo_proc2 *kinfo = NULL;
   struct kinfo_proc2 *kinfo = NULL;

+ 0 - 69
src/unix/openbsd.c

@@ -36,16 +36,6 @@
 #include <unistd.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) {
-  uv_mutex_init(&process_title_mutex);
-}
-
-
 int uv__platform_loop_init(uv_loop_t* loop) {
 int uv__platform_loop_init(uv_loop_t* loop) {
   return uv__kqueue_init(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) {
 int uv_resident_set_memory(size_t* rss) {
   struct kinfo_proc kinfo;
   struct kinfo_proc kinfo;
   size_t page_size = getpagesize();
   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;
   } msg;
 
 
   /* initialize message queue */
   /* 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)
   if (lst->msg_queue == -1)
     abort();
     abort();
 
 
@@ -255,12 +255,13 @@ int epoll_ctl(uv__os390_epoll* lst,
     lst->items[fd].events = event->events;
     lst->items[fd].events = event->events;
     lst->items[fd].revents = 0;
     lst->items[fd].revents = 0;
   } else if (op == EPOLL_CTL_MOD) {
   } 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);
       uv_mutex_unlock(&global_epoll_lock);
       errno = ENOENT;
       errno = ENOENT;
       return -1;
       return -1;
     }
     }
     lst->items[fd].events = event->events;
     lst->items[fd].events = event->events;
+    lst->items[fd].revents = 0;
   } else
   } else
     abort();
     abort();
 
 
@@ -275,8 +276,9 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
   struct pollfd* pfds;
   struct pollfd* pfds;
   int pollret;
   int pollret;
   int reventcount;
   int reventcount;
+  int nevents;
 
 
-  size = _SET_FDS_MSGS(size, 1, lst->size - 1);
+  _SET_FDS_MSGS(size, 1, lst->size - 1);
   pfds = lst->items;
   pfds = lst->items;
   pollret = poll(pfds, size, timeout);
   pollret = poll(pfds, size, timeout);
   if (pollret <= 0)
   if (pollret <= 0)
@@ -285,19 +287,28 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
   pollret = _NFDS(pollret) + _NMSGS(pollret);
   pollret = _NFDS(pollret) + _NMSGS(pollret);
 
 
   reventcount = 0;
   reventcount = 0;
+  nevents = 0;
   for (int i = 0; 
   for (int i = 0; 
        i < lst->size && i < maxevents && reventcount < pollret; ++i) {
        i < lst->size && i < maxevents && reventcount < pollret; ++i) {
     struct epoll_event ev;
     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;
       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) {
 size_t strnlen(const char* str, size_t maxlen) {
-  void* p = memchr(str, 0, maxlen);
+  char* p = memchr(str, 0, maxlen);
   if (p == NULL)
   if (p == NULL)
     return maxlen;
     return maxlen;
   else
   else

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

@@ -36,10 +36,6 @@
 #define MAX_ITEMS_PER_EPOLL       1024
 #define MAX_ITEMS_PER_EPOLL       1024
 
 
 #define UV__O_CLOEXEC             0x80000
 #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 {
 struct epoll_event {
   int events;
   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');
   assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A');
 
 
   /* Get the offset from the lowest 3 bytes */
   /* 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) {
   if (Output_path->len >= len) {
     errno = ENOBUFS;
     errno = ENOBUFS;
     return -1;
     return -1;
   }
   }
 
 
-  strncpy(buf, Output_path->path, len);
+  uv__strscpy(buf, Output_path->path, len);
 
 
   return 0;
   return 0;
 }
 }
@@ -357,13 +357,11 @@ uint64_t uv_get_total_memory(void) {
 
 
 
 
 int uv_resident_set_memory(size_t* rss) {
 int uv_resident_set_memory(size_t* rss) {
-  char* psa;
   char* ascb;
   char* ascb;
   char* rax;
   char* rax;
   size_t nframes;
   size_t nframes;
 
 
-  psa = PSA_PTR;
-  ascb  = *(char* __ptr32 *)(psa + PSAAOLD);
+  ascb  = *(char* __ptr32 *)(PSA_PTR + PSAAOLD);
   rax = *(char* __ptr32 *)(ascb + ASCBRSME);
   rax = *(char* __ptr32 *)(ascb + ASCBRSME);
   nframes = *(unsigned int*)(rax + RAXFMCT);
   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 */
     /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
 
 
     address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
     address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
-
+    memset(address->phys_addr, 0, sizeof(address->phys_addr));
     address++;
     address++;
   }
   }
 
 
@@ -531,12 +529,14 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   struct ifreq* p;
   struct ifreq* p;
   int count_v6;
   int count_v6;
 
 
+  *count = 0;
+  *addresses = NULL;
+
   /* get the ipv6 addresses first */
   /* get the ipv6 addresses first */
   uv_interface_address_t* addresses_v6;
   uv_interface_address_t* addresses_v6;
   uv__interface_addresses_v6(&addresses_v6, &count_v6);
   uv__interface_addresses_v6(&addresses_v6, &count_v6);
 
 
   /* now get the ipv4 addresses */
   /* now get the ipv4 addresses */
-  *count = 0;
 
 
   /* Assume maximum buffer size allowable */
   /* Assume maximum buffer size allowable */
   maxsize = 16384;
   maxsize = 16384;
@@ -578,6 +578,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
     (*count)++;
     (*count)++;
   }
   }
 
 
+  if (*count == 0) {
+    uv__close(sockfd);
+    return 0;
+  }
+
   /* Alloc the return interface structs */
   /* Alloc the return interface structs */
   *addresses = uv__malloc((*count + count_v6) *
   *addresses = uv__malloc((*count + count_v6) *
                           sizeof(uv_interface_address_t));
                           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;
     address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
+    memset(address->phys_addr, 0, sizeof(address->phys_addr));
     address++;
     address++;
   }
   }
 
 
@@ -662,7 +668,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
 
 
   /* Remove the file descriptor from the epoll. */
   /* Remove the file descriptor from the epoll. */
   if (loop->ep != NULL)
   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,
   memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok,
          sizeof(handle->rfis_rftok));
          sizeof(handle->rfis_rftok));
 
 
-  /* 
+  /*
    * This call will take "/" as the path argument in case we
    * This call will take "/" as the path argument in case we
    * don't care to supply the correct path. The system will simply
    * don't care to supply the correct path. The system will simply
    * ignore it.
    * ignore it.
@@ -838,9 +844,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
     e.fd = w->fd;
     e.fd = w->fd;
 
 
     if (w->events == 0)
     if (w->events == 0)
-      op = UV__EPOLL_CTL_ADD;
+      op = EPOLL_CTL_ADD;
     else
     else
-      op = UV__EPOLL_CTL_MOD;
+      op = EPOLL_CTL_MOD;
 
 
     /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
     /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
      * events, skip the syscall and squelch the events after epoll_wait().
      * 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)
       if (errno != EEXIST)
         abort();
         abort();
 
 
-      assert(op == UV__EPOLL_CTL_ADD);
+      assert(op == EPOLL_CTL_ADD);
 
 
       /* We've reactivated a file descriptor that's been watched before. */
       /* 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();
         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
          * Ignore all errors because we may be racing with another thread
          * when the file descriptor is closed.
          * 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;
         continue;
       }
       }
 
 
@@ -987,7 +993,7 @@ void uv__set_process_title(const char* title) {
 }
 }
 
 
 int uv__io_fork(uv_loop_t* loop) {
 int uv__io_fork(uv_loop_t* loop) {
-  /* 
+  /*
     Nullify the msg queue but don't close it because
     Nullify the msg queue but don't close it because
     it is still being used by the parent.
     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;
   sockfd = err;
 
 
   memset(&saddr, 0, sizeof saddr);
   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;
   saddr.sun_family = AF_UNIX;
 
 
   if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
   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 uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
+  int flags;
+  int mode;
   int err;
   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);
   err = uv__nonblock(fd, 1);
   if (err)
   if (err)
@@ -144,9 +156,13 @@ int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
     return err;
     return err;
 #endif /* defined(__APPLE__) */
 #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);
   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;
   saddr.sun_family = AF_UNIX;
 
 
   do {
   do {
@@ -196,7 +211,7 @@ void uv_pipe_connect(uv_connect_t* req,
   if (new_sock) {
   if (new_sock) {
     err = uv__stream_open((uv_stream_t*)handle,
     err = uv__stream_open((uv_stream_t*)handle,
                           uv__stream_fd(handle),
                           uv__stream_fd(handle),
-                          UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+                          UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
   }
   }
 
 
   if (err == 0)
   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 uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
   int err;
   int err;
 
 
+  if (uv__fd_exists(loop, fd))
+    return UV_EEXIST;
+
   err = uv__io_check_fd(loop, fd);
   err = uv__io_check_fd(loop, fd);
   if (err)
   if (err)
     return 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;
   flags = 0;
   if (container->flags & UV_WRITABLE_PIPE)
   if (container->flags & UV_WRITABLE_PIPE)
-    flags |= UV_STREAM_READABLE;
+    flags |= UV_HANDLE_READABLE;
   if (container->flags & UV_READABLE_PIPE)
   if (container->flags & UV_READABLE_PIPE)
-    flags |= UV_STREAM_WRITABLE;
+    flags |= UV_HANDLE_WRITABLE;
 
 
   return uv__stream_open(container->data.stream, pipefds[0], flags);
   return uv__stream_open(container->data.stream, pipefds[0], flags);
 }
 }

+ 4 - 0
src/unix/proctitle.c

@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 
 
+extern void uv__set_process_title_platform_init(void);
 extern void uv__set_process_title(const char* title);
 extern void uv__set_process_title(const char* title);
 
 
 static uv_mutex_t process_title_mutex;
 static uv_mutex_t process_title_mutex;
@@ -38,6 +39,9 @@ static struct {
 
 
 static void init_process_title_mutex_once(void) {
 static void init_process_title_mutex_once(void) {
   uv_mutex_init(&process_title_mutex);
   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 uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT;
 static struct uv__signal_tree_s uv__signal_tree =
 static struct uv__signal_tree_s uv__signal_tree =
     RB_INITIALIZER(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,
 RB_GENERATE_STATIC(uv__signal_tree_s,
                    uv_signal_s, tree_entry,
                    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_reinit(void);
 
 
 static void uv__signal_global_init(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
     /* pthread_atfork can register before and after handlers, one
      * for each child. This only registers one for the child. That
      * for each child. This only registers one for the child. That
      * state is both persistent and cumulative, so if we keep doing
      * 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))
     if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit))
       abort();
       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.
   /* We can only use signal-safe functions here.
    * That includes read/write and close, fortunately.
    * That includes read/write and close, fortunately.
    * We do all of this directly here instead of resetting
    * 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
    * uv__signal_global_once_init is only called from uv_loop_init
    * and this needs to function in existing loops.
    * 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) {
 static int uv__signal_lock(void) {
   int r;
   int r;
   char data;
   char data;
@@ -387,7 +396,7 @@ static int uv__signal_start(uv_signal_t* handle,
    */
    */
   first_handle = uv__signal_first_handle(signum);
   first_handle = uv__signal_first_handle(signum);
   if (first_handle == NULL ||
   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);
     err = uv__signal_register_handler(signum, oneshot);
     if (err) {
     if (err) {
       /* Registering the signal handler failed. Must be an invalid signal. */
       /* 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;
   handle->signum = signum;
   if (oneshot)
   if (oneshot)
-    handle->flags |= UV__SIGNAL_ONE_SHOT;
+    handle->flags |= UV_SIGNAL_ONE_SHOT;
 
 
   RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
   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;
       handle = msg->handle;
 
 
       if (msg->signum == handle->signum) {
       if (msg->signum == handle->signum) {
-        assert(!(handle->flags & UV_CLOSING));
+        assert(!(handle->flags & UV_HANDLE_CLOSING));
         handle->signal_cb(handle, handle->signum);
         handle->signal_cb(handle, handle->signum);
       }
       }
 
 
       handle->dispatched_signals++;
       handle->dispatched_signals++;
 
 
-      if (handle->flags & UV__SIGNAL_ONE_SHOT)
+      if (handle->flags & UV_SIGNAL_ONE_SHOT)
         uv__signal_stop(handle);
         uv__signal_stop(handle);
 
 
       /* If uv_close was called while there were caught signals that were not
       /* If uv_close was called while there were caught signals that were not
        * yet dispatched, the uv__finish_close was deferred. Make close pending
        * yet dispatched, the uv__finish_close was deferred. Make close pending
        * now if this has happened.
        * now if this has happened.
        */
        */
-      if ((handle->flags & UV_CLOSING) &&
+      if ((handle->flags & UV_HANDLE_CLOSING) &&
           (handle->caught_signals == handle->dispatched_signals)) {
           (handle->caught_signals == handle->dispatched_signals)) {
         uv__make_close_pending((uv_handle_t*) handle);
         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;
   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.
    * 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;
   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) {
   if (first_handle == NULL) {
     uv__signal_unregister_handler(handle->signum);
     uv__signal_unregister_handler(handle->signum);
   } else {
   } 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) {
     if (first_oneshot && !rem_oneshot) {
       ret = uv__signal_register_handler(handle->signum, 1);
       ret = uv__signal_register_handler(handle->signum, 1);
       assert(ret == 0);
       assert(ret == 0);

+ 124 - 138
src/unix/stream.c

@@ -58,11 +58,19 @@ struct uv__stream_select_s {
   fd_set* swrite;
   fd_set* swrite;
   size_t swrite_sz;
   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 == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \
-     (errno == EMSGSIZE && send_handle))
+     (errno == EMSGSIZE && send_handle != NULL))
 #else
 #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)
     (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
 #endif /* defined(__APPLE__) */
 #endif /* defined(__APPLE__) */
 
 
@@ -220,7 +228,7 @@ static void uv__stream_osx_select(void* arg) {
       uv_sem_wait(&s->async_sem);
       uv_sem_wait(&s->async_sem);
 
 
       /* Should be processed at this stage */
       /* 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))
   if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT))
     uv__stream_io(stream->loop, &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;
     return;
 
 
   /* NOTE: It is important to do it here, otherwise `select()` might be called
   /* 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)
   if (err)
     goto failed_async_init;
     goto failed_async_init;
 
 
-  s->async.flags |= UV__HANDLE_INTERNAL;
+  s->async.flags |= UV_HANDLE_INTERNAL;
   uv__handle_unref(&s->async);
   uv__handle_unref(&s->async);
 
 
   err = uv_sem_init(&s->close_sem, 0);
   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;
   stream->flags |= flags;
 
 
   if (stream->type == UV_TCP) {
   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);
       return UV__ERR(errno);
 
 
     /* TODO Use delay the user passed in. */
     /* 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);
       return UV__ERR(errno);
+    }
   }
   }
 
 
 #if defined(__APPLE__)
 #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) {
 void uv__stream_destroy(uv_stream_t* stream) {
   assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT));
   assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT));
-  assert(stream->flags & UV_CLOSED);
+  assert(stream->flags & UV_HANDLE_CLOSED);
 
 
   if (stream->connect_req) {
   if (stream->connect_req) {
     uv__req_unregister(stream->loop, 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);
   stream = container_of(w, uv_stream_t, io_watcher);
   assert(events & POLLIN);
   assert(events & POLLIN);
   assert(stream->accepted_fd == -1);
   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);
   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;
       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. */
       /* Give other processes a chance to accept connections. */
       struct timespec timeout = { 0, 1 };
       struct timespec timeout = { 0, 1 };
       nanosleep(&timeout, NULL);
       nanosleep(&timeout, NULL);
@@ -590,7 +601,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
     case UV_TCP:
     case UV_TCP:
       err = uv__stream_open(client,
       err = uv__stream_open(client,
                             server->accepted_fd,
                             server->accepted_fd,
-                            UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+                            UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
       if (err) {
       if (err) {
         /* TODO handle error */
         /* TODO handle error */
         uv__close(server->accepted_fd);
         uv__close(server->accepted_fd);
@@ -674,14 +685,14 @@ static void uv__drain(uv_stream_t* stream) {
   uv__stream_osx_interrupt_select(stream);
   uv__stream_osx_interrupt_select(stream);
 
 
   /* Shutdown? */
   /* 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);
     assert(stream->shutdown_req);
 
 
     req = stream->shutdown_req;
     req = stream->shutdown_req;
     stream->shutdown_req = NULL;
     stream->shutdown_req = NULL;
-    stream->flags &= ~UV_STREAM_SHUTTING;
+    stream->flags &= ~UV_HANDLE_SHUTTING;
     uv__req_unregister(stream->loop, req);
     uv__req_unregister(stream->loop, req);
 
 
     err = 0;
     err = 0;
@@ -689,7 +700,7 @@ static void uv__drain(uv_stream_t* stream) {
       err = UV__ERR(errno);
       err = UV__ERR(errno);
 
 
     if (err == 0)
     if (err == 0)
-      stream->flags |= UV_STREAM_SHUT;
+      stream->flags |= UV_HANDLE_SHUT;
 
 
     if (req->cb != NULL)
     if (req->cb != NULL)
       req->cb(req, err);
       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) {
 static size_t uv__write_req_size(uv_write_t* req) {
   size_t size;
   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) {
 static void uv__write_req_finish(uv_write_t* req) {
   uv_stream_t* stream = req->handle;
   uv_stream_t* stream = req->handle;
 
 
@@ -829,102 +879,32 @@ start:
       *pi = fd_to_send;
       *pi = fd_to_send;
     }
     }
 
 
-    do {
+    do
       n = sendmsg(uv__stream_fd(stream), &msg, 0);
       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 {
   } 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. */
   /* We're not done. */
   uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
   uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
@@ -947,10 +927,16 @@ error:
 static void uv__write_callbacks(uv_stream_t* stream) {
 static void uv__write_callbacks(uv_stream_t* stream) {
   uv_write_t* req;
   uv_write_t* req;
   QUEUE* q;
   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. */
     /* 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);
     req = QUEUE_DATA(q, uv_write_t, queue);
     QUEUE_REMOVE(q);
     QUEUE_REMOVE(q);
     uv__req_unregister(stream->loop, req);
     uv__req_unregister(stream->loop, req);
@@ -966,8 +952,6 @@ static void uv__write_callbacks(uv_stream_t* stream) {
     if (req->cb)
     if (req->cb)
       req->cb(req, req->error);
       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) {
 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);
   uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
   if (!uv__io_active(&stream->io_watcher, POLLOUT))
   if (!uv__io_active(&stream->io_watcher, POLLOUT))
     uv__handle_stop(stream);
     uv__handle_stop(stream);
   uv__stream_osx_interrupt_select(stream);
   uv__stream_osx_interrupt_select(stream);
   stream->read_cb(stream, UV_EOF, buf);
   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__
 #ifdef __clang__
 # pragma clang diagnostic push
 # pragma clang diagnostic push
 # pragma clang diagnostic ignored "-Wgnu-folding-constant"
 # pragma clang diagnostic ignored "-Wgnu-folding-constant"
+# pragma clang diagnostic ignored "-Wvla-extension"
 #endif
 #endif
 
 
 static void uv__read(uv_stream_t* stream) {
 static void uv__read(uv_stream_t* stream) {
@@ -1132,7 +1117,7 @@ static void uv__read(uv_stream_t* stream) {
   int err;
   int err;
   int is_ipc;
   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)
   /* 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.
    * 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;
   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?
    * tcp->read_cb is NULL or not?
    */
    */
   while (stream->read_cb
   while (stream->read_cb
-      && (stream->flags & UV_STREAM_READING)
+      && (stream->flags & UV_HANDLE_READING)
       && (count-- > 0)) {
       && (count-- > 0)) {
     assert(stream->alloc_cb != NULL);
     assert(stream->alloc_cb != NULL);
 
 
@@ -1186,7 +1171,7 @@ static void uv__read(uv_stream_t* stream) {
       /* Error */
       /* Error */
       if (errno == EAGAIN || errno == EWOULDBLOCK) {
       if (errno == EAGAIN || errno == EWOULDBLOCK) {
         /* Wait for the next one. */
         /* 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__io_start(stream->loop, &stream->io_watcher, POLLIN);
           uv__stream_osx_interrupt_select(stream);
           uv__stream_osx_interrupt_select(stream);
         }
         }
@@ -1199,8 +1184,8 @@ static void uv__read(uv_stream_t* stream) {
       } else {
       } else {
         /* Error. User should call uv_close(). */
         /* Error. User should call uv_close(). */
         stream->read_cb(stream, UV__ERR(errno), &buf);
         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);
           uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
           if (!uv__io_active(&stream->io_watcher, POLLOUT))
           if (!uv__io_active(&stream->io_watcher, POLLOUT))
             uv__handle_stop(stream);
             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. */
       /* Return if we didn't fill the buffer, there is no more data to read. */
       if (nread < buflen) {
       if (nread < buflen) {
-        stream->flags |= UV_STREAM_READ_PARTIAL;
+        stream->flags |= UV_HANDLE_READ_PARTIAL;
         return;
         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_TTY ||
          stream->type == UV_NAMED_PIPE);
          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)) {
       uv__is_closing(stream)) {
     return UV_ENOTCONN;
     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->handle = stream;
   req->cb = cb;
   req->cb = cb;
   stream->shutdown_req = req;
   stream->shutdown_req = req;
-  stream->flags |= UV_STREAM_SHUTTING;
+  stream->flags |= UV_HANDLE_SHUTTING;
 
 
   uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
   uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
   uv__stream_osx_interrupt_select(stream);
   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 ||
   assert(stream->type == UV_TCP ||
          stream->type == UV_NAMED_PIPE ||
          stream->type == UV_NAMED_PIPE ||
          stream->type == UV_TTY);
          stream->type == UV_TTY);
-  assert(!(stream->flags & UV_CLOSING));
+  assert(!(stream->flags & UV_HANDLE_CLOSING));
 
 
   if (stream->connect_req) {
   if (stream->connect_req) {
     uv__stream_connect(stream);
     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);
   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))
   if (events & (POLLIN | POLLERR | POLLHUP))
     uv__read(stream);
     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.
    * report the EOF yet because there is still data to read.
    */
    */
   if ((events & POLLHUP) &&
   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_buf_t buf = { NULL, 0 };
     uv__stream_eof(stream, &buf);
     uv__stream_eof(stream, &buf);
   }
   }
@@ -1417,7 +1402,7 @@ int uv_write2(uv_write_t* req,
   if (uv__stream_fd(stream) < 0)
   if (uv__stream_fd(stream) < 0)
     return UV_EBADF;
     return UV_EBADF;
 
 
-  if (!(stream->flags & UV_STREAM_WRITABLE))
+  if (!(stream->flags & UV_HANDLE_WRITABLE))
     return -EPIPE;
     return -EPIPE;
 
 
   if (send_handle) {
   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
      * if this assert fires then somehow the blocking stream isn't being
      * sufficiently flushed in uv__write.
      * 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__io_start(stream->loop, &stream->io_watcher, POLLOUT);
     uv__stream_osx_interrupt_select(stream);
     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 ||
   assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
       stream->type == UV_TTY);
       stream->type == UV_TTY);
 
 
-  if (stream->flags & UV_CLOSING)
+  if (stream->flags & UV_HANDLE_CLOSING)
     return UV_EINVAL;
     return UV_EINVAL;
 
 
-  if (!(stream->flags & UV_STREAM_READABLE))
+  if (!(stream->flags & UV_HANDLE_READABLE))
     return -ENOTCONN;
     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.
    * 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: try to do the read inline? */
   /* TODO: keep track of tcp state. If we've gotten a EOF then we should
   /* 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) {
 int uv_read_stop(uv_stream_t* stream) {
-  if (!(stream->flags & UV_STREAM_READING))
+  if (!(stream->flags & UV_HANDLE_READING))
     return 0;
     return 0;
 
 
-  stream->flags &= ~UV_STREAM_READING;
+  stream->flags &= ~UV_HANDLE_READING;
   uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
   uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
   if (!uv__io_active(&stream->io_watcher, POLLOUT))
   if (!uv__io_active(&stream->io_watcher, POLLOUT))
     uv__handle_stop(stream);
     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) {
 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) {
 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__io_close(handle->loop, &handle->io_watcher);
   uv_read_stop(handle);
   uv_read_stop(handle);
   uv__handle_stop(handle);
   uv__handle_stop(handle);
+  handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
 
 
   if (handle->io_watcher.fd != -1) {
   if (handle->io_watcher.fd != -1) {
     /* Don't close stdio file descriptors.  Nothing good comes from it. */
     /* 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
 #ifdef SUNOS_NO_IFADDRS
 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+  *count = 0;
+  *addresses = NULL;
   return UV_ENOSYS;
   return UV_ENOSYS;
 }
 }
 #else  /* SUNOS_NO_IFADDRS */
 #else  /* SUNOS_NO_IFADDRS */
@@ -705,13 +707,14 @@ static int uv__set_phys_addr(uv_interface_address_t* address,
 
 
   struct sockaddr_dl* sa_addr;
   struct sockaddr_dl* sa_addr;
   int sockfd;
   int sockfd;
-  int i;
+  size_t i;
   struct arpreq arpreq;
   struct arpreq arpreq;
 
 
   /* This appears to only work as root */
   /* This appears to only work as root */
   sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
   sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
   memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
   memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
   for (i = 0; i < sizeof(address->phys_addr); i++) {
   for (i = 0; i < sizeof(address->phys_addr); i++) {
+    /* Check that all bytes of phys_addr are zero. */
     if (address->phys_addr[i] != 0)
     if (address->phys_addr[i] != 0)
       return 0;
       return 0;
   }
   }
@@ -758,11 +761,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   struct ifaddrs* addrs;
   struct ifaddrs* addrs;
   struct ifaddrs* ent;
   struct ifaddrs* ent;
 
 
+  *count = 0;
+  *addresses = NULL;
+
   if (getifaddrs(&addrs))
   if (getifaddrs(&addrs))
     return UV__ERR(errno);
     return UV__ERR(errno);
 
 
-  *count = 0;
-
   /* Count the number of interfaces */
   /* Count the number of interfaces */
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
     if (uv__ifaddr_exclude(ent))
     if (uv__ifaddr_exclude(ent))
@@ -770,6 +774,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
     (*count)++;
     (*count)++;
   }
   }
 
 
+  if (*count == 0) {
+    freeifaddrs(addrs);
+    return 0;
+  }
+
   *addresses = uv__malloc(*count * sizeof(**addresses));
   *addresses = uv__malloc(*count * sizeof(**addresses));
   if (!(*addresses)) {
   if (!(*addresses)) {
     freeifaddrs(addrs);
     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,
   err = maybe_new_socket(handle,
                          addr->sa_family,
                          addr->sa_family,
-                         UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+                         UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
   if (err)
   if (err)
     return 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 uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
   int err;
   int err;
 
 
+  if (uv__fd_exists(handle->loop, sock))
+    return UV_EEXIST;
+
   err = uv__nonblock(sock, 1);
   err = uv__nonblock(sock, 1);
   if (err)
   if (err)
     return err;
     return err;
 
 
   return uv__stream_open((uv_stream_t*)handle,
   return uv__stream_open((uv_stream_t*)handle,
                          sock,
                          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)
   if (single_accept)
-    tcp->flags |= UV_TCP_SINGLE_ACCEPT;
+    tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
 
 
   flags = 0;
   flags = 0;
 #if defined(__MVS__)
 #if defined(__MVS__)
@@ -398,9 +401,9 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
   }
   }
 
 
   if (on)
   if (on)
-    handle->flags |= UV_TCP_NODELAY;
+    handle->flags |= UV_HANDLE_TCP_NODELAY;
   else
   else
-    handle->flags &= ~UV_TCP_NODELAY;
+    handle->flags &= ~UV_HANDLE_TCP_NODELAY;
 
 
   return 0;
   return 0;
 }
 }
@@ -416,9 +419,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
   }
   }
 
 
   if (on)
   if (on)
-    handle->flags |= UV_TCP_KEEPALIVE;
+    handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
   else
   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
   /* 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...
    *      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) {
 int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
   if (enable)
   if (enable)
-    handle->flags &= ~UV_TCP_SINGLE_ACCEPT;
+    handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT;
   else
   else
-    handle->flags |= UV_TCP_SINGLE_ACCEPT;
+    handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
   return 0;
   return 0;
 }
 }
 
 

+ 69 - 77
src/unix/thread.c

@@ -44,108 +44,119 @@
 #undef NANOSEC
 #undef NANOSEC
 #define NANOSEC ((uint64_t) 1e9)
 #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;
   int rc;
-  _uv_barrier* b;
 
 
   if (barrier == NULL || count == 0)
   if (barrier == NULL || count == 0)
-    return EINVAL;
-
-  if (barrier_attr != NULL)
-    return ENOTSUP;
+    return UV_EINVAL;
 
 
   b = uv__malloc(sizeof(*b));
   b = uv__malloc(sizeof(*b));
   if (b == NULL)
   if (b == NULL)
-    return ENOMEM;
+    return UV_ENOMEM;
 
 
   b->in = 0;
   b->in = 0;
   b->out = 0;
   b->out = 0;
   b->threshold = count;
   b->threshold = count;
 
 
-  if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
+  rc = uv_mutex_init(&b->mutex);
+  if (rc != 0)
     goto error2;
     goto error2;
-  if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
+
+  rc = uv_cond_init(&b->cond);
+  if (rc != 0)
     goto error;
     goto error;
 
 
   barrier->b = b;
   barrier->b = b;
   return 0;
   return 0;
 
 
 error:
 error:
-  pthread_mutex_destroy(&b->mutex);
+  uv_mutex_destroy(&b->mutex);
 error2:
 error2:
   uv__free(b);
   uv__free(b);
   return rc;
   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)
   if (barrier == NULL || barrier->b == NULL)
-    return EINVAL;
+    return UV_EINVAL;
 
 
   b = barrier->b;
   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) {
   if (++b->in == b->threshold) {
     b->in = 0;
     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;
   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);
   uv__free(barrier->b);
   barrier->b = NULL;
   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
 #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) {
 int uv_key_create(uv_key_t* key) {
   return UV__ERR(pthread_key_create(key, NULL));
   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;
   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;
   uv_handle_type type;
   int flags;
   int flags;
   int newfd;
   int newfd;
   int r;
   int r;
   int saved_flags;
   int saved_flags;
+  int mode;
   char path[256];
   char path[256];
+  (void)unused; /* deprecated parameter is no longer needed */
 
 
   /* File descriptors that refer to files cannot be monitored with epoll.
   /* File descriptors that refer to files cannot be monitored with epoll.
    * That restriction also applies to character devices like /dev/random
    * 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;
   flags = 0;
   newfd = -1;
   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
   /* 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
    * tty in non-blocking mode without affecting other processes that share it
    * with us.
    * with us.
@@ -128,14 +139,14 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
      * slave device.
      * slave device.
      */
      */
     if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
     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
     else
       r = -1;
       r = -1;
 
 
     if (r < 0) {
     if (r < 0) {
       /* fallback to using blocking writes */
       /* fallback to using blocking writes */
-      if (!readable)
-        flags |= UV_STREAM_BLOCKING;
+      if (mode != O_RDONLY)
+        flags |= UV_HANDLE_BLOCKING_WRITES;
       goto skip;
       goto skip;
     }
     }
 
 
@@ -154,22 +165,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
     fd = newfd;
     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:
 skip:
   uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
   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.
    * 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);
     uv__nonblock(fd, 1);
 
 
 #if defined(__APPLE__)
 #if defined(__APPLE__)
@@ -194,10 +189,10 @@ skip:
   }
   }
 #endif
 #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);
   uv__stream_open((uv_stream_t*) tty, fd, flags);
   tty->mode = UV_TTY_MODE_NORMAL;
   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;
   uv_udp_send_t* req;
   QUEUE* q;
   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)) {
   while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
     q = QUEUE_HEAD(&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);
       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);
   QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
   uv__handle_start(handle);
   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(handle);
 
 
     /* `uv__udp_sendmsg` may not be able to do non-blocking write straight
     /* `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)
   if (handle->io_watcher.fd != -1)
     return UV_EBUSY;
     return UV_EBUSY;
 
 
+  if (uv__fd_exists(handle->loop, sock))
+    return UV_EEXIST;
+
   err = uv__nonblock(sock, 1);
   err = uv__nonblock(sock, 1);
   if (err)
   if (err)
     return 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,
  * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
  * and use the general uv__setsockopt_maybe_char call otherwise.
  * 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)
   if (handle->flags & UV_HANDLE_IPV6)
     return uv__setsockopt(handle,
     return uv__setsockopt(handle,
                           IP_MULTICAST_TTL,
                           IP_MULTICAST_TTL,
                           IPV6_MULTICAST_HOPS,
                           IPV6_MULTICAST_HOPS,
                           &ttl,
                           &ttl,
                           sizeof(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,
   return uv__setsockopt_maybe_char(handle,
                                    IP_MULTICAST_TTL,
                                    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,
  * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
  * and use the general uv__setsockopt_maybe_char call otherwise.
  * 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)
   if (handle->flags & UV_HANDLE_IPV6)
     return uv__setsockopt(handle,
     return uv__setsockopt(handle,
                           IP_MULTICAST_LOOP,
                           IP_MULTICAST_LOOP,
                           IPV6_MULTICAST_LOOP,
                           IPV6_MULTICAST_LOOP,
                           &on,
                           &on,
                           sizeof(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,
   return uv__setsockopt_maybe_char(handle,
                                    IP_MULTICAST_LOOP,
                                    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) {
 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) {
 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) {
 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,
 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";
   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;
 #define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
 const char* uv_err_name(int err) {
 const char* uv_err_name(int err) {
@@ -166,6 +183,19 @@ const char* uv_err_name(int err) {
 #undef UV_ERR_NAME_GEN
 #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;
 #define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;
 const char* uv_strerror(int err) {
 const char* uv_strerror(int err) {
   switch (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_REMOVE(q);
     QUEUE_INSERT_TAIL(&loop->handle_queue, 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);
     walk_cb(h, arg);
   }
   }
 }
 }
@@ -386,9 +416,9 @@ static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
 
 
     fprintf(stream,
     fprintf(stream,
             "[%c%c%c] %-8s %p\n",
             "[%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,
             type,
             (void*)h);
             (void*)h);
   }
   }
@@ -632,7 +662,7 @@ int uv_loop_close(uv_loop_t* loop) {
 
 
   QUEUE_FOREACH(q, &loop->handle_queue) {
   QUEUE_FOREACH(q, &loop->handle_queue) {
     h = QUEUE_DATA(q, uv_handle_t, 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;
       return UV_EBUSY;
   }
   }
 
 

+ 91 - 36
src/uv-common.h

@@ -32,14 +32,15 @@
 #include <stddef.h>
 #include <stddef.h>
 
 
 #if defined(_MSC_VER) && _MSC_VER < 1600
 #if defined(_MSC_VER) && _MSC_VER < 1600
-# include "stdint-msvc2008.h"
+# include "uv/stdint-msvc2008.h"
 #else
 #else
 # include <stdint.h>
 # include <stdint.h>
 #endif
 #endif
 
 
 #include "uv.h"
 #include "uv.h"
-#include "tree.h"
+#include "uv/tree.h"
 #include "queue.h"
 #include "queue.h"
+#include "strscpy.h"
 
 
 #if EDOM > 0
 #if EDOM > 0
 # define UV__ERR(x) (-(x))
 # define UV__ERR(x) (-(x))
@@ -59,22 +60,67 @@ extern int snprintf(char*, size_t, const char*, ...);
 #define STATIC_ASSERT(expr)                                                   \
 #define STATIC_ASSERT(expr)                                                   \
   void uv__static_assert(int static_assert_failed[1 - 2 * !(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 {
 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);
 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. */
 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,
 void uv__work_submit(uv_loop_t* loop,
                      struct uv__work *w,
                      struct uv__work *w,
+                     enum uv__work_kind kind,
                      void (*work)(struct uv__work *w),
                      void (*work)(struct uv__work *w),
                      void (*done)(struct uv__work *w, int status));
                      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);
 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)                                             \
 #define uv__has_active_reqs(loop)                                             \
   ((loop)->active_reqs.count > 0)
   ((loop)->active_reqs.count > 0)
 
 
@@ -164,49 +221,47 @@ void uv__fs_scandir_cleanup(uv_fs_t* req);
   while (0)
   while (0)
 
 
 #define uv__is_active(h)                                                      \
 #define uv__is_active(h)                                                      \
-  (((h)->flags & UV__HANDLE_ACTIVE) != 0)
+  (((h)->flags & UV_HANDLE_ACTIVE) != 0)
 
 
 #define uv__is_closing(h)                                                     \
 #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)                                                   \
 #define uv__handle_start(h)                                                   \
   do {                                                                        \
   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)
   while (0)
 
 
 #define uv__handle_stop(h)                                                    \
 #define uv__handle_stop(h)                                                    \
   do {                                                                        \
   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)
   while (0)
 
 
 #define uv__handle_ref(h)                                                     \
 #define uv__handle_ref(h)                                                     \
   do {                                                                        \
   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)
   while (0)
 
 
 #define uv__handle_unref(h)                                                   \
 #define uv__handle_unref(h)                                                   \
   do {                                                                        \
   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)
   while (0)
 
 
 #define uv__has_ref(h)                                                        \
 #define uv__has_ref(h)                                                        \
-  (((h)->flags & UV__HANDLE_REF) != 0)
+  (((h)->flags & UV_HANDLE_REF) != 0)
 
 
 #if defined(_WIN32)
 #if defined(_WIN32)
 # define uv__handle_platform_init(h) ((h)->u.fd = -1)
 # define uv__handle_platform_init(h) ((h)->u.fd = -1)
@@ -218,7 +273,7 @@ void uv__fs_scandir_cleanup(uv_fs_t* req);
   do {                                                                        \
   do {                                                                        \
     (h)->loop = (loop_);                                                      \
     (h)->loop = (loop_);                                                      \
     (h)->type = (type_);                                                      \
     (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);            \
     QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue);            \
     uv__handle_platform_init(h);                                              \
     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) {
 const char* uv_handle_type_name(uv_handle_type type) {
   switch (type) {
   switch (type) {
 #define XX(uc,lc) case UV_##uc: return #lc;
 #define XX(uc,lc) case UV_##uc: return #lc;
-    UV_HANDLE_TYPE_MAP(XX)
+  UV_HANDLE_TYPE_MAP(XX)
 #undef 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;
   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) {
 const char* uv_req_type_name(uv_req_type type) {
   switch (type) {
   switch (type) {
 #define XX(uc,lc) case UV_##uc: return #lc;
 #define XX(uc,lc) case UV_##uc: return #lc;
-    UV_REQ_TYPE_MAP(XX)
+  UV_REQ_TYPE_MAP(XX)
 #undef 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;
   return NULL;
 }
 }

+ 5 - 5
src/win/async.c

@@ -29,7 +29,7 @@
 
 
 
 
 void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
 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) {
       !handle->async_sent) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     uv__handle_close(handle);
     uv__handle_close(handle);
@@ -71,9 +71,9 @@ int uv_async_send(uv_async_t* handle) {
     return -1;
     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)) {
   if (!uv__atomic_exchange_set(&handle->async_sent)) {
     POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
     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;
   handle->async_sent = 0;
 
 
-  if (handle->flags & UV__HANDLE_CLOSING) {
+  if (handle->flags & UV_HANDLE_CLOSING) {
     uv_want_endgame(loop, (uv_handle_t*)handle);
     uv_want_endgame(loop, (uv_handle_t*)handle);
   } else if (handle->async_cb != NULL) {
   } else if (handle->async_cb != NULL) {
     handle->async_cb(handle);
     handle->async_cb(handle);

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

@@ -29,10 +29,10 @@
 /* Atomic set operation on char */
 /* Atomic set operation on char */
 #ifdef _MSC_VER /* MSVC */
 #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)
 #pragma intrinsic(_InterlockedOr8)
 
 
 static char INLINE uv__atomic_exchange_set(char volatile* target) {
 static char INLINE uv__atomic_exchange_set(char volatile* target) {

+ 39 - 19
src/win/core.c

@@ -33,6 +33,7 @@
 #include "internal.h"
 #include "internal.h"
 #include "queue.h"
 #include "queue.h"
 #include "handle-inl.h"
 #include "handle-inl.h"
+#include "heap-inl.h"
 #include "req-inl.h"
 #include "req-inl.h"
 
 
 /* uv_once initialization guards */
 /* uv_once initialization guards */
@@ -221,6 +222,7 @@ static void uv_init(void) {
 
 
 
 
 int uv_loop_init(uv_loop_t* loop) {
 int uv_loop_init(uv_loop_t* loop) {
+  struct heap* timer_heap;
   int err;
   int err;
 
 
   /* Initialize libuv itself first */
   /* Initialize libuv itself first */
@@ -246,7 +248,13 @@ int uv_loop_init(uv_loop_t* loop) {
 
 
   loop->endgame_handles = NULL;
   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->check_handles = NULL;
   loop->prepare_handles = NULL;
   loop->prepare_handles = NULL;
@@ -273,7 +281,7 @@ int uv_loop_init(uv_loop_t* loop) {
     goto fail_async_init;
     goto fail_async_init;
 
 
   uv__handle_unref(&loop->wq_async);
   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);
   err = uv__loops_add(loop);
   if (err)
   if (err)
@@ -285,6 +293,10 @@ fail_async_init:
   uv_mutex_destroy(&loop->wq_mutex);
   uv_mutex_destroy(&loop->wq_mutex);
 
 
 fail_mutex_init:
 fail_mutex_init:
+  uv__free(timer_heap);
+  loop->timer_heap = NULL;
+
+fail_timers_alloc:
   CloseHandle(loop->iocp);
   CloseHandle(loop->iocp);
   loop->iocp = INVALID_HANDLE_VALUE;
   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) {
 void uv__once_init(void) {
   uv_once(&uv_init_guard_, uv_init);
   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_unlock(&loop->wq_mutex);
   uv_mutex_destroy(&loop->wq_mutex);
   uv_mutex_destroy(&loop->wq_mutex);
 
 
+  uv__free(loop->timer_heap);
+  loop->timer_heap = NULL;
+
   CloseHandle(loop->iocp);
   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;
   DWORD bytes;
   ULONG_PTR key;
   ULONG_PTR key;
   OVERLAPPED* overlapped;
   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;
   BOOL success;
   uv_req_t* req;
   uv_req_t* req;
   OVERLAPPED_ENTRY overlappeds[128];
   OVERLAPPED_ENTRY overlappeds[128];
@@ -422,12 +444,12 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
   timeout_time = loop->time + timeout;
   timeout_time = loop->time + timeout;
 
 
   for (repeat = 0; ; repeat++) {
   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) {
     if (success) {
       for (i = 0; i < count; i++) {
       for (i = 0; i < count; i++) {
@@ -485,12 +507,6 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
   DWORD timeout;
   DWORD timeout;
   int r;
   int r;
   int ran_pending;
   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);
   r = uv__loop_alive(loop);
   if (!r)
   if (!r)
@@ -498,7 +514,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
 
 
   while (r != 0 && loop->stop_flag == 0) {
   while (r != 0 && loop->stop_flag == 0) {
     uv_update_time(loop);
     uv_update_time(loop);
-    uv_process_timers(loop);
+    uv__run_timers(loop);
 
 
     ran_pending = uv_process_reqs(loop);
     ran_pending = uv_process_reqs(loop);
     uv_idle_invoke(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)
     if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
       timeout = uv_backend_timeout(loop);
       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_check_invoke(loop);
     uv_process_endgames(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
        * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
        * the check.
        * the check.
        */
        */
-      uv_process_timers(loop);
+      uv__run_timers(loop);
     }
     }
 
 
     r = uv__loop_alive(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) {
 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());
   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){
 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 |
   FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
                  FORMAT_MESSAGE_ARGUMENT_ARRAY |
                  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),
                        MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
                        (LPSTR) &lib->errmsg, 0, NULL);
                        (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 |
     res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                          FORMAT_MESSAGE_FROM_SYSTEM |
                          FORMAT_MESSAGE_FROM_SYSTEM |
                          FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
                          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";
     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) {
   if (syscall) {
     fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
     fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
   } else {
   } 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,
 static int uv_split_path(const WCHAR* filename, WCHAR** dir,
     WCHAR** file) {
     WCHAR** file) {
   size_t len, i;
   size_t len, i;
- 
+
   if (filename == NULL) {
   if (filename == NULL) {
     if (dir != NULL)
     if (dir != NULL)
       *dir = NULL;
       *dir = NULL;
@@ -215,11 +215,11 @@ int uv_fs_event_start(uv_fs_event_t* handle,
         uv__free(long_path);
         uv__free(long_path);
         long_path = NULL;
         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;
     dir_to_watch = pathw;
@@ -230,8 +230,11 @@ int uv_fs_event_start(uv_fs_event_t* handle,
      */
      */
 
 
     /* Convert to short path. */
     /* 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;
       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
    * - We are not active, just ignore the callback
    */
    */
   if (!uv__is_active(handle)) {
   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);
       uv_want_endgame(loop, (uv_handle_t*) handle);
     }
     }
     return;
     return;
@@ -543,7 +546,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
         }
         }
 
 
         offset = file_info->NextEntryOffset;
         offset = file_info->NextEntryOffset;
-      } while (offset && !(handle->flags & UV__HANDLE_CLOSING));
+      } while (offset && !(handle->flags & UV_HANDLE_CLOSING));
     } else {
     } else {
       handle->cb(handle, NULL, UV_CHANGE, 0);
       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));
     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);
     uv_fs_event_queue_readdirchanges(loop, handle);
   } else {
   } else {
     uv_want_endgame(loop, (uv_handle_t*)handle);
     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) {
 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));
     assert(!(handle->flags & UV_HANDLE_CLOSED));
 
 
     if (handle->buffer) {
     if (handle->buffer) {

+ 133 - 51
src/win/fs.c

@@ -55,7 +55,11 @@
   do {                                                                        \
   do {                                                                        \
     if (cb != NULL) {                                                         \
     if (cb != NULL) {                                                         \
       uv__req_register(loop, req);                                            \
       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;                                                               \
       return 0;                                                               \
     } else {                                                                  \
     } else {                                                                  \
       uv__fs_work(&req->work_req);                                            \
       uv__fs_work(&req->work_req);                                            \
@@ -92,14 +96,17 @@
     return;                                                                 \
     return;                                                                 \
   }
   }
 
 
+#define MILLIONu (1000U * 1000U)
+#define BILLIONu (1000U * 1000U * 1000U)
+
 #define FILETIME_TO_UINT(filetime)                                          \
 #define FILETIME_TO_UINT(filetime)                                          \
-   (*((uint64_t*) &(filetime)) - 116444736000000000ULL)
+   (*((uint64_t*) &(filetime)) - (uint64_t) 116444736 * BILLIONu)
 
 
 #define FILETIME_TO_TIME_T(filetime)                                        \
 #define FILETIME_TO_TIME_T(filetime)                                        \
-   (FILETIME_TO_UINT(filetime) / 10000000ULL)
+   (FILETIME_TO_UINT(filetime) / (10u * MILLIONu))
 
 
 #define FILETIME_TO_TIME_NS(filetime, secs)                                 \
 #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)                                  \
 #define FILETIME_TO_TIMESPEC(ts, filetime)                                  \
    do {                                                                     \
    do {                                                                     \
@@ -109,8 +116,8 @@
 
 
 #define TIME_T_TO_FILETIME(time, filetime_ptr)                              \
 #define TIME_T_TO_FILETIME(time, filetime_ptr)                              \
   do {                                                                      \
   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)->dwLowDateTime = bigtime & 0xFFFFFFFF;                   \
     (filetime_ptr)->dwHighDateTime = bigtime >> 32;                         \
     (filetime_ptr)->dwHighDateTime = bigtime >> 32;                         \
   } while(0)
   } while(0)
@@ -326,12 +333,11 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
         reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
         reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
         sizeof(WCHAR);
         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 &&
     if (w_target_len >= 4 &&
         w_target[0] == L'\\' &&
         w_target[0] == L'\\' &&
         w_target[1] == 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[5] == L'N' || w_target[5] == L'n') &&
                  (w_target[6] == L'C' || w_target[6] == L'c') &&
                  (w_target[6] == L'C' || w_target[6] == L'c') &&
                  w_target[7] == L'\\') {
                  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 += 6;
         w_target[0] = L'\\';
         w_target[0] = L'\\';
         w_target_len -= 6;
         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 /
     w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
         sizeof(WCHAR);
         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 &&
     if (!(w_target_len >= 6 &&
           w_target[0] == L'\\' &&
           w_target[0] == L'\\' &&
           w_target[1] == L'?' &&
           w_target[1] == L'?' &&
@@ -409,8 +415,8 @@ void fs__open(uv_fs_t* req) {
   int fd, current_umask;
   int fd, current_umask;
   int flags = req->fs.info.file_flags;
   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);
   current_umask = umask(0);
   umask(current_umask);
   umask(current_umask);
 
 
@@ -502,6 +508,33 @@ void fs__open(uv_fs_t* req) {
   }
   }
 
 
   if (flags & UV_FS_O_DIRECT) {
   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;
     attributes |= FILE_FLAG_NO_BUFFERING;
   }
   }
 
 
@@ -530,8 +563,8 @@ void fs__open(uv_fs_t* req) {
     DWORD error = GetLastError();
     DWORD error = GetLastError();
     if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) &&
     if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) &&
         !(flags & UV_FS_O_EXCL)) {
         !(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);
       SET_REQ_UV_ERROR(req, UV_EISDIR, error);
     } else {
     } else {
       SET_REQ_WIN32_ERROR(req, GetLastError());
       SET_REQ_WIN32_ERROR(req, GetLastError());
@@ -756,9 +789,9 @@ void fs__unlink(uv_fs_t* req) {
   }
   }
 
 
   if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
   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. */
     /* Check if it is a reparse point. If it's not, it's a normal directory. */
     if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
     if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
@@ -767,8 +800,8 @@ void fs__unlink(uv_fs_t* req) {
       return;
       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) {
     if (fs__readlink_handle(handle, NULL, NULL) < 0) {
       DWORD error = GetLastError();
       DWORD error = GetLastError();
       if (error == ERROR_SYMLINK_NOT_SUPPORTED)
       if (error == ERROR_SYMLINK_NOT_SUPPORTED)
@@ -783,9 +816,8 @@ void fs__unlink(uv_fs_t* req) {
     /* Remove read-only attribute */
     /* Remove read-only attribute */
     FILE_BASIC_INFORMATION basic = { 0 };
     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,
     status = pNtSetInformationFile(handle,
                                    &iosb,
                                    &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. */
   /* st_blocks contains the on-disk allocation size in 512-byte units. */
   statbuf->st_blocks =
   statbuf->st_blocks =
-      file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL;
+      (uint64_t) file_info.StandardInformation.AllocationSize.QuadPart >> 9;
 
 
   statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
   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) {
 static void fs__fchmod(uv_fs_t* req) {
   int fd = req->file.fd;
   int fd = req->file.fd;
+  int clear_archive_flag;
   HANDLE handle;
   HANDLE handle;
   NTSTATUS nt_status;
   NTSTATUS nt_status;
   IO_STATUS_BLOCK io_status;
   IO_STATUS_BLOCK io_status;
@@ -1497,7 +1530,11 @@ static void fs__fchmod(uv_fs_t* req) {
 
 
   VERIFY_FD(fd, 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,
   nt_status = pNtQueryInformationFile(handle,
                                       &io_status,
                                       &io_status,
@@ -1507,7 +1544,27 @@ static void fs__fchmod(uv_fs_t* req) {
 
 
   if (!NT_SUCCESS(nt_status)) {
   if (!NT_SUCCESS(nt_status)) {
     SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(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) {
   if (req->fs.info.mode & _S_IWRITE) {
@@ -1524,10 +1581,28 @@ static void fs__fchmod(uv_fs_t* req) {
 
 
   if (!NT_SUCCESS(nt_status)) {
   if (!NT_SUCCESS(nt_status)) {
     SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(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);
   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);
     fs__create_junction(req, pathw, new_pathw);
     return;
     return;
   }
   }
-  if (!pCreateSymbolicLinkW) {
-    SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
-    return;
-  }
 
 
   if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR)
   if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR)
     flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag;
     flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag;
   else
   else
     flags = uv__file_symlink_usermode_flag;
     flags = uv__file_symlink_usermode_flag;
 
 
-  if (pCreateSymbolicLinkW(new_pathw, pathw, flags)) {
+  if (CreateSymbolicLinkW(new_pathw, pathw, flags)) {
     SET_REQ_RESULT(req, 0);
     SET_REQ_RESULT(req, 0);
     return;
     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;
   int r;
   DWORD w_realpath_len;
   DWORD w_realpath_len;
   WCHAR* w_realpath_ptr = NULL;
   WCHAR* w_realpath_ptr = NULL;
   WCHAR* w_realpath_buf;
   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) {
   if (w_realpath_len == 0) {
     return -1;
     return -1;
   }
   }
@@ -1866,10 +1937,8 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
   }
   }
   w_realpath_ptr = w_realpath_buf;
   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);
     uv__free(w_realpath_buf);
     SetLastError(ERROR_INVALID_HANDLE);
     SetLastError(ERROR_INVALID_HANDLE);
     return -1;
     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) {
 static void fs__realpath(uv_fs_t* req) {
   HANDLE handle;
   HANDLE handle;
 
 
-  if (!pGetFinalPathNameByHandleW) {
-    SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
-    return;
-  }
-
   handle = CreateFileW(req->file.pathw,
   handle = CreateFileW(req->file.pathw,
                        0,
                        0,
                        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) {
 static void uv__fs_work(struct uv__work* w) {
   uv_fs_t* req;
   uv_fs_t* req;
 
 
@@ -1977,6 +2045,7 @@ static void uv__fs_work(struct uv__work* w) {
     XX(REALPATH, realpath)
     XX(REALPATH, realpath)
     XX(CHOWN, chown)
     XX(CHOWN, chown)
     XX(FCHOWN, fchown);
     XX(FCHOWN, fchown);
+    XX(LCHOWN, lchown);
     default:
     default:
       assert(!"bad uv_fs_type");
       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 uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
   int err;
   int err;
 
 

+ 22 - 18
src/win/getaddrinfo.c

@@ -24,6 +24,7 @@
 #include "uv.h"
 #include "uv.h"
 #include "internal.h"
 #include "internal.h"
 #include "req-inl.h"
 #include "req-inl.h"
+#include "idna.h"
 
 
 /* EAI_* constants. */
 /* EAI_* constants. */
 #include <winsock2.h>
 #include <winsock2.h>
@@ -71,8 +72,8 @@ int uv__getaddrinfo_translate_error(int sys_err) {
 #endif
 #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)
 #define ALIGNED_SIZE(X)     ((((X) + 3) >> 2) << 2)
 
 
 #ifndef NDIS_IF_MAX_STRING_SIZE
 #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) {
   if (req->retcode == 0) {
-    /* convert addrinfoW to addrinfo */
-    /* first calculate required length */
+    /* Convert addrinfoW to addrinfo. First calculate required length. */
     addrinfow_ptr = req->addrinfow;
     addrinfow_ptr = req->addrinfow;
     while (addrinfow_ptr != NULL) {
     while (addrinfow_ptr != NULL) {
       addrinfo_len += addrinfo_struct_len +
       addrinfo_len += addrinfo_struct_len +
@@ -260,11 +260,13 @@ int uv_getaddrinfo(uv_loop_t* loop,
                    const char* node,
                    const char* node,
                    const char* service,
                    const char* service,
                    const struct addrinfo* hints) {
                    const struct addrinfo* hints) {
+  char hostname_ascii[256];
   int nodesize = 0;
   int nodesize = 0;
   int servicesize = 0;
   int servicesize = 0;
   int hintssize = 0;
   int hintssize = 0;
   char* alloc_ptr = NULL;
   char* alloc_ptr = NULL;
   int err;
   int err;
+  long rc;
 
 
   if (req == NULL || (node == NULL && service == NULL)) {
   if (req == NULL || (node == NULL && service == NULL)) {
     return UV_EINVAL;
     return UV_EINVAL;
@@ -278,12 +280,19 @@ int uv_getaddrinfo(uv_loop_t* loop,
 
 
   /* calculate required memory size for all input values */
   /* calculate required memory size for all input values */
   if (node != NULL) {
   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) {
     if (nodesize == 0) {
       err = GetLastError();
       err = GetLastError();
       goto error;
       goto error;
     }
     }
+    node = hostname_ascii;
   }
   }
 
 
   if (service != NULL) {
   if (service != NULL) {
@@ -313,8 +322,8 @@ int uv_getaddrinfo(uv_loop_t* loop,
   /* save alloc_ptr now so we can free if error */
   /* save alloc_ptr now so we can free if error */
   req->alloc = (void*)alloc_ptr;
   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) {
   if (node != NULL) {
     req->node = (WCHAR*)alloc_ptr;
     req->node = (WCHAR*)alloc_ptr;
     if (MultiByteToWideChar(CP_UTF8,
     if (MultiByteToWideChar(CP_UTF8,
@@ -331,8 +340,8 @@ int uv_getaddrinfo(uv_loop_t* loop,
     req->node = NULL;
     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) {
   if (service != NULL) {
     req->service = (WCHAR*)alloc_ptr;
     req->service = (WCHAR*)alloc_ptr;
     if (MultiByteToWideChar(CP_UTF8,
     if (MultiByteToWideChar(CP_UTF8,
@@ -369,6 +378,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
   if (getaddrinfo_cb) {
   if (getaddrinfo_cb) {
     uv__work_submit(loop,
     uv__work_submit(loop,
                     &req->work_req,
                     &req->work_req,
+                    UV__WORK_SLOW_IO,
                     uv__getaddrinfo_work,
                     uv__getaddrinfo_work,
                     uv__getaddrinfo_done);
                     uv__getaddrinfo_done);
     return 0;
     return 0;
@@ -392,21 +402,15 @@ int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
   DWORD bufsize;
   DWORD bufsize;
   int r;
   int r;
 
 
-  uv__once_init();
-
   if (buffer == NULL || size == NULL || *size == 0)
   if (buffer == NULL || size == NULL || *size == 0)
     return UV_EINVAL;
     return UV_EINVAL;
 
 
-  if (pConvertInterfaceIndexToLuid == NULL)
-    return UV_ENOSYS;
-  r = pConvertInterfaceIndexToLuid(ifindex, &luid);
+  r = ConvertInterfaceIndexToLuid(ifindex, &luid);
 
 
   if (r != 0)
   if (r != 0)
     return uv_translate_sys_error(r);
     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)
   if (r != 0)
     return uv_translate_sys_error(r);
     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;
   uv_getnameinfo_t* req;
   WCHAR host[NI_MAXHOST];
   WCHAR host[NI_MAXHOST];
   WCHAR service[NI_MAXSERV];
   WCHAR service[NI_MAXSERV];
-  int ret = 0;
+  int ret;
 
 
   req = container_of(w, uv_getnameinfo_t, work_req);
   req = container_of(w, uv_getnameinfo_t, work_req);
   if (GetNameInfoW((struct sockaddr*)&req->storage,
   if (GetNameInfoW((struct sockaddr*)&req->storage,
@@ -53,27 +53,34 @@ static void uv__getnameinfo_work(struct uv__work* w) {
                    ARRAY_SIZE(service),
                    ARRAY_SIZE(service),
                    req->flags)) {
                    req->flags)) {
     ret = WSAGetLastError();
     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) {
   if (getnameinfo_cb) {
     uv__work_submit(loop,
     uv__work_submit(loop,
                     &req->work_req,
                     &req->work_req,
+                    UV__WORK_SLOW_IO,
                     uv__getnameinfo_work,
                     uv__getnameinfo_work,
                     uv__getnameinfo_done);
                     uv__getnameinfo_done);
     return 0;
     return 0;

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

@@ -32,7 +32,7 @@
 #define DECREASE_ACTIVE_COUNT(loop, handle)                             \
 #define DECREASE_ACTIVE_COUNT(loop, handle)                             \
   do {                                                                  \
   do {                                                                  \
     if (--(handle)->activecnt == 0 &&                                   \
     if (--(handle)->activecnt == 0 &&                                   \
-        !((handle)->flags & UV__HANDLE_CLOSING)) {                      \
+        !((handle)->flags & UV_HANDLE_CLOSING)) {                       \
       uv__handle_stop((handle));                                        \
       uv__handle_stop((handle));                                        \
     }                                                                   \
     }                                                                   \
     assert((handle)->activecnt >= 0);                                   \
     assert((handle)->activecnt >= 0);                                   \
@@ -53,7 +53,7 @@
     assert(handle->reqs_pending > 0);                                   \
     assert(handle->reqs_pending > 0);                                   \
     handle->reqs_pending--;                                             \
     handle->reqs_pending--;                                             \
                                                                         \
                                                                         \
-    if (handle->flags & UV__HANDLE_CLOSING &&                           \
+    if (handle->flags & UV_HANDLE_CLOSING &&                            \
         handle->reqs_pending == 0) {                                    \
         handle->reqs_pending == 0) {                                    \
       uv_want_endgame(loop, (uv_handle_t*)handle);                      \
       uv_want_endgame(loop, (uv_handle_t*)handle);                      \
     }                                                                   \
     }                                                                   \
@@ -62,14 +62,14 @@
 
 
 #define uv__handle_closing(handle)                                      \
 #define uv__handle_closing(handle)                                      \
   do {                                                                  \
   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));                   \
       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)
   } while (0)
 
 
 
 
@@ -126,7 +126,8 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
         break;
         break;
 
 
       case UV_TIMER:
       case UV_TIMER:
-        uv_timer_endgame(loop, (uv_timer_t*) handle);
+        uv__timer_close((uv_timer_t*) handle);
+        uv__handle_close(handle);
         break;
         break;
 
 
       case UV_PREPARE:
       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)
 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;
   HANDLE handle;
   UV_BEGIN_DISABLE_CRT_ASSERT();
   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) {
 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) {
 void uv_close(uv_handle_t* handle, uv_close_cb cb) {
   uv_loop_t* loop = handle->loop;
   uv_loop_t* loop = handle->loop;
 
 
-  if (handle->flags & UV__HANDLE_CLOSING) {
+  if (handle->flags & UV_HANDLE_CLOSING) {
     assert(0);
     assert(0);
     return;
     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) {
 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) {
 uv_os_fd_t uv_get_osfhandle(int fd) {
   return uv__get_osfhandle(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.h"
 #include "../uv-common.h"
 #include "../uv-common.h"
 
 
-#include "tree.h"
+#include "uv/tree.h"
 #include "winapi.h"
 #include "winapi.h"
 #include "winsock.h"
 #include "winsock.h"
 
 
@@ -57,78 +57,20 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
 #define UV_END_DISABLE_CRT_ASSERT()
 #define UV_END_DISABLE_CRT_ASSERT()
 #endif
 #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
  * 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 {
 typedef struct {
   WSAPROTOCOL_INFOW socket_info;
   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_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
 int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
 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_close(uv_loop_t* loop, uv_tcp_t* tcp);
 void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
 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_accept(uv_pipe_t* server, uv_stream_t* client);
 int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
 int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
     uv_read_cb read_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,
 void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
     uv_req_t* req);
     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);
 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
  * 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);
 void uv__util_init(void);
 
 
 uint64_t uv__hrtime(double scale);
 uint64_t uv__hrtime(double scale);
-int uv_current_pid(void);
 __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
 __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
 int uv__getpwuid_r(uv_passwd_t* pwd);
 int uv__getpwuid_r(uv_passwd_t* pwd);
 int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
 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) {
 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));
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     handle->flags |= UV_HANDLE_CLOSED;
     handle->flags |= UV_HANDLE_CLOSED;
     uv__handle_close(handle);
     uv__handle_close(handle);

File diff suppressed because it is too large
+ 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) {
 static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
   uv_req_t* req;
   uv_req_t* req;
   AFD_POLL_INFO* afd_poll_info;
   AFD_POLL_INFO* afd_poll_info;
-  DWORD result;
+  int result;
 
 
   /* Find a yet unsubmitted req to submit. */
   /* Find a yet unsubmitted req to submit. */
   if (handle->submitted_events_1 == 0) {
   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_1 = handle->events;
     handle->mask_events_2 = 0;
     handle->mask_events_2 = 0;
   } else {
   } 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;
     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->Exclusive = TRUE;
   afd_poll_info->NumberOfHandles = 1;
   afd_poll_info->NumberOfHandles = 1;
   afd_poll_info->Timeout.QuadPart = INT64_MAX;
   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) {
 static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
   AFD_POLL_INFO afd_poll_info;
   AFD_POLL_INFO afd_poll_info;
-  DWORD result;
+  int result;
 
 
   afd_poll_info.Exclusive = TRUE;
   afd_poll_info.Exclusive = TRUE;
   afd_poll_info.NumberOfHandles = 1;
   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 |
   if ((handle->events & ~(handle->submitted_events_1 |
       handle->submitted_events_2)) != 0) {
       handle->submitted_events_2)) != 0) {
     uv__fast_poll_submit_poll_req(loop, handle);
     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_1 == 0 &&
              handle->submitted_events_2 == 0) {
              handle->submitted_events_2 == 0) {
     uv_want_endgame(loop, (uv_handle_t*) handle);
     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) {
 static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
   assert(handle->type == UV_POLL);
   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);
   assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
 
 
   handle->events = events;
   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);
     uv_want_endgame(loop, (uv_handle_t*) handle);
     return 0;
     return 0;
   } else {
   } 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);
     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;
     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];
   peer_socket = loop->poll_peer_sockets[index];
   if (peer_socket == 0) {
   if (peer_socket == 0) {
     peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
     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;
     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_sec = 3 * 60;
   timeout.tv_usec = 0;
   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 |
   if ((handle->events & ~(handle->submitted_events_1 |
       handle->submitted_events_2)) != 0) {
       handle->submitted_events_2)) != 0) {
     uv__slow_poll_submit_poll_req(loop, handle);
     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_1 == 0 &&
              handle->submitted_events_2 == 0) {
              handle->submitted_events_2 == 0) {
     uv_want_endgame(loop, (uv_handle_t*) handle);
     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) {
 static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
   assert(handle->type == UV_POLL);
   assert(handle->type == UV_POLL);
-  assert(!(handle->flags & UV__HANDLE_CLOSING));
+  assert(!(handle->flags & UV_HANDLE_CLOSING));
   assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
   assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
 
 
   handle->events = events;
   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)
   if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
     return uv_translate_sys_error(WSAGetLastError());
     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
 #ifndef NDEBUG
   base_socket = INVALID_SOCKET;
   base_socket = INVALID_SOCKET;
 #endif
 #endif
@@ -557,9 +556,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
     return uv_translate_sys_error(WSAGetLastError());
     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);
   peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
 
 
   if (peer_socket != INVALID_SOCKET) {
   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) {
 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->flags & UV_HANDLE_CLOSED));
 
 
   assert(handle->submitted_events_1 == 0);
   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;
   DWORD client_access = 0;
   HANDLE child_pipe = INVALID_HANDLE_VALUE;
   HANDLE child_pipe = INVALID_HANDLE_VALUE;
   int err;
   int err;
+  int overlap;
 
 
   if (flags & UV_READABLE_PIPE) {
   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;
     server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
     client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
     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.lpSecurityDescriptor = NULL;
   sa.bInheritHandle = TRUE;
   sa.bInheritHandle = TRUE;
 
 
+  overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE);
   child_pipe = CreateFileA(pipe_name,
   child_pipe = CreateFileA(pipe_name,
                            client_access,
                            client_access,
                            0,
                            0,
                            &sa,
                            &sa,
                            OPEN_EXISTING,
                            OPEN_EXISTING,
-                           server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0,
+                           overlap ? FILE_FLAG_OVERLAPPED : 0,
                            NULL);
                            NULL);
   if (child_pipe == INVALID_HANDLE_VALUE) {
   if (child_pipe == INVALID_HANDLE_VALUE) {
     err = GetLastError();
     err = GetLastError();
@@ -159,8 +160,8 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
   }
   }
 #endif
 #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 (!ConnectNamedPipe(server_pipe->handle, NULL)) {
     if (GetLastError() != ERROR_PIPE_CONNECTED) {
     if (GetLastError() != ERROR_PIPE_CONNECTED) {
       err = GetLastError();
       err = GetLastError();
@@ -194,11 +195,11 @@ static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
   HANDLE current_process;
   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 ||
   if (handle == INVALID_HANDLE_VALUE ||
       handle == NULL ||
       handle == NULL ||
       handle == (HANDLE) -2) {
       handle == (HANDLE) -2) {
@@ -284,8 +285,8 @@ int uv__stdio_create(uv_loop_t* loop,
     return ERROR_OUTOFMEMORY;
     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;
   CHILD_STDIO_COUNT(buffer) = count;
   for (i = 0; i < count; i++) {
   for (i = 0; i < count; i++) {
     CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
     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 |
     switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
             UV_INHERIT_STREAM)) {
             UV_INHERIT_STREAM)) {
       case UV_IGNORE:
       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) {
         if (i <= 2) {
           DWORD access = (i == 0) ? FILE_GENERIC_READ :
           DWORD access = (i == 0) ? FILE_GENERIC_READ :
                                     FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
                                     FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
@@ -323,14 +324,14 @@ int uv__stdio_create(uv_loop_t* loop,
         break;
         break;
 
 
       case UV_CREATE_PIPE: {
       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;
         uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
         HANDLE child_pipe = INVALID_HANDLE_VALUE;
         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->type == UV_NAMED_PIPE);
         assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
         assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
         assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
         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. */
         /* Make an inheritable duplicate of the handle. */
         err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
         err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
         if (err) {
         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) {
           if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
             CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
             CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
             CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
             CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
@@ -418,8 +419,8 @@ int uv__stdio_create(uv_loop_t* loop,
 
 
         if (stream_handle == NULL ||
         if (stream_handle == NULL ||
             stream_handle == INVALID_HANDLE_VALUE) {
             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;
           err = ERROR_NOT_SUPPORTED;
           goto error;
           goto error;
         }
         }

+ 40 - 30
src/win/process.c

@@ -360,8 +360,8 @@ static WCHAR* search_path(const WCHAR *file,
     return NULL;
     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;
   for (file_name_start = (WCHAR*)file + file_len;
        file_name_start > file
        file_name_start > file
            && file_name_start[-1] != L'\\'
            && file_name_start[-1] != L'\\'
@@ -556,8 +556,8 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
     arg_count++;
     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;
   dst_len = dst_len * 2 + arg_count * 2;
 
 
   /* Allocate buffer for the final command line. */
   /* Allocate buffer for the final command line. */
@@ -739,7 +739,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
     }
     }
   }
   }
   *ptr_copy = NULL;
   *ptr_copy = NULL;
-  assert(env_len == ptr - dst_copy);
+  assert(env_len == (size_t) (ptr - dst_copy));
 
 
   /* sort our (UTF-16) copy */
   /* sort our (UTF-16) copy */
   qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
   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,
         var_size = GetEnvironmentVariableW(required_vars[i].wide,
                                            ptr,
                                            ptr,
                                            (int) (env_len - (ptr - dst)));
                                            (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");
           uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
         }
         }
       }
       }
@@ -815,7 +815,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
   }
   }
 
 
   /* Terminate with an extra NULL. */
   /* Terminate with an extra NULL. */
-  assert(env_len == (ptr - dst));
+  assert(env_len == (size_t) (ptr - dst));
   *ptr = L'\0';
   *ptr = L'\0';
 
 
   uv__free(dst_copy);
   uv__free(dst_copy);
@@ -831,8 +831,13 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
  */
  */
 static WCHAR* find_path(WCHAR *env) {
 static WCHAR* find_path(WCHAR *env) {
   for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
   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 &env[5];
+    }
   }
   }
 
 
   return NULL;
   return NULL;
@@ -865,9 +870,9 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
   assert(handle->exit_cb_pending);
   assert(handle->exit_cb_pending);
   handle->exit_cb_pending = 0;
   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);
     uv_want_endgame(loop, (uv_handle_t*) handle);
     return;
     return;
   }
   }
@@ -878,14 +883,14 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
     handle->wait_handle = INVALID_HANDLE_VALUE;
     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);
   uv__handle_stop(handle);
 
 
   if (GetExitCodeProcess(handle->process_handle, &status)) {
   if (GetExitCodeProcess(handle->process_handle, &status)) {
     exit_code = status;
     exit_code = status;
   } else {
   } 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());
     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);
   uv__handle_closing(handle);
 
 
   if (handle->wait_handle != INVALID_HANDLE_VALUE) {
   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);
     BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
     if (!r) {
     if (!r) {
       /* This should never happen, and if it happens, we can't recover... */
       /* 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) {
 void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
   assert(!handle->exit_cb_pending);
   assert(!handle->exit_cb_pending);
-  assert(handle->flags & UV__HANDLE_CLOSING);
+  assert(handle->flags & UV_HANDLE_CLOSING);
   assert(!(handle->flags & UV_HANDLE_CLOSED));
   assert(!(handle->flags & UV_HANDLE_CLOSED));
 
 
   /* Clean-up the process handle. */
   /* Clean-up the process handle. */
@@ -959,6 +964,8 @@ int uv_spawn(uv_loop_t* loop,
                               UV_PROCESS_SETGID |
                               UV_PROCESS_SETGID |
                               UV_PROCESS_SETUID |
                               UV_PROCESS_SETUID |
                               UV_PROCESS_WINDOWS_HIDE |
                               UV_PROCESS_WINDOWS_HIDE |
+                              UV_PROCESS_WINDOWS_HIDE_CONSOLE |
+                              UV_PROCESS_WINDOWS_HIDE_GUI |
                               UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
                               UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
 
 
   err = uv_utf8_to_utf16_alloc(options->file, &application);
   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;
   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. */
     /* Avoid creating console window if stdio is not inherited. */
     for (i = 0; i < options->stdio_count; i++) {
     for (i = 0; i < options->stdio_count; i++) {
       if (options->stdio[i].flags & UV_INHERIT_FD)
       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)
       if (i == options->stdio_count - 1)
         process_flags |= CREATE_NO_WINDOW;
         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. */
     /* Use SW_HIDE to avoid any potential process window. */
     startup.wShowWindow = SW_HIDE;
     startup.wShowWindow = SW_HIDE;
   } else {
   } else {
@@ -1104,14 +1114,13 @@ int uv_spawn(uv_loop_t* loop,
     goto done;
     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->process_handle = info.hProcess;
   process->pid = info.dwProcessId;
   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)) {
   if (!(options->flags & UV_PROCESS_DETACHED)) {
     uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
     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 &&
     if (fdopt->flags & UV_CREATE_PIPE &&
         fdopt->data.stream->type == UV_NAMED_PIPE &&
         fdopt->data.stream->type == UV_NAMED_PIPE &&
         ((uv_pipe_t*) fdopt->data.stream)->ipc) {
         ((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);
   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);
   uv__handle_start(process);
 
 
   /* Cleanup, whether we succeeded or failed. */
   /* Cleanup, whether we succeeded or failed. */
@@ -1186,16 +1196,16 @@ static int uv__kill(HANDLE process_handle, int signum) {
     case SIGTERM:
     case SIGTERM:
     case SIGKILL:
     case SIGKILL:
     case SIGINT: {
     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;
       DWORD status;
       int err;
       int err;
 
 
       if (TerminateProcess(process_handle, 1))
       if (TerminateProcess(process_handle, 1))
         return 0;
         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();
       err = GetLastError();
       if (err == ERROR_ACCESS_DENIED &&
       if (err == ERROR_ACCESS_DENIED &&
           GetExitCodeProcess(process_handle, &status) &&
           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) {
 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;
   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;
   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(
     unsigned long previous = InterlockedExchange(
             (volatile LONG*) &handle->pending_signum, signum);
             (volatile LONG*) &handle->pending_signum, signum);
 
 
-    if (handle->flags & UV__SIGNAL_ONE_SHOT_DISPATCHED)
+    if (handle->flags & UV_SIGNAL_ONE_SHOT_DISPATCHED)
       continue;
       continue;
 
 
     if (!previous) {
     if (!previous) {
@@ -98,8 +98,8 @@ int uv__signal_dispatch(int signum) {
     }
     }
 
 
     dispatched = 1;
     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);
   LeaveCriticalSection(&uv__signal_lock);
@@ -118,10 +118,10 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) {
 
 
     case CTRL_CLOSE_EVENT:
     case CTRL_CLOSE_EVENT:
       if (uv__signal_dispatch(SIGHUP)) {
       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);
         Sleep(INFINITE);
         return TRUE;
         return TRUE;
       }
       }
@@ -129,8 +129,8 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) {
 
 
     case CTRL_LOGOFF_EVENT:
     case CTRL_LOGOFF_EVENT:
     case CTRL_SHUTDOWN_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:
     default:
       /* We don't handle these. */
       /* We don't handle these. */
@@ -190,13 +190,13 @@ int uv__signal_start(uv_signal_t* handle,
                             int signum,
                             int signum,
                             int oneshot) {
                             int oneshot) {
   /* Test for invalid signal values. */
   /* Test for invalid signal values. */
-  if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG))
+  if (signum <= 0 || signum >= NSIG)
     return UV_EINVAL;
     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) {
   if (signum == handle->signum) {
     handle->signal_cb = signal_cb;
     handle->signal_cb = signal_cb;
     return 0;
     return 0;
@@ -213,7 +213,7 @@ int uv__signal_start(uv_signal_t* handle,
 
 
   handle->signum = signum;
   handle->signum = signum;
   if (oneshot)
   if (oneshot)
-    handle->flags |= UV__SIGNAL_ONE_SHOT;
+    handle->flags |= UV_SIGNAL_ONE_SHOT;
 
 
   RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
   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);
           (volatile LONG*) &handle->pending_signum, 0);
   assert(dispatched_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)
   if (dispatched_signum == handle->signum)
     handle->signal_cb(handle, dispatched_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);
     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. */
     /* When it is closing, it must be stopped at this point. */
     assert(handle->signum == 0);
     assert(handle->signum == 0);
     uv_want_endgame(loop, (uv_handle_t*) handle);
     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) {
 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->flags & UV_HANDLE_CLOSED));
 
 
   assert(handle->signum == 0);
   assert(handle->signum == 0);

+ 14 - 22
src/win/stream.c

@@ -105,12 +105,10 @@ int uv_read_stop(uv_stream_t* handle) {
   err = 0;
   err = 0;
   if (handle->type == UV_TTY) {
   if (handle->type == UV_TTY) {
     err = uv_tty_read_stop((uv_tty_t*) handle);
     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 {
   } 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);
     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);
       err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb);
       break;
       break;
     case UV_NAMED_PIPE:
     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;
       break;
     case UV_TTY:
     case UV_TTY:
       err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
       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;
   uv_loop_t* loop = handle->loop;
   int err;
   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);
   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,
 int uv_try_write(uv_stream_t* stream,
                  const uv_buf_t bufs[],
                  const uv_buf_t bufs[],
                  unsigned int nbufs) {
                  unsigned int nbufs) {
-  if (stream->flags & UV__HANDLE_CLOSING)
+  if (stream->flags & UV_HANDLE_CLOSING)
     return UV_EBADF;
     return UV_EBADF;
   if (!(stream->flags & UV_HANDLE_WRITABLE))
   if (!(stream->flags & UV_HANDLE_WRITABLE))
     return UV_EPIPE;
     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))
   if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0))
     return GetLastError();
     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,
   if (CreateIoCompletionPort((HANDLE)socket,
                              loop->iocp,
                              loop->iocp,
                              (ULONG_PTR)socket,
                              (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;
     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();
       return GetLastError();
-    }
+    handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
   }
   }
 
 
   if (handle->flags & UV_HANDLE_TCP_NODELAY) {
   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);
     UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
 
 
     err = 0;
     err = 0;
-    if (handle->flags & UV__HANDLE_CLOSING) {
+    if (handle->flags & UV_HANDLE_CLOSING) {
       err = ERROR_OPERATION_ABORTED;
       err = ERROR_OPERATION_ABORTED;
     } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
     } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
       err = WSAGetLastError();
       err = WSAGetLastError();
@@ -236,7 +233,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
     return;
     return;
   }
   }
 
 
-  if (handle->flags & UV__HANDLE_CLOSING &&
+  if (handle->flags & UV_HANDLE_CLOSING &&
       handle->reqs_pending == 0) {
       handle->reqs_pending == 0) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     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;
     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,
     setsockopt(handle->socket,
                IPPROTO_IPV6,
                IPPROTO_IPV6,
                IPV6_V6ONLY,
                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);
       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++) {
     for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) {
       req = &handle->tcp.serv.accept_reqs[i];
       req = &handle->tcp.serv.accept_reqs[i];
       UV_REQ_INIT(req, UV_ACCEPT);
       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->next_pending = NULL;
   req->accept_socket = INVALID_SOCKET;
   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. */
     /* Check if we're in a middle of changing the number of pending accepts. */
     if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
     if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
       uv_tcp_queue_accept(server, req);
       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;
   handle->alloc_cb = alloc_cb;
   INCREASE_ACTIVE_COUNT(loop, handle);
   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_READ_PENDING)) {
     if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
     if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
         !handle->read_req.event_handle) {
         !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) {
     uv_req_t* req) {
   DWORD bytes, flags, err;
   DWORD bytes, flags, err;
   uv_buf_t buf;
   uv_buf_t buf;
+  int count;
 
 
   assert(handle->type == UV_TCP);
   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);
       err = GET_REQ_SOCK_ERROR(req);
 
 
       if (err == WSAECONNABORTED) {
       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;
         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 */
     /* 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);
       buf = uv_buf_init(NULL, 0);
       handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
       handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
       if (buf.base == NULL || buf.len == 0) {
       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);
           DECREASE_ACTIVE_COUNT(loop, handle);
 
 
           if (err == WSAECONNABORTED) {
           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;
             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);
   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 (req->accept_socket == INVALID_SOCKET) {
     if (handle->flags & UV_HANDLE_LISTENING) {
     if (handle->flags & UV_HANDLE_LISTENING) {
       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);
       handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
     }
     }
   } else {
   } 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);
     closesocket(req->accept_socket);
     req->accept_socket = INVALID_SOCKET;
     req->accept_socket = INVALID_SOCKET;
     if (handle->flags & UV_HANDLE_LISTENING) {
     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;
   err = 0;
   if (REQ_SUCCESS(req)) {
   if (REQ_SUCCESS(req)) {
-    if (handle->flags & UV__HANDLE_CLOSING) {
+    if (handle->flags & UV_HANDLE_CLOSING) {
       /* use UV_ECANCELED for consistency with Unix */
       /* use UV_ECANCELED for consistency with Unix */
       err = ERROR_OPERATION_ABORTED;
       err = ERROR_OPERATION_ABORTED;
     } else if (setsockopt(handle->socket,
     } 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;
   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) {
   if (socket == INVALID_SOCKET) {
     return WSAGetLastError();
     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) {
   if (err) {
     closesocket(socket);
     closesocket(socket);
     return err;
     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);
     uv_connection_init((uv_stream_t*)tcp);
     tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
     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++;
   tcp->loop->active_tcp_streams++;
   return 0;
   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) {
 int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
   if (handle->flags & UV_HANDLE_CONNECTION) {
   if (handle->flags & UV_HANDLE_CONNECTION) {
     return UV_EINVAL;
     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 :
   non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 :
                                                 uv_tcp_non_ifs_lsp_ipv4;
                                                 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) {
   if (non_ifs_lsp) {
     DWORD bytes;
     DWORD bytes;
     if (WSAIoctl(socket,
     if (WSAIoctl(socket,
@@ -1379,38 +1379,37 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
   int close_socket = 1;
   int close_socket = 1;
 
 
   if (tcp->flags & UV_HANDLE_READ_PENDING) {
   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)) {
     if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
       /* Just do shutdown on non-shared sockets, which ensures graceful close. */
       /* Just do shutdown on non-shared sockets, which ensures graceful close. */
       shutdown(tcp->socket, SD_SEND);
       shutdown(tcp->socket, SD_SEND);
 
 
     } else if (uv_tcp_try_cancel_io(tcp) == 0) {
     } 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;
       close_socket = 0;
 
 
     } else {
     } 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) &&
   } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
              tcp->tcp.serv.accept_reqs != NULL) {
              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) {
     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;
       unsigned int i;
       for (i = 0; i < uv_simultaneous_server_accepts; i++) {
       for (i = 0; i < uv_simultaneous_server_accepts; i++) {
         uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[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 <limits.h>
 #include <stdlib.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 "uv.h"
 #include "internal.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)) {
 static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
   DWORD result;
   DWORD result;
   HANDLE existing_event, created_event;
   HANDLE existing_event, created_event;
@@ -69,8 +55,8 @@ static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
     guard->ran = 1;
     guard->ran = 1;
 
 
   } else {
   } 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);
     CloseHandle(created_event);
     result = WaitForSingleObject(existing_event, INFINITE);
     result = WaitForSingleObject(existing_event, INFINITE);
     assert(result == WAIT_OBJECT_0);
     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;
   ctx->arg = arg;
 
 
   /* Create the thread in suspended state so we have a chance to pass
   /* 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,
   thread = (HANDLE) _beginthreadex(NULL,
                                    0,
                                    0,
                                    uv__thread_start,
                                    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) {
 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) {
 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) {
 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) {
 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) {
 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;
     return 0;
   if (GetLastError() != ERROR_TIMEOUT)
   if (GetLastError() != ERROR_TIMEOUT)
     abort();
     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 uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
   int err;
   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>
 #include <stdlib.h>
 
 
 #if defined(_MSC_VER) && _MSC_VER < 1600
 #if defined(_MSC_VER) && _MSC_VER < 1600
-# include "stdint-msvc2008.h"
+# include "uv/stdint-msvc2008.h"
 #else
 #else
 # include <stdint.h>
 # include <stdint.h>
 #endif
 #endif
@@ -164,7 +164,7 @@ void uv_console_init(void) {
                                        OPEN_EXISTING,
                                        OPEN_EXISTING,
                                        0,
                                        0,
                                        0);
                                        0);
-  if (uv__tty_console_handle != NULL) {
+  if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
     QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
     QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
                       NULL,
                       NULL,
                       WT_EXECUTELONGFUNCTION);
                       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;
   HANDLE handle;
   CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
   CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
+  (void)unused;
 
 
   uv__once_init();
   uv__once_init();
   handle = (HANDLE) uv__get_osfhandle(fd);
   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;
     fd = -1;
   }
   }
 
 
+  readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents);
   if (!readable) {
   if (!readable) {
     /* Obtain the screen buffer info with the output handle. */
     /* Obtain the screen buffer info with the output handle. */
     if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
     if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
       return uv_translate_sys_error(GetLastError());
       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);
     uv_sem_wait(&uv_tty_output_lock);
 
 
     if (uv__vterm_state == UV_UNCHECKED)
     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 {
   } else {
     was_reading = 0;
     was_reading = 0;
+    alloc_cb = NULL;
+    read_cb = NULL;
   }
   }
 
 
   uv_sem_wait(&uv_tty_output_lock);
   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) {
 int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
   CONSOLE_SCREEN_BUFFER_INFO info;
   CONSOLE_SCREEN_BUFFER_INFO info;
 
 
@@ -484,8 +484,8 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
     bytes = MAX_INPUT_BUFFER_LENGTH;
     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;
   chars = bytes / 3;
 
 
   status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS);
   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) {
   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_INSERT,  "[2~",  "[2;2~", "[2;5~", "[2;6~")
     VK_CASE(VK_END,     "[4~",  "[4;2~", "[4;5~", "[4;6~")
     VK_CASE(VK_END,     "[4~",  "[4;2~", "[4;5~", "[4;6~")
     VK_CASE(VK_DOWN,    "[B",   "[1;2B", "[1;5B", "[1;6B")
     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;
     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 = uv_null_buf_;
   buf_used = 0;
   buf_used = 0;
 
 
@@ -733,16 +733,17 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
         continue;
         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;
         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) &&
       if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
           !(KEV.dwControlKeyState & ENHANCED_KEY) &&
           !(KEV.dwControlKeyState & ENHANCED_KEY) &&
           (KEV.wVirtualKeyCode == VK_INSERT ||
           (KEV.wVirtualKeyCode == VK_INSERT ||
@@ -779,8 +780,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
           continue;
           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))
         if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
             && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
             && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
             RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
             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 &&
         if (KEV.uChar.UnicodeChar >= 0xDC00 &&
             KEV.uChar.UnicodeChar < 0xE000) {
             KEV.uChar.UnicodeChar < 0xE000) {
           /* UTF-16 surrogate pair */
           /* 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,
           char_len = WideCharToMultiByte(CP_UTF8,
                                          0,
                                          0,
                                          utf16_buffer,
                                          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. */
         /* Whatever happened, the last character wasn't a high surrogate. */
         handle->tty.rd.last_utf16_high_surrogate = 0;
         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) {
         if (!char_len) {
           handle->flags &= ~UV_HANDLE_READING;
           handle->flags &= ~UV_HANDLE_READING;
           DECREASE_ACTIVE_COUNT(loop, handle);
           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,
       handle->read_cb((uv_stream_t*) handle,
                       uv_translate_sys_error(GET_REQ_ERROR(req)),
                       uv_translate_sys_error(GET_REQ_ERROR(req)),
                       &buf);
                       &buf);
-    } else {
-      /* The read was cancelled, or whatever we don't care */
-      handle->read_cb((uv_stream_t*) handle, 0, &buf);
     }
     }
-
   } else {
   } 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;
       DWORD bytes = req->u.io.overlapped.InternalHigh;
       handle->read_cb((uv_stream_t*) handle, bytes, &buf);
       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. */
   /* 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->type == UV_TTY);
   assert(handle->flags & UV_HANDLE_TTY_READABLE);
   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) {
   if (handle->tty.rd.read_line_buffer.len == 0) {
     uv_process_tty_read_raw_req(loop, handle, req);
     uv_process_tty_read_raw_req(loop, handle, req);
   } else {
   } 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->read_cb = read_cb;
   handle->alloc_cb = alloc_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) {
   if (handle->flags & UV_HANDLE_READ_PENDING) {
     return 0;
     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) {
   if (handle->tty.rd.last_key_len > 0) {
     SET_REQ_SUCCESS(&handle->read_req);
     SET_REQ_SUCCESS(&handle->read_req);
     uv_insert_pending_req(handle->loop, (uv_req_t*) &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;
     return 0;
 
 
   if (handle->flags & UV_HANDLE_TTY_RAW) {
   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);
     memset(&record, 0, sizeof record);
+    record.EventType = FOCUS_EVENT;
     if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
     if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
       return GetLastError();
       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;
     uv_tty_virtual_offset = info->dwCursorPosition.Y;
   } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
   } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
              uv_tty_virtual_height + 1) {
              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_offset = info->dwCursorPosition.Y -
                             uv_tty_virtual_height + 1;
                             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;
     x2 = 0;
     x2r = 1;
     x2r = 1;
   } else {
   } 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;
     x2 = 0xffff;
     x2r = 0;
     x2r = 0;
   }
   }
@@ -1613,8 +1610,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                              const uv_buf_t bufs[],
                              const uv_buf_t bufs[],
                              unsigned int nbufs,
                              unsigned int nbufs,
                              DWORD* error) {
                              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_buf[MAX_CONSOLE_CHAR];
   WCHAR* utf16_buffer;
   WCHAR* utf16_buffer;
   DWORD utf16_buf_used = 0;
   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 previous_eol = handle->tty.wr.previous_eol;
   unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
   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;
   *error = ERROR_SUCCESS;
 
 
   utf16_buffer = utf16_buf;
   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++) {
     for (j = 0; j < buf.len; j++) {
       unsigned char c = buf.base[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) {
       if (utf8_bytes_left == 0) {
         /* Read utf-8 start byte */
         /* Read utf-8 start byte */
         DWORD first_zero_bit;
         DWORD first_zero_bit;
@@ -1742,8 +1738,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
         /* Start byte where continuation was expected. */
         /* Start byte where continuation was expected. */
         utf8_bytes_left = 0;
         utf8_bytes_left = 0;
         utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
         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--;
         j--;
       }
       }
 
 
@@ -1776,8 +1772,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
           case '_':
           case '_':
           case 'P':
           case 'P':
           case ']':
           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;
             ansi_parser_state = ANSI_ST_CONTROL;
             continue;
             continue;
 
 
@@ -1859,8 +1855,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
               continue;
               continue;
 
 
             } else {
             } 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 */
               /* Check for too many arguments */
               if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
               if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
                 ansi_parser_state |= ANSI_IGNORE;
                 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) &&
           } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
                      handle->tty.wr.ansi_csi_argc == 0) {
                      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;
             continue;
 
 
           } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
           } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
@@ -2006,8 +2003,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
             continue;
             continue;
 
 
           } else {
           } 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;
             ansi_parser_state |= ANSI_IGNORE;
             continue;
             continue;
           }
           }
@@ -2020,8 +2017,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
         }
         }
 
 
       } else if (ansi_parser_state & ANSI_ST_CONTROL) {
       } 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_IN_STRING) {
           if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
           if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
             if (utf8_codepoint == '"') {
             if (utf8_codepoint == '"') {
@@ -2055,9 +2052,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
         abort();
         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) {
       if (utf8_codepoint > 0xffff) {
         utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
         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'\r';
           utf16_buf[utf16_buf_used++] = L'\n';
           utf16_buf[utf16_buf_used++] = L'\n';
         } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
         } 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 {
         } else {
           /* \r without \n; print \r as-is. */
           /* \r without \n; print \r as-is. */
           ENSURE_BUFFER_SPACE(1);
           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) {
 void uv_tty_close(uv_tty_t* handle) {
   assert(handle->u.fd == -1 || handle->u.fd > 2);
   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)
   if (handle->u.fd == -1)
     CloseHandle(handle->handle);
     CloseHandle(handle->handle);
   else
   else
     close(handle->u.fd);
     close(handle->u.fd);
 
 
-  if (handle->flags & UV_HANDLE_READING)
-    uv_tty_read_stop(handle);
-
   handle->u.fd = -1;
   handle->u.fd = -1;
   handle->handle = INVALID_HANDLE_VALUE;
   handle->handle = INVALID_HANDLE_VALUE;
   handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
   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 */
     /* TTY shutdown is really just a no-op */
     if (handle->stream.conn.shutdown_req->cb) {
     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);
         handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
       } else {
       } else {
         handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
         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;
     return;
   }
   }
 
 
-  if (handle->flags & UV__HANDLE_CLOSING &&
+  if (handle->flags & UV_HANDLE_CLOSING &&
       handle->reqs_pending == 0) {
       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) ||
     assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
            handle->tty.rd.read_raw_wait == NULL);
            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();
     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,
   if (CreateIoCompletionPort((HANDLE)socket,
                              loop->iocp,
                              loop->iocp,
                              (ULONG_PTR)socket,
                              (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();
     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) {
 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) {
       handle->reqs_pending == 0) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     uv__handle_close(handle);
     uv__handle_close(handle);
@@ -245,12 +242,12 @@ static int uv_udp_maybe_bind(uv_udp_t* handle,
     handle->flags |= UV_HANDLE_IPV6;
     handle->flags |= UV_HANDLE_IPV6;
 
 
   if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
   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,
     setsockopt(handle->socket,
                IPPROTO_IPV6,
                IPPROTO_IPV6,
                IPV6_V6ONLY,
                IPV6_V6ONLY,
@@ -369,7 +366,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
   int err;
   int err;
 
 
   if (handle->flags & UV_HANDLE_READING) {
   if (handle->flags & UV_HANDLE_READING) {
-    return WSAEALREADY;
+    return UV_EALREADY;
   }
   }
 
 
   err = uv_udp_maybe_bind(handle,
   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_),
                           sizeof(uv_addr_ip4_any_),
                           0);
                           0);
   if (err)
   if (err)
-    return err;
+    return uv_translate_sys_error(err);
 
 
   handle->flags |= UV_HANDLE_READING;
   handle->flags |= UV_HANDLE_READING;
   INCREASE_ACTIVE_COUNT(loop, handle);
   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->recv_cb = recv_cb;
   handle->alloc_cb = alloc_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))
   if (!(handle->flags & UV_HANDLE_READ_PENDING))
     uv_udp_queue_recv(loop, handle);
     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)) {
   if (!REQ_SUCCESS(req)) {
     DWORD err = GET_REQ_SOCK_ERROR(req);
     DWORD err = GET_REQ_SOCK_ERROR(req);
     if (err == WSAEMSGSIZE) {
     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) {
     } 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)) {
       if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
         goto done;
         goto done;
       }
       }
     } else {
     } 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) {
       if (handle->flags & UV_HANDLE_READING) {
         uv_udp_recv_stop(handle);
         uv_udp_recv_stop(handle);
         buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
         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;
     struct sockaddr_storage from;
     int from_len;
     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);
     buf = uv_buf_init(NULL, 0);
     handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
     handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
     if (buf.base == NULL || buf.len == 0) {
     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;
     return UV_EINVAL;
   }
   }
 
 
-  if (!(handle->flags & UV_HANDLE_BOUND))
+  if (handle->socket == INVALID_SOCKET)
     return UV_EBADF;
     return UV_EBADF;
 
 
   if (addr_st.ss_family == AF_INET) {
   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) {
 int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
   BOOL optval = (BOOL) value;
   BOOL optval = (BOOL) value;
 
 
-  if (!(handle->flags & UV_HANDLE_BOUND))
+  if (handle->socket == INVALID_SOCKET)
     return UV_EBADF;
     return UV_EBADF;
 
 
   if (setsockopt(handle->socket,
   if (setsockopt(handle->socket,
@@ -818,7 +815,7 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
       return UV_EINVAL;                                                       \
       return UV_EINVAL;                                                       \
     }                                                                         \
     }                                                                         \
                                                                               \
                                                                               \
-    if (!(handle->flags & UV_HANDLE_BOUND))                                   \
+    if (handle->socket == INVALID_SOCKET)                                     \
       return UV_EBADF;                                                        \
       return UV_EBADF;                                                        \
                                                                               \
                                                                               \
     if (!(handle->flags & UV_HANDLE_IPV6)) {                                  \
     if (!(handle->flags & UV_HANDLE_IPV6)) {                                  \

+ 250 - 48
src/win/util.c

@@ -74,10 +74,6 @@
 static char *process_title;
 static char *process_title;
 static CRITICAL_SECTION process_title_lock;
 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. */
 /* Interval (in seconds) of the high-resolution clock. */
 static double hrtime_interval_ = 0;
 static double hrtime_interval_ = 0;
 
 
@@ -149,8 +145,8 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
 
 
   uv__free(utf16_buffer);
   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;
   *size_ptr = utf8_len - 1;
   return 0;
   return 0;
 
 
@@ -173,16 +169,16 @@ int uv_cwd(char* buffer, size_t* size) {
   if (utf16_len == 0) {
   if (utf16_len == 0) {
     return uv_translate_sys_error(GetLastError());
     return uv_translate_sys_error(GetLastError());
   } else if (utf16_len > MAX_PATH) {
   } 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;
     return UV_EIO;
   }
   }
 
 
   /* utf16_len contains the length, *not* including the terminating null. */
   /* utf16_len contains the length, *not* including the terminating null. */
   utf16_buffer[utf16_len] = L'\0';
   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'\\' &&
   if (utf16_buffer[utf16_len - 1] == L'\\' &&
       !(utf16_len == 3 && utf16_buffer[1] == L':')) {
       !(utf16_len == 3 && utf16_buffer[1] == L':')) {
     utf16_len--;
     utf16_len--;
@@ -239,9 +235,9 @@ int uv_chdir(const char* dir) {
                           utf16_buffer,
                           utf16_buffer,
                           MAX_PATH) == 0) {
                           MAX_PATH) == 0) {
     DWORD error = GetLastError();
     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) {
     if (error == ERROR_INSUFFICIENT_BUFFER) {
       return UV_ENAMETOOLONG;
       return UV_ENAMETOOLONG;
     } else {
     } else {
@@ -253,9 +249,9 @@ int uv_chdir(const char* dir) {
     return uv_translate_sys_error(GetLastError());
     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);
   utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
   if (utf16_len == 0) {
   if (utf16_len == 0) {
     return uv_translate_sys_error(GetLastError());
     return uv_translate_sys_error(GetLastError());
@@ -263,8 +259,8 @@ int uv_chdir(const char* dir) {
     return UV_EIO;
     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'\\' &&
   if (utf16_buffer[utf16_len - 1] == L'\\' &&
       !(utf16_len == 3 && utf16_buffer[1] == L':')) {
       !(utf16_len == 3 && utf16_buffer[1] == L':')) {
     utf16_len--;
     utf16_len--;
@@ -272,8 +268,8 @@ int uv_chdir(const char* dir) {
   }
   }
 
 
   if (utf16_len < 2 || utf16_buffer[1] != L':') {
   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;
     drive_letter = 0;
   } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
   } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
     drive_letter = utf16_buffer[0];
     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) {
 char** uv_setup_args(int argc, char** argv) {
   return argv;
   return argv;
 }
 }
@@ -828,6 +816,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
   int is_vista_or_greater;
   int is_vista_or_greater;
   ULONG flags;
   ULONG flags;
 
 
+  *addresses_ptr = NULL;
+  *count_ptr = 0;
+
   is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
   is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
   if (is_vista_or_greater) {
   if (is_vista_or_greater) {
     flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
     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_size = 0;
   win_address_buf = NULL;
   win_address_buf = NULL;
 
 
   for (;;) {
   for (;;) {
     ULONG r;
     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,
     r = GetAdaptersAddresses(AF_UNSPEC,
                              flags,
                              flags,
                              NULL,
                              NULL,
@@ -866,8 +857,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
 
 
     switch (r) {
     switch (r) {
       case ERROR_BUFFER_OVERFLOW:
       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);
         win_address_buf = uv__malloc(win_address_buf_size);
         if (win_address_buf == NULL)
         if (win_address_buf == NULL)
           return UV_ENOMEM;
           return UV_ENOMEM;
@@ -901,15 +892,15 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
         return UV_ENOBUFS;
         return UV_ENOBUFS;
 
 
       default:
       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);
         assert(r != ERROR_SUCCESS);
         return uv_translate_sys_error(r);
         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;
   count = 0;
   uv_address_buf_size = 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;
     IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
     int name_size;
     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 ||
     if (adapter->OperStatus != IfOperStatusUp ||
         adapter->FirstUnicastAddress == NULL)
         adapter->FirstUnicastAddress == NULL)
       continue;
       continue;
@@ -941,8 +932,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
     }
     }
     uv_address_buf_size += name_size;
     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*)
     for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
                            adapter->FirstUnicastAddress;
                            adapter->FirstUnicastAddress;
          unicast_address != NULL;
          unicast_address != NULL;
@@ -959,8 +950,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
     return UV_ENOMEM;
     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;
   uv_address = uv_address_buf;
   name_buf = (char*) (uv_address_buf + count);
   name_buf = (char*) (uv_address_buf + count);
 
 
@@ -1199,8 +1190,8 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
     return UV_EIO;
     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'\\' &&
   if (path[len - 1] == L'\\' &&
       !(len == 3 && path[1] == L':')) {
       !(len == 3 && path[1] == L':')) {
     len--;
     len--;
@@ -1542,3 +1533,214 @@ int uv_os_gethostname(char* buffer, size_t* size) {
   *size = len;
   *size = len;
   return 0;
   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 */
 /* Ntdll function pointers */
+sRtlGetVersion pRtlGetVersion;
 sRtlNtStatusToDosError pRtlNtStatusToDosError;
 sRtlNtStatusToDosError pRtlNtStatusToDosError;
 sNtDeviceIoControlFile pNtDeviceIoControlFile;
 sNtDeviceIoControlFile pNtDeviceIoControlFile;
 sNtQueryInformationFile pNtQueryInformationFile;
 sNtQueryInformationFile pNtQueryInformationFile;
@@ -34,20 +35,8 @@ sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
 sNtQueryDirectoryFile pNtQueryDirectoryFile;
 sNtQueryDirectoryFile pNtQueryDirectoryFile;
 sNtQuerySystemInformation pNtQuerySystemInformation;
 sNtQuerySystemInformation pNtQuerySystemInformation;
 
 
-
 /* Kernel32 function pointers */
 /* Kernel32 function pointers */
 sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
 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 */
 /* Powrprof.dll function pointer */
 sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
 sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
@@ -55,22 +44,21 @@ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
 /* User32.dll function pointer */
 /* User32.dll function pointer */
 sSetWinEventHook pSetWinEventHook;
 sSetWinEventHook pSetWinEventHook;
 
 
-/* iphlpapi.dll function pointer */
-sConvertInterfaceIndexToLuid pConvertInterfaceIndexToLuid = NULL;
-sConvertInterfaceLuidToNameW pConvertInterfaceLuidToNameW = NULL;
 
 
 void uv_winapi_init(void) {
 void uv_winapi_init(void) {
   HMODULE ntdll_module;
   HMODULE ntdll_module;
-  HMODULE kernel32_module;
   HMODULE powrprof_module;
   HMODULE powrprof_module;
   HMODULE user32_module;
   HMODULE user32_module;
-  HMODULE iphlpapi_module;
+  HMODULE kernel32_module;
 
 
   ntdll_module = GetModuleHandleA("ntdll.dll");
   ntdll_module = GetModuleHandleA("ntdll.dll");
   if (ntdll_module == NULL) {
   if (ntdll_module == NULL) {
     uv_fatal_error(GetLastError(), "GetModuleHandleA");
     uv_fatal_error(GetLastError(), "GetModuleHandleA");
   }
   }
 
 
+  pRtlGetVersion = (sRtlGetVersion) GetProcAddress(ntdll_module,
+                                                   "RtlGetVersion");
+
   pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
   pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
       ntdll_module,
       ntdll_module,
       "RtlNtStatusToDosError");
       "RtlNtStatusToDosError");
@@ -127,37 +115,6 @@ void uv_winapi_init(void) {
       kernel32_module,
       kernel32_module,
       "GetQueuedCompletionStatusEx");
       "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");
   powrprof_module = LoadLibraryA("powrprof.dll");
   if (powrprof_module != NULL) {
   if (powrprof_module != NULL) {
     pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
     pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
@@ -170,11 +127,4 @@ void uv_winapi_init(void) {
       GetProcAddress(user32_module, "SetWinEventHook");
       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)
 # define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L)
 #endif
 #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
 #ifdef NTSTATUS_FROM_WIN32
 # undef NTSTATUS_FROM_WIN32
 # undef NTSTATUS_FROM_WIN32
 #endif
 #endif
@@ -4109,6 +4109,9 @@
 #endif
 #endif
 
 
 /* from winternl.h */
 /* from winternl.h */
+#if !defined(__UNICODE_STRING_DEFINED) && defined(__MINGW32_)
+#define __UNICODE_STRING_DEFINED
+#endif
 typedef struct _UNICODE_STRING {
 typedef struct _UNICODE_STRING {
   USHORT Length;
   USHORT Length;
   USHORT MaximumLength;
   USHORT MaximumLength;
@@ -4516,6 +4519,9 @@ typedef VOID (NTAPI *PIO_APC_ROUTINE)
               PIO_STATUS_BLOCK IoStatusBlock,
               PIO_STATUS_BLOCK IoStatusBlock,
               ULONG Reserved);
               ULONG Reserved);
 
 
+typedef NTSTATUS (NTAPI *sRtlGetVersion)
+                 (PRTL_OSVERSIONINFOW lpVersionInformation);
+
 typedef ULONG (NTAPI *sRtlNtStatusToDosError)
 typedef ULONG (NTAPI *sRtlNtStatusToDosError)
               (NTSTATUS Status);
               (NTSTATUS Status);
 
 
@@ -4650,48 +4656,6 @@ typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
               DWORD dwMilliseconds,
               DWORD dwMilliseconds,
               BOOL fAlertable);
               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 */
 /* from powerbase.h */
 #ifndef DEVICE_NOTIFY_CALLBACK
 #ifndef DEVICE_NOTIFY_CALLBACK
 # define DEVICE_NOTIFY_CALLBACK 2
 # define DEVICE_NOTIFY_CALLBACK 2
@@ -4746,6 +4710,7 @@ typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook)
 
 
 
 
 /* Ntdll function pointers */
 /* Ntdll function pointers */
+extern sRtlGetVersion pRtlGetVersion;
 extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
 extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
 extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
 extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
 extern sNtQueryInformationFile pNtQueryInformationFile;
 extern sNtQueryInformationFile pNtQueryInformationFile;
@@ -4754,20 +4719,8 @@ extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
 extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
 extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
 extern sNtQuerySystemInformation pNtQuerySystemInformation;
 extern sNtQuerySystemInformation pNtQuerySystemInformation;
 
 
-
 /* Kernel32 function pointers */
 /* Kernel32 function pointers */
 extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
 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 */
 /* Powrprof.dll function pointer */
 extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
 extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
@@ -4775,19 +4728,4 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi
 /* User32.dll function pointer */
 /* User32.dll function pointer */
 extern sSetWinEventHook pSetWinEventHook;
 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_ */
 #endif /* UV_WIN_WINAPI_H_ */

+ 4 - 4
src/win/winsock.c

@@ -256,8 +256,8 @@ int uv_ntstatus_to_winsock_error(NTSTATUS status) {
     default:
     default:
       if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
       if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
           (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
           (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);
         return (DWORD) (status & 0xffff);
       } else {
       } else {
         /* The default fallback for unmappable ntstatus codes. */
         /* 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);
                                   sizeof *info_out);
 
 
   if (overlapped == NULL) {
   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) {
     if (status == STATUS_PENDING) {
       DWORD r = WaitForSingleObject(event, INFINITE);
       DWORD r = WaitForSingleObject(event, INFINITE);
 
 

Some files were not shown because too many files changed in this diff