浏览代码

libuv 2017-02-21 (52ae8264)

Code extracted from:

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

at commit 52ae826492f50f151138ed115faa5e0ac8c803ce (v1.x).
libuv upstream 8 年之前
父节点
当前提交
1f661e87a6

+ 2 - 0
include/pthread-barrier.h

@@ -18,7 +18,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #define _UV_PTHREAD_BARRIER_
 #define _UV_PTHREAD_BARRIER_
 #include <errno.h>
 #include <errno.h>
 #include <pthread.h>
 #include <pthread.h>
+#if !defined(__MVS__)
 #include <semaphore.h> /* sem_t */
 #include <semaphore.h> /* sem_t */
+#endif
 
 
 #define PTHREAD_BARRIER_SERIAL_THREAD  0x12345
 #define PTHREAD_BARRIER_SERIAL_THREAD  0x12345
 
 

+ 3 - 0
include/uv-os390.h

@@ -24,4 +24,7 @@
 
 
 #define UV_PLATFORM_SEM_T int
 #define UV_PLATFORM_SEM_T int
 
 
+#define UV_PLATFORM_LOOP_FIELDS                                               \
+  void* ep;                                                                   \
+
 #endif /* UV_MVS_H */
 #endif /* UV_MVS_H */

+ 4 - 0
include/uv-unix.h

@@ -36,7 +36,9 @@
 #include <termios.h>
 #include <termios.h>
 #include <pwd.h>
 #include <pwd.h>
 
 
+#if !defined(__MVS__)
 #include <semaphore.h>
 #include <semaphore.h>
+#endif
 #include <pthread.h>
 #include <pthread.h>
 #include <signal.h>
 #include <signal.h>
 
 
@@ -44,6 +46,8 @@
 
 
 #if defined(__linux__)
 #if defined(__linux__)
 # include "uv-linux.h"
 # include "uv-linux.h"
+#elif defined (__MVS__)
+# include "uv-os390.h"
 #elif defined(_AIX)
 #elif defined(_AIX)
 # include "uv-aix.h"
 # include "uv-aix.h"
 #elif defined(__sun)
 #elif defined(__sun)

+ 2 - 2
include/uv-version.h

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

+ 6 - 5
include/uv-win.h

