瀏覽代碼

Merge branch 'upstream-libuv' into update-libuv

* upstream-libuv:
  libuv 2018-01-19 (63de1eca)
Brad King 7 年之前
父節點
當前提交
b58d48c15f
共有 61 個文件被更改,包括 2792 次插入978 次删除
  1. 2 2
      Utilities/cmlibuv/LICENSE
  2. 1 0
      Utilities/cmlibuv/include/pthread-barrier.h
  3. 12 0
      Utilities/cmlibuv/include/uv-errno.h
  4. 3 0
      Utilities/cmlibuv/include/uv-os390.h
  5. 96 0
      Utilities/cmlibuv/include/uv-unix.h
  6. 1 1
      Utilities/cmlibuv/include/uv-version.h
  7. 27 1
      Utilities/cmlibuv/include/uv-win.h
  8. 61 2
      Utilities/cmlibuv/include/uv.h
  9. 12 6
      Utilities/cmlibuv/src/threadpool.c
  10. 292 0
      Utilities/cmlibuv/src/unix/aix-common.c
  11. 20 222
      Utilities/cmlibuv/src/unix/aix.c
  12. 28 21
      Utilities/cmlibuv/src/unix/android-ifaddrs.c
  13. 4 1
      Utilities/cmlibuv/src/unix/atomic-ops.h
  14. 18 5
      Utilities/cmlibuv/src/unix/bsd-ifaddrs.c
  15. 37 8
      Utilities/cmlibuv/src/unix/core.c
  16. 58 29
      Utilities/cmlibuv/src/unix/freebsd.c
  17. 165 12
      Utilities/cmlibuv/src/unix/fs.c
  18. 23 5
      Utilities/cmlibuv/src/unix/fsevents.c
  19. 30 0
      Utilities/cmlibuv/src/unix/getaddrinfo.c
  20. 112 0
      Utilities/cmlibuv/src/unix/ibmi.c
  21. 14 1
      Utilities/cmlibuv/src/unix/internal.h
  22. 37 1
      Utilities/cmlibuv/src/unix/kqueue.c
  23. 7 7
      Utilities/cmlibuv/src/unix/linux-core.c
  24. 1 1
      Utilities/cmlibuv/src/unix/loop.c
  25. 47 10
      Utilities/cmlibuv/src/unix/netbsd.c
  26. 31 2
      Utilities/cmlibuv/src/unix/openbsd.c
  27. 197 32
      Utilities/cmlibuv/src/unix/os390-syscalls.c
  28. 3 0
      Utilities/cmlibuv/src/unix/os390-syscalls.h
  29. 162 13
      Utilities/cmlibuv/src/unix/os390.c
  30. 53 0
      Utilities/cmlibuv/src/unix/pipe.c
  31. 21 4
      Utilities/cmlibuv/src/unix/poll.c
  32. 39 3
      Utilities/cmlibuv/src/unix/process.c
  33. 28 7
      Utilities/cmlibuv/src/unix/proctitle.c
  34. 0 121
      Utilities/cmlibuv/src/unix/pthread-barrier.c
  35. 26 13
      Utilities/cmlibuv/src/unix/stream.c
  36. 2 2
      Utilities/cmlibuv/src/unix/sunos.c
  37. 75 26
      Utilities/cmlibuv/src/unix/tcp.c
  38. 171 26
      Utilities/cmlibuv/src/unix/thread.c
  39. 36 0
      Utilities/cmlibuv/src/unix/tty.c
  40. 5 3
      Utilities/cmlibuv/src/unix/udp.c
  41. 96 0
      Utilities/cmlibuv/src/uv-data-getter-setters.c
  42. 35 20
      Utilities/cmlibuv/src/win/dl.c
  43. 1 1
      Utilities/cmlibuv/src/win/error.c
  44. 249 284
      Utilities/cmlibuv/src/win/fs.c
  45. 71 0
      Utilities/cmlibuv/src/win/getaddrinfo.c
  46. 5 0
      Utilities/cmlibuv/src/win/handle.c
  47. 0 1
      Utilities/cmlibuv/src/win/internal.h
  48. 113 24
      Utilities/cmlibuv/src/win/pipe.c
  49. 26 5
      Utilities/cmlibuv/src/win/process.c
  50. 1 1
      Utilities/cmlibuv/src/win/signal.c
  51. 1 2
      Utilities/cmlibuv/src/win/stream-inl.h
  52. 26 6
      Utilities/cmlibuv/src/win/tcp.c
  53. 6 0
      Utilities/cmlibuv/src/win/thread.c
  54. 1 1
      Utilities/cmlibuv/src/win/timer.c
  55. 84 37
      Utilities/cmlibuv/src/win/tty.c
  56. 45 6
      Utilities/cmlibuv/src/win/udp.c
  57. 8 3
      Utilities/cmlibuv/src/win/util.c
  58. 10 0
      Utilities/cmlibuv/src/win/winapi.c
  59. 26 0
      Utilities/cmlibuv/src/win/winapi.h
  60. 28 0
      Utilities/cmlibuv/src/win/winsock.c
  61. 3 0
      Utilities/cmlibuv/src/win/winsock.h

+ 2 - 2
Utilities/cmlibuv/LICENSE

@@ -62,8 +62,8 @@ The externally maintained libraries used by libuv are:
   - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three
     clause BSD license.
 
-  - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile
-    Communications AB. Three clause BSD license.
+  - pthread-fixes.c, copyright Google Inc. and Sony Mobile Communications AB.
+    Three clause BSD license.
 
   - android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design
     Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement

+ 1 - 0
Utilities/cmlibuv/include/pthread-barrier.h

@@ -23,6 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #endif
 
 #define PTHREAD_BARRIER_SERIAL_THREAD  0x12345
+#define UV__PTHREAD_BARRIER_FALLBACK   1
 
 /*
  * To maintain ABI compatibility with

+ 12 - 0
Utilities/cmlibuv/include/uv-errno.h

@@ -416,4 +416,16 @@
 # define UV__EHOSTDOWN (-4031)
 #endif
 
+#if defined(EREMOTEIO) && !defined(_WIN32)
+# define UV__EREMOTEIO (-EREMOTEIO)
+#else
+# define UV__EREMOTEIO (-4030)
+#endif
+
+#if defined(ENOTTY) && !defined(_WIN32)
+# define UV__ENOTTY (-ENOTTY)
+#else
+# define UV__ENOTTY (-4029)
+#endif
+
 #endif /* UV_ERRNO_H_ */

+ 3 - 0
Utilities/cmlibuv/include/uv-os390.h

@@ -27,4 +27,7 @@
 #define UV_PLATFORM_LOOP_FIELDS                                               \
   void* ep;                                                                   \
 
+#define UV_PLATFORM_FS_EVENT_FIELDS                                           \
+  char rfis_rftok[8];                                                         \
+
 #endif /* UV_MVS_H */

+ 96 - 0
Utilities/cmlibuv/include/uv-unix.h

@@ -50,6 +50,8 @@
 # include "uv-linux.h"
 #elif defined (__MVS__)
 # include "uv-os390.h"
+#elif defined(_PASE)
+# include "uv-posix.h"
 #elif defined(_AIX)
 # include "uv-aix.h"
 #elif defined(__sun)
@@ -125,6 +127,7 @@ typedef struct uv_buf_t {
 typedef int uv_file;
 typedef int uv_os_sock_t;
 typedef int uv_os_fd_t;
+typedef pid_t uv_pid_t;
 
 #ifdef CMAKE_BOOTSTRAP
 #define UV_ONCE_INIT 0
@@ -379,4 +382,97 @@ typedef struct {
   uv_fs_event_cb cb;                                                          \
   UV_PLATFORM_FS_EVENT_FIELDS                                                 \
 
+/* fs open() flags supported on this platform: */
+#if defined(O_APPEND)
+# define UV_FS_O_APPEND       O_APPEND
+#else
+# define UV_FS_O_APPEND       0
+#endif
+#if defined(O_CREAT)
+# define UV_FS_O_CREAT        O_CREAT
+#else
+# define UV_FS_O_CREAT        0
+#endif
+#if defined(O_DIRECT)
+# define UV_FS_O_DIRECT       O_DIRECT
+#else
+# define UV_FS_O_DIRECT       0
+#endif
+#if defined(O_DIRECTORY)
+# define UV_FS_O_DIRECTORY    O_DIRECTORY
+#else
+# define UV_FS_O_DIRECTORY    0
+#endif
+#if defined(O_DSYNC)
+# define UV_FS_O_DSYNC        O_DSYNC
+#else
+# define UV_FS_O_DSYNC        0
+#endif
+#if defined(O_EXCL)
+# define UV_FS_O_EXCL         O_EXCL
+#else
+# define UV_FS_O_EXCL         0
+#endif
+#if defined(O_EXLOCK)
+# define UV_FS_O_EXLOCK       O_EXLOCK
+#else
+# define UV_FS_O_EXLOCK       0
+#endif
+#if defined(O_NOATIME)
+# define UV_FS_O_NOATIME      O_NOATIME
+#else
+# define UV_FS_O_NOATIME      0
+#endif
+#if defined(O_NOCTTY)
+# define UV_FS_O_NOCTTY       O_NOCTTY
+#else
+# define UV_FS_O_NOCTTY       0
+#endif
+#if defined(O_NOFOLLOW)
+# define UV_FS_O_NOFOLLOW     O_NOFOLLOW
+#else
+# define UV_FS_O_NOFOLLOW     0
+#endif
+#if defined(O_NONBLOCK)
+# define UV_FS_O_NONBLOCK     O_NONBLOCK
+#else
+# define UV_FS_O_NONBLOCK     0
+#endif
+#if defined(O_RDONLY)
+# define UV_FS_O_RDONLY       O_RDONLY
+#else
+# define UV_FS_O_RDONLY       0
+#endif
+#if defined(O_RDWR)
+# define UV_FS_O_RDWR         O_RDWR
+#else
+# define UV_FS_O_RDWR         0
+#endif
+#if defined(O_SYMLINK)
+# define UV_FS_O_SYMLINK      O_SYMLINK
+#else
+# define UV_FS_O_SYMLINK      0
+#endif
+#if defined(O_SYNC)
+# define UV_FS_O_SYNC         O_SYNC
+#else
+# define UV_FS_O_SYNC         0
+#endif
+#if defined(O_TRUNC)
+# define UV_FS_O_TRUNC        O_TRUNC
+#else
+# define UV_FS_O_TRUNC        0
+#endif
+#if defined(O_WRONLY)
+# define UV_FS_O_WRONLY       O_WRONLY
+#else
+# define UV_FS_O_WRONLY       0
+#endif
+
+/* fs open() flags supported on other platforms: */
+#define UV_FS_O_RANDOM        0
+#define UV_FS_O_SHORT_LIVED   0
+#define UV_FS_O_SEQUENTIAL    0
+#define UV_FS_O_TEMPORARY     0
+
 #endif /* UV_UNIX_H */

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

@@ -31,7 +31,7 @@
  */
 
 #define UV_VERSION_MAJOR 1
-#define UV_VERSION_MINOR 11
+#define UV_VERSION_MINOR 19
 #define UV_VERSION_PATCH 1
 #define UV_VERSION_IS_RELEASE 0
 #define UV_VERSION_SUFFIX "dev"

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

@@ -20,7 +20,7 @@
  */
 
 #ifndef _WIN32_WINNT
-# define _WIN32_WINNT   0x0502
+# define _WIN32_WINNT   0x0600
 #endif
 
 #if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
@@ -233,6 +233,7 @@ typedef struct uv_buf_t {
 typedef int uv_file;
 typedef SOCKET uv_os_sock_t;
 typedef HANDLE uv_os_fd_t;
+typedef int uv_pid_t;
 
 typedef HANDLE uv_thread_t;
 
@@ -659,3 +660,28 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
 #ifndef X_OK
 #define X_OK 1
 #endif
+
+/* fs open() flags supported on this platform: */
+#define UV_FS_O_APPEND       _O_APPEND
+#define UV_FS_O_CREAT        _O_CREAT
+#define UV_FS_O_EXCL         _O_EXCL
+#define UV_FS_O_RANDOM       _O_RANDOM
+#define UV_FS_O_RDONLY       _O_RDONLY
+#define UV_FS_O_RDWR         _O_RDWR
+#define UV_FS_O_SEQUENTIAL   _O_SEQUENTIAL
+#define UV_FS_O_SHORT_LIVED  _O_SHORT_LIVED
+#define UV_FS_O_TEMPORARY    _O_TEMPORARY
+#define UV_FS_O_TRUNC        _O_TRUNC
+#define UV_FS_O_WRONLY       _O_WRONLY
+
+/* fs open() flags supported on other platforms (or mapped on this platform): */
+#define UV_FS_O_DIRECT       0x02000000 /* FILE_FLAG_NO_BUFFERING */
+#define UV_FS_O_DIRECTORY    0
+#define UV_FS_O_DSYNC        0x04000000 /* FILE_FLAG_WRITE_THROUGH */
+#define UV_FS_O_EXLOCK       0x10000000 /* EXCLUSIVE SHARING MODE */
+#define UV_FS_O_NOATIME      0
+#define UV_FS_O_NOCTTY       0
+#define UV_FS_O_NOFOLLOW     0
+#define UV_FS_O_NONBLOCK     0
+#define UV_FS_O_SYMLINK      0
+#define UV_FS_O_SYNC         0x08000000 /* FILE_FLAG_WRITE_THROUGH */

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

@@ -144,6 +144,8 @@ extern "C" {
   XX(ENXIO, "no such device or address")                                      \
   XX(EMLINK, "too many links")                                                \
   XX(EHOSTDOWN, "host is down")                                               \
+  XX(EREMOTEIO, "remote I/O error")                                           \
+  XX(ENOTTY, "inappropriate ioctl for device")                                \
 
 #define UV_HANDLE_TYPE_MAP(XX)                                                \
   XX(ASYNC, async)                                                            \
@@ -427,7 +429,17 @@ struct uv_handle_s {
 };
 
 UV_EXTERN size_t uv_handle_size(uv_handle_type type);
+UV_EXTERN uv_handle_type uv_handle_get_type(const uv_handle_t* handle);
+UV_EXTERN const char* uv_handle_type_name(uv_handle_type type);
+UV_EXTERN void* uv_handle_get_data(const uv_handle_t* handle);
+UV_EXTERN uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle);
+UV_EXTERN void uv_handle_set_data(uv_handle_t* handle, void* data);
+
 UV_EXTERN size_t uv_req_size(uv_req_type type);
+UV_EXTERN void* uv_req_get_data(const uv_req_t* req);
+UV_EXTERN void uv_req_set_data(uv_req_t* req, void* data);
+UV_EXTERN uv_req_type uv_req_get_type(const uv_req_t* req);
+UV_EXTERN const char* uv_req_type_name(uv_req_type type);
 
 UV_EXTERN int uv_is_active(const uv_handle_t* handle);
 
@@ -467,6 +479,8 @@ struct uv_stream_s {
   UV_STREAM_FIELDS
 };
 
+UV_EXTERN size_t uv_stream_get_write_queue_size(const uv_stream_t* stream);
+
 UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
 UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client);
 
@@ -644,6 +658,8 @@ UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle,
                                 uv_alloc_cb alloc_cb,
                                 uv_udp_recv_cb recv_cb);
 UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle);
+UV_EXTERN size_t uv_udp_get_send_queue_size(const uv_udp_t* handle);
+UV_EXTERN size_t uv_udp_get_send_queue_count(const uv_udp_t* handle);
 
 
 /*
@@ -712,6 +728,7 @@ UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle,
 UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
 UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle);
 UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
+UV_EXTERN int uv_pipe_chmod(uv_pipe_t* handle, int flags);
 
 
 struct uv_poll_s {
@@ -723,7 +740,8 @@ struct uv_poll_s {
 enum uv_poll_event {
   UV_READABLE = 1,
   UV_WRITABLE = 2,
-  UV_DISCONNECT = 4
+  UV_DISCONNECT = 4,
+  UV_PRIORITIZED = 8
 };
 
 UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd);
@@ -962,6 +980,7 @@ UV_EXTERN int uv_spawn(uv_loop_t* loop,
                        const uv_process_options_t* options);
 UV_EXTERN int uv_process_kill(uv_process_t*, int signum);
 UV_EXTERN int uv_kill(int pid, int signum);
+UV_EXTERN uv_pid_t uv_process_get_pid(const uv_process_t*);
 
 
 /*
@@ -1038,6 +1057,7 @@ UV_EXTERN int uv_get_process_title(char* buffer, size_t size);
 UV_EXTERN int uv_set_process_title(const char* title);
 UV_EXTERN int uv_resident_set_memory(size_t* rss);
 UV_EXTERN int uv_uptime(double* uptime);
+UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd);
 
 typedef struct {
   long tv_sec;
@@ -1069,6 +1089,8 @@ UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
 UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size);
 UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd);
 UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
+UV_EXTERN uv_pid_t uv_os_getpid(void);
+UV_EXTERN uv_pid_t uv_os_getppid(void);
 
 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);
@@ -1115,7 +1137,8 @@ typedef enum {
   UV_FS_READLINK,
   UV_FS_CHOWN,
   UV_FS_FCHOWN,
-  UV_FS_REALPATH
+  UV_FS_REALPATH,
+  UV_FS_COPYFILE
 } uv_fs_type;
 
 /* uv_fs_t is a subclass of uv_req_t. */
@@ -1131,6 +1154,12 @@ struct uv_fs_s {
   UV_FS_PRIVATE_FIELDS
 };
 
+UV_EXTERN uv_fs_type uv_fs_get_type(const uv_fs_t*);
+UV_EXTERN ssize_t uv_fs_get_result(const uv_fs_t*);
+UV_EXTERN void* uv_fs_get_ptr(const uv_fs_t*);
+UV_EXTERN const char* uv_fs_get_path(const uv_fs_t*);
+UV_EXTERN uv_stat_t* uv_fs_get_statbuf(uv_fs_t*);
+
 UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req);
 UV_EXTERN int uv_fs_close(uv_loop_t* loop,
                           uv_fs_t* req,
@@ -1160,6 +1189,18 @@ UV_EXTERN int uv_fs_write(uv_loop_t* loop,
                           unsigned int nbufs,
                           int64_t offset,
                           uv_fs_cb cb);
+/*
+ * This flag can be used with uv_fs_copyfile() to return an error if the
+ * destination already exists.
+ */
+#define UV_FS_COPYFILE_EXCL   0x0001
+
+UV_EXTERN int uv_fs_copyfile(uv_loop_t* loop,
+                             uv_fs_t* req,
+                             const char* path,
+                             const char* new_path,
+                             int flags,
+                             uv_fs_cb cb);
 UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop,
                           uv_fs_t* req,
                           const char* path,
@@ -1393,6 +1434,21 @@ UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size
 UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size);
 UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst);
 
