From 12a78bc824655524d817508d6107ef4dcf8e3626 Mon Sep 17 00:00:00 2001
From: libuv upstream <libuv@googlegroups.com>
Date: Tue, 9 May 2017 15:51:26 -0400
Subject: libuv 2017-05-09 (e11dcd43)

Code extracted from:

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

at commit e11dcd4377185359874e67f4962995fdb7e83d19 (v1.x).
---
 include/uv-unix.h         |  15 +----
 include/uv.h              |   8 +++
 src/threadpool.c          |  35 ++++++----
 src/unix/aix.c            |   7 ++
 src/unix/async.c          | 121 ++++++++++++++--------------------
 src/unix/bsd-ifaddrs.c    | 133 ++++++++++++++++++++++++++++++++++++++
 src/unix/core.c           |  45 +++++++++++++
 src/unix/darwin.c         | 104 ------------------------------
 src/unix/freebsd.c        | 114 --------------------------------
 src/unix/internal.h       |  22 +++----
 src/unix/kqueue.c         |  36 ++++++++++-
 src/unix/linux-core.c     |  53 +++++++++------
 src/unix/linux-inotify.c  |  67 +++++++++++++++++++
 src/unix/loop.c           |  38 ++++++++++-
 src/unix/netbsd.c         | 108 -------------------------------
 src/unix/openbsd.c        | 111 --------------------------------
 src/unix/os390-syscalls.c |   2 +-
 src/unix/os390.c          |   6 ++
 src/unix/pipe.c           |   8 +--
 src/unix/posix-hrtime.c   |  35 ++++++++++
 src/unix/signal.c         | 100 ++++++++++++++++++++++++++--
 src/unix/stream.c         |   9 ++-
 src/unix/sunos.c          |  38 ++++++++---
 src/unix/udp.c            |  33 ++++++----
 src/uv-common.h           |  35 ++++++++--
 src/win/async.c           |   3 +-
 src/win/atomicops-inl.h   |   3 +-
 src/win/core.c            |  21 ++++--
 src/win/detect-wakeup.c   |   6 +-
 src/win/fs-event.c        |  33 +++++++---
 src/win/fs.c              |  10 ++-
 src/win/getaddrinfo.c     |   4 +-
 src/win/getnameinfo.c     |   3 +-
 src/win/internal.h        |  23 +++----
 src/win/pipe.c            |  17 ++---
 src/win/poll.c            |  10 ++-
 src/win/process.c         |   3 +-
 src/win/req-inl.h         |   9 +--
 src/win/signal.c          |  45 ++++++++++---
 src/win/stream-inl.h      |   3 +-
 src/win/stream.c          |   3 +-
 src/win/tcp.c             |  13 ++--
 src/win/tty.c             |   5 +-
 src/win/udp.c             |   6 +-
 src/win/util.c            | 161 ++++++++++++++++++++++++++++++++++++++++++++--
 src/win/winapi.c          |   2 +-
 src/win/winsock.c         |   2 +-
 47 files changed, 957 insertions(+), 711 deletions(-)
 create mode 100644 src/unix/bsd-ifaddrs.c
 create mode 100644 src/unix/posix-hrtime.c

diff --git a/include/uv-unix.h b/include/uv-unix.h
index 3030f71..5440729 100644
--- a/include/uv-unix.h
+++ b/include/uv-unix.h
@@ -79,7 +79,6 @@
 #endif
 
 struct uv__io_s;
-struct uv__async;
 struct uv_loop_s;
 
 typedef void (*uv__io_cb)(struct uv_loop_s* loop,
@@ -97,16 +96,6 @@ struct uv__io_s {
   UV_IO_PRIVATE_PLATFORM_FIELDS
 };
 
-typedef void (*uv__async_cb)(struct uv_loop_s* loop,
-                             struct uv__async* w,
-                             unsigned int nevents);
-
-struct uv__async {
-  uv__async_cb cb;
-  uv__io_t io_watcher;
-  int wfd;
-};
-
 #ifndef UV_PLATFORM_SEM_T
 # define UV_PLATFORM_SEM_T sem_t
 #endif
@@ -216,7 +205,9 @@ typedef struct {
   void* check_handles[2];                                                     \
   void* idle_handles[2];                                                      \
   void* async_handles[2];                                                     \
-  struct uv__async async_watcher;                                             \
+  void (*async_unused)(void);  /* TODO(bnoordhuis) Remove in libuv v2. */     \
+  uv__io_t async_io_watcher;                                                  \
+  int async_wfd;                                                              \
   struct {                                                                    \
     void* min;                                                                \
     unsigned int nelts;                                                       \
diff --git a/include/uv.h b/include/uv.h
index 31f09f0..14e09e4 100644
--- a/include/uv.h
+++ b/include/uv.h
@@ -274,6 +274,7 @@ UV_EXTERN void uv_loop_delete(uv_loop_t*);
 UV_EXTERN size_t uv_loop_size(void);
 UV_EXTERN int uv_loop_alive(const uv_loop_t* loop);
 UV_EXTERN int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...);
+UV_EXTERN int uv_loop_fork(uv_loop_t* loop);
 
 UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode);
 UV_EXTERN void uv_stop(uv_loop_t*);
@@ -1073,6 +1074,10 @@ UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses,
 UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses,
                                            int count);
 
+UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size);
+UV_EXTERN int uv_os_setenv(const char* name, const char* value);
+UV_EXTERN int uv_os_unsetenv(const char* name);
+
 
 typedef enum {
   UV_FS_UNKNOWN = -1,
@@ -1324,6 +1329,9 @@ UV_EXTERN int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle);
 UV_EXTERN int uv_signal_start(uv_signal_t* handle,
                               uv_signal_cb signal_cb,
                               int signum);
+UV_EXTERN int uv_signal_start_oneshot(uv_signal_t* handle,
+                                      uv_signal_cb signal_cb,
+                                      int signum);
 UV_EXTERN int uv_signal_stop(uv_signal_t* handle);
 
 UV_EXTERN void uv_loadavg(double avg[3]);
diff --git a/src/threadpool.c b/src/threadpool.c
index 2c5152b..1089341 100644
--- a/src/threadpool.c
+++ b/src/threadpool.c
@@ -23,18 +23,6 @@
 
 #if !defined(_WIN32)
 # include "unix/internal.h"
-#else
-# include "win/req-inl.h"
-/* TODO(saghul): unify internal req functions */
-static void uv__req_init(uv_loop_t* loop,
-                         uv_req_t* req,
-                         uv_req_type type) {
-  uv_req_init(loop, req);
-  req->type = type;
-  uv__req_register(loop, req);
-}
-# define uv__req_init(loop, req, type) \
-    uv__req_init((loop), (uv_req_t*)(req), (type))
 #endif
 
 #include <stdlib.h>