@@ -49,6 +49,7 @@ typedef struct pollfd {
 
 
 #include <process.h>
 #include <process.h>
 #include <signal.h>
 #include <signal.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
 
 
 #if defined(_MSC_VER) && _MSC_VER < 1600
 #if defined(_MSC_VER) && _MSC_VER < 1600
@@ -116,7 +117,7 @@ typedef struct pollfd {
          {0xb5367df0, 0xcbac, 0x11cf,                                         \
          {0xb5367df0, 0xcbac, 0x11cf,                                         \
          {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
          {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
 
 
-  typedef BOOL PASCAL (*LPFN_ACCEPTEX)
+  typedef BOOL (PASCAL *LPFN_ACCEPTEX)
                       (SOCKET sListenSocket,
                       (SOCKET sListenSocket,
                        SOCKET sAcceptSocket,
                        SOCKET sAcceptSocket,
                        PVOID lpOutputBuffer,
                        PVOID lpOutputBuffer,
@@ -126,7 +127,7 @@ typedef struct pollfd {
                        LPDWORD lpdwBytesReceived,
                        LPDWORD lpdwBytesReceived,
                        LPOVERLAPPED lpOverlapped);
                        LPOVERLAPPED lpOverlapped);
 
 
-  typedef BOOL PASCAL (*LPFN_CONNECTEX)
+  typedef BOOL (PASCAL *LPFN_CONNECTEX)
                       (SOCKET s,
                       (SOCKET s,
                        const struct sockaddr* name,
                        const struct sockaddr* name,
                        int namelen,
                        int namelen,
@@ -135,7 +136,7 @@ typedef struct pollfd {
                        LPDWORD lpdwBytesSent,
                        LPDWORD lpdwBytesSent,
                        LPOVERLAPPED lpOverlapped);
                        LPOVERLAPPED lpOverlapped);
 
 
-  typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS)
+  typedef void (PASCAL *LPFN_GETACCEPTEXSOCKADDRS)
                       (PVOID lpOutputBuffer,
                       (PVOID lpOutputBuffer,
                        DWORD dwReceiveDataLength,
                        DWORD dwReceiveDataLength,
                        DWORD dwLocalAddressLength,
                        DWORD dwLocalAddressLength,
@@ -145,13 +146,13 @@ typedef struct pollfd {
                        LPSOCKADDR* RemoteSockaddr,
                        LPSOCKADDR* RemoteSockaddr,
                        LPINT RemoteSockaddrLength);
                        LPINT RemoteSockaddrLength);
 
 
-  typedef BOOL PASCAL (*LPFN_DISCONNECTEX)
+  typedef BOOL (PASCAL *LPFN_DISCONNECTEX)
                       (SOCKET hSocket,
                       (SOCKET hSocket,
                        LPOVERLAPPED lpOverlapped,
                        LPOVERLAPPED lpOverlapped,
                        DWORD dwFlags,
                        DWORD dwFlags,
                        DWORD reserved);
                        DWORD reserved);
 
 
-  typedef BOOL PASCAL (*LPFN_TRANSMITFILE)
+  typedef BOOL (PASCAL *LPFN_TRANSMITFILE)
                       (SOCKET hSocket,
                       (SOCKET hSocket,
                        HANDLE hFile,
                        HANDLE hFile,
                        DWORD nNumberOfBytesToWrite,
                        DWORD nNumberOfBytesToWrite,

+ 2 - 0
include/uv.h

@@ -363,6 +363,8 @@ typedef enum {
 } uv_membership;
 } uv_membership;
 
 
 
 
+UV_EXTERN int uv_translate_sys_error(int sys_errno);
+
 UV_EXTERN const char* uv_strerror(int err);
 UV_EXTERN const char* uv_strerror(int err);
 UV_EXTERN const char* uv_err_name(int err);
 UV_EXTERN const char* uv_err_name(int err);
 
 

+ 84 - 2
src/unix/aix.c

@@ -64,6 +64,11 @@
 #define RDWR_BUF_SIZE   4096
 #define RDWR_BUF_SIZE   4096
 #define EQ(a,b)         (strcmp(a,b) == 0)
 #define EQ(a,b)         (strcmp(a,b) == 0)
 
 
+static void* args_mem = NULL;
+static char** process_argv = NULL;
+static int process_argc = 0;
+static char* process_title_ptr = NULL;
+
 int uv__platform_loop_init(uv_loop_t* loop) {
 int uv__platform_loop_init(uv_loop_t* loop) {
   loop->fs_fd = -1;
   loop->fs_fd = -1;
 
 
@@ -753,6 +758,13 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int
 
 
   assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file");
   assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file");
 
 
+  /* In file / directory move cases, AIX Event infrastructure
+   * produces a second event with no data.
+   * Ignore it and return gracefully.
+   */
+  if(bytes == 0)
+    return;
+
   /* Parse the data */
   /* Parse the data */
   if(bytes > 0)
   if(bytes > 0)
     rc = uv__parse_data(result_data, &events, handle);
     rc = uv__parse_data(result_data, &events, handle);
@@ -881,24 +893,94 @@ void uv__fs_event_close(uv_fs_event_t* handle) {
 
 
 
 
 char** uv_setup_args(int argc, char** argv) {
 char** uv_setup_args(int argc, char** argv) {
-  return argv;
+  char** new_argv;
+  size_t size;
+  char* s;
+  int i;
+
+  if (argc <= 0)
+    return argv;
+
+  /* Save the original pointer to argv.
+   * AIX uses argv to read the process name.
+   * (Not the memory pointed to by argv[0..n] as on Linux.)
+   */
+  process_argv = argv;
+  process_argc = argc;
+
+  /* Calculate how much memory we need for the argv strings. */
+  size = 0;
+  for (i = 0; i < argc; i++)
+    size += strlen(argv[i]) + 1;
+
+  /* Add space for the argv pointers. */
+  size += (argc + 1) * sizeof(char*);
+
+  new_argv = uv__malloc(size);
+  if (new_argv == NULL)
+    return argv;
+  args_mem = new_argv;
+
+  /* Copy over the strings and set up the pointer table. */
+  s = (char*) &new_argv[argc + 1];
+  for (i = 0; i < argc; i++) {
+    size = strlen(argv[i]) + 1;
+    memcpy(s, argv[i], size);
+    new_argv[i] = s;
+    s += size;
+  }
+  new_argv[i] = NULL;
+
+  return new_argv;
 }
 }
 
 
 
 
 int uv_set_process_title(const char* title) {
 int uv_set_process_title(const char* title) {
+  char* new_title;
+
+  /* We cannot free this pointer when libuv shuts down,
+   * the process may still be using it.
+   */
+  new_title = uv__strdup(title);
+  if (new_title == NULL)
+    return -ENOMEM;
+
+  /* If this is the first time this is set,
+   * don't free and set argv[1] to NULL.
+   */
+  if (process_title_ptr != NULL)
+    uv__free(process_title_ptr);
+
+  process_title_ptr = new_title;
+
+  process_argv[0] = process_title_ptr;
+  if (process_argc > 1)
+     process_argv[1] = NULL;
+
   return 0;
   return 0;
 }
 }
 
 
 
 
 int uv_get_process_title(char* buffer, size_t size) {
 int uv_get_process_title(char* buffer, size_t size) {
+  size_t len;
+  len = strlen(process_argv[0]);
   if (buffer == NULL || size == 0)
   if (buffer == NULL || size == 0)
     return -EINVAL;
     return -EINVAL;
+  else if (size <= len)
+    return -ENOBUFS;
+
+  memcpy(buffer, process_argv[0], len + 1);
 
 
-  buffer[0] = '\0';
   return 0;
   return 0;
 }
 }
 
 
 
 
+UV_DESTRUCTOR(static void free_args_mem(void)) {
+  uv__free(args_mem);  /* Keep valgrind happy. */
+  args_mem = NULL;
+}
+
+
 int uv_resident_set_memory(size_t* rss) {
 int uv_resident_set_memory(size_t* rss) {
   char pp[64];
   char pp[64];
   psinfo_t psinfo;
   psinfo_t psinfo;

+ 18 - 9
src/unix/atomic-ops.h

@@ -43,8 +43,12 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
   __compare_and_swap(ptr, &oldval, newval);
   __compare_and_swap(ptr, &oldval, newval);
   return out;
   return out;
 #elif defined(__MVS__)
 #elif defined(__MVS__)
-  return __plo_CS(ptr, (unsigned int*) ptr,
-                  oldval, (unsigned int*) &newval);
+  unsigned int op4;
+  if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
+                (unsigned int*) ptr, *ptr, &op4))
+    return oldval;
+  else
+    return op4;
 #else
 #else
   return __sync_val_compare_and_swap(ptr, oldval, newval);
   return __sync_val_compare_and_swap(ptr, oldval, newval);
 #endif
 #endif
@@ -67,13 +71,18 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
 # endif /* if defined(__64BIT__) */
 # endif /* if defined(__64BIT__) */
   return out;
   return out;
 #elif defined (__MVS__)
 #elif defined (__MVS__)
-# ifdef _LP64
-  return __plo_CSGR(ptr, (unsigned long long*) ptr,
-                    oldval, (unsigned long long*) &newval);
-# else
-  return __plo_CS(ptr, (unsigned int*) ptr,
-                  oldval, (unsigned int*) &newval);
-# endif
+#ifdef _LP64
+  unsigned long long op4;
+  if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval,
+                  (unsigned long long*) ptr, *ptr, &op4))
+#else
+  unsigned long op4;
+  if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
+                (unsigned int*) ptr, *ptr, &op4))
+#endif
+    return oldval;
+  else
+    return op4;
 #else
 #else
   return __sync_val_compare_and_swap(ptr, oldval, newval);
   return __sync_val_compare_and_swap(ptr, oldval, newval);
 #endif
 #endif

+ 11 - 7
src/unix/core.c

@@ -98,7 +98,7 @@ uint64_t uv_hrtime(void) {
 
 
 
 
 void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
 void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
-  assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+  assert(!uv__is_closing(handle));
 
 
   handle->flags |= UV_CLOSING;
   handle->flags |= UV_CLOSING;
   handle->close_cb = close_cb;
   handle->close_cb = close_cb;
@@ -517,6 +517,9 @@ int uv__close_nocheckstdio(int fd) {
 
 
 int uv__close(int fd) {
 int uv__close(int fd) {
   assert(fd > STDERR_FILENO);  /* Catch stdio close bugs. */
   assert(fd > STDERR_FILENO);  /* Catch stdio close bugs. */
+#if defined(__MVS__)
+  epoll_file_close(fd);
+#endif
   return uv__close_nocheckstdio(fd);
   return uv__close_nocheckstdio(fd);
 }
 }
 
 
@@ -836,13 +839,8 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
    * every tick of the event loop but the other backends allow us to
    * every tick of the event loop but the other backends allow us to
    * short-circuit here if the event mask is unchanged.
    * short-circuit here if the event mask is unchanged.
    */
    */
-  if (w->events == w->pevents) {
-    if (w->events == 0 && !QUEUE_EMPTY(&w->watcher_queue)) {
-      QUEUE_REMOVE(&w->watcher_queue);
-      QUEUE_INIT(&w->watcher_queue);
-    }
+  if (w->events == w->pevents)
     return;
     return;
-  }
 #endif
 #endif
 
 
   if (QUEUE_EMPTY(&w->watcher_queue))
   if (QUEUE_EMPTY(&w->watcher_queue))
@@ -1236,3 +1234,9 @@ void uv_os_free_passwd(uv_passwd_t* pwd) {
 int uv_os_get_passwd(uv_passwd_t* pwd) {
 int uv_os_get_passwd(uv_passwd_t* pwd) {
   return uv__getpwuid_r(pwd);
   return uv__getpwuid_r(pwd);
 }
 }
+
+
+int uv_translate_sys_error(int sys_errno) {
+  /* If < 0 then it's already a libuv error. */
+  return sys_errno <= 0 ? sys_errno : -sys_errno;
+}

+ 31 - 26
src/unix/fs.c

@@ -129,8 +129,23 @@
 static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
 static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
 #if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
 #if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
   return fdatasync(req->file);
   return fdatasync(req->file);
-#elif defined(__APPLE__) && defined(SYS_fdatasync)
-  return syscall(SYS_fdatasync, req->file);
+#elif 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.
+   */
+  return fcntl(req->file, F_FULLFSYNC);
+#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);
 #else
 #else
   return fsync(req->file);
   return fsync(req->file);
 #endif
 #endif
@@ -365,7 +380,6 @@ static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) {
 
 
 static ssize_t uv__fs_scandir(uv_fs_t* req) {
 static ssize_t uv__fs_scandir(uv_fs_t* req) {
   uv__dirent_t **dents;
   uv__dirent_t **dents;
-  int saved_errno;
   int n;
   int n;
 
 
   dents = NULL;
   dents = NULL;
@@ -374,28 +388,17 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) {
   /* NOTE: We will use nbufs as an index field */
   /* NOTE: We will use nbufs as an index field */
   req->nbufs = 0;
   req->nbufs = 0;
 
 
-  if (n == 0)
-    goto out; /* osx still needs to deallocate some memory */
-  else if (n == -1)
-    return n;
-
-  req->ptr = dents;
-
-  return n;
-
-out:
-  saved_errno = errno;
-  if (dents != NULL) {
-    int i;
-
-    /* Memory was allocated using the system allocator, so use free() here. */
-    for (i = 0; i < n; i++)
-      free(dents[i]);
+  if (n == 0) {
+    /* OS X still needs to deallocate some memory.
+     * Memory was allocated using the system allocator, so use free() here.
+     */
     free(dents);
     free(dents);
+    dents = NULL;
+  } else if (n == -1) {
+    return n;
   }
   }
-  errno = saved_errno;
 
 
-  req->ptr = NULL;
+  req->ptr = dents;
 
 
   return n;
   return n;
 }
 }
@@ -798,6 +801,10 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
   dst->st_flags = 0;
   dst->st_flags = 0;
   dst->st_gen = 0;
   dst->st_gen = 0;
 #elif !defined(_AIX) && (       \
 #elif !defined(_AIX) && (       \
+    defined(__DragonFly__)   || \
+    defined(__FreeBSD__)     || \
+    defined(__OpenBSD__)     || \
+    defined(__NetBSD__)      || \
     defined(_GNU_SOURCE)     || \
     defined(_GNU_SOURCE)     || \
     defined(_BSD_SOURCE)     || \
     defined(_BSD_SOURCE)     || \
     defined(_SVID_SOURCE)    || \
     defined(_SVID_SOURCE)    || \
@@ -809,9 +816,7 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
   dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec;
   dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec;
   dst->st_ctim.tv_sec = src->st_ctim.tv_sec;
   dst->st_ctim.tv_sec = src->st_ctim.tv_sec;
   dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec;
   dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec;
-# if defined(__DragonFly__)  || \
-     defined(__FreeBSD__)    || \
-     defined(__OpenBSD__)    || \
+# if defined(__FreeBSD__)    || \
      defined(__NetBSD__)
      defined(__NetBSD__)
   dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec;
   dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec;
   dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec;
   dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec;
@@ -945,7 +950,7 @@ static void uv__fs_work(struct uv__work* w) {
     X(FCHOWN, fchown(req->file, req->uid, req->gid));
     X(FCHOWN, fchown(req->file, req->uid, req->gid));
     X(FDATASYNC, uv__fs_fdatasync(req));
     X(FDATASYNC, uv__fs_fdatasync(req));
     X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
     X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
-    X(FSYNC, fsync(req->file));
+    X(FSYNC, uv__fs_fsync(req));
     X(FTRUNCATE, ftruncate(req->file, req->off));
     X(FTRUNCATE, ftruncate(req->file, req->off));
     X(FUTIME, uv__fs_futime(req));
     X(FUTIME, uv__fs_futime(req));
     X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
     X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));

+ 7 - 2
src/unix/internal.h

@@ -38,6 +38,10 @@
 # include "linux-syscalls.h"
 # include "linux-syscalls.h"
 #endif /* __linux__ */
 #endif /* __linux__ */
 
 
+#if defined(__MVS__)
+# include "os390-syscalls.h"
+#endif /* __MVS__ */
+
 #if defined(__sun)
 #if defined(__sun)
 # include <sys/port.h>
 # include <sys/port.h>
 # include <port.h>
 # include <port.h>
@@ -52,7 +56,7 @@
 #endif /* _AIX */
 #endif /* _AIX */
 
 
 #if defined(__APPLE__) && !TARGET_OS_IPHONE
 #if defined(__APPLE__) && !TARGET_OS_IPHONE
-# include <CoreServices/CoreServices.h>
+# include <AvailabilityMacros.h>
 #endif
 #endif
 
 
 #if defined(__ANDROID__)
 #if defined(__ANDROID__)
@@ -158,7 +162,8 @@ struct uv__stream_queued_fds_s {
     defined(__DragonFly__) || \
     defined(__DragonFly__) || \
     defined(__FreeBSD__) || \
     defined(__FreeBSD__) || \
     defined(__FreeBSD_kernel__) || \
     defined(__FreeBSD_kernel__) || \
-    defined(__linux__)
+    defined(__linux__) || \
+    defined(__OpenBSD__)
 #define uv__cloexec uv__cloexec_ioctl
 #define uv__cloexec uv__cloexec_ioctl
 #define uv__nonblock uv__nonblock_ioctl
 #define uv__nonblock uv__nonblock_ioctl
 #else
 #else

+ 1 - 1
src/unix/openbsd.c

@@ -163,7 +163,7 @@ char** uv_setup_args(int argc, char** argv) {
 int uv_set_process_title(const char* title) {
 int uv_set_process_title(const char* title) {
   uv__free(process_title);
   uv__free(process_title);
   process_title = uv__strdup(title);
   process_title = uv__strdup(title);
-  setproctitle(title);
+  setproctitle("%s", title);
   return 0;
   return 0;
 }
 }
 
 

+ 334 - 0
src/unix/os390-syscalls.c

@@ -0,0 +1,334 @@
+/* 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 "os390-syscalls.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <search.h>
+
+#define CW_CONDVAR 32
+
+#pragma linkage(BPX4CTW, OS)
+#pragma linkage(BPX1CTW, OS)
+
+static int number_of_epolls;
+static QUEUE global_epoll_queue;
+static uv_mutex_t global_epoll_lock;
+static uv_once_t once = UV_ONCE_INIT;
+
+int scandir(const char* maindir, struct dirent*** namelist,
+            int (*filter)(const struct dirent*),
+            int (*compar)(const struct dirent**,
+            const struct dirent **)) {
+  struct dirent** nl;
+  struct dirent* dirent;
+  unsigned count;
+  size_t allocated;
+  DIR* mdir;
+
+  nl = NULL;
+  count = 0;
+  allocated = 0;
+  mdir = opendir(maindir);
+  if (!mdir)
+    return -1;
+
+  while (1) {
+    dirent = readdir(mdir);
+    if (!dirent)
+      break;
+    if (!filter || filter(dirent)) {
+      struct dirent* copy;
+      copy = uv__malloc(sizeof(*copy));
+      if (!copy) {
+        while (count) {
+          dirent = nl[--count];
+          uv__free(dirent);
+        }
+        uv__free(nl);
+        closedir(mdir);
+        errno = ENOMEM;
+        return -1;
+      }
+      memcpy(copy, dirent, sizeof(*copy));
+
+      nl = uv__realloc(nl, sizeof(*copy) * (count + 1));
+      nl[count++] = copy;
+    }
+  }
+
+  qsort(nl, count, sizeof(struct dirent *),
+       (int (*)(const void *, const void *)) compar);
+
+  closedir(mdir);
+
+  *namelist = nl;
+  return count;
+}
+
+
+static unsigned int next_power_of_two(unsigned int val) {
+  val -= 1;
+  val |= val >> 1;
+  val |= val >> 2;
+  val |= val >> 4;
+  val |= val >> 8;
+  val |= val >> 16;
+  val += 1;
+  return val;
+}
+
+
+static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
+  unsigned int newsize;
+  unsigned int i;
+  struct pollfd* newlst;
+
+  if (len <= lst->size)
+    return;
+
+  newsize = next_power_of_two(len);
+  newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0]));
+
+  if (newlst == NULL)
+    abort();
+  for (i = lst->size; i < newsize; ++i)
+    newlst[i].fd = -1;
+
+  lst->items = newlst;
+  lst->size = newsize;
+}
+
+
+static void epoll_init() {
+  QUEUE_INIT(&global_epoll_queue);
+  if (uv_mutex_init(&global_epoll_lock))
+    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);
+
+  /* initialize list */
+  lst->size = 0;
+  lst->items = NULL;
+  return lst;
+}
+
+
+int epoll_ctl(uv__os390_epoll* lst,
+              int op,
+              int fd,
+              struct epoll_event *event) {
+  if(op == EPOLL_CTL_DEL) {
+    if (fd >= lst->size || lst->items[fd].fd == -1) {
+      errno = ENOENT;
+      return -1;
+    }
+    lst->items[fd].fd = -1;
+  } else if(op == EPOLL_CTL_ADD) {
+    maybe_resize(lst, fd + 1);
+    if (lst->items[fd].fd != -1) {
+      errno = EEXIST;
+      return -1;
+    }
+    lst->items[fd].fd = fd;
+    lst->items[fd].events = event->events;
+  } else if(op == EPOLL_CTL_MOD) {
+    if (fd >= lst->size || lst->items[fd].fd == -1) {
+      errno = ENOENT;
+      return -1;
+    }
+    lst->items[fd].events = event->events;
+  } else
+    abort();
+
+  return 0;
+}
+
+
+int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
+               int maxevents, int timeout) {
+  size_t size;
+  struct pollfd* pfds;
+  int pollret;
+  int reventcount;
+
+  uv_mutex_lock(&global_epoll_lock);
+  uv_mutex_unlock(&global_epoll_lock);
+  size = lst->size;
+  pfds = lst->items;
+  pollret = poll(pfds, size, timeout);
+  if(pollret == -1)
+    return pollret;
+
+  reventcount = 0;
+  for (int i = 0; i < lst->size && i < maxevents; ++i) {
+    struct epoll_event ev;
+
+    ev.events = 0;
+    ev.fd = pfds[i].fd;
+    if(!pfds[i].revents)
+      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;
+    events[reventcount++] = ev;
+  }
+
+  return reventcount;
+}
+
+
+int epoll_file_close(int fd) {
+  QUEUE* q;
+
+  uv_once(&once, epoll_init);
+  uv_mutex_lock(&global_epoll_lock);
+  QUEUE_FOREACH(q, &global_epoll_queue) {
+    uv__os390_epoll* lst;
+
+    lst = QUEUE_DATA(q, uv__os390_epoll, member);
+    if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1)
+      lst->items[fd].fd = -1;
+  }
+
+  uv_mutex_unlock(&global_epoll_lock);
+  return 0;
+}
+
+void epoll_queue_close(uv__os390_epoll* lst) {
+  uv_mutex_lock(&global_epoll_lock);
+  QUEUE_REMOVE(&lst->member);
+  uv_mutex_unlock(&global_epoll_lock);
+  uv__free(lst->items);
+  lst->items = NULL;
+}
+
+
+int nanosleep(const struct timespec* req, struct timespec* rem) {
+  unsigned nano;
+  unsigned seconds;
+  unsigned events;
+  unsigned secrem;
+  unsigned nanorem;
+  int rv;
+  int rc;
+  int rsn;
+
+  nano = (int)req->tv_nsec;
+  seconds = req->tv_sec;
+  events = CW_CONDVAR;
+
+#if defined(_LP64)
+  BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn);
+#else
+  BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn);
+#endif
+
+  assert(rv == -1 && errno == EAGAIN);
+
+  if(rem != NULL) {
+    rem->tv_nsec = nanorem;
+    rem->tv_sec = secrem;
+  }
+
+  return 0;
+}
+
+
+char* mkdtemp(char* path) {
+  static const char* tempchars =
+    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+  static const size_t num_chars = 62;
+  static const size_t num_x = 6;
+  char *ep, *cp;
+  unsigned int tries, i;
+  size_t len;
+  uint64_t v;
+  int fd;
+  int retval;
+  int saved_errno;
+
+  len = strlen(path);
+  ep = path + len;
+  if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  fd = open("/dev/urandom", O_RDONLY);
+  if (fd == -1)
+    return NULL;
+
+  tries = TMP_MAX;
+  retval = -1;
+  do {
+    if (read(fd, &v, sizeof(v)) != sizeof(v))
+      break;
+
+    cp = ep - num_x;
+    for (i = 0; i < num_x; i++) {
+      *cp++ = tempchars[v % num_chars];
+      v /= num_chars;
+    }
+
+    if (mkdir(path, S_IRWXU) == 0) {
+      retval = 0;
+      break;
+    }
+    else if (errno != EEXIST)
+      break;
+  } while (--tries);
+
+  saved_errno = errno;
+  uv__close(fd);
+  if (tries == 0) {
+    errno = EEXIST;
+    return NULL;
+  }
+
+  if (retval == -1) {
+    errno = saved_errno;
+    return NULL;
+  }
+
+  return path;
+}

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

@@ -0,0 +1,69 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+#ifndef UV_OS390_SYSCALL_H_
+#define UV_OS390_SYSCALL_H_
+
+#include "uv.h"
+#include "internal.h"
+#include <dirent.h>
+#include <poll.h>
+#include <pthread.h>
+
+#define EPOLL_CTL_ADD             1
+#define EPOLL_CTL_DEL             2
+#define EPOLL_CTL_MOD             3
+#define MAX_EPOLL_INSTANCES       256
+#define MAX_ITEMS_PER_EPOLL       1024
+
+#define UV__O_CLOEXEC             0x80000
+#define UV__EPOLL_CLOEXEC         UV__O_CLOEXEC
+#define UV__EPOLL_CTL_ADD         EPOLL_CTL_ADD
+#define UV__EPOLL_CTL_DEL         EPOLL_CTL_DEL
+#define UV__EPOLL_CTL_MOD         EPOLL_CTL_MOD
+
+struct epoll_event {
+  int events;
+  int fd;
+};
+
+typedef struct {
+  QUEUE member;
+  struct pollfd* items;
+  unsigned long size;
+} uv__os390_epoll;
+
+/* epoll api */
+uv__os390_epoll* epoll_create1(int flags);
+int epoll_ctl(uv__os390_epoll* ep, int op, int fd, struct epoll_event *event);
+int epoll_wait(uv__os390_epoll* ep, struct epoll_event *events, int maxevents, int timeout);
+int epoll_file_close(int fd);
+
+/* utility functions */
+int nanosleep(const struct timespec* req, struct timespec* rem);
+int scandir(const char* maindir, struct dirent*** namelist,
+            int (*filter)(const struct dirent *),
+            int (*compar)(const struct dirent **,
+            const struct dirent **));
+char *mkdtemp(char* path);
+
+#endif /* UV_OS390_SYSCALL_H_ */

+ 823 - 0
src/unix/os390.c

@@ -20,6 +20,628 @@
  */
  */
 
 
 #include "internal.h"
 #include "internal.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <utmpx.h>
+#include <unistd.h>
+#include <sys/ps.h>
+#if defined(__clang__)
+#include "csrsic.h"
+#else
+#include "//'SYS1.SAMPLIB(CSRSIC)'"
+#endif
+
+#define CVT_PTR           0x10
+#define CSD_OFFSET        0x294
+
+/*
+    Long-term average CPU service used by this logical partition,
+    in millions of service units per hour. If this value is above
+    the partition's defined capacity, the partition will be capped.
+    It is calculated using the physical CPU adjustment factor
+    (RCTPCPUA) so it may not match other measures of service which
+    are based on the logical CPU adjustment factor. It is available
+    if the hardware supports LPAR cluster.
+*/
+#define RCTLACS_OFFSET    0xC4
+
+/* 32-bit count of alive CPUs. This includes both CPs and IFAs */
+#define CSD_NUMBER_ONLINE_CPUS        0xD4
+
+/* Address of system resources manager (SRM) control table */
+#define CVTOPCTP_OFFSET   0x25C
+
+/* Address of the RCT table */
+#define RMCTRCT_OFFSET    0xE4
+
+/* Address of the rsm control and enumeration area. */
+#define CVTRCEP_OFFSET    0x490
+
+/*
+    Number of frames currently available to system.
+    Excluded are frames backing perm storage, frames offline, and bad frames.
+*/
+#define RCEPOOL_OFFSET    0x004
+
+/* Total number of frames currently on all available frame queues. */
+#define RCEAFC_OFFSET     0x088
+
+/* CPC model length from the CSRSI Service. */
+#define CPCMODEL_LENGTH   16
+
+/* Thread Entry constants */
+#define PGTH_CURRENT  1
+#define PGTH_LEN      26
+#define PGTHAPATH     0x20
+#pragma linkage(BPX4GTH, OS)
+#pragma linkage(BPX1GTH, OS)
+
+typedef unsigned data_area_ptr_assign_type;
+
+typedef union {
+  struct {
+#if defined(_LP64)
+    data_area_ptr_assign_type lower;
+#endif
+    data_area_ptr_assign_type assign;
+  };
+  char* deref;
+} data_area_ptr;
+
+
+void uv_loadavg(double avg[3]) {
+  /* TODO: implement the following */
+  avg[0] = 0;
+  avg[1] = 0;
+  avg[2] = 0;
+}
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+  uv__os390_epoll* ep;
+
+  ep = epoll_create1(UV__EPOLL_CLOEXEC);
+  loop->ep = ep;
+  if (ep == NULL)
+    return -errno;
+
+  return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+  if (loop->ep != NULL) {
+    epoll_queue_close(loop->ep);
+    loop->ep = NULL;
+  }
+}
+
+
+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;
+}
+
+
+/*
+    Get the exe path using the thread entry information
+    in the address space.
+*/
+static int getexe(const int pid, char* buf, size_t len) {
+  struct {
+    int pid;
+    int thid[2];
+    char accesspid;
+    char accessthid;
+    char asid[2];
+    char loginname[8];
+    char flag;
+    char len;
+  } Input_data;
+
+  union {
+    struct {
+      char gthb[4];
+      int pid;
+      int thid[2];
+      char accesspid;
+      char accessthid[3];
+      int lenused;
+      int offsetProcess;
+      int offsetConTTY;
+      int offsetPath;
+      int offsetCommand;
+      int offsetFileData;
+      int offsetThread;
+    } Output_data;
+    char buf[2048];
+  } Output_buf;
+
+  struct Output_path_type {
+    char gthe[4];
+    short int len;
+    char path[1024];
+  };
+
+  int Input_length;
+  int Output_length;
+  void* Input_address;
+  void* Output_address;
+  struct Output_path_type* Output_path;
+  int rv;
+  int rc;
+  int rsn;
+
+  Input_length = PGTH_LEN;
+  Output_length = sizeof(Output_buf);
+  Output_address = &Output_buf;
+  Input_address = &Input_data;
+  memset(&Input_data, 0, sizeof Input_data);
+  Input_data.flag |= PGTHAPATH;
+  Input_data.pid = pid;
+  Input_data.accesspid = PGTH_CURRENT;
+
+#ifdef _LP64
+  BPX4GTH(&Input_length,
+          &Input_address,
+          &Output_length,
+          &Output_address,
+          &rv,
+          &rc,
+          &rsn);
+#else
+  BPX1GTH(&Input_length,
+          &Input_address,
+          &Output_length,
+          &Output_address,
+          &rv,
+          &rc,
+          &rsn);
+#endif
+
+  if (rv == -1) {
+    errno = rc;
+    return -1;
+  }
+
+  /* Check highest byte to ensure data availability */
+  assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A');
+
+  /* Get the offset from the lowest 3 bytes */
+  Output_path = (char*)(&Output_buf) +
+                (Output_buf.Output_data.offsetPath & 0x00FFFFFF);
+
+  if (Output_path->len >= len) {
+    errno = ENOBUFS;
+    return -1;
+  }
+
+  strncpy(buf, Output_path->path, len);
+
+  return 0;
+}
+
+
+/*
+ * 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 zOS - 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;
+  int pid;
+
+  if (buffer == NULL || size == NULL || *size == 0)
+    return -EINVAL;
+
+  pid = getpid();
+  res = getexe(pid, 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) {
+  uint64_t freeram;
+
+  data_area_ptr cvt = {0};
+  data_area_ptr rcep = {0};
+  cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
+  rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
+  freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4;
+  return freeram;
+}
+
+
+uint64_t uv_get_total_memory(void) {
+  uint64_t totalram;
+
+  data_area_ptr cvt = {0};
+  data_area_ptr rcep = {0};
+  cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
+  rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
+  totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4;
+  return totalram;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+  W_PSPROC buf;
+
+  memset(&buf, 0, sizeof(buf));
+  if (w_getpsent(0, &buf, sizeof(W_PSPROC)) == -1)
+    return -EINVAL;
+
+  *rss = buf.ps_size;
+  return 0;
+}
+
+
+int uv_uptime(double* uptime) {
+  struct utmpx u ;
+  struct utmpx *v;
+  time64_t t;
+
+  u.ut_type = BOOT_TIME;
+  v = getutxid(&u);
+  if (v == NULL)
+    return -1;
+  *uptime = difftime64(time64(&t), v->ut_tv.tv_sec);
+  return 0;
+}
+
+
+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};
+  data_area_ptr csd = {0};
+  data_area_ptr rmctrct = {0};
+  data_area_ptr cvtopctp = {0};
+  int cpu_usage_avg;
+
+  cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
+
+  csd.assign = *((data_area_ptr_assign_type *) (cvt.deref + CSD_OFFSET));
+  cvtopctp.assign = *((data_area_ptr_assign_type *) (cvt.deref + CVTOPCTP_OFFSET));
+  rmctrct.assign = *((data_area_ptr_assign_type *) (cvtopctp.deref + RMCTRCT_OFFSET));
+
+  *count = *((int*) (csd.deref + CSD_NUMBER_ONLINE_CPUS));
+  cpu_usage_avg = *((unsigned short int*) (rmctrct.deref + RCTLACS_OFFSET));
+
+  *cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t));
+  if (!*cpu_infos)
+    return -ENOMEM;
+
+  cpu_info = *cpu_infos;
+  idx = 0;
+  while (idx < *count) {
+    cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability);
+    cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1);
+    memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1);
+    memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH);
+    cpu_info->cpu_times.user = cpu_usage_avg;
+    /* TODO: implement the following */
+    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;
+    ++idx;
+  }
+
+  return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+  for (int i = 0; i < count; ++i)
+    uv__free(cpu_infos[i].model);
+  uv__free(cpu_infos);
+}
+
+
+static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
+                                      int* count) {
+  uv_interface_address_t* address;
+  int sockfd;
+  int maxsize;
+  __net_ifconf6header_t ifc;
+  __net_ifconf6entry_t* ifr;
+  __net_ifconf6entry_t* p;
+  __net_ifconf6entry_t flg;
+
+  *count = 0;
+  /* Assume maximum buffer size allowable */
+  maxsize = 16384;
+
+  if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
+    return -errno;
+
+  ifc.__nif6h_version = 1;
+  ifc.__nif6h_buflen = maxsize;
+  ifc.__nif6h_buffer = uv__calloc(1, maxsize);;
+
+  if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
+    uv__close(sockfd);
+    return -errno;
+  }
+
+
+  *count = 0;
+  ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
+  while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
+    p = ifr;
+    ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
+
+    if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
+          p->__nif6e_addr.sin6_family == AF_INET))
+      continue;
+
+    if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
+      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 = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
+  while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
+    p = ifr;
+    ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
+
+    if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
+          p->__nif6e_addr.sin6_family == AF_INET))
+      continue;
+
+    if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
+      continue;
+
+    /* All conditions above must match count loop */
+
+    address->name = uv__strdup(p->__nif6e_name);
+
+    if (p->__nif6e_addr.sin6_family == AF_INET6)
+      address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
+    else
+      address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr);
+
+    /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
+
+    address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
+
+    address++;
+  }
+
+  uv__close(sockfd);
+  return 0;
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+  uv_interface_address_t* address;
+  int sockfd;
+  int maxsize;
+  struct ifconf ifc;
+  struct ifreq flg;
+  struct ifreq* ifr;
+  struct ifreq* p;
+  int count_v6;
+
+  /* get the ipv6 addresses first */
+  uv_interface_address_t* addresses_v6;
+  uv__interface_addresses_v6(&addresses_v6, &count_v6);
+
+  /* now get the ipv4 addresses */
+  *count = 0;
+
+  /* Assume maximum buffer size allowable */
+  maxsize = 16384;
+
+  sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+  if (0 > sockfd)
+    return -errno;
+
+  ifc.ifc_req = uv__calloc(1, maxsize);
+  ifc.ifc_len = maxsize;
+  if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
+    uv__close(sockfd);
+    return -errno;
+  }
+
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#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 + count_v6) *
+                          sizeof(uv_interface_address_t));
+
+  if (!(*addresses)) {
+    uv__close(sockfd);
+    return -ENOMEM;
+  }
+  address = *addresses;
+
+  /* copy over the ipv6 addresses */
+  memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
+  address += count_v6;
+  *count += count_v6;
+  uv__free(addresses_v6);
+
+  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);
+    }
+
+    address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
+    address++;
+  }
+
+#undef ADDR_SIZE
+#undef MAX
+
+  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 epoll_event* events;
+  struct epoll_event dummy;
+  uintptr_t i;
+  uintptr_t nfds;
+
+  assert(loop->watchers != NULL);
+
+  events = (struct epoll_event*) loop->watchers[loop->nwatchers];
+  nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+  if (events != NULL)
+    /* Invalidate events with same file descriptor */
+    for (i = 0; i < nfds; i++)
+      if ((int) events[i].fd == fd)
+        events[i].fd = -1;
+
+  /* Remove the file descriptor from the epoll. */
+  if (loop->ep != NULL)
+    epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy);
+}
+
 
 
 int uv__io_check_fd(uv_loop_t* loop, int fd) {
 int uv__io_check_fd(uv_loop_t* loop, int fd) {
   struct pollfd p[1];
   struct pollfd p[1];
@@ -40,3 +662,204 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) {
 
 
   return 0;
   return 0;
 }
 }
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+  UNREACHABLE();
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+  return -ENOSYS;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
+                      const char* filename, unsigned int flags) {
+  return -ENOSYS;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+  return -ENOSYS;
+}
+
+
+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;
+  int real_timeout;
+  QUEUE* q;
+  uv__io_t* w;
+  uint64_t base;
+  int count;
+  int nfds;
+  int fd;
+  int op;
+  int i;
+
+  if (loop->nfds == 0) {
+    assert(QUEUE_EMPTY(&loop->watcher_queue));
+    return;
+  }
+
+  while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+    uv_stream_t* stream;
+
+    q = QUEUE_HEAD(&loop->watcher_queue);
+    QUEUE_REMOVE(q);
+    QUEUE_INIT(q);
+    w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+
+    assert(w->pevents != 0);
+    assert(w->fd >= 0);
+
+    stream= container_of(w, uv_stream_t, io_watcher);
+
+    assert(w->fd < (int) loop->nwatchers);
+
+    e.events = w->pevents;
+    e.fd = w->fd;
+
+    if (w->events == 0)
+      op = UV__EPOLL_CTL_ADD;
+    else
+      op = UV__EPOLL_CTL_MOD;
+
+    /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
+     * events, skip the syscall and squelch the events after epoll_wait().
+     */
+    if (epoll_ctl(loop->ep, op, w->fd, &e)) {
+      if (errno != EEXIST)
+        abort();
+
+      assert(op == UV__EPOLL_CTL_ADD);
+
+      /* We've reactivated a file descriptor that's been watched before. */
+      if (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e))
+        abort();
+    }
+
+    w->events = w->pevents;
+  }
+
+  assert(timeout >= -1);
+  base = loop->time;
+  count = 48; /* Benchmarks suggest this gives the best throughput. */
+  real_timeout = timeout;
+  int nevents = 0;
+
+  nfds = 0;
+  for (;;) {
+    if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
+      timeout = max_safe_timeout;
+
+    nfds = epoll_wait(loop->ep, events,
+                      ARRAY_SIZE(events), timeout);
+
+    /* Update loop->time unconditionally. It's tempting to skip the update when
+     * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+     * operating system didn't reschedule our process while in the syscall.
+     */
+    base = loop->time;
+    SAVE_ERRNO(uv__update_time(loop));
+    if (nfds == 0) {
+      assert(timeout != -1);
+      timeout = real_timeout - timeout;
+      if (timeout > 0)
+        continue;
+
+      return;
+    }
+
+    if (nfds == -1) {
+
+      if (errno != EINTR)
+        abort();
+
+      if (timeout == -1)
+        continue;
+
+      if (timeout == 0)
+        return;
+
+      /* Interrupted by a signal. Update timeout and poll again. */
+      goto update_timeout;
+    }
+
+
+    assert(loop->watchers != NULL);
+    loop->watchers[loop->nwatchers] = (void*) events;
+    loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+    for (i = 0; i < nfds; i++) {
+      pe = events + i;
+      fd = pe->fd;
+
+      /* Skip invalidated events, see uv__platform_invalidate_fd */
+      if (fd == -1)
+        continue;
+
+      assert(fd >= 0);
+      assert((unsigned) fd < loop->nwatchers);
+
+      w = loop->watchers[fd];
+
+      if (w == NULL) {
+        /* File descriptor that we've stopped watching, disarm it.
+         *
+         * Ignore all errors because we may be racing with another thread
+         * when the file descriptor is closed.
+         */
+        epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, pe);
+        continue;
+      }
+
+      /* Give users only events they're interested in. Prevents spurious
+       * callbacks when previous callback invocation in this loop has stopped
+       * the current watcher. Also, filters out events that users has not
+       * requested us to watch.
+       */
+      pe->events &= w->pevents | POLLERR | POLLHUP;
+
+      if (pe->events == POLLERR || pe->events == POLLHUP)
+        pe->events |= w->pevents & (POLLIN | POLLOUT);
+
+      if (pe->events != 0) {
+        w->cb(loop, w, pe->events);
+        nevents++;
+      }
+    }
+    loop->watchers[loop->nwatchers] = NULL;
+    loop->watchers[loop->nwatchers + 1] = NULL;
+
+    if (nevents != 0) {
+      if (nfds == ARRAY_SIZE(events) && --count != 0) {
+        /* Poll for more events but don't block this time. */
+        timeout = 0;
+        continue;
+      }
+      return;
+    }
+
+    if (timeout == 0)
+      return;
+
+    if (timeout == -1)
+      continue;
+
+update_timeout:
+    assert(timeout > 0);
+
+    real_timeout -= (loop->time - base);
+    if (real_timeout <= 0)
+      return;
+
+    timeout = real_timeout;
+  }
+}
+
+void uv__set_process_title(const char* title) {
+  /* do nothing */
+}