+#if defined(IF_NAMESIZE)
+# define UV_IF_NAMESIZE (IF_NAMESIZE + 1)
+#elif defined(IFNAMSIZ)
+# define UV_IF_NAMESIZE (IFNAMSIZ + 1)
+#else
+# define UV_IF_NAMESIZE (16 + 1)
+#endif
+
+UV_EXTERN int uv_if_indextoname(unsigned int ifindex,
+                                char* buffer,
+                                size_t* size);
+UV_EXTERN int uv_if_indextoiid(unsigned int ifindex,
+                               char* buffer,
+                               size_t* size);
+
 UV_EXTERN int uv_exepath(char* buffer, size_t* size);
 
 UV_EXTERN int uv_cwd(char* buffer, size_t* size);
@@ -1412,6 +1468,7 @@ UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr);
 UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib);
 
 UV_EXTERN int uv_mutex_init(uv_mutex_t* handle);
+UV_EXTERN int uv_mutex_init_recursive(uv_mutex_t* handle);
 UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle);
 UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle);
 UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle);
@@ -1484,6 +1541,8 @@ struct uv_loop_s {
   UV_LOOP_PRIVATE_FIELDS
 };
 
+UV_EXTERN void* uv_loop_get_data(const uv_loop_t*);
+UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data);
 
 /* Don't export the private CPP symbols. */
 #undef UV_HANDLE_TYPE_PRIVATE

+ 12 - 6
Utilities/cmlibuv/src/threadpool.c

@@ -38,7 +38,6 @@ static uv_thread_t* threads;
 static uv_thread_t default_threads[4];
 static QUEUE exit_message;
 static QUEUE wq;
-static volatile int initialized;
 
 
 static void uv__cancelled(struct uv__work* w) {
@@ -53,7 +52,8 @@ static void worker(void* arg) {
   struct uv__work* w;
   QUEUE* q;
 
-  (void) arg;
+  uv_sem_post((uv_sem_t*) arg);
+  arg = NULL;
 
   for (;;) {
     uv_mutex_lock(&mutex);
@@ -105,7 +105,7 @@ static void post(QUEUE* q) {
 UV_DESTRUCTOR(static void cleanup(void)) {
   unsigned int i;
 
-  if (initialized == 0)
+  if (nthreads == 0)
     return;
 
   post(&exit_message);
@@ -122,7 +122,6 @@ UV_DESTRUCTOR(static void cleanup(void)) {
 
   threads = NULL;
   nthreads = 0;
-  initialized = 0;
 }
 #endif
 
@@ -130,6 +129,7 @@ UV_DESTRUCTOR(static void cleanup(void)) {
 static void init_threads(void) {
   unsigned int i;
   const char* val;
+  uv_sem_t sem;
 
   nthreads = ARRAY_SIZE(default_threads);
   val = getenv("UV_THREADPOOL_SIZE");
@@ -157,11 +157,17 @@ static void init_threads(void) {
 
   QUEUE_INIT(&wq);
 
+  if (uv_sem_init(&sem, 0))
+    abort();
+
   for (i = 0; i < nthreads; i++)
-    if (uv_thread_create(threads + i, worker, NULL))
+    if (uv_thread_create(threads + i, worker, &sem))
       abort();
 
-  initialized = 1;
+  for (i = 0; i < nthreads; i++)
+    uv_sem_wait(&sem);
+
+  uv_sem_destroy(&sem);
 }
 
 

+ 292 - 0
Utilities/cmlibuv/src/unix/aix-common.c

@@ -0,0 +1,292 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <libgen.h>
+
+#include <sys/protosw.h>
+#include <procinfo.h>
+#include <sys/proc.h>
+#include <sys/procfs.h>
+
+#include <sys/poll.h>
+
+#include <sys/pollset.h>
+#include <ctype.h>
+
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+#include <limits.h>
+#include <strings.h>
+#include <sys/vnode.h>
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+  uint64_t G = 1000000000;
+  timebasestruct_t t;
+  read_wall_time(&t, TIMEBASE_SZ);
+  time_base_to_time(&t, TIMEBASE_SZ);
+  return (uint64_t) t.tb_high * G + t.tb_low;
+}
+
+
+/*
+ * We could use a static buffer for the path manipulations that we need outside
+ * of the function, but this function could be called by multiple consumers and
+ * we don't want to potentially create a race condition in the use of snprintf.
+ * There is no direct way of getting the exe path in AIX - either through /procfs
+ * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
+ * and use it in conjunction with PATH environment variable to craft one.
+ */
+int uv_exepath(char* buffer, size_t* size) {
+  int res;
+  char args[PATH_MAX];
+  char abspath[PATH_MAX];
+  size_t abspath_size;
+  struct procsinfo pi;
+
+  if (buffer == NULL || size == NULL || *size == 0)
+    return -EINVAL;
+
+  pi.pi_pid = getpid();
+  res = getargs(&pi, sizeof(pi), args, sizeof(args));
+  if (res < 0)
+    return -EINVAL;
+
+  /*
+   * Possibilities for args:
+   * i) an absolute path such as: /home/user/myprojects/nodejs/node
+   * ii) a relative path such as: ./node or ../myprojects/nodejs/node
+   * iii) a bare filename such as "node", after exporting PATH variable
+   *     to its location.
+   */
+
+  /* Case i) and ii) absolute or relative paths */
+  if (strchr(args, '/') != NULL) {
+    if (realpath(args, abspath) != abspath)
+      return -errno;
+
+    abspath_size = strlen(abspath);
+
+    *size -= 1;
+    if (*size > abspath_size)
+      *size = abspath_size;
+
+    memcpy(buffer, abspath, *size);
+    buffer[*size] = '\0';
+
+    return 0;
+  } else {
+    /* Case iii). Search PATH environment variable */
+    char trypath[PATH_MAX];
+    char *clonedpath = NULL;
+    char *token = NULL;
+    char *path = getenv("PATH");
+
+    if (path == NULL)
+      return -EINVAL;
+
+    clonedpath = uv__strdup(path);
+    if (clonedpath == NULL)
+      return -ENOMEM;
+
+    token = strtok(clonedpath, ":");
+    while (token != NULL) {
+      snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
+      if (realpath(trypath, abspath) == abspath) {
+        /* Check the match is executable */
+        if (access(abspath, X_OK) == 0) {
+          abspath_size = strlen(abspath);
+
+          *size -= 1;
+          if (*size > abspath_size)
+            *size = abspath_size;
+
+          memcpy(buffer, abspath, *size);
+          buffer[*size] = '\0';
+
+          uv__free(clonedpath);
+          return 0;
+        }
+      }
+      token = strtok(NULL, ":");
+    }
+    uv__free(clonedpath);
+
+    /* Out of tokens (path entries), and no match found */
+    return -EINVAL;
+  }
+}
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+  int i;
+
+  for (i = 0; i < count; ++i) {
+    uv__free(cpu_infos[i].model);
+  }
+
+  uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses,
+  int* count) {
+  uv_interface_address_t* address;
+  int sockfd, inet6, size = 1;
+  struct ifconf ifc;
+  struct ifreq *ifr, *p, flg;
+  struct sockaddr_dl* sa_addr;
+
+  *count = 0;
+
+  if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
+    return -errno;
+  }
+
+  if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
+    uv__close(sockfd);
+    return -errno;
+  }
+
+  ifc.ifc_req = (struct ifreq*)uv__malloc(size);
+  ifc.ifc_len = size;
+  if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
+    uv__close(sockfd);
+    return -errno;
+  }
+
+#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
+
+  /* Count all up and running ipv4/ipv6 addresses */
+  ifr = ifc.ifc_req;
+  while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+    p = ifr;
+    ifr = (struct ifreq*)
+      ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+    if (!(p->ifr_addr.sa_family == AF_INET6 ||
+          p->ifr_addr.sa_family == AF_INET))
+      continue;
+
+    memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+    if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+      uv__close(sockfd);
+      return -errno;
+    }
+
+    if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+      continue;
+
+    (*count)++;
+  }
+
+  /* Alloc the return interface structs */
+  *addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
+  if (!(*addresses)) {
+    uv__close(sockfd);
+    return -ENOMEM;
+  }
+  address = *addresses;
+
+  ifr = ifc.ifc_req;
+  while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+    p = ifr;
+    ifr = (struct ifreq*)
+      ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+    if (!(p->ifr_addr.sa_family == AF_INET6 ||
+          p->ifr_addr.sa_family == AF_INET))
+      continue;
+
+    inet6 = (p->ifr_addr.sa_family == AF_INET6);
+
+    memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+    if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+      uv__close(sockfd);
+      return -ENOSYS;
+    }
+
+    if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+      continue;
+
+    /* All conditions above must match count loop */
+
+    address->name = uv__strdup(p->ifr_name);
+
+    if (inet6)
+      address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
+    else
+      address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
+
+    sa_addr = (struct sockaddr_dl*) &p->ifr_addr;
+    memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+
+    if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) {
+      uv__close(sockfd);
+      return -ENOSYS;
+    }
+
+    if (inet6)
+      address->netmask.netmask6 = *((struct sockaddr_in6*) &p->ifr_addr);
+    else
+      address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr);
+
+    address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
+
+    address++;
+  }
+
+#undef ADDR_SIZE
+
+  uv__close(sockfd);
+  return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+  int count) {
+  int i;
+
+  for (i = 0; i < count; ++i) {
+    uv__free(addresses[i].name);
+  }
+
+  uv__free(addresses);
+}

+ 20 - 222
Utilities/cmlibuv/src/unix/aix.c

@@ -1,4 +1,5 @@
 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
  * deal in the Software without restriction, including without limitation the
@@ -64,11 +65,18 @@
 #define RDWR_BUF_SIZE   4096
 #define EQ(a,b)         (strcmp(a,b) == 0)
 
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
 static void* args_mem = NULL;
 static char** process_argv = NULL;
 static int process_argc = 0;
 static char* process_title_ptr = NULL;
 
+static void init_process_title_mutex_once(void) {
+  uv_mutex_init(&process_title_mutex);
+}
+
+
 int uv__platform_loop_init(uv_loop_t* loop) {
   loop->fs_fd = -1;
 
@@ -316,104 +324,6 @@ update_timeout:
 }
 
 
-uint64_t uv__hrtime(uv_clocktype_t type) {
-  uint64_t G = 1000000000;
-  timebasestruct_t t;
-  read_wall_time(&t, TIMEBASE_SZ);
-  time_base_to_time(&t, TIMEBASE_SZ);
-  return (uint64_t) t.tb_high * G + t.tb_low;
-}
-
-
-/*
- * We could use a static buffer for the path manipulations that we need outside
- * of the function, but this function could be called by multiple consumers and
- * we don't want to potentially create a race condition in the use of snprintf.
- * There is no direct way of getting the exe path in AIX - either through /procfs
- * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
- * and use it in conjunction with PATH environment variable to craft one.
- */
-int uv_exepath(char* buffer, size_t* size) {
-  int res;
-  char args[PATH_MAX];
-  char abspath[PATH_MAX];
-  size_t abspath_size;
-  struct procsinfo pi;
-
-  if (buffer == NULL || size == NULL || *size == 0)
-    return -EINVAL;
-
-  pi.pi_pid = getpid();
-  res = getargs(&pi, sizeof(pi), args, sizeof(args));
-  if (res < 0)
-    return -EINVAL;
-
-  /*
-   * Possibilities for args:
-   * i) an absolute path such as: /home/user/myprojects/nodejs/node
-   * ii) a relative path such as: ./node or ../myprojects/nodejs/node
-   * iii) a bare filename such as "node", after exporting PATH variable
-   *     to its location.
-   */
-
-  /* Case i) and ii) absolute or relative paths */
-  if (strchr(args, '/') != NULL) {
-    if (realpath(args, abspath) != abspath)
-      return -errno;
-
-    abspath_size = strlen(abspath);
-
-    *size -= 1;
-    if (*size > abspath_size)
-      *size = abspath_size;
-
-    memcpy(buffer, abspath, *size);
-    buffer[*size] = '\0';
-
-    return 0;
-  } else {
-  /* Case iii). Search PATH environment variable */
-    char trypath[PATH_MAX];
-    char *clonedpath = NULL;
-    char *token = NULL;
-    char *path = getenv("PATH");
-
-    if (path == NULL)
-      return -EINVAL;
-
-    clonedpath = uv__strdup(path);
-    if (clonedpath == NULL)
-      return -ENOMEM;
-
-    token = strtok(clonedpath, ":");
-    while (token != NULL) {
-      snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
-      if (realpath(trypath, abspath) == abspath) {
-        /* Check the match is executable */
-        if (access(abspath, X_OK) == 0) {
-          abspath_size = strlen(abspath);
-
-          *size -= 1;
-          if (*size > abspath_size)
-            *size = abspath_size;
-
-          memcpy(buffer, abspath, *size);
-          buffer[*size] = '\0';
-
-          uv__free(clonedpath);
-          return 0;
-        }
-      }
-      token = strtok(NULL, ":");
-    }
-    uv__free(clonedpath);
-
-    /* Out of tokens (path entries), and no match found */
-    return -EINVAL;
-  }
-}
-
-
 uint64_t uv_get_free_memory(void) {
   perfstat_memory_total_t mem_total;
   int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
@@ -855,6 +765,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
   uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
   handle->path = uv__strdup(filename);
   handle->cb = cb;
+  handle->dir_filename = NULL;
 
   uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
 
@@ -952,6 +863,9 @@ int uv_set_process_title(const char* title) {
   if (new_title == NULL)
     return -ENOMEM;
 
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+  uv_mutex_lock(&process_title_mutex);
+
   /* If this is the first time this is set,
    * don't free and set argv[1] to NULL.
    */
@@ -964,6 +878,8 @@ int uv_set_process_title(const char* title) {
   if (process_argc > 1)
      process_argv[1] = NULL;
 
+  uv_mutex_unlock(&process_title_mutex);
+
   return 0;
 }
 
@@ -976,8 +892,13 @@ int uv_get_process_title(char* buffer, size_t size) {
   else if (size <= len)
     return -ENOBUFS;
 
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+  uv_mutex_lock(&process_title_mutex);
+
   memcpy(buffer, process_argv[0], len + 1);
 
+  uv_mutex_unlock(&process_title_mutex);
+
   return 0;
 }
 
@@ -1017,6 +938,7 @@ int uv_uptime(double* uptime) {
   size_t entries = 0;
   time_t boot_time;
 
+  boot_time = 0;
   utmpname(UTMP_FILE);
 
   setutent();
@@ -1093,130 +1015,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
 }
 
 
-void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
-  int i;
-
-  for (i = 0; i < count; ++i) {
-    uv__free(cpu_infos[i].model);
-  }
-
-  uv__free(cpu_infos);
-}
-
-
-int uv_interface_addresses(uv_interface_address_t** addresses,
-  int* count) {
-  uv_interface_address_t* address;
-  int sockfd, size = 1;
-  struct ifconf ifc;
-  struct ifreq *ifr, *p, flg;
-
-  *count = 0;
-
-  if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
-    return -errno;
-  }
-
-  if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
-    uv__close(sockfd);
-    return -errno;
-  }
-
-  ifc.ifc_req = (struct ifreq*)uv__malloc(size);
-  ifc.ifc_len = size;
-  if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
-    uv__close(sockfd);
-    return -errno;
-  }
-
-#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
-
-  /* Count all up and running ipv4/ipv6 addresses */
-  ifr = ifc.ifc_req;
-  while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
-    p = ifr;
-    ifr = (struct ifreq*)
-      ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
-
-    if (!(p->ifr_addr.sa_family == AF_INET6 ||
-          p->ifr_addr.sa_family == AF_INET))
-      continue;
-
-    memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
-    if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
-      uv__close(sockfd);
-      return -errno;
-    }
-
-    if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
-      continue;
-
-    (*count)++;
-  }
-
-  /* Alloc the return interface structs */
-  *addresses = (uv_interface_address_t*)
-    uv__malloc(*count * sizeof(uv_interface_address_t));
-  if (!(*addresses)) {
-    uv__close(sockfd);
-    return -ENOMEM;
-  }
-  address = *addresses;
-
-  ifr = ifc.ifc_req;
-  while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
-    p = ifr;
-    ifr = (struct ifreq*)
-      ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
-
-    if (!(p->ifr_addr.sa_family == AF_INET6 ||
-          p->ifr_addr.sa_family == AF_INET))
-      continue;
-
-    memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
-    if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
-      uv__close(sockfd);
-      return -ENOSYS;
-    }
-
-    if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
-      continue;
-
-    /* All conditions above must match count loop */
-
-    address->name = uv__strdup(p->ifr_name);
-
-    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);
-    }
-
-    /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
-
-    address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
-
-    address++;
-  }
-
-#undef ADDR_SIZE
-
-  uv__close(sockfd);
-  return 0;
-}
-
-
-void uv_free_interface_addresses(uv_interface_address_t* addresses,
-  int count) {
-  int i;
-
-  for (i = 0; i < count; ++i) {
-    uv__free(addresses[i].name);
-  }
-
-  uv__free(addresses);
-}
-
 void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
   struct pollfd* events;
   uintptr_t i;

+ 28 - 21
Utilities/cmlibuv/src/unix/android-ifaddrs.c

@@ -43,9 +43,10 @@ typedef struct NetlinkList
     unsigned int m_size;
 } NetlinkList;
 
-static int netlink_socket(void)
+static int netlink_socket(pid_t *p_pid)
 {
     struct sockaddr_nl l_addr;
+    socklen_t l_len;
 
     int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
     if(l_socket < 0)
@@ -61,6 +62,14 @@ static int netlink_socket(void)
         return -1;
     }
 
+    l_len = sizeof(l_addr);
+    if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0)
+    {
+        close(l_socket);
+        return -1;
+    }
+    *p_pid = l_addr.nl_pid;
+
     return l_socket;
 }
 
@@ -128,7 +137,7 @@ static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
     }
 }
 
-static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
+static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done)
 {
     size_t l_size = 4096;
     void *l_buffer = NULL;
@@ -153,11 +162,10 @@ static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_don
         }
         if(l_read >= 0)
         {
-            pid_t l_pid = getpid();
             struct nlmsghdr *l_hdr;
             for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
             {
-                if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+                if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
                 {
                     continue;
                 }
@@ -207,7 +215,7 @@ static void freeResultList(NetlinkList *p_list)
     }
 }
 
