Browse Source

Merge topic 'update-libuv'

23de1675fd libuv: Update CMake-internal buildsystem for 1.44.2
ff82df301c Merge branch 'upstream-libuv' into update-libuv
a23da15596 libuv 2022-07-12 (0c1fa696)
cfe8fd6421 libuv: Update script to get libuv 1.44.2

Acked-by: Kitware Robot <[email protected]>
Merge-request: !7709
Brad King 3 years ago
parent
commit
a48d668d18
56 changed files with 2525 additions and 1410 deletions
  1. 1 1
      Utilities/Scripts/update-libuv.bash
  2. 2 0
      Utilities/cmlibuv/CMakeLists.txt
  3. 3 2
      Utilities/cmlibuv/include/uv.h
  4. 4 4
      Utilities/cmlibuv/include/uv/version.h
  5. 7 1
      Utilities/cmlibuv/include/uv/win.h
  6. 1 1
      Utilities/cmlibuv/src/fs-poll.c
  7. 6 5
      Utilities/cmlibuv/src/idna.c
  8. 1 1
      Utilities/cmlibuv/src/strscpy.h
  9. 52 0
      Utilities/cmlibuv/src/strtok.c
  10. 27 0
      Utilities/cmlibuv/src/strtok.h
  11. 8 7
      Utilities/cmlibuv/src/unix/atomic-ops.h
  12. 4 4
      Utilities/cmlibuv/src/unix/bsd-ifaddrs.c
  13. 1 0
      Utilities/cmlibuv/src/unix/bsd-proctitle.c
  14. 2 0
      Utilities/cmlibuv/src/unix/cmake-bootstrap.c
  15. 144 100
      Utilities/cmlibuv/src/unix/core.c
  16. 15 0
      Utilities/cmlibuv/src/unix/freebsd.c
  17. 16 2
      Utilities/cmlibuv/src/unix/fs.c
  18. 167 0
      Utilities/cmlibuv/src/unix/hurd.c
  19. 17 8
      Utilities/cmlibuv/src/unix/internal.h
  20. 22 1
      Utilities/cmlibuv/src/unix/kqueue.c
  21. 3 26
      Utilities/cmlibuv/src/unix/linux-core.c
  22. 19 17
      Utilities/cmlibuv/src/unix/os390-syscalls.c
  23. 232 57
      Utilities/cmlibuv/src/unix/os390.c
  24. 5 3
      Utilities/cmlibuv/src/unix/pipe.c
  25. 661 125
      Utilities/cmlibuv/src/unix/process.c
  26. 27 72
      Utilities/cmlibuv/src/unix/stream.c
  27. 29 7
      Utilities/cmlibuv/src/unix/sunos.c
  28. 14 5
      Utilities/cmlibuv/src/unix/tcp.c
  29. 53 33
      Utilities/cmlibuv/src/unix/thread.c
  30. 68 16
      Utilities/cmlibuv/src/unix/tty.c
  31. 20 8
      Utilities/cmlibuv/src/unix/udp.c
  32. 3 1
      Utilities/cmlibuv/src/uv-common.c
  33. 4 1
      Utilities/cmlibuv/src/uv-common.h
  34. 5 5
      Utilities/cmlibuv/src/win/async.c
  35. 47 43
      Utilities/cmlibuv/src/win/core.c
  36. 18 18
      Utilities/cmlibuv/src/win/fs-event.c
  37. 12 12
      Utilities/cmlibuv/src/win/fs.c
  38. 13 13
      Utilities/cmlibuv/src/win/handle-inl.h
  39. 13 13
      Utilities/cmlibuv/src/win/handle.c
  40. 72 73
      Utilities/cmlibuv/src/win/internal.h
  41. 2 2
      Utilities/cmlibuv/src/win/loop-watcher.c
  42. 299 252
      Utilities/cmlibuv/src/win/pipe.c
  43. 19 17
      Utilities/cmlibuv/src/win/poll.c
  44. 10 10
      Utilities/cmlibuv/src/win/process.c
  45. 18 25
      Utilities/cmlibuv/src/win/req-inl.h
  46. 6 6
      Utilities/cmlibuv/src/win/signal.c
  47. 4 4
      Utilities/cmlibuv/src/win/stream-inl.h
  48. 19 12
      Utilities/cmlibuv/src/win/stream.c
  49. 129 126
      Utilities/cmlibuv/src/win/tcp.c
  50. 2 1
      Utilities/cmlibuv/src/win/thread.c
  51. 112 109
      Utilities/cmlibuv/src/win/tty.c
  52. 52 51
      Utilities/cmlibuv/src/win/udp.c
  53. 14 92
      Utilities/cmlibuv/src/win/util.c
  54. 4 4
      Utilities/cmlibuv/src/win/winapi.c
  55. 14 14
      Utilities/cmlibuv/src/win/winsock.c
  56. 3 0
      bootstrap

+ 1 - 1
Utilities/Scripts/update-libuv.bash

@@ -8,7 +8,7 @@ readonly name="libuv"
 readonly ownership="libuv upstream <[email protected]>"
 readonly subtree="Utilities/cmlibuv"
 readonly repo="https://github.com/libuv/libuv.git"
-readonly tag="v1.x"
+readonly tag="v1.44.2"
 readonly shortlog=false
 readonly paths="
   LICENSE

+ 2 - 0
Utilities/cmlibuv/CMakeLists.txt

@@ -27,6 +27,8 @@ set(uv_sources
   src/queue.h
   src/strscpy.c
   src/strscpy.h
+  src/strtok.c
+  src/strtok.h
   src/threadpool.c
   src/timer.c
   src/uv-common.c

+ 3 - 2
Utilities/cmlibuv/include/uv.h

@@ -1150,8 +1150,8 @@ struct uv_interface_address_s {
 
 struct uv_passwd_s {
   char* username;
-  long uid;
-  long gid;
+  unsigned long uid;
+  unsigned long gid;
   char* shell;
   char* homedir;
 };
@@ -1259,6 +1259,7 @@ UV_EXTERN uv_pid_t uv_os_getppid(void);
 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 unsigned int uv_available_parallelism(void);
 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 int uv_cpumask_size(void);

+ 4 - 4
Utilities/cmlibuv/include/uv/version.h

@@ -31,10 +31,10 @@
  */
 
 #define UV_VERSION_MAJOR 1
-#define UV_VERSION_MINOR 43
-#define UV_VERSION_PATCH 1
-#define UV_VERSION_IS_RELEASE 0
-#define UV_VERSION_SUFFIX "dev"
+#define UV_VERSION_MINOR 44
+#define UV_VERSION_PATCH 2
+#define UV_VERSION_IS_RELEASE 1
+#define UV_VERSION_SUFFIX ""
 
 #define UV_VERSION_HEX  ((UV_VERSION_MAJOR << 16) | \
                          (UV_VERSION_MINOR <<  8) | \

+ 7 - 1
Utilities/cmlibuv/include/uv/win.h

@@ -234,7 +234,7 @@ typedef struct _AFD_POLL_INFO {
   AFD_POLL_HANDLE_INFO Handles[1];
 } AFD_POLL_INFO, *PAFD_POLL_INFO;
 
-#define UV_MSAFD_PROVIDER_COUNT 3
+#define UV_MSAFD_PROVIDER_COUNT 4
 
 
 /**
@@ -388,6 +388,12 @@ typedef struct {
       OVERLAPPED overlapped;                                                  \
       size_t queued_bytes;                                                    \
     } io;                                                                     \
+    /* in v2, we can move these to the UV_CONNECT_PRIVATE_FIELDS */           \
+    struct {                                                                  \
+      ULONG_PTR result; /* overlapped.Internal is reused to hold the result */\
+      HANDLE pipeHandle;                                                      \
+      DWORD duplex_flags;                                                     \
+    } connect;                                                                \
   } u;                                                                        \
   struct uv_req_s* next_req;
 

+ 1 - 1
Utilities/cmlibuv/src/fs-poll.c

@@ -25,7 +25,7 @@
 #ifdef _WIN32
 #include "win/internal.h"
 #include "win/handle-inl.h"
-#define uv__make_close_pending(h) uv_want_endgame((h)->loop, (h))
+#define uv__make_close_pending(h) uv__want_endgame((h)->loop, (h))
 #else
 #include "unix/internal.h"
 #endif

+ 6 - 5
Utilities/cmlibuv/src/idna.c

@@ -21,6 +21,7 @@
 #include "idna.h"
 #include <assert.h>
 #include <string.h>
+#include <limits.h> /* UINT_MAX */
 
 static unsigned uv__utf8_decode1_slow(const char** p,
                                       const char* pe,
@@ -129,7 +130,7 @@ static int uv__idna_toascii_label(const char* s, const char* se,
   while (s < se) {
     c = uv__utf8_decode1(&s, se);
 
-    if (c == -1u)
+    if (c == UINT_MAX)
       return UV_EINVAL;
 
     if (c < 128)
@@ -151,7 +152,7 @@ static int uv__idna_toascii_label(const char* s, const char* se,
   s = ss;
   while (s < se) {
     c = uv__utf8_decode1(&s, se);
-    assert(c != -1u);
+    assert(c != UINT_MAX);
 
     if (c > 127)
       continue;
@@ -182,7 +183,7 @@ static int uv__idna_toascii_label(const char* s, const char* se,
 
     while (s < se) {
       c = uv__utf8_decode1(&s, se);
-      assert(c != -1u);
+      assert(c != UINT_MAX);
 
       if (c >= n)
         if (c < m)
@@ -201,7 +202,7 @@ static int uv__idna_toascii_label(const char* s, const char* se,
     s = ss;
     while (s < se) {
       c = uv__utf8_decode1(&s, se);
-      assert(c != -1u);
+      assert(c != UINT_MAX);
 
       if (c < n)
         if (++delta == 0)
@@ -280,7 +281,7 @@ long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
     st = si;
     c = uv__utf8_decode1(&si, se);
 
-    if (c == -1u)
+    if (c == UINT_MAX)
       return UV_EINVAL;
 
     if (c != '.')

+ 1 - 1
Utilities/cmlibuv/src/strscpy.h

@@ -28,7 +28,7 @@
  */
 #include "uv.h"
 
-/* Copies up to |n-1| bytes from |d| to |s| and always zero-terminates
+/* Copies up to |n-1| bytes from |s| to |d| and always zero-terminates
  * the result, except when |n==0|. Returns the number of bytes copied
  * or UV_E2BIG if |d| is too small.
  *

+ 52 - 0
Utilities/cmlibuv/src/strtok.c

@@ -0,0 +1,52 @@
+/* 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 <stdlib.h>
+#include "strtok.h"
+
+char* uv__strtok(char* str, const char* sep, char** itr) {
+  const char* sep_itr;
+  char* tmp;
+  char* start;
+
+  if (str == NULL)
+    start = tmp = *itr;
+  else
+    start = tmp = str;
+
+  if (tmp == NULL)
+    return NULL;
+
+  while (*tmp != '\0') {
+    sep_itr = sep;
+    while (*sep_itr != '\0') {
+      if (*tmp == *sep_itr) {
+        *itr = tmp + 1;
+        *tmp = '\0';
+        return start;
+      }
+      sep_itr++;
+    }
+    tmp++;
+  }
+  *itr = NULL;
+  return start;
+}

+ 27 - 0
Utilities/cmlibuv/src/strtok.h

@@ -0,0 +1,27 @@
+/* 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.
+ */
+
+#ifndef UV_STRTOK_H_
+#define UV_STRTOK_H_
+
+char* uv__strtok(char* str, const char* sep, char** itr);
+
+#endif  /* UV_STRTOK_H_ */

+ 8 - 7
Utilities/cmlibuv/src/unix/atomic-ops.h

@@ -43,12 +43,11 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
   __compare_and_swap((volatile int*)ptr, &oldval, newval);
   return oldval;
 #elif defined(__MVS__)
-  unsigned int op4;
-  if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
-                (unsigned int*) ptr, *ptr, &op4))
-    return oldval;
-  else
-    return op4;
+  /* Use hand-rolled assembly because codegen from builtin __plo_CSST results in
+   * a runtime bug.
+   */
+  __asm(" cs %0,%2,%1 \n " : "+r"(oldval), "+m"(*ptr) : "r"(newval) :);
+  return oldval;
 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
   return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval);
 #else
@@ -61,7 +60,9 @@ UV_UNUSED(static void cpu_relax(void)) {
   __asm__ __volatile__ ("rep; nop" ::: "memory");  /* a.k.a. PAUSE */
 #elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
   __asm__ __volatile__ ("yield" ::: "memory");
-#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)
+#elif (defined(__ppc__) || defined(__ppc64__)) && defined(__APPLE__)
+  __asm volatile ("" : : : "memory");
+#elif !defined(__APPLE__) && (defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__))
   __asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory");
 #endif
 }

+ 4 - 4
Utilities/cmlibuv/src/unix/bsd-ifaddrs.c

@@ -27,7 +27,7 @@
 
 #include <ifaddrs.h>
 #include <net/if.h>
-#if !defined(__CYGWIN__) && !defined(__MSYS__)
+#if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__GNU__)
 #include <net/if_dl.h>
 #endif
 
@@ -40,7 +40,7 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
     return 1;
   if (ent->ifa_addr == NULL)
     return 1;
-#if !defined(__CYGWIN__) && !defined(__MSYS__)
+#if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__GNU__)
   /*
    * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, return whether `sa_family`
    * equals `AF_LINK`. Otherwise, the result depends on the operating
@@ -69,7 +69,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   struct ifaddrs* addrs;
   struct ifaddrs* ent;
   uv_interface_address_t* address;
-#if !(defined(__CYGWIN__) || defined(__MSYS__))
+#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__)
   int i;
 #endif
 
@@ -126,7 +126,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
     address++;
   }
 
-#if !(defined(__CYGWIN__) || defined(__MSYS__))
+#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__)
   /* Fill in physical addresses for each interface */
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
     if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))

+ 1 - 0
Utilities/cmlibuv/src/unix/bsd-proctitle.c

@@ -38,6 +38,7 @@ static void init_process_title_mutex_once(void) {
 
 
 void uv__process_title_cleanup(void) {
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
   uv_mutex_destroy(&process_title_mutex);
 }
 

+ 2 - 0
Utilities/cmlibuv/src/unix/cmake-bootstrap.c

@@ -135,7 +135,9 @@ int uv__statx(int dirfd,
   errno = ENOSYS;
   return -1;
 }
+#endif
 
+#if defined(__linux__) || defined(__FreeBSD__)
 ssize_t uv__fs_copy_file_range(int fd_in, off_t* off_in,
                                int fd_out, off_t* off_out,
                                size_t len, unsigned int flags)

+ 144 - 100
Utilities/cmlibuv/src/unix/core.c

@@ -20,6 +20,7 @@
 
 #include "uv.h"
 #include "internal.h"
+#include "strtok.h"
 
 #include <stddef.h> /* NULL */
 #include <stdio.h> /* printf */
@@ -86,10 +87,12 @@ extern char** environ;
 #endif
 
 #if defined(__MVS__)
-#include <sys/ioctl.h>
+# include <sys/ioctl.h>
+# include "zos-sys-info.h"
 #endif
 
 #if defined(__linux__)
+# include <sched.h>
 # include <sys/syscall.h>
 # define uv__accept4 accept4
 #endif
@@ -98,7 +101,7 @@ extern char** environ;
 # include <sanitizer/linux_syscall_hooks.h>
 #endif
 
-static int uv__run_pending(uv_loop_t* loop);
+static void uv__run_pending(uv_loop_t* loop);
 
 /* Verify that uv_buf_t is ABI-compatible with struct iovec. */
 STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
@@ -164,6 +167,15 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
 
   case UV_FS_EVENT:
     uv__fs_event_close((uv_fs_event_t*)handle);
+#if defined(__sun) || defined(__MVS__)
+    /*
+     * On Solaris, illumos, and z/OS we will not be able to dissociate the
+     * watcher for an event which is pending delivery, so we cannot always call
+     * uv__make_close_pending() straight away. The backend will call the
+     * function once the event has cleared.
+     */
+    return;
+#endif
     break;
 
   case UV_POLL:
@@ -340,42 +352,43 @@ int uv_backend_fd(const uv_loop_t* loop) {
 }
 
 
-int uv_backend_timeout(const uv_loop_t* loop) {
-  if (loop->stop_flag != 0)
-    return 0;
-
-  if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
-    return 0;
-
-  if (!QUEUE_EMPTY(&loop->idle_handles))
-    return 0;
-
-  if (!QUEUE_EMPTY(&loop->pending_queue))
-    return 0;
+static int uv__loop_alive(const uv_loop_t* loop) {
+  return uv__has_active_handles(loop) ||
+         uv__has_active_reqs(loop) ||
+         !QUEUE_EMPTY(&loop->pending_queue) ||
+         loop->closing_handles != NULL;
+}
 
-  if (loop->closing_handles)
-    return 0;
 
-  return uv__next_timeout(loop);
+static int uv__backend_timeout(const uv_loop_t* loop) {
+  if (loop->stop_flag == 0 &&
+      /* uv__loop_alive(loop) && */
+      (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) &&
+      QUEUE_EMPTY(&loop->pending_queue) &&
+      QUEUE_EMPTY(&loop->idle_handles) &&
+      loop->closing_handles == NULL)
+    return uv__next_timeout(loop);
+  return 0;
 }
 
 
-static int uv__loop_alive(const uv_loop_t* loop) {
-  return uv__has_active_handles(loop) ||
-         uv__has_active_reqs(loop) ||
-         loop->closing_handles != NULL;
+int uv_backend_timeout(const uv_loop_t* loop) {
+  if (QUEUE_EMPTY(&loop->watcher_queue))
+    return uv__backend_timeout(loop);
+  /* Need to call uv_run to update the backend fd state. */
+  return 0;
 }
 
 
 int uv_loop_alive(const uv_loop_t* loop) {
-    return uv__loop_alive(loop);
+  return uv__loop_alive(loop);
 }
 
 
 int uv_run(uv_loop_t* loop, uv_run_mode mode) {
   int timeout;
   int r;
-  int ran_pending;
+  int can_sleep;
 
   r = uv__loop_alive(loop);
   if (!r)
@@ -384,16 +397,25 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
   while (r != 0 && loop->stop_flag == 0) {
     uv__update_time(loop);
     uv__run_timers(loop);
-    ran_pending = uv__run_pending(loop);
+
+    can_sleep =
+        QUEUE_EMPTY(&loop->pending_queue) && QUEUE_EMPTY(&loop->idle_handles);
+
+    uv__run_pending(loop);
     uv__run_idle(loop);
     uv__run_prepare(loop);
 
     timeout = 0;
-    if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
-      timeout = uv_backend_timeout(loop);
+    if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT)
+      timeout = uv__backend_timeout(loop);
 
     uv__io_poll(loop, timeout);
 
+    /* Process immediate callbacks (e.g. write_cb) a small fixed number of
+     * times to avoid loop starvation.*/
+    for (r = 0; r < 8 && !QUEUE_EMPTY(&loop->pending_queue); r++)
+      uv__run_pending(loop);
+
     /* Run one final update on the provider_idle_time in case uv__io_poll
      * returned because the timeout expired, but no events were received. This
      * call will be ignored if the provider_entry_time was either never set (if
@@ -603,20 +625,6 @@ int uv__nonblock_ioctl(int fd, int set) {
 
   return 0;
 }
-
-
-int uv__cloexec_ioctl(int fd, int set) {
-  int r;
-
-  do
-    r = ioctl(fd, set ? FIOCLEX : FIONCLEX);
-  while (r == -1 && errno == EINTR);
-
-  if (r)
-    return UV__ERR(errno);
-
-  return 0;
-}
 #endif
 
 
@@ -651,25 +659,13 @@ int uv__nonblock_fcntl(int fd, int set) {
 }
 
 
-int uv__cloexec_fcntl(int fd, int set) {
+int uv__cloexec(int fd, int set) {
   int flags;
   int r;
 
-  do
-    r = fcntl(fd, F_GETFD);
-  while (r == -1 && errno == EINTR);
-
-  if (r == -1)
-    return UV__ERR(errno);
-
-  /* Bail out now if already set/clear. */
-  if (!!(r & FD_CLOEXEC) == !!set)
-    return 0;
-
+  flags = 0;
   if (set)
-    flags = r | FD_CLOEXEC;
-  else
-    flags = r & ~FD_CLOEXEC;
+    flags = FD_CLOEXEC;
 
   do
     r = fcntl(fd, F_SETFD, flags);
@@ -683,28 +679,23 @@ int uv__cloexec_fcntl(int fd, int set) {
 
 
 ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
-  struct cmsghdr* cmsg;
+#if defined(__ANDROID__)   || \
+    defined(__DragonFly__) || \
+    defined(__FreeBSD__)   || \
+    defined(__NetBSD__)    || \
+    defined(__OpenBSD__)   || \
+    defined(__linux__)
   ssize_t rc;
+  rc = recvmsg(fd, msg, flags | MSG_CMSG_CLOEXEC);
+  if (rc == -1)
+    return UV__ERR(errno);
+  return rc;
+#else
+  struct cmsghdr* cmsg;
   int* pfd;
   int* end;
-#if defined(__linux__)
-  static int no_msg_cmsg_cloexec;
-  if (0 == uv__load_relaxed(&no_msg_cmsg_cloexec)) {
-    rc = recvmsg(fd, msg, flags | 0x40000000);  /* MSG_CMSG_CLOEXEC */
-    if (rc != -1)
-      return rc;
-    if (errno != EINVAL)
-      return UV__ERR(errno);
-    rc = recvmsg(fd, msg, flags);
-    if (rc == -1)
-      return UV__ERR(errno);
-    uv__store_relaxed(&no_msg_cmsg_cloexec, 1);
-  } else {
-    rc = recvmsg(fd, msg, flags);
-  }
-#else
+  ssize_t rc;
   rc = recvmsg(fd, msg, flags);
-#endif
   if (rc == -1)
     return UV__ERR(errno);
   if (msg->msg_controllen == 0)
@@ -717,6 +708,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
            pfd += 1)
         uv__cloexec(*pfd, 1);
   return rc;
+#endif
 }
 
 
@@ -809,14 +801,11 @@ int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
 }
 
 
-static int uv__run_pending(uv_loop_t* loop) {
+static void uv__run_pending(uv_loop_t* loop) {
   QUEUE* q;
   QUEUE pq;
   uv__io_t* w;
 
-  if (QUEUE_EMPTY(&loop->pending_queue))
-    return 0;
-
   QUEUE_MOVE(&loop->pending_queue, &pq);
 
   while (!QUEUE_EMPTY(&pq)) {
@@ -826,8 +815,6 @@ static int uv__run_pending(uv_loop_t* loop) {
     w = QUEUE_DATA(q, uv__io_t, pending_queue);
     w->cb(loop, w, POLLOUT);
   }
-
-  return 1;
 }
 
 
@@ -1042,6 +1029,32 @@ int uv__open_cloexec(const char* path, int flags) {
 }
 
 
+int uv__slurp(const char* filename, char* buf, size_t len) {
+  ssize_t n;
+  int fd;
+
+  assert(len > 0);
+
+  fd = uv__open_cloexec(filename, O_RDONLY);
+  if (fd < 0)
+    return fd;
+
+  do
+    n = read(fd, buf, len - 1);
+  while (n == -1 && errno == EINTR);
+
+  if (uv__close_nocheckstdio(fd))
+    abort();
+
+  if (n < 0)
+    return UV__ERR(errno);
+
+  buf[n] = '\0';
+
+  return 0;
+}
+
+
 int uv__dup2_cloexec(int oldfd, int newfd) {
 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__)
   int r;
@@ -1166,24 +1179,17 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
   size_t name_size;
   size_t homedir_size;
   size_t shell_size;
-  long initsize;
   int r;
 
   if (pwd == NULL)
     return UV_EINVAL;
 
-  initsize = sysconf(_SC_GETPW_R_SIZE_MAX);
-
-  if (initsize <= 0)
-    bufsize = 4096;
-  else
-    bufsize = (size_t) initsize;
-
   uid = geteuid();
-  buf = NULL;
 
-  for (;;) {
-    uv__free(buf);
+  /* Calling sysconf(_SC_GETPW_R_SIZE_MAX) would get the suggested size, but it
+   * is frequently 1024 or 4096, so we can just use that directly. The pwent
+   * will not usually be large. */
+  for (bufsize = 2000;; bufsize *= 2) {
     buf = uv__malloc(bufsize);
 
     if (buf == NULL)
@@ -1193,21 +1199,18 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
       r = getpwuid_r(uid, &pw, buf, bufsize, &result);
     while (r == EINTR);
 
+    if (r != 0 || result == NULL)
+      uv__free(buf);
+
     if (r != ERANGE)
       break;
-
-    bufsize *= 2;
   }
 
-  if (r != 0) {
-    uv__free(buf);
+  if (r != 0)
     return UV__ERR(r);
-  }
 
-  if (result == NULL) {
-    uv__free(buf);
+  if (result == NULL)
     return UV_ENOENT;
-  }
 
   /* Allocate memory for the username, shell, and home directory */
   name_size = strlen(pw.pw_name) + 1;
@@ -1569,6 +1572,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
   char* cloned_path;
   char* path_env;
   char* token;
+  char* itr;
 
   if (buf == NULL || buflen == NULL || *buflen == 0)
     return UV_EINVAL;
@@ -1610,7 +1614,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
   if (cloned_path == NULL)
     return UV_ENOMEM;
 
-  token = strtok(cloned_path, ":");
+  token = uv__strtok(cloned_path, ":", &itr);
   while (token != NULL) {
     snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, prog);
     if (realpath(trypath, abspath) == abspath) {
@@ -1629,10 +1633,50 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
         return 0;
       }
     }
-    token = strtok(NULL, ":");
+    token = uv__strtok(NULL, ":", &itr);
   }
   uv__free(cloned_path);
 
   /* Out of tokens (path entries), and no match found */
   return UV_EINVAL;
 }
+
+
+unsigned int uv_available_parallelism(void) {
+#ifdef __linux__
+  cpu_set_t set;
+  long rc;
+
+  memset(&set, 0, sizeof(set));
+
+  /* sysconf(_SC_NPROCESSORS_ONLN) in musl calls sched_getaffinity() but in
+   * glibc it's... complicated... so for consistency try sched_getaffinity()
+   * before falling back to sysconf(_SC_NPROCESSORS_ONLN).
+   */
+  if (0 == sched_getaffinity(0, sizeof(set), &set))
+    rc = CPU_COUNT(&set);
+  else
+    rc = sysconf(_SC_NPROCESSORS_ONLN);
+
+  if (rc < 1)
+    rc = 1;
+
+  return (unsigned) rc;
+#elif defined(__MVS__)
+  int rc;
+
+  rc = __get_num_online_cpus();
+  if (rc < 1)
+    rc = 1;
+
+  return (unsigned) rc;
+#else  /* __linux__ */
+  long rc;
+
+  rc = sysconf(_SC_NPROCESSORS_ONLN);
+  if (rc < 1)
+    rc = 1;
+
+  return (unsigned) rc;
+#endif  /* __linux__ */
+}

+ 15 - 0
Utilities/cmlibuv/src/unix/freebsd.c

@@ -287,3 +287,18 @@ int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
   return errno = ENOSYS, -1;
 #endif
 }
+
+ssize_t
+uv__fs_copy_file_range(int fd_in,
+                       off_t* off_in,
+                       int fd_out,
+                       off_t* off_out,
+                       size_t len,
+                       unsigned int flags)
+{
+#if __FreeBSD__ >= 13 && !defined(__DragonFly__)
+	return copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
+#else
+	return errno = ENOSYS, -1;
+#endif
+}

+ 16 - 2
Utilities/cmlibuv/src/unix/fs.c

@@ -247,7 +247,8 @@ UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) {
 static ssize_t uv__fs_futime(uv_fs_t* req) {
 #if defined(__linux__)                                                        \
     || defined(_AIX71)                                                        \
-    || defined(__HAIKU__)
+    || defined(__HAIKU__)                                                     \
+    || defined(__GNU__)
   struct timespec ts[2];
   ts[0] = uv__fs_to_timespec(req->atime);
   ts[1] = uv__fs_to_timespec(req->mtime);
@@ -1085,6 +1086,17 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
      */
 
 #if defined(__FreeBSD__) || defined(__DragonFly__)
+#if defined(__FreeBSD__)
+    off_t off;
+
+    off = req->off;
+    r = uv__fs_copy_file_range(in_fd, &off, out_fd, NULL, req->bufsml[0].len, 0);
+    if (r >= 0) {
+        r = off - req->off;
+        req->off = off;
+        return r;
+    }
+#endif
     len = 0;
     r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
 #elif defined(__FreeBSD_kernel__)
@@ -1179,7 +1191,9 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) {
 #if defined(__linux__)            ||                                           \
     defined(_AIX71)               ||                                           \
     defined(__sun)                ||                                           \
-    defined(__HAIKU__)
+    defined(__HAIKU__)            ||                                           \
+    defined(__GNU__)              ||                                           \
+    defined(__OpenBSD__)
   struct timespec ts[2];
   ts[0] = uv__fs_to_timespec(req->atime);
   ts[1] = uv__fs_to_timespec(req->mtime);

+ 167 - 0
Utilities/cmlibuv/src/unix/hurd.c

@@ -0,0 +1,167 @@
+/* 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.
+ */
+
+#define _GNU_SOURCE 1
+
+#include "uv.h"
+#include "internal.h"
+
+#include <hurd.h>
+#include <hurd/process.h>
+#include <mach/task_info.h>
+#include <mach/vm_statistics.h>
+#include <mach/vm_param.h>
+
+#include <inttypes.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+
+int uv_exepath(char* buffer, size_t* size) {
+  kern_return_t err;
+  /* XXX in current Hurd, strings are char arrays of 1024 elements */
+  string_t exepath;
+  ssize_t copied;
+
+  if (buffer == NULL || size == NULL || *size == 0)
+    return UV_EINVAL;
+
+  if (*size - 1 > 0) {
+    /* XXX limited length of buffer in current Hurd, this API will probably
+     * evolve in the future */
+    err = proc_get_exe(getproc(), getpid(), exepath);
+
+    if (err)
+      return UV__ERR(err);
+  }
+
+  copied = uv__strscpy(buffer, exepath, *size);
+
+  /* do not return error on UV_E2BIG failure */
+  *size = copied < 0 ? strlen(buffer) : (size_t) copied;
+
+  return 0;
+}
+
+int uv_resident_set_memory(size_t* rss) {
+  kern_return_t err;
+  struct task_basic_info bi;
+  mach_msg_type_number_t count;
+
+  count = TASK_BASIC_INFO_COUNT;
+  err = task_info(mach_task_self(), TASK_BASIC_INFO,
+		  (task_info_t) &bi, &count);
+
+  if (err)
+    return UV__ERR(err);
+
+  *rss = bi.resident_size;
+
+  return 0;
+}
+
+uint64_t uv_get_free_memory(void) {
+  kern_return_t err;
+  struct vm_statistics vmstats;
+  
+  err = vm_statistics(mach_task_self(), &vmstats);
+
+  if (err)
+    return 0;
+  
+  return vmstats.free_count * vm_page_size;
+}
+
+
+uint64_t uv_get_total_memory(void) {
+  kern_return_t err;
+  host_basic_info_data_t hbi;
+  mach_msg_type_number_t cnt;
+  
+  cnt = HOST_BASIC_INFO_COUNT;
+  err = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t) &hbi, &cnt); 
+
+  if (err)
+    return 0;
+
+  return hbi.memory_size;
+}
+
+
+int uv_uptime(double* uptime) {
+  char buf[128];
+
+  /* Try /proc/uptime first */
+  if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf)))
+    if (1 == sscanf(buf, "%lf", uptime))
+      return 0;
+
+  /* Reimplement here code from procfs to calculate uptime if not mounted? */
+
+  return UV__ERR(EIO);
+}
+
+void uv_loadavg(double avg[3]) {
+  char buf[128];  /* Large enough to hold all of /proc/loadavg. */
+
+  if (0 == uv__slurp("/proc/loadavg", buf, sizeof(buf)))
+    if (3 == sscanf(buf, "%lf %lf %lf", &avg[0], &avg[1], &avg[2]))
+      return;
+
+  /* Reimplement here code from procfs to calculate loadavg if not mounted? */
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+  kern_return_t err;
+  host_basic_info_data_t hbi;
+  mach_msg_type_number_t cnt;
+  
+  /* Get count of cpus  */
+  cnt = HOST_BASIC_INFO_COUNT;
+  err = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t) &hbi, &cnt); 
+
+  if (err) {
+    err = UV__ERR(err);
+    goto abort;
+  }
+
+  /* XXX not implemented on the Hurd */
+  *cpu_infos = uv__calloc(hbi.avail_cpus, sizeof(**cpu_infos));
+  if (*cpu_infos == NULL) {
+    err = UV_ENOMEM;
+    goto abort;
+  }
+
+  *count = hbi.avail_cpus;
+
+  return 0;
+  
+ abort:
+  *cpu_infos = NULL;
+  *count = 0;
+  return err;
+}
+
+uint64_t uv_get_constrained_memory(void) {
+  return 0;  /* Memory constraints are unknown. */
+}