+ 2 - 2
src/unix/poll.c

@@ -92,7 +92,7 @@ static void uv__poll_stop(uv_poll_t* handle) {
 
 
 
 
 int uv_poll_stop(uv_poll_t* handle) {
 int uv_poll_stop(uv_poll_t* handle) {
-  assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+  assert(!uv__is_closing(handle));
   uv__poll_stop(handle);
   uv__poll_stop(handle);
   return 0;
   return 0;
 }
 }
@@ -102,7 +102,7 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
   int events;
   int events;
 
 
   assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
   assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
-  assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+  assert(!uv__is_closing(handle));
 
 
   uv__poll_stop(handle);
   uv__poll_stop(handle);
 
 

+ 2 - 2
src/unix/process.c

@@ -323,7 +323,7 @@ static void uv__process_child_init(const uv_process_options_t* options,
     }
     }
 
 
     if (fd == use_fd)
     if (fd == use_fd)
-      uv__cloexec(use_fd, 0);
+      uv__cloexec_fcntl(use_fd, 0);
     else
     else
       fd = dup2(use_fd, fd);
       fd = dup2(use_fd, fd);
 
 
@@ -333,7 +333,7 @@ static void uv__process_child_init(const uv_process_options_t* options,
     }
     }
 
 
     if (fd <= 2)
     if (fd <= 2)