-static NetlinkList *getResultList(int p_socket, int p_request)
+static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid)
 {
     int l_size;
     int l_done;
@@ -227,7 +235,7 @@ static NetlinkList *getResultList(int p_socket, int p_request)
     {
         NetlinkList *l_item;
 
-        struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
+        struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done);
         /* Error */
         if(!l_hdr)
         {
@@ -449,7 +457,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
     char *l_name;
     char *l_addr;
 
-    for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+    for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
     {
         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
         if(l_info->ifa_family == AF_PACKET)
@@ -471,7 +479,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
                 l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
                 break;
             case IFA_LABEL:
-                l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+                l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1);
                 break;
             default:
                 break;
@@ -496,7 +504,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
     }
 
     l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
-    for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+    for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
     {
         void *l_rtaData = RTA_DATA(l_rta);
         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
@@ -559,7 +567,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
     {
         unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
         unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
-        char l_mask[16] = {0};
+        unsigned char l_mask[16] = {0};
         unsigned i;
         for(i=0; i<(l_prefix/8); ++i)
         {
@@ -578,18 +586,17 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
     return 0;
 }
 
-static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
+static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
 {
 
     int l_numLinks = 0;
-    pid_t l_pid = getpid();
     for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
     {
         unsigned int l_nlsize = p_netlinkList->m_size;
         struct nlmsghdr *l_hdr;
         for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
         {
-            if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+            if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
             {
                 continue;
             }
@@ -612,16 +619,15 @@ static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifadd
     return l_numLinks;
 }
 
-static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
+static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
 {
-    pid_t l_pid = getpid();
     for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
     {
         unsigned int l_nlsize = p_netlinkList->m_size;
         struct nlmsghdr *l_hdr;
         for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
         {
-            if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+            if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
             {
                 continue;
             }
@@ -648,6 +654,7 @@ int getifaddrs(struct ifaddrs **ifap)
     int l_socket;
     int l_result;
     int l_numLinks;
+    pid_t l_pid;
     NetlinkList *l_linkResults;
     NetlinkList *l_addrResults;
 
@@ -657,20 +664,20 @@ int getifaddrs(struct ifaddrs **ifap)
     }
     *ifap = NULL;
 
-    l_socket = netlink_socket();
+    l_socket = netlink_socket(&l_pid);
     if(l_socket < 0)
     {
         return -1;
     }
 
-    l_linkResults = getResultList(l_socket, RTM_GETLINK);
+    l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid);
     if(!l_linkResults)
     {
         close(l_socket);
         return -1;
     }
 
-    l_addrResults = getResultList(l_socket, RTM_GETADDR);
+    l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid);
     if(!l_addrResults)
     {
         close(l_socket);
@@ -679,8 +686,8 @@ int getifaddrs(struct ifaddrs **ifap)
     }
 
     l_result = 0;
-    l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
-    if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
+    l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap);
+    if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1)
     {
         l_result = -1;
     }

+ 4 - 1
Utilities/cmlibuv/src/unix/atomic-ops.h

@@ -20,7 +20,6 @@
 
 #if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
 #include <atomic.h>
-#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n)
 #endif
 
 UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
@@ -49,6 +48,8 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
     return oldval;
   else
     return op4;
+#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+  return atomic_cas_uint(ptr, oldval, newval);
 #else
   return __sync_val_compare_and_swap(ptr, oldval, newval);
 #endif
@@ -83,6 +84,8 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
     return oldval;
   else
     return op4;
+#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+  return atomic_cas_ulong(ptr, oldval, newval);
 #else
   return __sync_val_compare_and_swap(ptr, oldval, newval);
 #endif

+ 18 - 5
Utilities/cmlibuv/src/unix/bsd-ifaddrs.c

@@ -31,11 +31,20 @@
 #include <net/if_dl.h>
 #endif
 
-static int uv__ifaddr_exclude(struct ifaddrs *ent) {
+static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
   if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
     return 1;
   if (ent->ifa_addr == NULL)
     return 1;
+#if !defined(__CYGWIN__) && !defined(__MSYS__)
+  /*
+   * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family`
+   * equals to `AF_LINK` or not. Otherwise, the result depends on the operation
+   * system with `AF_LINK` or `PF_INET`.
+   */
+  if (exclude_type == UV__EXCLUDE_IFPHYS)
+    return (ent->ifa_addr->sa_family != AF_LINK);
+#endif
 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
   /*
    * On BSD getifaddrs returns information related to the raw underlying
@@ -43,7 +52,11 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) {
    */
   if (ent->ifa_addr->sa_family == AF_LINK)
     return 1;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
+#elif defined(__NetBSD__)
+  if (ent->ifa_addr->sa_family != PF_INET &&
+      ent->ifa_addr->sa_family != PF_INET6)
+    return 1;
+#elif defined(__OpenBSD__)
   if (ent->ifa_addr->sa_family != PF_INET)
     return 1;
 #endif
@@ -63,7 +76,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
 
   /* Count the number of interfaces */
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (uv__ifaddr_exclude(ent))
+    if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
       continue;
     (*count)++;
   }
@@ -78,7 +91,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   address = *addresses;
 
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (uv__ifaddr_exclude(ent))
+    if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
       continue;
 
     address->name = uv__strdup(ent->ifa_name);
@@ -102,7 +115,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
 
   /* Fill in physical addresses for each interface */
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (uv__ifaddr_exclude(ent))
+    if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
       continue;
 
     address = *addresses;

+ 37 - 8
Utilities/cmlibuv/src/unix/core.c

@@ -28,7 +28,6 @@
 #include <errno.h>
 #include <assert.h>
 #include <unistd.h>
-#include <sys/param.h> /* MAXHOSTNAMELEN on Linux and the BSDs */
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -59,13 +58,19 @@
 
 #if defined(__DragonFly__)      || \
     defined(__FreeBSD__)        || \
-    defined(__FreeBSD_kernel__)
+    defined(__FreeBSD_kernel__) || \
+    defined(__NetBSD__)
 # include <sys/sysctl.h>
 # include <sys/filio.h>
 # include <sys/wait.h>
 # define UV__O_CLOEXEC O_CLOEXEC
 # if defined(__FreeBSD__) && __FreeBSD__ >= 10
 #  define uv__accept4 accept4
+# endif
+# if defined(__NetBSD__)
+#  define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d))
+# endif
+# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
 #  define UV__SOCK_NONBLOCK SOCK_NONBLOCK
 #  define UV__SOCK_CLOEXEC  SOCK_CLOEXEC
 # endif
@@ -82,6 +87,10 @@
 #include <sys/ioctl.h>
 #endif
 
+#if !defined(__MVS__)
+#include <sys/param.h> /* MAXHOSTNAMELEN on Linux and the BSDs */
+#endif
+
 /* Fallback for the maximum hostname length */
 #ifndef MAXHOSTNAMELEN
 # define MAXHOSTNAMELEN 256
@@ -459,7 +468,9 @@ int uv__accept(int sockfd) {
   assert(sockfd >= 0);
 
   while (1) {
-#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10)
+#if defined(__linux__)                          || \
+    (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \
+    defined(__NetBSD__)
     static int no_accept4;
 
     if (no_accept4)
@@ -835,7 +846,7 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
 
 
 void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
-  assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP)));
+  assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
   assert(0 != events);
   assert(w->fd >= 0);
   assert(w->fd < INT_MAX);
@@ -863,7 +874,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
 
 
 void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
-  assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP)));
+  assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
   assert(0 != events);
 
   if (w->fd == -1)
@@ -895,7 +906,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
 
 
 void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
-  uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP);
+  uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
   QUEUE_REMOVE(&w->pending_queue);
 
   /* Remove stale events for this file descriptor */
@@ -910,7 +921,7 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
 
 
 int uv__io_active(const uv__io_t* w, unsigned int events) {
-  assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP)));
+  assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
   assert(0 != events);
   return 0 != (w->pevents & events);
 }
@@ -985,7 +996,7 @@ int uv__open_cloexec(const char* path, int flags) {
 
 int uv__dup2_cloexec(int oldfd, int newfd) {
   int r;
-#if defined(__FreeBSD__) && __FreeBSD__ >= 10
+#if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
   r = dup3(oldfd, newfd, O_CLOEXEC);
   if (r == -1)
     return -errno;
@@ -1289,6 +1300,9 @@ int uv_os_setenv(const char* name, const char* value) {
 
 
 int uv_os_unsetenv(const char* name) {
+  if (name == NULL)
+    return -EINVAL;
+
   if (unsetenv(name) != 0)
     return -errno;
 
@@ -1324,3 +1338,18 @@ int uv_os_gethostname(char* buffer, size_t* size) {
   *size = len;
   return 0;
 }
+
+
+uv_os_fd_t uv_get_osfhandle(int fd) {
+  return fd;
+}
+
+
+uv_pid_t uv_os_getpid(void) {
+  return getpid();
+}
+
+
+uv_pid_t uv_os_getppid(void) {
+  return getppid();
+}

+ 58 - 29
Utilities/cmlibuv/src/unix/freebsd.c

@@ -25,7 +25,6 @@
 #include <string.h>
 #include <errno.h>
 
-#include <kvm.h>
 #include <paths.h>
 #include <sys/user.h>
 #include <sys/types.h>
@@ -48,9 +47,16 @@
 # define CP_INTR 4
 #endif
 
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
 static char *process_title;
 
 
+static void init_process_title_mutex_once(void) {
+  uv_mutex_init(&process_title_mutex);
+}
+
+
 int uv__platform_loop_init(uv_loop_t* loop) {
   return uv__kqueue_init(loop);
 }
@@ -161,9 +167,20 @@ char** uv_setup_args(int argc, char** argv) {
 
 int uv_set_process_title(const char* title) {
   int oid[4];
+  char* new_title;
+
+  new_title = uv__strdup(title);
+
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+  uv_mutex_lock(&process_title_mutex);
+
+  if (process_title == NULL) {
+    uv_mutex_unlock(&process_title_mutex);
+    return -ENOMEM;
+  }
 
   uv__free(process_title);
-  process_title = uv__strdup(title);
+  process_title = new_title;
 
   oid[0] = CTL_KERN;
   oid[1] = KERN_PROC;
@@ -177,6 +194,8 @@ int uv_set_process_title(const char* title) {
          process_title,
          strlen(process_title) + 1);
 
+  uv_mutex_unlock(&process_title_mutex);
+
   return 0;
 }
 
@@ -187,51 +206,54 @@ int uv_get_process_title(char* buffer, size_t size) {
   if (buffer == NULL || size == 0)
     return -EINVAL;
 
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+  uv_mutex_lock(&process_title_mutex);
+
   if (process_title) {
     len = strlen(process_title) + 1;
 
-    if (size < len)
+    if (size < len) {
+      uv_mutex_unlock(&process_title_mutex);
       return -ENOBUFS;
+    }
 
     memcpy(buffer, process_title, len);
   } else {
     len = 0;
   }
 
+  uv_mutex_unlock(&process_title_mutex);
+
   buffer[len] = '\0';
 
   return 0;
 }
 
-
 int uv_resident_set_memory(size_t* rss) {
-  kvm_t *kd = NULL;
-  struct kinfo_proc *kinfo = NULL;
-  pid_t pid;
-  int nprocs;
-  size_t page_size = getpagesize();
+  struct kinfo_proc kinfo;
+  size_t page_size;
+  size_t kinfo_size;
+  int mib[4];
+
+  mib[0] = CTL_KERN;
+  mib[1] = KERN_PROC;
+  mib[2] = KERN_PROC_PID;
+  mib[3] = getpid();
 
-  pid = getpid();
+  kinfo_size = sizeof(kinfo);
 
-  kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
-  if (kd == NULL) goto error;
+  if (sysctl(mib, 4, &kinfo, &kinfo_size, NULL, 0))
+    return -errno;
 
-  kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs);
-  if (kinfo == NULL) goto error;
+  page_size = getpagesize();
 
 #ifdef __DragonFly__
-  *rss = kinfo->kp_vm_rssize * page_size;
+  *rss = kinfo.kp_vm_rssize * page_size;
 #else
-  *rss = kinfo->ki_rssize * page_size;
+  *rss = kinfo.ki_rssize * page_size;
 #endif
 
-  kvm_close(kd);
-
   return 0;
-
-error:
-  if (kd) kvm_close(kd);
-  return -EPERM;
 }
 
 
@@ -254,6 +276,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
   uv_cpu_info_t* cpu_info;
   const char* maxcpus_key;
   const char* cptimes_key;
+  const char* model_key;
   char model[512];
   long* cp_times;
   int numcpus;
@@ -272,8 +295,20 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
   cptimes_key = "kern.cp_times";
 #endif
 
+#if defined(__arm__) || defined(__aarch64__)
+  /* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */
+  model_key = "hw.machine";
+  cpuspeed = 0;
+#else
+  model_key = "hw.model";
+
+  size = sizeof(cpuspeed);
+  if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0))
+    return -errno;
+#endif
+
   size = sizeof(model);
-  if (sysctlbyname("hw.model", &model, &size, NULL, 0))
+  if (sysctlbyname(model_key, &model, &size, NULL, 0))
     return -errno;
 
   size = sizeof(numcpus);
@@ -286,12 +321,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
 
   *count = numcpus;
 
-  size = sizeof(cpuspeed);
-  if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) {
-    uv__free(*cpu_infos);
-    return -errno;
-  }
-
   /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of
    * ncpu.
    */

+ 165 - 12
Utilities/cmlibuv/src/unix/fs.c

@@ -60,8 +60,14 @@
 # include <sys/sendfile.h>
 #endif
 
+#if defined(__APPLE__)
+# include <copyfile.h>
+#endif
+
 #define INIT(subtype)                                                         \
   do {                                                                        \
+    if (req == NULL)                                                          \
+      return -EINVAL;                                                         \
     req->type = UV_FS;                                                        \
     if (cb != NULL)                                                           \
       uv__req_init(loop, req, UV_FS);                                         \
@@ -126,26 +132,33 @@
   while (0)
 
 
-static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
-#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
-  return fdatasync(req->file);
-#elif defined(__APPLE__)
+static ssize_t uv__fs_fsync(uv_fs_t* req) {
+#if defined(__APPLE__)
   /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache
    * to the drive platters. This is in contrast to Linux's fdatasync and fsync
    * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent
-   * for flushing buffered data to permanent storage.
+   * for flushing buffered data to permanent storage. If F_FULLFSYNC is not
+   * supported by the file system we should fall back to fsync(). This is the
+   * same approach taken by sqlite.
    */
-  return fcntl(req->file, F_FULLFSYNC);
+  int r;
+
+  r = fcntl(req->file, F_FULLFSYNC);
+  if (r != 0 && errno == ENOTTY)
+    r = fsync(req->file);
+  return r;
 #else
   return fsync(req->file);
 #endif
 }
 
 
-static ssize_t uv__fs_fsync(uv_fs_t* req) {
-#if defined(__APPLE__)
-  /* See the comment in uv__fs_fdatasync. */
-  return fcntl(req->file, F_FULLFSYNC);
+static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
+#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
+  return fdatasync(req->file);
+#elif defined(__APPLE__)
+  /* See the comment in uv__fs_fsync. */
+  return uv__fs_fsync(req);
 #else
   return fsync(req->file);
 #endif
@@ -442,7 +455,12 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
     return -1;
   }
 
+#if defined(__MVS__)
+  len = os390_readlink(req->path, buf, len);
+#else
   len = readlink(req->path, buf, len);
+#endif
+
 
   if (len == -1) {
     uv__free(buf);
@@ -776,6 +794,118 @@ done:
   return r;
 }
 
+static ssize_t uv__fs_copyfile(uv_fs_t* req) {
+#if defined(__APPLE__) && !TARGET_OS_IPHONE
+  /* On macOS, use the native copyfile(3). */
+  copyfile_flags_t flags;
+
+  flags = COPYFILE_ALL;
+
+  if (req->flags & UV_FS_COPYFILE_EXCL)
+    flags |= COPYFILE_EXCL;
+
+  return copyfile(req->path, req->new_path, NULL, flags);
+#else
+  uv_fs_t fs_req;
+  uv_file srcfd;
+  uv_file dstfd;
+  struct stat statsbuf;
+  int dst_flags;
+  int result;
+  int err;
+  size_t bytes_to_send;
+  int64_t in_offset;
+
+  dstfd = -1;
+  err = 0;
+
+  /* Open the source file. */
+  srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL);
+  uv_fs_req_cleanup(&fs_req);
+
+  if (srcfd < 0)
+    return srcfd;
+
+  /* Get the source file's mode. */
+  if (fstat(srcfd, &statsbuf)) {
+    err = -errno;
+    goto out;
+  }
+
+  dst_flags = O_WRONLY | O_CREAT | O_TRUNC;
+
+  if (req->flags & UV_FS_COPYFILE_EXCL)
+    dst_flags |= O_EXCL;
+
+  /* Open the destination file. */
+  dstfd = uv_fs_open(NULL,
+                     &fs_req,
+                     req->new_path,
+                     dst_flags,
+                     statsbuf.st_mode,
+                     NULL);
+  uv_fs_req_cleanup(&fs_req);
+
+  if (dstfd < 0) {
+    err = dstfd;
+    goto out;
+  }
+
+  if (fchmod(dstfd, statsbuf.st_mode) == -1) {
+    err = -errno;
+    goto out;
+  }
+
+  bytes_to_send = statsbuf.st_size;
+  in_offset = 0;
+  while (bytes_to_send != 0) {
+    err = uv_fs_sendfile(NULL,
+                         &fs_req,
+                         dstfd,
+                         srcfd,
+                         in_offset,
+                         bytes_to_send,
+                         NULL);
+    uv_fs_req_cleanup(&fs_req);
+    if (err < 0)
+      break;
+    bytes_to_send -= fs_req.result;
+    in_offset += fs_req.result;
+  }
+
+out:
+  if (err < 0)
+    result = err;
+  else
+    result = 0;
+
+  /* Close the source file. */
+  err = uv__close_nocheckstdio(srcfd);
+
+  /* Don't overwrite any existing errors. */
+  if (err != 0 && result == 0)
+    result = err;
+
+  /* Close the destination file if it is open. */
+  if (dstfd >= 0) {
+    err = uv__close_nocheckstdio(dstfd);
+
+    /* Don't overwrite any existing errors. */
+    if (err != 0 && result == 0)
+      result = err;
+
+    /* Remove the destination file if something went wrong. */
+    if (result != 0) {
+      uv_fs_unlink(NULL, &fs_req, req->new_path, NULL);
+      /* Ignore the unlink return value, as an error already happened. */
+      uv_fs_req_cleanup(&fs_req);
+    }
+  }
+
+  return result;
+#endif
+}
+
 static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
   dst->st_dev = src->st_dev;
   dst->st_mode = src->st_mode;
@@ -956,6 +1086,7 @@ static void uv__fs_work(struct uv__work* w) {
     X(CHMOD, chmod(req->path, req->mode));
     X(CHOWN, chown(req->path, req->uid, req->gid));
     X(CLOSE, close(req->file));
+    X(COPYFILE, uv__fs_copyfile(req));
     X(FCHMOD, fchmod(req->file, req->mode));
     X(FCHOWN, fchown(req->file, req->uid, req->gid));
     X(FDATASYNC, uv__fs_fdatasync(req));
@@ -1196,10 +1327,11 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
                unsigned int nbufs,
                int64_t off,
                uv_fs_cb cb) {
+  INIT(READ);
+
   if (bufs == NULL || nbufs == 0)
     return -EINVAL;
 
-  INIT(READ);
   req->file = file;
 
   req->nbufs = nbufs;
@@ -1334,10 +1466,11 @@ int uv_fs_write(uv_loop_t* loop,
                 unsigned int nbufs,
                 int64_t off,
                 uv_fs_cb cb) {
+  INIT(WRITE);
+
   if (bufs == NULL || nbufs == 0)
     return -EINVAL;
 
-  INIT(WRITE);
   req->file = file;
 
   req->nbufs = nbufs;
@@ -1359,6 +1492,9 @@ int uv_fs_write(uv_loop_t* loop,
 
 
 void uv_fs_req_cleanup(uv_fs_t* req) {
+  if (req == NULL)
+    return;
+
   /* Only necessary for asychronous requests, i.e., requests with a callback.
    * Synchronous ones don't copy their arguments and have req->path and
    * req->new_path pointing to user-owned memory.  UV_FS_MKDTEMP is the
@@ -1377,3 +1513,20 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
     uv__free(req->ptr);
   req->ptr = NULL;
 }
+
+
+int uv_fs_copyfile(uv_loop_t* loop,
+                   uv_fs_t* req,
+                   const char* path,
+                   const char* new_path,
+                   int flags,
+                   uv_fs_cb cb) {
+  INIT(COPYFILE);
+
+  if (flags & ~UV_FS_COPYFILE_EXCL)
+    return -EINVAL;
+
+  PATH2;
+  req->flags = flags;
+  POST;
+}

+ 23 - 5
Utilities/cmlibuv/src/unix/fsevents.c

@@ -230,6 +230,7 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
   uv_loop_t* loop;
   uv__cf_loop_state_t* state;
   uv__fsevents_event_t* event;
+  FSEventStreamEventFlags flags;
   QUEUE head;
 
   loop = info;
@@ -245,8 +246,10 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
 
     /* Process and filter out events */
     for (i = 0; i < numEvents; i++) {
+      flags = eventFlags[i];
+
       /* Ignore system events */
-      if (eventFlags[i] & kFSEventsSystem)
+      if (flags & kFSEventsSystem)
         continue;
 
       path = paths[i];
@@ -271,6 +274,9 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
       /* Ignore events with path equal to directory itself */
       if (len == 0)
         continue;
+#else
+      if (len == 0 && (flags & kFSEventStreamEventFlagItemIsDir))
+        continue;
 #endif /* MAC_OS_X_VERSION_10_7 */
 
       /* Do not emit events from subdirectories (without option set) */
@@ -291,12 +297,24 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
 
       memset(event, 0, sizeof(*event));
       memcpy(event->path, path, len + 1);
+      event->events = UV_RENAME;
 
-      if ((eventFlags[i] & kFSEventsModified) != 0 &&
-          (eventFlags[i] & kFSEventsRenamed) == 0)
+#ifdef MAC_OS_X_VERSION_10_7
+      if (0 != (flags & kFSEventsModified) &&
+          0 == (flags & kFSEventsRenamed)) {
+        event->events = UV_CHANGE;
+      }
+#else
+      if (0 != (flags & kFSEventsModified) &&
+          0 != (flags & kFSEventStreamEventFlagItemIsDir) &&
+          0 == (flags & kFSEventStreamEventFlagItemRenamed)) {
         event->events = UV_CHANGE;
-      else
-        event->events = UV_RENAME;
+      }
+      if (0 == (flags & kFSEventStreamEventFlagItemIsDir) &&
+          0 == (flags & kFSEventStreamEventFlagItemRenamed)) {
+        event->events = UV_CHANGE;
+      }
+#endif /* MAC_OS_X_VERSION_10_7 */
 
       QUEUE_INSERT_TAIL(&head, &event->member);
     }

+ 30 - 0
Utilities/cmlibuv/src/unix/getaddrinfo.c

@@ -32,6 +32,7 @@
 #include <stddef.h> /* NULL */
 #include <stdlib.h>
 #include <string.h>
+#include <net/if.h> /* if_indextoname() */
 
 /* EAI_* constants. */
 #include <netdb.h>
@@ -200,3 +201,32 @@ void uv_freeaddrinfo(struct addrinfo* ai) {
   if (ai)
     freeaddrinfo(ai);
 }
+
+
+int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
+  char ifname_buf[UV_IF_NAMESIZE];
+  size_t len;
+
+  if (buffer == NULL || size == NULL || *size == 0)
+    return UV_EINVAL;
+
+  if (if_indextoname(ifindex, ifname_buf) == NULL)
+    return -errno;
+
+  len = strnlen(ifname_buf, sizeof(ifname_buf));
+
+  if (*size <= len) {
+    *size = len + 1;
+    return UV_ENOBUFS;
+  }
+
+  memcpy(buffer, ifname_buf, len);
+  buffer[len] = '\0';
+  *size = len;
+
+  return 0;
+}
+
+int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
+  return uv_if_indextoname(ifindex, buffer, size);
+}

+ 112 - 0
Utilities/cmlibuv/src/unix/ibmi.c

@@ -0,0 +1,112 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <libgen.h>
+
+#include <sys/protosw.h>
+#include <procinfo.h>
+#include <sys/proc.h>
+#include <sys/procfs.h>
+
+#include <ctype.h>
+
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+#include <limits.h>
+#include <strings.h>
+#include <sys/vnode.h>
+
+uint64_t uv_get_free_memory(void) {
+  return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+  return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
+}
+
+
+void uv_loadavg(double avg[3]) {
+    avg[0] = avg[1] = avg[2] = 0;
+    return;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+  return UV_ENOSYS;
+}
+
+
+int uv_uptime(double* uptime) {
+  return UV_ENOSYS;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+  unsigned int numcpus, idx = 0;
+  uv_cpu_info_t* cpu_info;
+
+  *cpu_infos = NULL;
+  *count = 0;
+
+  numcpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+  *cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t));
+  if (!*cpu_infos) {
+    return -ENOMEM;
+  }
+
+  cpu_info = *cpu_infos;
+  for (idx = 0; idx < numcpus; idx++) {
+    cpu_info->speed = 0;
+    cpu_info->model = uv__strdup("unknown");
+    cpu_info->cpu_times.user = 0;
+    cpu_info->cpu_times.sys = 0;
+    cpu_info->cpu_times.idle = 0;
+    cpu_info->cpu_times.irq = 0;
+    cpu_info->cpu_times.nice = 0;
+    cpu_info++;
+  }
+  *count = numcpus;
+
+  return 0;
+}

+ 14 - 1
Utilities/cmlibuv/src/unix/internal.h

@@ -120,6 +120,12 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
 # define UV__POLLRDHUP 0x2000
 #endif
 
+#ifdef POLLPRI
+# define UV__POLLPRI POLLPRI
+#else
+# define UV__POLLPRI 0
+#endif
+
 #if !defined(O_CLOEXEC) && defined(__FreeBSD__)
 /*
  * It may be that we are just missing `__POSIX_VISIBLE >= 200809`.
@@ -155,6 +161,12 @@ enum {
   UV_LOOP_BLOCK_SIGPROF = 1
 };
 
+/* flags of excluding ifaddr */
+enum {
+  UV__EXCLUDE_IFPHYS,
+  UV__EXCLUDE_IFADDR
+};
+
 typedef enum {
   UV_CLOCK_PRECISE = 0,  /* Use the highest resolution clock available. */
   UV_CLOCK_FAST = 1      /* Use the fastest clock with <= 1ms granularity. */
@@ -173,7 +185,8 @@ struct uv__stream_queued_fds_s {
     defined(__FreeBSD__) || \
     defined(__FreeBSD_kernel__) || \
     defined(__linux__) || \
-    defined(__OpenBSD__)
+    defined(__OpenBSD__) || \
+    defined(__NetBSD__)
 #define uv__cloexec uv__cloexec_ioctl
 #define uv__nonblock uv__nonblock_ioctl
 #else

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

@@ -34,6 +34,17 @@
 #include <fcntl.h>
 #include <time.h>
 
+/*
+ * Required on
+ * - Until at least FreeBSD 11.0
+ * - Older versions of Mac OS X
+ *
+ * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp
+ */
+#ifndef EV_OOBAND
+#define EV_OOBAND  EV_FLAG1
+#endif
+
 static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
 
 
@@ -48,11 +59,12 @@ int uv__kqueue_init(uv_loop_t* loop) {
 }
 
 
+#if defined(__APPLE__)
 static int uv__has_forked_with_cfrunloop;
+#endif
 
 int uv__io_fork(uv_loop_t* loop) {
   int err;
-  uv__close(loop->backend_fd);
   loop->backend_fd = -1;
   err = uv__kqueue_init(loop);
   if (err)
@@ -166,6 +178,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
       }
     }
 
+   if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) {
+      EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0);
+
+      if (++nevents == ARRAY_SIZE(events)) {
+        if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
+          abort();
+        nevents = 0;
+      }
+    }
+
     w->events = w->pevents;
   }
 