+ 17 - 8
Utilities/cmlibuv/src/unix/internal.h

@@ -155,7 +155,8 @@ typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
 
 /* loop flags */
 enum {
-  UV_LOOP_BLOCK_SIGPROF = 1
+  UV_LOOP_BLOCK_SIGPROF = 0x1,
+  UV_LOOP_REAP_CHILDREN = 0x2
 };
 
 /* flags of excluding ifaddr */
@@ -184,11 +185,9 @@ struct uv__stream_queued_fds_s {
     defined(__linux__) || \
     defined(__OpenBSD__) || \
     defined(__NetBSD__)
-#define uv__cloexec uv__cloexec_ioctl
 #define uv__nonblock uv__nonblock_ioctl
 #define UV__NONBLOCK_IS_IOCTL 1
 #else
-#define uv__cloexec uv__cloexec_fcntl
 #define uv__nonblock uv__nonblock_fcntl
 #define UV__NONBLOCK_IS_IOCTL 0
 #endif
@@ -206,8 +205,7 @@ struct uv__stream_queued_fds_s {
 #endif
 
 /* core */
-int uv__cloexec_ioctl(int fd, int set);
-int uv__cloexec_fcntl(int fd, int set);
+int uv__cloexec(int fd, int set);
 int uv__nonblock_ioctl(int fd, int set);
 int uv__nonblock_fcntl(int fd, int set);
 int uv__close(int fd); /* preserves errno */
@@ -251,14 +249,15 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
 int uv__accept(int sockfd);
 int uv__dup2_cloexec(int oldfd, int newfd);
 int uv__open_cloexec(const char* path, int flags);
+int uv__slurp(const char* filename, char* buf, size_t len);
 
 /* tcp */
-int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
+int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
 int uv__tcp_nodelay(int fd, int on);
 int uv__tcp_keepalive(int fd, int on, unsigned int delay);
 
 /* pipe */
-int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
+int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
 
 /* signal */
 void uv__signal_close(uv_signal_t* handle);
@@ -288,10 +287,10 @@ void uv__tcp_close(uv_tcp_t* handle);
 size_t uv__thread_stack_size(void);
 void uv__udp_close(uv_udp_t* handle);
 void uv__udp_finish_close(uv_udp_t* handle);
-uv_handle_type uv__handle_type(int fd);
 FILE* uv__open_file(const char* path);
 int uv__getpwuid_r(uv_passwd_t* pwd);
 int uv__search_path(const char* prog, char* buf, size_t* buflen);
+void uv__wait_children(uv_loop_t* loop);
 
 /* random */
 int uv__random_devurandom(void* buf, size_t buflen);
@@ -366,5 +365,15 @@ size_t strnlen(const char* s, size_t maxlen);
 #endif
 #endif
 
+#if defined(__FreeBSD__)
+ssize_t
+uv__fs_copy_file_range(int fd_in,
+                       off_t* off_in,
+                       int fd_out,
+                       off_t* off_out,
+                       size_t len,
+                       unsigned int flags);
+#endif
+
 
 #endif /* UV_UNIX_INTERNAL_H_ */

+ 22 - 1
Utilities/cmlibuv/src/unix/kqueue.c

@@ -117,6 +117,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
   unsigned int revents;
   QUEUE* q;
   uv__io_t* w;
+  uv_process_t* process;
   sigset_t* pset;
   sigset_t set;
   uint64_t base;
@@ -285,6 +286,21 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
     for (i = 0; i < nfds; i++) {
       ev = events + i;
       fd = ev->ident;
+
+      /* Handle kevent NOTE_EXIT results */
+      if (ev->filter == EVFILT_PROC) {
+        QUEUE_FOREACH(q, &loop->process_handles) {
+          process = QUEUE_DATA(q, uv_process_t, queue);
+          if (process->pid == fd) {
+            process->flags |= UV_HANDLE_REAP;
+            loop->flags |= UV_LOOP_REAP_CHILDREN;
+            break;
+          }
+        }
+        nevents++;
+        continue;
+      }
+
       /* Skip invalidated events, see uv__platform_invalidate_fd */
       if (fd == -1)
         continue;
@@ -377,6 +393,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
       nevents++;
     }
 
+    if (loop->flags & UV_LOOP_REAP_CHILDREN) {
+      loop->flags &= ~UV_LOOP_REAP_CHILDREN;
+      uv__wait_children(loop);
+    }
+
     if (reset_timeout != 0) {
       timeout = user_timeout;
       reset_timeout = 0;
@@ -435,7 +456,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
 
   /* Invalidate events with same file descriptor */
   for (i = 0; i < nfds; i++)
-    if ((int) events[i].ident == fd)
+    if ((int) events[i].ident == fd && events[i].filter != EVFILT_PROC)
       events[i].ident = -1;
 }
 

+ 3 - 26
Utilities/cmlibuv/src/unix/linux-core.c

@@ -211,31 +211,6 @@ err:
   return UV_EINVAL;
 }
 
-static int uv__slurp(const char* filename, char* buf, size_t len) {
-  ssize_t n;
-  int fd;
-
-  assert(len > 0);
-
-  fd = uv__open_cloexec(filename, O_RDONLY);
-  if (fd < 0)
-    return fd;
-
-  do
-    n = read(fd, buf, len - 1);
-  while (n == -1 && errno == EINTR);
-
-  if (uv__close_nocheckstdio(fd))
-    abort();
-
-  if (n < 0)
-    return UV__ERR(errno);
-
-  buf[n] = '\0';
-
-  return 0;
-}
-
 int uv_uptime(double* uptime) {
   static volatile int no_clock_boottime;
   char buf[128];
@@ -243,7 +218,7 @@ int uv_uptime(double* uptime) {
   int r;
 
   /* Try /proc/uptime first, then fallback to clock_gettime(). */
-  
+
   if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf)))
     if (1 == sscanf(buf, "%lf", uptime))
       return 0;
@@ -641,6 +616,7 @@ static uint64_t read_cpufreq(unsigned int cpunum) {
 }
 
 
+#ifdef HAVE_IFADDRS_H
 static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
   if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
     return 1;
@@ -654,6 +630,7 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
     return exclude_type;
   return !exclude_type;
 }
+#endif
 
 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
 #ifndef HAVE_IFADDRS_H

+ 19 - 17
Utilities/cmlibuv/src/unix/os390-syscalls.c

@@ -284,6 +284,8 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
   nmsgsfds_t size;
   struct pollfd* pfds;
   int pollret;
+  int pollfdret;
+  int pollmsgret;
   int reventcount;
   int nevents;
   struct pollfd msg_fd;
@@ -304,24 +306,24 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
     return -1;
   }
 
-  if (lst->size > 0)
-    _SET_FDS_MSGS(size, 1, lst->size - 1);
-  else
-    _SET_FDS_MSGS(size, 0, 0);
+  assert(lst->size > 0);
+  _SET_FDS_MSGS(size, 1, lst->size - 1);
   pfds = lst->items;
   pollret = poll(pfds, size, timeout);
   if (pollret <= 0)
     return pollret;
 
-  assert(lst->size > 0);
-
-  pollret = _NFDS(pollret) + _NMSGS(pollret);
+  pollfdret = _NFDS(pollret);
+  pollmsgret = _NMSGS(pollret);
 
   reventcount = 0;
   nevents = 0;
-  msg_fd = pfds[lst->size - 1];
+  msg_fd = pfds[lst->size - 1]; /* message queue is always last entry */
+  maxevents = maxevents - pollmsgret; /* allow spot for message queue */
   for (i = 0;
-       i < lst->size && i < maxevents && reventcount < pollret; ++i) {
+       i < lst->size - 1 &&
+       nevents < maxevents &&
+       reventcount < pollfdret; ++i) {
     struct epoll_event ev;
     struct pollfd* pfd;
 
@@ -332,18 +334,18 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
     ev.fd = pfd->fd;
     ev.events = pfd->revents;
     ev.is_msg = 0;
-    if (pfd->revents & POLLIN && pfd->revents & POLLOUT)
-      reventcount += 2;
-    else if (pfd->revents & (POLLIN | POLLOUT))
-      ++reventcount;
 
-    pfd->revents = 0;
+    reventcount++;
     events[nevents++] = ev;
   }
 
-  if (msg_fd.revents != 0 && msg_fd.fd != -1)
-    if (i == lst->size)
-      events[nevents - 1].is_msg = 1;
+  if (pollmsgret > 0 && msg_fd.revents != 0 && msg_fd.fd != -1) {
+    struct epoll_event ev;
+    ev.fd = msg_fd.fd;
+    ev.events = msg_fd.revents;
+    ev.is_msg = 1;
+    events[nevents++] = ev;
+  }
 
   return nevents;
 }

+ 232 - 57
Utilities/cmlibuv/src/unix/os390.c

@@ -278,7 +278,9 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
   __net_ifconf6header_t ifc;
   __net_ifconf6entry_t* ifr;
   __net_ifconf6entry_t* p;
-  __net_ifconf6entry_t flg;
+  unsigned int i;
+  int count_names;
+  unsigned char netmask[16] = {0};
 
   *count = 0;
   /* Assume maximum buffer size allowable */
@@ -287,24 +289,33 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
   if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
     return UV__ERR(errno);
 
+  ifc.__nif6h_buffer = uv__calloc(1, maxsize);
+
+  if (ifc.__nif6h_buffer == NULL) {
+    uv__close(sockfd);
+    return UV_ENOMEM;
+  }
+
   ifc.__nif6h_version = 1;
   ifc.__nif6h_buflen = maxsize;
-  ifc.__nif6h_buffer = uv__calloc(1, maxsize);;
 
   if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
+    /* This will error on a system that does not support IPv6. However, we want
+     * to treat this as there being 0 interfaces so we can continue to get IPv4
+     * interfaces in uv_interface_addresses(). So return 0 instead of the error.
+     */
+    uv__free(ifc.__nif6h_buffer);
     uv__close(sockfd);
-    return UV__ERR(errno);
+    errno = 0;
+    return 0;
   }
 
-
-  *count = 0;
   ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
   while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
     p = ifr;
     ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
 
-    if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
-          p->__nif6e_addr.sin6_family == AF_INET))
+    if (!(p->__nif6e_addr.sin6_family == AF_INET6))
       continue;
 
     if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
@@ -313,21 +324,28 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
     ++(*count);
   }
 
+  if ((*count) == 0) {
+    uv__free(ifc.__nif6h_buffer);
+    uv__close(sockfd);
+    return 0;
+  }
+
   /* Alloc the return interface structs */
-  *addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
+  *addresses = uv__calloc(1, *count * sizeof(uv_interface_address_t));
   if (!(*addresses)) {
+    uv__free(ifc.__nif6h_buffer);
     uv__close(sockfd);
     return UV_ENOMEM;
   }
   address = *addresses;
 
+  count_names = 0;
   ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
   while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
     p = ifr;
     ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
 
-    if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
-          p->__nif6e_addr.sin6_family == AF_INET))
+    if (!(p->__nif6e_addr.sin6_family == AF_INET6))
       continue;
 
     if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
@@ -335,20 +353,41 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
 
     /* All conditions above must match count loop */
 
-    address->name = uv__strdup(p->__nif6e_name);
+    i = 0;
+    /* Ignore EBCDIC space (0x40) padding in name */
+    while (i < ARRAY_SIZE(p->__nif6e_name) &&
+           p->__nif6e_name[i] != 0x40 &&
+           p->__nif6e_name[i] != 0)
+      ++i;
+    address->name = uv__malloc(i + 1);
+    if (address->name == NULL) {
+      uv_free_interface_addresses(*addresses, count_names);
+      uv__free(ifc.__nif6h_buffer);
+      uv__close(sockfd);
+      return UV_ENOMEM;
+    }
+    memcpy(address->name, p->__nif6e_name, i);
+    address->name[i] = '\0';
+    __e2a_s(address->name);
+    count_names++;
 
-    if (p->__nif6e_addr.sin6_family == AF_INET6)
-      address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
-    else
-      address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr);
+    address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
 
-    /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
+    for (i = 0; i < (p->__nif6e_prefixlen / 8); i++)
+      netmask[i] = 0xFF;
 
-    address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
-    memset(address->phys_addr, 0, sizeof(address->phys_addr));
+    if (p->__nif6e_prefixlen % 8)
+      netmask[i] = 0xFF << (8 - (p->__nif6e_prefixlen % 8));
+
+    address->netmask.netmask6.sin6_len = p->__nif6e_prefixlen;
+    memcpy(&(address->netmask.netmask6.sin6_addr), netmask, 16);
+    address->netmask.netmask6.sin6_family = AF_INET6;
+
+    address->is_internal = p->__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
     address++;
   }
 
+  uv__free(ifc.__nif6h_buffer);
   uv__close(sockfd);
   return 0;
 }
@@ -362,14 +401,18 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   struct ifreq flg;
   struct ifreq* ifr;
   struct ifreq* p;
+  uv_interface_address_t* addresses_v6;
   int count_v6;
+  unsigned int i;
+  int rc;
+  int count_names;
 
   *count = 0;
   *addresses = NULL;
 
   /* get the ipv6 addresses first */
-  uv_interface_address_t* addresses_v6;
-  uv__interface_addresses_v6(&addresses_v6, &count_v6);
+  if ((rc = uv__interface_addresses_v6(&addresses_v6, &count_v6)) != 0)
+    return rc;
 
   /* now get the ipv4 addresses */
 
@@ -377,12 +420,27 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   maxsize = 16384;
 
   sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
-  if (0 > sockfd)
+  if (0 > sockfd) {
+    if (count_v6)
+      uv_free_interface_addresses(addresses_v6, count_v6);
     return UV__ERR(errno);
+  }
 
   ifc.ifc_req = uv__calloc(1, maxsize);
+
+  if (ifc.ifc_req == NULL) {
+    if (count_v6)
+      uv_free_interface_addresses(addresses_v6, count_v6);
+    uv__close(sockfd);
+    return UV_ENOMEM;
+  }
+
   ifc.ifc_len = maxsize;
+
   if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
+    if (count_v6)
+      uv_free_interface_addresses(addresses_v6, count_v6);
+    uv__free(ifc.ifc_req);
     uv__close(sockfd);
     return UV__ERR(errno);
   }
@@ -403,6 +461,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
 
     memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
     if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+      if (count_v6)
+        uv_free_interface_addresses(addresses_v6, count_v6);
+      uv__free(ifc.ifc_req);
       uv__close(sockfd);
       return UV__ERR(errno);
     }
@@ -413,27 +474,35 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
     (*count)++;
   }
 
-  if (*count == 0) {
+  if (*count == 0 && count_v6 == 0) {
+    uv__free(ifc.ifc_req);
     uv__close(sockfd);
     return 0;
   }
 
   /* Alloc the return interface structs */
-  *addresses = uv__malloc((*count + count_v6) *
+  *addresses = uv__calloc(1, (*count + count_v6) *
                           sizeof(uv_interface_address_t));
 
   if (!(*addresses)) {
+    if (count_v6)
+      uv_free_interface_addresses(addresses_v6, count_v6);
+    uv__free(ifc.ifc_req);
     uv__close(sockfd);
     return UV_ENOMEM;
   }
   address = *addresses;
 
-  /* copy over the ipv6 addresses */
-  memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
-  address += count_v6;
-  *count += count_v6;
-  uv__free(addresses_v6);
+  /* copy over the ipv6 addresses if any are found */
+  if (count_v6) {
+    memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
+    address += count_v6;
+    *count += count_v6;
+    /* free ipv6 addresses, but keep address names */
+    uv__free(addresses_v6);
+  }
 
+  count_names = *count;
   ifr = ifc.ifc_req;
   while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
     p = ifr;
@@ -446,6 +515,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
 
     memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
     if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+      uv_free_interface_addresses(*addresses, count_names);
+      uv__free(ifc.ifc_req);
       uv__close(sockfd);
       return UV_ENOSYS;
     }
@@ -455,22 +526,43 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
 
     /* All conditions above must match count loop */
 
-    address->name = uv__strdup(p->ifr_name);
+    i = 0;
+    /* Ignore EBCDIC space (0x40) padding in name */
+    while (i < ARRAY_SIZE(p->ifr_name) &&
+           p->ifr_name[i] != 0x40 &&
+           p->ifr_name[i] != 0)
+      ++i;
+    address->name = uv__malloc(i + 1);
+    if (address->name == NULL) {
+      uv_free_interface_addresses(*addresses, count_names);
+      uv__free(ifc.ifc_req);
+      uv__close(sockfd);
+      return UV_ENOMEM;
+    }
+    memcpy(address->name, p->ifr_name, i);
+    address->name[i] = '\0';
+    __e2a_s(address->name);
+    count_names++;
+
+    address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
 
-    if (p->ifr_addr.sa_family == AF_INET6) {
-      address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
-    } else {
-      address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
+    if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) {
+      uv_free_interface_addresses(*addresses, count_names);
+      uv__free(ifc.ifc_req);
+      uv__close(sockfd);
+      return UV__ERR(errno);
     }
 
+    address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr);
+    address->netmask.netmask4.sin_family = AF_INET;
     address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
-    memset(address->phys_addr, 0, sizeof(address->phys_addr));
     address++;
   }
 
 #undef ADDR_SIZE
 #undef MAX
 
+  uv__free(ifc.ifc_req);
   uv__close(sockfd);
   return 0;
 }
@@ -529,27 +621,17 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) {
 }
 
 
-void uv__fs_event_close(uv_fs_event_t* handle) {
-  uv_fs_event_stop(handle);
-}
-
-
 int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
   uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
   return 0;
 }
 
 
-int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
-                      const char* filename, unsigned int flags) {
+static int os390_regfileint(uv_fs_event_t* handle, char* path) {
   uv__os390_epoll* ep;
   _RFIS reg_struct;
-  char* path;
   int rc;
 
-  if (uv__is_active(handle))
-    return UV_EINVAL;
-
   ep = handle->loop->ep;
   assert(ep->msg_queue != -1);
 
@@ -558,25 +640,44 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
   reg_struct.__rfis_type = 1;
   memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle));
 
+  rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
+  if (rc != 0)
+    return UV__ERR(errno);
+
+  memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
+         sizeof(handle->rfis_rftok));
+
+  return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
+                      const char* filename, unsigned int flags) {
+  char* path;
+  int rc;
+
+  if (uv__is_active(handle))
+    return UV_EINVAL;
+
   path = uv__strdup(filename);
   if (path == NULL)
     return UV_ENOMEM;
 
-  rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
-  if (rc != 0)
-    return UV__ERR(errno);
+  rc = os390_regfileint(handle, path);
+  if (rc != 0) {
+    uv__free(path);
+    return rc;
+  }
 
   uv__handle_start(handle);
   handle->path = path;
   handle->cb = cb;
-  memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
-         sizeof(handle->rfis_rftok));
 
   return 0;
 }
 
 
-int uv_fs_event_stop(uv_fs_event_t* handle) {
+int uv__fs_event_stop(uv_fs_event_t* handle) {
   uv__os390_epoll* ep;
   _RFIS reg_struct;
   int rc;
@@ -602,12 +703,40 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
   if (rc != 0 && errno != EALREADY && errno != ENOENT)
     abort();
 
+  if (handle->path != NULL) {
+    uv__free(handle->path);
+    handle->path = NULL;
+  }
+
+  if (rc != 0 && errno == EALREADY)
+    return -1;
+
   uv__handle_stop(handle);
 
   return 0;
 }
 
 
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+  uv__fs_event_stop(handle);
+  return 0;
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+  /*
+   * If we were unable to unregister file interest here, then it is most likely
+   * that there is a pending queued change notification. When this happens, we
+   * don't want to complete the close as it will free the underlying memory for
+   * the handle, causing a use-after-free problem when the event is processed.
+   * We defer the final cleanup until after the event is consumed in
+   * os390_message_queue_handler().
+   */
+  if (uv__fs_event_stop(handle) == 0)
+    uv__make_close_pending((uv_handle_t*) handle);
+}
+
+
 static int os390_message_queue_handler(uv__os390_epoll* ep) {
   uv_fs_event_t* handle;
   int msglen;
@@ -628,7 +757,15 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) {
   events = 0;
   if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE)
     events = UV_CHANGE;
-  else if (msg.__rfim_event == _RFIM_RENAME)
+  else if (msg.__rfim_event == _RFIM_RENAME || msg.__rfim_event == _RFIM_UNLINK)
+    events = UV_RENAME;
+  else if (msg.__rfim_event == 156)
+    /* TODO(gabylb): zos - this event should not happen, need to investigate.
+     *
+     * This event seems to occur when the watched file is [re]moved, or an
+     * editor (like vim) renames then creates the file on save (for vim, that's
+     * when backupcopy=no|auto).
+     */
     events = UV_RENAME;
   else
     /* Some event that we are not interested in. */
@@ -639,6 +776,26 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) {
    */
   __a2e_l(msg.__rfim_utok, sizeof(msg.__rfim_utok));
   handle = *(uv_fs_event_t**)(msg.__rfim_utok);
+  assert(handle != NULL);
+
+  assert((handle->flags & UV_HANDLE_CLOSED) == 0);
+  if (uv__is_closing(handle)) {
+    uv__handle_stop(handle);
+    uv__make_close_pending((uv_handle_t*) handle);
+    return 0;
+  } else if (handle->path == NULL) {
+    /* _RFIS_UNREG returned EALREADY. */
+    uv__handle_stop(handle);
+    return 0;
+  }
+
+  /* The file is implicitly unregistered when the change notification is
+   * sent, only one notification is sent per registration. So we need to
+   * re-register interest in a file after each change notification we
+   * receive.
+   */
+  assert(handle->path != NULL);
+  os390_regfileint(handle, handle->path);
   handle->cb(handle, uv__basename_r(handle->path), events, 0);
   return 1;
 }