@@ -139,7 +127,7 @@ UV_DESTRUCTOR(static void cleanup(void)) {
 #endif
 
 
-static void init_once(void) {
+static void init_threads(void) {
   unsigned int i;
   const char* val;
 
@@ -177,6 +165,27 @@ static void init_once(void) {
 }
 
 
+#ifndef _WIN32
+static void reset_once(void) {
+  uv_once_t child_once = UV_ONCE_INIT;
+  memcpy(&once, &child_once, sizeof(child_once));
+}
+#endif
+
+
+static void init_once(void) {
+#ifndef _WIN32
+  /* Re-initialize the threadpool after fork.
+   * Note that this discards the global mutex and condition as well
+   * as the work queue.
+   */
+  if (pthread_atfork(NULL, NULL, &reset_once))
+    abort();
+#endif
+  init_threads();
+}
+
+
 void uv__work_submit(uv_loop_t* loop,
                      struct uv__work* w,
                      void (*work)(struct uv__work* w),
diff --git a/src/unix/aix.c b/src/unix/aix.c
index 1d2cd4a..388c9cc 100644
--- a/src/unix/aix.c
+++ b/src/unix/aix.c
@@ -96,6 +96,13 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
 }
 
 
+int uv__io_fork(uv_loop_t* loop) {
+  uv__platform_loop_delete(loop);
+
+  return uv__platform_loop_init(loop);
+}
+
+
 int uv__io_check_fd(uv_loop_t* loop, int fd) {
   struct poll_ctl pc;
 
diff --git a/src/unix/async.c b/src/unix/async.c
index 393cdeb..45c088e 100644
--- a/src/unix/async.c
+++ b/src/unix/async.c
@@ -33,16 +33,15 @@
 #include <string.h>
 #include <unistd.h>
 
-static void uv__async_event(uv_loop_t* loop,
-                            struct uv__async* w,
-                            unsigned int nevents);
+static void uv__async_send(uv_loop_t* loop);
+static int uv__async_start(uv_loop_t* loop);
 static int uv__async_eventfd(void);
 
 
 int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
   int err;
 
-  err = uv__async_start(loop, &loop->async_watcher, uv__async_event);
+  err = uv__async_start(loop);
   if (err)
     return err;
 
@@ -63,7 +62,7 @@ int uv_async_send(uv_async_t* handle) {
     return 0;
 
   if (cmpxchgi(&handle->pending, 0, 1) == 0)
-    uv__async_send(&handle->loop->async_watcher);
+    uv__async_send(handle->loop);
 
   return 0;
 }
@@ -75,44 +74,18 @@ void uv__async_close(uv_async_t* handle) {
 }
 
 
-static void uv__async_event(uv_loop_t* loop,
-                            struct uv__async* w,
-                            unsigned int nevents) {
+static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+  char buf[1024];
+  ssize_t r;
   QUEUE queue;
   QUEUE* q;
   uv_async_t* h;
 
-  QUEUE_MOVE(&loop->async_handles, &queue);
-  while (!QUEUE_EMPTY(&queue)) {
-    q = QUEUE_HEAD(&queue);
-    h = QUEUE_DATA(q, uv_async_t, queue);
-
-    QUEUE_REMOVE(q);
-    QUEUE_INSERT_TAIL(&loop->async_handles, q);
-
-    if (cmpxchgi(&h->pending, 1, 0) == 0)
-      continue;
-
-    if (h->async_cb == NULL)
-      continue;
-    h->async_cb(h);
-  }
-}
-
+  assert(w == &loop->async_io_watcher);
 
-static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
-  struct uv__async* wa;
-  char buf[1024];
-  unsigned n;
-  ssize_t r;
-
-  n = 0;
   for (;;) {
     r = read(w->fd, buf, sizeof(buf));
 
-    if (r > 0)
-      n += r;
-
     if (r == sizeof(buf))
       continue;
 
@@ -128,23 +101,26 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
     abort();
   }
 
-  wa = container_of(w, struct uv__async, io_watcher);
+  QUEUE_MOVE(&loop->async_handles, &queue);
+  while (!QUEUE_EMPTY(&queue)) {
+    q = QUEUE_HEAD(&queue);
+    h = QUEUE_DATA(q, uv_async_t, queue);
+
+    QUEUE_REMOVE(q);
+    QUEUE_INSERT_TAIL(&loop->async_handles, q);
 
-#if defined(__linux__)
-  if (wa->wfd == -1) {
-    uint64_t val;
-    assert(n == sizeof(val));
-    memcpy(&val, buf, sizeof(val));  /* Avoid alignment issues. */
-    wa->cb(loop, wa, val);
-    return;
-  }
-#endif
+    if (cmpxchgi(&h->pending, 1, 0) == 0)
+      continue;
+
+    if (h->async_cb == NULL)
+      continue;
 
-  wa->cb(loop, wa, n);
+    h->async_cb(h);
+  }
 }
 
 
-void uv__async_send(struct uv__async* wa) {
+static void uv__async_send(uv_loop_t* loop) {
   const void* buf;
   ssize_t len;
   int fd;
@@ -152,14 +128,14 @@ void uv__async_send(struct uv__async* wa) {
 
   buf = "";
   len = 1;
-  fd = wa->wfd;
+  fd = loop->async_wfd;
 
 #if defined(__linux__)
   if (fd == -1) {
     static const uint64_t val = 1;
     buf = &val;
     len = sizeof(val);
-    fd = wa->io_watcher.fd;  /* eventfd */
+    fd = loop->async_io_watcher.fd;  /* eventfd */
   }
 #endif
 
@@ -178,17 +154,11 @@ void uv__async_send(struct uv__async* wa) {
 }
 
 
-void uv__async_init(struct uv__async* wa) {
-  wa->io_watcher.fd = -1;
-  wa->wfd = -1;
-}
-
-
-int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) {
+static int uv__async_start(uv_loop_t* loop) {
   int pipefd[2];
   int err;
 
-  if (wa->io_watcher.fd != -1)
+  if (loop->async_io_watcher.fd != -1)
     return 0;
 
   err = uv__async_eventfd();
@@ -222,32 +192,41 @@ int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) {
   if (err < 0)
     return err;
 
-  uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]);
-  uv__io_start(loop, &wa->io_watcher, POLLIN);
-  wa->wfd = pipefd[1];
-  wa->cb = cb;
+  uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]);
+  uv__io_start(loop, &loop->async_io_watcher, POLLIN);
+  loop->async_wfd = pipefd[1];
 
   return 0;
 }
 
 
-void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) {
-  if (wa->io_watcher.fd == -1)
+int uv__async_fork(uv_loop_t* loop) {
+  if (loop->async_io_watcher.fd == -1) /* never started */
+    return 0;
+
+  uv__async_stop(loop);
+
+  return uv__async_start(loop);
+}
+
+
+void uv__async_stop(uv_loop_t* loop) {
+  if (loop->async_io_watcher.fd == -1)
     return;
 
-  if (wa->wfd != -1) {
-    if (wa->wfd != wa->io_watcher.fd)
-      uv__close(wa->wfd);
-    wa->wfd = -1;
+  if (loop->async_wfd != -1) {
+    if (loop->async_wfd != loop->async_io_watcher.fd)
+      uv__close(loop->async_wfd);
+    loop->async_wfd = -1;
   }
 
-  uv__io_stop(loop, &wa->io_watcher, POLLIN);
-  uv__close(wa->io_watcher.fd);
-  wa->io_watcher.fd = -1;
+  uv__io_stop(loop, &loop->async_io_watcher, POLLIN);
+  uv__close(loop->async_io_watcher.fd);
+  loop->async_io_watcher.fd = -1;
 }
 
 
-static int uv__async_eventfd() {
+static int uv__async_eventfd(void) {
 #if defined(__linux__)
   static int no_eventfd2;
   static int no_eventfd;
diff --git a/src/unix/bsd-ifaddrs.c b/src/unix/bsd-ifaddrs.c
new file mode 100644
index 0000000..0b5653d
--- /dev/null
+++ b/src/unix/bsd-ifaddrs.c
@@ -0,0 +1,133 @@
+/* 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 <errno.h>
+#include <stddef.h>
+
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+
+static int uv__ifaddr_exclude(struct ifaddrs *ent) {
+  if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+    return 1;
+  if (ent->ifa_addr == NULL)
+    return 1;
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
+  /*
+   * On BSD getifaddrs returns information related to the raw underlying
+   * devices.  We're not interested in this information.
+   */
+  if (ent->ifa_addr->sa_family == AF_LINK)
+    return 1;
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+  if (ent->ifa_addr->sa_family != PF_INET)
+    return 1;
+#endif
+  return 0;
+}
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+  struct ifaddrs* addrs;
+  struct ifaddrs* ent;
+  uv_interface_address_t* address;
+  int i;
+
+  if (getifaddrs(&addrs) != 0)
+    return -errno;
+
+  *count = 0;
+
+  /* Count the number of interfaces */
+  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+    if (uv__ifaddr_exclude(ent))
+      continue;
+    (*count)++;
+  }
+
+  *addresses = uv__malloc(*count * sizeof(**addresses));
+
+  if (*addresses == NULL) {
+    freeifaddrs(addrs);
+    return -ENOMEM;
+  }
+
+  address = *addresses;
+
+  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+    if (uv__ifaddr_exclude(ent))
+      continue;
+
+    address->name = uv__strdup(ent->ifa_name);
+
+    if (ent->ifa_addr->sa_family == AF_INET6) {
+      address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+    } else {
+      address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+    }
+
+    if (ent->ifa_netmask->sa_family == AF_INET6) {
+      address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+    } else {
+      address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+    }
+
+    address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+    address++;
+  }
+
+  /* Fill in physical addresses for each interface */
+  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+    if (uv__ifaddr_exclude(ent))
+      continue;
+
+    address = *addresses;
+
+    for (i = 0; i < *count; i++) {
+      if (strcmp(address->name, ent->ifa_name) == 0) {
+        struct sockaddr_dl* sa_addr;
+        sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+        memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+      }
+      address++;
+    }
+  }
+
+  freeifaddrs(addrs);
+
+  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);
+}
diff --git a/src/unix/core.c b/src/unix/core.c
index 9ef7134..96495b8 100644
--- a/src/unix/core.c
+++ b/src/unix/core.c
@@ -1240,3 +1240,48 @@ 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;
 }
+
+
+int uv_os_getenv(const char* name, char* buffer, size_t* size) {
+  char* var;
+  size_t len;
+
+  if (name == NULL || buffer == NULL || size == NULL || *size == 0)
+    return -EINVAL;
+
+  var = getenv(name);
+
+  if (var == NULL)
+    return -ENOENT;
+
+  len = strlen(var);
+
+  if (len >= *size) {
+    *size = len + 1;
+    return -ENOBUFS;
+  }
+
+  memcpy(buffer, var, len + 1);
+  *size = len;
+
+  return 0;
+}
+
+
+int uv_os_setenv(const char* name, const char* value) {
+  if (name == NULL || value == NULL)
+    return -EINVAL;
+
+  if (setenv(name, value, 1) != 0)
+    return -errno;
+
+  return 0;
+}
+
+
+int uv_os_unsetenv(const char* name) {
+  if (unsetenv(name) != 0)
+    return -errno;
+
+  return 0;
+}
diff --git a/src/unix/darwin.c b/src/unix/darwin.c
index cf95da2..df6dd1c 100644
--- a/src/unix/darwin.c
+++ b/src/unix/darwin.c
@@ -25,10 +25,6 @@
 #include <stdint.h>
 #include <errno.h>
 
-#include <ifaddrs.h>
-#include <net/if.h>
-#include <net/if_dl.h>
-
 #include <mach/mach.h>
 #include <mach/mach_time.h>
 #include <mach-o/dyld.h> /* _NSGetExecutablePath */
@@ -233,103 +229,3 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
 
   uv__free(cpu_infos);
 }
-
-
-int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
-  struct ifaddrs *addrs, *ent;
-  uv_interface_address_t* address;
-  int i;
-  struct sockaddr_dl *sa_addr;
-
-  if (getifaddrs(&addrs))
-    return -errno;
-
-  *count = 0;
-
-  /* Count the number of interfaces */
-  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
-        (ent->ifa_addr == NULL) ||
-        (ent->ifa_addr->sa_family == AF_LINK)) {
-      continue;
-    }
-
-    (*count)++;
-  }
-
-  *addresses = uv__malloc(*count * sizeof(**addresses));
-  if (!(*addresses)) {
-    freeifaddrs(addrs);
-    return -ENOMEM;
-  }
-
-  address = *addresses;
-
-  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
-      continue;
-
-    if (ent->ifa_addr == NULL)
-      continue;
-
-    /*
-     * On Mac OS X getifaddrs returns information related to Mac Addresses for
-     * various devices, such as firewire, etc. These are not relevant here.
-     */
-    if (ent->ifa_addr->sa_family == AF_LINK)
-      continue;
-
-    address->name = uv__strdup(ent->ifa_name);
-
-    if (ent->ifa_addr->sa_family == AF_INET6) {
-      address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
-    } else {
-      address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
-    }
-
-    if (ent->ifa_netmask->sa_family == AF_INET6) {
-      address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
-    } else {
-      address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
-    }
-
-    address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
-
-    address++;
-  }
-
-  /* Fill in physical addresses for each interface */
-  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
-        (ent->ifa_addr == NULL) ||
-        (ent->ifa_addr->sa_family != AF_LINK)) {
-      continue;
-    }
-
-    address = *addresses;
-
-    for (i = 0; i < (*count); i++) {
-      if (strcmp(address->name, ent->ifa_name) == 0) {
-        sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
-        memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
-      }
-      address++;
-    }
-  }
-
-  freeifaddrs(addrs);
-
-  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);
-}
diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c
index cba44a3..e52ae99 100644
--- a/src/unix/freebsd.c
+++ b/src/unix/freebsd.c
@@ -25,10 +25,6 @@
 #include <string.h>
 #include <errno.h>
 
-#include <ifaddrs.h>
-#include <net/if.h>
-#include <net/if_dl.h>
-
 #include <kvm.h>
 #include <paths.h>
 #include <sys/user.h>
@@ -41,9 +37,6 @@
 #include <unistd.h> /* sysconf */
 #include <fcntl.h>
 
-#undef NANOSEC
-#define NANOSEC ((uint64_t) 1e9)
-
 #ifndef CPUSTATES
 # define CPUSTATES 5U
 #endif
@@ -67,13 +60,6 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
 }
 
 
-uint64_t uv__hrtime(uv_clocktype_t type) {
-  struct timespec ts;
-  clock_gettime(CLOCK_MONOTONIC, &ts);
-  return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
-}
-
-
 #ifdef __DragonFly__
 int uv_exepath(char* buffer, size_t* size) {
   char abspath[PATH_MAX * 2 + 1];
@@ -358,103 +344,3 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
 
   uv__free(cpu_infos);
 }