@@ -275,6 +297,20 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
         }
       }
 
+      if (ev->filter == EV_OOBAND) {
+        if (w->pevents & UV__POLLPRI) {
+          revents |= UV__POLLPRI;
+          w->rcount = ev->data;
+        } else {
+          /* TODO batch up */
+          struct kevent events[1];
+          EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
+          if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
+            if (errno != ENOENT)
+              abort();
+        }
+      }
+
       if (ev->filter == EVFILT_WRITE) {
         if (w->pevents & POLLOUT) {
           revents |= POLLOUT;

+ 7 - 7
Utilities/cmlibuv/src/unix/linux-core.c

@@ -388,7 +388,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
        * free when we switch over to edge-triggered I/O.
        */
       if (pe->events == POLLERR || pe->events == POLLHUP)
-        pe->events |= w->pevents & (POLLIN | POLLOUT);
+        pe->events |= w->pevents & (POLLIN | POLLOUT | UV__POLLPRI);
 
       if (pe->events != 0) {
         /* Run signal watchers last.  This also affects child process watchers
@@ -837,7 +837,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
   uv__free(cpu_infos);
 }
 
-static int uv__ifaddr_exclude(struct ifaddrs *ent) {
+static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
   if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
     return 1;
   if (ent->ifa_addr == NULL)
@@ -847,8 +847,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) {
    * devices. We're not interested in this information yet.
    */
   if (ent->ifa_addr->sa_family == PF_PACKET)
-    return 1;
-  return 0;
+    return exclude_type;
+  return !exclude_type;
 }
 
 int uv_interface_addresses(uv_interface_address_t** addresses,
@@ -869,7 +869,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
 
   /* Count the number of interfaces */
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (uv__ifaddr_exclude(ent))
+    if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
       continue;
 
     (*count)++;
@@ -887,7 +887,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
   address = *addresses;
 
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (uv__ifaddr_exclude(ent))
+    if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
       continue;
 
     address->name = uv__strdup(ent->ifa_name);
@@ -911,7 +911,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
 
   /* Fill in physical addresses for each interface */
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (uv__ifaddr_exclude(ent))
+    if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
       continue;
 
     address = *addresses;

+ 1 - 1
Utilities/cmlibuv/src/unix/loop.c

@@ -31,7 +31,6 @@ int uv_loop_init(uv_loop_t* loop) {
   void* saved_data;
   int err;
 
-  uv__signal_global_once_init();
 
   saved_data = loop->data;
   memset(loop, 0, sizeof(*loop));
@@ -68,6 +67,7 @@ int uv_loop_init(uv_loop_t* loop) {
   if (err)
     return err;
 
+  uv__signal_global_once_init();
   err = uv_signal_init(loop, &loop->child_watcher);
   if (err)
     goto fail_signal_init;

+ 47 - 10
Utilities/cmlibuv/src/unix/netbsd.c

@@ -40,9 +40,16 @@
 #include <unistd.h>
 #include <time.h>
 
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
 static char *process_title;
 
 
+static void init_process_title_mutex_once(void) {
+  uv_mutex_init(&process_title_mutex);
+}
+
+
 int uv__platform_loop_init(uv_loop_t* loop) {
   return uv__kqueue_init(loop);
 }
@@ -66,22 +73,32 @@ void uv_loadavg(double avg[3]) {
 
 
 int uv_exepath(char* buffer, size_t* size) {
+  /* Intermediate buffer, retrieving partial path name does not work
+   * As of NetBSD-8(beta), vnode->path translator does not handle files
+   * with longer names than 31 characters.
+   */
+  char int_buf[PATH_MAX];
+  size_t int_size;
   int mib[4];
-  size_t cb;
-  pid_t mypid;
 
   if (buffer == NULL || size == NULL || *size == 0)
     return -EINVAL;
 
-  mypid = getpid();
   mib[0] = CTL_KERN;
   mib[1] = KERN_PROC_ARGS;
-  mib[2] = mypid;
-  mib[3] = KERN_PROC_ARGV;
+  mib[2] = -1;
+  mib[3] = KERN_PROC_PATHNAME;
+  int_size = ARRAY_SIZE(int_buf);
 
-  cb = *size;
-  if (sysctl(mib, 4, buffer, &cb, NULL, 0))
+  if (sysctl(mib, 4, int_buf, &int_size, NULL, 0))
     return -errno;
+
+  /* Copy string from the intermediate buffer to outer one with appropriate
+   * length.
+   */
+  strlcpy(buffer, int_buf, *size);
+
+  /* Set new size. */
   *size = strlen(buffer);
 
   return 0;
@@ -124,11 +141,24 @@ char** uv_setup_args(int argc, char** argv) {
 
 
 int uv_set_process_title(const char* title) {
-  if (process_title) uv__free(process_title);
+  char* new_title;
+
+  new_title = uv__strdup(title);
+
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+  uv_mutex_lock(&process_title_mutex);
 
-  process_title = uv__strdup(title);
+  if (process_title == NULL) {
+    uv_mutex_unlock(&process_title_mutex);
+    return -ENOMEM;
+  }
+
+  uv__free(process_title);
+  process_title = new_title;
   setproctitle("%s", title);
 
+  uv_mutex_unlock(&process_title_mutex);
+
   return 0;
 }
 
@@ -139,17 +169,24 @@ int uv_get_process_title(char* buffer, size_t size) {
   if (buffer == NULL || size == 0)
     return -EINVAL;
 
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+  uv_mutex_lock(&process_title_mutex);
+
   if (process_title) {
     len = strlen(process_title) + 1;
 
-    if (size < len)
+    if (size < len) {
+      uv_mutex_unlock(&process_title_mutex);
       return -ENOBUFS;
+    }
 
     memcpy(buffer, process_title, len);
   } else {
     len = 0;
   }
 
+  uv_mutex_unlock(&process_title_mutex);
+
   buffer[len] = '\0';
 
   return 0;

+ 31 - 2
Utilities/cmlibuv/src/unix/openbsd.c

@@ -36,9 +36,16 @@
 #include <unistd.h>
 
 
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
 static char *process_title;
 
 
+static void init_process_title_mutex_once(void) {
+  uv_mutex_init(&process_title_mutex);
+}
+
+
 int uv__platform_loop_init(uv_loop_t* loop) {
   return uv__kqueue_init(loop);
 }
@@ -146,9 +153,24 @@ char** uv_setup_args(int argc, char** argv) {
 
 
 int uv_set_process_title(const char* title) {
+  char* new_title;
+
+  new_title = uv__strdup(title);
+
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+  uv_mutex_lock(&process_title_mutex);
+
+  if (process_title == NULL) {
+    uv_mutex_unlock(&process_title_mutex);
+    return -ENOMEM;
+  }
+
   uv__free(process_title);
-  process_title = uv__strdup(title);
+  process_title = new_title;
   setproctitle("%s", title);
+
+  uv_mutex_unlock(&process_title_mutex);
+
   return 0;
 }
 
@@ -159,17 +181,24 @@ int uv_get_process_title(char* buffer, size_t size) {
   if (buffer == NULL || size == 0)
     return -EINVAL;
 
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+  uv_mutex_lock(&process_title_mutex);
+
   if (process_title) {
     len = strlen(process_title) + 1;
 
-    if (size < len)
+    if (size < len) {
+      uv_mutex_unlock(&process_title_mutex);
       return -ENOBUFS;
+    }
 
     memcpy(buffer, process_title, len);
   } else {
     len = 0;
   }
 
+  uv_mutex_unlock(&process_title_mutex);
+
   buffer[len] = '\0';
 
   return 0;

+ 197 - 32
Utilities/cmlibuv/src/unix/os390-syscalls.c

@@ -25,6 +25,8 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <search.h>
+#include <termios.h>
+#include <sys/msg.h>
 
 #define CW_CONDVAR 32
 
@@ -103,10 +105,19 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
   unsigned int newsize;
   unsigned int i;
   struct pollfd* newlst;
+  struct pollfd event;
 
   if (len <= lst->size)
     return;
 
+  if (lst->size == 0)
+    event.fd = -1;
+  else {
+    /* Extract the message queue at the end. */
+    event = lst->items[lst->size - 1];
+    lst->items[lst->size - 1].fd = -1;
+  }
+
   newsize = next_power_of_two(len);
   newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0]));
 
@@ -115,32 +126,101 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
   for (i = lst->size; i < newsize; ++i)
     newlst[i].fd = -1;
 
+  /* Restore the message queue at the end */
+  newlst[newsize - 1] = event;
+
   lst->items = newlst;
   lst->size = newsize;
 }
 
 
+static void init_message_queue(uv__os390_epoll* lst) {
+  struct {
+    long int header;
+    char body;
+  } msg;
+
+  /* initialize message queue */
+  lst->msg_queue = msgget(IPC_PRIVATE, 0622 | IPC_CREAT);
+  if (lst->msg_queue == -1)
+    abort();
+
+  /*
+     On z/OS, the message queue will be affiliated with the process only
+     when a send is performed on it. Once this is done, the system
+     can be queried for all message queues belonging to our process id.
+  */
+  msg.header = 1;
+  if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0)
+    abort();
+
+  /* Clean up the dummy message sent above */
+  if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body))
+    abort();
+}
+
+
+static void before_fork(void) {
+  uv_mutex_lock(&global_epoll_lock);
+}
+
+
+static void after_fork(void) {
+  uv_mutex_unlock(&global_epoll_lock);
+}
+
+
+static void child_fork(void) {
+  QUEUE* q;
+  uv_once_t child_once = UV_ONCE_INIT;
+
+  /* reset once */
+  memcpy(&once, &child_once, sizeof(child_once));
+
+  /* reset epoll list */
+  while (!QUEUE_EMPTY(&global_epoll_queue)) {
+    uv__os390_epoll* lst;
+    q = QUEUE_HEAD(&global_epoll_queue);
+    QUEUE_REMOVE(q);
+    lst = QUEUE_DATA(q, uv__os390_epoll, member);
+    uv__free(lst->items);
+    lst->items = NULL;
+    lst->size = 0;
+  }
+
+  uv_mutex_unlock(&global_epoll_lock);
+  uv_mutex_destroy(&global_epoll_lock);
+}
+
+
 static void epoll_init(void) {
   QUEUE_INIT(&global_epoll_queue);
   if (uv_mutex_init(&global_epoll_lock))
     abort();
+
+  if (pthread_atfork(&before_fork, &after_fork, &child_fork))
+    abort();
 }
 
 
 uv__os390_epoll* epoll_create1(int flags) {
   uv__os390_epoll* lst;
 
-  uv_once(&once, epoll_init);
-  uv_mutex_lock(&global_epoll_lock);
   lst = uv__malloc(sizeof(*lst));
-  if (lst == -1)
-    return NULL;
-  QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
-  uv_mutex_unlock(&global_epoll_lock);
+  if (lst != NULL) {
+    /* initialize list */
+    lst->size = 0;
+    lst->items = NULL;
+    init_message_queue(lst);
+    maybe_resize(lst, 1);
+    lst->items[lst->size - 1].fd = lst->msg_queue;
+    lst->items[lst->size - 1].events = POLLIN;
+    uv_once(&once, epoll_init);
+    uv_mutex_lock(&global_epoll_lock);
+    QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
+    uv_mutex_unlock(&global_epoll_lock);
+  }
 
-  /* initialize list */
-  lst->size = 0;
-  lst->items = NULL;
   return lst;
 }
 
@@ -149,22 +229,32 @@ int epoll_ctl(uv__os390_epoll* lst,
               int op,
               int fd,
               struct epoll_event *event) {
-  if(op == EPOLL_CTL_DEL) {
+  uv_mutex_lock(&global_epoll_lock);
+
+  if (op == EPOLL_CTL_DEL) {
     if (fd >= lst->size || lst->items[fd].fd == -1) {
+      uv_mutex_unlock(&global_epoll_lock);
       errno = ENOENT;
       return -1;
     }
     lst->items[fd].fd = -1;
-  } else if(op == EPOLL_CTL_ADD) {
-    maybe_resize(lst, fd + 1);
+  } else if (op == EPOLL_CTL_ADD) {
+
+    /* Resizing to 'fd + 1' would expand the list to contain at least
+     * 'fd'. But we need to guarantee that the last index on the list 
+     * is reserved for the message queue. So specify 'fd + 2' instead.
+     */
+    maybe_resize(lst, fd + 2);
     if (lst->items[fd].fd != -1) {
+      uv_mutex_unlock(&global_epoll_lock);
       errno = EEXIST;
       return -1;
     }
     lst->items[fd].fd = fd;
     lst->items[fd].events = event->events;
-  } else if(op == EPOLL_CTL_MOD) {
+  } else if (op == EPOLL_CTL_MOD) {
     if (fd >= lst->size || lst->items[fd].fd == -1) {
+      uv_mutex_unlock(&global_epoll_lock);
       errno = ENOENT;
       return -1;
     }
@@ -172,44 +262,36 @@ int epoll_ctl(uv__os390_epoll* lst,
   } else
     abort();
 
+  uv_mutex_unlock(&global_epoll_lock);
   return 0;
 }
 
 
 int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
                int maxevents, int timeout) {
-  size_t size;
+  nmsgsfds_t size;
   struct pollfd* pfds;
   int pollret;
   int reventcount;
 
-  uv_mutex_lock(&global_epoll_lock);
-  uv_mutex_unlock(&global_epoll_lock);
-  size = lst->size;
+  size = _SET_FDS_MSGS(size, 1, lst->size - 1);
   pfds = lst->items;
   pollret = poll(pfds, size, timeout);
-  if(pollret == -1)
+  if (pollret <= 0)
     return pollret;
 
+  pollret = _NFDS(pollret) + _NMSGS(pollret);
+
   reventcount = 0;
-  for (int i = 0; i < lst->size && i < maxevents; ++i) {
+  for (int i = 0; 
+       i < lst->size && i < maxevents && reventcount < pollret; ++i) {
     struct epoll_event ev;
 
-    ev.events = 0;
-    ev.fd = pfds[i].fd;
-    if(!pfds[i].revents)
+    if (pfds[i].fd == -1 || pfds[i].revents == 0)
       continue;
 
-    if(pfds[i].revents & POLLRDNORM)
-      ev.events = ev.events | POLLIN;
-
-    if(pfds[i].revents & POLLWRNORM)
-      ev.events = ev.events | POLLOUT;
-
-    if(pfds[i].revents & POLLHUP)
-      ev.events = ev.events | POLLHUP;
-
-    pfds[i].revents = 0;
+    ev.fd = pfds[i].fd;
+    ev.events = pfds[i].revents;
     events[reventcount++] = ev;
   }
 
@@ -235,9 +317,14 @@ int epoll_file_close(int fd) {
 }
 
 void epoll_queue_close(uv__os390_epoll* lst) {
+  /* Remove epoll instance from global queue */
   uv_mutex_lock(&global_epoll_lock);
   QUEUE_REMOVE(&lst->member);
   uv_mutex_unlock(&global_epoll_lock);
+
+  /* Free resources */
+  msgctl(lst->msg_queue, IPC_RMID, NULL);
+  lst->msg_queue = -1;
   uv__free(lst->items);
   lst->items = NULL;
 }
@@ -332,3 +419,81 @@ char* mkdtemp(char* path) {
 
   return path;
 }
+
+
+ssize_t os390_readlink(const char* path, char* buf, size_t len) {
+  ssize_t rlen;
+  ssize_t vlen;
+  ssize_t plen;
+  char* delimiter;
+  char old_delim;
+  char* tmpbuf;
+  char realpathstr[PATH_MAX + 1];
+
+  tmpbuf = uv__malloc(len + 1);
+  if (tmpbuf == NULL) {
+    errno = ENOMEM;
+    return -1;
+  }
+
+  rlen = readlink(path, tmpbuf, len);
+  if (rlen < 0) {
+    uv__free(tmpbuf);
+    return rlen;
+  }
+
+  if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) {
+    /* Straightforward readlink. */
+    memcpy(buf, tmpbuf, rlen);
+    uv__free(tmpbuf);
+    return rlen;
+  }
+
+  /*
+   * There is a parmlib variable at the beginning
+   * which needs interpretation.
+   */
+  tmpbuf[rlen] = '\0';
+  delimiter = strchr(tmpbuf + 2, '/');
+  if (delimiter == NULL)
+    /* No slash at the end */
+    delimiter = strchr(tmpbuf + 2, '\0');
+
+  /* Read real path of the variable. */
+  old_delim = *delimiter;
+  *delimiter = '\0';
+  if (realpath(tmpbuf, realpathstr) == NULL) {
+    uv__free(tmpbuf);
+    return -1;
+  }
+
+  /* realpathstr is not guaranteed to end with null byte.*/
+  realpathstr[PATH_MAX] = '\0';
+
+  /* Reset the delimiter and fill up the buffer. */
+  *delimiter = old_delim;
+  plen = strlen(delimiter);
+  vlen = strlen(realpathstr);
+  rlen = plen + vlen;
+  if (rlen > len) {
+    uv__free(tmpbuf);
+    errno = ENAMETOOLONG;
+    return -1;
+  }
+  memcpy(buf, realpathstr, vlen);
+  memcpy(buf + vlen, delimiter, plen);
+
+  /* Done using temporary buffer. */
+  uv__free(tmpbuf);
+
+  return rlen;
+}
+
+
+size_t strnlen(const char* str, size_t maxlen) {
+  void* p = memchr(str, 0, maxlen);
+  if (p == NULL)
+    return maxlen;
+  else
+    return p - str;
+}

+ 3 - 0
Utilities/cmlibuv/src/unix/os390-syscalls.h

@@ -50,6 +50,7 @@ typedef struct {
   QUEUE member;
   struct pollfd* items;
   unsigned long size;
+  int msg_queue;
 } uv__os390_epoll;
 
 /* epoll api */
@@ -65,5 +66,7 @@ int scandir(const char* maindir, struct dirent*** namelist,
             int (*compar)(const struct dirent **,
             const struct dirent **));
 char *mkdtemp(char* path);
+ssize_t os390_readlink(const char* path, char* buf, size_t len);
+size_t strnlen(const char* str, size_t maxlen);
 
 #endif /* UV_OS390_SYSCALL_H_ */

+ 162 - 13
Utilities/cmlibuv/src/unix/os390.c

@@ -25,6 +25,9 @@
 #include <utmpx.h>
 #include <unistd.h>
 #include <sys/ps.h>
+#include <builtins.h>
+#include <termios.h>
+#include <sys/msg.h>
 #if defined(__clang__)
 #include "csrsic.h"
 #else
@@ -32,6 +35,7 @@
 #endif
 
 #define CVT_PTR           0x10
+#define PSA_PTR           0x00
 #define CSD_OFFSET        0x294
 
 /*
@@ -69,6 +73,18 @@
 /* CPC model length from the CSRSI Service. */
 #define CPCMODEL_LENGTH   16
 
+/* Pointer to the home (current) ASCB. */
+#define PSAAOLD           0x224
+
+/* Pointer to rsm address space block extension. */
+#define ASCBRSME          0x16C
+
+/*
+    NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE.
+    It does not include 2G frames.
+*/
+#define RAXFMCT           0x2C
+
 /* Thread Entry constants */
 #define PGTH_CURRENT  1
 #define PGTH_LEN      26
@@ -76,6 +92,9 @@
 #pragma linkage(BPX4GTH, OS)
 #pragma linkage(BPX1GTH, OS)
 
+/* TOD Clock resolution in nanoseconds */
+#define TOD_RES 4.096
+
 typedef unsigned data_area_ptr_assign_type;
 
 typedef union {
@@ -100,7 +119,7 @@ void uv_loadavg(double avg[3]) {
 int uv__platform_loop_init(uv_loop_t* loop) {
   uv__os390_epoll* ep;
 
-  ep = epoll_create1(UV__EPOLL_CLOEXEC);
+  ep = epoll_create1(0);
   loop->ep = ep;
   if (ep == NULL)
     return -errno;
@@ -118,9 +137,10 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
 
 
 uint64_t uv__hrtime(uv_clocktype_t type) {
-  struct timeval time;
-  gettimeofday(&time, NULL);
-  return (uint64_t) time.tv_sec * 1e9 + time.tv_usec * 1e3;
+  unsigned long long timestamp;
+  __stckf(&timestamp);
+  /* Convert to nanoseconds */
+  return timestamp / TOD_RES;
 }
 
 
@@ -337,13 +357,17 @@ uint64_t uv_get_total_memory(void) {
 
 
 int uv_resident_set_memory(size_t* rss) {
-  W_PSPROC buf;
+  char* psa;
+  char* ascb;
+  char* rax;
+  size_t nframes;
 
-  memset(&buf, 0, sizeof(buf));
-  if (w_getpsent(0, &buf, sizeof(W_PSPROC)) == -1)
-    return -EINVAL;
+  psa = PSA_PTR;
+  ascb  = *(char* __ptr32 *)(psa + PSAAOLD);
+  rax = *(char* __ptr32 *)(ascb + ASCBRSME);
+  nframes = *(unsigned int*)(rax + RAXFMCT);
 
-  *rss = buf.ps_size;
+  *rss = nframes * sysconf(_SC_PAGESIZE);
   return 0;
 }
 
@@ -364,7 +388,6 @@ int uv_uptime(double* uptime) {
 
 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
   uv_cpu_info_t* cpu_info;
-  int result;
   int idx;
   siv1v2 info;
   data_area_ptr cvt = {0};
@@ -663,11 +686,124 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) {
   return 0;
 }
 
+
+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) {
+  uv__os390_epoll* ep;
+  _RFIS reg_struct;
+  char* path;
+  int rc;
+
+  if (uv__is_active(handle))
+    return -EINVAL;
+
+  ep = handle->loop->ep;
+  assert(ep->msg_queue != -1);
+
+  reg_struct.__rfis_cmd  = _RFIS_REG;
+  reg_struct.__rfis_qid  = ep->msg_queue;
+  reg_struct.__rfis_type = 1;
+  memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle));
+
+  path = uv__strdup(filename);
+  if (path == NULL)
+    return -ENOMEM;
+
+  rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
+  if (rc != 0)
+    return -errno;
+
+  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) {
+  uv__os390_epoll* ep;
+  _RFIS reg_struct;
+  int rc;
+
+  if (!uv__is_active(handle))
+    return 0;
+
+  ep = handle->loop->ep;
+  assert(ep->msg_queue != -1);
+
+  reg_struct.__rfis_cmd  = _RFIS_UNREG;
+  reg_struct.__rfis_qid  = ep->msg_queue;
+  reg_struct.__rfis_type = 1;
+  memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok,
+         sizeof(handle->rfis_rftok));
+
+  /* 
+   * This call will take "/" as the path argument in case we
+   * don't care to supply the correct path. The system will simply
+   * ignore it.
+   */
+  rc = __w_pioctl("/", _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
+  if (rc != 0 && errno != EALREADY && errno != ENOENT)
+    abort();
+
+  uv__handle_stop(handle);
+
+  return 0;
+}
+
+
+static int os390_message_queue_handler(uv__os390_epoll* ep) {
+  uv_fs_event_t* handle;
+  int msglen;
+  int events;
+  _RFIM msg;
+
+  if (ep->msg_queue == -1)
+    return 0;
+
+  msglen = msgrcv(ep->msg_queue, &msg, sizeof(msg), 0, IPC_NOWAIT);
+
+  if (msglen == -1 && errno == ENOMSG)
+    return 0;
+
+  if (msglen == -1)
+    abort();
+
+  events = 0;
+  if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE)
+    events = UV_CHANGE;
+  else if (msg.__rfim_event == _RFIM_RENAME)
+    events = UV_RENAME;
+  else
+    /* Some event that we are not interested in. */
+    return 0;
+
+  handle = *(uv_fs_event_t**)(msg.__rfim_utok);
+  handle->cb(handle, uv__basename_r(handle->path), events, 0);
+  return 1;
+}
+
+
 void uv__io_poll(uv_loop_t* loop, int timeout) {
   static const int max_safe_timeout = 1789569;
   struct epoll_event events[1024];
   struct epoll_event* pe;
   struct epoll_event e;
+  uv__os390_epoll* ep;
   int real_timeout;
   QUEUE* q;
   uv__io_t* w;
@@ -745,9 +881,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
     SAVE_ERRNO(uv__update_time(loop));
     if (nfds == 0) {
       assert(timeout != -1);
-      timeout = real_timeout - timeout;
-      if (timeout > 0)
+
+      if (timeout > 0) {
+        timeout = real_timeout - timeout;
         continue;
+      }
 
       return;
     }
@@ -779,6 +917,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
       if (fd == -1)
         continue;
 
+      ep = loop->ep;
+      if (fd == ep->msg_queue) {
+        os390_message_queue_handler(ep);
+        continue;
+      }
+
       assert(fd >= 0);
       assert((unsigned) fd < loop->nwatchers);
 
@@ -843,7 +987,12 @@ void uv__set_process_title(const char* title) {
 }
 
 int uv__io_fork(uv_loop_t* loop) {
-  uv__platform_loop_delete(loop);
+  /* 
+    Nullify the msg queue but don't close it because
+    it is still being used by the parent.
+  */
+  loop->ep = NULL;
 
+  uv__platform_loop_delete(loop);
   return uv__platform_loop_init(loop);
 }

+ 53 - 0
Utilities/cmlibuv/src/unix/pipe.c

@@ -300,3 +300,56 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
   else
     return uv__handle_type(handle->accepted_fd);
 }
+
+
+int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
+  unsigned desired_mode;
+  struct stat pipe_stat;
+  char* name_buffer;
+  size_t name_len;
+  int r;
+
+  if (handle == NULL || uv__stream_fd(handle) == -1)
+    return -EBADF;
+
+  if (mode != UV_READABLE &&
+      mode != UV_WRITABLE &&
+      mode != (UV_WRITABLE | UV_READABLE))
+    return -EINVAL;
+
+  if (fstat(uv__stream_fd(handle), &pipe_stat) == -1)
+    return -errno;
+
+  desired_mode = 0;
+  if (mode & UV_READABLE)
+    desired_mode |= S_IRUSR | S_IRGRP | S_IROTH;
+  if (mode & UV_WRITABLE)
+    desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
+
+  /* Exit early if pipe already has desired mode. */
+  if ((pipe_stat.st_mode & desired_mode) == desired_mode)
+    return 0;
+
+  pipe_stat.st_mode |= desired_mode;
+
+  /* Unfortunately fchmod does not work on all platforms, we will use chmod. */
+  name_len = 0;
+  r = uv_pipe_getsockname(handle, NULL, &name_len);
+  if (r != UV_ENOBUFS)
+    return r;
+
+  name_buffer = uv__malloc(name_len);
+  if (name_buffer == NULL)
+    return UV_ENOMEM;
+
+  r = uv_pipe_getsockname(handle, name_buffer, &name_len);
+  if (r != 0) {
+    uv__free(name_buffer);
+    return r;
+  }
+
+  r = chmod(name_buffer, pipe_stat.st_mode);
+  uv__free(name_buffer);
+
+  return r != -1 ? 0 : -errno;
+}

+ 21 - 4
Utilities/cmlibuv/src/unix/poll.c

@@ -33,8 +33,19 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
 
   handle = container_of(w, uv_poll_t, io_watcher);
 
-  if (events & POLLERR) {
-    uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP);
+  /*
+   * As documented in the kernel source fs/kernfs/file.c #780
+   * poll will return POLLERR|POLLPRI in case of sysfs
+   * polling. This does not happen in case of out-of-band
+   * TCP messages.
+   *
+   * The above is the case on (at least) FreeBSD and Linux.
+   *
+   * So to properly determine a POLLPRI or a POLLERR we need
+   * to check for both.
+   */
+  if ((events & POLLERR) && !(events & UV__POLLPRI)) {
+    uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
     uv__handle_stop(handle);
     handle->poll_cb(handle, -EBADF, 0);
     return;
@@ -43,6 +54,8 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
   pevents = 0;
   if (events & POLLIN)
     pevents |= UV_READABLE;
+  if (events & UV__POLLPRI)
+    pevents |= UV_PRIORITIZED;
   if (events & POLLOUT)
     pevents |= UV_WRITABLE;
   if (events & UV__POLLRDHUP)
@@ -86,8 +99,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
 static void uv__poll_stop(uv_poll_t* handle) {
   uv__io_stop(handle->loop,
               &handle->io_watcher,
-              POLLIN | POLLOUT | UV__POLLRDHUP);
+              POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
   uv__handle_stop(handle);
+  uv__platform_invalidate_fd(handle->loop, handle->io_watcher.fd);
 }
 
 
@@ -101,7 +115,8 @@ int uv_poll_stop(uv_poll_t* handle) {
 int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
   int events;
 
-  assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
+  assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
+                      UV_PRIORITIZED)) == 0);
   assert(!uv__is_closing(handle));
 
   uv__poll_stop(handle);
@@ -112,6 +127,8 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
   events = 0;
   if (pevents & UV_READABLE)
     events |= POLLIN;
+  if (pevents & UV_PRIORITIZED)
+    events |= UV__POLLPRI;
   if (pevents & UV_WRITABLE)
     events |= POLLOUT;
   if (pevents & UV_DISCONNECT)

+ 39 - 3
Utilities/cmlibuv/src/unix/process.c

@@ -279,9 +279,12 @@ static void uv__process_child_init(const uv_process_options_t* options,
                                    int stdio_count,
                                    int (*pipes)[2],
                                    int error_fd) {
+  sigset_t set;
   int close_fd;
   int use_fd;
+  int err;
   int fd;
+  int n;
 
   if (options->flags & UV_PROCESS_DETACHED)
     setsid();
@@ -376,6 +379,31 @@ static void uv__process_child_init(const uv_process_options_t* options,
     environ = options->env;
   }
 
+  /* Reset signal disposition.  Use a hard-coded limit because NSIG
+   * is not fixed on Linux: it's either 32, 34 or 64, depending on
+   * whether RT signals are enabled.  We are not allowed to touch
+   * RT signal handlers, glibc uses them internally.
+   */
+  for (n = 1; n < 32; n += 1) {
+    if (n == SIGKILL || n == SIGSTOP)
+      continue;  /* Can't be changed. */
+
+    if (SIG_ERR != signal(n, SIG_DFL))
+      continue;
+
+    uv__write_int(error_fd, -errno);
+    _exit(127);
+  }
+
+  /* Reset signal mask. */
+  sigemptyset(&set);
+  err = pthread_sigmask(SIG_SETMASK, &set, NULL);
+
+  if (err != 0) {
+    uv__write_int(error_fd, -err);
+    _exit(127);
+  }
+
   execvp(options->file, options->args);
   uv__write_int(error_fd, -errno);
   _exit(127);
@@ -391,6 +419,7 @@ int uv_spawn(uv_loop_t* loop,
   return -ENOSYS;
 #else
   int signal_pipe[2] = { -1, -1 };
+  int pipes_storage[8][2];
   int (*pipes)[2];
   int stdio_count;
   ssize_t r;
@@ -415,7 +444,10 @@ int uv_spawn(uv_loop_t* loop,
     stdio_count = 3;
 
   err = -ENOMEM;
-  pipes = uv__malloc(stdio_count * sizeof(*pipes));
+  pipes = pipes_storage;
+  if (stdio_count > (int) ARRAY_SIZE(pipes_storage))
+    pipes = uv__malloc(stdio_count * sizeof(*pipes));
+
   if (pipes == NULL)
     goto error;
 
@@ -520,7 +552,9 @@ int uv_spawn(uv_loop_t* loop,
   process->pid = pid;
   process->exit_cb = options->exit_cb;
 
-  uv__free(pipes);
+  if (pipes != pipes_storage)
+    uv__free(pipes);
+
   return exec_errorno;
 
 error:
@@ -534,7 +568,9 @@ error:
       if (pipes[i][1] != -1)
         uv__close_nocheckstdio(pipes[i][1]);
     }
-    uv__free(pipes);
+
+    if (pipes != pipes_storage)
+      uv__free(pipes);
   }
 
   return err;

+ 28 - 7
Utilities/cmlibuv/src/unix/proctitle.c

@@ -26,6 +26,8 @@
 
 extern void uv__set_process_title(const char* title);
 
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
 static void* args_mem;
 
 static struct {
@@ -34,6 +36,11 @@ static struct {
 } process_title;
 
 
+static void init_process_title_mutex_once(void) {
+  uv_mutex_init(&process_title_mutex);
+}
+
+
 char** uv_setup_args(int argc, char** argv) {
   char** new_argv;
   size_t size;
@@ -81,12 +88,16 @@ char** uv_setup_args(int argc, char** argv) {
 
 
 int uv_set_process_title(const char* title) {
-  if (process_title.len == 0)
-    return 0;
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+  uv_mutex_lock(&process_title_mutex);
+
+  if (process_title.len != 0) {
+    /* No need to terminate, byte after is always '\0'. */
+    strncpy(process_title.str, title, process_title.len);
+    uv__set_process_title(title);
+  }
 
-  /* No need to terminate, byte after is always '\0'. */
-  strncpy(process_title.str, title, process_title.len);
-  uv__set_process_title(title);
+  uv_mutex_unlock(&process_title_mutex);
 
   return 0;
 }
@@ -95,12 +106,22 @@ int uv_set_process_title(const char* title) {
 int uv_get_process_title(char* buffer, size_t size) {
   if (buffer == NULL || size == 0)
     return -EINVAL;
-  else if (size <= process_title.len)
+
+  uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+  uv_mutex_lock(&process_title_mutex);
+
+  if (size <= process_title.len) {
+    uv_mutex_unlock(&process_title_mutex);
     return -ENOBUFS;
+  }
+
+  if (process_title.len != 0)
+    memcpy(buffer, process_title.str, process_title.len + 1);
 
-  memcpy(buffer, process_title.str, process_title.len + 1);
   buffer[process_title.len] = '\0';
 
+  uv_mutex_unlock(&process_title_mutex);
+
   return 0;
 }
 

+ 0 - 121
Utilities/cmlibuv/src/unix/pthread-barrier.c

@@ -1,121 +0,0 @@
-/*
-Copyright (c) 2016, Kari Tristan Helgason <[email protected]>
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-#include "uv-common.h"
-#include "pthread-barrier.h"
-
-#include <stdlib.h>
-#include <assert.h>
-
-/* TODO: support barrier_attr */
-int pthread_barrier_init(pthread_barrier_t* barrier,
-                         const void* barrier_attr,
-                         unsigned count) {
-  int rc;
-  _uv_barrier* b;
-
-  if (barrier == NULL || count == 0)
-    return EINVAL;
-
-  if (barrier_attr != NULL)
-    return ENOTSUP;
-
-  b = uv__malloc(sizeof(*b));
-  if (b == NULL)
-    return ENOMEM;
-
-  b->in = 0;
-  b->out = 0;
-  b->threshold = count;
-
-  if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
-    goto error2;
-  if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
-    goto error;
-
-  barrier->b = b;
-  return 0;
-
-error:
-  pthread_mutex_destroy(&b->mutex);
-error2:
-  uv__free(b);
-  return rc;
-}
-
-int pthread_barrier_wait(pthread_barrier_t* barrier) {
-  int rc;
-  _uv_barrier* b;
-
-  if (barrier == NULL || barrier->b == NULL)
-    return EINVAL;
-
-  b = barrier->b;
-  /* Lock the mutex*/
-  if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
-    return rc;
-
-  /* Increment the count. If this is the first thread to reach the threshold,
-     wake up waiters, unlock the mutex, then return
-     PTHREAD_BARRIER_SERIAL_THREAD. */
-  if (++b->in == b->threshold) {
-    b->in = 0;
-    b->out = b->threshold - 1;
-    rc = pthread_cond_signal(&b->cond);
-    assert(rc == 0);
-
-    pthread_mutex_unlock(&b->mutex);
-    return PTHREAD_BARRIER_SERIAL_THREAD;
-  }
-  /* Otherwise, wait for other threads until in is set to 0,
-     then return 0 to indicate this is not the first thread. */
-  do {
-    if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0)
-      break;
-  } while (b->in != 0);
-
-  /* mark thread exit */
-  b->out--;
-  pthread_cond_signal(&b->cond);
-  pthread_mutex_unlock(&b->mutex);
-  return rc;
-}
-
-int pthread_barrier_destroy(pthread_barrier_t* barrier) {
-  int rc;
-  _uv_barrier* b;
-
-  if (barrier == NULL || barrier->b == NULL)
-    return EINVAL;
-
-  b = barrier->b;
-
-  if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
-    return rc;
-
-  if (b->in > 0 || b->out > 0)
-    rc = EBUSY;
-
-  pthread_mutex_unlock(&b->mutex);
-
-  if (rc)
-    return rc;
-
-  pthread_cond_destroy(&b->cond);
-  pthread_mutex_destroy(&b->mutex);
-  uv__free(barrier->b);
-  barrier->b = NULL;
-  return 0;
-}

+ 26 - 13
Utilities/cmlibuv/src/unix/stream.c

@@ -514,7 +514,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
   int err;
 
   stream = container_of(w, uv_stream_t, io_watcher);
-  assert(events == POLLIN);
+  assert(events & POLLIN);
   assert(stream->accepted_fd == -1);
   assert(!(stream->flags & UV_CLOSING));
 
@@ -750,6 +750,7 @@ static void uv__write(uv_stream_t* stream) {
   int iovmax;
   int iovcnt;
   ssize_t n;
+  int err;
 
 start:
 
@@ -782,14 +783,21 @@ start:
    */
 
   if (req->send_handle) {
+    int fd_to_send;
     struct msghdr msg;
     struct cmsghdr *cmsg;
-    int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
     union {
       char data[64];
       struct cmsghdr alias;
     } scratch;
 
+    if (uv__is_closing(req->send_handle)) {
+      err = -EBADF;
+      goto error;
+    }
+
+    fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
+
     memset(&scratch, 0, sizeof(scratch));
 
     assert(fd_to_send >= 0);
@@ -851,15 +859,9 @@ start:
   }
 
   if (n < 0) {
-    if (errno != EAGAIN && errno != EWOULDBLOCK) {
-      /* Error */
-      req->error = -errno;
-      uv__write_req_finish(req);
-      uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
-      if (!uv__io_active(&stream->io_watcher, POLLIN))
-        uv__handle_stop(stream);
-      uv__stream_osx_interrupt_select(stream);
-      return;
+    if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENOBUFS) {
+      err = -errno;
+      goto error;
     } else if (stream->flags & UV_STREAM_BLOCKING) {
       /* If this is a blocking stream, try again. */
       goto start;
@@ -923,6 +925,16 @@ start:
 
   /* Notify select() thread about state change */
   uv__stream_osx_interrupt_select(stream);
+
+  return;
+
+error:
+  req->error = err;
+  uv__write_req_finish(req);
+  uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
+  if (!uv__io_active(&stream->io_watcher, POLLIN))
+    uv__handle_stop(stream);
+  uv__stream_osx_interrupt_select(stream);
 }
 
 
@@ -1249,8 +1261,9 @@ static void uv__read(uv_stream_t* stream) {
 
 
 int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
-  assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) &&
-         "uv_shutdown (unix) only supports uv_handle_t right now");
+  assert(stream->type == UV_TCP ||
+         stream->type == UV_TTY ||
+         stream->type == UV_NAMED_PIPE);
 
   if (!(stream->flags & UV_STREAM_WRITABLE) ||
       stream->flags & UV_STREAM_SHUT ||

+ 2 - 2
Utilities/cmlibuv/src/unix/sunos.c

@@ -751,7 +751,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) {
     return 1;
   if (ent->ifa_addr == NULL)
     return 1;
-  if (ent->ifa_addr->sa_family == PF_PACKET)
+  if (ent->ifa_addr->sa_family != AF_INET &&
+      ent->ifa_addr->sa_family != AF_INET6)
     return 1;
   return 0;
 }
@@ -760,7 +761,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   uv_interface_address_t* address;
   struct ifaddrs* addrs;
   struct ifaddrs* ent;
-  int i;
 
   if (getifaddrs(&addrs))
     return -errno;

+ 75 - 26
Utilities/cmlibuv/src/unix/tcp.c

@@ -28,15 +28,12 @@
 #include <errno.h>
 
 
-static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
+static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
+  struct sockaddr_storage saddr;
+  socklen_t slen;
   int sockfd;
   int err;
 
-  if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) {
-    handle->flags |= flags;
-    return 0;
-  }
-
   err = uv__socket(domain, SOCK_STREAM, 0);
   if (err < 0)
     return err;
@@ -48,10 +45,74 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
     return err;
   }
 
+  if (flags & UV_HANDLE_BOUND) {
+    /* Bind this new socket to an arbitrary port */
+    slen = sizeof(saddr);
+    memset(&saddr, 0, sizeof(saddr));
+    err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen);
+    if (err) {
+      uv__close(sockfd);
+      return err;
+    }
+
+    err = bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen);
+    if (err) {
+      uv__close(sockfd);
+      return err;
+    }
+  }
+
   return 0;
 }
 
 
+static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
+  struct sockaddr_storage saddr;
+  socklen_t slen;
+
+  if (domain == AF_UNSPEC) {
+    handle->flags |= flags;
+    return 0;
+  }
+
+  if (uv__stream_fd(handle) != -1) {
+
+    if (flags & UV_HANDLE_BOUND) {
+
+      if (handle->flags & UV_HANDLE_BOUND) {
+        /* It is already bound to a port. */
+        handle->flags |= flags;
+        return 0;
+      }
+      
+      /* Query to see if tcp socket is bound. */
+      slen = sizeof(saddr);
+      memset(&saddr, 0, sizeof(saddr));
+      if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen))
+        return -errno;
+
+      if ((saddr.ss_family == AF_INET6 &&
+          ((struct sockaddr_in6*) &saddr)->sin6_port != 0) ||
+          (saddr.ss_family == AF_INET &&
+          ((struct sockaddr_in*) &saddr)->sin_port != 0)) {
+        /* Handle is already bound to a port. */
+        handle->flags |= flags;
+        return 0;
+      }
+
+      /* Bind to arbitrary port */
+      if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen))
+        return -errno;
+    }
+
+    handle->flags |= flags;
+    return 0;
+  }
+
+  return new_socket(handle, domain, flags);
+}
+
+
 int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
   int domain;
 
