uv: Upgrade to v0.11.22
authorTimothy J Fontaine <tjfontaine@gmail.com>
Tue, 11 Mar 2014 00:01:21 +0000 (17:01 -0700)
committerTimothy J Fontaine <tjfontaine@gmail.com>
Tue, 11 Mar 2014 00:01:21 +0000 (17:01 -0700)
46 files changed:
deps/uv/AUTHORS
deps/uv/ChangeLog
deps/uv/Makefile.am
deps/uv/Makefile.mingw
deps/uv/checksparse.sh
deps/uv/configure.ac
deps/uv/include/pthread-fixes.h
deps/uv/include/uv-errno.h
deps/uv/include/uv-unix.h
deps/uv/include/uv-version.h
deps/uv/include/uv-win.h
deps/uv/include/uv.h
deps/uv/libuv.pc.in
deps/uv/src/unix/core.c
deps/uv/src/unix/fs.c
deps/uv/src/unix/internal.h
deps/uv/src/unix/kqueue.c
deps/uv/src/unix/linux-syscalls.c
deps/uv/src/unix/linux-syscalls.h
deps/uv/src/unix/pipe.c
deps/uv/src/unix/process.c
deps/uv/src/unix/pthread-fixes.c
deps/uv/src/unix/stream.c
deps/uv/src/unix/tty.c
deps/uv/src/win/core.c
deps/uv/src/win/fs.c
deps/uv/src/win/internal.h
deps/uv/src/win/pipe.c
deps/uv/src/win/poll.c
deps/uv/src/win/process-stdio.c
deps/uv/src/win/process.c
deps/uv/src/win/signal.c
deps/uv/src/win/stream.c
deps/uv/src/win/tcp.c
deps/uv/src/win/tty.c
deps/uv/src/win/util.c
deps/uv/src/win/winsock.c
deps/uv/test/benchmark-multi-accept.c
deps/uv/test/task.h
deps/uv/test/test-cwd-and-chdir.c
deps/uv/test/test-fs.c
deps/uv/test/test-ipc-send-recv.c
deps/uv/test/test-ipc.c
deps/uv/test/test-list.h
deps/uv/test/test-pipe-sendmsg.c [new file with mode: 0644]
deps/uv/uv.gyp

index b6ea578..7836488 100644 (file)
@@ -124,3 +124,10 @@ William Light <wrl@illest.net>
 Oleg Efimov <o.efimov@corp.badoo.com>
 Lars Gierth <larsg@systemli.org>
 rcp <zerhacken@yahoo.com>
+Alexis Campailla <alexis@janeasystems.com>
+StarWing <weasley.wx@gmail.com>
+thierry-FreeBSD <thierry@FreeBSD.org>
+Isaiah Norton <isaiah.norton@gmail.com>
+Raul Martins <raulms.martins@gmail.com>
+David Capello <davidcapello@gmail.com>
+Paul Tan <pyokagan@gmail.com>
index a37b0e4..3536abb 100644 (file)
@@ -1,4 +1,41 @@
-2014.02.28, Version 0.11.21 (Unstable)
+2014.03.11, Version 0.11.22 (Unstable)
+
+Changes since version 0.11.21:
+
+* unix, windows: map ERANGE errno (Saúl Ibarra Corretgé)
+
+* unix, windows: make uv_cwd be consistent with uv_exepath (Saúl Ibarra
+  Corretgé)
+
+* process: remove debug perror() prints (Fedor Indutny)
+
+* windows: fall back for volume info query (Isaiah Norton)
+
+* pipe: allow queueing pending handles (Fedor Indutny)
+
+* windows: fix winsock status codes for address errors (Raul Martins)
+
+* windows: Remove unused variable from uv__pipe_insert_pending_socket (David
+  Capello)
+
+* unix: workaround broken pthread_sigmask on Android (Paul Tan)
+
+* error: add ENXIO for O_NONBLOCK FIFO open() (Fedor Indutny)
+
+* freebsd: use accept4, introduced in version 10 (Saúl Ibarra Corretgé)
+
+* windows: fix warnings of MinGW -Wall -O3 (StarWing)
+
+* openbsd, osx: fix compilation warning on scandir (Saúl Ibarra Corretgé)
+
+* linux: always deregister closing fds from epoll (Geoffry Song)
+
+* unix: reopen tty as /dev/tty (Saúl Ibarra Corretgé)
+
+* kqueue: invalidate fd in uv_fs_event_t (Fedor Indutny)
+
+
+2014.02.28, Version 0.11.21 (Unstable), 3ef958158ae1019e027ebaa93114160099db5206
 
 Changes since version 0.11.20:
 
@@ -90,6 +127,14 @@ Changes since version 0.11.18:
 * linux: fix C99/C++ comment (Fedor Indutny)
 
 
+2014.02.19, Version 0.10.25 (Stable), d778dc588507588b12b9f9d2905078db542ed751
+
+Changes since version 0.10.24:
+
+* stream: start thread after assignments (Oguz Bastemur)
+
+* unix: correct error when calling uv_shutdown twice (Saúl Ibarra Corretgé)
+
 2014.01.30, Version 0.10.24 (Stable), aecd296b6bce9b40f06a61c5c94e43d45ac7308a
 
 Changes since version 0.10.23:
index 75ec751..3aa40c6 100644 (file)
@@ -158,6 +158,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
                          test/test-pipe-bind-error.c \
                          test/test-pipe-connect-error.c \
                          test/test-pipe-getsockname.c \
+                         test/test-pipe-sendmsg.c \
                          test/test-pipe-server-close.c \
                          test/test-platform-output.c \
                          test/test-poll-close.c \
index b424f90..af84c75 100644 (file)
@@ -12,7 +12,7 @@
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-CC = gcc
+CC ?= gcc
 
 CFLAGS += -Wall \
           -Wextra \
@@ -72,8 +72,11 @@ OBJS = src/fs-poll.o \
 
 all: libuv.a
 
+clean:
+       -$(RM) $(OBJS) libuv.a
+
 libuv.a: $(OBJS)
        $(AR) crs $@ $^
 
-# FIXME(bnoordhuis) Don't rebuild everything when a source file changes.
-$(OBJS): $(OBJS:.o=.c) $(INCLUDES)
+$(OBJS): %.o : %.c $(INCLUDES)
+       $(CC) $(CFLAGS) -c -o $@ $<
index 54cd580..d2dc3a5 100755 (executable)
@@ -115,6 +115,7 @@ test/test-pass-always.c
 test/test-ping-pong.c
 test/test-pipe-bind-error.c
 test/test-pipe-connect-error.c
+test/test-pipe-sendmsg.c
 test/test-pipe-server-close.c
 test/test-platform-output.c
 test/test-poll-close.c