@@ -650,6 +807,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
   struct epoll_event* pe;
   struct epoll_event e;
   uv__os390_epoll* ep;
+  int have_signals;
   int real_timeout;
   QUEUE* q;
   uv__io_t* w;
@@ -712,6 +870,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
   count = 48; /* Benchmarks suggest this gives the best throughput. */
   real_timeout = timeout;
   int nevents = 0;
+  have_signals = 0;
 
   if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
     reset_timeout = 1;
@@ -796,6 +955,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
       ep = loop->ep;
       if (pe->is_msg) {
         os390_message_queue_handler(ep);
+        nevents++;
         continue;
       }
 
@@ -825,19 +985,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
         pe->events |= w->pevents & (POLLIN | POLLOUT);
 
       if (pe->events != 0) {
-        uv__metrics_update_idle_time(loop);
-        w->cb(loop, w, pe->events);
+        /* Run signal watchers last.  This also affects child process watchers
+         * because those are implemented in terms of signal watchers.
+         */
+        if (w == &loop->signal_io_watcher) {
+          have_signals = 1;
+        } else {
+          uv__metrics_update_idle_time(loop);
+          w->cb(loop, w, pe->events);
+        }
         nevents++;
       }
     }
-    loop->watchers[loop->nwatchers] = NULL;
-    loop->watchers[loop->nwatchers + 1] = NULL;
 
     if (reset_timeout != 0) {
       timeout = user_timeout;
       reset_timeout = 0;
     }
 
+    if (have_signals != 0) {
+      uv__metrics_update_idle_time(loop);
+      loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
+    }
+
+    loop->watchers[loop->nwatchers] = NULL;
+    loop->watchers[loop->nwatchers + 1] = NULL;
+
+    if (have_signals != 0)
+      return;  /* Event loop should cycle now so don't poll again. */
+
     if (nevents != 0) {
       if (nfds == ARRAY_SIZE(events) && --count != 0) {
         /* Poll for more events but don't block this time. */
@@ -872,6 +1048,5 @@ int uv__io_fork(uv_loop_t* loop) {
   */
   loop->ep = NULL;
 
-  uv__platform_loop_delete(loop);
   return uv__platform_loop_init(loop);
 }

+ 5 - 3
Utilities/cmlibuv/src/unix/pipe.c

@@ -49,7 +49,9 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
   /* Already bound? */
   if (uv__stream_fd(handle) >= 0)
     return UV_EINVAL;
-
+  if (uv__is_closing(handle)) {
+    return UV_EINVAL;
+  }
   /* Make a copy of the file name, it outlives this function's scope. */
   pipe_fname = uv__strdup(name);
   if (pipe_fname == NULL)
@@ -89,7 +91,7 @@ err_socket:
 }
 
 
-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) {
   if (uv__stream_fd(handle) == -1)
     return UV_EINVAL;
 
@@ -317,7 +319,7 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
   if (handle->accepted_fd == -1)
     return UV_UNKNOWN_HANDLE;
   else
-    return uv__handle_type(handle->accepted_fd);
+    return uv_guess_handle(handle->accepted_fd);
 }
 
 

+ 661 - 125
Utilities/cmlibuv/src/unix/process.c

@@ -27,6 +27,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <signal.h>
+#include <string.h>
 
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -35,9 +36,22 @@
 #include <poll.h>
 #include <sched.h>
 
-#if defined(__APPLE__) && !TARGET_OS_IPHONE
+#if defined(__APPLE__)
+# include <spawn.h>
+# include <paths.h>
+# include <sys/kauth.h>
+# include <sys/types.h>
+# include <sys/sysctl.h>
+# include <dlfcn.h>
 # include <crt_externs.h>
+# include <xlocale.h>
 # define environ (*_NSGetEnviron())
+
+/* macOS 10.14 back does not define this constant */
+# ifndef POSIX_SPAWN_SETSID
+#  define POSIX_SPAWN_SETSID 1024
+# endif
+
 #else
 extern char **environ;
 #endif
@@ -61,21 +75,35 @@ extern char **environ;
 #endif
 #endif
 