@@ -260,6 +321,7 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
 
 int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
   static int single_accept = -1;
+  unsigned long flags;
   int err;
 
   if (tcp->delayed_error)
@@ -273,30 +335,17 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
   if (single_accept)
     tcp->flags |= UV_TCP_SINGLE_ACCEPT;
 
-  err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE);
-  if (err)
-    return err;
-
-#ifdef __MVS__
+  flags = UV_STREAM_READABLE;
+#if defined(__MVS__)
   /* on zOS the listen call does not bind automatically
      if the socket is unbound. Hence the manual binding to
      an arbitrary port is required to be done manually
   */
-
-  if (!(tcp->flags & UV_HANDLE_BOUND)) {
-    struct sockaddr_storage saddr;
-    socklen_t slen  = sizeof(saddr);
-    memset(&saddr, 0, sizeof(saddr));
-
-    if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen))
-      return -errno;
-
-    if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen))
-      return -errno;
-
-    tcp->flags |= UV_HANDLE_BOUND;
-  }
-#endif
+  flags |= UV_HANDLE_BOUND;
+#endif  
+  err = maybe_new_socket(tcp, AF_INET, flags);
+  if (err)
+    return err;
 
   if (listen(tcp->io_watcher.fd, backlog))
     return -errno;

+ 171 - 26
Utilities/cmlibuv/src/unix/thread.c