-
-
-int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
-  struct ifaddrs *addrs, *ent;
-  uv_interface_address_t* address;
-  int i;
-  struct sockaddr_dl *sa_addr;
-
-  if (getifaddrs(&addrs))
-    return -errno;
-
-   *count = 0;
-
-  /* Count the number of interfaces */
-  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
-        (ent->ifa_addr == NULL) ||
-        (ent->ifa_addr->sa_family == AF_LINK)) {
-      continue;
-    }
-
-    (*count)++;
-  }
-
-  *addresses = uv__malloc(*count * sizeof(**addresses));
-  if (!(*addresses)) {
-    freeifaddrs(addrs);
-    return -ENOMEM;
-  }
-
-  address = *addresses;
-
-  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
-      continue;
-
-    if (ent->ifa_addr == NULL)
-      continue;
-
-    /*
-     * On FreeBSD getifaddrs returns information related to the raw underlying
-     * devices. We're not interested in this information yet.
-     */
-    if (ent->ifa_addr->sa_family == AF_LINK)
-      continue;
-
-    address->name = uv__strdup(ent->ifa_name);
-
-    if (ent->ifa_addr->sa_family == AF_INET6) {
-      address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
-    } else {
-      address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
-    }
-
-    if (ent->ifa_netmask->sa_family == AF_INET6) {
-      address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
-    } else {
-      address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
-    }
-
-    address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
-
-    address++;
-  }
-
-  /* Fill in physical addresses for each interface */
-  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
-        (ent->ifa_addr == NULL) ||
-        (ent->ifa_addr->sa_family != AF_LINK)) {
-      continue;
-    }
-
-    address = *addresses;
-
-    for (i = 0; i < (*count); i++) {
-      if (strcmp(address->name, ent->ifa_name) == 0) {
-        sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
-        memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
-      }
-      address++;
-    }
-  }
-
-  freeifaddrs(addrs);
-
-  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);
-}
diff --git a/src/unix/internal.h b/src/unix/internal.h
index b48f8fa..2e3afa6 100644
--- a/src/unix/internal.h
+++ b/src/unix/internal.h
@@ -192,12 +192,12 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w);
 int uv__io_active(const uv__io_t* w, unsigned int events);
 int uv__io_check_fd(uv_loop_t* loop, int fd);
 void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
+int uv__io_fork(uv_loop_t* loop);
 
 /* async */
-void uv__async_send(struct uv__async* wa);
-void uv__async_init(struct uv__async* wa);
-int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb);
-void uv__async_stop(uv_loop_t* loop, struct uv__async* wa);
+void uv__async_stop(uv_loop_t* loop);
+int uv__async_fork(uv_loop_t* loop);
+
 
 /* loop */
 void uv__run_idle(uv_loop_t* loop);
@@ -233,6 +233,7 @@ int uv__next_timeout(const uv_loop_t* loop);
 void uv__signal_close(uv_signal_t* handle);
 void uv__signal_global_once_init(void);
 void uv__signal_loop_cleanup(uv_loop_t* loop);
+int uv__signal_loop_fork(uv_loop_t* loop);
 
 /* platform specific */
 uint64_t uv__hrtime(uv_clocktype_t type);
@@ -302,15 +303,6 @@ static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000;
 
 #endif /* defined(__APPLE__) */
 
-UV_UNUSED(static void uv__req_init(uv_loop_t* loop,
-                                   uv_req_t* req,
-                                   uv_req_type type)) {
-  req->type = type;
-  uv__req_register(loop, req);
-}
-#define uv__req_init(loop, req, type) \
-  uv__req_init((loop), (uv_req_t*)(req), (type))
-
 UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
   /* Use a fast time source if available.  We only need millisecond precision.
    */
@@ -327,4 +319,8 @@ UV_UNUSED(static char* uv__basename_r(const char* path)) {
   return s + 1;
 }
 
+#if defined(__linux__)
+int uv__inotify_fork(uv_loop_t* loop, void* old_watchers);
+#endif
+
 #endif /* UV_UNIX_INTERNAL_H_ */
diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c
index fffd462..6bc60bb 100644
--- a/src/unix/kqueue.c
+++ b/src/unix/kqueue.c
@@ -48,6 +48,37 @@ int uv__kqueue_init(uv_loop_t* loop) {
 }
 
 
+static int uv__has_forked_with_cfrunloop;
+
+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)
+    return err;
+
+#if defined(__APPLE__)
+  if (loop->cf_state != NULL) {
+    /* We cannot start another CFRunloop and/or thread in the child
+       process; CF aborts if you try or if you try to touch the thread
+       at all to kill it. So the best we can do is ignore it from now
+       on. This means we can't watch directories in the same way
+       anymore (like other BSDs). It also means we cannot properly
+       clean up the allocated resources; calling
+       uv__fsevents_loop_delete from uv_loop_close will crash the
+       process. So we sidestep the issue by pretending like we never
+       started it in the first place.
+    */
+    uv__has_forked_with_cfrunloop = 1;
+    uv__free(loop->cf_state);
+    loop->cf_state = NULL;
+  }
+#endif
+  return err;
+}
+
+
 int uv__io_check_fd(uv_loop_t* loop, int fd) {
   struct kevent ev;
   int rc;
@@ -404,6 +435,9 @@ int uv_fs_event_start(uv_fs_event_t* handle,
   handle->cb = cb;
 
 #if defined(__APPLE__)
+  if (uv__has_forked_with_cfrunloop)
+    goto fallback;
+
   /* Nullify field to perform checks later */
   handle->cf_cb = NULL;
   handle->realpath = NULL;
@@ -438,7 +472,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
   uv__handle_stop(handle);
 
 #if defined(__APPLE__)
-  if (uv__fsevents_close(handle))
+  if (uv__has_forked_with_cfrunloop || uv__fsevents_close(handle))
 #endif /* defined(__APPLE__) */
   {
     uv__io_close(handle->loop, &handle->event_watcher);
diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c
index 58dd813..646be4f 100644
--- a/src/unix/linux-core.c
+++ b/src/unix/linux-core.c
@@ -107,6 +107,24 @@ int uv__platform_loop_init(uv_loop_t* loop) {
 }
 
 
+int uv__io_fork(uv_loop_t* loop) {
+  int err;
+  void* old_watchers;
+
+  old_watchers = loop->inotify_watchers;
+
+  uv__close(loop->backend_fd);
+  loop->backend_fd = -1;
+  uv__platform_loop_delete(loop);
+
+  err = uv__platform_loop_init(loop);
+  if (err)
+    return err;
+
+  return uv__inotify_fork(loop, old_watchers);
+}
+
+
 void uv__platform_loop_delete(uv_loop_t* loop) {
   if (loop->inotify_fd == -1) return;
   uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN);
@@ -868,6 +886,19 @@ 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) {
+  if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+    return 1;
+  if (ent->ifa_addr == NULL)
+    return 1;
+  /*
+   * On Linux getifaddrs returns information related to the raw underlying
+   * devices. We're not interested in this information yet.
+   */
+  if (ent->ifa_addr->sa_family == PF_PACKET)
+    return 1;
+  return 0;
+}
 
 int uv_interface_addresses(uv_interface_address_t** addresses,
   int* count) {
@@ -887,11 +918,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
 
   /* Count the number of interfaces */
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
-        (ent->ifa_addr == NULL) ||
-        (ent->ifa_addr->sa_family == PF_PACKET)) {
+    if (uv__ifaddr_exclude(ent))
       continue;
-    }
 
     (*count)++;
   }
@@ -908,17 +936,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
   address = *addresses;
 
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
-      continue;
-
-    if (ent->ifa_addr == NULL)
-      continue;
-
-    /*
-     * On Linux getifaddrs returns information related to the raw underlying
-     * devices. We're not interested in this information yet.
-     */
-    if (ent->ifa_addr->sa_family == PF_PACKET)
+    if (uv__ifaddr_exclude(ent))
       continue;
 
     address->name = uv__strdup(ent->ifa_name);
@@ -942,11 +960,8 @@ 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 (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
-        (ent->ifa_addr == NULL) ||
-        (ent->ifa_addr->sa_family != PF_PACKET)) {
+    if (uv__ifaddr_exclude(ent))
       continue;
-    }
 
     address = *addresses;
 
diff --git a/src/unix/linux-inotify.c b/src/unix/linux-inotify.c
index 4708c05..5934c5d 100644
--- a/src/unix/linux-inotify.c
+++ b/src/unix/linux-inotify.c
@@ -61,6 +61,8 @@ static void uv__inotify_read(uv_loop_t* loop,
                              uv__io_t* w,
                              unsigned int revents);
 
+static void maybe_free_watcher_list(struct watcher_list* w,
+                                    uv_loop_t* loop);
 
 static int new_inotify_fd(void) {
   int err;
@@ -108,6 +110,71 @@ static int init_inotify(uv_loop_t* loop) {
 }
 
 
+int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) {
+  /* Open the inotify_fd, and re-arm all the inotify watchers. */
+  int err;
+  struct watcher_list* tmp_watcher_list_iter;
+  struct watcher_list* watcher_list;
+  struct watcher_list tmp_watcher_list;
+  QUEUE queue;
+  QUEUE* q;
+  uv_fs_event_t* handle;
+  char* tmp_path;
+
+  if (old_watchers != NULL) {
+    /* We must restore the old watcher list to be able to close items
+     * out of it.
+     */
+    loop->inotify_watchers = old_watchers;
+
+    QUEUE_INIT(&tmp_watcher_list.watchers);
+    /* Note that the queue we use is shared with the start and stop()
+     * functions, making QUEUE_FOREACH unsafe to use. So we use the
+     * QUEUE_MOVE trick to safely iterate. Also don't free the watcher
+     * list until we're done iterating. c.f. uv__inotify_read.
+     */
+    RB_FOREACH_SAFE(watcher_list, watcher_root,
+                    CAST(&old_watchers), tmp_watcher_list_iter) {
+      watcher_list->iterating = 1;
+      QUEUE_MOVE(&watcher_list->watchers, &queue);
+      while (!QUEUE_EMPTY(&queue)) {
+        q = QUEUE_HEAD(&queue);
+        handle = QUEUE_DATA(q, uv_fs_event_t, watchers);
+        /* It's critical to keep a copy of path here, because it
+         * will be set to NULL by stop() and then deallocated by
+         * maybe_free_watcher_list
+         */
+        tmp_path = uv__strdup(handle->path);
+        assert(tmp_path != NULL);
+        QUEUE_REMOVE(q);
+        QUEUE_INSERT_TAIL(&watcher_list->watchers, q);
+        uv_fs_event_stop(handle);
+
+        QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers);
+        handle->path = tmp_path;
+      }
+      watcher_list->iterating = 0;
+      maybe_free_watcher_list(watcher_list, loop);
+    }
+
+    QUEUE_MOVE(&tmp_watcher_list.watchers, &queue);
+    while (!QUEUE_EMPTY(&queue)) {
+        q = QUEUE_HEAD(&queue);
+        QUEUE_REMOVE(q);
+        handle = QUEUE_DATA(q, uv_fs_event_t, watchers);
+        tmp_path = handle->path;
+        handle->path = NULL;
+        err = uv_fs_event_start(handle, handle->cb, tmp_path, 0);
+        uv__free(tmp_path);
+        if (err)
+          return err;
+    }
+  }
+
+  return 0;
+}
+
+
 static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) {
   struct watcher_list w;
   w.wd = wd;
diff --git a/src/unix/loop.c b/src/unix/loop.c
index bd63c2f..bcd4924 100644
--- a/src/unix/loop.c
+++ b/src/unix/loop.c
@@ -54,7 +54,8 @@ int uv_loop_init(uv_loop_t* loop) {
 
   loop->closing_handles = NULL;
   uv__update_time(loop);
-  uv__async_init(&loop->async_watcher);
+  loop->async_io_watcher.fd = -1;
+  loop->async_wfd = -1;
   loop->signal_pipefd[0] = -1;
   loop->signal_pipefd[1] = -1;
   loop->backend_fd = -1;
@@ -108,10 +109,43 @@ fail_signal_init:
 }
 
 
+int uv_loop_fork(uv_loop_t* loop) {
+  int err;
+  unsigned int i;
+  uv__io_t* w;
+
+  err = uv__io_fork(loop);
+  if (err)
+    return err;
+
+  err = uv__async_fork(loop);
+  if (err)
+    return err;
+
+  err = uv__signal_loop_fork(loop);
+  if (err)
+    return err;
+
+  /* Rearm all the watchers that aren't re-queued by the above. */
+  for (i = 0; i < loop->nwatchers; i++) {
+    w = loop->watchers[i];
+    if (w == NULL)
+      continue;
+
+    if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) {
+      w->events = 0; /* Force re-registration in uv__io_poll. */
+      QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
+    }
+  }
+
+  return 0;
+}
+
+
 void uv__loop_close(uv_loop_t* loop) {
   uv__signal_loop_cleanup(loop);
   uv__platform_loop_delete(loop);
-  uv__async_stop(loop, &loop->async_watcher);
+  uv__async_stop(loop);
 
   if (loop->emfile_fd != -1) {
     uv__close(loop->emfile_fd);
diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c
index 4a9e6cb..9b5546b 100644
--- a/src/unix/netbsd.c
+++ b/src/unix/netbsd.c
@@ -27,14 +27,11 @@
 
 #include <kvm.h>
 #include <paths.h>
-#include <ifaddrs.h>
 #include <unistd.h>
 #include <time.h>
 #include <stdlib.h>
 #include <fcntl.h>
 
-#include <net/if.h>
-#include <net/if_dl.h>
 #include <sys/resource.h>
 #include <sys/types.h>
 #include <sys/sysctl.h>
@@ -43,9 +40,6 @@
 #include <unistd.h>
 #include <time.h>
 
-#undef NANOSEC
-#define NANOSEC ((uint64_t) 1e9)
-
 static char *process_title;
 
 
@@ -58,13 +52,6 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
 }
 
 
-uint64_t uv__hrtime(uv_clocktype_t type) {
-  struct timespec ts;
-  clock_gettime(CLOCK_MONOTONIC, &ts);
-  return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
-}
-
-
 void uv_loadavg(double avg[3]) {
   struct loadavg info;
   size_t size = sizeof(info);
@@ -283,98 +270,3 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
 
   uv__free(cpu_infos);
 }
-
-
-int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
-  struct ifaddrs *addrs, *ent;
-  uv_interface_address_t* address;
-  int i;
-  struct sockaddr_dl *sa_addr;
-
-  if (getifaddrs(&addrs))
-    return -errno;
-
-  *count = 0;
-
-  /* Count the number of interfaces */
-  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
-        (ent->ifa_addr == NULL) ||
-        (ent->ifa_addr->sa_family != PF_INET)) {
-      continue;
-    }
-    (*count)++;
-  }
-
-  *addresses = uv__malloc(*count * sizeof(**addresses));
-
-  if (!(*addresses)) {
-    freeifaddrs(addrs);
-    return -ENOMEM;
-  }
-
-  address = *addresses;
-
-  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
-      continue;
-
-    if (ent->ifa_addr == NULL)
-      continue;
-
-    if (ent->ifa_addr->sa_family != PF_INET)
-      continue;
-
-    address->name = uv__strdup(ent->ifa_name);
-
-    if (ent->ifa_addr->sa_family == AF_INET6) {
-      address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
-    } else {
-      address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
-    }
-
-    if (ent->ifa_netmask->sa_family == AF_INET6) {
-      address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
-    } else {
-      address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
-    }
-
-    address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
-
-    address++;
-  }
-
-  /* Fill in physical addresses for each interface */
-  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
-        (ent->ifa_addr == NULL) ||
-        (ent->ifa_addr->sa_family != AF_LINK)) {
-      continue;
-    }
-
-    address = *addresses;
-
-    for (i = 0; i < (*count); i++) {
-      if (strcmp(address->name, ent->ifa_name) == 0) {
-        sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
-        memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
-      }
-      address++;
-    }
-  }
-
-  freeifaddrs(addrs);
-
-  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);
-}
diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c
index ac28b69..7e4b253 100644
--- a/src/unix/openbsd.c
+++ b/src/unix/openbsd.c
@@ -28,10 +28,6 @@
 #include <sys/time.h>
 #include <sys/sysctl.h>
 