+#if defined(__APPLE__) || \
+    defined(__DragonFly__) || \
+    defined(__FreeBSD__) || \
+    defined(__NetBSD__) || \
+    defined(__OpenBSD__)
+#include <sys/event.h>
+#else
+#define UV_USE_SIGCHLD
+#endif
+
+#ifdef UV_USE_SIGCHLD
 static void uv__chld(uv_signal_t* handle, int signum) {
+  assert(signum == SIGCHLD);
+  uv__wait_children(handle->loop);
+}
+#endif
+
+void uv__wait_children(uv_loop_t* loop) {
   uv_process_t* process;
-  uv_loop_t* loop;
   int exit_status;
   int term_signal;
   int status;
+  int options;
   pid_t pid;
   QUEUE pending;
   QUEUE* q;
   QUEUE* h;
 
-  assert(signum == SIGCHLD);
-
   QUEUE_INIT(&pending);
-  loop = handle->loop;
 
   h = &loop->process_handles;
   q = QUEUE_HEAD(h);
@@ -83,19 +111,33 @@ static void uv__chld(uv_signal_t* handle, int signum) {
     process = QUEUE_DATA(q, uv_process_t, queue);
     q = QUEUE_NEXT(q);
 
+#ifndef UV_USE_SIGCHLD
+    if ((process->flags & UV_HANDLE_REAP) == 0)
+      continue;
+    options = 0;
+    process->flags &= ~UV_HANDLE_REAP;
+#else
+    options = WNOHANG;
+#endif
+
     do
-      pid = waitpid(process->pid, &status, WNOHANG);
+      pid = waitpid(process->pid, &status, options);
     while (pid == -1 && errno == EINTR);
 
-    if (pid == 0)
+#ifdef UV_USE_SIGCHLD
+    if (pid == 0) /* Not yet exited */
       continue;
+#endif
 
     if (pid == -1) {
       if (errno != ECHILD)
         abort();
+      /* The child died, and we missed it. This probably means someone else
+       * stole the waitpid from us. Handle this by not handling it at all. */
       continue;
     }
 
+    assert(pid == process->pid);
     process->status = status;
     QUEUE_REMOVE(&process->queue);
     QUEUE_INSERT_TAIL(&pending, &process->queue);
@@ -206,16 +248,14 @@ static void uv__write_int(int fd, int val) {
     n = write(fd, &val, sizeof(val));
   while (n == -1 && errno == EINTR);
 
-  if (n == -1 && errno == EPIPE)
-    return; /* parent process has quit */
-
-  assert(n == sizeof(val));
+  /* The write might have failed (e.g. if the parent process has died),
+   * but we have nothing left but to _exit ourself now too. */
+  _exit(127);
 }
 
 
 static void uv__write_errno(int error_fd) {
   uv__write_int(error_fd, UV__ERR(errno));
-  _exit(127);
 }
 
 
@@ -273,22 +313,31 @@ static void uv__process_child_init(const uv_process_options_t* options,
     use_fd = pipes[fd][1];
     if (use_fd < 0 || use_fd >= fd)
       continue;
+#ifdef F_DUPFD_CLOEXEC /* POSIX 2008 */
+    pipes[fd][1] = fcntl(use_fd, F_DUPFD_CLOEXEC, stdio_count);
+#else
     pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
+#endif
     if (pipes[fd][1] == -1)
       uv__write_errno(error_fd);
+#ifndef F_DUPFD_CLOEXEC /* POSIX 2008 */
+    n = uv__cloexec(pipes[fd][1], 1);
+    if (n)
+      uv__write_int(error_fd, n);
+#endif
   }
 
   for (fd = 0; fd < stdio_count; fd++) {
-    close_fd = pipes[fd][0];
+    close_fd = -1;
     use_fd = pipes[fd][1];
 
     if (use_fd < 0) {
       if (fd >= 3)
         continue;
       else {
-        /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
-         * set
-         */
+        /* Redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
+         * set. */
+        uv__close_nocheckstdio(fd); /* Free up fd, if it happens to be open. */
         use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
         close_fd = use_fd;
 
@@ -297,28 +346,27 @@ static void uv__process_child_init(const uv_process_options_t* options,
       }
     }
 
-    if (fd == use_fd)
-      uv__cloexec_fcntl(use_fd, 0);
-    else
+    if (fd == use_fd) {
+      if (close_fd == -1) {
+        n = uv__cloexec(use_fd, 0);
+        if (n)
+          uv__write_int(error_fd, n);
+      }
+    }
+    else {
       fd = dup2(use_fd, fd);
+    }
 
     if (fd == -1)
       uv__write_errno(error_fd);
 
-    if (fd <= 2)
+    if (fd <= 2 && close_fd == -1)
       uv__nonblock_fcntl(fd, 0);
 
     if (close_fd >= stdio_count)
       uv__close(close_fd);
   }
 
-  for (fd = 0; fd < stdio_count; fd++) {
-    use_fd = pipes[fd][1];
-
-    if (use_fd >= stdio_count)
-      uv__close(use_fd);
-  }
-
   if (options->cwd != NULL && chdir(options->cwd))
     uv__write_errno(error_fd);
 
@@ -361,9 +409,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
 #endif
 #endif
 
-  if (options->env != NULL) {
+  if (options->env != NULL)
     environ = options->env;
-  }
 
   /* Reset signal mask just before exec. */
   sigemptyset(&signewset);
@@ -377,11 +424,555 @@ static void uv__process_child_init(const uv_process_options_t* options,
 #endif
 
   uv__write_errno(error_fd);
-  abort();
 }
 #endif
 
 
+#if defined(__APPLE__)
+typedef struct uv__posix_spawn_fncs_tag {
+  struct {
+    int (*addchdir_np)(const posix_spawn_file_actions_t *, const char *);
+  } file_actions;
+} uv__posix_spawn_fncs_t;
+
+
+static uv_once_t posix_spawn_init_once = UV_ONCE_INIT;
+static uv__posix_spawn_fncs_t posix_spawn_fncs;
+static int posix_spawn_can_use_setsid;
+
+
+static void uv__spawn_init_posix_spawn_fncs(void) {
+  /* Try to locate all non-portable functions at runtime */
+  posix_spawn_fncs.file_actions.addchdir_np =
+    dlsym(RTLD_DEFAULT, "posix_spawn_file_actions_addchdir_np");
+}
+
+
+static void uv__spawn_init_can_use_setsid(void) {
+  int which[] = {CTL_KERN, KERN_OSRELEASE};
+  unsigned major;
+  unsigned minor;
+  unsigned patch;
+  char buf[256];
+  size_t len;
+
+  len = sizeof(buf);
+  if (sysctl(which, ARRAY_SIZE(which), buf, &len, NULL, 0))
+    return;
+
+  /* NULL specifies to use LC_C_LOCALE */
+  if (3 != sscanf_l(buf, NULL, "%u.%u.%u", &major, &minor, &patch))
+    return;
+
+  posix_spawn_can_use_setsid = (major >= 19);  /* macOS Catalina */
+}
+
+
+static void uv__spawn_init_posix_spawn(void) {
+  /* Init handles to all potentially non-defined functions */
+  uv__spawn_init_posix_spawn_fncs();
+
+  /* Init feature detection for POSIX_SPAWN_SETSID flag */
+  uv__spawn_init_can_use_setsid();
+}
+
+
+static int uv__spawn_set_posix_spawn_attrs(
+    posix_spawnattr_t* attrs,
+    const uv__posix_spawn_fncs_t* posix_spawn_fncs,
+    const uv_process_options_t* options) {
+  int err;
+  unsigned int flags;
+  sigset_t signal_set;
+
+  err = posix_spawnattr_init(attrs);
+  if (err != 0) {
+    /* If initialization fails, no need to de-init, just return */
+    return err;
+  }
+
+  if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
+    /* kauth_cred_issuser currently requires exactly uid == 0 for these
+     * posixspawn_attrs (set_groups_np, setuid_np, setgid_np), which deviates
+     * from the normal specification of setuid (which also uses euid), and they
+     * are also undocumented syscalls, so we do not use them. */
+    err = ENOSYS;
+    goto error;
+  }
+
+  /* Set flags for spawn behavior
+   * 1) POSIX_SPAWN_CLOEXEC_DEFAULT: (Apple Extension) All descriptors in the
+   *    parent will be treated as if they had been created with O_CLOEXEC. The
+   *    only fds that will be passed on to the child are those manipulated by
+   *    the file actions
+   * 2) POSIX_SPAWN_SETSIGDEF: Signals mentioned in spawn-sigdefault in the
+   *    spawn attributes will be reset to behave as their default
+   * 3) POSIX_SPAWN_SETSIGMASK: Signal mask will be set to the value of
+   *    spawn-sigmask in attributes
+   * 4) POSIX_SPAWN_SETSID: Make the process a new session leader if a detached
+   *    session was requested. */
+  flags = POSIX_SPAWN_CLOEXEC_DEFAULT |
+          POSIX_SPAWN_SETSIGDEF |
+          POSIX_SPAWN_SETSIGMASK;
+  if (options->flags & UV_PROCESS_DETACHED) {
+    /* If running on a version of macOS where this flag is not supported,
+     * revert back to the fork/exec flow. Otherwise posix_spawn will
+     * silently ignore the flag. */
+    if (!posix_spawn_can_use_setsid) {
+      err = ENOSYS;
+      goto error;
+    }
+
+    flags |= POSIX_SPAWN_SETSID;
+  }
+  err = posix_spawnattr_setflags(attrs, flags);
+  if (err != 0)
+    goto error;
+
+  /* Reset all signal the child to their default behavior */
+  sigfillset(&signal_set);
+  err = posix_spawnattr_setsigdefault(attrs, &signal_set);
+  if (err != 0)
+    goto error;
+
+  /* Reset the signal mask for all signals */
+  sigemptyset(&signal_set);
+  err = posix_spawnattr_setsigmask(attrs, &signal_set);
+  if (err != 0)
+    goto error;
+
+  return err;
+
+error:
+  (void) posix_spawnattr_destroy(attrs);
+  return err;
+}
+
+
+static int uv__spawn_set_posix_spawn_file_actions(
+    posix_spawn_file_actions_t* actions,
+    const uv__posix_spawn_fncs_t* posix_spawn_fncs,
+    const uv_process_options_t* options,
+    int stdio_count,
+    int (*pipes)[2]) {
+  int fd;
+  int fd2;
+  int use_fd;
+  int err;
+
+  err = posix_spawn_file_actions_init(actions);
+  if (err != 0) {
+    /* If initialization fails, no need to de-init, just return */
+    return err;
+  }
+
+  /* Set the current working directory if requested */
+  if (options->cwd != NULL) {
+    if (posix_spawn_fncs->file_actions.addchdir_np == NULL) {
+      err = ENOSYS;
+      goto error;
+    }
+
+    err = posix_spawn_fncs->file_actions.addchdir_np(actions, options->cwd);
+    if (err != 0)
+      goto error;
+  }
+
+  /* Do not return ENOSYS after this point, as we may mutate pipes. */
+
+  /* First duplicate low numbered fds, since it's not safe to duplicate them,
+   * they could get replaced. Example: swapping stdout and stderr; without
+   * this fd 2 (stderr) would be duplicated into fd 1, thus making both
+   * stdout and stderr go to the same fd, which was not the intention. */
+  for (fd = 0; fd < stdio_count; fd++) {
+    use_fd = pipes[fd][1];
+    if (use_fd < 0 || use_fd >= fd)
+      continue;
+    use_fd = stdio_count;
+    for (fd2 = 0; fd2 < stdio_count; fd2++) {
+      /* If we were not setting POSIX_SPAWN_CLOEXEC_DEFAULT, we would need to
+       * also consider whether fcntl(fd, F_GETFD) returned without the
+       * FD_CLOEXEC flag set. */
+      if (pipes[fd2][1] == use_fd) {
+        use_fd++;
+        fd2 = 0;
+      }
+    }
+    err = posix_spawn_file_actions_adddup2(
+      actions,
+      pipes[fd][1],
+      use_fd);
+    assert(err != ENOSYS);
+    if (err != 0)
+      goto error;
+    pipes[fd][1] = use_fd;
+  }
+
+  /* Second, move the descriptors into their respective places */
+  for (fd = 0; fd < stdio_count; fd++) {
+    use_fd = pipes[fd][1];
+    if (use_fd < 0) {
+      if (fd >= 3)
+        continue;
+      else {
+        /* If ignored, redirect to (or from) /dev/null, */
+        err = posix_spawn_file_actions_addopen(
+          actions,
+          fd,
+          "/dev/null",
+          fd == 0 ? O_RDONLY : O_RDWR,
+          0);
+        assert(err != ENOSYS);
+        if (err != 0)
+          goto error;
+        continue;
+      }
+    }
+
+    if (fd == use_fd)
+        err = posix_spawn_file_actions_addinherit_np(actions, fd);
+    else
+        err = posix_spawn_file_actions_adddup2(actions, use_fd, fd);
+    assert(err != ENOSYS);
+    if (err != 0)
+      goto error;
+
+    /* Make sure the fd is marked as non-blocking (state shared between child
+     * and parent). */
+    uv__nonblock_fcntl(use_fd, 0);
+  }
+
+  /* Finally, close all the superfluous descriptors */
+  for (fd = 0; fd < stdio_count; fd++) {
+    use_fd = pipes[fd][1];
+    if (use_fd < stdio_count)
+      continue;
+
+    /* Check if we already closed this. */
+    for (fd2 = 0; fd2 < fd; fd2++) {
+      if (pipes[fd2][1] == use_fd)
+          break;
+    }
+    if (fd2 < fd)
+      continue;
+
+    err = posix_spawn_file_actions_addclose(actions, use_fd);
+    assert(err != ENOSYS);
+    if (err != 0)
+      goto error;
+  }
+
+  return 0;
+
+error:
+  (void) posix_spawn_file_actions_destroy(actions);
+  return err;
+}
+
+char* uv__spawn_find_path_in_env(char** env) {
+  char** env_iterator;
+  const char path_var[] = "PATH=";
+
+  /* Look for an environment variable called PATH in the
+   * provided env array, and return its value if found */
+  for (env_iterator = env; *env_iterator != NULL; env_iterator++) {
+    if (strncmp(*env_iterator, path_var, sizeof(path_var) - 1) == 0) {
+      /* Found "PATH=" at the beginning of the string */
+      return *env_iterator + sizeof(path_var) - 1;
+    }
+  }
+
+  return NULL;
+}
+
+
+static int uv__spawn_resolve_and_spawn(const uv_process_options_t* options,
+                                       posix_spawnattr_t* attrs,
+                                       posix_spawn_file_actions_t* actions,
+                                       pid_t* pid) {
+  const char *p;
+  const char *z;
+  const char *path;
+  size_t l;
+  size_t k;
+  int err;
+  int seen_eacces;
+
+  path = NULL;
+  err = -1;
+  seen_eacces = 0;
+
+  /* Short circuit for erroneous case */
+  if (options->file == NULL)
+    return ENOENT;
+
+  /* The environment for the child process is that of the parent unless overriden
+   * by options->env */
+  char** env = environ;
+  if (options->env != NULL)
+    env = options->env;
+
+  /* If options->file contains a slash, posix_spawn/posix_spawnp should behave
+   * the same, and do not involve PATH resolution at all. The libc
+   * `posix_spawnp` provided by Apple is buggy (since 10.15), so we now emulate it
+   * here, per https://github.com/libuv/libuv/pull/3583. */
+  if (strchr(options->file, '/') != NULL) {
+    do
+      err = posix_spawn(pid, options->file, actions, attrs, options->args, env);
+    while (err == EINTR);
+    return err;
+  }
+
+  /* Look for the definition of PATH in the provided env */
+  path = uv__spawn_find_path_in_env(env);
+
+  /* The following resolution logic (execvpe emulation) is copied from
+   * https://git.musl-libc.org/cgit/musl/tree/src/process/execvp.c
+   * and adapted to work for our specific usage */
+
+  /* If no path was provided in env, use the default value
+   * to look for the executable */
+  if (path == NULL)
+    path = _PATH_DEFPATH;
+
+  k = strnlen(options->file, NAME_MAX + 1);
+  if (k > NAME_MAX)
+    return ENAMETOOLONG;
+
+  l = strnlen(path, PATH_MAX - 1) + 1;
+
+  for (p = path;; p = z) {
+    /* Compose the new process file from the entry in the PATH
+     * environment variable and the actual file name */
+    char b[PATH_MAX + NAME_MAX];
+    z = strchr(p, ':');
+    if (!z)
+      z = p + strlen(p);
+    if ((size_t)(z - p) >= l) {
+      if (!*z++)
+        break;
+
+      continue;
+    }
+    memcpy(b, p, z - p);
+    b[z - p] = '/';
+    memcpy(b + (z - p) + (z > p), options->file, k + 1);
+
+    /* Try to spawn the new process file. If it fails with ENOENT, the
+     * new process file is not in this PATH entry, continue with the next
+     * PATH entry. */
+    do
+      err = posix_spawn(pid, b, actions, attrs, options->args, env);
+    while (err == EINTR);
+
+    switch (err) {
+    case EACCES:
+      seen_eacces = 1;
+      break; /* continue search */
+    case ENOENT:
+    case ENOTDIR:
+      break; /* continue search */
+    default:
+      return err;
+    }
+
+    if (!*z++)
+      break;
+  }
+
+  if (seen_eacces)
+    return EACCES;
+  return err;
+}
+
+
+static int uv__spawn_and_init_child_posix_spawn(
+    const uv_process_options_t* options,
+    int stdio_count,
+    int (*pipes)[2],
+    pid_t* pid,
+    const uv__posix_spawn_fncs_t* posix_spawn_fncs) {
+  int err;
+  posix_spawnattr_t attrs;
+  posix_spawn_file_actions_t actions;
+
+  err = uv__spawn_set_posix_spawn_attrs(&attrs, posix_spawn_fncs, options);
+  if (err != 0)
+    goto error;
+
+  /* This may mutate pipes. */
+  err = uv__spawn_set_posix_spawn_file_actions(&actions,
+                                               posix_spawn_fncs,
+                                               options,
+                                               stdio_count,
+                                               pipes);
+  if (err != 0) {
+    (void) posix_spawnattr_destroy(&attrs);
+    goto error;
+  }
+
+  /* Try to spawn options->file resolving in the provided environment
+   * if any */
+  err = uv__spawn_resolve_and_spawn(options, &attrs, &actions, pid);
+  assert(err != ENOSYS);
+
+  /* Destroy the actions/attributes */
+  (void) posix_spawn_file_actions_destroy(&actions);
+  (void) posix_spawnattr_destroy(&attrs);
+
+error:
+  /* In an error situation, the attributes and file actions are
+   * already destroyed, only the happy path requires cleanup */
+  return UV__ERR(err);
+}
+#endif
+
+static int uv__spawn_and_init_child_fork(const uv_process_options_t* options,
+                                         int stdio_count,
+                                         int (*pipes)[2],
+                                         int error_fd,
+                                         pid_t* pid) {
+  sigset_t signewset;
+  sigset_t sigoldset;
+
+  /* Start the child with most signals blocked, to avoid any issues before we
+   * can reset them, but allow program failures to exit (and not hang). */
+  sigfillset(&signewset);
+  sigdelset(&signewset, SIGKILL);
+  sigdelset(&signewset, SIGSTOP);
+  sigdelset(&signewset, SIGTRAP);
+  sigdelset(&signewset, SIGSEGV);
+  sigdelset(&signewset, SIGBUS);
+  sigdelset(&signewset, SIGILL);
+  sigdelset(&signewset, SIGSYS);
+  sigdelset(&signewset, SIGABRT);
+  if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0)
+    abort();
+
+  *pid = fork();
+
+  if (*pid == 0) {
+    /* Fork succeeded, in the child process */
+    uv__process_child_init(options, stdio_count, pipes, error_fd);
+    abort();
+  }
+
+  if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0)
+    abort();
+
+  if (*pid == -1)
+    /* Failed to fork */
+    return UV__ERR(errno);
+
+  /* Fork succeeded, in the parent process */
+  return 0;
+}
+
+static int uv__spawn_and_init_child(
+    uv_loop_t* loop,
+    const uv_process_options_t* options,
+    int stdio_count,
+    int (*pipes)[2],
+    pid_t* pid) {
+  int signal_pipe[2] = { -1, -1 };
+  int status;
+  int err;
+  int exec_errorno;
+  ssize_t r;
+
+#if defined(__APPLE__)
+  uv_once(&posix_spawn_init_once, uv__spawn_init_posix_spawn);
+
+  /* Special child process spawn case for macOS Big Sur (11.0) onwards
+   *
+   * Big Sur introduced a significant performance degradation on a call to
+   * fork/exec when the process has many pages mmaped in with MAP_JIT, like, say
+   * a javascript interpreter. Electron-based applications, for example,
+   * are impacted; though the magnitude of the impact depends on how much the
+   * app relies on subprocesses.
+   *
+   * On macOS, though, posix_spawn is implemented in a way that does not
+   * exhibit the problem. This block implements the forking and preparation
+   * logic with posix_spawn and its related primitives. It also takes advantage of
+   * the macOS extension POSIX_SPAWN_CLOEXEC_DEFAULT that makes impossible to
+   * leak descriptors to the child process. */
+  err = uv__spawn_and_init_child_posix_spawn(options,
+                                             stdio_count,
+                                             pipes,
+                                             pid,
+                                             &posix_spawn_fncs);
+
+  /* The posix_spawn flow will return UV_ENOSYS if any of the posix_spawn_x_np
+   * non-standard functions is both _needed_ and _undefined_. In those cases,
+   * default back to the fork/execve strategy. For all other errors, just fail. */
+  if (err != UV_ENOSYS)
+    return err;
+
+#endif
+
+  /* This pipe is used by the parent to wait until
+   * the child has called `execve()`. We need this
+   * to avoid the following race condition:
+   *
+   *    if ((pid = fork()) > 0) {
+   *      kill(pid, SIGTERM);
+   *    }
+   *    else if (pid == 0) {
+   *      execve("/bin/cat", argp, envp);
+   *    }
+   *
+   * The parent sends a signal immediately after forking.
+   * Since the child may not have called `execve()` yet,
+   * there is no telling what process receives the signal,
+   * our fork or /bin/cat.
+   *
+   * To avoid ambiguity, we create a pipe with both ends
+   * marked close-on-exec. Then, after the call to `fork()`,
+   * the parent polls the read end until it EOFs or errors with EPIPE.
+   */
+  err = uv__make_pipe(signal_pipe, 0);
+  if (err)
+    return err;
+
+  /* Acquire write lock to prevent opening new fds in worker threads */
+  uv_rwlock_wrlock(&loop->cloexec_lock);
+
+  err = uv__spawn_and_init_child_fork(options, stdio_count, pipes, signal_pipe[1], pid);
+
+  /* Release lock in parent process */
+  uv_rwlock_wrunlock(&loop->cloexec_lock);
+
+  uv__close(signal_pipe[1]);
+
+  if (err == 0) {
+    do
+      r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
+    while (r == -1 && errno == EINTR);
+
+    if (r == 0)
+      ; /* okay, EOF */
+    else if (r == sizeof(exec_errorno)) {
+      do
+        err = waitpid(*pid, &status, 0); /* okay, read errorno */
+      while (err == -1 && errno == EINTR);
+      assert(err == *pid);
+      err = exec_errorno;
+    } else if (r == -1 && errno == EPIPE) {
+      /* Something unknown happened to our child before spawn */
+      do
+        err = waitpid(*pid, &status, 0); /* okay, got EPIPE */
+      while (err == -1 && errno == EINTR);
+      assert(err == *pid);
+      err = UV_EPIPE;
+    } else
+      abort();
+  }
+
+  uv__close_nocheckstdio(signal_pipe[0]);
+
+  return err;
+}
+
 int uv_spawn(uv_loop_t* loop,
              uv_process_t* process,
              const uv_process_options_t* options) {
@@ -389,18 +980,13 @@ int uv_spawn(uv_loop_t* loop,
   /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
   return UV_ENOSYS;
 #else
-  sigset_t signewset;
-  sigset_t sigoldset;
-  int signal_pipe[2] = { -1, -1 };
   int pipes_storage[8][2];
   int (*pipes)[2];
   int stdio_count;
-  ssize_t r;
   pid_t pid;
   int err;
   int exec_errorno;
   int i;
-  int status;
 
   if (options->cpumask != NULL) {
 #ifndef CMAKE_BOOTSTRAP
@@ -427,6 +1013,7 @@ int uv_spawn(uv_loop_t* loop,
 
   uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
   QUEUE_INIT(&process->queue);
+  process->status = 0;
 
   stdio_count = options->stdio_count;
   if (stdio_count < 3)
@@ -451,92 +1038,43 @@ int uv_spawn(uv_loop_t* loop,
       goto error;
   }
 
-  /* This pipe is used by the parent to wait until
-   * the child has called `execve()`. We need this
-   * to avoid the following race condition:
-   *
-   *    if ((pid = fork()) > 0) {
-   *      kill(pid, SIGTERM);
-   *    }
-   *    else if (pid == 0) {
-   *      execve("/bin/cat", argp, envp);
-   *    }
-   *
-   * The parent sends a signal immediately after forking.
-   * Since the child may not have called `execve()` yet,
-   * there is no telling what process receives the signal,
-   * our fork or /bin/cat.
-   *
-   * To avoid ambiguity, we create a pipe with both ends
-   * marked close-on-exec. Then, after the call to `fork()`,
-   * the parent polls the read end until it EOFs or errors with EPIPE.
-   */
-  err = uv__make_pipe(signal_pipe, 0);
-  if (err)
-    goto error;
-
+#ifdef UV_USE_SIGCHLD
   uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
+#endif
 
-  /* Acquire write lock to prevent opening new fds in worker threads */
-  uv_rwlock_wrlock(&loop->cloexec_lock);
-
-  /* Start the child with most signals blocked, to avoid any issues before we
-   * can reset them, but allow program failures to exit (and not hang). */
-  sigfillset(&signewset);
-  sigdelset(&signewset, SIGKILL);
-  sigdelset(&signewset, SIGSTOP);
-  sigdelset(&signewset, SIGTRAP);
-  sigdelset(&signewset, SIGSEGV);
-  sigdelset(&signewset, SIGBUS);
-  sigdelset(&signewset, SIGILL);
-  sigdelset(&signewset, SIGSYS);
-  sigdelset(&signewset, SIGABRT);
-  if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0)
-    abort();
-
-  pid = fork();
-  if (pid == -1)
-    err = UV__ERR(errno);
-
-  if (pid == 0)
-    uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
-
-  if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0)
-    abort();
+  /* Spawn the child */
+  exec_errorno = uv__spawn_and_init_child(loop, options, stdio_count, pipes, &pid);
 
-  /* Release lock in parent process */
-  uv_rwlock_wrunlock(&loop->cloexec_lock);
+#if 0
+  /* This runs into a nodejs issue (it expects initialized streams, even if the
+   * exec failed).
+   * See https://github.com/libuv/libuv/pull/3107#issuecomment-782482608 */
+  if (exec_errorno != 0)
+      goto error;
+#endif
 
-  uv__close(signal_pipe[1]);
+  /* Activate this handle if exec() happened successfully, even if we later
+   * fail to open a stdio handle. This ensures we can eventually reap the child
+   * with waitpid. */
+  if (exec_errorno == 0) {
+#ifndef UV_USE_SIGCHLD
+    struct kevent event;
+    EV_SET(&event, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, 0);
+    if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) {
+      if (errno != ESRCH)
+        abort();
+      /* Process already exited. Call waitpid on the next loop iteration. */
+      process->flags |= UV_HANDLE_REAP;
+      loop->flags |= UV_LOOP_REAP_CHILDREN;
+    }
+#endif
 
-  if (pid == -1) {
-    uv__close(signal_pipe[0]);
-    goto error;
+    process->pid = pid;
+    process->exit_cb = options->exit_cb;
+    QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
+    uv__handle_start(process);
   }
 
-  process->status = 0;
-  exec_errorno = 0;
-  do
-    r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
-  while (r == -1 && errno == EINTR);
-
-  if (r == 0)
-    ; /* okay, EOF */
-  else if (r == sizeof(exec_errorno)) {
-    do
-      err = waitpid(pid, &status, 0); /* okay, read errorno */
-    while (err == -1 && errno == EINTR);
-    assert(err == pid);
-  } else if (r == -1 && errno == EPIPE) {
-    do
-      err = waitpid(pid, &status, 0); /* okay, got EPIPE */
-    while (err == -1 && errno == EINTR);
-    assert(err == pid);
-  } else
-    abort();
-
-  uv__close_nocheckstdio(signal_pipe[0]);
-
   for (i = 0; i < options->stdio_count; i++) {
     err = uv__process_open_stream(options->stdio + i, pipes[i]);
     if (err == 0)
@@ -548,15 +1086,6 @@ int uv_spawn(uv_loop_t* loop,
     goto error;
   }
 
-  /* Only activate this handle if exec() happened successfully */
-  if (exec_errorno == 0) {
-    QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
-    uv__handle_start(process);
-  }
-
-  process->pid = pid;
-  process->exit_cb = options->exit_cb;
-
   if (pipes != pipes_storage)
     uv__free(pipes);
 
@@ -589,9 +1118,16 @@ int uv_process_kill(uv_process_t* process, int signum) {
 
 
 int uv_kill(int pid, int signum) {
-  if (kill(pid, signum))
+  if (kill(pid, signum)) {
+#if defined(__MVS__)
+    /* EPERM is returned if the process is a zombie. */
+    siginfo_t infop;
+    if (errno == EPERM &&
+        waitid(P_PID, pid, &infop, WNOHANG | WNOWAIT | WEXITED) == 0)
+      return 0;
+#endif
     return UV__ERR(errno);
-  else
+  } else
     return 0;
 }
 

+ 27 - 72
Utilities/cmlibuv/src/unix/stream.c

@@ -66,6 +66,7 @@ static void uv__read(uv_stream_t* stream);
 static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
 static void uv__write_callbacks(uv_stream_t* stream);
 static size_t uv__write_req_size(uv_write_t* req);
+static void uv__drain(uv_stream_t* stream);
 
 
 void uv__stream_init(uv_loop_t* loop,
@@ -453,17 +454,7 @@ void uv__stream_destroy(uv_stream_t* stream) {
 
   uv__stream_flush_write_queue(stream, UV_ECANCELED);
   uv__write_callbacks(stream);
-
-  if (stream->shutdown_req) {
-    /* The ECANCELED error code is a lie, the shutdown(2) syscall is a
-     * fait accompli at this point. Maybe we should revisit this in v0.11.
-     * A possible reason for leaving it unchanged is that it informs the
-     * callee that the handle has been destroyed.
-     */
-    uv__req_unregister(stream->loop, stream->shutdown_req);
-    stream->shutdown_req->cb(stream->shutdown_req, UV_ECANCELED);
-    stream->shutdown_req = NULL;
-  }
+  uv__drain(stream);
 
   assert(stream->write_queue_size == 0);
 }
@@ -641,14 +632,16 @@ done:
 
 int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
   int err;
-
+  if (uv__is_closing(stream)) {
+    return UV_EINVAL;
+  }
   switch (stream->type) {
   case UV_TCP:
-    err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
+    err = uv__tcp_listen((uv_tcp_t*)stream, backlog, cb);
     break;
 
   case UV_NAMED_PIPE:
-    err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
+    err = uv__pipe_listen((uv_pipe_t*)stream, backlog, cb);
     break;
 
   default:
@@ -667,25 +660,30 @@ static void uv__drain(uv_stream_t* stream) {
   int err;
 
   assert(QUEUE_EMPTY(&stream->write_queue));
-  uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
-  uv__stream_osx_interrupt_select(stream);
+  if (!(stream->flags & UV_HANDLE_CLOSING)) {
+    uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
+    uv__stream_osx_interrupt_select(stream);
+  }
 
-  /* Shutdown? */
-  if ((stream->flags & UV_HANDLE_SHUTTING) &&
-      !(stream->flags & UV_HANDLE_CLOSING) &&
-      !(stream->flags & UV_HANDLE_SHUT)) {
-    assert(stream->shutdown_req);
+  if (!(stream->flags & UV_HANDLE_SHUTTING))
+    return;
 
-    req = stream->shutdown_req;
+  req = stream->shutdown_req;
+  assert(req);
+
+  if ((stream->flags & UV_HANDLE_CLOSING) ||
+      !(stream->flags & UV_HANDLE_SHUT)) {
     stream->shutdown_req = NULL;
     stream->flags &= ~UV_HANDLE_SHUTTING;
     uv__req_unregister(stream->loop, req);
 
     err = 0;
-    if (shutdown(uv__stream_fd(stream), SHUT_WR))
+    if (stream->flags & UV_HANDLE_CLOSING)
+      /* The user destroyed the stream before we got to do the shutdown. */
+      err = UV_ECANCELED;
+    else if (shutdown(uv__stream_fd(stream), SHUT_WR))
       err = UV__ERR(errno);
-
-    if (err == 0)
+    else /* Success. */
       stream->flags |= UV_HANDLE_SHUT;
 
     if (req->cb != NULL)
@@ -926,7 +924,6 @@ static void uv__write(uv_stream_t* stream) {
   }
 
   req->error = n;
-  /* XXX(jwn): this must call uv__stream_flush_write_queue(stream, n) here, since we won't generate any more events */
   uv__write_req_finish(req);
   uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
   uv__stream_osx_interrupt_select(stream);
@@ -964,49 +961,6 @@ static void uv__write_callbacks(uv_stream_t* stream) {
 }
 
 
-uv_handle_type uv__handle_type(int fd) {
-  struct sockaddr_storage ss;
-  socklen_t sslen;
-  socklen_t len;
-  int type;
-
-  memset(&ss, 0, sizeof(ss));
-  sslen = sizeof(ss);
-
-  if (getsockname(fd, (struct sockaddr*)&ss, &sslen))
-    return UV_UNKNOWN_HANDLE;
-
-  len = sizeof type;
-
-  if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len))
-    return UV_UNKNOWN_HANDLE;
-
-  if (type == SOCK_STREAM) {
-#if defined(_AIX) || defined(__DragonFly__)
-    /* on AIX/DragonFly the getsockname call returns an empty sa structure
-     * for sockets of type AF_UNIX.  For all other types it will
-     * return a properly filled in structure.
-     */
-    if (sslen == 0)
-      return UV_NAMED_PIPE;
-#endif
-    switch (ss.ss_family) {
-      case AF_UNIX:
-        return UV_NAMED_PIPE;
-      case AF_INET:
-      case AF_INET6:
-        return UV_TCP;
-      }
-  }
-
-  if (type == SOCK_DGRAM &&
-      (ss.ss_family == AF_INET || ss.ss_family == AF_INET6))
-    return UV_UDP;
-
-  return UV_UNKNOWN_HANDLE;
-}
-
-
 static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
   stream->flags |= UV_HANDLE_READ_EOF;
   stream->flags &= ~UV_HANDLE_READING;
@@ -1278,7 +1232,8 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
 
   assert(uv__stream_fd(stream) >= 0);
 
-  /* Initialize request */
+  /* Initialize request. The `shutdown(2)` call will always be deferred until
+   * `uv__drain`, just before the callback is run. */
   uv__req_init(stream->loop, req, UV_SHUTDOWN);
   req->handle = stream;
   req->cb = cb;
@@ -1286,8 +1241,8 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
   stream->flags |= UV_HANDLE_SHUTTING;
   stream->flags &= ~UV_HANDLE_WRITABLE;
 
-  uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
-  uv__stream_osx_interrupt_select(stream);
+  if (QUEUE_EMPTY(&stream->write_queue))
+    uv__io_feed(stream->loop, &stream->io_watcher);
 
   return 0;
 }

+ 29 - 7
Utilities/cmlibuv/src/unix/sunos.c

@@ -158,7 +158,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
   sigset_t set;
   uint64_t base;
   uint64_t diff;
-  uint64_t idle_poll;
   unsigned int nfds;
   unsigned int i;
   int saved_errno;
@@ -428,7 +427,7 @@ void uv_loadavg(double avg[3]) {
 #if defined(PORT_SOURCE_FILE)
 
 static int uv__fs_event_rearm(uv_fs_event_t *handle) {
-  if (handle->fd == -1)
+  if (handle->fd == PORT_DELETED)
     return UV_EBADF;
 
   if (port_associate(handle->loop->fs_fd,
@@ -479,6 +478,12 @@ static void uv__fs_event_read(uv_loop_t* loop,
     handle = (uv_fs_event_t*) pe.portev_user;
     assert((r == 0) && "unexpected port_get() error");
 
+    if (uv__is_closing(handle)) {
+      uv__handle_stop(handle);
+      uv__make_close_pending((uv_handle_t*) handle);
+      break;
+    }
+
     events = 0;
     if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
       events |= UV_CHANGE;
@@ -546,12 +551,14 @@ int uv_fs_event_start(uv_fs_event_t* handle,
 }
 
 
-int uv_fs_event_stop(uv_fs_event_t* handle) {
+static int uv__fs_event_stop(uv_fs_event_t* handle) {
+  int ret = 0;
+
   if (!uv__is_active(handle))
     return 0;
 
-  if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) {
-    port_dissociate(handle->loop->fs_fd,
+  if (handle->fd == PORT_LOADED) {
+    ret = port_dissociate(handle->loop->fs_fd,
                     PORT_SOURCE_FILE,
                     (uintptr_t) &handle->fo);
   }
@@ -560,13 +567,28 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
   uv__free(handle->path);
   handle->path = NULL;
   handle->fo.fo_name = NULL;
-  uv__handle_stop(handle);
+  if (ret == 0)
+    uv__handle_stop(handle);
+
+  return ret;
+}
 
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+  (void) uv__fs_event_stop(handle);
   return 0;
 }
 
 void uv__fs_event_close(uv_fs_event_t* handle) {
-  uv_fs_event_stop(handle);
+  /*
+   * If we were unable to dissociate the port here, then it is most likely
+   * that there is a pending queued event. When this happens, we don't want
+   * to complete the close as it will free the underlying memory for the
+   * handle, causing a use-after-free problem when the event is processed.
+   * We defer the final cleanup until after the event is consumed in
+   * uv__fs_event_read().
+   */
+  if (uv__fs_event_stop(handle) == 0)
+    uv__make_close_pending((uv_handle_t*) handle);
 }
 
 #else /* !defined(PORT_SOURCE_FILE) */

+ 14 - 5
Utilities/cmlibuv/src/unix/tcp.c

@@ -184,14 +184,15 @@ int uv__tcp_bind(uv_tcp_t* tcp,
 #endif
 
   errno = 0;
-  if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
+  err = bind(tcp->io_watcher.fd, addr, addrlen);
+  if (err == -1 && errno != EADDRINUSE) {
     if (errno == EAFNOSUPPORT)
       /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
        * socket created with AF_INET to an AF_INET6 address or vice versa. */
       return UV_EINVAL;
     return UV__ERR(errno);
   }
-  tcp->delayed_error = UV__ERR(errno);
+  tcp->delayed_error = (err == -1) ? UV__ERR(errno) : 0;
 
   tcp->flags |= UV_HANDLE_BOUND;
   if (addr->sa_family == AF_INET6)
@@ -320,15 +321,23 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
     return UV_EINVAL;
 
   fd = uv__stream_fd(handle);
-  if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)))
-    return UV__ERR(errno);
+  if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l))) {
+    if (errno == EINVAL) {
+      /* Open Group Specifications Issue 7, 2018 edition states that
+       * EINVAL may mean the socket has been shut down already.
+       * Behavior observed on Solaris, illumos and macOS. */
+      errno = 0;
+    } else {
+      return UV__ERR(errno);
+    }
+  }
 
   uv_close((uv_handle_t*) handle, close_cb);
   return 0;
 }
 
 
-int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
+int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
   static int single_accept_cached = -1;
   unsigned long flags;
   int single_accept;

+ 53 - 33
Utilities/cmlibuv/src/unix/thread.c

@@ -162,12 +162,46 @@ void uv_barrier_destroy(uv_barrier_t* barrier) {
 #endif
 
 
-/* On MacOS, threads other than the main thread are created with a reduced
- * stack size by default.  Adjust to RLIMIT_STACK aligned to the page size.
+/* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is
+ * too small to safely receive signals on.
+ *
+ * Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has
+ * the largest MINSIGSTKSZ of the architectures that musl supports) so
+ * let's use that as a lower bound.
  *
- * On Linux, threads created by musl have a much smaller stack than threads
+ * We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ
+ * is between 28 and 133 KB when compiling against glibc, depending
+ * on the architecture.
+ */
+static size_t uv__min_stack_size(void) {
+  static const size_t min = 8192;
+
+#ifdef PTHREAD_STACK_MIN  /* Not defined on NetBSD. */
+  if (min < (size_t) PTHREAD_STACK_MIN)
+    return PTHREAD_STACK_MIN;
+#endif  /* PTHREAD_STACK_MIN */
+
+  return min;
+}
+
+
+/* On Linux, threads created by musl have a much smaller stack than threads
  * created by glibc (80 vs. 2048 or 4096 kB.)  Follow glibc for consistency.
  */
+static size_t uv__default_stack_size(void) {
+#if !defined(__linux__)
+  return 0;
+#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
+  return 4 << 20;  /* glibc default. */
+#else
+  return 2 << 20;  /* glibc default. */
+#endif
+}
+
+
+/* On MacOS, threads other than the main thread are created with a reduced
+ * stack size by default.  Adjust to RLIMIT_STACK aligned to the page size.
+ */
 size_t uv__thread_stack_size(void) {
 #if defined(__APPLE__) || defined(__linux__)
   struct rlimit lim;
@@ -176,34 +210,20 @@ size_t uv__thread_stack_size(void) {
    * the system call wrapper invokes the wrong system call. Don't treat
    * that as fatal, just use the default stack size instead.
    */
-  if (0 == getrlimit(RLIMIT_STACK, &lim) && lim.rlim_cur != RLIM_INFINITY) {
-    /* pthread_attr_setstacksize() expects page-aligned values. */
-    lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
-
-    /* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is
-     * too small to safely receive signals on.
-     *
-     * Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has
-     * the largest MINSIGSTKSZ of the architectures that musl supports) so
-     * let's use that as a lower bound.
-     *
-     * We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ
-     * is between 28 and 133 KB when compiling against glibc, depending
-     * on the architecture.
-     */
-    if (lim.rlim_cur >= 8192)
-      if (lim.rlim_cur >= PTHREAD_STACK_MIN)
-        return lim.rlim_cur;
-  }
-#endif
+  if (getrlimit(RLIMIT_STACK, &lim))
+    return uv__default_stack_size();
 
-#if !defined(__linux__)
-  return 0;
-#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
-  return 4 << 20;  /* glibc default. */
-#else
-  return 2 << 20;  /* glibc default. */
+  if (lim.rlim_cur == RLIM_INFINITY)
+    return uv__default_stack_size();
+
+  /* pthread_attr_setstacksize() expects page-aligned values. */
+  lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
+
+  if (lim.rlim_cur >= (rlim_t) uv__min_stack_size())
+    return lim.rlim_cur;
 #endif
+
+  return uv__default_stack_size();
 }
 
 
@@ -222,6 +242,7 @@ int uv_thread_create_ex(uv_thread_t* tid,
   pthread_attr_t attr_storage;
   size_t pagesize;
   size_t stack_size;
+  size_t min_stack_size;
 
   /* Used to squelch a -Wcast-function-type warning. */
   union {
@@ -239,10 +260,9 @@ int uv_thread_create_ex(uv_thread_t* tid,
     pagesize = (size_t)getpagesize();
     /* Round up to the nearest page boundary. */
     stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
-#ifdef PTHREAD_STACK_MIN
-    if (stack_size < PTHREAD_STACK_MIN)
-      stack_size = PTHREAD_STACK_MIN;
-#endif
+    min_stack_size = uv__min_stack_size();
+    if (stack_size < min_stack_size)
+      stack_size = min_stack_size;
   }
 
   if (stack_size > 0) {

+ 68 - 16
Utilities/cmlibuv/src/unix/tty.c

@@ -62,10 +62,25 @@ static int isreallyatty(int file) {
 #define isatty(fd) isreallyatty(fd)
 #endif
 
+#if !defined(CMAKE_BOOTSTRAP)
+
 static int orig_termios_fd = -1;
 static struct termios orig_termios;
 static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
 
+int uv__tcsetattr(int fd, int how, const struct termios *term) {
+  int rc;
+
+  do
+    rc = tcsetattr(fd, how, term);
+  while (rc == -1 && errno == EINTR);
+
+  if (rc == -1)
+    return UV__ERR(errno);
+
+  return 0;
+}
+
 static int uv__tty_is_slave(const int fd) {
   int result;
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -265,13 +280,18 @@ static void uv__tty_make_raw(struct termios* tio) {
 int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
   struct termios tmp;
   int fd;
+  int rc;
 
   if (tty->mode == (int) mode)
     return 0;
 
   fd = uv__stream_fd(tty);
   if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
-    if (tcgetattr(fd, &tty->orig_termios))
+    do
+      rc = tcgetattr(fd, &tty->orig_termios);
+    while (rc == -1 && errno == EINTR);
+
+    if (rc == -1)
       return UV__ERR(errno);
 
     /* This is used for uv_tty_reset_mode() */
@@ -301,11 +321,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
   }
 
   /* Apply changes after draining */
-  if (tcsetattr(fd, TCSADRAIN, &tmp))
-    return UV__ERR(errno);
+  rc = uv__tcsetattr(fd, TCSADRAIN, &tmp);
+  if (rc == 0)
+    tty->mode = mode;
 
-  tty->mode = mode;
-  return 0;
+  return rc;
 }
 
 
@@ -326,9 +346,10 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
   return 0;
 }
 
+#endif
 
 uv_handle_type uv_guess_handle(uv_file file) {
-  struct sockaddr sa;
+  struct sockaddr_storage ss;
   struct stat s;
   socklen_t len;
   int type;
@@ -339,8 +360,24 @@ uv_handle_type uv_guess_handle(uv_file file) {
   if (isatty(file))
     return UV_TTY;
 
-  if (fstat(file, &s))
+  if (fstat(file, &s)) {
+#if defined(__PASE__)
+    /* On ibmi receiving RST from TCP instead of FIN immediately puts fd into
+     * an error state. fstat will return EINVAL, getsockname will also return
+     * EINVAL, even if sockaddr_storage is valid. (If file does not refer to a
+     * socket, ENOTSOCK is returned instead.)
+     * In such cases, we will permit the user to open the connection as uv_tcp
+     * still, so that the user can get immediately notified of the error in
+     * their read callback and close this fd.
+     */
+    len = sizeof(ss);
+    if (getsockname(file, (struct sockaddr*) &ss, &len)) {
+      if (errno == EINVAL)
+        return UV_TCP;
+    }
+#endif
     return UV_UNKNOWN_HANDLE;
+  }
 
   if (S_ISREG(s.st_mode))
     return UV_FILE;
@@ -354,16 +391,29 @@ uv_handle_type uv_guess_handle(uv_file file) {
   if (!S_ISSOCK(s.st_mode))
     return UV_UNKNOWN_HANDLE;
 
-  len = sizeof(type);
-  if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
+  len = sizeof(ss);
+  if (getsockname(file, (struct sockaddr*) &ss, &len)) {
+#if defined(_AIX)
+    /* On aix receiving RST from TCP instead of FIN immediately puts fd into
+     * an error state. In such case getsockname will return EINVAL, even if
+     * sockaddr_storage is valid.
+     * In such cases, we will permit the user to open the connection as uv_tcp
+     * still, so that the user can get immediately notified of the error in
+     * their read callback and close this fd.
+     */
+    if (errno == EINVAL) {
+      return UV_TCP;
+    }
+#endif
     return UV_UNKNOWN_HANDLE;
+  }
 
-  len = sizeof(sa);
-  if (getsockname(file, &sa, &len))
+  len = sizeof(type);
+  if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
     return UV_UNKNOWN_HANDLE;
 
   if (type == SOCK_DGRAM)
-    if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
+    if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6)
       return UV_UDP;
 
   if (type == SOCK_STREAM) {
@@ -376,15 +426,16 @@ uv_handle_type uv_guess_handle(uv_file file) {
       return UV_NAMED_PIPE;
 #endif /* defined(_AIX) || defined(__DragonFly__) */
 
-    if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
+    if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6)
       return UV_TCP;
-    if (sa.sa_family == AF_UNIX)
+    if (ss.ss_family == AF_UNIX)
       return UV_NAMED_PIPE;
   }
 
   return UV_UNKNOWN_HANDLE;
 }
 
+#if !defined(CMAKE_BOOTSTRAP)
 
 /* This function is async signal-safe, meaning that it's safe to call from
  * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s
@@ -400,8 +451,7 @@ int uv_tty_reset_mode(void) {
 
   err = 0;
   if (orig_termios_fd != -1)
-    if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios))
-      err = UV__ERR(errno);
+    err = uv__tcsetattr(orig_termios_fd, TCSANOW, &orig_termios);
 
   uv_spinlock_unlock(&termios_spinlock);
   errno = saved_errno;
@@ -415,3 +465,5 @@ void uv_tty_set_vterm_state(uv_tty_vtermstate_t state) {
 int uv_tty_get_vterm_state(uv_tty_vtermstate_t* state) {
   return UV_ENOTSUP;
 }
+
+#endif

+ 20 - 8
Utilities/cmlibuv/src/unix/udp.c

@@ -201,6 +201,7 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
   for (k = 0; k < chunks; ++k) {
     iov[k].iov_base = buf->base + k * UV__UDP_DGRAM_MAXSIZE;
     iov[k].iov_len = UV__UDP_DGRAM_MAXSIZE;
+    memset(&msgs[k].msg_hdr, 0, sizeof(msgs[k].msg_hdr));
     msgs[k].msg_hdr.msg_iov = iov + k;
     msgs[k].msg_hdr.msg_iovlen = 1;
     msgs[k].msg_hdr.msg_name = peers + k;
@@ -494,7 +495,7 @@ static int uv__set_reuse(int fd) {
     if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
        return UV__ERR(errno);
   }
-#elif defined(SO_REUSEPORT) && !defined(__linux__)
+#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__)
   if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
     return UV__ERR(errno);
 #else
@@ -655,16 +656,16 @@ int uv__udp_connect(uv_udp_t* handle,
 }
 
 /* From https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html
- * Any of uv supported UNIXs kernel should be standardized, but the kernel 
+ * Any of uv supported UNIXs kernel should be standardized, but the kernel
  * implementation logic not same, let's use pseudocode to explain the udp
  * disconnect behaviors:
- * 
+ *
  * Predefined stubs for pseudocode:
  *   1. sodisconnect: The function to perform the real udp disconnect
  *   2. pru_connect: The function to perform the real udp connect
  *   3. so: The kernel object match with socket fd
  *   4. addr: The sockaddr parameter from user space
- * 
+ *
  * BSDs:
  *   if(sodisconnect(so) == 0) { // udp disconnect succeed
  *     if (addr->sa_len != so->addr->sa_len) return EINVAL;
@@ -694,16 +695,25 @@ int uv__udp_disconnect(uv_udp_t* handle) {
 #endif
 
     memset(&addr, 0, sizeof(addr));
-    
+
 #if defined(__MVS__)
     addr.ss_family = AF_UNSPEC;
 #else
     addr.sa_family = AF_UNSPEC;
 #endif
-    
+
     do {
       errno = 0;
+#ifdef __PASE__
+      /* On IBMi a connectionless transport socket can be disconnected by
+       * either setting the addr parameter to NULL or setting the
+       * addr_length parameter to zero, and issuing another connect().
+       * https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/connec.htm
+       */
+      r = connect(handle->io_watcher.fd, (struct sockaddr*) NULL, 0);
+#else
       r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr));
+#endif
     } while (r == -1 && errno == EINTR);
 
     if (r == -1) {
@@ -927,7 +937,8 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
     !defined(__NetBSD__) &&                                         \
     !defined(__ANDROID__) &&                                        \
     !defined(__DragonFly__) &&                                      \
-    !defined(__QNX__)
+    !defined(__QNX__) &&                                            \
+    !defined(__GNU__)
 static int uv__udp_set_source_membership4(uv_udp_t* handle,
                                           const struct sockaddr_in* multicast_addr,
                                           const char* interface_addr,
@@ -1119,7 +1130,8 @@ int uv_udp_set_source_membership(uv_udp_t* handle,
     !defined(__NetBSD__) &&                                         \
     !defined(__ANDROID__) &&                                        \
     !defined(__DragonFly__) &&                                      \
-    !defined(__QNX__)
+    !defined(__QNX__) &&                                            \
+    !defined(__GNU__)
   int err;
   union uv__sockaddr mcast_addr;
   union uv__sockaddr src_addr;

+ 3 - 1
Utilities/cmlibuv/src/uv-common.c

@@ -296,7 +296,9 @@ int uv_tcp_bind(uv_tcp_t* handle,
 
   if (handle->type != UV_TCP)
     return UV_EINVAL;
-
+  if (uv__is_closing(handle)) {
+    return UV_EINVAL;
+  }
   if (addr->sa_family == AF_INET)
     addrlen = sizeof(struct sockaddr_in);
   else if (addr->sa_family == AF_INET6)

+ 4 - 1
Utilities/cmlibuv/src/uv-common.h

@@ -130,7 +130,10 @@ enum {
   UV_SIGNAL_ONE_SHOT                    = 0x02000000,
 
   /* Only used by uv_poll_t handles. */
-  UV_HANDLE_POLL_SLOW                   = 0x01000000
+  UV_HANDLE_POLL_SLOW                   = 0x01000000,
+
+  /* Only used by uv_process_t handles. */
+  UV_HANDLE_REAP                        = 0x10000000
 };
 
 int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);

+ 5 - 5
Utilities/cmlibuv/src/win/async.c

@@ -28,7 +28,7 @@
 #include "req-inl.h"
 
 
-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 &&
       !handle->async_sent) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
@@ -54,9 +54,9 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
 }
 
 
-void uv_async_close(uv_loop_t* loop, uv_async_t* handle) {
+void uv__async_close(uv_loop_t* loop, uv_async_t* handle) {
   if (!((uv_async_t*)handle)->async_sent) {
-    uv_want_endgame(loop, (uv_handle_t*) handle);
+    uv__want_endgame(loop, (uv_handle_t*) handle);
   }
 
   uv__handle_closing(handle);
@@ -83,7 +83,7 @@ int uv_async_send(uv_async_t* handle) {
 }
 
 
-void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
+void uv__process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
     uv_req_t* req) {
   assert(handle->type == UV_ASYNC);
   assert(req->type == UV_WAKEUP);
@@ -91,7 +91,7 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
   handle->async_sent = 0;
 
   if (handle->flags & UV_HANDLE_CLOSING) {
-    uv_want_endgame(loop, (uv_handle_t*)handle);
+    uv__want_endgame(loop, (uv_handle_t*)handle);
   } else if (handle->async_cb != NULL) {
     handle->async_cb(handle);
   }

+ 47 - 43
Utilities/cmlibuv/src/win/core.c

@@ -84,10 +84,12 @@ static int uv__loops_capacity;
 #define UV__LOOPS_CHUNK_SIZE 8
 static uv_mutex_t uv__loops_lock;
 
+
 static void uv__loops_init(void) {
   uv_mutex_init(&uv__loops_lock);
 }
 
+
 static int uv__loops_add(uv_loop_t* loop) {
   uv_loop_t** new_loops;
   int new_capacity, i;
@@ -115,6 +117,7 @@ failed_loops_realloc:
   return ERROR_OUTOFMEMORY;
 }
 
+
 static void uv__loops_remove(uv_loop_t* loop) {
   int loop_index;
   int smaller_capacity;
@@ -173,7 +176,7 @@ void uv__wake_all_loops(void) {
   uv_mutex_unlock(&uv__loops_lock);
 }
 
-static void uv_init(void) {
+static void uv__init(void) {
   /* Tell Windows that we will handle critical errors. */
   SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
                SEM_NOOPENFILEERRORBOX);
@@ -199,19 +202,19 @@ static void uv_init(void) {
   /* Fetch winapi function pointers. This must be done first because other
    * initialization code might need these function pointers to be loaded.
    */
-  uv_winapi_init();
+  uv__winapi_init();
 
   /* Initialize winsock */
-  uv_winsock_init();
+  uv__winsock_init();
 
   /* Initialize FS */
-  uv_fs_init();
+  uv__fs_init();
 
   /* Initialize signal stuff */
-  uv_signals_init();
+  uv__signals_init();
 
   /* Initialize console */
-  uv_console_init();
+  uv__console_init();
 
   /* Initialize utilities */
   uv__util_init();
@@ -327,7 +330,7 @@ void uv_update_time(uv_loop_t* loop) {
 
 
 void uv__once_init(void) {
-  uv_once(&uv_init_guard_, uv_init);
+  uv_once(&uv_init_guard_, uv__init);
 }
 
 
@@ -395,23 +398,28 @@ int uv_loop_fork(uv_loop_t* loop) {
 }
 
 
-int uv_backend_timeout(const uv_loop_t* loop) {
-  if (loop->stop_flag != 0)
-    return 0;
-
-  if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
-    return 0;
+static int uv__loop_alive(const uv_loop_t* loop) {
+  return uv__has_active_handles(loop) ||
+         uv__has_active_reqs(loop) ||
+         loop->pending_reqs_tail != NULL ||
+         loop->endgame_handles != NULL;
+}
 
-  if (loop->pending_reqs_tail)
-    return 0;
 
-  if (loop->endgame_handles)
-    return 0;
+int uv_loop_alive(const uv_loop_t* loop) {
+  return uv__loop_alive(loop);
+}
 
-  if (loop->idle_handles)
-    return 0;
 
-  return uv__next_timeout(loop);
+int uv_backend_timeout(const uv_loop_t* loop) {
+  if (loop->stop_flag == 0 &&
+      /* uv__loop_alive(loop) && */
+      (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) &&
+      loop->pending_reqs_tail == NULL &&
+      loop->idle_handles == NULL &&
+      loop->endgame_handles == NULL)
+    return uv__next_timeout(loop);
+  return 0;
 }
 
 
@@ -462,8 +470,8 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
 
     if (overlapped) {
       /* Package was dequeued */
-      req = uv_overlapped_to_req(overlapped);
-      uv_insert_pending_req(loop, req);
+      req = uv__overlapped_to_req(overlapped);
+      uv__insert_pending_req(loop, req);
 
       /* Some time might have passed waiting for I/O,
        * so update the loop time here.
@@ -547,8 +555,8 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
          * meant only to wake us up.
          */
         if (overlappeds[i].lpOverlapped) {
-          req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
-          uv_insert_pending_req(loop, req);
+          req = uv__overlapped_to_req(overlappeds[i].lpOverlapped);
+          uv__insert_pending_req(loop, req);
         }
       }
 
@@ -581,22 +589,10 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
 }
 
 
-static int uv__loop_alive(const uv_loop_t* loop) {
-  return uv__has_active_handles(loop) ||
-         uv__has_active_reqs(loop) ||
-         loop->endgame_handles != NULL;
-}
-
-
-int uv_loop_alive(const uv_loop_t* loop) {
-    return uv__loop_alive(loop);
-}
-
-
 int uv_run(uv_loop_t *loop, uv_run_mode mode) {
   DWORD timeout;
   int r;
-  int ran_pending;
+  int can_sleep;
 
   r = uv__loop_alive(loop);
   if (!r)
@@ -606,12 +602,14 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
     uv_update_time(loop);
     uv__run_timers(loop);
 
-    ran_pending = uv_process_reqs(loop);
-    uv_idle_invoke(loop);
-    uv_prepare_invoke(loop);
+    can_sleep = loop->pending_reqs_tail == NULL && loop->idle_handles == NULL;
+
+    uv__process_reqs(loop);
+    uv__idle_invoke(loop);
+    uv__prepare_invoke(loop);
 
     timeout = 0;
-    if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
+    if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT)
       timeout = uv_backend_timeout(loop);
 
     if (pGetQueuedCompletionStatusEx)
@@ -619,6 +617,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
     else
       uv__poll_wine(loop, timeout);
 
+    /* Process immediate callbacks (e.g. write_cb) a small fixed number of
+     * times to avoid loop starvation.*/
+    for (r = 0; r < 8 && loop->pending_reqs_tail != NULL; r++)
+      uv__process_reqs(loop);
+
     /* Run one final update on the provider_idle_time in case uv__poll*
      * returned because the timeout expired, but no events were received. This
      * call will be ignored if the provider_entry_time was either never set (if
@@ -626,8 +629,8 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
      */
     uv__metrics_update_idle_time(loop);
 
-    uv_check_invoke(loop);
-    uv_process_endgames(loop);
+    uv__check_invoke(loop);
+    uv__process_endgames(loop);
 
     if (mode == UV_RUN_ONCE) {
       /* UV_RUN_ONCE implies forward progress: at least one callback must have
@@ -638,6 +641,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
        * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
        * the check.
        */
+      uv_update_time(loop);
       uv__run_timers(loop);
     }
 

+ 18 - 18
Utilities/cmlibuv/src/win/fs-event.c

@@ -33,7 +33,7 @@
 const unsigned int uv_directory_watcher_buffer_size = 4096;
 
 
-static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
+static void uv__fs_event_queue_readdirchanges(uv_loop_t* loop,
     uv_fs_event_t* handle) {
   assert(handle->dir_handle != INVALID_HANDLE_VALUE);
   assert(!handle->req_pending);
@@ -57,15 +57,15 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
                              NULL)) {
     /* Make this req pending reporting an error. */
     SET_REQ_ERROR(&handle->req, GetLastError());
-    uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
+    uv__insert_pending_req(loop, (uv_req_t*)&handle->req);
   }
 
   handle->req_pending = 1;
 }
 
-static void uv_relative_path(const WCHAR* filename,
-                             const WCHAR* dir,
-                             WCHAR** relpath) {
+static void uv__relative_path(const WCHAR* filename,
+                              const WCHAR* dir,
+                              WCHAR** relpath) {
   size_t relpathlen;
   size_t filenamelen = wcslen(filename);
   size_t dirlen = wcslen(dir);
@@ -80,7 +80,7 @@ static void uv_relative_path(const WCHAR* filename,
   (*relpath)[relpathlen] = L'\0';
 }
 
-static int uv_split_path(const WCHAR* filename, WCHAR** dir,
+static int uv__split_path(const WCHAR* filename, WCHAR** dir,
     WCHAR** file) {
   size_t len, i;
   DWORD dir_len;
@@ -255,12 +255,12 @@ int uv_fs_event_start(uv_fs_event_t* handle,
 short_path_done:
     short_path = short_path_buffer;
 
-    if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
+    if (uv__split_path(pathw, &dir, &handle->filew) != 0) {
       last_error = GetLastError();
       goto error;
     }
 
-    if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) {
+    if (uv__split_path(short_path, NULL, &handle->short_filew) != 0) {
       last_error = GetLastError();
       goto error;
     }
@@ -423,7 +423,7 @@ static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) {
 }
 
 
-void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
+void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
     uv_fs_event_t* handle) {
   FILE_NOTIFY_INFORMATION* file_info;
   int err, sizew, size;
@@ -442,7 +442,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
    */
   if (!uv__is_active(handle)) {
     if (handle->flags & UV_HANDLE_CLOSING) {
-      uv_want_endgame(loop, (uv_handle_t*) handle);
+      uv__want_endgame(loop, (uv_handle_t*) handle);
     }
     return;
   }
@@ -515,9 +515,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
 
               if (long_filenamew) {
                 /* Get the file name out of the long path. */
-                uv_relative_path(long_filenamew,
-                                 handle->dirw,
-                                 &filenamew);
+                uv__relative_path(long_filenamew,
+                                  handle->dirw,
+                                  &filenamew);
                 uv__free(long_filenamew);
                 long_filenamew = filenamew;
                 sizew = -1;
@@ -575,26 +575,26 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
   }
 
   if (handle->flags & UV_HANDLE_CLOSING) {
-    uv_want_endgame(loop, (uv_handle_t*)handle);
+    uv__want_endgame(loop, (uv_handle_t*)handle);
   } else if (uv__is_active(handle)) {
-    uv_fs_event_queue_readdirchanges(loop, handle);
+    uv__fs_event_queue_readdirchanges(loop, handle);
   }
 }
 
 
-void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
+void uv__fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
   uv_fs_event_stop(handle);
 
   uv__handle_closing(handle);
 
   if (!handle->req_pending) {
-    uv_want_endgame(loop, (uv_handle_t*)handle);
+    uv__want_endgame(loop, (uv_handle_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) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
 

+ 12 - 12
Utilities/cmlibuv/src/win/fs.c

@@ -46,7 +46,7 @@
   do {                                                                        \
     if (req == NULL)                                                          \
       return UV_EINVAL;                                                       \
-    uv_fs_req_init(loop, req, subtype, cb);                                   \
+    uv__fs_req_init(loop, req, subtype, cb);                                  \
   }                                                                           \
   while (0)
 
@@ -132,7 +132,7 @@ static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGE
 static DWORD uv__allocation_granularity;
 
 
-void uv_fs_init(void) {
+void uv__fs_init(void) {
   SYSTEM_INFO system_info;
 
   GetSystemInfo(&system_info);
@@ -241,7 +241,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
 
 
 
-INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
+INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req,
     uv_fs_type fs_type, const uv_fs_cb cb) {
   uv__once_init();
   UV_REQ_INIT(req, UV_FS);
@@ -912,12 +912,11 @@ void fs__read(uv_fs_t* req) {
     SET_REQ_RESULT(req, bytes);
   } else {
     error = GetLastError();
-
     if (error == ERROR_ACCESS_DENIED) {
       error = ERROR_INVALID_FLAGS;
     }
 
-    if (error == ERROR_HANDLE_EOF) {
+    if (error == ERROR_HANDLE_EOF || error == ERROR_BROKEN_PIPE) {
       SET_REQ_RESULT(req, bytes);
     } else {
       SET_REQ_WIN32_ERROR(req, error);
@@ -1881,8 +1880,9 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path,
                        NULL);
 
   if (handle == INVALID_HANDLE_VALUE)
-    ret = GetLastError();
-  else if (fs__stat_handle(handle, statbuf, do_lstat) != 0)
+    return GetLastError();
+
+  if (fs__stat_handle(handle, statbuf, do_lstat) != 0)
     ret = GetLastError();
   else
     ret = 0;
@@ -2300,13 +2300,13 @@ INLINE static DWORD fs__utime_impl_from_path(WCHAR* path,
                        flags,
                        NULL);
 
-  if (handle == INVALID_HANDLE_VALUE) {
-    ret = GetLastError();
-  } else if (fs__utime_handle(handle, atime, mtime) != 0) {
+  if (handle == INVALID_HANDLE_VALUE)
+    return GetLastError();
+
+  if (fs__utime_handle(handle, atime, mtime) != 0)
     ret = GetLastError();
-  } else {
+  else
     ret = 0;
-  }
 
   CloseHandle(handle);
   return ret;

+ 13 - 13
Utilities/cmlibuv/src/win/handle-inl.h

@@ -55,7 +55,7 @@
                                                                         \
     if (handle->flags & UV_HANDLE_CLOSING &&                            \
         handle->reqs_pending == 0) {                                    \
-      uv_want_endgame(loop, (uv_handle_t*)handle);                      \
+      uv__want_endgame(loop, (uv_handle_t*)handle);                     \
     }                                                                   \
   } while (0)
 
@@ -85,7 +85,7 @@
   } while (0)
 
 
-INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
+INLINE static void uv__want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
   if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
     handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
 
@@ -95,7 +95,7 @@ INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
 }
 
 
-INLINE static void uv_process_endgames(uv_loop_t* loop) {
+INLINE static void uv__process_endgames(uv_loop_t* loop) {
   uv_handle_t* handle;
 
   while (loop->endgame_handles) {
@@ -106,23 +106,23 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
 
     switch (handle->type) {
       case UV_TCP:
-        uv_tcp_endgame(loop, (uv_tcp_t*) handle);
+        uv__tcp_endgame(loop, (uv_tcp_t*) handle);
         break;
 
       case UV_NAMED_PIPE:
-        uv_pipe_endgame(loop, (uv_pipe_t*) handle);
+        uv__pipe_endgame(loop, (uv_pipe_t*) handle);
         break;
 
       case UV_TTY:
-        uv_tty_endgame(loop, (uv_tty_t*) handle);
+        uv__tty_endgame(loop, (uv_tty_t*) handle);
         break;
 
       case UV_UDP:
-        uv_udp_endgame(loop, (uv_udp_t*) handle);
+        uv__udp_endgame(loop, (uv_udp_t*) handle);
         break;
 
       case UV_POLL:
-        uv_poll_endgame(loop, (uv_poll_t*) handle);
+        uv__poll_endgame(loop, (uv_poll_t*) handle);
         break;
 
       case UV_TIMER:
@@ -133,23 +133,23 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
       case UV_PREPARE:
       case UV_CHECK:
       case UV_IDLE:
-        uv_loop_watcher_endgame(loop, handle);
+        uv__loop_watcher_endgame(loop, handle);
         break;
 
       case UV_ASYNC:
-        uv_async_endgame(loop, (uv_async_t*) handle);
+        uv__async_endgame(loop, (uv_async_t*) handle);
         break;
 
       case UV_SIGNAL:
-        uv_signal_endgame(loop, (uv_signal_t*) handle);
+        uv__signal_endgame(loop, (uv_signal_t*) handle);
         break;
 
       case UV_PROCESS:
-        uv_process_endgame(loop, (uv_process_t*) handle);
+        uv__process_endgame(loop, (uv_process_t*) handle);
         break;
 
       case UV_FS_EVENT:
-        uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
+        uv__fs_event_endgame(loop, (uv_fs_event_t*) handle);
         break;
 
       case UV_FS_POLL:

+ 13 - 13
Utilities/cmlibuv/src/win/handle.c

@@ -77,63 +77,63 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
   /* Handle-specific close actions */
   switch (handle->type) {
     case UV_TCP:
-      uv_tcp_close(loop, (uv_tcp_t*)handle);
+      uv__tcp_close(loop, (uv_tcp_t*)handle);
       return;
 
     case UV_NAMED_PIPE:
-      uv_pipe_close(loop, (uv_pipe_t*) handle);
+      uv__pipe_close(loop, (uv_pipe_t*) handle);
       return;
 
     case UV_TTY:
-      uv_tty_close((uv_tty_t*) handle);
+      uv__tty_close((uv_tty_t*) handle);
       return;
 
     case UV_UDP:
-      uv_udp_close(loop, (uv_udp_t*) handle);
+      uv__udp_close(loop, (uv_udp_t*) handle);
       return;
 
     case UV_POLL:
-      uv_poll_close(loop, (uv_poll_t*) handle);
+      uv__poll_close(loop, (uv_poll_t*) handle);
       return;
 
     case UV_TIMER:
       uv_timer_stop((uv_timer_t*)handle);
       uv__handle_closing(handle);
-      uv_want_endgame(loop, handle);
+      uv__want_endgame(loop, handle);
       return;
 
     case UV_PREPARE:
       uv_prepare_stop((uv_prepare_t*)handle);
       uv__handle_closing(handle);
-      uv_want_endgame(loop, handle);
+      uv__want_endgame(loop, handle);
       return;
 
     case UV_CHECK:
       uv_check_stop((uv_check_t*)handle);
       uv__handle_closing(handle);
-      uv_want_endgame(loop, handle);
+      uv__want_endgame(loop, handle);
       return;
 
     case UV_IDLE:
       uv_idle_stop((uv_idle_t*)handle);
       uv__handle_closing(handle);
-      uv_want_endgame(loop, handle);
+      uv__want_endgame(loop, handle);
       return;
 
     case UV_ASYNC:
-      uv_async_close(loop, (uv_async_t*) handle);
+      uv__async_close(loop, (uv_async_t*) handle);
       return;
 
     case UV_SIGNAL:
-      uv_signal_close(loop, (uv_signal_t*) handle);
+      uv__signal_close(loop, (uv_signal_t*) handle);
       return;
 
     case UV_PROCESS:
-      uv_process_close(loop, (uv_process_t*) handle);
+      uv__process_close(loop, (uv_process_t*) handle);
       return;
 
     case UV_FS_EVENT:
-      uv_fs_event_close(loop, (uv_fs_event_t*) handle);
+      uv__fs_event_close(loop, (uv_fs_event_t*) handle);
       return;
 
     case UV_FS_POLL:

+ 72 - 73
Utilities/cmlibuv/src/win/internal.h

@@ -76,25 +76,28 @@ typedef struct {
   uint32_t delayed_error;
 } uv__ipc_socket_xfer_info_t;
 
-int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
-int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
-int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_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_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
     uv_read_cb read_cb);
-int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
+int uv__tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
     const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
 int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[],
     unsigned int nbufs);
 
-void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req);
-void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
+void uv__process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req);
+void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
     uv_write_t* req);
-void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
+void uv__process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
     uv_req_t* req);
-void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
+void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
     uv_connect_t* req);
+void uv__process_tcp_shutdown_req(uv_loop_t* loop,
+                                  uv_tcp_t* stream,
+                                  uv_shutdown_t* req);
 
-void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
-void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
+void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
+void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
 
 int uv__tcp_xfer_export(uv_tcp_t* handle,
                         int pid,
@@ -108,12 +111,12 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp,
 /*
  * UDP
  */
-void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
-void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
+void uv__process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
+void uv__process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
     uv_udp_send_t* req);
 
-void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle);
-void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
+void uv__udp_close(uv_loop_t* loop, uv_udp_t* handle);
+void uv__udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
 
 
 /*
@@ -122,9 +125,9 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
 int uv__create_stdio_pipe_pair(uv_loop_t* loop,
     uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags);
 
-int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
-int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
-int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
+int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
+int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client);
+int uv__pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
     uv_read_cb read_cb);
 void uv__pipe_read_stop(uv_pipe_t* handle);
 int uv__pipe_write(uv_loop_t* loop,
@@ -134,75 +137,77 @@ int uv__pipe_write(uv_loop_t* loop,
                    size_t nbufs,
                    uv_stream_t* send_handle,
                    uv_write_cb cb);
+void uv__pipe_shutdown(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req);
 
-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);
-void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
+void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
     uv_write_t* req);
-void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
+void uv__process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
     uv_req_t* raw_req);
-void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
+void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
     uv_connect_t* req);
-void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
+void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
     uv_shutdown_t* req);
 
-void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
-void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle);
-void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
+void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
+void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
 
 
 /*
  * TTY
  */
-void uv_console_init(void);
+void uv__console_init(void);
 
-int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
+int uv__tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
     uv_read_cb read_cb);
-int uv_tty_read_stop(uv_tty_t* handle);
-int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
+int uv__tty_read_stop(uv_tty_t* handle);
+int uv__tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
     const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
 int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[],
     unsigned int nbufs);
-void uv_tty_close(uv_tty_t* handle);
+void uv__tty_close(uv_tty_t* handle);
 
-void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
+void uv__process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
     uv_req_t* req);
-void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
+void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
     uv_write_t* req);
 /*
- * uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
+ * uv__process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
  * TODO: find a way to remove it
  */
-void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
+void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
     uv_req_t* raw_req);
 /*
- * uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
+ * uv__process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
  * TODO: find a way to remove it
  */
-void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
+void uv__process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
     uv_connect_t* req);
-
-void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
+void uv__process_tty_shutdown_req(uv_loop_t* loop,
+                                  uv_tty_t* stream,
+                                  uv_shutdown_t* req);
+void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
 
 
 /*
  * Poll watchers
  */
-void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+void uv__process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
     uv_req_t* req);
 
-int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle);
-void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
+int uv__poll_close(uv_loop_t* loop, uv_poll_t* handle);
+void uv__poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
 
 
 /*
  * Loop watchers
  */
-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);
 
-void uv_prepare_invoke(uv_loop_t* loop);
-void uv_check_invoke(uv_loop_t* loop);
-void uv_idle_invoke(uv_loop_t* loop);
+void uv__prepare_invoke(uv_loop_t* loop);
+void uv__check_invoke(uv_loop_t* loop);
+void uv__idle_invoke(uv_loop_t* loop);
 
 void uv__once_init(void);
 
@@ -210,53 +215,47 @@ void uv__once_init(void);
 /*
  * Async watcher
  */
-void uv_async_close(uv_loop_t* loop, uv_async_t* handle);
-void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle);
+void uv__async_close(uv_loop_t* loop, uv_async_t* handle);
+void uv__async_endgame(uv_loop_t* loop, uv_async_t* handle);
 
-void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
+void uv__process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
     uv_req_t* req);
 
 
 /*
  * Signal watcher
  */
-void uv_signals_init(void);
+void uv__signals_init(void);
 int uv__signal_dispatch(int signum);
 
-void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle);
-void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
+void uv__signal_close(uv_loop_t* loop, uv_signal_t* handle);
+void uv__signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
 
-void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
+void uv__process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
     uv_req_t* req);
 
 
 /*
  * Spawn
  */
-void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
-void uv_process_close(uv_loop_t* loop, uv_process_t* handle);
-void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
-
-
-/*
- * Error
- */
-int uv_translate_sys_error(int sys_errno);
+void uv__process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
+void uv__process_close(uv_loop_t* loop, uv_process_t* handle);
+void uv__process_endgame(uv_loop_t* loop, uv_process_t* handle);
 
 
 /*
  * FS
  */
-void uv_fs_init(void);
+void uv__fs_init(void);
 
 
 /*
  * FS Event
  */
-void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
+void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
     uv_fs_event_t* handle);
-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_close(uv_loop_t* loop, uv_fs_event_t* handle);
+void uv__fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
 
 
 /*
@@ -303,28 +302,28 @@ HANDLE uv__stdio_handle(BYTE* buffer, int fd);
 /*
  * Winapi and ntapi utility functions
  */
-void uv_winapi_init(void);
+void uv__winapi_init(void);
 
 
 /*
  * Winsock utility functions
  */
-void uv_winsock_init(void);
+void uv__winsock_init(void);
 
-int uv_ntstatus_to_winsock_error(NTSTATUS status);
+int uv__ntstatus_to_winsock_error(NTSTATUS status);
 
-BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
-BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
+BOOL uv__get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
+BOOL uv__get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
 
-int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
+int WSAAPI uv__wsarecv_workaround(SOCKET socket, WSABUF* buffers,
     DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
     LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
-int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
+int WSAAPI uv__wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
     DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
     int* addr_len, WSAOVERLAPPED *overlapped,
     LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
 
-int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
+int WSAAPI uv__msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
     AFD_POLL_INFO* info_out, OVERLAPPED* overlapped);
 
 /* Whether there are any non-IFS LSPs stacked on TCP */

+ 2 - 2
Utilities/cmlibuv/src/win/loop-watcher.c

@@ -26,7 +26,7 @@
 #include "handle-inl.h"
 
 
-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) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
     handle->flags |= UV_HANDLE_CLOSED;
@@ -104,7 +104,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
   }                                                                           \
                                                                               \
                                                                               \
-  void uv_##name##_invoke(uv_loop_t* loop) {                                  \
+  void uv__##name##_invoke(uv_loop_t* loop) {                                 \
     uv_##name##_t* handle;                                                    \
                                                                               \
     (loop)->next_##name##_handle = (loop)->name##_handles;                    \

File diff suppressed because it is too large
+ 299 - 252
Utilities/cmlibuv/src/win/pipe.c


+ 19 - 17
Utilities/cmlibuv/src/win/poll.c

@@ -34,7 +34,9 @@ static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
   {0xf9eab0c0, 0x26d4, 0x11d0,
       {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
   {0x9fc48064, 0x7298, 0x43e4,
-      {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
+      {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}},
+  {0xa00943d9, 0x9c2e, 0x4633,
+      {0x9b, 0x59, 0x00, 0x57, 0xa3, 0x16, 0x09, 0x94}}
 };
 
 typedef struct uv_single_fd_set_s {
@@ -122,14 +124,14 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
 
   memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
 
-  result = uv_msafd_poll((SOCKET) handle->peer_socket,
-                         afd_poll_info,
-                         afd_poll_info,
-                         &req->u.io.overlapped);
+  result = uv__msafd_poll((SOCKET) handle->peer_socket,
+                          afd_poll_info,
+                          afd_poll_info,
+                          &req->u.io.overlapped);
   if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
     /* Queue this req, reporting an error. */
     SET_REQ_ERROR(req, WSAGetLastError());
-    uv_insert_pending_req(loop, req);
+    uv__insert_pending_req(loop, req);
   }
 }
 
@@ -195,7 +197,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
   } else if ((handle->flags & UV_HANDLE_CLOSING) &&
              handle->submitted_events_1 == 0 &&
              handle->submitted_events_2 == 0) {
-    uv_want_endgame(loop, (uv_handle_t*) handle);
+    uv__want_endgame(loop, (uv_handle_t*) handle);
   }
 }
 