@@ -41,36 +41,159 @@
 #define NANOSEC ((uint64_t) 1e9)
 
 
-int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
-  int err;
-  pthread_attr_t* attr;
-#if defined(__APPLE__)
-  pthread_attr_t attr_storage;
-  struct rlimit lim;
+#if defined(UV__PTHREAD_BARRIER_FALLBACK)
+/* TODO: support barrier_attr */
+int pthread_barrier_init(pthread_barrier_t* barrier,
+                         const void* barrier_attr,
+                         unsigned count) {
+  int rc;
+  _uv_barrier* b;
+
+  if (barrier == NULL || count == 0)
+    return EINVAL;
+
+  if (barrier_attr != NULL)
+    return ENOTSUP;
+
+  b = uv__malloc(sizeof(*b));
+  if (b == NULL)
+    return ENOMEM;
+
+  b->in = 0;
+  b->out = 0;
+  b->threshold = count;
+
+  if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
+    goto error2;
+  if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
+    goto error;
+
+  barrier->b = b;
+  return 0;
+
+error:
+  pthread_mutex_destroy(&b->mutex);
+error2:
+  uv__free(b);
+  return rc;
+}
+
+int pthread_barrier_wait(pthread_barrier_t* barrier) {
+  int rc;
+  _uv_barrier* b;
+
+  if (barrier == NULL || barrier->b == NULL)
+    return EINVAL;
+
+  b = barrier->b;
+  /* Lock the mutex*/
+  if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
+    return rc;
+
+  /* Increment the count. If this is the first thread to reach the threshold,
+     wake up waiters, unlock the mutex, then return
+     PTHREAD_BARRIER_SERIAL_THREAD. */
+  if (++b->in == b->threshold) {
+    b->in = 0;
+    b->out = b->threshold - 1;
+    rc = pthread_cond_signal(&b->cond);
+    assert(rc == 0);
+
+    pthread_mutex_unlock(&b->mutex);
+    return PTHREAD_BARRIER_SERIAL_THREAD;
+  }
+  /* Otherwise, wait for other threads until in is set to 0,
+     then return 0 to indicate this is not the first thread. */
+  do {
+    if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0)
+      break;
+  } while (b->in != 0);
+
+  /* mark thread exit */
+  b->out--;
+  pthread_cond_signal(&b->cond);
+  pthread_mutex_unlock(&b->mutex);
+  return rc;
+}
+
+int pthread_barrier_destroy(pthread_barrier_t* barrier) {
+  int rc;
+  _uv_barrier* b;
+
+  if (barrier == NULL || barrier->b == NULL)
+    return EINVAL;
+
+  b = barrier->b;
+
+  if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
+    return rc;
+
+  if (b->in > 0 || b->out > 0)
+    rc = EBUSY;
+
+  pthread_mutex_unlock(&b->mutex);
+
+  if (rc)
+    return rc;
+
+  pthread_cond_destroy(&b->cond);
+  pthread_mutex_destroy(&b->mutex);
+  uv__free(barrier->b);
+  barrier->b = NULL;
+  return 0;
+}
 #endif
 
-  /* On OSX threads other than the main thread are created with a reduced stack
-   * size by default, adjust it to RLIMIT_STACK.
-   */
-#if defined(__APPLE__)
-  if (getrlimit(RLIMIT_STACK, &lim))
-    abort();
 
-  attr = &attr_storage;
-  if (pthread_attr_init(attr))
+/* 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.
+ *
+ * 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 thread_stack_size(void) {
+#if defined(__APPLE__) || defined(__linux__)
+  struct rlimit lim;
+
+  if (getrlimit(RLIMIT_STACK, &lim))
     abort();
 
   if (lim.rlim_cur != RLIM_INFINITY) {
     /* pthread_attr_setstacksize() expects page-aligned values. */
     lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
-
     if (lim.rlim_cur >= PTHREAD_STACK_MIN)
-      if (pthread_attr_setstacksize(attr, lim.rlim_cur))
-        abort();
+      return lim.rlim_cur;
   }
+#endif
+
+#if !defined(__linux__)
+  return 0;
+#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
+  return 4 << 20;  /* glibc default. */
 #else
-  attr = NULL;
+  return 2 << 20;  /* glibc default. */
 #endif
