From e92d35d80be6e193cb547e94c6fbf3654542dbaa Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Mon, 10 Mar 2014 17:01:21 -0700 Subject: [PATCH] uv: Upgrade to v0.11.22 --- deps/uv/AUTHORS | 7 + deps/uv/ChangeLog | 47 +++++- deps/uv/Makefile.am | 1 + deps/uv/Makefile.mingw | 9 +- deps/uv/checksparse.sh | 1 + deps/uv/configure.ac | 6 +- deps/uv/include/pthread-fixes.h | 13 ++ deps/uv/include/uv-errno.h | 6 + deps/uv/include/uv-unix.h | 1 + deps/uv/include/uv-version.h | 2 +- deps/uv/include/uv-win.h | 5 +- deps/uv/include/uv.h | 31 ++-- deps/uv/libuv.pc.in | 2 +- deps/uv/src/unix/core.c | 111 ++++++++++++- deps/uv/src/unix/fs.c | 4 + deps/uv/src/unix/internal.h | 12 ++ deps/uv/src/unix/kqueue.c | 6 +- deps/uv/src/unix/linux-syscalls.c | 21 +++ deps/uv/src/unix/linux-syscalls.h | 1 + deps/uv/src/unix/pipe.c | 28 ++++ deps/uv/src/unix/process.c | 7 +- deps/uv/src/unix/pthread-fixes.c | 23 +++ deps/uv/src/unix/stream.c | 290 +++++++++++++++++++--------------- deps/uv/src/unix/tty.c | 65 ++++++-- deps/uv/src/win/core.c | 4 +- deps/uv/src/win/fs.c | 18 ++- deps/uv/src/win/internal.h | 4 +- deps/uv/src/win/pipe.c | 163 +++++++++++-------- deps/uv/src/win/poll.c | 8 +- deps/uv/src/win/process-stdio.c | 10 +- deps/uv/src/win/process.c | 2 +- deps/uv/src/win/signal.c | 8 +- deps/uv/src/win/stream.c | 25 --- deps/uv/src/win/tcp.c | 6 +- deps/uv/src/win/tty.c | 2 +- deps/uv/src/win/util.c | 27 +++- deps/uv/src/win/winsock.c | 7 +- deps/uv/test/benchmark-multi-accept.c | 27 ++-- deps/uv/test/task.h | 29 +++- deps/uv/test/test-cwd-and-chdir.c | 6 +- deps/uv/test/test-fs.c | 4 +- deps/uv/test/test-ipc-send-recv.c | 40 +++-- deps/uv/test/test-ipc.c | 41 +++-- deps/uv/test/test-list.h | 2 + deps/uv/test/test-pipe-sendmsg.c | 169 ++++++++++++++++++++ deps/uv/uv.gyp | 1 + 46 files changed, 943 insertions(+), 359 deletions(-) create mode 100644 deps/uv/test/test-pipe-sendmsg.c diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index b6ea578..7836488 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -124,3 +124,10 @@ William Light Oleg Efimov Lars Gierth rcp +Alexis Campailla +StarWing +thierry-FreeBSD +Isaiah Norton +Raul Martins +David Capello +Paul Tan diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index a37b0e4..3536abb 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -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: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 75ec751..3aa40c6 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -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 \ diff --git a/deps/uv/Makefile.mingw b/deps/uv/Makefile.mingw index b424f90..af84c75 100644 --- a/deps/uv/Makefile.mingw +++ b/deps/uv/Makefile.mingw @@ -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 $@ $< diff --git a/deps/uv/checksparse.sh b/deps/uv/checksparse.sh index 54cd580..d2dc3a5 100755 --- a/deps/uv/checksparse.sh +++ b/deps/uv/checksparse.sh @@ -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 diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 2b6eadf..8c928a5 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -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]) diff --git a/deps/uv/include/pthread-fixes.h b/deps/uv/include/pthread-fixes.h index 230ce31..88c6b66 100644 --- a/deps/uv/include/pthread-fixes.h +++ b/deps/uv/include/pthread-fixes.h @@ -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 */ diff --git a/deps/uv/include/uv-errno.h b/deps/uv/include/uv-errno.h index 466cdf2..3b6834f 100644 --- a/deps/uv/include/uv-errno.h +++ b/deps/uv/include/uv-errno.h @@ -394,4 +394,10 @@ # define UV__ERANGE (-4034) #endif +#if defined(ENXIO) && !defined(_WIN32) +# define UV__ENXIO (-ENXIO) +#else +# define UV__ENXIO (-4033) +#endif + #endif /* UV_ERRNO_H_ */ diff --git a/deps/uv/include/uv-unix.h b/deps/uv/include/uv-unix.h index eea5a3f..b150905 100644 --- a/deps/uv/include/uv-unix.h +++ b/deps/uv/include/uv-unix.h @@ -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 */ diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index e48082f..e4ebf24 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -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 */ diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv-win.h index db8f861..c254280 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv-win.h @@ -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; diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 49c2a43..7886e62 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -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); diff --git a/deps/uv/libuv.pc.in b/deps/uv/libuv.pc.in index 86c1a12..2933ec2 100644 --- a/deps/uv/libuv.pc.in +++ b/deps/uv/libuv.pc.in @@ -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} diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index a843044..b393097 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -59,6 +59,15 @@ # include # include # include +# 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; + } +} diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index b06f992..cf45669 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -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; } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 4a4656a..61f5f6a 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -120,6 +120,8 @@ # 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); diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 5a25e11..7706417 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -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; diff --git a/deps/uv/src/unix/linux-syscalls.c b/deps/uv/src/unix/linux-syscalls.c index c9cc44d..1ff8abd 100644 --- a/deps/uv/src/unix/linux-syscalls.c +++ b/deps/uv/src/unix/linux-syscalls.c @@ -219,6 +219,16 @@ # 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 +} diff --git a/deps/uv/src/unix/linux-syscalls.h b/deps/uv/src/unix/linux-syscalls.h index 6d9ec9f..0f0b34b 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -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_ */ diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index 34c118b..a26c3db 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -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); +} diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 55f6ac5..53fef84 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -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); } diff --git a/deps/uv/src/unix/pthread-fixes.c b/deps/uv/src/unix/pthread-fixes.c index 2e4c542..dc54f35 100644 --- a/deps/uv/src/unix/pthread-fixes.c +++ b/deps/uv/src/unix/pthread-fixes.c @@ -29,6 +29,29 @@ 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 +#include + +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 diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index ad6856b..370894b 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -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)); } diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index ca9459d..c7ed101 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -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; } diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index 2e70276..f749ba9 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -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) diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index d997b0e..273ec39 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -97,8 +97,10 @@ #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 diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index cf6c858..82f8eb6 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -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); /* diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 69c5cde..b832a28 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -31,6 +31,17 @@ #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; +} diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c index 75351af..1786c40 100644 --- a/deps/uv/src/win/poll.c +++ b/deps/uv/src/win/poll.c @@ -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)) { diff --git a/deps/uv/src/win/process-stdio.c b/deps/uv/src/win/process-stdio.c index 5757764..98566da 100644 --- a/deps/uv/src/win/process-stdio.c +++ b/deps/uv/src/win/process-stdio.c @@ -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; } } diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 88a1419..9d5144d 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -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[] = { diff --git a/deps/uv/src/win/signal.c b/deps/uv/src/win/signal.c index 9dc5fcc..fc489f6 100644 --- a/deps/uv/src/win/signal.c +++ b/deps/uv/src/win/signal.c @@ -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. */ diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c index 0abca3a..6553ab1 100644 --- a/deps/uv/src/win/stream.c +++ b/deps/uv/src/win/stream.c @@ -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; diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index f77db3b..d3df3ae 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -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); diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 8855af3..1b17cb7 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -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; diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index c9ca773..32a82fa 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -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), diff --git a/deps/uv/src/win/winsock.c b/deps/uv/src/win/winsock.c index 938b6d0..3711ee9 100644 --- a/deps/uv/src/win/winsock.c +++ b/deps/uv/src/win/winsock.c @@ -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; diff --git a/deps/uv/test/benchmark-multi-accept.c b/deps/uv/test/benchmark-multi-accept.c index b1b0c1e..da0c76d 100644 --- a/deps/uv/test/benchmark-multi-accept.c +++ b/deps/uv/test/benchmark-multi-accept.c @@ -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); } diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h index 3b786a8..e890c77 100644 --- a/deps/uv/test/task.h +++ b/deps/uv/test/task.h @@ -22,6 +22,8 @@ #ifndef TASK_H_ #define TASK_H_ +#include "uv.h" + #include #include #include @@ -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_ */ diff --git a/deps/uv/test/test-cwd-and-chdir.c b/deps/uv/test/test-cwd-and-chdir.c index f1082ac..6f61731 100644 --- a/deps/uv/test/test-cwd-and-chdir.c +++ b/deps/uv/test/test-cwd-and-chdir.c @@ -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); diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 940672f..306ec6b 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -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; } diff --git a/deps/uv/test/test-ipc-send-recv.c b/deps/uv/test/test-ipc-send-recv.c index b2b5aa0..d9b9133 100644 --- a/deps/uv/test/test-ipc-send-recv.c +++ b/deps/uv/test/test-ipc-send-recv.c @@ -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); diff --git a/deps/uv/test/test-ipc.c b/deps/uv/test/test-ipc.c index cc44d32..61b649b 100644 --- a/deps/uv/test/test-ipc.c +++ b/deps/uv/test/test-ipc.c @@ -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); diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 0252acc..345df51 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -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 index 0000000..f6d893b --- /dev/null +++ b/deps/uv/test/test-pipe-sendmsg.c @@ -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 +#include +#include +#include +#include +#include +#include + + +/* 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 */ diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index d84755a..ddf303e 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -338,6 +338,7 @@ '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', -- 2.7.4