@@ -357,7 +359,7 @@ static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
                          WT_EXECUTELONGFUNCTION)) {
     /* Make this req pending, reporting an error. */
     SET_REQ_ERROR(req, GetLastError());
-    uv_insert_pending_req(loop, req);
+    uv__insert_pending_req(loop, req);
   }
 }
 
@@ -400,7 +402,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
   } else if ((handle->flags & UV_HANDLE_CLOSING) &&
              handle->submitted_events_1 == 0 &&
              handle->submitted_events_2 == 0) {
-    uv_want_endgame(loop, (uv_handle_t*) handle);
+    uv__want_endgame(loop, (uv_handle_t*) handle);
   }
 }
 
@@ -524,7 +526,7 @@ int uv_poll_stop(uv_poll_t* handle) {
 }
 
 
-void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
+void uv__process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
   if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
     uv__fast_poll_process_poll_req(loop, handle, req);
   } else {
@@ -533,7 +535,7 @@ void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
 }
 
 
-int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+int uv__poll_close(uv_loop_t* loop, uv_poll_t* handle) {
   AFD_POLL_INFO afd_poll_info;
   DWORD error;
   int result;
@@ -543,7 +545,7 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
 
   if (handle->submitted_events_1 == 0 &&
       handle->submitted_events_2 == 0) {
-    uv_want_endgame(loop, (uv_handle_t*) handle);
+    uv__want_endgame(loop, (uv_handle_t*) handle);
     return 0;
   }
 
@@ -559,10 +561,10 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
   afd_poll_info.Handles[0].Status = 0;
   afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
 
-  result = uv_msafd_poll(handle->socket,
-                         &afd_poll_info,
-                         uv__get_afd_poll_info_dummy(),
-                         uv__get_overlapped_dummy());
+  result = uv__msafd_poll(handle->socket,
+                          &afd_poll_info,
+                          uv__get_afd_poll_info_dummy(),
+                          uv__get_overlapped_dummy());
 
   if (result == SOCKET_ERROR) {
     error = WSAGetLastError();
@@ -574,7 +576,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_CLOSED));
 