-      uv__nonblock(fd, 0);
+      uv__nonblock_fcntl(fd, 0);
 
 
     if (close_fd >= stdio_count)
     if (close_fd >= stdio_count)
       uv__close(close_fd);
       uv__close(close_fd);

+ 6 - 0
src/unix/proctitle.c

@@ -48,9 +48,15 @@ char** uv_setup_args(int argc, char** argv) {
   for (i = 0; i < argc; i++)
   for (i = 0; i < argc; i++)
     size += strlen(argv[i]) + 1;
     size += strlen(argv[i]) + 1;
 
 
+#if defined(__MVS__)
+  /* argv is not adjacent. So just use argv[0] */
+  process_title.str = argv[0];
+  process_title.len = strlen(argv[0]);
+#else
   process_title.str = argv[0];
   process_title.str = argv[0];
   process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
   process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
   assert(process_title.len + 1 == size);  /* argv memory should be adjacent. */
   assert(process_title.len + 1 == size);  /* argv memory should be adjacent. */
+#endif
 
 
   /* Add space for the argv pointers. */
   /* Add space for the argv pointers. */
   size += (argc + 1) * sizeof(char*);
   size += (argc + 1) * sizeof(char*);

+ 2 - 1
src/unix/pthread-barrier.c

@@ -73,7 +73,8 @@ int pthread_barrier_wait(pthread_barrier_t* barrier) {
   if (++b->in == b->threshold) {
   if (++b->in == b->threshold) {
     b->in = 0;
     b->in = 0;
     b->out = b->threshold - 1;
     b->out = b->threshold - 1;
-    assert(pthread_cond_signal(&b->cond) == 0);
+    rc = pthread_cond_signal(&b->cond);
+    assert(rc == 0);
 
 
     pthread_mutex_unlock(&b->mutex);
     pthread_mutex_unlock(&b->mutex);
     return PTHREAD_BARRIER_SERIAL_THREAD;
     return PTHREAD_BARRIER_SERIAL_THREAD;

+ 4 - 4
src/unix/signal.c

@@ -43,7 +43,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2);
 static void uv__signal_stop(uv_signal_t* handle);
 static void uv__signal_stop(uv_signal_t* handle);
 
 
 
 
-static pthread_once_t uv__signal_global_init_guard = PTHREAD_ONCE_INIT;
+static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT;
 static struct uv__signal_tree_s uv__signal_tree =
 static struct uv__signal_tree_s uv__signal_tree =
     RB_INITIALIZER(uv__signal_tree);
     RB_INITIALIZER(uv__signal_tree);
 static int uv__signal_lock_pipefd[2];
 static int uv__signal_lock_pipefd[2];
@@ -64,7 +64,7 @@ static void uv__signal_global_init(void) {
 
 
 
 
 void uv__signal_global_once_init(void) {
 void uv__signal_global_once_init(void) {
-  pthread_once(&uv__signal_global_init_guard, uv__signal_global_init);
+  uv_once(&uv__signal_global_init_guard, uv__signal_global_init);
 }
 }
 
 
 
 
@@ -290,7 +290,7 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
   sigset_t saved_sigmask;
   sigset_t saved_sigmask;
   int err;
   int err;
 
 
-  assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+  assert(!uv__is_closing(handle));
 
 
   /* If the user supplies signum == 0, then return an error already. If the
   /* If the user supplies signum == 0, then return an error already. If the
    * signum is otherwise invalid then uv__signal_register will find out
    * signum is otherwise invalid then uv__signal_register will find out
@@ -434,7 +434,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
 
 
 
 
 int uv_signal_stop(uv_signal_t* handle) {
 int uv_signal_stop(uv_signal_t* handle) {
-  assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+  assert(!uv__is_closing(handle));
   uv__signal_stop(handle);
   uv__signal_stop(handle);
   return 0;
   return 0;
 }
 }

+ 27 - 4
src/unix/stream.c

@@ -390,7 +390,7 @@ failed_malloc:
 
 
 
 
 int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
 int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__MVS__)
   int enable;
   int enable;
 #endif
 #endif
 
 
@@ -409,7 +409,7 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
       return -errno;
       return -errno;
   }
   }
 
 
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__MVS__)
   enable = 1;
   enable = 1;
   if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) &&
   if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) &&
       errno != ENOTSOCK &&
       errno != ENOTSOCK &&
@@ -1194,6 +1194,30 @@ static void uv__read(uv_stream_t* stream) {
           return;
           return;
         }
         }
       }
       }
+
+#if defined(__MVS__)
+      if (is_ipc && msg.msg_controllen > 0) {
+        uv_buf_t blankbuf;
+        int nread;
+        struct iovec *old;
+
+        blankbuf.base = 0;
+        blankbuf.len = 0;
+        old = msg.msg_iov;
+        msg.msg_iov = (struct iovec*) &blankbuf;
+        nread = 0;
+        do {
+          nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
+          err = uv__stream_recv_cmsg(stream, &msg);
+          if (err != 0) {
+            stream->read_cb(stream, err, &buf);
+            msg.msg_iov = old;
+            return;
+          }
+        } while (nread == 0 && msg.msg_controllen > 0);
+        msg.msg_iov = old;
+      }
+#endif
       stream->read_cb(stream, nread, &buf);
       stream->read_cb(stream, nread, &buf);
 
 
       /* Return if we didn't fill the buffer, there is no more data to read. */
       /* Return if we didn't fill the buffer, there is no more data to read. */
@@ -1221,8 +1245,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
   if (!(stream->flags & UV_STREAM_WRITABLE) ||
   if (!(stream->flags & UV_STREAM_WRITABLE) ||
       stream->flags & UV_STREAM_SHUT ||
       stream->flags & UV_STREAM_SHUT ||
       stream->flags & UV_STREAM_SHUTTING ||
       stream->flags & UV_STREAM_SHUTTING ||
-      stream->flags & UV_CLOSED ||
-      stream->flags & UV_CLOSING) {
+      uv__is_closing(stream)) {
     return -ENOTCONN;
     return -ENOTCONN;
   }
   }
 
 

+ 6 - 5
src/unix/sunos.c

@@ -695,6 +695,11 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
   uv__free(cpu_infos);
   uv__free(cpu_infos);
 }
 }
 
 
+#ifdef SUNOS_NO_IFADDRS
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+  return -ENOSYS;
+}
+#else  /* SUNOS_NO_IFADDRS */
 /*
 /*
  * Inspired By:
  * Inspired By:
  * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris
  * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris
@@ -742,9 +747,6 @@ static int uv__set_phys_addr(uv_interface_address_t* address,
 }
 }
 
 
 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
-#ifdef SUNOS_NO_IFADDRS
-  return -ENOSYS;
-#else
   uv_interface_address_t* address;
   uv_interface_address_t* address;
   struct ifaddrs* addrs;
   struct ifaddrs* addrs;
   struct ifaddrs* ent;
   struct ifaddrs* ent;
@@ -805,9 +807,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   freeifaddrs(addrs);
   freeifaddrs(addrs);
 
 
   return 0;
   return 0;
-#endif  /* SUNOS_NO_IFADDRS */
 }
 }