index 2b6eadf..8c928a5 100644 (file)
@@ -13,7 +13,7 @@
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 AC_PREREQ(2.57)
-AC_INIT([libuv], [0.11.21], [https://github.com/joyent/libuv/issues])
+AC_INIT([libuv], [0.11.22], [https://github.com/joyent/libuv/issues])
 AC_CONFIG_MACRO_DIR([m4])
 m4_include([m4/libuv-extra-automake-flags.m4])
 AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS)
@@ -47,8 +47,8 @@ AM_CONDITIONAL([SUNOS],   [AS_CASE([$host_os], [solaris*], [true], [false])])
 AM_CONDITIONAL([WINNT],   [AS_CASE([$host_os], [mingw*],   [true], [false])])
 PANDORA_ENABLE_DTRACE
 AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes)
-AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" = "xyes"])
-AS_IF([test "x$PKG_CONFIG" = "xyes"], [
+AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" != "x"])
+AS_IF([test "x$PKG_CONFIG" != "x"], [
     AC_CONFIG_FILES([libuv.pc])
 ])
 AC_CONFIG_FILES([Makefile])
index 230ce31..88c6b66 100644 (file)
@@ -56,4 +56,17 @@ int pthread_barrier_destroy(pthread_barrier_t *barrier);
 #endif  /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */
 
 int pthread_yield(void);
+
+/* Workaround pthread_sigmask() returning EINVAL on versions < 4.1 by
+ * replacing all calls to pthread_sigmask with sigprocmask. See:
+ * https://android.googlesource.com/platform/bionic/+/9bf330b5
+ * https://code.google.com/p/android/issues/detail?id=15337
+ */
+int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
+
+#ifdef pthread_sigmask
+#undef pthread_sigmask
+#endif
+#define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset)
+
 #endif  /* GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H */
index 466cdf2..3b6834f 100644 (file)
 # define UV__ERANGE (-4034)
 #endif
 
+#if defined(ENXIO) && !defined(_WIN32)
+# define UV__ENXIO (-ENXIO)
+#else
+# define UV__ENXIO (-4033)
+#endif
+
 #endif /* UV_ERRNO_H_ */
index eea5a3f..b150905 100644 (file)
@@ -230,6 +230,7 @@ typedef struct {
   uv_connection_cb connection_cb;                                             \
   int delayed_error;                                                          \
   int accepted_fd;                                                            \
+  void* queued_fds;                                                           \
   UV_STREAM_PRIVATE_PLATFORM_FIELDS                                           \
 
 #define UV_TCP_PRIVATE_FIELDS /* empty */
index e48082f..e4ebf24 100644 (file)
@@ -32,7 +32,7 @@
 
 #define UV_VERSION_MAJOR 0
 #define UV_VERSION_MINOR 11
-#define UV_VERSION_PATCH 21
+#define UV_VERSION_PATCH 22
 #define UV_VERSION_IS_RELEASE 1
 
 #endif /* UV_VERSION_H */
index db8f861..c254280 100644 (file)
@@ -424,10 +424,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
   uv_write_t ipc_header_write_req;                                            \
   int ipc_pid;                                                                \
   uint64_t remaining_ipc_rawdata_bytes;                                       \
-  unsigned char reserved[sizeof(void*)];                                      \
   struct {                                                                    \
-    WSAPROTOCOL_INFOW* socket_info;                                           \
-    int tcp_connection;                                                       \
+    void* queue[2];                                                           \
+    int queue_len;                                                            \
   } pending_ipc_info;                                                         \
   uv_write_t* non_overlapped_writes_tail;
 
index 49c2a43..7886e62 100644 (file)
@@ -137,6 +137,7 @@ extern "C" {
   XX(EXDEV, "cross-device link not permitted")                                \
   XX(UNKNOWN, "unknown error")                                                \
   XX(EOF, "end of file")                                                      \
+  XX(ENXIO, "no such device or address")                                      \
 
 #define UV_HANDLE_TYPE_MAP(XX)                                                \
   XX(ASYNC, async)                                                            \
@@ -398,17 +399,6 @@ typedef void (*uv_alloc_cb)(uv_handle_t* handle,
 typedef void (*uv_read_cb)(uv_stream_t* stream,
                            ssize_t nread,
                            const uv_buf_t* buf);
-
-/*
- * Just like the uv_read_cb except that if the pending parameter is true
- * then you can use uv_accept() to pull the new handle into the process.
- * If no handle is pending then pending will be UV_UNKNOWN_HANDLE.
- */
-typedef void (*uv_read2_cb)(uv_pipe_t* pipe,
-                            ssize_t nread,
-                            const uv_buf_t* buf,
-                            uv_handle_type pending);
-
 typedef void (*uv_write_cb)(uv_write_t* req, int status);
 typedef void (*uv_connect_cb)(uv_connect_t* req, int status);
 typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status);
@@ -611,7 +601,6 @@ UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
   size_t write_queue_size;                                                    \
   uv_alloc_cb alloc_cb;                                                       \
   uv_read_cb read_cb;                                                         \
-  uv_read2_cb read2_cb;                                                       \
   /* private */                                                               \
   UV_STREAM_PRIVATE_FIELDS
 
@@ -660,13 +649,6 @@ UV_EXTERN int uv_read_start(uv_stream_t*,
 
 UV_EXTERN int uv_read_stop(uv_stream_t*);
 
-/*
- * Extended read methods for receiving handles over a pipe. The pipe must be
- * initialized with ipc == 1.
- */
-UV_EXTERN int uv_read2_start(uv_stream_t*, uv_alloc_cb alloc_cb,
-    uv_read2_cb read_cb);
-
 
 /*
  * Write data to stream. Buffers are written in order. Example:
@@ -1213,6 +1195,15 @@ UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle,
  */
 UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
 
+/*
+ * Used to receive handles over ipc pipes.
+ *
+ * First - call `uv_pipe_pending_count`, if it is > 0 - initialize handle
+ * using type, returned by `uv_pipe_pending_type` and call
+ * `uv_accept(pipe, handle)`.
+ */
+UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle);
+UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
 
 /*
  * uv_poll_t is a subclass of uv_handle_t.
@@ -2076,7 +2067,7 @@ UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst);
 UV_EXTERN int uv_exepath(char* buffer, size_t* size);
 
 /* Gets the current working directory */
-UV_EXTERN int uv_cwd(char* buffer, size_t size);
+UV_EXTERN int uv_cwd(char* buffer, size_t* size);
 
 /* Changes the current working directory */
 UV_EXTERN int uv_chdir(const char* dir);
index 86c1a12..2933ec2 100644 (file)
@@ -7,5 +7,5 @@ Name: @PACKAGE_NAME@
 Version: @PACKAGE_VERSION@
 Description: multi-platform support library with a focus on asynchronous I/O.
 
-Libs: -L${libdir} -luv
+Libs: -L${libdir} -luv @LIBS@
 Cflags: -I${includedir}
index a843044..b393097 100644 (file)
 # include <sys/filio.h>
 # include <sys/ioctl.h>
 # include <sys/wait.h>
+# define UV__O_CLOEXEC O_CLOEXEC
+# if __FreeBSD__ >= 10
+#  define uv__accept4 accept4
+#  define UV__SOCK_NONBLOCK SOCK_NONBLOCK
+#  define UV__SOCK_CLOEXEC  SOCK_CLOEXEC
+# endif
+# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC)
+#  define F_DUP2FD_CLOEXEC  _F_DUP2FD_CLOEXEC
+# endif
 #endif
 
 static void uv__run_pending(uv_loop_t* loop);
@@ -371,7 +380,7 @@ int uv__accept(int sockfd) {
   assert(sockfd >= 0);
 
   while (1) {
-#if defined(__linux__)
+#if defined(__linux__) || __FreeBSD__ >= 10
     static int no_accept4;
 
     if (no_accept4)
@@ -589,16 +598,14 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
 }
 
 
-int uv_cwd(char* buffer, size_t size) {
-  if (buffer == NULL)
-    return -EINVAL;
-
-  if (size == 0)
+int uv_cwd(char* buffer, size_t* size) {
+  if (buffer == NULL || size == NULL)
     return -EINVAL;
 
-  if (getcwd(buffer, size) == NULL)
+  if (getcwd(buffer, *size) == NULL)
     return -errno;
 
+  *size = strlen(buffer);
   return 0;
 }
 
@@ -817,3 +824,93 @@ int uv_getrusage(uv_rusage_t* rusage) {
 
   return 0;
 }
+
+
+int uv__open_cloexec(const char* path, int flags) {
+  int err;
+  int fd;
+
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9)
+  static int no_cloexec;
+
+  if (!no_cloexec) {
+    fd = open(path, flags | UV__O_CLOEXEC);
+    if (fd != -1)
+      return fd;
+
+    if (errno != EINVAL)
+      return -errno;
+
+    /* O_CLOEXEC not supported. */
+    no_cloexec = 1;
+  }
+#endif
+
+  fd = open(path, flags);
+  if (fd == -1)
+    return -errno;
+
+  err = uv__cloexec(fd, 1);
+  if (err) {
+    uv__close(fd);
+    return err;
+  }
+
+  return fd;
+}
+
+
+int uv__dup2_cloexec(int oldfd, int newfd) {
+  int r;
+#if defined(__FreeBSD__) && __FreeBSD__ >= 10
+  do
+    r = dup3(oldfd, newfd, O_CLOEXEC);
+  while (r == -1 && errno == EINTR);
+  if (r == -1)
+    return -errno;
+  return r;
+#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC)
+  do
+    r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd);
+  while (r == -1 && errno == EINTR);
+  if (r != -1)
+    return r;
+  if (errno != EINVAL)
+    return -errno;
+  /* Fall through. */
+#elif defined(__linux__)
+  static int no_dup3;
+  if (!no_dup3) {
+    do
+      r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC);
+    while (r == -1 && (errno == EINTR || errno == EBUSY));
+    if (r != -1)
+      return r;
+    if (errno != ENOSYS)
+      return -errno;
+    /* Fall through. */
+    no_dup3 = 1;
+  }
+#endif
+  {
+    int err;
+    do
+      r = dup2(oldfd, newfd);
+#if defined(__linux__)
+    while (r == -1 && (errno == EINTR || errno == EBUSY));
+#else
+    while (r == -1 && errno == EINTR);
+#endif
+
+    if (r == -1)
+      return -errno;
+
+    err = uv__cloexec(newfd, 1);
+    if (err) {
+      uv__close(newfd);
+      return err;
+    }
+
+    return r;
+  }
+}
index b06f992..cf45669 100644 (file)
@@ -271,7 +271,11 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
 }
 
 
+#if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8))
+static int uv__fs_readdir_filter(struct dirent* dent) {
+#else
 static int uv__fs_readdir_filter(const struct dirent* dent) {
+#endif
   return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
 }
 
index 4a4656a..61f5f6a 100644 (file)
 # define O_CLOEXEC 0x00100000
 #endif
 
+typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
+
 /* handle flags */
 enum {
   UV_CLOSING              = 0x01,   /* uv_close() called but not finished. */
@@ -142,6 +144,13 @@ typedef enum {
   UV_CLOCK_FAST = 1      /* Use the fastest clock with <= 1ms granularity. */
 } uv_clocktype_t;
 
+struct uv__stream_queued_fds_s {
+  unsigned int size;
+  unsigned int offset;
+  int fds[1];
+};
+
+
 /* core */
 int uv__nonblock(int fd, int set);
 int uv__close(int fd);
@@ -180,6 +189,8 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd);
 #endif /* defined(__APPLE__) */
 void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
 int uv__accept(int sockfd);
+int uv__dup2_cloexec(int oldfd, int newfd);
+int uv__open_cloexec(const char* path, int flags);
 
 /* tcp */
 int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
@@ -226,6 +237,7 @@ void uv__tcp_close(uv_tcp_t* handle);
 void uv__timer_close(uv_timer_t* handle);
 void uv__udp_close(uv_udp_t* handle);
 void uv__udp_finish_close(uv_udp_t* handle);
+uv_handle_type uv__handle_type(int fd);
 
 #if defined(__APPLE__)
 int uv___stream_fd(uv_stream_t* handle);
index 5a25e11..7706417 100644 (file)
@@ -383,10 +383,10 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
 
 #if defined(__APPLE__)
   if (uv__fsevents_close(handle))
-    uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN);
-#else
-  uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN);
 #endif /* defined(__APPLE__) */
+  {
+    uv__io_close(handle->loop, &handle->event_watcher);
+  }
 
   free(handle->path);
   handle->path = NULL;
index c9cc44d..1ff8abd 100644 (file)
 # endif
 #endif /* __NR_pwritev */
 
+#ifndef __NR_dup3
+# if defined(__x86_64__)
+#  define __NR_dup3 292
+# elif defined(__i386__)
+#  define __NR_dup3 330
+# elif defined(__arm__)
+#  define __NR_dup3 (UV_SYSCALL_BASE + 358)
+# endif
+#endif /* __NR_pwritev */
+
 
 int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
 #if defined(__i386__)
@@ -407,6 +417,7 @@ int uv__utimesat(int dirfd,
 #endif
 }
 
+
 ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
 #if defined(__NR_preadv)
   return syscall(__NR_preadv, fd, iov, iovcnt, offset);
@@ -415,6 +426,7 @@ ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
 #endif
 }
 
+
 ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
 #if defined(__NR_pwritev)
   return syscall(__NR_pwritev, fd, iov, iovcnt, offset);
@@ -422,3 +434,12 @@ ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) {
   return errno = ENOSYS, -1;
 #endif
 }
+
+
+int uv__dup3(int oldfd, int newfd, int flags) {
+#if defined(__NR_dup3)
+  return syscall(__NR_dup3, oldfd, newfd, flags);
+#else
+  return errno = ENOSYS, -1;
+#endif
+}
index 6d9ec9f..0f0b34b 100644 (file)
@@ -149,5 +149,6 @@ int uv__utimesat(int dirfd,
                  int flags);
 ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
 ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+int uv__dup3(int oldfd, int newfd, int flags);
 
 #endif /* UV_LINUX_SYSCALL_H_ */
index 34c118b..a26c3db 100644 (file)
@@ -246,3 +246,31 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) {
 
 void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
 }