+ 10 - 10
Utilities/cmlibuv/src/win/process.c

@@ -105,7 +105,7 @@ static void uv__init_global_job_handle(void) {
 }
 
 
-static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
+static int uv__utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
   int ws_len, r;
   WCHAR* ws;
 
@@ -137,7 +137,7 @@ static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
 }
 
 
-static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
+static void uv__process_init(uv_loop_t* loop, uv_process_t* handle) {
   uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
   handle->exit_cb = NULL;
   handle->pid = 0;
@@ -864,7 +864,7 @@ static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
 
 
 /* Called on main thread after a child process has exited. */
-void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
+void uv__process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
   int64_t exit_code;
   DWORD status;
 
@@ -874,7 +874,7 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
   /* 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;
   }
 
@@ -902,7 +902,7 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
 }
 
 
-void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
+void uv__process_close(uv_loop_t* loop, uv_process_t* handle) {
   uv__handle_closing(handle);
 
   if (handle->wait_handle != INVALID_HANDLE_VALUE) {
@@ -918,12 +918,12 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
   }
 
   if (!handle->exit_cb_pending) {
-    uv_want_endgame(loop, (uv_handle_t*)handle);
+    uv__want_endgame(loop, (uv_handle_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->flags & UV_HANDLE_CLOSING);
   assert(!(handle->flags & UV_HANDLE_CLOSED));
@@ -948,7 +948,7 @@ int uv_spawn(uv_loop_t* loop,
   PROCESS_INFORMATION info;
   DWORD process_flags;
 
-  uv_process_init(loop, process);
+  uv__process_init(loop, process);
   process->exit_cb = options->exit_cb;
 
   if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
@@ -975,7 +975,7 @@ int uv_spawn(uv_loop_t* loop,
                               UV_PROCESS_WINDOWS_HIDE_GUI |
                               UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
 
-  err = uv_utf8_to_utf16_alloc(options->file, &application);
+  err = uv__utf8_to_utf16_alloc(options->file, &application);
   if (err)
     goto done;
 
@@ -994,7 +994,7 @@ int uv_spawn(uv_loop_t* loop,
 
   if (options->cwd) {
     /* Explicit cwd */
-    err = uv_utf8_to_utf16_alloc(options->cwd, &cwd);
+    err = uv__utf8_to_utf16_alloc(options->cwd, &cwd);
     if (err)
       goto done;
 

+ 18 - 25
Utilities/cmlibuv/src/win/req-inl.h

@@ -50,7 +50,7 @@
   (pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
 
 #define GET_REQ_SOCK_ERROR(req)                                         \
-  (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
+  (uv__ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
 
 
 #define REGISTER_HANDLE_REQ(loop, handle, req)                          \
@@ -82,12 +82,12 @@
   }
 
 
-INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
+INLINE static uv_req_t* uv__overlapped_to_req(OVERLAPPED* overlapped) {
   return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
 }
 
 
-INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
+INLINE static void uv__insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
   req->next_req = NULL;
   if (loop->pending_reqs_tail) {
 #ifdef _DEBUG
@@ -115,19 +115,19 @@ INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
   do {                                                                        \
     switch (((uv_handle_t*) (req)->handle_at)->type) {                        \
       case UV_TCP:                                                            \
-        uv_process_tcp_##method##_req(loop,                                   \
+        uv__process_tcp_##method##_req(loop,                                  \
                                       (uv_tcp_t*) ((req)->handle_at),         \
                                       req);                                   \
         break;                                                                \
                                                                               \
       case UV_NAMED_PIPE:                                                     \
-        uv_process_pipe_##method##_req(loop,                                  \
+        uv__process_pipe_##method##_req(loop,                                 \
                                        (uv_pipe_t*) ((req)->handle_at),       \
                                        req);                                  \
         break;                                                                \
                                                                               \
       case UV_TTY:                                                            \
-        uv_process_tty_##method##_req(loop,                                   \
+        uv__process_tty_##method##_req(loop,                                  \
                                       (uv_tty_t*) ((req)->handle_at),         \
                                       req);                                   \
         break;                                                                \
@@ -138,13 +138,13 @@ INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
   } while (0)
 
 
-INLINE static int uv_process_reqs(uv_loop_t* loop) {
+INLINE static void uv__process_reqs(uv_loop_t* loop) {
   uv_req_t* req;
   uv_req_t* first;
   uv_req_t* next;
 
   if (loop->pending_reqs_tail == NULL)
-    return 0;
+    return;
 
   first = loop->pending_reqs_tail->next_req;
   next = first;
@@ -172,50 +172,43 @@ INLINE static int uv_process_reqs(uv_loop_t* loop) {
         break;
 
       case UV_SHUTDOWN:
-        /* Tcp shutdown requests don't come here. */
-        assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
-        uv_process_pipe_shutdown_req(
-            loop,
-            (uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
-            (uv_shutdown_t*) req);
+        DELEGATE_STREAM_REQ(loop, (uv_shutdown_t*) req, shutdown, handle);
         break;
 
       case UV_UDP_RECV:
-        uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
+        uv__process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
         break;
 
       case UV_UDP_SEND:
-        uv_process_udp_send_req(loop,
-                                ((uv_udp_send_t*) req)->handle,
-                                (uv_udp_send_t*) req);
+        uv__process_udp_send_req(loop,
+                                 ((uv_udp_send_t*) req)->handle,
+                                 (uv_udp_send_t*) req);
         break;
 
       case UV_WAKEUP:
-        uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
+        uv__process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
         break;
 
       case UV_SIGNAL_REQ:
-        uv_process_signal_req(loop, (uv_signal_t*) req->data, req);
+        uv__process_signal_req(loop, (uv_signal_t*) req->data, req);
         break;
 
       case UV_POLL_REQ:
-        uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
+        uv__process_poll_req(loop, (uv_poll_t*) req->data, req);
         break;
 
       case UV_PROCESS_EXIT:
-        uv_process_proc_exit(loop, (uv_process_t*) req->data);
+        uv__process_proc_exit(loop, (uv_process_t*) req->data);
         break;
 
       case UV_FS_EVENT_REQ:
-        uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
+        uv__process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
         break;
 
       default:
         assert(0);
     }
   }
-
-  return 1;
 }
 
 #endif /* UV_WIN_REQ_INL_H_ */

+ 6 - 6
Utilities/cmlibuv/src/win/signal.c

@@ -39,7 +39,7 @@ int uv__signal_start(uv_signal_t* handle,
                      int signum,
                      int oneshot);
 
-void uv_signals_init(void) {
+void uv__signals_init(void) {
   InitializeCriticalSection(&uv__signal_lock);
   if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
     abort();
@@ -231,7 +231,7 @@ int uv__signal_start(uv_signal_t* handle,
 }
 
 
-void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
+void uv__process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
     uv_req_t* req) {
   long dispatched_signum;
 
@@ -254,22 +254,22 @@ void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
   if (handle->flags & UV_HANDLE_CLOSING) {
     /* When it is closing, it must be stopped at this point. */
     assert(handle->signum == 0);
-    uv_want_endgame(loop, (uv_handle_t*) handle);
+    uv__want_endgame(loop, (uv_handle_t*) handle);
   }
 }
 
 
-void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
+void uv__signal_close(uv_loop_t* loop, uv_signal_t* handle) {
   uv_signal_stop(handle);
   uv__handle_closing(handle);
 
   if (handle->pending_signum == 0) {
-    uv_want_endgame(loop, (uv_handle_t*) handle);
+    uv__want_endgame(loop, (uv_handle_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_CLOSED));
 

+ 4 - 4
Utilities/cmlibuv/src/win/stream-inl.h

@@ -30,9 +30,9 @@
 #include "req-inl.h"
 
 
-INLINE static void uv_stream_init(uv_loop_t* loop,
-                                  uv_stream_t* handle,
-                                  uv_handle_type type) {
+INLINE static void uv__stream_init(uv_loop_t* loop,
+                                   uv_stream_t* handle,
+                                   uv_handle_type type) {
   uv__handle_init(loop, (uv_handle_t*) handle, type);
   handle->write_queue_size = 0;
   handle->activecnt = 0;
@@ -46,7 +46,7 @@ INLINE static void uv_stream_init(uv_loop_t* loop,
 }
 
 
-INLINE static void uv_connection_init(uv_stream_t* handle) {
+INLINE static void uv__connection_init(uv_stream_t* handle) {
   handle->flags |= UV_HANDLE_CONNECTION;
 }
 

+ 19 - 12
Utilities/cmlibuv/src/win/stream.c

@@ -29,14 +29,16 @@
 
 int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
   int err;
-
+  if (uv__is_closing(stream)) {
+    return UV_EINVAL;
+  }
   err = ERROR_INVALID_PARAMETER;
   switch (stream->type) {
     case UV_TCP:
-      err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
+      err = uv__tcp_listen((uv_tcp_t*)stream, backlog, cb);
       break;
     case UV_NAMED_PIPE:
-      err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
+      err = uv__pipe_listen((uv_pipe_t*)stream, backlog, cb);
       break;
     default:
       assert(0);
@@ -52,10 +54,10 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
   err = ERROR_INVALID_PARAMETER;
   switch (server->type) {
     case UV_TCP:
-      err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
+      err = uv__tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
       break;
     case UV_NAMED_PIPE:
-      err = uv_pipe_accept((uv_pipe_t*)server, client);
+      err = uv__pipe_accept((uv_pipe_t*)server, client);
       break;
     default:
       assert(0);
@@ -73,13 +75,13 @@ int uv__read_start(uv_stream_t* handle,
   err = ERROR_INVALID_PARAMETER;
   switch (handle->type) {
     case UV_TCP:
-      err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
+      err = uv__tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
       break;
     case UV_NAMED_PIPE:
-      err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
+      err = uv__pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
       break;
     case UV_TTY:
-      err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb);
+      err = uv__tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb);
       break;
     default:
       assert(0);
@@ -97,7 +99,7 @@ int uv_read_stop(uv_stream_t* handle) {
 
   err = 0;
   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 {
@@ -124,14 +126,14 @@ int uv_write(uv_write_t* req,
   err = ERROR_INVALID_PARAMETER;
   switch (handle->type) {
     case UV_TCP:
-      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;
     case UV_NAMED_PIPE:
       err = uv__pipe_write(
           loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb);
       break;
     case UV_TTY:
-      err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
+      err = uv__tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
       break;
     default:
       assert(0);
@@ -217,7 +219,12 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
   handle->reqs_pending++;
   REGISTER_HANDLE_REQ(loop, handle, req);
 
-  uv_want_endgame(loop, (uv_handle_t*)handle);
+  if (handle->stream.conn.write_reqs_pending == 0) {
+    if (handle->type == UV_NAMED_PIPE)
+      uv__pipe_shutdown(loop, (uv_pipe_t*) handle, req);
+    else
+      uv__insert_pending_req(loop, (uv_req_t*) req);
+  }
 
   return 0;
 }

+ 129 - 126
Utilities/cmlibuv/src/win/tcp.c

@@ -78,11 +78,11 @@ static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsign
 }
 
 
-static int uv_tcp_set_socket(uv_loop_t* loop,
-                             uv_tcp_t* handle,
-                             SOCKET socket,
-                             int family,
-                             int imported) {
+static int uv__tcp_set_socket(uv_loop_t* loop,
+                              uv_tcp_t* handle,
+                              SOCKET socket,
+                              int family,
+                              int imported) {
   DWORD yes = 1;
   int non_ifs_lsp;
   int err;
@@ -162,7 +162,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
   if (flags & ~0xFF)
     return UV_EINVAL;
 
-  uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP);
+  uv__stream_init(loop, (uv_stream_t*) handle, UV_TCP);
   handle->tcp.serv.accept_reqs = NULL;
   handle->tcp.serv.pending_accepts = NULL;
   handle->socket = INVALID_SOCKET;
@@ -173,7 +173,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
   handle->delayed_error = 0;
 
   /* If anything fails beyond this point we need to remove the handle from
-   * 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 (domain != AF_UNSPEC) {
@@ -187,7 +187,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
       return uv_translate_sys_error(err);
     }
 
-    err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0);
+    err = uv__tcp_set_socket(handle->loop, handle, sock, domain, 0);
     if (err) {
       closesocket(sock);
       QUEUE_REMOVE(&handle->handle_queue);
@@ -205,73 +205,76 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
 }
 
 
-void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
+void uv__process_tcp_shutdown_req(uv_loop_t* loop, uv_tcp_t* stream, uv_shutdown_t *req) {
   int err;
-  unsigned int i;
-  uv_tcp_accept_t* req;
 
-  if (handle->flags & UV_HANDLE_CONNECTION &&
-      handle->stream.conn.shutdown_req != NULL &&
-      handle->stream.conn.write_reqs_pending == 0) {
+  assert(req);
+  assert(stream->stream.conn.write_reqs_pending == 0);
+  assert(!(stream->flags & UV_HANDLE_SHUT));
+  assert(stream->flags & UV_HANDLE_CONNECTION);
 
-    UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
+  stream->stream.conn.shutdown_req = NULL;
+  stream->flags &= ~UV_HANDLE_SHUTTING;
+  UNREGISTER_HANDLE_REQ(loop, stream, req);
 
-    err = 0;
-    if (handle->flags & UV_HANDLE_CLOSING) {
-      err = ERROR_OPERATION_ABORTED;
-    } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
-      err = WSAGetLastError();
-    }
+  err = 0;
+  if (stream->flags & UV_HANDLE_CLOSING)
+   /* The user destroyed the stream before we got to do the shutdown. */
+    err = UV_ECANCELED;
+  else if (shutdown(stream->socket, SD_SEND) == SOCKET_ERROR)
+    err = uv_translate_sys_error(WSAGetLastError());
+  else /* Success. */
+    stream->flags |= UV_HANDLE_SHUT;
+
+  if (req->cb)
+    req->cb(req, err);
 
-    if (handle->stream.conn.shutdown_req->cb) {
-      handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req,
-                               uv_translate_sys_error(err));
-    }
+  DECREASE_PENDING_REQ_COUNT(stream);
+}
 
-    handle->stream.conn.shutdown_req = NULL;
-    DECREASE_PENDING_REQ_COUNT(handle);
-    return;
-  }
 
-  if (handle->flags & UV_HANDLE_CLOSING &&
-      handle->reqs_pending == 0) {
-    assert(!(handle->flags & UV_HANDLE_CLOSED));
-    assert(handle->socket == INVALID_SOCKET);
+void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
+  unsigned int i;
+  uv_tcp_accept_t* req;
+
+  assert(handle->flags & UV_HANDLE_CLOSING);
+  assert(handle->reqs_pending == 0);
+  assert(!(handle->flags & UV_HANDLE_CLOSED));
+  assert(handle->socket == INVALID_SOCKET);
 
-    if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
-      if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
-        for (i = 0; i < uv_simultaneous_server_accepts; i++) {
-          req = &handle->tcp.serv.accept_reqs[i];
-          if (req->wait_handle != INVALID_HANDLE_VALUE) {
-            UnregisterWait(req->wait_handle);
-            req->wait_handle = INVALID_HANDLE_VALUE;
-          }
-          if (req->event_handle != NULL) {
-            CloseHandle(req->event_handle);
-            req->event_handle = NULL;
-          }
+  if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
+    if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+      for (i = 0; i < uv_simultaneous_server_accepts; i++) {
+        req = &handle->tcp.serv.accept_reqs[i];
+        if (req->wait_handle != INVALID_HANDLE_VALUE) {
+          UnregisterWait(req->wait_handle);
+          req->wait_handle = INVALID_HANDLE_VALUE;
+        }
+        if (req->event_handle != NULL) {
+          CloseHandle(req->event_handle);
+          req->event_handle = NULL;
         }
       }
-
-      uv__free(handle->tcp.serv.accept_reqs);
-      handle->tcp.serv.accept_reqs = NULL;
     }
 
-    if (handle->flags & UV_HANDLE_CONNECTION &&
-        handle->flags & UV_HANDLE_EMULATE_IOCP) {
-      if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
-        UnregisterWait(handle->read_req.wait_handle);
-        handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
-      }
-      if (handle->read_req.event_handle != NULL) {
-        CloseHandle(handle->read_req.event_handle);
-        handle->read_req.event_handle = NULL;
-      }
-    }
+    uv__free(handle->tcp.serv.accept_reqs);
+    handle->tcp.serv.accept_reqs = NULL;
+  }
 
-    uv__handle_close(handle);
-    loop->active_tcp_streams--;
+  if (handle->flags & UV_HANDLE_CONNECTION &&
+      handle->flags & UV_HANDLE_EMULATE_IOCP) {
+    if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
+      UnregisterWait(handle->read_req.wait_handle);
+      handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+    }
+    if (handle->read_req.event_handle != NULL) {
+      CloseHandle(handle->read_req.event_handle);
+      handle->read_req.event_handle = NULL;
+    }
   }
+
+  uv__handle_close(handle);
+  loop->active_tcp_streams--;
 }
 
 
@@ -286,10 +289,10 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
  * See issue #1360.
  *
  */
-static int uv_tcp_try_bind(uv_tcp_t* handle,
-                           const struct sockaddr* addr,
-                           unsigned int addrlen,
-                           unsigned int flags) {
+static int uv__tcp_try_bind(uv_tcp_t* handle,
+                            const struct sockaddr* addr,
+                            unsigned int addrlen,
+                            unsigned int flags) {
   DWORD err;
   int r;
 
@@ -305,7 +308,7 @@ static int uv_tcp_try_bind(uv_tcp_t* handle,
       return WSAGetLastError();
     }
 
-    err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0);
+    err = uv__tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0);
     if (err) {
       closesocket(sock);
       return err;
@@ -385,7 +388,7 @@ static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) {
 }
 
 
-static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
+static void uv__tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
   uv_loop_t* loop = handle->loop;
   BOOL success;
   DWORD bytes;
@@ -406,7 +409,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
   accept_socket = socket(family, SOCK_STREAM, 0);
   if (accept_socket == INVALID_SOCKET) {
     SET_REQ_ERROR(req, WSAGetLastError());
-    uv_insert_pending_req(loop, (uv_req_t*)req);
+    uv__insert_pending_req(loop, (uv_req_t*)req);
     handle->reqs_pending++;
     return;
   }
@@ -414,7 +417,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
   /* Make the socket non-inheritable */
   if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) {
     SET_REQ_ERROR(req, GetLastError());
-    uv_insert_pending_req(loop, (uv_req_t*)req);
+    uv__insert_pending_req(loop, (uv_req_t*)req);
     handle->reqs_pending++;
     closesocket(accept_socket);
     return;
@@ -440,7 +443,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
     /* Process the req without IOCP. */
     req->accept_socket = accept_socket;
     handle->reqs_pending++;
-    uv_insert_pending_req(loop, (uv_req_t*)req);
+    uv__insert_pending_req(loop, (uv_req_t*)req);
   } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
     /* The req will be processed with IOCP. */
     req->accept_socket = accept_socket;
@@ -451,12 +454,12 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
           req->event_handle, post_completion, (void*) req,
           INFINITE, WT_EXECUTEINWAITTHREAD)) {
       SET_REQ_ERROR(req, GetLastError());
-      uv_insert_pending_req(loop, (uv_req_t*)req);
+      uv__insert_pending_req(loop, (uv_req_t*)req);
     }
   } else {
     /* Make this req pending reporting an error. */
     SET_REQ_ERROR(req, WSAGetLastError());
-    uv_insert_pending_req(loop, (uv_req_t*)req);
+    uv__insert_pending_req(loop, (uv_req_t*)req);
     handle->reqs_pending++;
     /* Destroy the preallocated client socket. */
     closesocket(accept_socket);
@@ -469,7 +472,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
 }
 
 
-static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
+static void uv__tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
   uv_read_t* req;
   uv_buf_t buf;
   int result;
@@ -524,7 +527,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
   if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
     /* Process the req without IOCP. */
     req->u.io.overlapped.InternalHigh = bytes;
-    uv_insert_pending_req(loop, (uv_req_t*)req);
+    uv__insert_pending_req(loop, (uv_req_t*)req);
   } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
     /* The req will be processed with IOCP. */
     if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
@@ -533,12 +536,12 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
           req->event_handle, post_completion, (void*) req,
           INFINITE, WT_EXECUTEINWAITTHREAD)) {
       SET_REQ_ERROR(req, GetLastError());
-      uv_insert_pending_req(loop, (uv_req_t*)req);
+      uv__insert_pending_req(loop, (uv_req_t*)req);
     }
   } else {
     /* Make this req pending reporting an error. */
     SET_REQ_ERROR(req, WSAGetLastError());
-    uv_insert_pending_req(loop, (uv_req_t*)req);
+    uv__insert_pending_req(loop, (uv_req_t*)req);
   }
 }
 
@@ -558,7 +561,7 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
 }
 
 