-
+#endif  /* SUNOS_NO_IFADDRS */
 
 
 void uv_free_interface_addresses(uv_interface_address_t* addresses,
 void uv_free_interface_addresses(uv_interface_address_t* addresses,
   int count) {
   int count) {

+ 1 - 31
src/unix/thread.c

@@ -40,28 +40,8 @@
 #undef NANOSEC
 #undef NANOSEC
 #define NANOSEC ((uint64_t) 1e9)
 #define NANOSEC ((uint64_t) 1e9)
 
 
-struct thread_ctx {
-  void (*entry)(void* arg);
-  void* arg;
-};
-
-
-static void* uv__thread_start(void *arg)
-{
-  struct thread_ctx *ctx_p;
-  struct thread_ctx ctx;
-
-  ctx_p = arg;
-  ctx = *ctx_p;
-  uv__free(ctx_p);
-  ctx.entry(ctx.arg);
-
-  return 0;
-}
-
 
 
 int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
 int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
-  struct thread_ctx* ctx;
   int err;
   int err;
   pthread_attr_t* attr;
   pthread_attr_t* attr;
 #if defined(__APPLE__)
 #if defined(__APPLE__)
@@ -69,13 +49,6 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
   struct rlimit lim;
   struct rlimit lim;
 #endif
 #endif
 
 
-  ctx = uv__malloc(sizeof(*ctx));
-  if (ctx == NULL)
-    return UV_ENOMEM;
-
-  ctx->entry = entry;
-  ctx->arg = arg;
-
   /* On OSX threads other than the main thread are created with a reduced stack
   /* On OSX threads other than the main thread are created with a reduced stack
    * size by default, adjust it to RLIMIT_STACK.
    * size by default, adjust it to RLIMIT_STACK.
    */
    */
@@ -99,14 +72,11 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
   attr = NULL;
   attr = NULL;
 #endif
 #endif
 
 
-  err = pthread_create(tid, attr, uv__thread_start, ctx);
+  err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg);
 
 
   if (attr != NULL)
   if (attr != NULL)
     pthread_attr_destroy(attr);
     pthread_attr_destroy(attr);
 
 
-  if (err)
-    uv__free(ctx);
-
   return -err;
   return -err;
 }
 }
 
 