-#include <ifaddrs.h>
-#include <net/if.h>
-#include <net/if_dl.h>
-
 #include <errno.h>
 #include <fcntl.h>
 #include <kvm.h>
@@ -40,9 +36,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#undef NANOSEC
-#define NANOSEC ((uint64_t) 1e9)
-
 
 static char *process_title;
 
@@ -56,13 +49,6 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
 }
 
 
-uint64_t uv__hrtime(uv_clocktype_t type) {
-  struct timespec ts;
-  clock_gettime(CLOCK_MONOTONIC, &ts);
-  return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
-}
-
-
 void uv_loadavg(double avg[3]) {
   struct loadavg info;
   size_t size = sizeof(info);
@@ -297,100 +283,3 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
 
   uv__free(cpu_infos);
 }
-
-
-int uv_interface_addresses(uv_interface_address_t** addresses,
-  int* count) {
-  struct ifaddrs *addrs, *ent;
-  uv_interface_address_t* address;
-  int i;
-  struct sockaddr_dl *sa_addr;
-
-  if (getifaddrs(&addrs) != 0)
-    return -errno;
-
-   *count = 0;
-
-  /* Count the number of interfaces */
-  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
-        (ent->ifa_addr == NULL) ||
-        (ent->ifa_addr->sa_family != PF_INET)) {
-      continue;
-    }
-    (*count)++;
-  }
-
-  *addresses = uv__malloc(*count * sizeof(**addresses));
-
-  if (!(*addresses)) {
-    freeifaddrs(addrs);
-    return -ENOMEM;
-  }
-
-  address = *addresses;
-
-  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
-      continue;
-
-    if (ent->ifa_addr == NULL)
-      continue;
-
-    if (ent->ifa_addr->sa_family != PF_INET)
-      continue;
-
-    address->name = uv__strdup(ent->ifa_name);
-
-    if (ent->ifa_addr->sa_family == AF_INET6) {
-      address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
-    } else {
-      address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
-    }
-
-    if (ent->ifa_netmask->sa_family == AF_INET6) {
-      address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
-    } else {
-      address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
-    }
-
-    address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
-
-    address++;
-  }
-
-  /* Fill in physical addresses for each interface */
-  for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
-        (ent->ifa_addr == NULL) ||
-        (ent->ifa_addr->sa_family != AF_LINK)) {
-      continue;
-    }
-
-    address = *addresses;
-
-    for (i = 0; i < (*count); i++) {
-      if (strcmp(address->name, ent->ifa_name) == 0) {
-        sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
-        memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
-      }
-      address++;
-    }
-  }
-
-  freeifaddrs(addrs);
-
-  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);
-}
diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c
index 2bf3b73..7edf235 100644
--- a/src/unix/os390-syscalls.c
+++ b/src/unix/os390-syscalls.c
@@ -120,7 +120,7 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
 }
 
 
-static void epoll_init() {
+static void epoll_init(void) {
   QUEUE_INIT(&global_epoll_queue);
   if (uv_mutex_init(&global_epoll_lock))
     abort();
diff --git a/src/unix/os390.c b/src/unix/os390.c
index be325a9..e9ba90c 100644
--- a/src/unix/os390.c
+++ b/src/unix/os390.c
@@ -863,3 +863,9 @@ update_timeout:
 void uv__set_process_title(const char* title) {
   /* do nothing */
 }
+
+int uv__io_fork(uv_loop_t* loop) {
+  uv__platform_loop_delete(loop);
+
+  return uv__platform_loop_init(loop);
+}
diff --git a/src/unix/pipe.c b/src/unix/pipe.c
index b73994c..dd3d034 100644
--- a/src/unix/pipe.c
+++ b/src/unix/pipe.c
@@ -47,7 +47,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
   int err;
 
   pipe_fname = NULL;
-  sockfd = -1;
 
   /* Already bound? */
   if (uv__stream_fd(handle) >= 0)
@@ -76,7 +75,9 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
     /* Convert ENOENT to EACCES for compatibility with Windows. */
     if (err == -ENOENT)
       err = -EACCES;
-    goto err_bind;
+
+    uv__close(sockfd);
+    goto err_socket;
   }
 
   /* Success. */
@@ -85,9 +86,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
   handle->io_watcher.fd = sockfd;
   return 0;
 
-err_bind:
-  uv__close(sockfd);
-
 err_socket:
   uv__free((void*)pipe_fname);
   return err;
diff --git a/src/unix/posix-hrtime.c b/src/unix/posix-hrtime.c
new file mode 100644
index 0000000..323dfc2
--- /dev/null
+++ b/src/unix/posix-hrtime.c
@@ -0,0 +1,35 @@
+/* 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 <stdint.h>
+#include <time.h>
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+  struct timespec ts;
+  clock_gettime(CLOCK_MONOTONIC, &ts);
+  return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
+}
diff --git a/src/unix/signal.c b/src/unix/signal.c
index dbd8f86..cb09ead 100644
--- a/src/unix/signal.c
+++ b/src/unix/signal.c
@@ -38,9 +38,14 @@ RB_HEAD(uv__signal_tree_s, uv_signal_s);
 
 
 static int uv__signal_unlock(void);
+static int uv__signal_start(uv_signal_t* handle,
+                            uv_signal_cb signal_cb,
+                            int signum,
+                            int oneshot);
 static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events);
 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_unregister_handler(int signum);
 
 
 static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT;
@@ -53,8 +58,19 @@ RB_GENERATE_STATIC(uv__signal_tree_s,
                    uv_signal_s, tree_entry,
                    uv__signal_compare)
 
+static void uv__signal_global_reinit(void);
 
 static void uv__signal_global_init(void) {
+  if (!uv__signal_lock_pipefd[0])
+    /* pthread_atfork can register before and after handlers, one
+     * for each child. This only registers one for the child. That
+     * state is both persistent and cumulative, so if we keep doing
+     * it the handler functions will be called multiple times. Thus
+     * we only want to do it once.
+     */
+    if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit))
+      abort();
+
   if (uv__make_pipe(uv__signal_lock_pipefd, 0))
     abort();
 
@@ -63,6 +79,22 @@ static void uv__signal_global_init(void) {
 }
 
 
+static void uv__signal_global_reinit(void) {
+  /* We can only use signal-safe functions here.
+   * That includes read/write and close, fortunately.
+   * We do all of this directly here instead of resetting
+   * uv__signal_global_init_guard because
+   * uv__signal_global_once_init is only called from uv_loop_init
+   * and this needs to function in existing loops.
+   */
+  uv__close(uv__signal_lock_pipefd[0]);
+  uv__signal_lock_pipefd[0] = -1;
+  uv__close(uv__signal_lock_pipefd[1]);
+  uv__signal_lock_pipefd[1] = -1;
+  uv__signal_global_init();
+}
+
+
 void uv__signal_global_once_init(void) {
   uv_once(&uv__signal_global_init_guard, uv__signal_global_init);
 }
@@ -122,6 +154,7 @@ static uv_signal_t* uv__signal_first_handle(int signum) {
   uv_signal_t* handle;
 
   lookup.signum = signum;
+  lookup.flags = 0;
   lookup.loop = NULL;
 
   handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup);
@@ -174,7 +207,7 @@ static void uv__signal_handler(int signum) {
 }
 
 