+
+
+int uv_pipe_pending_count(uv_pipe_t* handle) {
+  uv__stream_queued_fds_t* queued_fds;
+
+  if (!handle->ipc)
+    return 0;
+
+  if (handle->accepted_fd == -1)
+    return 0;
+
+  if (handle->queued_fds == NULL)
+    return 1;
+
+  queued_fds = handle->queued_fds;
+  return queued_fds->offset + 1;
+}
+
+
+uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
+  if (!handle->ipc)
+    return UV_UNKNOWN_HANDLE;
+
+  if (handle->accepted_fd == -1)
+    return UV_UNKNOWN_HANDLE;
+  else
+    return uv__handle_type(handle->accepted_fd);
+}
index 55f6ac5..53fef84 100644 (file)
@@ -302,8 +302,7 @@ static void uv__process_child_init(const uv_process_options_t* options,
         close_fd = use_fd;
 
         if (use_fd == -1) {
-        uv__write_int(error_fd, -errno);
-          perror("failed to open stdio");
+          uv__write_int(error_fd, -errno);
           _exit(127);
         }
       }
@@ -330,7 +329,6 @@ static void uv__process_child_init(const uv_process_options_t* options,
 
   if (options->cwd != NULL && chdir(options->cwd)) {
     uv__write_int(error_fd, -errno);
-    perror("chdir()");
     _exit(127);
   }
 
@@ -347,13 +345,11 @@ static void uv__process_child_init(const uv_process_options_t* options,
 
   if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
     uv__write_int(error_fd, -errno);
-    perror("setgid()");
     _exit(127);
   }
 
   if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
     uv__write_int(error_fd, -errno);
-    perror("setuid()");
     _exit(127);
   }
 
@@ -363,7 +359,6 @@ static void uv__process_child_init(const uv_process_options_t* options,
 
   execvp(options->file, options->args);
   uv__write_int(error_fd, -errno);
-  perror("execvp()");
   _exit(127);
 }
 
index 2e4c542..dc54f35 100644 (file)
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+/* Android versions < 4.1 have a broken pthread_sigmask.
+ * Note that this block of code must come before any inclusion of
+ * pthread-fixes.h so that the real pthread_sigmask can be referenced.
+ * */
+#include <errno.h>
+#include <pthread.h>
+
+int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) {
+  static int workaround;
+
+  if (workaround) {
+    return sigprocmask(how, set, oset);
+  } else if (pthread_sigmask(how, set, oset)) {
+    if (errno == EINVAL && sigprocmask(how, set, oset) == 0) {
+      workaround = 1;
+      return 0;
+    } else {
+      return -1;
+    }
+  } else {
+    return 0;
+  }
+}
 
 /*Android doesn't provide pthread_barrier_t for now.*/
 #ifndef PTHREAD_BARRIER_SERIAL_THREAD
index ad6856b..370894b 100644 (file)
@@ -63,36 +63,6 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
 static size_t uv__write_req_size(uv_write_t* req);
 
 
-/* Used by the accept() EMFILE party trick. */
-static int uv__open_cloexec(const char* path, int flags) {
-  int err;
-  int fd;
-
-#if defined(__linux__)
-  fd = open(path, flags | UV__O_CLOEXEC);
-  if (fd != -1)
-    return fd;
-
-  if (errno != EINVAL)
-    return -errno;
-
-  /* O_CLOEXEC not supported. */
-#endif
-
-  fd = open(path, flags);
-  if (fd == -1)
-    return -errno;
-
-  err = uv__cloexec(fd, 1);
-  if (err) {
-    uv__close(fd);
-    return err;
-  }
-
-  return fd;
-}
-
-
 static size_t uv_count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
   unsigned int i;
   size_t bytes;
@@ -112,13 +82,13 @@ void uv__stream_init(uv_loop_t* loop,
 
   uv__handle_init(loop, (uv_handle_t*)stream, type);
   stream->read_cb = NULL;
-  stream->read2_cb = NULL;
   stream->alloc_cb = NULL;
   stream->close_cb = NULL;
   stream->connection_cb = NULL;
   stream->connect_req = NULL;
   stream->shutdown_req = NULL;
   stream->accepted_fd = -1;
+  stream->queued_fds = NULL;
   stream->delayed_error = 0;
   QUEUE_INIT(&stream->write_queue);
   QUEUE_INIT(&stream->write_completed_queue);
@@ -570,6 +540,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
   if (server->accepted_fd == -1)
     return -EAGAIN;
 
+  err = 0;
   switch (client->type) {
     case UV_NAMED_PIPE:
     case UV_TCP:
@@ -579,8 +550,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
       if (err) {
         /* TODO handle error */
         uv__close(server->accepted_fd);
-        server->accepted_fd = -1;
-        return err;
+        goto done;
       }
       break;
 
@@ -588,8 +558,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
       err = uv_udp_open((uv_udp_t*) client, server->accepted_fd);
       if (err) {
         uv__close(server->accepted_fd);
-        server->accepted_fd = -1;
-        return err;
+        goto done;
       }
       break;
 
@@ -597,9 +566,33 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
       assert(0);
   }
 
-  uv__io_start(server->loop, &server->io_watcher, UV__POLLIN);
-  server->accepted_fd = -1;
-  return 0;
+done:
+  /* Process queued fds */
+  if (server->queued_fds != NULL) {
+    uv__stream_queued_fds_t* queued_fds;
+
+    queued_fds = server->queued_fds;
+
+    /* Read first */
+    server->accepted_fd = queued_fds->fds[0];
+
+    /* All read, free */
+    assert(queued_fds->offset > 0);
+    if (--queued_fds->offset == 0) {
+      free(queued_fds);
+      server->queued_fds = NULL;
+    } else {
+      /* Shift rest */
+      memmove(queued_fds->fds,
+              queued_fds->fds + 1,
+              queued_fds->offset * sizeof(*queued_fds->fds));
+    }
+  } else {
+    server->accepted_fd = -1;
+    if (err == 0)
+      uv__io_start(server->loop, &server->io_watcher, UV__POLLIN);
+  }
+  return err;
 }
 
 
@@ -777,12 +770,12 @@ start:
     msg.msg_flags = 0;
 
     msg.msg_control = (void*) scratch;
-    msg.msg_controllen = CMSG_LEN(sizeof(fd_to_send));
+    msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send));
 
     cmsg = CMSG_FIRSTHDR(&msg);
     cmsg->cmsg_level = SOL_SOCKET;
     cmsg->cmsg_type = SCM_RIGHTS;
-    cmsg->cmsg_len = msg.msg_controllen;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send));
 
     /* silence aliasing warning */
     {
@@ -913,7 +906,7 @@ static void uv__write_callbacks(uv_stream_t* stream) {
 }
 
 
-static uv_handle_type uv__handle_type(int fd) {
+uv_handle_type uv__handle_type(int fd) {
   struct sockaddr_storage ss;
   socklen_t len;
   int type;
@@ -947,24 +940,106 @@ static uv_handle_type uv__handle_type(int fd) {
 }
 
 
-static void uv__stream_read_cb(uv_stream_t* stream,
-                               int status,
-                               const uv_buf_t* buf,
-                               uv_handle_type type) {
-  if (stream->read_cb != NULL)
-    stream->read_cb(stream, status, buf);
-  else
-    stream->read2_cb((uv_pipe_t*) stream, status, buf, type);
-}
-
-
 static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
   stream->flags |= UV_STREAM_READ_EOF;
   uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN);
   if (!uv__io_active(&stream->io_watcher, UV__POLLOUT))
     uv__handle_stop(stream);
   uv__stream_osx_interrupt_select(stream);
-  uv__stream_read_cb(stream, UV_EOF, buf, UV_UNKNOWN_HANDLE);
+  stream->read_cb(stream, UV_EOF, buf);
+}
+
+
+static int uv__stream_queue_fd(uv_stream_t* stream, int fd) {
+  uv__stream_queued_fds_t* queued_fds;
+  unsigned int queue_size;
+
+  queued_fds = stream->queued_fds;
+  if (queued_fds == NULL) {
+    queue_size = 8;
+    queued_fds = malloc((queue_size - 1) * sizeof(*queued_fds->fds) +
+                        sizeof(*queued_fds));
+    if (queued_fds == NULL)
+      return -ENOMEM;
+    queued_fds->size = queue_size;
+    queued_fds->offset = 0;
+    stream->queued_fds = queued_fds;
+
+    /* Grow */
+  } else if (queued_fds->size == queued_fds->offset) {
+    queue_size = queued_fds->size + 8;
+    queued_fds = realloc(queued_fds,
+                         (queue_size - 1) * sizeof(*queued_fds->fds) +
+                             sizeof(*queued_fds));
+
+    /*
+     * Allocation failure, report back.
+     * NOTE: if it is fatal - sockets will be closed in uv__stream_close
+     */
+    if (queued_fds == NULL)
+      return -ENOMEM;
+    queued_fds->size = queue_size;
+    stream->queued_fds = queued_fds;
+  }
+
+  /* Put fd in a queue */
+  queued_fds->fds[queued_fds->offset++] = fd;
+
+  return 0;
+}
+
+
+#define UV__CMSG_FD_COUNT 64
+#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int))
+
+
+static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
+  struct cmsghdr* cmsg;
+
+  for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+    char* start;
+    char* end;
+    int err;
+    void* pv;
+    int* pi;
+    unsigned int i;
+    unsigned int count;
+
+    if (cmsg->cmsg_type != SCM_RIGHTS) {
+      fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
+          cmsg->cmsg_type);
+      continue;
+    }
+
+    /* silence aliasing warning */
+    pv = CMSG_DATA(cmsg);
+    pi = pv;
+
+    /* Count available fds */
+    start = (char*) cmsg;
+    end = (char*) cmsg + cmsg->cmsg_len;
+    count = 0;
+    while (start + CMSG_LEN(count * sizeof(*pi)) < end)
+      count++;
+    assert(start + CMSG_LEN(count * sizeof(*pi)) == end);
+
+    for (i = 0; i < count; i++) {
+      /* Already has accepted fd, queue now */
+      if (stream->accepted_fd != -1) {
+        err = uv__stream_queue_fd(stream, pi[i]);
+        if (err != 0) {
+          /* Close rest */
+          for (; i < count; i++)
+            uv__close(pi[i]);
+          return err;
+        }
+      } else {
+        stream->accepted_fd = pi[i];
+      }
+    }
+  }
+
+  return 0;
 }
 
 