+ 13 - 1
src/uv-common.c

@@ -512,8 +512,18 @@ void uv__fs_scandir_cleanup(uv_fs_t* req) {
 int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
 int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
   uv__dirent_t** dents;
   uv__dirent_t** dents;
   uv__dirent_t* dent;
   uv__dirent_t* dent;
+  unsigned int* nbufs;
 
 
-  unsigned int* nbufs = uv__get_nbufs(req);
+  /* Check to see if req passed */
+  if (req->result < 0)
+    return req->result;
+
+  /* Ptr will be null if req was canceled or no files found */
+  if (!req->ptr)
+    return UV_EOF;
+
+  nbufs = uv__get_nbufs(req);
+  assert(nbufs);
 
 
   dents = req->ptr;
   dents = req->ptr;
 
 
@@ -613,7 +623,9 @@ uv_loop_t* uv_loop_new(void) {
 int uv_loop_close(uv_loop_t* loop) {
 int uv_loop_close(uv_loop_t* loop) {
   QUEUE* q;
   QUEUE* q;
   uv_handle_t* h;
   uv_handle_t* h;
+#ifndef NDEBUG
   void* saved_data;
   void* saved_data;
+#endif
 
 
   if (!QUEUE_EMPTY(&(loop)->active_reqs))
   if (!QUEUE_EMPTY(&(loop)->active_reqs))
     return UV_EBUSY;
     return UV_EBUSY;

+ 0 - 4
src/win/core.c

@@ -35,10 +35,6 @@
 #include "handle-inl.h"
 #include "handle-inl.h"
 #include "req-inl.h"
 #include "req-inl.h"
 
 
-
-static uv_loop_t default_loop_struct;
-static uv_loop_t* default_loop_ptr;
-
 /* uv_once initialization guards */
 /* uv_once initialization guards */
 static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
 static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
 
 

+ 1 - 0
src/win/error.c

@@ -71,6 +71,7 @@ int uv_translate_sys_error(int sys_errno) {
   switch (sys_errno) {
   switch (sys_errno) {
     case ERROR_NOACCESS:                    return UV_EACCES;
     case ERROR_NOACCESS:                    return UV_EACCES;
     case WSAEACCES:                         return UV_EACCES;
     case WSAEACCES:                         return UV_EACCES;
+    case ERROR_ELEVATION_REQUIRED:          return UV_EACCES;
     case ERROR_ADDRESS_ALREADY_ASSOCIATED:  return UV_EADDRINUSE;
     case ERROR_ADDRESS_ALREADY_ASSOCIATED:  return UV_EADDRINUSE;
     case WSAEADDRINUSE:                     return UV_EADDRINUSE;
     case WSAEADDRINUSE:                     return UV_EADDRINUSE;
     case WSAEADDRNOTAVAIL:                  return UV_EADDRNOTAVAIL;
     case WSAEADDRNOTAVAIL:                  return UV_EADDRNOTAVAIL;

+ 2 - 1
src/win/fs-event.c

@@ -188,7 +188,6 @@ int uv_fs_event_start(uv_fs_event_t* handle,
 
 
   if (is_path_dir) {
   if (is_path_dir) {
      /* path is a directory, so that's the directory that we will watch. */
      /* path is a directory, so that's the directory that we will watch. */
-    handle->dirw = pathw;
     dir_to_watch = pathw;
     dir_to_watch = pathw;
   } else {
   } else {
     /*
     /*
@@ -274,6 +273,8 @@ int uv_fs_event_start(uv_fs_event_t* handle,
     goto error;
     goto error;
   }
   }
 
 
+  assert(is_path_dir ? pathw != NULL : pathw == NULL);
+  handle->dirw = pathw;
   handle->req_pending = 1;
   handle->req_pending = 1;
   return 0;
   return 0;
 
 

+ 1 - 3
src/win/fs.c

@@ -123,7 +123,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
     const char* new_path, const int copy_path) {
     const char* new_path, const int copy_path) {
   char* buf;
   char* buf;
   char* pos;
   char* pos;
-  ssize_t buf_sz = 0, path_len, pathw_len = 0, new_pathw_len = 0;
+  ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0;
 
 
   /* new_path can only be set if path is also set. */
   /* new_path can only be set if path is also set. */
   assert(new_path == NULL || path != NULL);
   assert(new_path == NULL || path != NULL);
@@ -403,7 +403,6 @@ void fs__open(uv_fs_t* req) {
   switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
   switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
   case _O_RDONLY:
   case _O_RDONLY:
     access = FILE_GENERIC_READ;
     access = FILE_GENERIC_READ;
-    attributes |= FILE_FLAG_BACKUP_SEMANTICS;
     break;
     break;
   case _O_WRONLY:
   case _O_WRONLY:
     access = FILE_GENERIC_WRITE;
     access = FILE_GENERIC_WRITE;
@@ -418,7 +417,6 @@ void fs__open(uv_fs_t* req) {
   if (flags & _O_APPEND) {
   if (flags & _O_APPEND) {
     access &= ~FILE_WRITE_DATA;
     access &= ~FILE_WRITE_DATA;
     access |= FILE_APPEND_DATA;
     access |= FILE_APPEND_DATA;
-    attributes &= ~FILE_FLAG_BACKUP_SEMANTICS;
   }
   }
 
 
   /*
   /*

+ 1 - 2
src/win/getaddrinfo.c

@@ -262,8 +262,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
   int err;
   int err;
 
 
   if (req == NULL || (node == NULL && service == NULL)) {
   if (req == NULL || (node == NULL && service == NULL)) {
-    err = WSAEINVAL;
-    goto error;
+    return UV_EINVAL;
   }
   }
 
 
   uv_req_init(loop, (uv_req_t*)req);
   uv_req_init(loop, (uv_req_t*)req);

+ 1 - 0
src/win/process-stdio.c

@@ -372,6 +372,7 @@ int uv__stdio_create(uv_loop_t* loop,
 
 
           case FILE_TYPE_PIPE:
           case FILE_TYPE_PIPE:
             CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
             CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
+            break;
 
 
           case FILE_TYPE_CHAR:
           case FILE_TYPE_CHAR:
           case FILE_TYPE_REMOTE:
           case FILE_TYPE_REMOTE:

+ 1 - 1
src/win/process.c

@@ -492,7 +492,7 @@ WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
    *   input : hello\\"world
    *   input : hello\\"world
    *   output: "hello\\\\\"world"
    *   output: "hello\\\\\"world"
    *   input : hello world\
    *   input : hello world\
-   *   output: "hello world\"
+   *   output: "hello world\\"
    */
    */
 
 
   *(target++) = L'"';
   *(target++) = L'"';

+ 5 - 113
src/win/signal.c

@@ -30,12 +30,14 @@
 RB_HEAD(uv_signal_tree_s, uv_signal_s);
 RB_HEAD(uv_signal_tree_s, uv_signal_s);
 
 
 static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
 static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
-static ssize_t volatile uv__signal_control_handler_refs = 0;
 static CRITICAL_SECTION uv__signal_lock;
 static CRITICAL_SECTION uv__signal_lock;
 
 
+static BOOL WINAPI uv__signal_control_handler(DWORD type);
 
 
 void uv_signals_init() {
 void uv_signals_init() {
   InitializeCriticalSection(&uv__signal_lock);
   InitializeCriticalSection(&uv__signal_lock);
+  if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
+    abort();
 }
 }
 
 
 
 
@@ -125,102 +127,6 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) {
 }
 }
 
 
 
 
-static int uv__signal_register_control_handler() {
-  /* When this function is called, the uv__signal_lock must be held. */
-
-  /* If the console control handler has already been hooked, just add a */
-  /* reference. */
-  if (uv__signal_control_handler_refs > 0) {
-    uv__signal_control_handler_refs++;
-    return 0;
-  }
-
-  if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
-    return GetLastError();
-
-  uv__signal_control_handler_refs++;
-
-  return 0;
-}
-
-
-static void uv__signal_unregister_control_handler() {
-  /* When this function is called, the uv__signal_lock must be held. */
-  BOOL r;
-
-  /* Don't unregister if the number of console control handlers exceeds one. */
-  /* Just remove a reference in that case. */
-  if (uv__signal_control_handler_refs > 1) {
-    uv__signal_control_handler_refs--;
-    return;
-  }
-
-  assert(uv__signal_control_handler_refs == 1);
-
-  r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE);
-  /* This should never fail; if it does it is probably a bug in libuv. */
-  assert(r);
-
-  uv__signal_control_handler_refs--;
-}
-
-
-static int uv__signal_register(int signum) {
-  switch (signum) {
-    case SIGINT:
-    case SIGBREAK:
-    case SIGHUP:
-      return uv__signal_register_control_handler();
-
-    case SIGWINCH:
-      /* SIGWINCH is generated in tty.c. No need to register anything. */
-      return 0;
-
-    case SIGILL:
-    case SIGABRT_COMPAT:
-    case SIGFPE:
-    case SIGSEGV:
-    case SIGTERM:
-    case SIGABRT:
-      /* Signal is never raised. */
-      return 0;
-
-    default:
-      /* Invalid signal. */
-      return ERROR_INVALID_PARAMETER;
-  }
-}
-
-
-static void uv__signal_unregister(int signum) {
-  switch (signum) {
-    case SIGINT:
-    case SIGBREAK:
-    case SIGHUP:
-      uv__signal_unregister_control_handler();
-      return;
-
-    case SIGWINCH:
-      /* SIGWINCH is generated in tty.c. No need to unregister anything. */
-      return;
-
-    case SIGILL:
-    case SIGABRT_COMPAT:
-    case SIGFPE:
-    case SIGSEGV:
-    case SIGTERM:
-    case SIGABRT:
-      /* Nothing is registered for this signal. */
-      return;
-
-    default:
-      /* Libuv bug. */
-      assert(0 && "Invalid signum");
-      return;
-  }
-}
-
-
 int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
 int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
   uv_req_t* req;
   uv_req_t* req;
 
 
@@ -247,8 +153,6 @@ int uv_signal_stop(uv_signal_t* handle) {
 
 
   EnterCriticalSection(&uv__signal_lock);
   EnterCriticalSection(&uv__signal_lock);
 
 
-  uv__signal_unregister(handle->signum);
-
   removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
   removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
   assert(removed_handle == handle);
   assert(removed_handle == handle);
 
 
@@ -262,14 +166,9 @@ int uv_signal_stop(uv_signal_t* handle) {
 
 
 
 
 int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
 int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
-  int err;
-
-  /* If the user supplies signum == 0, then return an error already. If the */
-  /* signum is otherwise invalid then uv__signal_register will find out */
-  /* eventually. */
-  if (signum == 0) {
+  /* Test for invalid signal values. */
+  if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG))
     return UV_EINVAL;
     return UV_EINVAL;
-  }
 
 
   /* Short circuit: if the signal watcher is already watching {signum} don't */
   /* Short circuit: if the signal watcher is already watching {signum} don't */
   /* go through the process of deregistering and registering the handler. */
   /* go through the process of deregistering and registering the handler. */
@@ -289,13 +188,6 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
 
 
   EnterCriticalSection(&uv__signal_lock);
   EnterCriticalSection(&uv__signal_lock);
 
 
-  err = uv__signal_register(signum);
-  if (err) {
-    /* Uh-oh, didn't work. */
-    LeaveCriticalSection(&uv__signal_lock);
-    return uv_translate_sys_error(err);
-  }
-
   handle->signum = signum;
   handle->signum = signum;
   RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
   RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
 
 

+ 58 - 33
src/win/tty.c

@@ -56,6 +56,7 @@
 #define ANSI_BACKSLASH_SEEN   0x80
 #define ANSI_BACKSLASH_SEEN   0x80
 
 
 #define MAX_INPUT_BUFFER_LENGTH 8192
 #define MAX_INPUT_BUFFER_LENGTH 8192
+#define MAX_CONSOLE_CHAR 8192
 
 
 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
 #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
 #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
@@ -1003,6 +1004,9 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
   if (handle->tty.rd.last_key_len > 0) {
   if (handle->tty.rd.last_key_len > 0) {
     SET_REQ_SUCCESS(&handle->read_req);
     SET_REQ_SUCCESS(&handle->read_req);
     uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
     uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
+    /* Make sure no attempt is made to insert it again until it's handled. */
+    handle->flags |= UV_HANDLE_READ_PENDING;
+    handle->reqs_pending++;
     return 0;
     return 0;
   }
   }
 
 
@@ -1616,17 +1620,29 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
                              DWORD* error) {
                              DWORD* error) {
   /* We can only write 8k characters at a time. Windows can't handle */
   /* We can only write 8k characters at a time. Windows can't handle */
   /* much more characters in a single console write anyway. */
   /* much more characters in a single console write anyway. */
-  WCHAR utf16_buf[8192];
+  WCHAR utf16_buf[MAX_CONSOLE_CHAR];
+  WCHAR* utf16_buffer;
   DWORD utf16_buf_used = 0;
   DWORD utf16_buf_used = 0;
-  unsigned int i;
-
-#define FLUSH_TEXT()                                                \
-  do {                                                              \
-    if (utf16_buf_used > 0) {                                       \
-      uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error);   \
-      utf16_buf_used = 0;                                           \
-    }                                                               \
-  } while (0)
+  unsigned int i, len, max_len, pos;
+  int allocate = 0;
+
+#define FLUSH_TEXT()                                                 \
+  do {                                                               \
+    pos = 0;                                                         \
+    do {                                                             \
+      len = utf16_buf_used - pos;                                    \
+      if (len > MAX_CONSOLE_CHAR)                                    \
+        len = MAX_CONSOLE_CHAR;                                      \
+      uv_tty_emit_text(handle, &utf16_buffer[pos], len, error);      \
+      pos += len;                                                    \
+    } while (pos < utf16_buf_used);                                  \
+    if (allocate) {                                                  \
+      uv__free(utf16_buffer);                                        \
+      allocate = 0;                                                  \
+      utf16_buffer = utf16_buf;                                      \
+    }                                                                \
+    utf16_buf_used = 0;                                              \
+ } while (0)
 
 
 #define ENSURE_BUFFER_SPACE(wchars_needed)                          \
 #define ENSURE_BUFFER_SPACE(wchars_needed)                          \
   if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) {     \
   if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) {     \
@@ -1644,38 +1660,47 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
   /* state. */
   /* state. */
   *error = ERROR_SUCCESS;
   *error = ERROR_SUCCESS;
 
 
+  utf16_buffer = utf16_buf;
+
   uv_sem_wait(&uv_tty_output_lock);
   uv_sem_wait(&uv_tty_output_lock);
 
 
   for (i = 0; i < nbufs; i++) {
   for (i = 0; i < nbufs; i++) {
     uv_buf_t buf = bufs[i];
     uv_buf_t buf = bufs[i];
     unsigned int j;
     unsigned int j;
 
 
-  if (uv__vterm_state == UV_SUPPORTED) {
-    utf16_buf_used = MultiByteToWideChar(CP_UTF8,
-                                         0,
-                                         buf.base,
-                                         buf.len,
-                                         NULL,
-                                         0);
+    if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) {
+      utf16_buf_used = MultiByteToWideChar(CP_UTF8,
+                                           0,
+                                           buf.base,
+                                           buf.len,
+                                           NULL,
+                                           0);
+
+      if (utf16_buf_used == 0) {
+        *error = GetLastError();
+        break;
+      }
 
 
-    if (utf16_buf_used == 0) {
-      *error = GetLastError();
-      break;
-    }
+      max_len = (utf16_buf_used + 1) * sizeof(WCHAR);
+      allocate = max_len > MAX_CONSOLE_CHAR;
+      if (allocate)
+        utf16_buffer = uv__malloc(max_len);
+      if (!MultiByteToWideChar(CP_UTF8,
+                               0,
+                               buf.base,
+                               buf.len,
+                               utf16_buffer,
+                               utf16_buf_used)) {
+        if (allocate)
+          uv__free(utf16_buffer);
+        *error = GetLastError();
+        break;
+      }
 
 
-    if (!MultiByteToWideChar(CP_UTF8,
-                             0,
-                             buf.base,
-                             buf.len,
-                             utf16_buf,
-                             utf16_buf_used)) {
-      *error = GetLastError();
-      break;
-    }
+      FLUSH_TEXT();
 
 
-    FLUSH_TEXT();
-    continue;
-  }
+      continue;
+    }
 
 
     for (j = 0; j < buf.len; j++) {
     for (j = 0; j < buf.len; j++) {
       unsigned char c = buf.base[j];
       unsigned char c = buf.base[j];

+ 6 - 2
src/win/winapi.h

@@ -4145,7 +4145,7 @@ typedef const UNICODE_STRING *PCUNICODE_STRING;
       struct {
       struct {
         UCHAR  DataBuffer[1];
         UCHAR  DataBuffer[1];
       } GenericReparseBuffer;
       } GenericReparseBuffer;
-    } DUMMYUNIONNAME;
+    };
   } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
   } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
 #endif
 #endif
 
 
@@ -4153,7 +4153,7 @@ typedef struct _IO_STATUS_BLOCK {
   union {
   union {
     NTSTATUS Status;
     NTSTATUS Status;
     PVOID Pointer;
     PVOID Pointer;
-  } DUMMYUNIONNAME;
+  };
   ULONG_PTR Information;
   ULONG_PTR Information;
 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
 
 
@@ -4606,6 +4606,10 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
 #endif
 #endif
 
 
 /* from winerror.h */
 /* from winerror.h */
+#ifndef ERROR_ELEVATION_REQUIRED
+# define ERROR_ELEVATION_REQUIRED 740
+#endif
+
 #ifndef ERROR_SYMLINK_NOT_SUPPORTED
 #ifndef ERROR_SYMLINK_NOT_SUPPORTED
 # define ERROR_SYMLINK_NOT_SUPPORTED 1464
 # define ERROR_SYMLINK_NOT_SUPPORTED 1464
 #endif
 #endif