-static int uv__signal_register_handler(int signum) {
+static int uv__signal_register_handler(int signum, int oneshot) {
   /* When this function is called, the signal lock must be held. */
   struct sigaction sa;
 
@@ -183,6 +216,7 @@ static int uv__signal_register_handler(int signum) {
   if (sigfillset(&sa.sa_mask))
     abort();
   sa.sa_handler = uv__signal_handler;
+  sa.sa_flags = oneshot ? SA_RESETHAND : 0;
 
   /* XXX save old action so we can restore it later on? */
   if (sigaction(signum, &sa, NULL))
@@ -228,6 +262,16 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) {
 }
 
 
+int uv__signal_loop_fork(uv_loop_t* loop) {
+  uv__io_stop(loop, &loop->signal_io_watcher, POLLIN);
+  uv__close(loop->signal_pipefd[0]);
+  uv__close(loop->signal_pipefd[1]);
+  loop->signal_pipefd[0] = -1;
+  loop->signal_pipefd[1] = -1;
+  return uv__signal_loop_once_init(loop);
+}
+
+
 void uv__signal_loop_cleanup(uv_loop_t* loop) {
   QUEUE* q;
 
@@ -287,8 +331,24 @@ void uv__signal_close(uv_signal_t* handle) {
 
 
 int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
+  return uv__signal_start(handle, signal_cb, signum, 0);
+}
+
+
+int uv_signal_start_oneshot(uv_signal_t* handle,
+                            uv_signal_cb signal_cb,
+                            int signum) {
+  return uv__signal_start(handle, signal_cb, signum, 1);
+}
+
+
+static int uv__signal_start(uv_signal_t* handle,
+                            uv_signal_cb signal_cb,
+                            int signum,
+                            int oneshot) {
   sigset_t saved_sigmask;
   int err;
+  uv_signal_t* first_handle;
 
   assert(!uv__is_closing(handle));
 
@@ -318,9 +378,12 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
 
   /* If at this point there are no active signal watchers for this signum (in
    * any of the loops), it's time to try and register a handler for it here.
+   * Also in case there's only one-shot handlers and a regular handler comes in.
    */
-  if (uv__signal_first_handle(signum) == NULL) {
-    err = uv__signal_register_handler(signum);
+  first_handle = uv__signal_first_handle(signum);
+  if (first_handle == NULL ||
+      (!oneshot && (first_handle->flags & UV__SIGNAL_ONE_SHOT))) {
+    err = uv__signal_register_handler(signum, oneshot);
     if (err) {
       /* Registering the signal handler failed. Must be an invalid signal. */
       uv__signal_unlock_and_unblock(&saved_sigmask);
@@ -329,6 +392,9 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
   }
 
   handle->signum = signum;
+  if (oneshot)
+    handle->flags |= UV__SIGNAL_ONE_SHOT;
+
   RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
 
   uv__signal_unlock_and_unblock(&saved_sigmask);
@@ -390,6 +456,9 @@ static void uv__signal_event(uv_loop_t* loop,
 
       handle->dispatched_signals++;
 
+      if (handle->flags & UV__SIGNAL_ONE_SHOT)
+        uv__signal_stop(handle);
+
       /* If uv_close was called while there were caught signals that were not
        * yet dispatched, the uv__finish_close was deferred. Make close pending
        * now if this has happened.
@@ -414,12 +483,22 @@ static void uv__signal_event(uv_loop_t* loop,
 
 
 static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
+  int f1;
+  int f2;
   /* Compare signums first so all watchers with the same signnum end up
    * adjacent.
    */
   if (w1->signum < w2->signum) return -1;
   if (w1->signum > w2->signum) return 1;
 
+  /* Handlers without UV__SIGNAL_ONE_SHOT set will come first, so if the first
+   * handler returned is a one-shot handler, the rest will be too.
+   */
+  f1 = w1->flags & UV__SIGNAL_ONE_SHOT;
+  f2 = w2->flags & UV__SIGNAL_ONE_SHOT;
+  if (f1 < f2) return -1;
+  if (f1 > f2) return 1;
+
   /* Sort by loop pointer, so we can easily look up the first item after
    * { .signum = x, .loop = NULL }.
    */
@@ -443,6 +522,10 @@ int uv_signal_stop(uv_signal_t* handle) {
 static void uv__signal_stop(uv_signal_t* handle) {
   uv_signal_t* removed_handle;
   sigset_t saved_sigmask;
+  uv_signal_t* first_handle;
+  int rem_oneshot;
+  int first_oneshot;
+  int ret;
 
   /* If the watcher wasn't started, this is a no-op. */
   if (handle->signum == 0)
@@ -457,8 +540,17 @@ static void uv__signal_stop(uv_signal_t* handle) {
   /* Check if there are other active signal watchers observing this signal. If
    * not, unregister the signal handler.
    */
-  if (uv__signal_first_handle(handle->signum) == NULL)
+  first_handle = uv__signal_first_handle(handle->signum);
+  if (first_handle == NULL) {
     uv__signal_unregister_handler(handle->signum);
+  } else {
+    rem_oneshot = handle->flags & UV__SIGNAL_ONE_SHOT;
+    first_oneshot = first_handle->flags & UV__SIGNAL_ONE_SHOT;
+    if (first_oneshot && !rem_oneshot) {
+      ret = uv__signal_register_handler(handle->signum, 1);
+      assert(ret == 0);
+    }
+  }
 
   uv__signal_unlock_and_unblock(&saved_sigmask);
 
diff --git a/src/unix/stream.c b/src/unix/stream.c
index 7059df1..dbd04f2 100644
--- a/src/unix/stream.c
+++ b/src/unix/stream.c
@@ -785,7 +785,12 @@ start:
     struct msghdr msg;
     struct cmsghdr *cmsg;
     int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
-    char scratch[64] = {0};
+    union {
+      char data[64];
+      struct cmsghdr alias;
+    } scratch;
+
+    memset(&scratch, 0, sizeof(scratch));
 
     assert(fd_to_send >= 0);
 
@@ -795,7 +800,7 @@ start:
     msg.msg_iovlen = iovcnt;
     msg.msg_flags = 0;
 
-    msg.msg_control = (void*) scratch;
+    msg.msg_control = &scratch.alias;
     msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send));
 
     cmsg = CMSG_FIRSTHDR(&msg);
diff --git a/src/unix/sunos.c b/src/unix/sunos.c
index a43f7f1..c34b870 100644
--- a/src/unix/sunos.c
+++ b/src/unix/sunos.c
@@ -99,6 +99,18 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
 }
 
 
+int uv__io_fork(uv_loop_t* loop) {
+#if defined(PORT_SOURCE_FILE)
+  if (loop->fs_fd != -1) {
+    /* stop the watcher before we blow away its fileno */
+    uv__io_stop(loop, &loop->fs_event_watcher, POLLIN);
+  }
+#endif
+  uv__platform_loop_delete(loop);
+  return uv__platform_loop_init(loop);
+}
+
+
 void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
   struct port_event* events;
   uintptr_t i;
@@ -469,8 +481,10 @@ int uv_fs_event_start(uv_fs_event_t* handle,
   memset(&handle->fo, 0, sizeof handle->fo);
   handle->fo.fo_name = handle->path;
   err = uv__fs_event_rearm(handle);
-  if (err != 0)
+  if (err != 0) {
+    uv_fs_event_stop(handle);
     return err;
+  }
 
   if (first_run) {
     uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd);
@@ -746,6 +760,17 @@ static int uv__set_phys_addr(uv_interface_address_t* address,
   return 0;
 }
 
+
+static int uv__ifaddr_exclude(struct ifaddrs *ent) {
+  if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+    return 1;
+  if (ent->ifa_addr == NULL)
+    return 1;
+  if (ent->ifa_addr->sa_family == PF_PACKET)
+    return 1;
+  return 0;
+}
+
 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   uv_interface_address_t* address;
   struct ifaddrs* addrs;
@@ -759,12 +784,8 @@ 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 (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
-        (ent->ifa_addr == NULL) ||
-        (ent->ifa_addr->sa_family == PF_PACKET)) {
+    if (uv__ifaddr_exclude(ent))
       continue;
-    }
-
     (*count)++;
   }
 
@@ -777,10 +798,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
   address = *addresses;
 
   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
-    if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
-      continue;
-
-    if (ent->ifa_addr == NULL)
+    if (uv__ifaddr_exclude(ent))
       continue;
 
     address->name = uv__strdup(ent->ifa_name);
diff --git a/src/unix/udp.c b/src/unix/udp.c
index 1cd4925..c556325 100644
--- a/src/unix/udp.c
+++ b/src/unix/udp.c
@@ -307,7 +307,7 @@ int uv__udp_bind(uv_udp_t* handle,
   if (flags & UV_UDP_REUSEADDR) {
     err = uv__set_reuse(fd);
     if (err)
-      goto out;
+      return err;
   }
 
   if (flags & UV_UDP_IPV6ONLY) {
@@ -315,11 +315,11 @@ int uv__udp_bind(uv_udp_t* handle,
     yes = 1;
     if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) {
       err = -errno;
-      goto out;
+      return err;
     }
 #else
     err = -ENOTSUP;
-    goto out;
+    return err;
 #endif
   }
 
@@ -329,27 +329,25 @@ int uv__udp_bind(uv_udp_t* handle,
       /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
        * socket created with AF_INET to an AF_INET6 address or vice versa. */
       err = -EINVAL;
-    goto out;
+    return err;
   }
 
   if (addr->sa_family == AF_INET6)
     handle->flags |= UV_HANDLE_IPV6;
 
   handle->flags |= UV_HANDLE_BOUND;
-
   return 0;
-
-out:
-  uv__close(handle->io_watcher.fd);
-  handle->io_watcher.fd = -1;
-  return err;
 }
 
 
 static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
                                        int domain,
                                        unsigned int flags) {
-  unsigned char taddr[sizeof(struct sockaddr_in6)];
+  union {
+    struct sockaddr_in6 in6;
+    struct sockaddr_in in;
+    struct sockaddr addr;
+  } taddr;
   socklen_t addrlen;
 
   if (handle->io_watcher.fd != -1)
@@ -358,7 +356,7 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
   switch (domain) {
   case AF_INET:
   {
-    struct sockaddr_in* addr = (void*)&taddr;
+    struct sockaddr_in* addr = &taddr.in;
     memset(addr, 0, sizeof *addr);
     addr->sin_family = AF_INET;
     addr->sin_addr.s_addr = INADDR_ANY;
@@ -367,7 +365,7 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
   }
   case AF_INET6:
   {
-    struct sockaddr_in6* addr = (void*)&taddr;
+    struct sockaddr_in6* addr = &taddr.in6;
     memset(addr, 0, sizeof *addr);
     addr->sin6_family = AF_INET6;
     addr->sin6_addr = in6addr_any;
@@ -379,7 +377,7 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
     abort();
   }
 
-  return uv__udp_bind(handle, (const struct sockaddr*) &taddr, addrlen, flags);
+  return uv__udp_bind(handle, &taddr.addr, addrlen, flags);
 }
 
 
@@ -429,6 +427,13 @@ int uv__udp_send(uv_udp_send_t* req,
 
   if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) {
     uv__udp_sendmsg(handle);
+
+    /* `uv__udp_sendmsg` may not be able to do non-blocking write straight
+     * away. In such cases the `io_watcher` has to be queued for asynchronous
+     * write.
+     */
+    if (!QUEUE_EMPTY(&handle->write_queue))
+      uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
   } else {
     uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
   }
diff --git a/src/uv-common.h b/src/uv-common.h
index 27902fd..781a855 100644
--- a/src/uv-common.h
+++ b/src/uv-common.h
@@ -55,16 +55,19 @@ extern int snprintf(char*, size_t, const char*, ...);
 
 #ifndef _WIN32
 enum {
+  UV__SIGNAL_ONE_SHOT = 0x80000,  /* On signal reception remove sighandler */
   UV__HANDLE_INTERNAL = 0x8000,
   UV__HANDLE_ACTIVE   = 0x4000,
   UV__HANDLE_REF      = 0x2000,
   UV__HANDLE_CLOSING  = 0 /* no-op on unix */
 };
 #else
-# define UV__HANDLE_INTERNAL  0x80
-# define UV__HANDLE_ACTIVE    0x40
-# define UV__HANDLE_REF       0x20
-# define UV__HANDLE_CLOSING   0x01
+# define UV__SIGNAL_ONE_SHOT_DISPATCHED   0x200
+# define UV__SIGNAL_ONE_SHOT              0x100
+# define UV__HANDLE_INTERNAL              0x80
+# define UV__HANDLE_ACTIVE                0x40
+# define UV__HANDLE_REF                   0x20
+# define UV__HANDLE_CLOSING               0x01
 #endif
 
 int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
@@ -215,6 +218,30 @@ void uv__fs_scandir_cleanup(uv_fs_t* req);
   }                                                                           \
   while (0)
 
+/* Note: uses an open-coded version of SET_REQ_SUCCESS() because of
+ * a circular dependency between src/uv-common.h and src/win/internal.h.
+ */
+#if defined(_WIN32)
+# define UV_REQ_INIT(req, typ)                                                \
+  do {                                                                        \
+    (req)->type = (typ);                                                      \
+    (req)->u.io.overlapped.Internal = 0;  /* SET_REQ_SUCCESS() */             \
+  }                                                                           \
+  while (0)
+#else
+# define UV_REQ_INIT(req, typ)                                                \
+  do {                                                                        \
+    (req)->type = (typ);                                                      \
+  }                                                                           \
+  while (0)
+#endif
+
+#define uv__req_init(loop, req, typ)                                          \
+  do {                                                                        \
+    UV_REQ_INIT(req, typ);                                                    \
+    uv__req_register(loop, req);                                              \
+  }                                                                           \
+  while (0)
 
 /* Allocator prototypes */
 void *uv__calloc(size_t count, size_t size);
diff --git a/src/win/async.c b/src/win/async.c
index ad240ab..0b636ed 100644
--- a/src/win/async.c
+++ b/src/win/async.c
@@ -45,8 +45,7 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
   handle->async_cb = async_cb;
 
   req = &handle->async_req;
-  uv_req_init(loop, req);
-  req->type = UV_WAKEUP;
+  UV_REQ_INIT(req, UV_WAKEUP);
   req->data = handle;
 
   uv__handle_start(handle);
diff --git a/src/win/atomicops-inl.h b/src/win/atomicops-inl.h
index 61e0060..6d8126f 100644
--- a/src/win/atomicops-inl.h
+++ b/src/win/atomicops-inl.h
@@ -23,6 +23,7 @@
 #define UV_WIN_ATOMICOPS_INL_H_
 
 #include "uv.h"
+#include "internal.h"
 
 
 /* Atomic set operation on char */
@@ -34,7 +35,7 @@
 /* target to be aligned. */
 #pragma intrinsic(_InterlockedOr8)
 
-static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) {
+static char INLINE uv__atomic_exchange_set(char volatile* target) {
   return _InterlockedOr8(target, 1);
 }
 
diff --git a/src/win/core.c b/src/win/core.c
index e84186d..9ed4e82 100644
--- a/src/win/core.c
+++ b/src/win/core.c
@@ -83,13 +83,8 @@ static int uv__loops_capacity;
 #define UV__LOOPS_CHUNK_SIZE 8
 static uv_mutex_t uv__loops_lock;
 
-static void uv__loops_init() {
+static void uv__loops_init(void) {
   uv_mutex_init(&uv__loops_lock);
-  uv__loops = uv__calloc(UV__LOOPS_CHUNK_SIZE, sizeof(uv_loop_t*));
-  if (!uv__loops)
-    uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
-  uv__loops_size = 0;
-  uv__loops_capacity = UV__LOOPS_CHUNK_SIZE;
 }
 
 static int uv__loops_add(uv_loop_t* loop) {
@@ -138,6 +133,13 @@ static void uv__loops_remove(uv_loop_t* loop) {
   uv__loops[uv__loops_size - 1] = NULL;
   --uv__loops_size;
 
+  if (uv__loops_size == 0) {
+    uv__loops_capacity = 0;
+    uv__free(uv__loops);
+    uv__loops = NULL;
+    goto loop_removed;
+  }
+
   /* If we didn't grow to big skip downsizing */
   if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
     goto loop_removed;
@@ -156,7 +158,7 @@ loop_removed:
   uv_mutex_unlock(&uv__loops_lock);
 }
 
-void uv__wake_all_loops() {
+void uv__wake_all_loops(void) {
   int i;
   uv_loop_t* loop;
 
@@ -332,6 +334,11 @@ int uv_backend_fd(const uv_loop_t* loop) {
 }
 
 
+int uv_loop_fork(uv_loop_t* loop) {
+  return UV_ENOSYS;
+}
+
+
 int uv_backend_timeout(const uv_loop_t* loop) {
   if (loop->stop_flag != 0)
     return 0;
diff --git a/src/win/detect-wakeup.c b/src/win/detect-wakeup.c
index a12179f..72dfb7a 100644
--- a/src/win/detect-wakeup.c
+++ b/src/win/detect-wakeup.c
@@ -2,9 +2,9 @@
 #include "internal.h"
 #include "winapi.h"
 
-static void uv__register_system_resume_callback();
+static void uv__register_system_resume_callback(void);
 
-void uv__init_detect_system_wakeup() {
+void uv__init_detect_system_wakeup(void) {
   /* Try registering system power event callback. This is the cleanest
    * method, but it will only work on Win8 and above.
    */
@@ -20,7 +20,7 @@ static ULONG CALLBACK uv__system_resume_callback(PVOID Context,
   return 0;
 }
 
-static void uv__register_system_resume_callback() {
+static void uv__register_system_resume_callback(void) {
   _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient;
   _HPOWERNOTIFY registration_handle;
 
diff --git a/src/win/fs-event.c b/src/win/fs-event.c
index 05fc1d0..95f843a 100644
--- a/src/win/fs-event.c
+++ b/src/win/fs-event.c
@@ -81,8 +81,17 @@ static void uv_relative_path(const WCHAR* filename,
 
 static int uv_split_path(const WCHAR* filename, WCHAR** dir,
     WCHAR** file) {
-  int len = wcslen(filename);
-  int i = len;
+  size_t len, i;
+ 
+  if (filename == NULL) {
+    if (dir != NULL)
+      *dir = NULL;
+    *file = NULL;
+    return 0;
+  }
+
+  len = wcslen(filename);
+  i = len;
   while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
 
   if (i == 0) {
@@ -131,8 +140,7 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
   handle->short_filew = NULL;
   handle->dirw = NULL;
 
-  uv_req_init(loop, (uv_req_t*)&handle->req);
-  handle->req.type = UV_FS_EVENT_REQ;
+  UV_REQ_INIT(&handle->req, UV_FS_EVENT_REQ);
   handle->req.data = handle;
 
   return 0;
@@ -146,7 +154,8 @@ int uv_fs_event_start(uv_fs_event_t* handle,
   int name_size, is_path_dir;
   DWORD attr, last_error;
   WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
-  WCHAR short_path[MAX_PATH];
+  WCHAR short_path_buffer[MAX_PATH];
+  WCHAR* short_path;
 
   if (uv__is_active(handle))
     return UV_EINVAL;
@@ -196,9 +205,9 @@ int uv_fs_event_start(uv_fs_event_t* handle,
      */
 
     /* Convert to short path. */
+    short_path = short_path_buffer;
     if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) {
-      last_error = GetLastError();
-      goto error;
+      short_path = NULL;
     }
 
     if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
@@ -306,6 +315,9 @@ error:
     handle->buffer = NULL;
   }
 
+  if (uv__is_active(handle))
+    uv__handle_stop(handle);
+
   return uv_translate_sys_error(last_error);
 }
 
@@ -345,8 +357,11 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
 }
 
 
-static int file_info_cmp(WCHAR* str, WCHAR* file_name, int file_name_len) {
-  int str_len;
+static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) {
+  size_t str_len;
+
+  if (str == NULL)
+    return -1;
 
   str_len = wcslen(str);
 
diff --git a/src/win/fs.c b/src/win/fs.c
index 6902d4f..2d72cdc 100644
--- a/src/win/fs.c
+++ b/src/win/fs.c
@@ -114,7 +114,7 @@ const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\";
 const WCHAR UNC_PATH_PREFIX_LEN = 8;
 
 
-void uv_fs_init() {
+void uv_fs_init(void) {
   _fmode = _O_BINARY;
 }
 
@@ -220,9 +220,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
 
 INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
     uv_fs_type fs_type, const uv_fs_cb cb) {
-  uv_req_init(loop, (uv_req_t*) req);
-
-  req->type = UV_FS;
+  UV_REQ_INIT(req, UV_FS);
   req->loop = loop;
   req->flags = 0;
   req->fs_type = fs_type;
@@ -1373,7 +1371,7 @@ static void fs__access(uv_fs_t* req) {
    * - or it's a directory.
    * (Directories cannot be read-only on Windows.)
    */
-  if (!(req->flags & W_OK) ||
+  if (!(req->fs.info.mode & W_OK) ||
       !(attr & FILE_ATTRIBUTE_READONLY) ||
       (attr & FILE_ATTRIBUTE_DIRECTORY)) {
     SET_REQ_RESULT(req, 0);
@@ -2400,7 +2398,7 @@ int uv_fs_access(uv_loop_t* loop,
   if (err)
     return uv_translate_sys_error(err);
 
-  req->flags = flags;
+  req->fs.info.mode = flags;
 
   if (cb) {
     QUEUE_FS_TP_JOB(loop, req);
diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c
index c13bfec..baab838 100644
--- a/src/win/getaddrinfo.c
+++ b/src/win/getaddrinfo.c
@@ -265,11 +265,9 @@ int uv_getaddrinfo(uv_loop_t* loop,
     return UV_EINVAL;
   }
 
-  uv_req_init(loop, (uv_req_t*)req);
-
+  UV_REQ_INIT(req, UV_GETADDRINFO);
   req->getaddrinfo_cb = getaddrinfo_cb;
   req->addrinfo = NULL;
-  req->type = UV_GETADDRINFO;
   req->loop = loop;
   req->retcode = 0;
 
diff --git a/src/win/getnameinfo.c b/src/win/getnameinfo.c
index 66b64b8..9f10cd2 100644
--- a/src/win/getnameinfo.c
+++ b/src/win/getnameinfo.c
@@ -127,12 +127,11 @@ int uv_getnameinfo(uv_loop_t* loop,
     return UV_EINVAL;
   }
 
-  uv_req_init(loop, (uv_req_t*)req);
+  UV_REQ_INIT(req, UV_GETNAMEINFO);
   uv__req_register(loop, req);
 
   req->getnameinfo_cb = getnameinfo_cb;
   req->flags = flags;
-  req->type = UV_GETNAMEINFO;
   req->loop = loop;
   req->retcode = 0;
 
diff --git a/src/win/internal.h b/src/win/internal.h
index b8cfde9..444327d 100644
--- a/src/win/internal.h
+++ b/src/win/internal.h
@@ -206,7 +206,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
 /*
  * TTY
  */
-void uv_console_init();
+void uv_console_init(void);
 
 int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
     uv_read_cb read_cb);
@@ -259,7 +259,7 @@ void uv_prepare_invoke(uv_loop_t* loop);
 void uv_check_invoke(uv_loop_t* loop);
 void uv_idle_invoke(uv_loop_t* loop);
 
-void uv__once_init();
+void uv__once_init(void);
 
 
 /*
@@ -275,7 +275,7 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
 /*
  * Signal watcher
  */
-void uv_signals_init();
+void uv_signals_init(void);
 int uv__signal_dispatch(int signum);
 
 void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle);
@@ -302,7 +302,7 @@ int uv_translate_sys_error(int sys_errno);
 /*
  * FS
  */
-void uv_fs_init();
+void uv_fs_init(void);
 
 
 /*
@@ -323,14 +323,15 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
 /*
  * Utilities.
  */
-void uv__util_init();
+void uv__util_init(void);
 
 uint64_t uv__hrtime(double scale);
-int uv_parent_pid();
-int uv_current_pid();
+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);
 int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
+int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16);
 
 
 /*
@@ -349,13 +350,13 @@ HANDLE uv__stdio_handle(BYTE* buffer, int fd);
 /*
  * Winapi and ntapi utility functions
  */
-void uv_winapi_init();
+void uv_winapi_init(void);
 
 
 /*
  * Winsock utility functions
  */
-void uv_winsock_init();
+void uv_winsock_init(void);
 
 int uv_ntstatus_to_winsock_error(NTSTATUS status);
 
@@ -384,11 +385,11 @@ extern struct sockaddr_in6 uv_addr_ip6_any_;
 /*
  * Wake all loops with fake message
  */
-void uv__wake_all_loops();
+void uv__wake_all_loops(void);
 
 /*
  * Init system wake-up detection
  */
-void uv__init_detect_system_wakeup();
+void uv__init_detect_system_wakeup(void);
 
 #endif /* UV_WIN_INTERNAL_H_ */
diff --git a/src/win/pipe.c b/src/win/pipe.c
index 2442be7..edf3002 100644
--- a/src/win/pipe.c
+++ b/src/win/pipe.c
@@ -103,7 +103,7 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
   handle->pipe.conn.non_overlapped_writes_tail = NULL;
   handle->pipe.conn.readfile_thread = NULL;
 
-  uv_req_init(loop, (uv_req_t*) &handle->pipe.conn.ipc_header_write_req);
+  UV_REQ_INIT(&handle->pipe.conn.ipc_header_write_req, UV_UNKNOWN_REQ);
 
   return 0;
 }
@@ -505,8 +505,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
 
   for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
     req = &handle->pipe.serv.accept_reqs[i];
-    uv_req_init(loop, (uv_req_t*) req);
-    req->type = UV_ACCEPT;
+    UV_REQ_INIT(req, UV_ACCEPT);
     req->data = handle;
     req->pipeHandle = INVALID_HANDLE_VALUE;
     req->next_pending = NULL;
@@ -626,8 +625,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
   HANDLE pipeHandle = INVALID_HANDLE_VALUE;
   DWORD duplex_flags;
 
-  uv_req_init(loop, (uv_req_t*) req);
-  req->type = UV_CONNECT;
+  UV_REQ_INIT(req, UV_CONNECT);
   req->handle = (uv_stream_t*) handle;
   req->cb = cb;
 
@@ -962,7 +960,7 @@ static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
     uv_mutex_lock(m); /* mutex controls *setting* of readfile_thread */
     if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
                         GetCurrentProcess(), &hThread,
-                        0, TRUE, DUPLICATE_SAME_ACCESS)) {
+                        0, FALSE, DUPLICATE_SAME_ACCESS)) {
       handle->pipe.conn.readfile_thread = hThread;
     } else {
       hThread = NULL;
@@ -1239,8 +1237,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
 
   assert(handle->handle != INVALID_HANDLE_VALUE);
 
-  uv_req_init(loop, (uv_req_t*) req);
-  req->type = UV_WRITE;
+  UV_REQ_INIT(req, UV_WRITE);
   req->handle = (uv_stream_t*) handle;
   req->cb = cb;
   req->ipc_header = 0;
@@ -1301,8 +1298,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
         }
       }
 
-      uv_req_init(loop, (uv_req_t*) ipc_header_req);
-      ipc_header_req->type = UV_WRITE;
+      UV_REQ_INIT(ipc_header_req, UV_WRITE);
       ipc_header_req->handle = (uv_stream_t*) handle;
       ipc_header_req->cb = NULL;
       ipc_header_req->ipc_header = 1;
@@ -2076,7 +2072,6 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size)
   buffer[addrlen] = '\0';
 
   err = 0;
-  goto cleanup;
 
 error:
   uv__free(name_info);
diff --git a/src/win/poll.c b/src/win/poll.c
index d479e52..a648ba7 100644
--- a/src/win/poll.c
+++ b/src/win/poll.c
@@ -61,13 +61,13 @@ static void uv__init_overlapped_dummy(void) {
 }
 
 
-static OVERLAPPED* uv__get_overlapped_dummy() {
+static OVERLAPPED* uv__get_overlapped_dummy(void) {
   uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
   return &overlapped_dummy_;
 }
 
 
-static AFD_POLL_INFO* uv__get_afd_poll_info_dummy() {
+static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) {
   return &afd_poll_info_dummy_;
 }
 
@@ -572,13 +572,11 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
 
   /* Initialize 2 poll reqs. */
   handle->submitted_events_1 = 0;
-  uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1));
-  handle->poll_req_1.type = UV_POLL_REQ;
+  UV_REQ_INIT(&handle->poll_req_1, UV_POLL_REQ);
   handle->poll_req_1.data = handle;
 
   handle->submitted_events_2 = 0;
-  uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2));
-  handle->poll_req_2.type = UV_POLL_REQ;
+  UV_REQ_INIT(&handle->poll_req_2, UV_POLL_REQ);
   handle->poll_req_2.data = handle;
 
   return 0;
diff --git a/src/win/process.c b/src/win/process.c
index bdf88d2..d141601 100644
--- a/src/win/process.c
+++ b/src/win/process.c
@@ -148,8 +148,7 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
   handle->child_stdio_buffer = NULL;
   handle->exit_cb_pending = 0;
 
-  uv_req_init(loop, (uv_req_t*)&handle->exit_req);
-  handle->exit_req.type = UV_PROCESS_EXIT;
+  UV_REQ_INIT(&handle->exit_req, UV_PROCESS_EXIT);
   handle->exit_req.data = handle;
 }
 
diff --git a/src/win/req-inl.h b/src/win/req-inl.h
index b5e502e..f2513b7 100644
--- a/src/win/req-inl.h
+++ b/src/win/req-inl.h
@@ -34,6 +34,9 @@
 #define SET_REQ_ERROR(req, error)                                       \
   SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
 
+/* Note: used open-coded in UV_REQ_INIT() because of a circular dependency
+ * between src/uv-common.h and src/win/internal.h.
+ */
 #define SET_REQ_SUCCESS(req)                                            \
   SET_REQ_STATUS((req), STATUS_SUCCESS)
 
@@ -79,12 +82,6 @@
   }
 
 
-INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) {
-  req->type = UV_UNKNOWN_REQ;
-  SET_REQ_SUCCESS(req);
-}
-
-
 INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
   return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
 }
diff --git a/src/win/signal.c b/src/win/signal.c
index af7974c..7b42dd9 100644
--- a/src/win/signal.c
+++ b/src/win/signal.c
@@ -34,7 +34,12 @@ static CRITICAL_SECTION uv__signal_lock;
 
 static BOOL WINAPI uv__signal_control_handler(DWORD type);
 
-void uv_signals_init() {
+int uv__signal_start(uv_signal_t* handle,
+                     uv_signal_cb signal_cb,
+                     int signum,
+                     int oneshot);
+
+void uv_signals_init(void) {
   InitializeCriticalSection(&uv__signal_lock);
   if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
     abort();
@@ -70,7 +75,9 @@ RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare
 int uv__signal_dispatch(int signum) {
   uv_signal_t lookup;
   uv_signal_t* handle;
-  int dispatched = 0;
+  int dispatched;
+
+  dispatched = 0;
 
   EnterCriticalSection(&uv__signal_lock);
 
@@ -83,11 +90,16 @@ int uv__signal_dispatch(int signum) {
     unsigned long previous = InterlockedExchange(
             (volatile LONG*) &handle->pending_signum, signum);
 
+    if (handle->flags & UV__SIGNAL_ONE_SHOT_DISPATCHED)
+      continue;
+
     if (!previous) {
       POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
     }
 
     dispatched = 1;
+    if (handle->flags & UV__SIGNAL_ONE_SHOT)
+      handle->flags |= UV__SIGNAL_ONE_SHOT_DISPATCHED;
   }
 
   LeaveCriticalSection(&uv__signal_lock);
@@ -128,17 +140,13 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) {
 
 
 int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
-  uv_req_t* req;
-
   uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
   handle->pending_signum = 0;
   handle->signum = 0;
   handle->signal_cb = NULL;
 
-  req = &handle->signal_req;
-  uv_req_init(loop, req);
-  req->type = UV_SIGNAL_REQ;
-  req->data = handle;
+  UV_REQ_INIT(&handle->signal_req, UV_SIGNAL_REQ);
+  handle->signal_req.data = handle;
 
   return 0;
 }
@@ -166,6 +174,21 @@ int uv_signal_stop(uv_signal_t* handle) {
 
 
 int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
+  return uv__signal_start(handle, signal_cb, signum, 0);
+}
+
+
+int uv_signal_start_oneshot(uv_signal_t* handle,
+                            uv_signal_cb signal_cb,
+                            int signum) {
+  return uv__signal_start(handle, signal_cb, signum, 1);
+}
+
+
+int uv__signal_start(uv_signal_t* handle,
+                            uv_signal_cb signal_cb,
+                            int signum,
+                            int oneshot) {
   /* Test for invalid signal values. */
   if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG))
     return UV_EINVAL;
@@ -189,6 +212,9 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
   EnterCriticalSection(&uv__signal_lock);
 
   handle->signum = signum;
+  if (oneshot)
+    handle->flags |= UV__SIGNAL_ONE_SHOT;
+
   RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
 
   LeaveCriticalSection(&uv__signal_lock);
@@ -217,6 +243,9 @@ void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
   if (dispatched_signum == handle->signum)
     handle->signal_cb(handle, dispatched_signum);
 
+  if (handle->flags & UV__SIGNAL_ONE_SHOT)
+    uv_signal_stop(handle);
+
   if (handle->flags & UV__HANDLE_CLOSING) {
     /* When it is closing, it must be stopped at this point. */
     assert(handle->signum == 0);
diff --git a/src/win/stream-inl.h b/src/win/stream-inl.h
index b7a3c11..bf12148 100644
--- a/src/win/stream-inl.h
+++ b/src/win/stream-inl.h
@@ -43,10 +43,9 @@ INLINE static void uv_connection_init(uv_stream_t* handle) {
   handle->flags |= UV_HANDLE_CONNECTION;
   handle->stream.conn.write_reqs_pending = 0;
 
-  uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req));
+  UV_REQ_INIT(&handle->read_req, UV_READ);
   handle->read_req.event_handle = NULL;
   handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
-  handle->read_req.type = UV_READ;
   handle->read_req.data = handle;
 
   handle->stream.conn.shutdown_req = NULL;
diff --git a/src/win/stream.c b/src/win/stream.c
index a2466e5..13cbfdc 100644
--- a/src/win/stream.c
+++ b/src/win/stream.c
@@ -210,8 +210,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
     return UV_EPIPE;
   }
 
-  uv_req_init(loop, (uv_req_t*) req);
-  req->type = UV_SHUTDOWN;
+  UV_REQ_INIT(req, UV_SHUTDOWN);
   req->handle = handle;
   req->cb = cb;
 
diff --git a/src/win/tcp.c b/src/win/tcp.c
index 0709696..972539f 100644
--- a/src/win/tcp.c
+++ b/src/win/tcp.c
@@ -555,7 +555,6 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
 
 
 int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
-  uv_loop_t* loop = handle->loop;
   unsigned int i, simultaneous_accepts;
   uv_tcp_accept_t* req;
   int err;
@@ -612,8 +611,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
 
     for (i = 0; i < simultaneous_accepts; i++) {
       req = &handle->tcp.serv.accept_reqs[i];
-      uv_req_init(loop, (uv_req_t*)req);
-      req->type = UV_ACCEPT;
+      UV_REQ_INIT(req, UV_ACCEPT);
       req->accept_socket = INVALID_SOCKET;
       req->data = handle;
 
@@ -635,8 +633,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
     /* try to clean up {uv_simultaneous_server_accepts} requests. */
     for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) {
       req = &handle->tcp.serv.accept_reqs[i];
-      uv_req_init(loop, (uv_req_t*) req);
-      req->type = UV_ACCEPT;
+      UV_REQ_INIT(req, UV_ACCEPT);
       req->accept_socket = INVALID_SOCKET;
       req->data = handle;
       req->wait_handle = INVALID_HANDLE_VALUE;
@@ -779,8 +776,7 @@ static int uv_tcp_try_connect(uv_connect_t* req,
     }
   }
 
-  uv_req_init(loop, (uv_req_t*) req);
-  req->type = UV_CONNECT;
+  UV_REQ_INIT(req, UV_CONNECT);
   req->handle = (uv_stream_t*) handle;
   req->cb = cb;
   memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
@@ -863,8 +859,7 @@ int uv_tcp_write(uv_loop_t* loop,
   int result;
   DWORD bytes;
 
-  uv_req_init(loop, (uv_req_t*) req);
-  req->type = UV_WRITE;
+  UV_REQ_INIT(req, UV_WRITE);
   req->handle = (uv_stream_t*) handle;
   req->cb = cb;
 
diff --git a/src/win/tty.c b/src/win/tty.c
index 1b7adf6..a6f5839 100644
--- a/src/win/tty.c
+++ b/src/win/tty.c
@@ -138,7 +138,7 @@ typedef enum {
 static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED;
 static void uv__determine_vterm_state(HANDLE handle);
 
-void uv_console_init() {
+void uv_console_init(void) {
   if (uv_sem_init(&uv_tty_output_lock, 1))
     abort();
 }
@@ -2126,8 +2126,7 @@ int uv_tty_write(uv_loop_t* loop,
                  uv_write_cb cb) {
   DWORD error;
 
-  uv_req_init(loop, (uv_req_t*) req);
-  req->type = UV_WRITE;
+  UV_REQ_INIT(req, UV_WRITE);
   req->handle = (uv_stream_t*) handle;
   req->cb = cb;
 
diff --git a/src/win/udp.c b/src/win/udp.c
index 9bf1453..2fd15cf 100644
--- a/src/win/udp.c
+++ b/src/win/udp.c
@@ -142,8 +142,7 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
   handle->func_wsarecvfrom = WSARecvFrom;
   handle->send_queue_size = 0;
   handle->send_queue_count = 0;
-  uv_req_init(loop, (uv_req_t*) &(handle->recv_req));
-  handle->recv_req.type = UV_UDP_RECV;
+  UV_REQ_INIT(&handle->recv_req, UV_UDP_RECV);
   handle->recv_req.data = handle;
 
   /* If anything fails beyond this point we need to remove the handle from
@@ -417,8 +416,7 @@ static int uv__send(uv_udp_send_t* req,
   uv_loop_t* loop = handle->loop;
   DWORD result, bytes;
 
-  uv_req_init(loop, (uv_req_t*) req);
-  req->type = UV_UDP_SEND;
+  UV_REQ_INIT(req, UV_UDP_SEND);
   req->handle = handle;
   req->cb = cb;
   memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
diff --git a/src/win/util.c b/src/win/util.c
index 050058a..1d64d4c 100644
--- a/src/win/util.c
+++ b/src/win/util.c
@@ -59,6 +59,9 @@
 # define UNLEN 256
 #endif
 
+/* Maximum environment variable size, including the terminating null */
+#define MAX_ENV_VAR_LENGTH 32767
+
 /* Cached copy of the process title, plus a mutex guarding it. */
 static char *process_title;
 static CRITICAL_SECTION process_title_lock;
@@ -74,7 +77,7 @@ static double hrtime_interval_ = 0;
 /*
  * One-time initialization code for functionality defined in util.c.
  */
-void uv__util_init() {
+void uv__util_init(void) {
   LARGE_INTEGER perf_frequency;
 
   /* Initialize process title access mutex. */
@@ -320,7 +323,7 @@ uint64_t uv_get_total_memory(void) {
 }
 
 
-int uv_parent_pid() {
+int uv_parent_pid(void) {
   int parent_pid = -1;
   HANDLE handle;
   PROCESSENTRY32 pe;
@@ -343,7 +346,7 @@ int uv_parent_pid() {
 }
 
 
-int uv_current_pid() {
+int uv_current_pid(void) {
   if (current_pid == 0) {
     current_pid = GetCurrentProcessId();
   }
@@ -405,7 +408,7 @@ done:
 }
 
 
-static int uv__get_process_title() {
+static int uv__get_process_title(void) {
   WCHAR title_w[MAX_TITLE_LENGTH];
 
   if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {
@@ -1322,6 +1325,47 @@ int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) {
 }
 
 
+/*
+ * Converts a UTF-8 string into a UTF-16 one. The resulting string is
+ * null-terminated.
+ *
+ * If utf8 is null terminated, utf8len can be set to -1, otherwise it must
+ * be specified.
+ */
+int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
+  int bufsize;
+
+  if (utf8 == NULL)
+    return UV_EINVAL;
+
+  /* Check how much space we need */
+  bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0);
+
+  if (bufsize == 0)
+    return uv_translate_sys_error(GetLastError());
+
+  /* Allocate the destination buffer adding an extra byte for the terminating
+   * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so
+   * we do it ourselves always, just in case. */
+  *utf16 = uv__malloc(sizeof(WCHAR) * (bufsize + 1));
+
+  if (*utf16 == NULL)
+    return UV_ENOMEM;
+
+  /* Convert to UTF-16 */
+  bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize);
+
+  if (bufsize == 0) {
+    uv__free(*utf16);
+    *utf16 = NULL;
+    return uv_translate_sys_error(GetLastError());
+  }
+
+  (*utf16)[bufsize] = '\0';
+  return 0;
+}
+
+
 int uv__getpwuid_r(uv_passwd_t* pwd) {
   HANDLE token;
   wchar_t username[UNLEN + 1];
@@ -1387,3 +1431,112 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
 int uv_os_get_passwd(uv_passwd_t* pwd) {
   return uv__getpwuid_r(pwd);
 }
+
+
+int uv_os_getenv(const char* name, char* buffer, size_t* size) {
+  wchar_t var[MAX_ENV_VAR_LENGTH];
+  wchar_t* name_w;
+  DWORD bufsize;
+  size_t len;
+  int r;
+
+  if (name == NULL || buffer == NULL || size == NULL || *size == 0)
+    return UV_EINVAL;
+
+  r = uv__convert_utf8_to_utf16(name, -1, &name_w);
+
+  if (r != 0)
+    return r;
+
+  len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH);
+  uv__free(name_w);
+  assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */
+
+  if (len == 0) {
+    r = GetLastError();
+
+    if (r == ERROR_ENVVAR_NOT_FOUND)
+      return UV_ENOENT;
+
+    return uv_translate_sys_error(r);
+  }
+
+  /* Check how much space we need */
+  bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -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,
+                                var,
+                                -1,
+                                buffer,
+                                *size,
+                                NULL,
+                                NULL);
+
+  if (bufsize == 0)
+    return uv_translate_sys_error(GetLastError());
+
+  *size = bufsize - 1;
+  return 0;
+}
+
+
+int uv_os_setenv(const char* name, const char* value) {
+  wchar_t* name_w;
+  wchar_t* value_w;
+  int r;
+
+  if (name == NULL || value == NULL)
+    return UV_EINVAL;
+
+  r = uv__convert_utf8_to_utf16(name, -1, &name_w);
+
+  if (r != 0)
+    return r;
+
+  r = uv__convert_utf8_to_utf16(value, -1, &value_w);
+
+  if (r != 0) {
+    uv__free(name_w);
+    return r;
+  }
+
+  r = SetEnvironmentVariableW(name_w, value_w);
+  uv__free(name_w);
+  uv__free(value_w);
+
+  if (r == 0)
+    return uv_translate_sys_error(GetLastError());
+
+  return 0;
+}
+
+
+int uv_os_unsetenv(const char* name) {
+  wchar_t* name_w;
+  int r;
+
+  if (name == NULL)
+    return UV_EINVAL;
+
+  r = uv__convert_utf8_to_utf16(name, -1, &name_w);
+
+  if (r != 0)
+    return r;
+
+  r = SetEnvironmentVariableW(name_w, NULL);
+  uv__free(name_w);
+
+  if (r == 0)
+    return uv_translate_sys_error(GetLastError());
+
+  return 0;
+}
diff --git a/src/win/winapi.c b/src/win/winapi.c
index 1fa179b..aa5d719 100644
--- a/src/win/winapi.c
+++ b/src/win/winapi.c
@@ -53,7 +53,7 @@ sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
 sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
 
 
-void uv_winapi_init() {
+void uv_winapi_init(void) {
   HMODULE ntdll_module;
   HMODULE kernel32_module;
   HMODULE powrprof_module;
diff --git a/src/win/winsock.c b/src/win/winsock.c
index d2e667e..e86d76b 100644
--- a/src/win/winsock.c
+++ b/src/win/winsock.c
@@ -80,7 +80,7 @@ static int error_means_no_support(DWORD error) {
 }
 
 
-void uv_winsock_init() {
+void uv_winsock_init(void) {
   WSADATA wsa_data;
   int errorno;
   SOCKET dummy;
-- 
cgit v0.12