-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) {
   unsigned int i, simultaneous_accepts;
   uv_tcp_accept_t* req;
   int err;
@@ -578,10 +581,10 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
   }
 
   if (!(handle->flags & UV_HANDLE_BOUND)) {
-    err = uv_tcp_try_bind(handle,
-                          (const struct sockaddr*) &uv_addr_ip4_any_,
-                          sizeof(uv_addr_ip4_any_),
-                          0);
+    err = uv__tcp_try_bind(handle,
+                           (const struct sockaddr*) &uv_addr_ip4_any_,
+                           sizeof(uv_addr_ip4_any_),
+                           0);
     if (err)
       return err;
     if (handle->delayed_error)
@@ -589,7 +592,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
   }
 
   if (!handle->tcp.serv.func_acceptex) {
-    if (!uv_get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) {
+    if (!uv__get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) {
       return WSAEAFNOSUPPORT;
     }
   }
@@ -630,7 +633,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
         req->event_handle = NULL;
       }
 
-      uv_tcp_queue_accept(handle, req);
+      uv__tcp_queue_accept(handle, req);
     }
 
     /* Initialize other unused requests too, because uv_tcp_endgame doesn't
@@ -650,7 +653,7 @@ 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) {
   uv_loop_t* loop = server->loop;
   int err = 0;
   int family;
@@ -672,7 +675,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
     family = AF_INET;
   }
 
-  err = uv_tcp_set_socket(client->loop,
+  err = uv__tcp_set_socket(client->loop,
                           client,
                           req->accept_socket,
                           family,
@@ -680,7 +683,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
   if (err) {
     closesocket(req->accept_socket);
   } else {
-    uv_connection_init((uv_stream_t*) client);
+    uv__connection_init((uv_stream_t*) client);
     /* AcceptEx() implicitly binds the accepted socket. */
     client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
   }
@@ -693,7 +696,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
   if (!(server->flags & UV_HANDLE_CLOSING)) {
     /* Check if we're in a middle of changing the number of pending accepts. */
     if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
-      uv_tcp_queue_accept(server, req);
+      uv__tcp_queue_accept(server, req);
     } else {
       /* We better be switching to a single pending accept. */
       assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT);
@@ -706,7 +709,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
          * All previously queued accept requests are now processed.
          * We now switch to queueing just a single accept.
          */
-        uv_tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]);
+        uv__tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]);
         server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
         server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
       }
@@ -719,7 +722,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
 }
 
 
-int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
+int uv__tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
     uv_read_cb read_cb) {
   uv_loop_t* loop = handle->loop;
 
@@ -738,7 +741,7 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
         uv_fatal_error(GetLastError(), "CreateEvent");
       }
     }
-    uv_tcp_queue_read(loop, handle);
+    uv__tcp_queue_read(loop, handle);
   }
 
   return 0;
@@ -779,7 +782,7 @@ static int uv__is_fast_loopback_fail_supported(void) {
   return os_info.dwBuildNumber >= 16299;
 }
 
-static int uv_tcp_try_connect(uv_connect_t* req,
+static int uv__tcp_try_connect(uv_connect_t* req,
                               uv_tcp_t* handle,
                               const struct sockaddr* addr,
                               unsigned int addrlen,
@@ -807,7 +810,7 @@ static int uv_tcp_try_connect(uv_connect_t* req,
     } else {
       abort();
     }
-    err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
+    err = uv__tcp_try_bind(handle, bind_addr, addrlen, 0);
     if (err)
       return err;
     if (handle->delayed_error != 0)
@@ -815,7 +818,7 @@ static int uv_tcp_try_connect(uv_connect_t* req,
   }
 
   if (!handle->tcp.conn.func_connectex) {
-    if (!uv_get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) {
+    if (!uv__get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) {
       return WSAEAFNOSUPPORT;
     }
   }
@@ -850,7 +853,7 @@ out:
     /* Process the req without IOCP. */
     handle->reqs_pending++;
     REGISTER_HANDLE_REQ(loop, handle, req);
-    uv_insert_pending_req(loop, (uv_req_t*)req);
+    uv__insert_pending_req(loop, (uv_req_t*)req);
     return 0;
   }
 
@@ -866,7 +869,7 @@ out:
     /* Process the req without IOCP. */
     handle->reqs_pending++;
     REGISTER_HANDLE_REQ(loop, handle, req);
-    uv_insert_pending_req(loop, (uv_req_t*)req);
+    uv__insert_pending_req(loop, (uv_req_t*)req);
   } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
     /* The req will be processed with IOCP. */
     handle->reqs_pending++;
@@ -903,7 +906,7 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
 }
 
 
-int uv_tcp_write(uv_loop_t* loop,
+int uv__tcp_write(uv_loop_t* loop,
                  uv_write_t* req,
                  uv_tcp_t* handle,
                  const uv_buf_t bufs[],
@@ -941,7 +944,7 @@ int uv_tcp_write(uv_loop_t* loop,
     handle->reqs_pending++;
     handle->stream.conn.write_reqs_pending++;
     REGISTER_HANDLE_REQ(loop, handle, req);
-    uv_insert_pending_req(loop, (uv_req_t*) req);
+    uv__insert_pending_req(loop, (uv_req_t*) req);
   } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
     /* Request queued by the kernel. */
     req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
@@ -954,7 +957,7 @@ int uv_tcp_write(uv_loop_t* loop,
           req->event_handle, post_write_completion, (void*) req,
           INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
       SET_REQ_ERROR(req, GetLastError());
-      uv_insert_pending_req(loop, (uv_req_t*)req);
+      uv__insert_pending_req(loop, (uv_req_t*)req);
     }
   } else {
     /* Send failed due to an error, report it later */
@@ -963,7 +966,7 @@ int uv_tcp_write(uv_loop_t* loop,
     handle->stream.conn.write_reqs_pending++;
     REGISTER_HANDLE_REQ(loop, handle, req);
     SET_REQ_ERROR(req, WSAGetLastError());
-    uv_insert_pending_req(loop, (uv_req_t*) req);
+    uv__insert_pending_req(loop, (uv_req_t*) req);
   }
 
   return 0;
@@ -994,7 +997,7 @@ int uv__tcp_try_write(uv_tcp_t* handle,
 }
 
 
-void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
+void uv__process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
     uv_req_t* req) {
   DWORD bytes, flags, err;
   uv_buf_t buf;
@@ -1115,7 +1118,7 @@ done:
     /* Post another read if still reading and not closing. */
     if ((handle->flags & UV_HANDLE_READING) &&
         !(handle->flags & UV_HANDLE_READ_PENDING)) {
-      uv_tcp_queue_read(loop, handle);
+      uv__tcp_queue_read(loop, handle);
     }
   }
 
@@ -1123,7 +1126,7 @@ done:
 }
 
 
-void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
+void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
     uv_write_t* req) {
   int err;
 
@@ -1160,16 +1163,17 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
       closesocket(handle->socket);
       handle->socket = INVALID_SOCKET;
     }
-    if (handle->stream.conn.shutdown_req != NULL) {
-      uv_want_endgame(loop, (uv_handle_t*)handle);
-    }
+    if (handle->flags & UV_HANDLE_SHUTTING)
+      uv__process_tcp_shutdown_req(loop,
+                                   handle,
+                                   handle->stream.conn.shutdown_req);
   }
 
   DECREASE_PENDING_REQ_COUNT(handle);
 }
 
 
-void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
+void uv__process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
     uv_req_t* raw_req) {
   uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req;
   int err;
@@ -1209,7 +1213,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
     closesocket(req->accept_socket);
     req->accept_socket = INVALID_SOCKET;
     if (handle->flags & UV_HANDLE_LISTENING) {
-      uv_tcp_queue_accept(handle, req);
+      uv__tcp_queue_accept(handle, req);
     }
   }
 
@@ -1217,7 +1221,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
 }
 
 
-void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
+void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
     uv_connect_t* req) {
   int err;
 
@@ -1242,7 +1246,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
                           SO_UPDATE_CONNECT_CONTEXT,
                           NULL,
                           0) == 0) {
-      uv_connection_init((uv_stream_t*)handle);
+      uv__connection_init((uv_stream_t*)handle);
       handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
       loop->active_tcp_streams++;
     } else {
@@ -1312,7 +1316,7 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp,
     return WSAGetLastError();
   }
 
-  err = uv_tcp_set_socket(
+  err = uv__tcp_set_socket(
       tcp->loop, tcp, socket, xfer_info->socket_info.iAddressFamily, 1);
   if (err) {
     closesocket(socket);
@@ -1323,7 +1327,7 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp,
   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;
   }
 
@@ -1404,14 +1408,14 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
 }
 
 
-static void uv_tcp_try_cancel_reqs(uv_tcp_t* tcp) {
+static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) {
   SOCKET socket;
   int non_ifs_lsp;
   int reading;
   int writing;
 
   socket = tcp->socket;
-  reading = tcp->flags & UV_HANDLE_READING;
+  reading = tcp->flags & UV_HANDLE_READ_PENDING;
   writing = tcp->stream.conn.write_reqs_pending > 0;
   if (!reading && !writing)
     return;
@@ -1456,12 +1460,12 @@ static void uv_tcp_try_cancel_reqs(uv_tcp_t* tcp) {
 }
 
 
-void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
+void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
   if (tcp->flags & UV_HANDLE_CONNECTION) {
-    uv_tcp_try_cancel_reqs(tcp);
     if (tcp->flags & UV_HANDLE_READING) {
       uv_read_stop((uv_stream_t*) tcp);
     }
+    uv__tcp_try_cancel_reqs(tcp);
   } else {
     if (tcp->tcp.serv.accept_reqs != NULL) {
       /* First close the incoming sockets to cancel the accept operations before
@@ -1483,6 +1487,9 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
     DECREASE_ACTIVE_COUNT(loop, tcp);
   }
 
+  tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+  uv__handle_closing(tcp);
+
   /* If any overlapped req failed to cancel, calling `closesocket` now would
    * cause Win32 to send an RST packet. Try to avoid that for writes, if
    * possibly applicable, by waiting to process the completion notifications
@@ -1494,12 +1501,8 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
     tcp->socket = INVALID_SOCKET;
   }
 
-  tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
-  uv__handle_closing(tcp);
-
-  if (tcp->reqs_pending == 0) {
-    uv_want_endgame(tcp->loop, (uv_handle_t*)tcp);
-  }
+  if (tcp->reqs_pending == 0)
+    uv__want_endgame(loop, (uv_handle_t*) tcp);
 }
 
 
@@ -1520,7 +1523,7 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
     return uv_translate_sys_error(GetLastError());
   }
 
-  err = uv_tcp_set_socket(handle->loop,
+  err = uv__tcp_set_socket(handle->loop,
                           handle,
                           sock,
                           protocol_info.iAddressFamily,
@@ -1537,7 +1540,7 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
     saddr_len = sizeof(saddr);
     if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) {
       /* Socket is already connected. */
-      uv_connection_init((uv_stream_t*) handle);
+      uv__connection_init((uv_stream_t*) handle);
       handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
     }
   }
@@ -1555,7 +1558,7 @@ int uv__tcp_bind(uv_tcp_t* handle,
                  unsigned int flags) {
   int err;
 
-  err = uv_tcp_try_bind(handle, addr, addrlen, flags);
+  err = uv__tcp_try_bind(handle, addr, addrlen, flags);
   if (err)
     return uv_translate_sys_error(err);
 
@@ -1573,7 +1576,7 @@ int uv__tcp_connect(uv_connect_t* req,
                     uv_connect_cb cb) {
   int err;
 
-  err = uv_tcp_try_connect(req, handle, addr, addrlen, cb);
+  err = uv__tcp_try_connect(req, handle, addr, addrlen, cb);
   if (err)
     return uv_translate_sys_error(err);
 
@@ -1634,7 +1637,7 @@ int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int f
     goto wsaerror;
   if (!SetHandleInformation((HANDLE) client1, HANDLE_FLAG_INHERIT, 0))
     goto error;
-  if (!uv_get_acceptex_function(server, &func_acceptex)) {
+  if (!uv__get_acceptex_function(server, &func_acceptex)) {
     err = WSAEAFNOSUPPORT;
     goto cleanup;
   }

+ 2 - 1
Utilities/cmlibuv/src/win/thread.c

@@ -182,8 +182,9 @@ int uv_thread_create_ex(uv_thread_t* tid,
 
 
 uv_thread_t uv_thread_self(void) {
+  uv_thread_t key;
   uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
-  uv_thread_t key = uv_key_get(&uv__current_thread_key);
+  key = uv_key_get(&uv__current_thread_key);
   if (key == NULL) {
       /* If the thread wasn't started by uv_thread_create (such as the main
        * thread), we assign an id to it now. */

+ 112 - 109
Utilities/cmlibuv/src/win/tty.c

@@ -67,10 +67,10 @@
 #define CURSOR_SIZE_SMALL     25
 #define CURSOR_SIZE_LARGE     100
 
-static void uv_tty_capture_initial_style(
+static void uv__tty_capture_initial_style(
     CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
     CONSOLE_CURSOR_INFO* cursor_info);
-static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
+static void uv__tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
 static int uv__cancel_read_console(uv_tty_t* handle);
 
 
@@ -163,7 +163,7 @@ static BOOL uv__need_check_vterm_state = TRUE;
 static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED;
 static void uv__determine_vterm_state(HANDLE handle);
 
-void uv_console_init(void) {
+void uv__console_init(void) {
   if (uv_sem_init(&uv_tty_output_lock, 1))
     abort();
   uv__tty_console_handle = CreateFileW(L"CONOUT$",
@@ -238,16 +238,16 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
       uv__determine_vterm_state(handle);
 
     /* Remember the original console text attributes and cursor info. */
-    uv_tty_capture_initial_style(&screen_buffer_info, &cursor_info);
+    uv__tty_capture_initial_style(&screen_buffer_info, &cursor_info);
 
-    uv_tty_update_virtual_window(&screen_buffer_info);
+    uv__tty_update_virtual_window(&screen_buffer_info);
 
     uv_sem_post(&uv_tty_output_lock);
   }
 
 
-  uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
-  uv_connection_init((uv_stream_t*) tty);
+  uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
+  uv__connection_init((uv_stream_t*) tty);
 
   tty->handle = handle;
   tty->u.fd = fd;
@@ -289,7 +289,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
 /* Set the default console text attributes based on how the console was
  * configured when libuv started.
  */
-static void uv_tty_capture_initial_style(
+static void uv__tty_capture_initial_style(
     CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
     CONSOLE_CURSOR_INFO* cursor_info) {
   static int style_captured = 0;
@@ -380,7 +380,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
     was_reading = 1;
     alloc_cb = tty->alloc_cb;
     read_cb = tty->read_cb;
-    err = uv_tty_read_stop(tty);
+    err = uv__tty_read_stop(tty);
     if (err) {
       return uv_translate_sys_error(err);
     }
@@ -404,7 +404,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
 
   /* If we just stopped reading, restart. */
   if (was_reading) {
-    err = uv_tty_read_start(tty, alloc_cb, read_cb);
+    err = uv__tty_read_start(tty, alloc_cb, read_cb);
     if (err) {
       return uv_translate_sys_error(err);
     }
@@ -422,7 +422,7 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
   }
 
   uv_sem_wait(&uv_tty_output_lock);
-  uv_tty_update_virtual_window(&info);
+  uv__tty_update_virtual_window(&info);
   uv_sem_post(&uv_tty_output_lock);
 
   *width = uv_tty_virtual_width;
@@ -452,7 +452,7 @@ static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
 }
 
 
-static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
+static void uv__tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
   uv_read_t* req;
   BOOL r;
 
@@ -475,7 +475,7 @@ static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
   if (!r) {
     handle->tty.rd.read_raw_wait = NULL;
     SET_REQ_ERROR(req, GetLastError());
-    uv_insert_pending_req(loop, (uv_req_t*)req);
+    uv__insert_pending_req(loop, (uv_req_t*)req);
   }
 
   handle->flags |= UV_HANDLE_READ_PENDING;
@@ -579,7 +579,7 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
 }
 
 
-static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
+static void uv__tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
   uv_read_t* req;
   BOOL r;
 
@@ -611,7 +611,7 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
                         WT_EXECUTELONGFUNCTION);
   if (!r) {
     SET_REQ_ERROR(req, GetLastError());
-    uv_insert_pending_req(loop, (uv_req_t*)req);
+    uv__insert_pending_req(loop, (uv_req_t*)req);
   }
 
   handle->flags |= UV_HANDLE_READ_PENDING;
@@ -619,11 +619,11 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
 }
 
 
-static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
+static void uv__tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
   if (handle->flags & UV_HANDLE_TTY_RAW) {
-    uv_tty_queue_read_raw(loop, handle);
+    uv__tty_queue_read_raw(loop, handle);
   } else {
-    uv_tty_queue_read_line(loop, handle);
+    uv__tty_queue_read_line(loop, handle);
   }
 }
 
@@ -947,7 +947,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
   /* Wait for more input events. */
   if ((handle->flags & UV_HANDLE_READING) &&
       !(handle->flags & UV_HANDLE_READ_PENDING)) {
-    uv_tty_queue_read(loop, handle);
+    uv__tty_queue_read(loop, handle);
   }
 
   DECREASE_PENDING_REQ_COUNT(handle);
@@ -992,14 +992,14 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
   /* Wait for more input events. */
   if ((handle->flags & UV_HANDLE_READING) &&
       !(handle->flags & UV_HANDLE_READ_PENDING)) {
-    uv_tty_queue_read(loop, handle);
+    uv__tty_queue_read(loop, handle);
   }
 
   DECREASE_PENDING_REQ_COUNT(handle);
 }
 
 
-void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
+void uv__process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
     uv_req_t* req) {
   assert(handle->type == UV_TTY);
   assert(handle->flags & UV_HANDLE_TTY_READABLE);
@@ -1015,7 +1015,7 @@ void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
 }
 
 
-int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
+int uv__tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
     uv_read_cb read_cb) {
   uv_loop_t* loop = handle->loop;
 
@@ -1038,20 +1038,20 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
    * Short-circuit if this could be the case. */
   if (handle->tty.rd.last_key_len > 0) {
     SET_REQ_SUCCESS(&handle->read_req);
-    uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
+    uv__insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
     /* Make sure no attempt is made to insert it again until it's handled. */
     handle->flags |= UV_HANDLE_READ_PENDING;
     handle->reqs_pending++;
     return 0;
   }
 
-  uv_tty_queue_read(loop, handle);
+  uv__tty_queue_read(loop, handle);
 
   return 0;
 }
 
 
-int uv_tty_read_stop(uv_tty_t* handle) {
+int uv__tty_read_stop(uv_tty_t* handle) {
   INPUT_RECORD record;
   DWORD written, err;
 
@@ -1137,7 +1137,7 @@ static int uv__cancel_read_console(uv_tty_t* handle) {
 }
 
 
-static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
+static void uv__tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
   uv_tty_virtual_width = info->dwSize.X;
   uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
 
@@ -1160,12 +1160,12 @@ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
 }
 
 
-static COORD uv_tty_make_real_coord(uv_tty_t* handle,
+static COORD uv__tty_make_real_coord(uv_tty_t* handle,
     CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y,
     unsigned char y_relative) {
   COORD result;
 
-  uv_tty_update_virtual_window(info);
+  uv__tty_update_virtual_window(info);
 
   /* Adjust y position */
   if (y_relative) {
@@ -1197,7 +1197,7 @@ static COORD uv_tty_make_real_coord(uv_tty_t* handle,
 }
 
 
-static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
+static int uv__tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
     DWORD* error) {
   DWORD written;
 
@@ -1218,7 +1218,7 @@ static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
 }
 
 
-static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
+static int uv__tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
     int y, unsigned char y_relative, DWORD* error) {
   CONSOLE_SCREEN_BUFFER_INFO info;
   COORD pos;
@@ -1232,7 +1232,7 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
     *error = GetLastError();
   }
 
-  pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
+  pos = uv__tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
 
   if (!SetConsoleCursorPosition(handle->handle, pos)) {
     if (GetLastError() == ERROR_INVALID_PARAMETER) {
@@ -1248,7 +1248,7 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
 }
 
 
-static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
+static int uv__tty_reset(uv_tty_t* handle, DWORD* error) {
   const COORD origin = {0, 0};
   const WORD char_attrs = uv_tty_default_text_attributes;
   CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
@@ -1300,7 +1300,7 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
 
   /* Move the virtual window up to the top. */
   uv_tty_virtual_offset = 0;
-  uv_tty_update_virtual_window(&screen_buffer_info);
+  uv__tty_update_virtual_window(&screen_buffer_info);
 
   /* Reset the cursor size and the cursor state. */
   if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) {
@@ -1312,7 +1312,7 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
 }
 
 
-static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
+static int uv__tty_clear(uv_tty_t* handle, int dir, char entire_screen,
     DWORD* error) {
   CONSOLE_SCREEN_BUFFER_INFO info;
   COORD start, end;
@@ -1341,7 +1341,7 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
     x2r = 1;
   } else {
     /* Clear to end of row. We pretend the console is 65536 characters wide,
-     * uv_tty_make_real_coord will clip it to the actual console width. */
+     * uv__tty_make_real_coord will clip it to the actual console width. */
     x2 = 0xffff;
     x2r = 0;
   }
@@ -1364,8 +1364,8 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
     return -1;
   }
 
-  start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
-  end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
+  start = uv__tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
+  end = uv__tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
   count = (end.Y * info.dwSize.X + end.X) -
           (start.Y * info.dwSize.X + start.X) + 1;
 
@@ -1400,7 +1400,7 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
       info.wAttributes |= bg >> 4;                                            \
     } while (0)
 
-static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
+static int uv__tty_set_style(uv_tty_t* handle, DWORD* error) {
   unsigned short argc = handle->tty.wr.ansi_csi_argc;
   unsigned short* argv = handle->tty.wr.ansi_csi_argv;
   int i;
@@ -1556,7 +1556,7 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
 }
 
 
-static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
+static int uv__tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
     DWORD* error) {
   CONSOLE_SCREEN_BUFFER_INFO info;
 
@@ -1569,10 +1569,11 @@ static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
     return -1;
   }
 
-  uv_tty_update_virtual_window(&info);
+  uv__tty_update_virtual_window(&info);
 
   handle->tty.wr.saved_position.X = info.dwCursorPosition.X;
-  handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
+  handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y -
+        uv_tty_virtual_offset;
   handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
 
   if (save_attributes) {
@@ -1585,7 +1586,7 @@ static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
 }
 
 
-static int uv_tty_restore_state(uv_tty_t* handle,
+static int uv__tty_restore_state(uv_tty_t* handle,
     unsigned char restore_attributes, DWORD* error) {
   CONSOLE_SCREEN_BUFFER_INFO info;
   WORD new_attributes;
@@ -1595,7 +1596,7 @@ static int uv_tty_restore_state(uv_tty_t* handle,
   }
 
   if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
-    if (uv_tty_move_caret(handle,
+    if (uv__tty_move_caret(handle,
                           handle->tty.wr.saved_position.X,
                           0,
                           handle->tty.wr.saved_position.Y,
@@ -1625,7 +1626,7 @@ static int uv_tty_restore_state(uv_tty_t* handle,
   return 0;
 }
 
-static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
+static int uv__tty_set_cursor_visibility(uv_tty_t* handle,
                                         BOOL visible,
                                         DWORD* error) {
   CONSOLE_CURSOR_INFO cursor_info;
@@ -1645,7 +1646,7 @@ static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
   return 0;
 }
 
-static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) {
+static int uv__tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) {
   CONSOLE_CURSOR_INFO cursor_info;
 
   if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
@@ -1670,7 +1671,7 @@ static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) {
 }
 
 
-static int uv_tty_write_bufs(uv_tty_t* handle,
+static int uv__tty_write_bufs(uv_tty_t* handle,
                              const uv_buf_t bufs[],
                              unsigned int nbufs,
                              DWORD* error) {
@@ -1683,7 +1684,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
 #define FLUSH_TEXT()                                                \
   do {                                                              \
     if (utf16_buf_used > 0) {                                       \
-      uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error);   \
+      uv__tty_emit_text(handle, utf16_buf, utf16_buf_used, error);  \
       utf16_buf_used = 0;                                           \
     }                                                               \
   } while (0)
@@ -1802,21 +1803,21 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
           case 'c':
             /* Full console reset. */
             FLUSH_TEXT();
-            uv_tty_reset(handle, error);
+            uv__tty_reset(handle, error);
             ansi_parser_state = ANSI_NORMAL;
             continue;
 
           case '7':
             /* Save the cursor position and text attributes. */
             FLUSH_TEXT();
-            uv_tty_save_state(handle, 1, error);
+            uv__tty_save_state(handle, 1, error);
             ansi_parser_state = ANSI_NORMAL;
             continue;
 
           case '8':
             /* Restore the cursor position and text attributes */
             FLUSH_TEXT();
-            uv_tty_restore_state(handle, 1, error);
+            uv__tty_restore_state(handle, 1, error);
             ansi_parser_state = ANSI_NORMAL;
             continue;
 
@@ -1849,7 +1850,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
               ? handle->tty.wr.ansi_csi_argv[0] : 1;
             if (style >= 0 && style <= 6) {
               FLUSH_TEXT();
-              uv_tty_set_cursor_shape(handle, style, error);
+              uv__tty_set_cursor_shape(handle, style, error);
             }
           }
 
@@ -1947,7 +1948,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 if (handle->tty.wr.ansi_csi_argc == 1 &&
                     handle->tty.wr.ansi_csi_argv[0] == 25) {
                   FLUSH_TEXT();
-                  uv_tty_set_cursor_visibility(handle, 0, error);
+                  uv__tty_set_cursor_visibility(handle, 0, error);
                 }
                 break;
 
@@ -1956,7 +1957,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 if (handle->tty.wr.ansi_csi_argc == 1 &&
                     handle->tty.wr.ansi_csi_argv[0] == 25) {
                   FLUSH_TEXT();
-                  uv_tty_set_cursor_visibility(handle, 1, error);
+                  uv__tty_set_cursor_visibility(handle, 1, error);
                 }
                 break;
             }
@@ -1970,7 +1971,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 FLUSH_TEXT();
                 y = -(handle->tty.wr.ansi_csi_argc
                   ? handle->tty.wr.ansi_csi_argv[0] : 1);
-                uv_tty_move_caret(handle, 0, 1, y, 1, error);
+                uv__tty_move_caret(handle, 0, 1, y, 1, error);
                 break;
 
               case 'B':
@@ -1978,7 +1979,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 FLUSH_TEXT();
                 y = handle->tty.wr.ansi_csi_argc
                   ? handle->tty.wr.ansi_csi_argv[0] : 1;
-                uv_tty_move_caret(handle, 0, 1, y, 1, error);
+                uv__tty_move_caret(handle, 0, 1, y, 1, error);
                 break;
 
               case 'C':
@@ -1986,7 +1987,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 FLUSH_TEXT();
                 x = handle->tty.wr.ansi_csi_argc
                   ? handle->tty.wr.ansi_csi_argv[0] : 1;
-                uv_tty_move_caret(handle, x, 1, 0, 1, error);
+                uv__tty_move_caret(handle, x, 1, 0, 1, error);
                 break;
 
               case 'D':
@@ -1994,7 +1995,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 FLUSH_TEXT();
                 x = -(handle->tty.wr.ansi_csi_argc
                   ? handle->tty.wr.ansi_csi_argv[0] : 1);
-                uv_tty_move_caret(handle, x, 1, 0, 1, error);
+                uv__tty_move_caret(handle, x, 1, 0, 1, error);
                 break;
 
               case 'E':
@@ -2002,7 +2003,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 FLUSH_TEXT();
                 y = handle->tty.wr.ansi_csi_argc
                   ? handle->tty.wr.ansi_csi_argv[0] : 1;
-                uv_tty_move_caret(handle, 0, 0, y, 1, error);
+                uv__tty_move_caret(handle, 0, 0, y, 1, error);
                 break;
 
               case 'F':
@@ -2010,7 +2011,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 FLUSH_TEXT();
                 y = -(handle->tty.wr.ansi_csi_argc
                   ? handle->tty.wr.ansi_csi_argv[0] : 1);
-                uv_tty_move_caret(handle, 0, 0, y, 1, error);
+                uv__tty_move_caret(handle, 0, 0, y, 1, error);
                 break;
 
               case 'G':
@@ -2019,7 +2020,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 x = (handle->tty.wr.ansi_csi_argc >= 1 &&
                      handle->tty.wr.ansi_csi_argv[0])
                   ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
-                uv_tty_move_caret(handle, x, 0, 0, 1, error);
+                uv__tty_move_caret(handle, x, 0, 0, 1, error);
                 break;
 
               case 'H':
@@ -2032,7 +2033,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 x = (handle->tty.wr.ansi_csi_argc >= 2 &&
                      handle->tty.wr.ansi_csi_argv[1])
                   ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
-                uv_tty_move_caret(handle, x, 0, y, 0, error);
+                uv__tty_move_caret(handle, x, 0, y, 0, error);
                 break;
 
               case 'J':
@@ -2041,7 +2042,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 d = handle->tty.wr.ansi_csi_argc
                   ? handle->tty.wr.ansi_csi_argv[0] : 0;
                 if (d >= 0 && d <= 2) {
-                  uv_tty_clear(handle, d, 1, error);
+                  uv__tty_clear(handle, d, 1, error);
                 }
                 break;
 
@@ -2051,26 +2052,26 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                 d = handle->tty.wr.ansi_csi_argc
                   ? handle->tty.wr.ansi_csi_argv[0] : 0;
                 if (d >= 0 && d <= 2) {
-                  uv_tty_clear(handle, d, 0, error);
+                  uv__tty_clear(handle, d, 0, error);
                 }
                 break;
 
               case 'm':
                 /* Set style */
                 FLUSH_TEXT();
-                uv_tty_set_style(handle, error);
+                uv__tty_set_style(handle, error);
                 break;
 
               case 's':
                 /* Save the cursor position. */
                 FLUSH_TEXT();
-                uv_tty_save_state(handle, 0, error);
+                uv__tty_save_state(handle, 0, error);
                 break;
 
               case 'u':
                 /* Restore the cursor position */
                 FLUSH_TEXT();
-                uv_tty_restore_state(handle, 0, error);
+                uv__tty_restore_state(handle, 0, error);
                 break;
             }
           }
@@ -2179,7 +2180,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
 }
 
 
-int uv_tty_write(uv_loop_t* loop,
+int uv__tty_write(uv_loop_t* loop,
                  uv_write_t* req,
                  uv_tty_t* handle,
                  const uv_buf_t bufs[],
@@ -2197,13 +2198,13 @@ int uv_tty_write(uv_loop_t* loop,
 
   req->u.io.queued_bytes = 0;
 
-  if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) {
+  if (!uv__tty_write_bufs(handle, bufs, nbufs, &error)) {
     SET_REQ_SUCCESS(req);
   } else {
     SET_REQ_ERROR(req, error);
   }
 
-  uv_insert_pending_req(loop, (uv_req_t*) req);
+  uv__insert_pending_req(loop, (uv_req_t*) req);
 
   return 0;
 }
@@ -2217,14 +2218,14 @@ int uv__tty_try_write(uv_tty_t* handle,
   if (handle->stream.conn.write_reqs_pending > 0)
     return UV_EAGAIN;
 
-  if (uv_tty_write_bufs(handle, bufs, nbufs, &error))
+  if (uv__tty_write_bufs(handle, bufs, nbufs, &error))
     return uv_translate_sys_error(error);
 
   return uv__count_bufs(bufs, nbufs);
 }
 
 
-void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
+void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
   uv_write_t* req) {
   int err;
 
@@ -2236,20 +2237,22 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
     req->cb(req, uv_translate_sys_error(err));
   }
 
+
   handle->stream.conn.write_reqs_pending--;
-  if (handle->stream.conn.shutdown_req != NULL &&
-      handle->stream.conn.write_reqs_pending == 0) {
-    uv_want_endgame(loop, (uv_handle_t*)handle);
-  }
+  if (handle->stream.conn.write_reqs_pending == 0)
+    if (handle->flags & UV_HANDLE_SHUTTING)
+      uv__process_tty_shutdown_req(loop,
+                                   handle,
+                                   handle->stream.conn.shutdown_req);
 
   DECREASE_PENDING_REQ_COUNT(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);
   if (handle->flags & UV_HANDLE_READING)
-    uv_tty_read_stop(handle);
+    uv__tty_read_stop(handle);
 
   if (handle->u.fd == -1)
     CloseHandle(handle->handle);
@@ -2261,61 +2264,61 @@ void uv_tty_close(uv_tty_t* handle) {
   handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
   uv__handle_closing(handle);
 
-  if (handle->reqs_pending == 0) {
-    uv_want_endgame(handle->loop, (uv_handle_t*) handle);
-  }
+  if (handle->reqs_pending == 0)
+    uv__want_endgame(handle->loop, (uv_handle_t*) handle);
 }
 
 
-void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
-  if (!(handle->flags & UV_HANDLE_TTY_READABLE) &&
-      handle->stream.conn.shutdown_req != NULL &&
-      handle->stream.conn.write_reqs_pending == 0) {
-    UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
+void uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown_t* req) {
+  assert(stream->stream.conn.write_reqs_pending == 0);
+  assert(req);
 
-    /* TTY shutdown is really just a no-op */
-    if (handle->stream.conn.shutdown_req->cb) {
-      if (handle->flags & UV_HANDLE_CLOSING) {
-        handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
-      } else {
-        handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
-      }
+  stream->stream.conn.shutdown_req = NULL;
+  stream->flags &= ~UV_HANDLE_SHUTTING;
+  UNREGISTER_HANDLE_REQ(loop, stream, req);
+
+  /* TTY shutdown is really just a no-op */
+  if (req->cb) {
+    if (stream->flags & UV_HANDLE_CLOSING) {
+      req->cb(req, UV_ECANCELED);
+    } else {
+      req->cb(req, 0);
     }
+  }
 
-    handle->stream.conn.shutdown_req = NULL;
+  DECREASE_PENDING_REQ_COUNT(stream);
+}
 
-    DECREASE_PENDING_REQ_COUNT(handle);
-    return;
-  }
 
-  if (handle->flags & UV_HANDLE_CLOSING &&
-      handle->reqs_pending == 0) {
-    /* The wait handle used for raw reading should be unregistered when the
-     * wait callback runs. */
-    assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
-           handle->tty.rd.read_raw_wait == NULL);
+void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
+  assert(handle->flags & UV_HANDLE_CLOSING);
+  assert(handle->reqs_pending == 0);
 
-    assert(!(handle->flags & UV_HANDLE_CLOSED));
-    uv__handle_close(handle);
-  }
+  /* The wait handle used for raw reading should be unregistered when the
+   * wait callback runs. */
+  assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
+         handle->tty.rd.read_raw_wait == NULL);
+
+  assert(!(handle->flags & UV_HANDLE_CLOSED));
+  uv__handle_close(handle);
 }
 
 
 /*
- * uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
+ * uv__process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
  * TODO: find a way to remove it
  */
-void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
+void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
     uv_req_t* raw_req) {
   abort();
 }
 
 
 /*
- * uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
+ * uv__process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
  * TODO: find a way to remove it
  */
-void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
+void uv__process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
     uv_connect_t* req) {
   abort();
 }

+ 52 - 51
Utilities/cmlibuv/src/win/udp.c

@@ -60,7 +60,7 @@ int uv_udp_getsockname(const uv_udp_t* handle,
 }
 
 
-static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
+static int uv__udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
     int family) {
   DWORD yes = 1;
   WSAPROTOCOL_INFOW info;
@@ -106,8 +106,8 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET 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;
+      handle->func_wsarecv = uv__wsarecv_workaround;
+      handle->func_wsarecvfrom = uv__wsarecvfrom_workaround;
     } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
       return GetLastError();
     }