+}
+
+
+int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
+  int err;
+  size_t stack_size;
+  pthread_attr_t* attr;
+  pthread_attr_t attr_storage;
+
+  attr = NULL;
+  stack_size = thread_stack_size();
+
+  if (stack_size > 0) {
+    attr = &attr_storage;
+
+    if (pthread_attr_init(attr))
+      abort();
+
+    if (pthread_attr_setstacksize(attr, stack_size))
+      abort();
+  }
 
   err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg);
 
@@ -118,6 +241,25 @@ int uv_mutex_init(uv_mutex_t* mutex) {
 }
 
 
+int uv_mutex_init_recursive(uv_mutex_t* mutex) {
+  pthread_mutexattr_t attr;
+  int err;
+
+  if (pthread_mutexattr_init(&attr))
+    abort();
+
+  if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
+    abort();
+
+  err = pthread_mutex_init(mutex, &attr);
+
+  if (pthread_mutexattr_destroy(&attr))
+    abort();
+
+  return -err;
+}
+
+
 void uv_mutex_destroy(uv_mutex_t* mutex) {
   if (pthread_mutex_destroy(mutex))
     abort();
@@ -281,18 +423,20 @@ int uv_sem_trywait(uv_sem_t* sem) {
 
 int uv_sem_init(uv_sem_t* sem, unsigned int value) {
   uv_sem_t semid;
-  struct sembuf buf;
   int err;
+  union {
+    int val;
+    struct semid_ds* buf;
+    unsigned short* array;
+  } arg;
 
-  buf.sem_num = 0;
-  buf.sem_op = value;
-  buf.sem_flg = 0;
 
   semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR);
   if (semid == -1)
     return -errno;
 
-  if (-1 == semop(semid, &buf, 1)) {
+  arg.val = value;
+  if (-1 == semctl(semid, 0, SETVAL, arg)) {
     err = errno;
     if (-1 == semctl(*sem, 0, IPC_RMID))
       abort();
@@ -424,7 +568,7 @@ int uv_cond_init(uv_cond_t* cond) {
   if (err)
     return -err;
 
-#if !(defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
+#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21)
   err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
   if (err)
     goto error2;
@@ -511,7 +655,8 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
   timeout += uv__hrtime(UV_CLOCK_PRECISE);
   ts.tv_sec = timeout / NANOSEC;
   ts.tv_nsec = timeout % NANOSEC;
-#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+
   /*
    * The bionic pthread implementation doesn't support CLOCK_MONOTONIC,
    * but has this alternative function instead.
@@ -519,7 +664,7 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
   r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
 #else
   r = pthread_cond_timedwait(cond, mutex, &ts);
-#endif /* __ANDROID__ */
+#endif /* __ANDROID_API__ */
 #endif
 
 

+ 36 - 0
Utilities/cmlibuv/src/unix/tty.c

@@ -48,6 +48,42 @@ static int uv__tty_is_slave(const int fd) {
   char dummy[256];
 
   result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
+#elif defined(__NetBSD__)
+  /*
+   * NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave
+   * device name for both descriptors, the master one and slave one.
+   *
+   * Implement function to compare major device number with pts devices.
+   *
+   * The major numbers are machine-dependent, on NetBSD/amd64 they are
+   * respectively:
+   *  - master tty: ptc - major 6
+   *  - slave tty:  pts - major 5
+   */
+
+  struct stat sb;
+  /* Lookup device's major for the pts driver and cache it. */
+  static devmajor_t pts = NODEVMAJOR;
+
+  if (pts == NODEVMAJOR) {
+    pts = getdevmajor("pts", S_IFCHR);
+    if (pts == NODEVMAJOR)
+      abort();
+  }
+
+  /* Lookup stat structure behind the file descriptor. */
+  if (fstat(fd, &sb) != 0)
+    abort();
+
+  /* Assert character device. */
+  if (!S_ISCHR(sb.st_mode))
+    abort();
+
+  /* Assert valid major. */
+  if (major(sb.st_rdev) == NODEVMAJOR)
+    abort();
+
+  result = (pts == major(sb.st_rdev));
 #else
   /* Fallback to ptsname
    */

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

@@ -237,8 +237,10 @@ static void uv__udp_sendmsg(uv_udp_t* handle) {
       size = sendmsg(handle->io_watcher.fd, &h, 0);
     } while (size == -1 && errno == EINTR);
 
-    if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
-      break;
+    if (size == -1) {
+      if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
+        break;
+    }
 
     req->status = (size == -1 ? -errno : size);
 
@@ -472,7 +474,7 @@ int uv__udp_try_send(uv_udp_t* handle,
   } while (size == -1 && errno == EINTR);
 
   if (size == -1) {
-    if (errno == EAGAIN || errno == EWOULDBLOCK)
+    if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
       return -EAGAIN;
     else
       return -errno;

+ 96 - 0
Utilities/cmlibuv/src/uv-data-getter-setters.c

@@ -0,0 +1,96 @@
+#include "uv.h"
+
+const char* uv_handle_type_name(uv_handle_type type) {
+  switch (type) {
+#define XX(uc,lc) case UV_##uc: return #lc;
+    UV_HANDLE_TYPE_MAP(XX)
+#undef XX
+    case UV_FILE: return "file";
+    case UV_HANDLE_TYPE_MAX:
+    case UV_UNKNOWN_HANDLE: return NULL;
+  }
+  return NULL;
+}
+
+uv_handle_type uv_handle_get_type(const uv_handle_t* handle) {
+  return handle->type;
+}
+
+void* uv_handle_get_data(const uv_handle_t* handle) {
+  return handle->data;
+}
+
+uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) {
+  return handle->loop;
+}
+
+void uv_handle_set_data(uv_handle_t* handle, void* data) {
+  handle->data = data;
+}
+
+const char* uv_req_type_name(uv_req_type type) {
+  switch (type) {
+#define XX(uc,lc) case UV_##uc: return #lc;
+    UV_REQ_TYPE_MAP(XX)
+#undef XX
+    case UV_REQ_TYPE_MAX:
+    case UV_UNKNOWN_REQ: return NULL;
+  }
+  return NULL;
+}
+
+uv_req_type uv_req_get_type(const uv_req_t* req) {
+  return req->type;
+}
+
+void* uv_req_get_data(const uv_req_t* req) {
+  return req->data;
+}
+
+void uv_req_set_data(uv_req_t* req, void* data) {
+  req->data = data;
+}
+
+size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) {
+  return stream->write_queue_size;
+}
+
+size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) {
+  return handle->send_queue_size;
+}
+
+size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) {
+  return handle->send_queue_count;
+}
+
+uv_pid_t uv_process_get_pid(const uv_process_t* proc) {
+  return proc->pid;
+}
+
+uv_fs_type uv_fs_get_type(const uv_fs_t* req) {
+  return req->fs_type;
+}
+
+ssize_t uv_fs_get_result(const uv_fs_t* req) {
+  return req->result;
+}
+
+void* uv_fs_get_ptr(const uv_fs_t* req) {
+  return req->ptr;
+}
+
+const char* uv_fs_get_path(const uv_fs_t* req) {
+  return req->path;
+}
+
+uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) {
+  return &req->statbuf;
+}
+
+void* uv_loop_get_data(const uv_loop_t* loop) {
+  return loop->data;
+}
+
+void uv_loop_set_data(uv_loop_t* loop, void* data) {
+  loop->data = data;
+}

+ 35 - 20
Utilities/cmlibuv/src/win/dl.c

@@ -22,7 +22,7 @@
 #include "uv.h"
 #include "internal.h"
 
-static int uv__dlerror(uv_lib_t* lib, int errorno);
+static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno);
 
 
 int uv_dlopen(const char* filename, uv_lib_t* lib) {
@@ -37,12 +37,12 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) {
                            -1,
                            filename_w,
                            ARRAY_SIZE(filename_w))) {
-    return uv__dlerror(lib, GetLastError());
+    return uv__dlerror(lib, filename, GetLastError());
   }
 
   lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
   if (lib->handle == NULL) {
-    return uv__dlerror(lib, GetLastError());
+    return uv__dlerror(lib, filename, GetLastError());
   }
 
   return 0;
@@ -65,7 +65,7 @@ void uv_dlclose(uv_lib_t* lib) {
 
 int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
   *ptr = (void*) GetProcAddress(lib->handle, name);
-  return uv__dlerror(lib, *ptr ? 0 : GetLastError());
+  return uv__dlerror(lib, "", *ptr ? 0 : GetLastError());
 }
 
 
@@ -88,31 +88,46 @@ static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
 
 
 
-static int uv__dlerror(uv_lib_t* lib, int errorno) {
+static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) {
+  DWORD_PTR arg;
   DWORD res;
+  char* msg;
 
   if (lib->errmsg) {
-    LocalFree((void*)lib->errmsg);
+    LocalFree(lib->errmsg);
     lib->errmsg = NULL;
   }
 
-  if (errorno) {
+  if (errorno == 0)
+    return 0;
+
+  res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                       FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+                       MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+                       (LPSTR) &lib->errmsg, 0, NULL);
+
+  if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
     res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                          FORMAT_MESSAGE_FROM_SYSTEM |
                          FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
-                         MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
-                         (LPSTR) &lib->errmsg, 0, NULL);
-    if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
-      res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                           FORMAT_MESSAGE_FROM_SYSTEM |
-                           FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
-                           0, (LPSTR) &lib->errmsg, 0, NULL);
-    }
-
-    if (!res) {
-      uv__format_fallback_error(lib, errorno);
-    }
+                         0, (LPSTR) &lib->errmsg, 0, NULL);
+  }
+
+  if (res && errorno == ERROR_BAD_EXE_FORMAT && strstr(lib->errmsg, "%1")) {
+    msg = lib->errmsg;
+    lib->errmsg = NULL;
+    arg = (DWORD_PTR) filename;
+    res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                         FORMAT_MESSAGE_ARGUMENT_ARRAY |
+                         FORMAT_MESSAGE_FROM_STRING,
+                         msg,
+                         0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg);
+    LocalFree(msg);
   }
 
-  return errorno ? -1 : 0;
+  if (!res)
+    uv__format_fallback_error(lib, errorno);
+
+  return -1;
 }

+ 1 - 1
Utilities/cmlibuv/src/win/error.c

@@ -58,7 +58,7 @@ void uv_fatal_error(const int errorno, const char* syscall) {
     LocalFree(buf);
   }
 
-  *((char*)NULL) = 0xff; /* Force debug break */
+  DebugBreak();
   abort();
 }
 

文件差異過大導致無法顯示
+ 249 - 284
Utilities/cmlibuv/src/win/fs.c


+ 71 - 0
Utilities/cmlibuv/src/win/getaddrinfo.c

@@ -28,6 +28,8 @@
 /* EAI_* constants. */
 #include <winsock2.h>
 
+/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */
+#include <iphlpapi.h>
 
 int uv__getaddrinfo_translate_error(int sys_err) {
   switch (sys_err) {
@@ -73,6 +75,9 @@ int uv__getaddrinfo_translate_error(int sys_err) {
 /* Do we need different versions of this for different architectures? */
 #define ALIGNED_SIZE(X)     ((((X) + 3) >> 2) << 2)
 
+#ifndef NDIS_IF_MAX_STRING_SIZE
+#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE
+#endif
 
 static void uv__getaddrinfo_work(struct uv__work* w) {
   uv_getaddrinfo_t* req;
@@ -380,3 +385,69 @@ error:
   }
   return uv_translate_sys_error(err);
 }
+
+int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
+  NET_LUID luid;
+  wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
+  DWORD bufsize;
+  int r;
+
+  if (buffer == NULL || size == NULL || *size == 0)
+    return UV_EINVAL;
+
+  r = ConvertInterfaceIndexToLuid(ifindex, &luid);
+
+  if (r != 0)
+    return uv_translate_sys_error(r);
+
+  r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
+
+  if (r != 0)
+    return uv_translate_sys_error(r);
+
+  /* Check how much space we need */
+  bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
+
+  if (bufsize == 0) {
+    return uv_translate_sys_error(GetLastError());
+  } else if (bufsize > *size) {
+    *size = bufsize;
+    return UV_ENOBUFS;
+  }
+
+  /* Convert to UTF-8 */
+  bufsize = WideCharToMultiByte(CP_UTF8,
+                                0,
+                                wname,
+                                -1,
+                                buffer,
+                                *size,
+                                NULL,
+                                NULL);
+
+  if (bufsize == 0)
+    return uv_translate_sys_error(GetLastError());
+
+  *size = bufsize - 1;
+  return 0;
+}
+
+int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
+  int r;
+
+  if (buffer == NULL || size == NULL || *size == 0)
+    return UV_EINVAL;
+
+  r = snprintf(buffer, *size, "%d", ifindex);
+
+  if (r < 0)
+    return uv_translate_sys_error(r);
+
+  if (r >= (int) *size) {
+    *size = r + 1;
+    return UV_ENOBUFS;
+  }
+
+  *size = r;
+  return 0;
+}

+ 5 - 0
Utilities/cmlibuv/src/win/handle.c

@@ -152,3 +152,8 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
 int uv_is_closing(const uv_handle_t* handle) {
   return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED));
 }
+
+
+uv_os_fd_t uv_get_osfhandle(int fd) {
+  return uv__get_osfhandle(fd);
+}

+ 0 - 1
Utilities/cmlibuv/src/win/internal.h

@@ -330,7 +330,6 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
 void uv__util_init(void);
 
 uint64_t uv__hrtime(double scale);
-int uv_parent_pid(void);
 int uv_current_pid(void);
 __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
 int uv__getpwuid_r(uv_passwd_t* pwd);

+ 113 - 24
Utilities/cmlibuv/src/win/pipe.c

@@ -31,6 +31,9 @@
 #include "stream-inl.h"
 #include "req-inl.h"
 