@@ -972,9 +1047,10 @@ static void uv__read(uv_stream_t* stream) {
   uv_buf_t buf;
   ssize_t nread;
   struct msghdr msg;
-  struct cmsghdr* cmsg;
-  char cmsg_space[64];
+  char cmsg_space[CMSG_SPACE(UV__CMSG_FD_SIZE)];
   int count;
+  int err;
+  int is_ipc;
 
   stream->flags &= ~UV_STREAM_READ_PARTIAL;
 
@@ -983,10 +1059,12 @@ static void uv__read(uv_stream_t* stream) {
    */
   count = 32;
 
+  is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc;
+
   /* XXX: Maybe instead of having UV_STREAM_READING we just test if
    * tcp->read_cb is NULL or not?
    */
-  while ((stream->read_cb || stream->read2_cb)
+  while (stream->read_cb
       && (stream->flags & UV_STREAM_READING)
       && (count-- > 0)) {
     assert(stream->alloc_cb != NULL);
@@ -994,29 +1072,28 @@ static void uv__read(uv_stream_t* stream) {
     stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf);
     if (buf.len == 0) {
       /* User indicates it can't or won't handle the read. */
-      uv__stream_read_cb(stream, UV_ENOBUFS, &buf, UV_UNKNOWN_HANDLE);
+      stream->read_cb(stream, UV_ENOBUFS, &buf);
       return;
     }
 
     assert(buf.base != NULL);
     assert(uv__stream_fd(stream) >= 0);
 
-    if (stream->read_cb) {
+    if (!is_ipc) {
       do {
         nread = read(uv__stream_fd(stream), buf.base, buf.len);
       }
       while (nread < 0 && errno == EINTR);
     } else {
-      assert(stream->read2_cb);
-      /* read2_cb uses recvmsg */
+      /* ipc uses recvmsg */
       msg.msg_flags = 0;
       msg.msg_iov = (struct iovec*) &buf;
       msg.msg_iovlen = 1;
       msg.msg_name = NULL;
       msg.msg_namelen = 0;
       /* Set up to receive a descriptor even if one isn't in the message */
-      msg.msg_controllen = 64;
-      msg.msg_control = (void*)  cmsg_space;
+      msg.msg_controllen = sizeof(cmsg_space);
+      msg.msg_control = cmsg_space;
 
       do {
         nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
@@ -1032,10 +1109,10 @@ static void uv__read(uv_stream_t* stream) {
           uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN);
           uv__stream_osx_interrupt_select(stream);
         }
-        uv__stream_read_cb(stream, 0, &buf, UV_UNKNOWN_HANDLE);
+        stream->read_cb(stream, 0, &buf);
       } else {
         /* Error. User should call uv_close(). */
-        uv__stream_read_cb(stream, -errno, &buf, UV_UNKNOWN_HANDLE);
+        stream->read_cb(stream, -errno, &buf);
         assert(!uv__io_active(&stream->io_watcher, UV__POLLIN) &&
                "stream->read_cb(status=-1) did not call uv_close()");
       }
@@ -1047,50 +1124,14 @@ static void uv__read(uv_stream_t* stream) {
       /* Successful read */
       ssize_t buflen = buf.len;
 
-      if (stream->read_cb) {
-        stream->read_cb(stream, nread, &buf);
-      } else {
-        assert(stream->read2_cb);
-
-        /*
-         * XXX: Some implementations can send multiple file descriptors in a
-         * single message. We should be using CMSG_NXTHDR() to walk the
-         * chain to get at them all. This would require changing the API to
-         * hand these back up the caller, is a pain.
-         */
-
-        for (cmsg = CMSG_FIRSTHDR(&msg);
-             msg.msg_controllen > 0 && cmsg != NULL;
-             cmsg = CMSG_NXTHDR(&msg, cmsg)) {
-
-          if (cmsg->cmsg_type == SCM_RIGHTS) {
-            if (stream->accepted_fd != -1) {
-              fprintf(stderr, "(libuv) ignoring extra FD received\n");
-            }
-
-            /* silence aliasing warning */
-            {
-              void* pv = CMSG_DATA(cmsg);
-              int* pi = pv;
-              stream->accepted_fd = *pi;
-            }
-
-          } else {
-            fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
-                cmsg->cmsg_type);
-          }
-        }
-
-
-        if (stream->accepted_fd >= 0) {
-          stream->read2_cb((uv_pipe_t*) stream,
-                           nread,
-                           &buf,
-                           uv__handle_type(stream->accepted_fd));
-        } else {
-          stream->read2_cb((uv_pipe_t*) stream, nread, &buf, UV_UNKNOWN_HANDLE);
+      if (is_ipc) {
+        err = uv__stream_recv_cmsg(stream, &msg);
+        if (err != 0) {
+          stream->read_cb(stream, err, NULL);
+          return;
         }
       }
+      stream->read_cb(stream, nread, &buf);
 
       /* Return if we didn't fill the buffer, there is no more data to read. */
       if (nread < buflen) {
@@ -1102,6 +1143,10 @@ static void uv__read(uv_stream_t* stream) {
 }
 
 
+#undef UV__CMSG_FD_COUNT
+#undef UV__CMSG_FD_SIZE
+
+
 int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
   assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) &&
          "uv_shutdown (unix) only supports uv_handle_t right now");
@@ -1371,10 +1416,9 @@ int uv_try_write(uv_stream_t* stream,
 }
 
 
-static int uv__read_start_common(uv_stream_t* stream,
-                                 uv_alloc_cb alloc_cb,
-                                 uv_read_cb read_cb,
-                                 uv_read2_cb read2_cb) {
+int uv_read_start(uv_stream_t* stream,
+                  uv_alloc_cb alloc_cb,
+                  uv_read_cb read_cb) {
   assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
       stream->type == UV_TTY);
 
@@ -1394,7 +1438,6 @@ static int uv__read_start_common(uv_stream_t* stream,
   assert(alloc_cb);
 
   stream->read_cb = read_cb;
-  stream->read2_cb = read2_cb;
   stream->alloc_cb = alloc_cb;
 
   uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN);
@@ -1405,18 +1448,6 @@ static int uv__read_start_common(uv_stream_t* stream,
 }
 
 
-int uv_read_start(uv_stream_t* stream, uv_alloc_cb alloc_cb,
-    uv_read_cb read_cb) {
-  return uv__read_start_common(stream, alloc_cb, read_cb, NULL);
-}
-
-
-int uv_read2_start(uv_stream_t* stream, uv_alloc_cb alloc_cb,
-    uv_read2_cb read_cb) {
-  return uv__read_start_common(stream, alloc_cb, NULL, read_cb);
-}
-
-
 int uv_read_stop(uv_stream_t* stream) {
   /* Sanity check. We're going to stop the handle unless it's primed for
    * writing but that means there should be some kind of write action in
@@ -1435,7 +1466,6 @@ int uv_read_stop(uv_stream_t* stream) {
   uv__stream_osx_interrupt_select(stream);
 
   stream->read_cb = NULL;
-  stream->read2_cb = NULL;
   stream->alloc_cb = NULL;
   return 0;
 }
@@ -1469,6 +1499,9 @@ int uv___stream_fd(uv_stream_t* handle) {
 
 
 void uv__stream_close(uv_stream_t* handle) {
+  unsigned int i;
+  uv__stream_queued_fds_t* queued_fds;
+
 #if defined(__APPLE__)
   /* Terminate select loop first */
   if (handle->select != NULL) {
@@ -1506,6 +1539,15 @@ void uv__stream_close(uv_stream_t* handle) {
     handle->accepted_fd = -1;
   }
 
+  /* Close all queued fds */
+  if (handle->queued_fds != NULL) {
+    queued_fds = handle->queued_fds;
+    for (i = 0; i < queued_fds->offset; i++)
+      uv__close(queued_fds->fds[i]);
+    free(handle->queued_fds);
+    handle->queued_fds = NULL;
+  }
+
   assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT));
 }
 
index ca9459d..c7ed101 100644 (file)
@@ -35,26 +35,61 @@ static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
 
 
 int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
-  uv__stream_init(loop, (uv_stream_t*)tty, UV_TTY);
+  int flags;
+  int newfd;
+  int r;
+
+  newfd = -1;
+
+  uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
+
+  /* Reopen the file descriptor when it refers to a tty. This lets us put the
+   * tty in non-blocking mode without affecting other processes that share it
+   * with us.
+   *
+   * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also
+   * affects fd 1 of `cat` because both file descriptors refer to the same
+   * struct file in the kernel. When we reopen our fd 0, it points to a
+   * different struct file, hence changing its properties doesn't affect
+   * other processes.
+   */
+  if (isatty(fd)) {
+    newfd = uv__open_cloexec("/dev/tty", O_RDWR);
+
+    if (newfd == -1)
+      return -errno;
 
-#if defined(__APPLE__)
-  {
-    int err = uv__stream_try_select((uv_stream_t*) tty, &fd);
-    if (err)
-      return err;
+    r = uv__dup2_cloexec(newfd, fd);
+    if (r < 0 && r != -EINVAL) {
+      /* EINVAL means newfd == fd which could conceivably happen if another
+       * thread called close(fd) between our calls to isatty() and open().
+       * That's a rather unlikely event but let's handle it anyway.
+       */
+      uv__close(newfd);
+      return r;
+    }
+
+    fd = newfd;
   }
-#endif /* defined(__APPLE__) */
-
-  if (readable) {
-    uv__nonblock(fd, 1);
-    uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_READABLE);
-  } else {
-    /* Note: writable tty we set to blocking mode. */
-    uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_WRITABLE);
-    tty->flags |= UV_STREAM_BLOCKING;
+
+#if defined(__APPLE__)
+  r = uv__stream_try_select((uv_stream_t*) tty, &fd);
+  if (r) {
+    if (newfd != -1)
+      uv__close(newfd);
+    return r;
   }
+#endif
 
+  if (readable)
+    flags = UV_STREAM_READABLE;
+  else
+    flags = UV_STREAM_WRITABLE;
+
+  uv__nonblock(fd, 1);
+  uv__stream_open((uv_stream_t*) tty, fd, flags);
   tty->mode = 0;
+
   return 0;
 }
 
index 2e70276..f749ba9 100644 (file)
@@ -70,11 +70,13 @@ static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_v
 #endif
 
 
+#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
 static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
     const wchar_t* function, const wchar_t * file, unsigned int line,
     uintptr_t reserved) {
   /* No-op. */
 }
+#endif
 
 
 static void uv_init(void) {
@@ -192,7 +194,7 @@ int uv_loop_close(uv_loop_t* loop) {
       return UV_EBUSY;
   }
   if (loop != &uv_default_loop_) {
-    int i;
+    size_t i;
     for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
       SOCKET sock = loop->poll_peer_sockets[i];
       if (sock != 0 && sock != INVALID_SOCKET)
index d997b0e..273ec39 100644 (file)
 
 #define TIME_T_TO_FILETIME(time, filetime_ptr)                              \
   do {                                                                      \
-    *(uint64_t*) (filetime_ptr) = ((int64_t) (time) * 10000000LL) +         \
+    uint64_t bigtime = ((int64_t) (time) * 10000000LL) +                    \
                                   116444736000000000ULL;                    \
+    (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF;                   \
+    (filetime_ptr)->dwHighDateTime = bigtime >> 32;                         \
   } while(0)
 
 #define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
@@ -121,7 +123,7 @@ INLINE static int fs__capture_path(uv_loop_t* loop, uv_fs_t* req,
     const char* path, const char* new_path, const int copy_path) {
   char* buf;
   char* pos;
-  ssize_t buf_sz = 0, path_len, pathw_len, new_pathw_len;
+  ssize_t buf_sz = 0, path_len, pathw_len = 0, new_pathw_len = 0;
 
   /* new_path can only be set if path is also set. */
   assert(new_path == NULL || path != NULL);
@@ -181,7 +183,7 @@ INLINE static int fs__capture_path(uv_loop_t* loop, uv_fs_t* req,
                                   -1,
                                   (WCHAR*) pos,
                                   pathw_len);
-    assert(r == pathw_len);
+    assert(r == (DWORD) pathw_len);
     req->pathw = (WCHAR*) pos;
     pos += r * sizeof(WCHAR);
   } else {
@@ -195,7 +197,7 @@ INLINE static int fs__capture_path(uv_loop_t* loop, uv_fs_t* req,
                                   -1,
                                   (WCHAR*) pos,
                                   new_pathw_len);
-    assert(r == new_pathw_len);
+    assert(r == (DWORD) new_pathw_len);
     req->new_pathw = (WCHAR*) pos;
     pos += r * sizeof(WCHAR);
   } else {
@@ -861,9 +863,13 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
                                             FileFsVolumeInformation);
 
   /* Buffer overflow (a warning status code) is expected here. */
-  if (NT_ERROR(nt_status)) {
+  if (io_status.Status == STATUS_NOT_IMPLEMENTED) {
+    statbuf->st_dev = 0;
+  } else if (NT_ERROR(nt_status)) {
     SetLastError(pRtlNtStatusToDosError(nt_status));
     return -1;
+  } else {
+    statbuf->st_dev = volume_info.VolumeSerialNumber;
   }
 
   /* Todo: st_mode should probably always be 0666 for everyone. We might also
@@ -920,8 +926,6 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
 
   statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
 
-  statbuf->st_dev = volume_info.VolumeSerialNumber;
-
   /* The st_blksize is supposed to be the 'optimal' number of bytes for reading
    * and writing to the disk. That is, for any definition of 'optimal' - it's
    * supposed to at least avoid read-update-write behavior when writing to the
index cf6c858..82f8eb6 100644 (file)
@@ -166,8 +166,6 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
 int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
 int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
     uv_read_cb read_cb);
-int uv_pipe_read2_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
-    uv_read2_cb read_cb);
 int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
     const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
 int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
@@ -325,7 +323,7 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
 void uv__util_init();
 
 int uv_parent_pid();
-void uv_fatal_error(const int errorno, const char* syscall);
+__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
 
 
 /*
index 69c5cde..b832a28 100644 (file)
 #include "stream-inl.h"
 #include "req-inl.h"
 
+typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;
+
+struct uv__ipc_queue_item_s {
+  /*
+   * NOTE: It is important for socket_info to be the first field,
+   * because we will we assigning it to the pending_ipc_info.socket_info
+   */
+  WSAPROTOCOL_INFOW socket_info;
+  QUEUE member;
+  int tcp_connection;
+};
 
 /* A zero-size buffer for use by uv_pipe_read */
 static char uv_zero_[] = "";
@@ -86,8 +97,8 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
   handle->name = NULL;
   handle->ipc_pid = 0;
   handle->remaining_ipc_rawdata_bytes = 0;
-  handle->pending_ipc_info.socket_info = NULL;
-  handle->pending_ipc_info.tcp_connection = 0;
+  QUEUE_INIT(&handle->pending_ipc_info.queue);
+  handle->pending_ipc_info.queue_len = 0;
   handle->ipc = ipc;
   handle->non_overlapped_writes_tail = NULL;
 
@@ -287,6 +298,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
   NTSTATUS nt_status;
   IO_STATUS_BLOCK io_status;
   FILE_PIPE_LOCAL_INFORMATION pipe_info;
+  uv__ipc_queue_item_t* item;
 
   if ((handle->flags & UV_HANDLE_CONNECTION) &&
       handle->shutdown_req != NULL &&
@@ -362,10 +374,28 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
     assert(!(handle->flags & UV_HANDLE_CLOSED));
 
     if (handle->flags & UV_HANDLE_CONNECTION) {
-      if (handle->pending_ipc_info.socket_info) {
-        free(handle->pending_ipc_info.socket_info);
-        handle->pending_ipc_info.socket_info = NULL;
+      /* Free pending sockets */
+      while (!QUEUE_EMPTY(&handle->pending_ipc_info.queue)) {
+        QUEUE* q;
+        SOCKET socket;
+
+        q = QUEUE_HEAD(&handle->pending_ipc_info.queue);
+        QUEUE_REMOVE(q);
+        item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
+
+        /* Materialize socket and close it */
+        socket = WSASocketW(FROM_PROTOCOL_INFO,
+                            FROM_PROTOCOL_INFO,
+                            FROM_PROTOCOL_INFO,
+                            &item->socket_info,
+                            0,
+                            WSA_FLAG_OVERLAPPED);
+        free(item);
+
+        if (socket != INVALID_SOCKET)
+          closesocket(socket);
       }
+      handle->pending_ipc_info.queue_len = 0;
 
       if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
         if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
@@ -720,15 +750,29 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
   uv_loop_t* loop = server->loop;
   uv_pipe_t* pipe_client;
   uv_pipe_accept_t* req;
+  QUEUE* q;
+  uv__ipc_queue_item_t* item;
+  int err;
 
   if (server->ipc) {
-    if (!server->pending_ipc_info.socket_info) {
+    if (QUEUE_EMPTY(&server->pending_ipc_info.queue)) {
       /* No valid pending sockets. */
       return WSAEWOULDBLOCK;
     }
 
-    return uv_tcp_import((uv_tcp_t*)client, server->pending_ipc_info.socket_info,
-                         server->pending_ipc_info.tcp_connection);
+    q = QUEUE_HEAD(&server->pending_ipc_info.queue);
+    QUEUE_REMOVE(q);
+    server->pending_ipc_info.queue_len--;
+    item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
+
+    err = uv_tcp_import((uv_tcp_t*)client,
+                        &item->socket_info,
+                        item->tcp_connection);
+    if (err != 0)
+      return err;
+
+    free(item);
+
   } else {
     pipe_client = (uv_pipe_t*)client;
 
@@ -956,14 +1000,14 @@ error:
 }
 
 
-static int uv_pipe_read_start_impl(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
-    uv_read_cb read_cb, uv_read2_cb read2_cb) {
+int uv_pipe_read_start(uv_pipe_t* handle,
+                       uv_alloc_cb alloc_cb,
+                       uv_read_cb read_cb) {
   uv_loop_t* loop = handle->loop;
 
   handle->flags |= UV_HANDLE_READING;
   INCREASE_ACTIVE_COUNT(loop, handle);
   handle->read_cb = read_cb;
-  handle->read2_cb = read2_cb;
   handle->alloc_cb = alloc_cb;
 
   /* If reading was stopped and then started again, there could still be a */
@@ -975,18 +1019,6 @@ static int uv_pipe_read_start_impl(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
 }
 
 
-int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
-    uv_read_cb read_cb) {
-  return uv_pipe_read_start_impl(handle, alloc_cb, read_cb, NULL);
-}
-
-
-int uv_pipe_read2_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
-    uv_read2_cb read_cb) {
-  return uv_pipe_read_start_impl(handle, alloc_cb, NULL, read_cb);
-}
-
-
 static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle,
     uv_write_t* req) {
   req->next_req = NULL;
@@ -1045,7 +1077,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
   int err;
   int result;
   uv_tcp_t* tcp_send_handle;
-  uv_write_t* ipc_header_req;
+  uv_write_t* ipc_header_req = NULL;
   uv_ipc_frame_uv_stream ipc_frame;
 
   if (nbufs != 1 && (nbufs != 0 || !send_handle)) {
@@ -1224,6 +1256,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
       /* Request completed immediately. */
       req->queued_bytes = 0;
     } else {
+      assert(ipc_header_req != NULL);
       /* Request queued by the kernel. */
       if (WaitForSingleObject(ipc_header_req->overlapped.hEvent, INFINITE) !=
           WAIT_OBJECT_0) {
@@ -1314,11 +1347,7 @@ static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
   handle->flags &= ~UV_HANDLE_READABLE;
   uv_read_stop((uv_stream_t*) handle);
 
-  if (handle->read2_cb) {
-    handle->read2_cb(handle, UV_EOF, &uv_null_buf_, UV_UNKNOWN_HANDLE);
-  } else {
-    handle->read_cb((uv_stream_t*) handle, UV_EOF, &uv_null_buf_);
-  }
+  handle->read_cb((uv_stream_t*) handle, UV_EOF, &uv_null_buf_);
 }
 
 
@@ -1330,14 +1359,7 @@ static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
 
   uv_read_stop((uv_stream_t*) handle);
 
-  if (handle->read2_cb) {
-    handle->read2_cb(handle,
-                     uv_translate_sys_error(error),
-                     &buf,
-                     UV_UNKNOWN_HANDLE);
-  } else {
-    handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(error), &buf);
-  }
+  handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(error), &buf);
 }
 
 
@@ -1351,6 +1373,22 @@ static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
 }
 
 
+void uv__pipe_insert_pending_socket(uv_pipe_t* handle,
+                                    WSAPROTOCOL_INFOW* info,
+                                    int tcp_connection) {
+  uv__ipc_queue_item_t* item;
+
+  item = (uv__ipc_queue_item_t*) malloc(sizeof(*item));
+  if (item == NULL)
+    uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+
+  memcpy(&item->socket_info, info, sizeof(item->socket_info));
+  item->tcp_connection = tcp_connection;
+  QUEUE_INSERT_TAIL(&handle->pending_ipc_info.queue, &item->member);
+  handle->pending_ipc_info.queue_len++;
+}
+
+
 void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
     uv_req_t* req) {
   DWORD bytes, avail;
@@ -1426,16 +1464,10 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
             assert(bytes == sizeof(ipc_frame) - sizeof(ipc_frame.header));
 
             /* Store the pending socket info. */
-            assert(!handle->pending_ipc_info.socket_info);
-            handle->pending_ipc_info.socket_info =
-              (WSAPROTOCOL_INFOW*)malloc(sizeof(*(handle->pending_ipc_info.socket_info)));
-            if (!handle->pending_ipc_info.socket_info) {
-              uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
-            }
-
-            *(handle->pending_ipc_info.socket_info) = ipc_frame.socket_info;
-            handle->pending_ipc_info.tcp_connection =
-              ipc_frame.header.flags & UV_IPC_TCP_CONNECTION;
+            uv__pipe_insert_pending_socket(
+                handle,
+                &ipc_frame.socket_info,
+                ipc_frame.header.flags & UV_IPC_TCP_CONNECTION);
           }
 
           if (ipc_frame.header.flags & UV_IPC_RAW_DATA) {
@@ -1450,11 +1482,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
 
       handle->alloc_cb((uv_handle_t*) handle, avail, &buf);
       if (buf.len == 0) {
-        if (handle->read2_cb) {
-          handle->read2_cb(handle, UV_ENOBUFS, &buf, UV_UNKNOWN_HANDLE);
-        } else if (handle->read_cb) {
-          handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
-        }
+        handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
         break;
       }
       assert(buf.base != NULL);
@@ -1469,20 +1497,8 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
           assert(handle->remaining_ipc_rawdata_bytes >= bytes);
           handle->remaining_ipc_rawdata_bytes =
             handle->remaining_ipc_rawdata_bytes - bytes;
-          if (handle->read2_cb) {
-            handle->read2_cb(handle, bytes, &buf,
-              handle->pending_ipc_info.socket_info ? UV_TCP : UV_UNKNOWN_HANDLE);
-          } else if (handle->read_cb) {
-            handle->read_cb((uv_stream_t*)handle, bytes, &buf);
-          }
-
-          if (handle->pending_ipc_info.socket_info) {
-            free(handle->pending_ipc_info.socket_info);
-            handle->pending_ipc_info.socket_info = NULL;
-          }
-        } else {
-          handle->read_cb((uv_stream_t*)handle, bytes, &buf);
         }
+        handle->read_cb((uv_stream_t*)handle, bytes, &buf);
 
         /* Read again only if bytes == buf.len */
         if (bytes <= buf.len) {
@@ -1859,3 +1875,20 @@ error:
   free(name_info);
   return err;
 }
+
+
+int uv_pipe_pending_count(uv_pipe_t* handle) {
+  if (!handle->ipc)
+    return 0;
+  return handle->pending_ipc_info.queue_len;
+}
+
+
+uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
+  if (!handle->ipc)
+    return UV_UNKNOWN_HANDLE;
+  if (handle->pending_ipc_info.queue_len == 0)
+    return UV_UNKNOWN_HANDLE;
+  else
+    return UV_TCP;
+}
index 75351af..1786c40 100644 (file)
@@ -85,6 +85,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
     handle->mask_events_2 = 0;
   } else {
     assert(0);
+    return;
   }
 
   /* Setting Exclusive to TRUE makes the other poll request return if there */
@@ -119,7 +120,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
 
 static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
   AFD_POLL_INFO afd_poll_info;
-  DWORD result;
+  int result;
 
   afd_poll_info.Exclusive = TRUE;
   afd_poll_info.NumberOfHandles = 1;
@@ -158,6 +159,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
     mask_events = handle->mask_events_2;
   } else {
     assert(0);
+    return;
   }
 
   /* Report an error unless the select was just interrupted. */
@@ -281,7 +283,7 @@ static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
   SOCKET peer_socket;
 
   index = -1;
-  for (i = 0; i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
+  for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
     if (memcmp((void*) &protocol_info->ProviderId,
                (void*) &uv_msafd_provider_ids[i],
                sizeof protocol_info->ProviderId) == 0) {
@@ -392,6 +394,7 @@ static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
     handle->mask_events_2 = 0;
   } else {
     assert(0);
+    return;
   }
 
   if (!QueueUserWorkItem(uv__slow_poll_thread_proc,
@@ -418,6 +421,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
     mask_events = handle->mask_events_2;
   } else {
     assert(0);
+    return;
   }
 
   if (!REQ_SUCCESS(req)) {
index 5757764..98566da 100644 (file)
@@ -327,7 +327,7 @@ int uv__stdio_create(uv_loop_t* loop,
         /* an uv_pipe_t for use by the parent. The other one is given to */
         /* the child. */
         uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
-        HANDLE child_pipe;
+        HANDLE child_pipe = INVALID_HANDLE_VALUE;
 
         /* Create a new, connected pipe pair. stdio[i].stream should point */
         /* to an uninitialized, but not connected pipe handle. */
@@ -389,6 +389,7 @@ int uv__stdio_create(uv_loop_t* loop,
 
           default:
             assert(0);
+            return -1;
         }
 
         CHILD_STDIO_HANDLE(buffer, i) = child_handle;
@@ -423,11 +424,9 @@ int uv__stdio_create(uv_loop_t* loop,
         }
 
         /* Make an inheritable copy of the handle. */
-        if (uv__duplicate_handle(loop,
-                             stream_handle,
-                             &child_handle) < 0) {
+        err = uv__duplicate_handle(loop, stream_handle, &child_handle);
+        if (err)
           goto error;
-        }
 
         CHILD_STDIO_HANDLE(buffer, i) = child_handle;
         CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
@@ -436,6 +435,7 @@ int uv__stdio_create(uv_loop_t* loop,
 
       default:
         assert(0);
+        return -1;
     }
   }
 
index 88a1419..9d5144d 100644 (file)
@@ -624,7 +624,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
   char** env;
   size_t env_len = 1; /* room for closing null */
   int len;
-  int i;
+  size_t i;
   DWORD var_size;
 
   env_var_t required_vars[] = {
index 9dc5fcc..fc489f6 100644 (file)
@@ -78,7 +78,8 @@ int uv__signal_dispatch(int signum) {
   for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
        handle != NULL && handle->signum == signum;
        handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
-    unsigned long previous = InterlockedExchange(&handle->pending_signum, signum);
+    unsigned long previous = InterlockedExchange(
+            (volatile LONG*) &handle->pending_signum, signum);
 
     if (!previous) {
       POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
@@ -307,12 +308,13 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
 
 void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
     uv_req_t* req) {
-  unsigned long dispatched_signum;
+  long dispatched_signum;
 
   assert(handle->type == UV_SIGNAL);
   assert(req->type == UV_SIGNAL_REQ);
 
-  dispatched_signum = InterlockedExchange(&handle->pending_signum, 0);
+  dispatched_signum = InterlockedExchange(
+          (volatile LONG*) &handle->pending_signum, 0);
   assert(dispatched_signum != 0);
 
   /* Check if the pending signal equals the signum that we are watching for. */
index 0abca3a..6553ab1 100644 (file)
@@ -96,31 +96,6 @@ int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
 }
 
 
-int uv_read2_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
-    uv_read2_cb read_cb) {
-  int err;
-
-  if (handle->flags & UV_HANDLE_READING) {
-    return UV_EALREADY;
-  }
-
-  if (!(handle->flags & UV_HANDLE_READABLE)) {
-    return UV_ENOTCONN;
-  }
-
-  err = ERROR_INVALID_PARAMETER;
-  switch (handle->type) {
-    case UV_NAMED_PIPE:
-      err = uv_pipe_read2_start((uv_pipe_t*)handle, alloc_cb, read_cb);
-      break;
-    default:
-      assert(0);
-  }
-
-  return uv_translate_sys_error(err);
-}
-
-
 int uv_read_stop(uv_stream_t* handle) {
   int err;
 
index f77db3b..d3df3ae 100644 (file)
@@ -1099,9 +1099,9 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
     int tcp_connection) {
   int err;
 
-  SOCKET socket = WSASocketW(AF_INET,
-                             SOCK_STREAM,
-                             IPPROTO_IP,
+  SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO,
+                             FROM_PROTOCOL_INFO,
+                             FROM_PROTOCOL_INFO,
                              socket_protocol_info,
                              0,
                              WSA_FLAG_OVERLAPPED);
index 8855af3..1b17cb7 100644 (file)
@@ -698,7 +698,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
         buf.base[buf_used++] = handle->last_key[handle->last_key_offset++];
 
         /* If the buffer is full, emit it */
-        if (buf_used == buf.len) {
+        if ((size_t) buf_used == buf.len) {
           handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
           buf = uv_null_buf_;
           buf_used = 0;
index c9ca773..32a82fa 100644 (file)
@@ -163,12 +163,12 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
 }
 
 
-int uv_cwd(char* buffer, size_t size) {
+int uv_cwd(char* buffer, size_t* size) {
   DWORD utf16_len;
   WCHAR utf16_buffer[MAX_PATH];
   int r;
 
-  if (buffer == NULL || size == 0) {
+  if (buffer == NULL || size == NULL) {
     return UV_EINVAL;
   }
 
@@ -192,19 +192,36 @@ int uv_cwd(char* buffer, size_t size) {
     utf16_buffer[utf16_len] = L'\0';
   }
 
+  /* Check how much space we need */
+  r = WideCharToMultiByte(CP_UTF8,
+                          0,
+                          utf16_buffer,
+                          -1,
+                          NULL,
+                          0,
+                          NULL,
+                          NULL);
+  if (r == 0) {
+    return uv_translate_sys_error(GetLastError());
+  } else if (r > (int) *size) {
+    *size = r;
+    return UV_ENOBUFS;
+  }
+
   /* Convert to UTF-8 */
   r = WideCharToMultiByte(CP_UTF8,
                           0,
                           utf16_buffer,
                           -1,
                           buffer,
-                          size > INT_MAX ? INT_MAX : (int) size,
+                          *size > INT_MAX ? INT_MAX : (int) *size,
                           NULL,
                           NULL);
   if (r == 0) {
     return uv_translate_sys_error(GetLastError());
   }
 
+  *size = r;
   return 0;
 }
 
@@ -323,7 +340,7 @@ int uv_parent_pid() {
   int parent_pid = -1;
   HANDLE handle;
   PROCESSENTRY32 pe;
-  int current_pid = GetCurrentProcessId();
+  DWORD current_pid = GetCurrentProcessId();
 
   pe.dwSize = sizeof(PROCESSENTRY32);
   handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
@@ -638,7 +655,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
     DWORD cpu_speed_size = sizeof(cpu_speed);
     WCHAR cpu_brand[256];
     DWORD cpu_brand_size = sizeof(cpu_brand);
-    int len;
+    size_t len;
 
     len = _snwprintf(key_name,
                      ARRAY_SIZE(key_name),
index 938b6d0..3711ee9 100644 (file)
@@ -40,7 +40,8 @@ struct sockaddr_in6 uv_addr_ip6_any_;
  */
 static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
     void **target) {
-  DWORD result, bytes;
+  int result;
+  DWORD bytes;
 
   result = WSAIoctl(socket,
                     SIO_GET_EXTENSION_FUNCTION_POINTER,
@@ -166,13 +167,12 @@ int uv_ntstatus_to_winsock_error(NTSTATUS status) {
     case STATUS_COMMITMENT_LIMIT:
     case STATUS_WORKING_SET_QUOTA:
     case STATUS_NO_MEMORY:
-    case STATUS_CONFLICTING_ADDRESSES:
     case STATUS_QUOTA_EXCEEDED:
     case STATUS_TOO_MANY_PAGING_FILES:
     case STATUS_REMOTE_RESOURCES:
-    case STATUS_TOO_MANY_ADDRESSES:
       return WSAENOBUFS;
 
+    case STATUS_TOO_MANY_ADDRESSES:
     case STATUS_SHARING_VIOLATION:
     case STATUS_ADDRESS_ALREADY_EXISTS:
       return WSAEADDRINUSE;
@@ -241,6 +241,7 @@ int uv_ntstatus_to_winsock_error(NTSTATUS status) {
     case STATUS_PIPE_DISCONNECTED:
       return WSAESHUTDOWN;
 
+    case STATUS_CONFLICTING_ADDRESSES:
     case STATUS_INVALID_ADDRESS:
     case STATUS_INVALID_ADDRESS_COMPONENT:
       return WSAEADDRNOTAVAIL;
index b1b0c1e..da0c76d 100644 (file)
@@ -83,10 +83,9 @@ static void ipc_connection_cb(uv_stream_t* ipc_pipe, int status);
 static void ipc_write_cb(uv_write_t* req, int status);
 static void ipc_close_cb(uv_handle_t* handle);
 static void ipc_connect_cb(uv_connect_t* req, int status);
-static void ipc_read2_cb(uv_pipe_t* ipc_pipe,
-                         ssize_t nread,
-                         const uv_buf_t* buf,
-                         uv_handle_type type);
+static void ipc_read_cb(uv_stream_t* handle,
+                        ssize_t nread,
+                        const uv_buf_t* buf);
 static void ipc_alloc_cb(uv_handle_t* handle,
                          size_t suggested_size,
                          uv_buf_t* buf);
@@ -155,9 +154,9 @@ static void ipc_connect_cb(uv_connect_t* req, int status) {
   struct ipc_client_ctx* ctx;
   ctx = container_of(req, struct ipc_client_ctx, connect_req);
   ASSERT(0 == status);
-  ASSERT(0 == uv_read2_start((uv_stream_t*) &ctx->ipc_pipe,
-                             ipc_alloc_cb,
-                             ipc_read2_cb));
+  ASSERT(0 == uv_read_start((uv_stream_t*) &ctx->ipc_pipe,
+                            ipc_alloc_cb,
+                            ipc_read_cb));
 }
 
 
@@ -171,16 +170,20 @@ static void ipc_alloc_cb(uv_handle_t* handle,
 }
 
 
-static void ipc_read2_cb(uv_pipe_t* ipc_pipe,
-                         ssize_t nread,
-                         const uv_buf_t* buf,
-                         uv_handle_type type) {
+static void ipc_read_cb(uv_stream_t* handle,
+                        ssize_t nread,
+                        const uv_buf_t* buf) {
   struct ipc_client_ctx* ctx;
   uv_loop_t* loop;
+  uv_handle_type type;
+  uv_pipe_t* ipc_pipe;
 
+  ipc_pipe = (uv_pipe_t*) handle;
   ctx = container_of(ipc_pipe, struct ipc_client_ctx, ipc_pipe);
   loop = ipc_pipe->loop;
 
+  ASSERT(1 == uv_pipe_pending_count(ipc_pipe));
+  type = uv_pipe_pending_type(ipc_pipe);
   if (type == UV_TCP)
     ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) ctx->server_handle));
   else if (type == UV_NAMED_PIPE)
@@ -188,7 +191,7 @@ static void ipc_read2_cb(uv_pipe_t* ipc_pipe,
   else
     ASSERT(0);
 
-  ASSERT(0 == uv_accept((uv_stream_t*) &ctx->ipc_pipe, ctx->server_handle));
+  ASSERT(0 == uv_accept(handle, ctx->server_handle));
   uv_close((uv_handle_t*) &ctx->ipc_pipe, NULL);
 }
 
index 3b786a8..e890c77 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef TASK_H_
 #define TASK_H_
 
+#include "uv.h"
+
 #include <stdio.h>
 #include <stddef.h>
 #include <stdlib.h>
@@ -112,8 +114,11 @@ typedef enum {
 /* This macro cleans up the main loop. This is used to avoid valgrind
  * warnings about memory being "leaked" by the main event loop.
  */
-#define MAKE_VALGRIND_HAPPY()  \
-  uv_loop_delete(uv_default_loop())
+#define MAKE_VALGRIND_HAPPY()           \
+  do {                                  \
+    close_loop(uv_default_loop());      \
+    uv_loop_delete(uv_default_loop());  \
+  } while (0)
 
 /* Just sugar for wrapping the main() for a task or helper. */
 #define TEST_IMPL(name)                                                       \
@@ -204,4 +209,24 @@ static int snprintf(char* buf, size_t len, const char* fmt, ...) {
 
 #endif
 
+#if defined(__clang__) ||                                \
+    defined(__GNUC__) ||                                 \
+    defined(__INTEL_COMPILER) ||                         \
+    defined(__SUNPRO_C)
+# define UNUSED __attribute__((unused))
+#else
+# define UNUSED
+#endif
+
+/* Fully close a loop */
+static void close_walk_cb(uv_handle_t* handle, void* arg) {
+  if (!uv_is_closing(handle))
+    uv_close(handle, NULL);
+}
+
+UNUSED static void close_loop(uv_loop_t* loop) {
+  uv_walk(loop, close_walk_cb, NULL);
+  uv_run(loop, UV_RUN_DEFAULT);
+}
+
 #endif /* TASK_H_ */
index f1082ac..6f61731 100644 (file)
@@ -33,8 +33,8 @@ TEST_IMPL(cwd_and_chdir) {
   char* last_slash;
   int err;
 
-  size = sizeof(buffer_orig) / sizeof(buffer_orig[0]);
-  err = uv_cwd(buffer_orig, size);
+  size = sizeof(buffer_orig);
+  err = uv_cwd(buffer_orig, &size);
   ASSERT(err == 0);
 
   /* Remove trailing slash unless at a root directory. */
@@ -55,7 +55,7 @@ TEST_IMPL(cwd_and_chdir) {
   err = uv_chdir(buffer_orig);
   ASSERT(err == 0);
 
-  err = uv_cwd(buffer_new, size);
+  err = uv_cwd(buffer_new, &size);
   ASSERT(err == 0);
 
   ASSERT(strcmp(buffer_orig, buffer_new) == 0);
index 940672f..306ec6b 100644 (file)
@@ -1465,8 +1465,10 @@ TEST_IMPL(fs_symlink_dir) {
 #ifdef _WIN32
   {
     static char src_path_buf[PATHMAX];
+    size_t size;
+    size = sizeof(src_path_buf);
     strcpy(src_path_buf, "\\\\?\\");
-    uv_cwd(src_path_buf + 4, sizeof(src_path_buf));
+    uv_cwd(src_path_buf + 4, &size);
     strcat(src_path_buf, "\\test_dir\\");
     test_dir = src_path_buf;
   }
index b2b5aa0..d9b9133 100644 (file)
@@ -60,15 +60,20 @@ static void alloc_cb(uv_handle_t* handle,
 }
 
 
-static void recv_cb(uv_pipe_t* handle,
+static void recv_cb(uv_stream_t* handle,
                     ssize_t nread,
-                    const uv_buf_t* buf,
-                    uv_handle_type pending) {
+                    const uv_buf_t* buf) {
+  uv_handle_type pending;
+  uv_pipe_t* pipe;
   int r;
 
-  ASSERT(pending == ctx.expected_type);
-  ASSERT(handle == &ctx.channel);
+  pipe = (uv_pipe_t*) handle;
+  ASSERT(pipe == &ctx.channel);
   ASSERT(nread >= 0);
+  ASSERT(1 == uv_pipe_pending_count(pipe));
+
+  pending = uv_pipe_pending_type(pipe);
+  ASSERT(pending == ctx.expected_type);
 
   if (pending == UV_NAMED_PIPE)
     r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0);
@@ -78,7 +83,7 @@ static void recv_cb(uv_pipe_t* handle,
     abort();
   ASSERT(r == 0);
 
-  r = uv_accept((uv_stream_t*)&ctx.channel, &ctx.recv.stream);
+  r = uv_accept(handle, &ctx.recv.stream);
   ASSERT(r == 0);
 
   uv_close((uv_handle_t*)&ctx.channel, NULL);
@@ -103,7 +108,7 @@ static int run_test(void) {
                 NULL);
   ASSERT(r == 0);
 
-  r = uv_read2_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb);
+  r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb);
   ASSERT(r == 0);
 
   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
@@ -165,16 +170,21 @@ static void write2_cb(uv_write_t* req, int status) {
 }
 
 
-static void read2_cb(uv_pipe_t* handle,
-                     ssize_t nread,
-                     const uv_buf_t* rdbuf,
-                     uv_handle_type pending) {
+static void read_cb(uv_stream_t* handle,
+                    ssize_t nread,
+                    const uv_buf_t* rdbuf) {
   uv_buf_t wrbuf;
+  uv_pipe_t* pipe;
+  uv_handle_type pending;
   int r;
 
-  ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
-  ASSERT(handle == &ctx.channel);
+  pipe = (uv_pipe_t*) handle;
+  ASSERT(pipe == &ctx.channel);
   ASSERT(nread >= 0);
+  ASSERT(1 == uv_pipe_pending_count(pipe));
+
+  pending = uv_pipe_pending_type(pipe);
+  ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
 
   wrbuf = uv_buf_init(".", 1);
 
@@ -186,7 +196,7 @@ static void read2_cb(uv_pipe_t* handle,
     abort();
   ASSERT(r == 0);
 
-  r = uv_accept((uv_stream_t*)handle, &ctx.recv.stream);
+  r = uv_accept(handle, &ctx.recv.stream);
   ASSERT(r == 0);
 
   r = uv_write2(&ctx.write_req,
@@ -215,7 +225,7 @@ int ipc_send_recv_helper(void) {
   ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx.channel));
   ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx.channel));
 
-  r = uv_read2_start((uv_stream_t*)&ctx.channel, alloc_cb, read2_cb);
+  r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, read_cb);
   ASSERT(r == 0);
 
   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
index cc44d32..61b649b 100644 (file)
@@ -30,7 +30,7 @@ static uv_tcp_t tcp_server;
 static uv_tcp_t tcp_connection;
 
 static int exit_cb_called;
-static int read2_cb_called;
+static int read_cb_called;
 static int tcp_write_cb_called;
 static int tcp_read_cb_called;
 static int on_pipe_read_called;
@@ -138,13 +138,16 @@ static void make_many_connections(void) {
 }
 
 
-static void on_read(uv_pipe_t* pipe,
+static void on_read(uv_stream_t* handle,
                     ssize_t nread,
-                    const uv_buf_t* buf,
-                    uv_handle_type pending) {
+                    const uv_buf_t* buf) {
   int r;
+  uv_pipe_t* pipe;
+  uv_handle_type pending;
   uv_buf_t outbuf;
 
+  pipe = (uv_pipe_t*) handle;
+
   if (nread == 0) {
     /* Everything OK, but nothing read. */
     free(buf->base);
@@ -163,9 +166,11 @@ static void on_read(uv_pipe_t* pipe,
 
   fprintf(stderr, "got %d bytes\n", (int)nread);
 
+  pending = uv_pipe_pending_type(pipe);
   if (!tcp_server_listening) {
+    ASSERT(1 == uv_pipe_pending_count(pipe));
     ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
-    read2_cb_called++;
+    read_cb_called++;
 
     /* Accept the pending TCP server, and start listening on it. */
     ASSERT(pending == UV_TCP);
@@ -191,6 +196,7 @@ static void on_read(uv_pipe_t* pipe,
     make_many_connections();
   } else if (memcmp("accepted_connection\n", buf->base, nread) == 0) {
     /* Remote server has accepted a connection.  Close the channel. */
+    ASSERT(0 == uv_pipe_pending_count(pipe));
     ASSERT(pending == UV_UNKNOWN_HANDLE);
     remote_conn_accepted = 1;
     uv_close((uv_handle_t*)&channel, NULL);
@@ -267,13 +273,15 @@ static void on_tcp_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
 }
 
 
-static void on_read_connection(uv_pipe_t* pipe,
+static void on_read_connection(uv_stream_t* handle,
                                ssize_t nread,
-                               const uv_buf_t* buf,
-                               uv_handle_type pending) {
+                               const uv_buf_t* buf) {
   int r;
   uv_buf_t outbuf;
+  uv_pipe_t* pipe;
+  uv_handle_type pending;
 
+  pipe = (uv_pipe_t*) handle;
   if (nread == 0) {
     /* Everything OK, but nothing read. */
     free(buf->base);
@@ -292,15 +300,18 @@ static void on_read_connection(uv_pipe_t* pipe,
 
   fprintf(stderr, "got %d bytes\n", (int)nread);
 
+  ASSERT(1 == uv_pipe_pending_count(pipe));
+  pending = uv_pipe_pending_type(pipe);
+
   ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
-  read2_cb_called++;
+  read_cb_called++;
 
   /* Accept the pending TCP connection */
   ASSERT(pending == UV_TCP);
   r = uv_tcp_init(uv_default_loop(), &tcp_connection);
   ASSERT(r == 0);
 
-  r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_connection);
+  r = uv_accept(handle, (uv_stream_t*)&tcp_connection);
   ASSERT(r == 0);
 
   /* Make sure that the expected data is correctly multiplexed. */
@@ -319,12 +330,12 @@ static void on_read_connection(uv_pipe_t* pipe,
 }
 
 
-static int run_ipc_test(const char* helper, uv_read2_cb read_cb) {
+static int run_ipc_test(const char* helper, uv_read_cb read_cb) {
   uv_process_t process;
   int r;
 
   spawn_helper(&channel, &process, helper);
-  uv_read2_start((uv_stream_t*)&channel, on_alloc, read_cb);
+  uv_read_start((uv_stream_t*)&channel, on_alloc, read_cb);
 
   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
   ASSERT(r == 0);
@@ -338,7 +349,7 @@ TEST_IMPL(ipc_listen_before_write) {
   int r = run_ipc_test("ipc_helper_listen_before_write", on_read);
   ASSERT(local_conn_accepted == 1);
   ASSERT(remote_conn_accepted == 1);
-  ASSERT(read2_cb_called == 1);
+  ASSERT(read_cb_called == 1);
   ASSERT(exit_cb_called == 1);
   return r;
 }
@@ -348,7 +359,7 @@ TEST_IMPL(ipc_listen_after_write) {
   int r = run_ipc_test("ipc_helper_listen_after_write", on_read);
   ASSERT(local_conn_accepted == 1);
   ASSERT(remote_conn_accepted == 1);
-  ASSERT(read2_cb_called == 1);
+  ASSERT(read_cb_called == 1);
   ASSERT(exit_cb_called == 1);
   return r;
 }
@@ -356,7 +367,7 @@ TEST_IMPL(ipc_listen_after_write) {
 
 TEST_IMPL(ipc_tcp_connection) {
   int r = run_ipc_test("ipc_helper_tcp_connection", on_read_connection);
-  ASSERT(read2_cb_called == 1);
+  ASSERT(read_cb_called == 1);
   ASSERT(tcp_write_cb_called == 1);
   ASSERT(tcp_read_cb_called == 1);
   ASSERT(exit_cb_called == 1);
index 0252acc..345df51 100644 (file)
@@ -96,6 +96,7 @@ TEST_DECLARE   (pipe_connect_bad_name)
 TEST_DECLARE   (pipe_connect_to_file)
 TEST_DECLARE   (pipe_getsockname)
 TEST_DECLARE   (pipe_getsockname_abstract)
+TEST_DECLARE   (pipe_sendmsg)
 TEST_DECLARE   (pipe_server_close)
 TEST_DECLARE   (connection_fail)
 TEST_DECLARE   (connection_fail_doesnt_auto_close)
@@ -362,6 +363,7 @@ TASK_LIST_START
   TEST_ENTRY  (pipe_listen_without_bind)
   TEST_ENTRY  (pipe_getsockname)
   TEST_ENTRY  (pipe_getsockname_abstract)
+  TEST_ENTRY  (pipe_sendmsg)
 
   TEST_ENTRY  (connection_fail)
   TEST_ENTRY  (connection_fail_doesnt_auto_close)
diff --git a/deps/uv/test/test-pipe-sendmsg.c b/deps/uv/test/test-pipe-sendmsg.c
new file mode 100644 (file)
index 0000000..f6d893b
--- /dev/null
@@ -0,0 +1,169 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+#ifndef _WIN32
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+
+/* NOTE: size should be divisible by 2 */
+static uv_pipe_t incoming[4];
+static unsigned int incoming_count;
+static unsigned int close_called;
+
+
+static void set_nonblocking(uv_os_sock_t sock) {
+  int r;
+#ifdef _WIN32
+  unsigned long on = 1;
+  r = ioctlsocket(sock, FIONBIO, &on);
+  ASSERT(r == 0);
+#else
+  int flags = fcntl(sock, F_GETFL, 0);
+  ASSERT(flags >= 0);
+  r = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+  ASSERT(r >= 0);
+#endif
+}
+
+
+
+
+static void close_cb(uv_handle_t* handle) {
+  close_called++;
+}
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+  static char base[1];
+
+  buf->base = base;
+  buf->len = sizeof(base);
+}
+
+
+static void read_cb(uv_stream_t* handle,
+                    ssize_t nread,
+                    const uv_buf_t* buf) {
+  uv_pipe_t* p;
+  uv_pipe_t* inc;
+  uv_handle_type pending;
+  unsigned int i;
+
+  p = (uv_pipe_t*) handle;
+  ASSERT(nread >= 0);
+
+  while (uv_pipe_pending_count(p) != 0) {
+    pending = uv_pipe_pending_type(p);
+    ASSERT(pending == UV_NAMED_PIPE);
+
+    ASSERT(incoming_count < ARRAY_SIZE(incoming));
+    inc = &incoming[incoming_count++];
+    ASSERT(0 == uv_pipe_init(p->loop, inc, 0));
+    ASSERT(0 == uv_accept(handle, (uv_stream_t*) inc));
+  }
+
+  if (incoming_count != ARRAY_SIZE(incoming))
+    return;
+
+  ASSERT(0 == uv_read_stop((uv_stream_t*) p));
+  uv_close((uv_handle_t*) p, close_cb);
+  for (i = 0; i < ARRAY_SIZE(incoming); i++)
+    uv_close((uv_handle_t*) &incoming[i], close_cb);
+}
+
+
+TEST_IMPL(pipe_sendmsg) {
+  uv_pipe_t p;
+  int r;
+  int fds[2];
+  int send_fds[ARRAY_SIZE(incoming)];
+  struct msghdr msg;
+  char scratch[64];
+  struct cmsghdr *cmsg;
+  unsigned int i;
+  uv_buf_t buf;
+
+  ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
+  for (i = 0; i < ARRAY_SIZE(send_fds); i += 2)
+    ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, send_fds + i));
+  ASSERT(i == ARRAY_SIZE(send_fds));
+  ASSERT(0 == uv_pipe_init(uv_default_loop(), &p, 1));
+  ASSERT(0 == uv_pipe_open(&p, fds[1]));
+
+  buf = uv_buf_init("X", 1);
+  memset(&msg, 0, sizeof(msg));
+  msg.msg_iov = (struct iovec*) &buf;
+  msg.msg_iovlen = 1;
+  msg.msg_flags = 0;
+
+  msg.msg_control = (void*) scratch;
+  msg.msg_controllen = CMSG_LEN(sizeof(send_fds));
+  ASSERT(sizeof(scratch) >= msg.msg_controllen);
+
+  cmsg = CMSG_FIRSTHDR(&msg);
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_RIGHTS;
+  cmsg->cmsg_len = msg.msg_controllen;
+
+  /* silence aliasing warning */
+  {
+    void* pv = CMSG_DATA(cmsg);
+    int* pi = pv;
+    for (i = 0; i < ARRAY_SIZE(send_fds); i++)
+      pi[i] = send_fds[i];
+  }
+
+  set_nonblocking(fds[1]);
+  ASSERT(0 == uv_read_start((uv_stream_t*) &p, alloc_cb, read_cb));
+
+  do
+    r = sendmsg(fds[0], &msg, 0);
+  while (r == -1 && errno == EINTR);
+  ASSERT(r == 1);
+
+  uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+  ASSERT(ARRAY_SIZE(incoming) == incoming_count);
+  ASSERT(ARRAY_SIZE(incoming) + 1 == close_called);
+  close(fds[0]);
+
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
+
+#else  /* !_WIN32 */
+
+TEST_IMPL(pipe_sendmsg) {
+  MAKE_VALGRIND_HAPPY();
+  return 0;
+}
+
+#endif  /* _WIN32 */
index d84755a..ddf303e 100644 (file)
         'test/test-pipe-bind-error.c',
         'test/test-pipe-connect-error.c',
         'test/test-pipe-getsockname.c',
+        'test/test-pipe-sendmsg.c',
         'test/test-pipe-server-close.c',
         'test/test-platform-output.c',
         'test/test-poll.c',