@@ -155,7 +155,7 @@ int uv__udp_init_ex(uv_loop_t* loop,
       return uv_translate_sys_error(err);
     }
 
-    err = uv_udp_set_socket(handle->loop, handle, sock, domain);
+    err = uv__udp_set_socket(handle->loop, handle, sock, domain);
     if (err) {
       closesocket(sock);
       QUEUE_REMOVE(&handle->handle_queue);
@@ -167,7 +167,7 @@ int uv__udp_init_ex(uv_loop_t* loop,
 }
 
 
-void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
+void uv__udp_close(uv_loop_t* loop, uv_udp_t* handle) {
   uv_udp_recv_stop(handle);
   closesocket(handle->socket);
   handle->socket = INVALID_SOCKET;
@@ -175,12 +175,12 @@ void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
   uv__handle_closing(handle);
 
   if (handle->reqs_pending == 0) {
-    uv_want_endgame(loop, (uv_handle_t*) handle);
+    uv__want_endgame(loop, (uv_handle_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 &&
       handle->reqs_pending == 0) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
@@ -194,10 +194,10 @@ int uv_udp_using_recvmmsg(const uv_udp_t* handle) {
 }
 
 
-static int uv_udp_maybe_bind(uv_udp_t* handle,
-                             const struct sockaddr* addr,
-                             unsigned int addrlen,
-                             unsigned int flags) {
+static int uv__udp_maybe_bind(uv_udp_t* handle,
+                              const struct sockaddr* addr,
+                              unsigned int addrlen,
+                              unsigned int flags) {
   int r;
   int err;
   DWORD no = 0;
@@ -216,7 +216,7 @@ static int uv_udp_maybe_bind(uv_udp_t* handle,
       return WSAGetLastError();
     }
 
-    err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family);
+    err = uv__udp_set_socket(handle->loop, handle, sock, addr->sa_family);
     if (err) {
       closesocket(sock);
       return err;
@@ -264,7 +264,7 @@ static int uv_udp_maybe_bind(uv_udp_t* handle,
 }
 
 
-static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
+static void uv__udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
   uv_req_t* req;
   uv_buf_t buf;
   DWORD bytes, flags;
@@ -311,7 +311,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
       handle->flags |= UV_HANDLE_READ_PENDING;
       req->u.io.overlapped.InternalHigh = bytes;
       handle->reqs_pending++;
-      uv_insert_pending_req(loop, req);
+      uv__insert_pending_req(loop, req);
     } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
       /* The req will be processed with IOCP. */
       handle->flags |= UV_HANDLE_READ_PENDING;
@@ -319,7 +319,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
     } else {
       /* Make this req pending reporting an error. */
       SET_REQ_ERROR(req, WSAGetLastError());
-      uv_insert_pending_req(loop, req);
+      uv__insert_pending_req(loop, req);
       handle->reqs_pending++;
     }
 
@@ -343,7 +343,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
       handle->flags |= UV_HANDLE_READ_PENDING;
       req->u.io.overlapped.InternalHigh = bytes;
       handle->reqs_pending++;
-      uv_insert_pending_req(loop, req);
+      uv__insert_pending_req(loop, req);
     } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
       /* The req will be processed with IOCP. */
       handle->flags |= UV_HANDLE_READ_PENDING;
@@ -351,7 +351,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
     } else {
       /* Make this req pending reporting an error. */
       SET_REQ_ERROR(req, WSAGetLastError());
-      uv_insert_pending_req(loop, req);
+      uv__insert_pending_req(loop, req);
       handle->reqs_pending++;
     }
   }
@@ -367,10 +367,10 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
     return UV_EALREADY;
   }
 
-  err = uv_udp_maybe_bind(handle,
-                          (const struct sockaddr*) &uv_addr_ip4_any_,
-                          sizeof(uv_addr_ip4_any_),
-                          0);
+  err = uv__udp_maybe_bind(handle,
+                           (const struct sockaddr*) &uv_addr_ip4_any_,
+                           sizeof(uv_addr_ip4_any_),
+                           0);
   if (err)
     return uv_translate_sys_error(err);
 
@@ -384,7 +384,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
   /* If reading was stopped and then started again, there could still be a recv
    * request pending. */
   if (!(handle->flags & UV_HANDLE_READ_PENDING))
-    uv_udp_queue_recv(loop, handle);
+    uv__udp_queue_recv(loop, handle);
 
   return 0;
 }
@@ -433,7 +433,7 @@ static int uv__send(uv_udp_send_t* req,
     handle->send_queue_size += req->u.io.queued_bytes;
     handle->send_queue_count++;
     REGISTER_HANDLE_REQ(loop, handle, req);
-    uv_insert_pending_req(loop, (uv_req_t*)req);
+    uv__insert_pending_req(loop, (uv_req_t*)req);
   } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
     /* Request queued by the kernel. */
     req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
@@ -450,7 +450,7 @@ static int uv__send(uv_udp_send_t* req,
 }
 
 
-void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
+void uv__process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
     uv_req_t* req) {
   uv_buf_t buf;
   int partial;
@@ -554,14 +554,14 @@ done:
   /* Post another read if still reading and not closing. */
   if ((handle->flags & UV_HANDLE_READING) &&
       !(handle->flags & UV_HANDLE_READ_PENDING)) {
-    uv_udp_queue_recv(loop, handle);
+    uv__udp_queue_recv(loop, handle);
   }
 
   DECREASE_PENDING_REQ_COUNT(handle);
 }
 
 
-void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
+void uv__process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
     uv_udp_send_t* req) {
   int err;
 
@@ -598,10 +598,10 @@ static int uv__udp_set_membership4(uv_udp_t* handle,
     return UV_EINVAL;
 
   /* If the socket is unbound, bind to inaddr_any. */
-  err = uv_udp_maybe_bind(handle,
-                          (const struct sockaddr*) &uv_addr_ip4_any_,
-                          sizeof(uv_addr_ip4_any_),
-                          UV_UDP_REUSEADDR);
+  err = uv__udp_maybe_bind(handle,
+                           (const struct sockaddr*) &uv_addr_ip4_any_,
+                           sizeof(uv_addr_ip4_any_),
+                           UV_UDP_REUSEADDR);
   if (err)
     return uv_translate_sys_error(err);
 
@@ -652,10 +652,10 @@ int uv__udp_set_membership6(uv_udp_t* handle,
   if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
     return UV_EINVAL;
 
-  err = uv_udp_maybe_bind(handle,
-                          (const struct sockaddr*) &uv_addr_ip6_any_,
-                          sizeof(uv_addr_ip6_any_),
-                          UV_UDP_REUSEADDR);
+  err = uv__udp_maybe_bind(handle,
+                           (const struct sockaddr*) &uv_addr_ip6_any_,
+                           sizeof(uv_addr_ip6_any_),
+                           UV_UDP_REUSEADDR);
 
   if (err)
     return uv_translate_sys_error(err);
@@ -708,10 +708,10 @@ static int uv__udp_set_source_membership4(uv_udp_t* handle,
     return UV_EINVAL;
 
   /* If the socket is unbound, bind to inaddr_any. */
-  err = uv_udp_maybe_bind(handle,
-                          (const struct sockaddr*) &uv_addr_ip4_any_,
-                          sizeof(uv_addr_ip4_any_),
-                          UV_UDP_REUSEADDR);
+  err = uv__udp_maybe_bind(handle,
+                           (const struct sockaddr*) &uv_addr_ip4_any_,
+                           sizeof(uv_addr_ip4_any_),
+                           UV_UDP_REUSEADDR);
   if (err)
     return uv_translate_sys_error(err);
 
@@ -763,10 +763,10 @@ int uv__udp_set_source_membership6(uv_udp_t* handle,
   if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
     return UV_EINVAL;
 
-  err = uv_udp_maybe_bind(handle,
-                          (const struct sockaddr*) &uv_addr_ip6_any_,
-                          sizeof(uv_addr_ip6_any_),
-                          UV_UDP_REUSEADDR);
+  err = uv__udp_maybe_bind(handle,
+                           (const struct sockaddr*) &uv_addr_ip6_any_,
+                           sizeof(uv_addr_ip6_any_),
+                           UV_UDP_REUSEADDR);
 
   if (err)
     return uv_translate_sys_error(err);
@@ -962,10 +962,10 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
     return uv_translate_sys_error(GetLastError());
   }
 
-  err = uv_udp_set_socket(handle->loop,
-                          handle,
-                          sock,
-                          protocol_info.iAddressFamily);
+  err = uv__udp_set_socket(handle->loop,
+                           handle,
+                           sock,
+                           protocol_info.iAddressFamily);
   if (err)
     return uv_translate_sys_error(err);
 
@@ -1044,7 +1044,7 @@ int uv__udp_bind(uv_udp_t* handle,
                  unsigned int flags) {
   int err;
 
-  err = uv_udp_maybe_bind(handle, addr, addrlen, flags);
+  err = uv__udp_maybe_bind(handle, addr, addrlen, flags);
   if (err)
     return uv_translate_sys_error(err);
 
@@ -1066,7 +1066,7 @@ int uv__udp_connect(uv_udp_t* handle,
     else
       return UV_EINVAL;
 
-    err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
+    err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0);
     if (err)
       return uv_translate_sys_error(err);
   }
@@ -1117,7 +1117,7 @@ int uv__udp_send(uv_udp_send_t* req,
     else
       return UV_EINVAL;
 
-    err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
+    err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0);
     if (err)
       return uv_translate_sys_error(err);
   }
@@ -1146,6 +1146,7 @@ int uv__udp_try_send(uv_udp_t* handle,
     err = uv__convert_to_localhost_if_unspecified(addr, &converted);
     if (err)
       return err;
+    addr = (const struct sockaddr*) &converted;
   }
 
   /* Already sending a message.*/
@@ -1159,7 +1160,7 @@ int uv__udp_try_send(uv_udp_t* handle,
       bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
     else
       return UV_EINVAL;
-    err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
+    err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0);
     if (err)
       return uv_translate_sys_error(err);
   }
@@ -1169,7 +1170,7 @@ int uv__udp_try_send(uv_udp_t* handle,
                   nbufs,
                   &bytes,
                   0,
-                  (const struct sockaddr*) &converted,
+                  addr,
                   addrlen,
                   NULL,
                   NULL);

+ 14 - 92
Utilities/cmlibuv/src/win/util.c

@@ -531,103 +531,25 @@ int uv_resident_set_memory(size_t* rss) {
 
 
 int uv_uptime(double* uptime) {
-  BYTE stack_buffer[4096];
-  BYTE* malloced_buffer = NULL;
-  BYTE* buffer = (BYTE*) stack_buffer;
-  size_t buffer_size = sizeof(stack_buffer);
-  DWORD data_size;
-
-  PERF_DATA_BLOCK* data_block;
-  PERF_OBJECT_TYPE* object_type;
-  PERF_COUNTER_DEFINITION* counter_definition;
-
-  DWORD i;
-
-  for (;;) {
-    LONG result;
-
-    data_size = (DWORD) buffer_size;
-    result = RegQueryValueExW(HKEY_PERFORMANCE_DATA,
-                              L"2",
-                              NULL,
-                              NULL,
-                              buffer,
-                              &data_size);
-    if (result == ERROR_SUCCESS) {
-      break;
-    } else if (result != ERROR_MORE_DATA) {
-      *uptime = 0;
-      return uv_translate_sys_error(result);
-    }
-
-    buffer_size *= 2;
-    /* Don't let the buffer grow infinitely. */
-    if (buffer_size > 1 << 20) {
-      goto internalError;
-    }
-
-    uv__free(malloced_buffer);
-
-    buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size);
-    if (malloced_buffer == NULL) {
-      *uptime = 0;
-      return UV_ENOMEM;
-    }
-  }
-
-  if (data_size < sizeof(*data_block))
-    goto internalError;
-
-  data_block = (PERF_DATA_BLOCK*) buffer;
-
-  if (wmemcmp(data_block->Signature, L"PERF", 4) != 0)
-    goto internalError;
-
-  if (data_size < data_block->HeaderLength + sizeof(*object_type))
-    goto internalError;
-
-  object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength);
-
-  if (object_type->NumInstances != PERF_NO_INSTANCES)
-    goto internalError;
+  *uptime = GetTickCount64() / 1000.0;
+  return 0;
+}
 
-  counter_definition = (PERF_COUNTER_DEFINITION*) (buffer +
-      data_block->HeaderLength + object_type->HeaderLength);
-  for (i = 0; i < object_type->NumCounters; i++) {
-    if ((BYTE*) counter_definition + sizeof(*counter_definition) >
-        buffer + data_size) {
-      break;
-    }
 
-    if (counter_definition->CounterNameTitleIndex == 674 &&
-        counter_definition->CounterSize == sizeof(uint64_t)) {
-      if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size ||
-          !(counter_definition->CounterType & PERF_OBJECT_TIMER)) {
-        goto internalError;
-      } else {
-        BYTE* address = (BYTE*) object_type + object_type->DefinitionLength +
-                        counter_definition->CounterOffset;
-        uint64_t value = *((uint64_t*) address);
-        *uptime = floor((double) (object_type->PerfTime.QuadPart - value) /
-                        (double) object_type->PerfFreq.QuadPart);
-        uv__free(malloced_buffer);
-        return 0;
-      }
-    }
+unsigned int uv_available_parallelism(void) {
+  SYSTEM_INFO info;
+  unsigned rc;
 
-    counter_definition = (PERF_COUNTER_DEFINITION*)
-        ((BYTE*) counter_definition + counter_definition->ByteLength);
-  }
+  /* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems
+   * with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458
+   */
+  GetSystemInfo(&info);
 
-  /* If we get here, the uptime value was not found. */
-  uv__free(malloced_buffer);
-  *uptime = 0;
-  return UV_ENOSYS;
+  rc = info.dwNumberOfProcessors;
+  if (rc < 1)
+    rc = 1;
 
- internalError:
-  uv__free(malloced_buffer);
-  *uptime = 0;
-  return UV_EIO;
+  return rc;
 }
 
 

+ 4 - 4
Utilities/cmlibuv/src/win/winapi.c

@@ -48,7 +48,7 @@ sSetWinEventHook pSetWinEventHook;
 /* ws2_32.dll function pointer */
 uv_sGetHostNameW pGetHostNameW;
 
-void uv_winapi_init(void) {
+void uv__winapi_init(void) {
   HMODULE ntdll_module;
   HMODULE powrprof_module;
   HMODULE user32_module;
@@ -126,19 +126,19 @@ void uv_winapi_init(void) {
       kernel32_module,
       "GetQueuedCompletionStatusEx");
 
-  powrprof_module = LoadLibraryA("powrprof.dll");
+  powrprof_module = LoadLibraryExA("powrprof.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
   if (powrprof_module != NULL) {
     pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
       GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
   }
 
-  user32_module = LoadLibraryA("user32.dll");
+  user32_module = GetModuleHandleA("user32.dll");
   if (user32_module != NULL) {
     pSetWinEventHook = (sSetWinEventHook)
       GetProcAddress(user32_module, "SetWinEventHook");
   }
 
-  ws2_32_module = LoadLibraryA("ws2_32.dll");
+  ws2_32_module = GetModuleHandleA("ws2_32.dll");
   if (ws2_32_module != NULL) {
     pGetHostNameW = (uv_sGetHostNameW) GetProcAddress(
         ws2_32_module,

+ 14 - 14
Utilities/cmlibuv/src/win/winsock.c

@@ -38,7 +38,7 @@ struct sockaddr_in6 uv_addr_ip6_any_;
 /*
  * Retrieves the pointer to a winsock extension function.
  */
-static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
+static BOOL uv__get_extension_function(SOCKET socket, GUID guid,
     void **target) {
   int result;
   DWORD bytes;
@@ -62,20 +62,20 @@ static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
 }
 
 
-BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
+BOOL uv__get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
   const GUID wsaid_acceptex = WSAID_ACCEPTEX;
-  return uv_get_extension_function(socket, wsaid_acceptex, (void**)target);
+  return uv__get_extension_function(socket, wsaid_acceptex, (void**)target);
 }
 
 
-BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
+BOOL uv__get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
   const GUID wsaid_connectex = WSAID_CONNECTEX;
-  return uv_get_extension_function(socket, wsaid_connectex, (void**)target);
+  return uv__get_extension_function(socket, wsaid_connectex, (void**)target);
 }
 
 
 
-void uv_winsock_init(void) {
+void uv__winsock_init(void) {
   WSADATA wsa_data;
   int errorno;
   SOCKET dummy;
@@ -134,7 +134,7 @@ void uv_winsock_init(void) {
 }
 
 
-int uv_ntstatus_to_winsock_error(NTSTATUS status) {
+int uv__ntstatus_to_winsock_error(NTSTATUS status) {
   switch (status) {
     case STATUS_SUCCESS:
       return ERROR_SUCCESS;
@@ -267,7 +267,7 @@ int uv_ntstatus_to_winsock_error(NTSTATUS status) {
  * the user to use the default msafd driver, doesn't work when other LSPs are
  * stacked on top of it.
  */
-int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
+int WSAAPI uv__wsarecv_workaround(SOCKET socket, WSABUF* buffers,
     DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
     LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
   NTSTATUS status;
@@ -346,7 +346,7 @@ int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
       break;
 
     default:
-      error = uv_ntstatus_to_winsock_error(status);
+      error = uv__ntstatus_to_winsock_error(status);
       break;
   }
 
@@ -360,8 +360,8 @@ int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
 }
 
 
-/* See description of uv_wsarecv_workaround. */
-int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
+/* See description of uv__wsarecv_workaround. */
+int WSAAPI uv__wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
     DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
     int* addr_len, WSAOVERLAPPED *overlapped,
     LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
@@ -444,7 +444,7 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
       break;
 
     default:
-      error = uv_ntstatus_to_winsock_error(status);
+      error = uv__ntstatus_to_winsock_error(status);
       break;
   }
 
@@ -458,7 +458,7 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
 }
 
 
-int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
+int WSAAPI uv__msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
     AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
   IO_STATUS_BLOCK iosb;
   IO_STATUS_BLOCK* iosb_ptr;
@@ -531,7 +531,7 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
       break;
 
     default:
-      error = uv_ntstatus_to_winsock_error(status);
+      error = uv__ntstatus_to_winsock_error(status);
       break;
   }
 

+ 3 - 0
bootstrap

@@ -593,6 +593,7 @@ if ${cmake_system_mingw}; then
     src/inet.c \
     src/threadpool.c \
     src/strscpy.c \
+    src/strtok.c \
     src/timer.c \
     src/uv-common.c \
     src/win/async.c \
@@ -623,6 +624,7 @@ if ${cmake_system_mingw}; then
 else
   LIBUV_C_SOURCES="\
     src/strscpy.c \
+    src/strtok.c \
     src/timer.c \
     src/uv-common.c \
     src/unix/cmake-bootstrap.c \
@@ -639,6 +641,7 @@ else
     src/unix/signal.c \
     src/unix/stream.c \
     src/unix/tcp.c \
+    src/unix/tty.c \
     "
 fi
 

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