+#include <aclapi.h>
+#include <accctrl.h>
+
 typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;
 
 struct uv__ipc_queue_item_s {
@@ -202,7 +205,7 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
     uv_unique_pipe_name(ptr, name, nameSize);
 
     pipeHandle = CreateNamedPipeA(name,
-      access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
+      access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
       PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
       NULL);
 
@@ -534,7 +537,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
    */
   handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
       PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
-      FILE_FLAG_FIRST_PIPE_INSTANCE,
+      FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
       PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
       PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
 
@@ -803,7 +806,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
     assert(req->pipeHandle == INVALID_HANDLE_VALUE);
 
     req->pipeHandle = CreateNamedPipeW(handle->name,
-        PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+        PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC,
         PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
         PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
 
@@ -968,27 +971,31 @@ static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
     uv_mutex_unlock(m);
   }
 restart_readfile:
-  result = ReadFile(handle->handle,
-                    &uv_zero_,
-                    0,
-                    &bytes,
-                    NULL);
-  if (!result) {
-    err = GetLastError();
-    if (err == ERROR_OPERATION_ABORTED &&
-        handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
-      if (handle->flags & UV_HANDLE_READING) {
-        /* just a brief break to do something else */
-        handle->pipe.conn.readfile_thread = NULL;
-        /* resume after it is finished */
-        uv_mutex_lock(m);
-        handle->pipe.conn.readfile_thread = hThread;
-        uv_mutex_unlock(m);
-        goto restart_readfile;
-      } else {
-        result = 1; /* successfully stopped reading */
+  if (handle->flags & UV_HANDLE_READING) {
+    result = ReadFile(handle->handle,
+                      &uv_zero_,
+                      0,
+                      &bytes,
+                      NULL);
+    if (!result) {
+      err = GetLastError();
+      if (err == ERROR_OPERATION_ABORTED &&
+          handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+        if (handle->flags & UV_HANDLE_READING) {
+          /* just a brief break to do something else */
+          handle->pipe.conn.readfile_thread = NULL;
+          /* resume after it is finished */
+          uv_mutex_lock(m);
+          handle->pipe.conn.readfile_thread = hThread;
+          uv_mutex_unlock(m);
+          goto restart_readfile;
+        } else {
+          result = 1; /* successfully stopped reading */
+        }
       }
     }
+  } else {
+    result = 1; /* successfully aborted read before it even started */
   }
   if (hThread) {
     assert(hThread == handle->pipe.conn.readfile_thread);
@@ -1515,7 +1522,10 @@ static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
 
 static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
     int error, uv_buf_t buf) {
-  if (error == ERROR_BROKEN_PIPE) {
+  if (error == ERROR_OPERATION_ABORTED) {
+    /* do nothing (equivalent to EINTR) */
+  }
+  else if (error == ERROR_BROKEN_PIPE) {
     uv_pipe_read_eof(loop, handle, buf);
   } else {
     uv_pipe_read_error(loop, handle, error, buf);
@@ -1906,6 +1916,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
   if (os_handle == INVALID_HANDLE_VALUE)
     return UV_EBADF;
 
+  uv__once_init();
   /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
    * underlying OS handle and forget about the original fd.
    * We could also opt to use the original OS handle and just never close it,
@@ -1961,7 +1972,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
 
   if (pipe->ipc) {
     assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
-    pipe->pipe.conn.ipc_pid = uv_parent_pid();
+    pipe->pipe.conn.ipc_pid = uv_os_getppid();
     assert(pipe->pipe.conn.ipc_pid != -1);
   }
   return 0;
@@ -1979,6 +1990,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size)
   unsigned int name_len;
   int err;
 
+  uv__once_init();
   name_info = NULL;
 
   if (handle->handle == INVALID_HANDLE_VALUE) {
@@ -2123,3 +2135,80 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
   else
     return UV_TCP;
 }
+
+int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
+  SID_IDENTIFIER_AUTHORITY sid_world = SECURITY_WORLD_SID_AUTHORITY;
+  PACL old_dacl, new_dacl;
+  PSECURITY_DESCRIPTOR sd;
+  EXPLICIT_ACCESS ea;
+  PSID everyone;
+  int error;
+
+  if (handle == NULL || handle->handle == INVALID_HANDLE_VALUE)
+    return UV_EBADF;
+
+  if (mode != UV_READABLE &&
+      mode != UV_WRITABLE &&
+      mode != (UV_WRITABLE | UV_READABLE))
+    return UV_EINVAL;
+
+  if (!AllocateAndInitializeSid(&sid_world,
+                                1,
+                                SECURITY_WORLD_RID,
+                                0, 0, 0, 0, 0, 0, 0,
+                                &everyone)) {
+    error = GetLastError();
+    goto done;
+  }
+
+  if (GetSecurityInfo(handle->handle,
+                      SE_KERNEL_OBJECT,
+                      DACL_SECURITY_INFORMATION,
+                      NULL,
+                      NULL,
+                      &old_dacl,
+                      NULL,
+                      &sd)) {
+    error = GetLastError();
+    goto clean_sid;
+  }
+ 
+  memset(&ea, 0, sizeof(EXPLICIT_ACCESS));
+  if (mode & UV_READABLE)
+    ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
+  if (mode & UV_WRITABLE)
+    ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+  ea.grfAccessPermissions |= SYNCHRONIZE;
+  ea.grfAccessMode = SET_ACCESS;
+  ea.grfInheritance = NO_INHERITANCE;
+  ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+  ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
+  ea.Trustee.ptstrName = (LPTSTR)everyone;
+
+  if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl)) {
+    error = GetLastError();
+    goto clean_sd;
+  }
+
+  if (SetSecurityInfo(handle->handle,
+                      SE_KERNEL_OBJECT,
+                      DACL_SECURITY_INFORMATION,
+                      NULL,
+                      NULL,
+                      new_dacl,
+                      NULL)) {
+    error = GetLastError();
+    goto clean_dacl;
+  }
+
+  error = 0;
+
+clean_dacl:
+  LocalFree((HLOCAL) new_dacl);
+clean_sd:
+  LocalFree((HLOCAL) sd);
+clean_sid:
+  FreeSid(everyone);
+done:
+  return uv_translate_sys_error(error);
+}

+ 26 - 5
Utilities/cmlibuv/src/win/process.c

@@ -405,8 +405,15 @@ static WCHAR* search_path(const WCHAR *file,
       /* Next slice starts just after where the previous one ended */
       dir_start = dir_end;
 
+      /* If path is quoted, find quote end */
+      if (*dir_start == L'"' || *dir_start == L'\'') {
+        dir_end = wcschr(dir_start + 1, *dir_start);
+        if (dir_end == NULL) {
+          dir_end = wcschr(dir_start, L'\0');
+        }
+      }
       /* Slice until the next ; or \0 is found */
-      dir_end = wcschr(dir_start, L';');
+      dir_end = wcschr(dir_end, L';');
       if (dir_end == NULL) {
         dir_end = wcschr(dir_start, L'\0');
       }
@@ -1051,15 +1058,18 @@ int uv_spawn(uv_loop_t* loop,
   startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
   startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
 
+  process_flags = CREATE_UNICODE_ENVIRONMENT;
+
   if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
     /* Use SW_HIDE to avoid any potential process window. */
     startup.wShowWindow = SW_HIDE;
+
+    /* Hide console windows. */
+    process_flags |= CREATE_NO_WINDOW;
   } else {
     startup.wShowWindow = SW_SHOWDEFAULT;
   }
 
-  process_flags = CREATE_UNICODE_ENVIRONMENT;
-
   if (options->flags & UV_PROCESS_DETACHED) {
     /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
      * means that libuv might not let you create a fully daemonized process
@@ -1163,6 +1173,10 @@ int uv_spawn(uv_loop_t* loop,
 
 
 static int uv__kill(HANDLE process_handle, int signum) {
+  if (signum < 0 || signum >= NSIG) {
+    return UV_EINVAL;
+  }
+
   switch (signum) {
     case SIGTERM:
     case SIGKILL:
@@ -1227,8 +1241,15 @@ int uv_process_kill(uv_process_t* process, int signum) {
 
 int uv_kill(int pid, int signum) {
   int err;
-  HANDLE process_handle = OpenProcess(PROCESS_TERMINATE |
-    PROCESS_QUERY_INFORMATION, FALSE, pid);
+  HANDLE process_handle;
+
+  if (pid == 0) {
+    process_handle = GetCurrentProcess();
+  } else {
+    process_handle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION,
+                                 FALSE,
+                                 pid);
+  }
 
   if (process_handle == NULL) {
     err = GetLastError();

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

@@ -64,7 +64,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
 }
 
 
-RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare);
+RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare)
 
 
 /*

+ 1 - 2
Utilities/cmlibuv/src/win/stream-inl.h

@@ -36,6 +36,7 @@ INLINE static void uv_stream_init(uv_loop_t* loop,
   uv__handle_init(loop, (uv_handle_t*) handle, type);
   handle->write_queue_size = 0;
   handle->activecnt = 0;
+  handle->stream.conn.shutdown_req = NULL;
 }
 
 
@@ -47,8 +48,6 @@ INLINE static void uv_connection_init(uv_stream_t* handle) {
   handle->read_req.event_handle = NULL;
   handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
   handle->read_req.data = handle;
-
-  handle->stream.conn.shutdown_req = NULL;
 }
 
 

+ 26 - 6
Utilities/cmlibuv/src/win/tcp.c

@@ -747,10 +747,15 @@ static int uv_tcp_try_connect(uv_connect_t* req,
                               uv_connect_cb cb) {
   uv_loop_t* loop = handle->loop;
   const struct sockaddr* bind_addr;
+  struct sockaddr_storage converted;
   BOOL success;
   DWORD bytes;
   int err;
 
+  err = uv__convert_to_localhost_if_unspecified(addr, &converted);
+  if (err)
+    return err;
+
   if (handle->delayed_error) {
     return handle->delayed_error;
   }
@@ -782,12 +787,12 @@ static int uv_tcp_try_connect(uv_connect_t* req,
   memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
 
   success = handle->tcp.conn.func_connectex(handle->socket,
-                                           addr,
-                                           addrlen,
-                                           NULL,
-                                           0,
-                                           &bytes,
-                                           &req->u.io.overlapped);
+                                            (const struct sockaddr*) &converted,
+                                            addrlen,
+                                            NULL,
+                                            0,
+                                            &bytes,
+                                            &req->u.io.overlapped);
 
   if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
     /* Process the req without IOCP. */
@@ -1446,6 +1451,8 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
   WSAPROTOCOL_INFOW protocol_info;
   int opt_len;
   int err;
+  struct sockaddr_storage saddr;
+  int saddr_len;
 
   /* Detect the address family of the socket. */
   opt_len = (int) sizeof protocol_info;
@@ -1466,6 +1473,19 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
     return uv_translate_sys_error(err);
   }
 
+  /* Support already active socket. */
+  saddr_len = sizeof(saddr);
+  if (!uv_tcp_getsockname(handle, (struct sockaddr*) &saddr, &saddr_len)) {
+    /* Socket is already bound. */
+    handle->flags |= UV_HANDLE_BOUND;
+    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);
+      handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+    }
+  }
+
   return 0;
 }
 

+ 6 - 0
Utilities/cmlibuv/src/win/thread.c

@@ -182,6 +182,7 @@ int uv_thread_join(uv_thread_t *tid) {
   else {
     CloseHandle(*tid);
     *tid = 0;
+    MemoryBarrier();  /* For feature parity with pthread_join(). */
     return 0;
   }
 }
@@ -198,6 +199,11 @@ int uv_mutex_init(uv_mutex_t* mutex) {
 }
 
 
+int uv_mutex_init_recursive(uv_mutex_t* mutex) {
+  return uv_mutex_init(mutex);
+}
+
+
 void uv_mutex_destroy(uv_mutex_t* mutex) {
   DeleteCriticalSection(mutex);
 }

+ 1 - 1
Utilities/cmlibuv/src/win/timer.c

@@ -56,7 +56,7 @@ static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
 }
 
 
-RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare);
+RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare)
 
 
 int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {

+ 84 - 37
Utilities/cmlibuv/src/win/tty.c

@@ -112,14 +112,30 @@ static int uv_tty_virtual_offset = -1;
 static int uv_tty_virtual_height = -1;
 static int uv_tty_virtual_width = -1;
 
+/* The console window size
+ * We keep this separate from uv_tty_virtual_*. We use those values to only
+ * handle signalling SIGWINCH
+ */
+
+static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE;
+static int uv__tty_console_height = -1;
+static int uv__tty_console_width = -1;
+
+static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param);
+static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
+                                                  DWORD event,
+                                                  HWND hwnd,
+                                                  LONG idObject,
+                                                  LONG idChild,
+                                                  DWORD dwEventThread,
+                                                  DWORD dwmsEventTime);
+
 /* We use a semaphore rather than a mutex or critical section because in some
    cases (uv__cancel_read_console) we need take the lock in the main thread and
    release it in another thread. Using a semaphore ensures that in such
    scenario the main thread will still block when trying to acquire the lock. */
 static uv_sem_t uv_tty_output_lock;
 
-static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE;
-
 static WORD uv_tty_default_text_attributes =
     FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
 
@@ -141,6 +157,18 @@ static void uv__determine_vterm_state(HANDLE handle);
 void uv_console_init(void) {
   if (uv_sem_init(&uv_tty_output_lock, 1))
     abort();
+  uv__tty_console_handle = CreateFileW(L"CONOUT$",
+                                       GENERIC_READ | GENERIC_WRITE,
+                                       FILE_SHARE_WRITE,
+                                       0,
+                                       OPEN_EXISTING,
+                                       0,
+                                       0);
+  if (uv__tty_console_handle != NULL) {
+    QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
+                      NULL,
+                      WT_EXECUTELONGFUNCTION);
+  }
 }
 
 
@@ -148,6 +176,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
   HANDLE handle;
   CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
 
+  uv__once_init();
   handle = (HANDLE) uv__get_osfhandle(fd);
   if (handle == INVALID_HANDLE_VALUE)
     return UV_EBADF;
@@ -183,11 +212,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
     if (uv__vterm_state == UV_UNCHECKED)
       uv__determine_vterm_state(handle);
 
-    /* Store the global tty output handle. This handle is used by TTY read */
-    /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */
-    /* is received. */
-    uv_tty_output_handle = handle;
-
     /* Remember the original console text attributes. */
     uv_tty_capture_initial_style(&screen_buffer_info);
 
@@ -704,25 +728,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
       }
       records_left--;
 
-      /* If the window was resized, recompute the virtual window size. This */
-      /* will trigger a SIGWINCH signal if the window size changed in an */
-      /* way that matters to libuv. */
-      if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
-        CONSOLE_SCREEN_BUFFER_INFO info;
-
-        uv_sem_wait(&uv_tty_output_lock);
-
-        if (uv_tty_output_handle != INVALID_HANDLE_VALUE &&
-            GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) {
-          uv_tty_update_virtual_window(&info);
-        }
-
-        uv_sem_post(&uv_tty_output_lock);
-
-        continue;
-      }
-
-      /* Ignore other events that are not key or resize events. */
+      /* Ignore other events that are not key events. */
       if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
         continue;
       }
@@ -1102,9 +1108,6 @@ static int uv__cancel_read_console(uv_tty_t* handle) {
 
 
 static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
-  int old_virtual_width = uv_tty_virtual_width;
-  int old_virtual_height = uv_tty_virtual_height;
-
   uv_tty_virtual_width = info->dwSize.X;
   uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
 
@@ -1124,14 +1127,6 @@ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
   if (uv_tty_virtual_offset < 0) {
     uv_tty_virtual_offset = 0;
   }
-
-  /* If the virtual window size changed, emit a SIGWINCH signal. Don't emit */
-  /* if this was the first time the virtual window size was computed. */
-  if (old_virtual_width != -1 && old_virtual_height != -1 &&
-      (uv_tty_virtual_width != old_virtual_width ||
-       uv_tty_virtual_height != old_virtual_height)) {
-    uv__signal_dispatch(SIGWINCH);
-  }
 }
 
 
@@ -2279,3 +2274,55 @@ static void uv__determine_vterm_state(HANDLE handle) {
 
   uv__vterm_state = UV_SUPPORTED;
 }
+
+static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) {
+  CONSOLE_SCREEN_BUFFER_INFO sb_info;
+  MSG msg;
+
+  if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
+    return 0;
+
+  uv__tty_console_width = sb_info.dwSize.X;
+  uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
+
+  if (pSetWinEventHook == NULL)
+    return 0;
+
+  if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT,
+                        EVENT_CONSOLE_LAYOUT,
+                        NULL,
+                        uv__tty_console_resize_event,
+                        0,
+                        0,
+                        WINEVENT_OUTOFCONTEXT))
+    return 0;
+
+  while (GetMessage(&msg, NULL, 0, 0)) {
+    TranslateMessage(&msg);
+    DispatchMessage(&msg);
+  }
+  return 0;
+}
+
+static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
+                                                  DWORD event,
+                                                  HWND hwnd,
+                                                  LONG idObject,
+                                                  LONG idChild,
+                                                  DWORD dwEventThread,
+                                                  DWORD dwmsEventTime) {
+  CONSOLE_SCREEN_BUFFER_INFO sb_info;
+  int width, height;
+
+  if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
+    return;
+
+  width = sb_info.dwSize.X;
+  height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
+
+  if (width != uv__tty_console_width || height != uv__tty_console_height) {
+    uv__tty_console_width = width;
+    uv__tty_console_height = height;
+    uv__signal_dispatch(SIGWINCH);
+  }
+}

+ 45 - 6
Utilities/cmlibuv/src/win/udp.c

@@ -897,13 +897,12 @@ int uv__udp_send(uv_udp_send_t* req,
   int err;
 
   if (!(handle->flags & UV_HANDLE_BOUND)) {
-    if (addrlen == sizeof(uv_addr_ip4_any_)) {
+    if (addrlen == sizeof(uv_addr_ip4_any_))
       bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
-    } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
+    else if (addrlen == sizeof(uv_addr_ip6_any_))
       bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
-    } else {
-      abort();
-    }
+    else
+      return UV_EINVAL;
     err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
     if (err)
       return uv_translate_sys_error(err);
@@ -922,5 +921,45 @@ int uv__udp_try_send(uv_udp_t* handle,
                      unsigned int nbufs,
                      const struct sockaddr* addr,
                      unsigned int addrlen) {
-  return UV_ENOSYS;
+  DWORD bytes;
+  const struct sockaddr* bind_addr;
+  struct sockaddr_storage converted;
+  int err;
+
+  assert(nbufs > 0);
+
+  err = uv__convert_to_localhost_if_unspecified(addr, &converted);
+  if (err)
+    return err;
+
+  /* Already sending a message.*/
+  if (handle->send_queue_count != 0)
+    return UV_EAGAIN;
+
+  if (!(handle->flags & UV_HANDLE_BOUND)) {
+    if (addrlen == sizeof(uv_addr_ip4_any_))
+      bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
+    else if (addrlen == sizeof(uv_addr_ip6_any_))
+      bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
+    else
+      return UV_EINVAL;
+    err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
+    if (err)
+      return uv_translate_sys_error(err);
+  }
+
+  err = WSASendTo(handle->socket,
+                  (WSABUF*)bufs,
+                  nbufs,
+                  &bytes,
+                  0,
+                  (const struct sockaddr*) &converted,
+                  addrlen,
+                  NULL,
+                  NULL);
+
+  if (err)
+    return uv_translate_sys_error(WSAGetLastError());
+
+  return bytes;
 }

+ 8 - 3
Utilities/cmlibuv/src/win/util.c

@@ -331,7 +331,12 @@ uint64_t uv_get_total_memory(void) {
 }
 
 
-int uv_parent_pid(void) {
+uv_pid_t uv_os_getpid(void) {
+  return GetCurrentProcessId();
+}
+
+
+uv_pid_t uv_os_getppid(void) {
   int parent_pid = -1;
   HANDLE handle;
   PROCESSENTRY32 pe;
@@ -1388,7 +1393,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
   if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
     return uv_translate_sys_error(GetLastError());
 
-  bufsize = sizeof(path);
+  bufsize = ARRAY_SIZE(path);
   if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
     r = GetLastError();
     CloseHandle(token);
@@ -1403,7 +1408,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
   CloseHandle(token);
 
   /* Get the username using GetUserNameW() */
-  bufsize = sizeof(username);
+  bufsize = ARRAY_SIZE(username);
   if (!GetUserNameW(username, &bufsize)) {
     r = GetLastError();
 

+ 10 - 0
Utilities/cmlibuv/src/win/winapi.c

@@ -52,11 +52,15 @@ sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
 /* Powrprof.dll function pointer */
 sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
 
+/* User32.dll function pointer */
+sSetWinEventHook pSetWinEventHook;
+
 
 void uv_winapi_init(void) {
   HMODULE ntdll_module;
   HMODULE kernel32_module;
   HMODULE powrprof_module;
+  HMODULE user32_module;
 
   ntdll_module = GetModuleHandleA("ntdll.dll");
   if (ntdll_module == NULL) {
@@ -156,4 +160,10 @@ void uv_winapi_init(void) {
       GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
   }
 
+  user32_module = LoadLibraryA("user32.dll");
+  if (user32_module != NULL) {
+    pSetWinEventHook = (sSetWinEventHook)
+      GetProcAddress(user32_module, "SetWinEventHook");
+  }
+
 }

+ 26 - 0
Utilities/cmlibuv/src/win/winapi.h

@@ -4104,6 +4104,10 @@
 # define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE          0x00002000
 #endif
 
+#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
+# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x00000002
+#endif
+
 /* from winternl.h */
 typedef struct _UNICODE_STRING {
   USHORT Length;
@@ -4730,6 +4734,25 @@ typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification)
                HANDLE        Recipient,
                _PHPOWERNOTIFY RegistrationHandle);
 
+/* from Winuser.h */
+typedef VOID (CALLBACK* WINEVENTPROC)
+             (HWINEVENTHOOK hWinEventHook,
+              DWORD         event,
+              HWND          hwnd,
+              LONG          idObject,
+              LONG          idChild,
+              DWORD         idEventThread,
+              DWORD         dwmsEventTime);
+
+typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook)
+                      (UINT         eventMin,
+                       UINT         eventMax,
+                       HMODULE      hmodWinEventProc,
+                       WINEVENTPROC lpfnWinEventProc,
+                       DWORD        idProcess,
+                       DWORD        idThread,
+                       UINT         dwflags);
+
 
 /* Ntdll function pointers */
 extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
@@ -4758,4 +4781,7 @@ extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
 /* Powrprof.dll function pointer */
 extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
 
+/* User32.dll function pointer */
+extern sSetWinEventHook pSetWinEventHook;
+
 #endif /* UV_WIN_WINAPI_H_ */

+ 28 - 0
Utilities/cmlibuv/src/win/winsock.c

@@ -559,3 +559,31 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
     return SOCKET_ERROR;
   }
 }
+
+int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
+                                            struct sockaddr_storage* storage) {
+  struct sockaddr_in* dest4;
+  struct sockaddr_in6* dest6;
+
+  if (addr == NULL)
+    return UV_EINVAL;
+
+  switch (addr->sa_family) {
+  case AF_INET:
+    dest4 = (struct sockaddr_in*) storage;
+    memcpy(dest4, addr, sizeof(*dest4));
+    if (dest4->sin_addr.s_addr == 0)
+      dest4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    return 0;
+  case AF_INET6:
+    dest6 = (struct sockaddr_in6*) storage;
+    memcpy(dest6, addr, sizeof(*dest6));
+    if (memcmp(&dest6->sin6_addr,
+               &uv_addr_ip6_any_.sin6_addr,
+               sizeof(uv_addr_ip6_any_.sin6_addr)) == 0)
+      dest6->sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
+    return 0;
+  default:
+    return UV_EINVAL;
+  }
+}

+ 3 - 0
Utilities/cmlibuv/src/win/winsock.h

@@ -188,4 +188,7 @@ typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH {
 
 #endif
 
+int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
+                                            struct sockaddr_storage* storage);
+
 #endif /* UV_WIN_WINSOCK_H_ */

部分文件因文件數量過多而無法顯示