summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcjihrig <cjihrig@gmail.com>2021-02-13 13:03:10 -0500
committerAntoine du Hamel <duhamelantoine1995@gmail.com>2021-02-15 23:09:54 +0100
commit78d6e62fd07ad500f84f1dad8a2509be597dcfc1 (patch)
tree7fa9f0e433f77bd1e7de52e21652fcc03e9ed215
parent0f29587757a782973b0aeabdee255b79c30780a2 (diff)
downloadnode-new-78d6e62fd07ad500f84f1dad8a2509be597dcfc1.tar.gz
deps: upgrade to libuv 1.41.0
Notable changes: - The IBM i platform has been promoted to a Tier 2 platform. - libuv is now built with `-fno-strict-aliasing`, and recommends that projects using libuv do the same. - `uv_fs_mkdir()` now returns `UV_EINVAL` for invalid directory names on Windows. - `uv_uptime()` now returns the correct value on OpenVZ containers. - Windows 8 is the new minimum supported version of Windows. - Bind errors are now reported from `uv_tcp_connect()`. - The `uv_pipe()` function has been added. - The `uv_socketpair()` function has been added. - `uv_read_start()` error handling has been unified across Windows and Unix. PR-URL: https://github.com/nodejs/node/pull/37360 Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com> Reviewed-By: Richard Lau <rlau@redhat.com> Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
-rw-r--r--deps/uv/.mailmap2
-rw-r--r--deps/uv/AUTHORS13
-rw-r--r--deps/uv/CMakeLists.txt14
-rw-r--r--deps/uv/ChangeLog79
-rw-r--r--deps/uv/Makefile.am7
-rw-r--r--deps/uv/README.md10
-rw-r--r--deps/uv/SUPPORTED_PLATFORMS.md4
-rw-r--r--deps/uv/configure.ac3
-rw-r--r--deps/uv/docs/src/pipe.rst18
-rw-r--r--deps/uv/docs/src/poll.rst61
-rw-r--r--deps/uv/docs/src/process.rst12
-rw-r--r--deps/uv/docs/src/stream.rst5
-rw-r--r--deps/uv/docs/src/tcp.rst24
-rw-r--r--deps/uv/docs/src/udp.rst12
-rw-r--r--deps/uv/include/uv.h15
-rw-r--r--deps/uv/include/uv/version.h2
-rw-r--r--deps/uv/src/timer.c1
-rw-r--r--deps/uv/src/unix/async.c2
-rw-r--r--deps/uv/src/unix/bsd-ifaddrs.c6
-rw-r--r--deps/uv/src/unix/core.c5
-rw-r--r--deps/uv/src/unix/fs.c44
-rw-r--r--deps/uv/src/unix/internal.h6
-rw-r--r--deps/uv/src/unix/linux-core.c61
-rw-r--r--deps/uv/src/unix/linux-syscalls.c37
-rw-r--r--deps/uv/src/unix/linux-syscalls.h4
-rw-r--r--deps/uv/src/unix/pipe.c54
-rw-r--r--deps/uv/src/unix/poll.c9
-rw-r--r--deps/uv/src/unix/process.c64
-rw-r--r--deps/uv/src/unix/proctitle.c1
-rw-r--r--deps/uv/src/unix/signal.c2
-rw-r--r--deps/uv/src/unix/stream.c12
-rw-r--r--deps/uv/src/unix/tcp.c53
-rw-r--r--deps/uv/src/uv-common.c19
-rw-r--r--deps/uv/src/uv-common.h4
-rw-r--r--deps/uv/src/win/fs.c49
-rw-r--r--deps/uv/src/win/internal.h4
-rw-r--r--deps/uv/src/win/pipe.c228
-rw-r--r--deps/uv/src/win/process-stdio.c96
-rw-r--r--deps/uv/src/win/stream.c13
-rw-r--r--deps/uv/src/win/tcp.c143
-rw-r--r--deps/uv/test/benchmark-pump.c2
-rw-r--r--deps/uv/test/blackhole-server.c1
-rw-r--r--deps/uv/test/echo-server.c5
-rw-r--r--deps/uv/test/run-tests.c36
-rw-r--r--deps/uv/test/task.h40
-rw-r--r--deps/uv/test/test-close-fd.c30
-rw-r--r--deps/uv/test/test-error.c3
-rw-r--r--deps/uv/test/test-fs-copyfile.c3
-rw-r--r--deps/uv/test/test-fs-event.c3
-rw-r--r--deps/uv/test/test-fs-readdir.c3
-rw-r--r--deps/uv/test/test-fs.c150
-rw-r--r--deps/uv/test/test-getaddrinfo.c4
-rw-r--r--deps/uv/test/test-ipc.c7
-rw-r--r--deps/uv/test/test-list.h30
-rw-r--r--deps/uv/test/test-ping-pong.c221
-rw-r--r--deps/uv/test/test-pipe-connect-error.c3
-rw-r--r--deps/uv/test/test-pipe-getsockname.c8
-rw-r--r--deps/uv/test/test-pipe-set-non-blocking.c53
-rw-r--r--deps/uv/test/test-platform-output.c1
-rw-r--r--deps/uv/test/test-poll-multiple-handles.c99
-rw-r--r--deps/uv/test/test-shutdown-eof.c8
-rw-r--r--deps/uv/test/test-spawn.c124
-rw-r--r--deps/uv/test/test-tcp-bind-error.c49
-rw-r--r--deps/uv/test/test-tcp-connect-timeout.c2
-rw-r--r--deps/uv/test/test-tty.c3
-rw-r--r--deps/uv/test/test-udp-connect.c2
-rw-r--r--deps/uv/tools/make_dist_html.py8
67 files changed, 1520 insertions, 576 deletions
diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap
index 56a80f586b..045b7702d9 100644
--- a/deps/uv/.mailmap
+++ b/deps/uv/.mailmap
@@ -32,6 +32,7 @@ Nicholas Vavilov <vvnicholas@gmail.com>
Nick Logan <ugexe@cpan.org> <nlogan@gmail.com>
Rasmus Christian Pedersen <zerhacken@yahoo.com>
Rasmus Christian Pedersen <zerhacken@yahoo.com> <ruysch@outlook.com>
+Richard Lau <rlau@redhat.com> <riclau@uk.ibm.com>
Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org>
Ryan Dahl <ryan@joyent.com> <ry@tinyclouds.org>
Ryan Emery <seebees@gmail.com>
@@ -47,6 +48,7 @@ Timothy J. Fontaine <tjfontaine@gmail.com>
Yasuhiro Matsumoto <mattn.jp@gmail.com>
Yazhong Liu <yorkiefixer@gmail.com>
Yuki Okumura <mjt@cltn.org>
+cjihrig <cjihrig@gmail.com>
gengjiawen <technicalcute@gmail.com>
jBarz <jBarz@users.noreply.github.com> <jbarboza@ca.ibm.com>
jBarz <jBarz@users.noreply.github.com> <jbarz@users.noreply.github.com>
diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS
index e7c789cfd1..9f327af9f8 100644
--- a/deps/uv/AUTHORS
+++ b/deps/uv/AUTHORS
@@ -212,7 +212,7 @@ guworks <ground.up.works@gmail.com>
RossBencina <rossb@audiomulch.com>
Roger A. Light <roger@atchoo.org>
chenttuuvv <chenttuuvv@yahoo.com>
-Richard Lau <riclau@uk.ibm.com>
+Richard Lau <rlau@redhat.com>
ronkorving <rkorving@wizcorp.jp>
Corbin Simpson <MostAwesomeDude@gmail.com>
Zachary Hamm <zsh@imipolexg.org>
@@ -448,3 +448,14 @@ Aleksej Lebedev <root@zta.lk>
Nikolay Mitev <github@hmel.org>
Ulrik Strid <ulrik.strid@outlook.com>
Elad Lahav <elahav@qnx.com>
+Elad Nachmias <eladn@pazam.net>
+Darshan Sen <raisinten@gmail.com>
+Simon Kadisch <simon.kadisch@k13-engineering.at>
+Momtchil Momtchev <momtchil@momtchev.com>
+Ethel Weston <66453757+ethelweston@users.noreply.github.com>
+Drew DeVault <sir@cmpwn.com>
+Mark Klein <klein@cscs.ch>
+schamberg97 <50446906+schamberg97@users.noreply.github.com>
+Bob Weinand <bobwei9@hotmail.com>
+Issam E. Maghni <issam.e.maghni@mailbox.org>
+Juan Pablo Canepa <jpcanepa@gmail.com>
diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt
index e648b00be6..c8e881d18f 100644
--- a/deps/uv/CMakeLists.txt
+++ b/deps/uv/CMakeLists.txt
@@ -30,6 +30,13 @@ if(QEMU)
add_definitions(-D__QEMU__=1)
endif()
+option(ASAN "Enable AddressSanitizer (ASan)" OFF)
+if(ASAN AND CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang")
+ add_definitions(-D__ASAN__=1)
+ set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
+ set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address")
+endif()
+
# Compiler check
string(CONCAT is-msvc $<OR:
$<C_COMPILER_ID:MSVC>,
@@ -95,6 +102,9 @@ list(APPEND uv_cflags ${lint-no-conditional-assignment-msvc})
list(APPEND uv_cflags ${lint-no-unsafe-msvc})
list(APPEND uv_cflags ${lint-utf8-msvc} )
+check_c_compiler_flag(-fno-strict-aliasing UV_F_STRICT_ALIASING)
+list(APPEND uv_cflags $<$<BOOL:${UV_F_STRICT_ALIASING}>:-fno-strict-aliasing>)
+
set(uv_sources
src/fs-poll.c
src/idna.c
@@ -108,7 +118,7 @@ set(uv_sources
src/version.c)
if(WIN32)
- list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0600)
+ list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602)
list(APPEND uv_libraries
psapi
user32
@@ -318,7 +328,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "QNX")
src/unix/bsd-ifaddrs.c
src/unix/no-proctitle.c
src/unix/no-fsevents.c)
- list(APPEND uv_cflags -fno-strict-aliasing)
list(APPEND uv_libraries socket)
endif()
@@ -466,6 +475,7 @@ if(LIBUV_BUILD_TESTS)
test/test-poll-close-doesnt-corrupt-stack.c
test/test-poll-close.c
test/test-poll-closesocket.c
+ test/test-poll-multiple-handles.c
test/test-poll-oob.c
test/test-poll.c
test/test-process-priority.c
diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog
index 055dcaf9f1..d0eaf9fe34 100644
--- a/deps/uv/ChangeLog
+++ b/deps/uv/ChangeLog
@@ -1,3 +1,82 @@
+2021.02.14, Version 1.41.0 (Stable), 1dff88e5161cba5c59276d2070d2e304e4dcb242
+
+Changes since version 1.40.0:
+
+* mailmap: update contact information for richardlau (Richard Lau)
+
+* build: add asan checks (gengjiawen)
+
+* unix: report bind error in uv_tcp_connect() (Ben Noordhuis)
+
+* doc: uv_tcp_bind() never returns UV_EADDRINUSE (Ben Noordhuis)
+
+* test: fix pump and tcp_write_batch benchmarks (Santiago Gimeno)
+
+* doc: mark IBM i as Tier 2 support (Jesse Gorzinski)
+
+* doc,poll: add notes (repeated cb & cancel pending cb) (Elad Nachmias)
+
+* linux: fix -Wincompatible-pointer-types warning (Ben Noordhuis)
+
+* linux: fix -Wsign-compare warning (Ben Noordhuis)
+
+* android: add system call api guards (Ben Noordhuis)
+
+* unix,win: harmonize uv_read_start() error handling (Ben Noordhuis)
+
+* unix,win: more uv_read_start() argument validation (Ben Noordhuis)
+
+* build: turn on -fno-strict-aliasing (Ben Noordhuis)
+
+* stream: add uv_pipe and uv_socketpair to the API (Jameson Nash)
+
+* unix,win: initialize timer `timeout` field (Ben Noordhuis)
+
+* bsd-ifaddrs: improve comments (Darshan Sen)
+
+* test: remove unnecessary uv_fs_stat() calls (Ben Noordhuis)
+
+* fs: fix utime/futime timestamp rounding errors (Ben Noordhuis)
+
+* test: ensure reliable floating point comparison (Jameson Nash)
+
+* unix,fs: fix uv_fs_sendfile() (Santiago Gimeno)
+
+* unix: fix uv_fs_stat when using statx (Simon Kadisch)
+
+* linux,macos: fix uv_set_process_title regression (Momtchil Momtchev)
+
+* doc: clarify UDP errors and recvmmsg (Ethel Weston)
+
+* test-getaddrinfo: use example.invalid (Drew DeVault)
+
+* Revert "build: fix android autotools build" (Bernardo Ramos)
+
+* unix,fs: on DVS fs, statx returns EOPNOTSUPP (Mark Klein)
+
+* win, fs: mkdir really return UV_EINVAL for invalid names (Nicholas Vavilov)
+
+* tools: migrate tools/make_dist_html.py to python3 (Dominique Dumont)
+
+* unix: fix uv_uptime() on linux (schamberg97)
+
+* unix: check for partial copy_file_range support (Momtchil Momtchev)
+
+* win: bump minimum supported version to windows 8 (Ben Noordhuis)
+
+* poll,unix: ensure safety of rapid fd reuse (Bob Weinand)
+
+* test: fix some warnings (Issam E. Maghni)
+
+* unix: fix uv_uptime() regression (Santiago Gimeno)
+
+* doc: fix versionadded metadata (cjihrig)
+
+* test: fix 'incompatible pointer types' warnings (cjihrig)
+
+* unix: check for EXDEV in uv__fs_sendfile() (Darshan Sen)
+
+
2020.09.26, Version 1.40.0 (Stable), 4e69e333252693bd82d6338d6124f0416538dbfc
Changes since version 1.39.0:
diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am
index 46308eaae2..e8bab4963d 100644
--- a/deps/uv/Makefile.am
+++ b/deps/uv/Makefile.am
@@ -56,7 +56,7 @@ if WINNT
uvinclude_HEADERS += include/uv/win.h include/uv/tree.h
AM_CPPFLAGS += -I$(top_srcdir)/src/win \
-DWIN32_LEAN_AND_MEAN \
- -D_WIN32_WINNT=0x0600
+ -D_WIN32_WINNT=0x0602
libuv_la_SOURCES += src/win/async.c \
src/win/atomicops-inl.h \
src/win/core.c \
@@ -225,6 +225,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-poll-close.c \
test/test-poll-close-doesnt-corrupt-stack.c \
test/test-poll-closesocket.c \
+ test/test-poll-multiple-handles.c \
test/test-poll-oob.c \
test/test-process-priority.c \
test/test-process-title.c \
@@ -385,10 +386,6 @@ if ANDROID
uvinclude_HEADERS += include/uv/android-ifaddrs.h
libuv_la_CFLAGS += -D_GNU_SOURCE
libuv_la_SOURCES += src/unix/android-ifaddrs.c \
- src/unix/linux-core.c \
- src/unix/linux-inotify.c \
- src/unix/linux-syscalls.c \
- src/unix/procfs-exepath.c \
src/unix/pthread-fixes.c \
src/unix/random-getrandom.c \
src/unix/random-sysctl-linux.c
diff --git a/deps/uv/README.md b/deps/uv/README.md
index 98007c5e7d..f6c73709cc 100644
--- a/deps/uv/README.md
+++ b/deps/uv/README.md
@@ -286,6 +286,16 @@ listed in `test/benchmark-list.h`.
Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md).
+### `-fno-strict-aliasing`
+
+It is recommended to turn on the `-fno-strict-aliasing` compiler flag in
+projects that use libuv. The use of ad hoc "inheritance" in the libuv API
+may not be safe in the presence of compiler optimizations that depend on
+strict aliasing.
+
+MSVC does not have an equivalent flag but it also does not appear to need it
+at the time of writing (December 2019.)
+
### AIX Notes
AIX compilation using IBM XL C/C++ requires version 12.1 or greater.
diff --git a/deps/uv/SUPPORTED_PLATFORMS.md b/deps/uv/SUPPORTED_PLATFORMS.md
index 72e054eba0..30e0ea617a 100644
--- a/deps/uv/SUPPORTED_PLATFORMS.md
+++ b/deps/uv/SUPPORTED_PLATFORMS.md
@@ -4,14 +4,14 @@
|---|---|---|---|
| GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | |
| macOS | Tier 1 | macOS >= 10.7 | |
-| Windows | Tier 1 | >= Windows 7 | MSVC 2008 and later are supported |
+| Windows | Tier 1 | >= Windows 8 | VS 2015 and later are supported |
| FreeBSD | Tier 1 | >= 10 | |
| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix |
+| IBM i | Tier 2 | >= IBM i 7.2 | Maintainers: @libuv/ibmi |
| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos |
| Linux with musl | Tier 2 | musl >= 1.0 | |
| SmartOS | Tier 2 | >= 14.4 | Maintainers: @libuv/smartos |
| Android | Tier 3 | NDK >= r15b | |
-| IBM i | Tier 3 | >= IBM i 7.2 | Maintainers: @libuv/ibmi |
| MinGW | Tier 3 | MinGW32 and MinGW-w64 | |
| SunOS | Tier 3 | Solaris 121 and later | |
| Other | Tier 3 | N/A | |
diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac
index 1a66b74d28..4bdc7fd3f5 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], [1.40.0], [https://github.com/libuv/libuv/issues])
+AC_INIT([libuv], [1.41.0], [https://github.com/libuv/libuv/issues])
AC_CONFIG_MACRO_DIR([m4])
m4_include([m4/libuv-extra-automake-flags.m4])
m4_include([m4/as_case.m4])
@@ -25,6 +25,7 @@ AC_ENABLE_STATIC
AC_PROG_CC
AM_PROG_CC_C_O
CC_FLAG_VISIBILITY #[-fvisibility=hidden]
+CC_CHECK_CFLAGS_APPEND([-fno-strict-aliasing])
CC_CHECK_CFLAGS_APPEND([-g])
CC_CHECK_CFLAGS_APPEND([-std=gnu89])
CC_CHECK_CFLAGS_APPEND([-Wall])
diff --git a/deps/uv/docs/src/pipe.rst b/deps/uv/docs/src/pipe.rst
index 6437a9d994..5fa83b80d3 100644
--- a/deps/uv/docs/src/pipe.rst
+++ b/deps/uv/docs/src/pipe.rst
@@ -118,3 +118,21 @@ API
function is blocking.
.. versionadded:: 1.16.0
+
+.. c:function:: int uv_pipe(uv_file fds[2], int read_flags, int write_flags)
+
+ Create a pair of connected pipe handles.
+ Data may be written to `fds[1]` and read from `fds[0]`.
+ The resulting handles can be passed to `uv_pipe_open`, used with `uv_spawn`,
+ or for any other purpose.
+
+ Valid values for `flags` are:
+
+ - UV_NONBLOCK_PIPE: Opens the specified socket handle for `OVERLAPPED`
+ or `FIONBIO`/`O_NONBLOCK` I/O usage.
+ This is recommended for handles that will be used by libuv,
+ and not usually recommended otherwise.
+
+ Equivalent to :man:`pipe(2)` with the `O_CLOEXEC` flag set.
+
+ .. versionadded:: 1.41.0
diff --git a/deps/uv/docs/src/poll.rst b/deps/uv/docs/src/poll.rst
index aba8915886..93a101ec68 100644
--- a/deps/uv/docs/src/poll.rst
+++ b/deps/uv/docs/src/poll.rst
@@ -86,36 +86,63 @@ API
.. c:function:: int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb)
Starts polling the file descriptor. `events` is a bitmask made up of
- UV_READABLE, UV_WRITABLE, UV_PRIORITIZED and UV_DISCONNECT. As soon as an
- event is detected the callback will be called with `status` set to 0, and the
- detected events set on the `events` field.
+ `UV_READABLE`, `UV_WRITABLE`, `UV_PRIORITIZED` and `UV_DISCONNECT`. As soon
+ as an event is detected the callback will be called with `status` set to 0,
+ and the detected events set on the `events` field.
- The UV_PRIORITIZED event is used to watch for sysfs interrupts or TCP out-of-band
- messages.
+ The `UV_PRIORITIZED` event is used to watch for sysfs interrupts or TCP
+ out-of-band messages.
- The UV_DISCONNECT event is optional in the sense that it may not be
- reported and the user is free to ignore it, but it can help optimize the shutdown
- path because an extra read or write call might be avoided.
+ The `UV_DISCONNECT` event is optional in the sense that it may not be
+ reported and the user is free to ignore it, but it can help optimize the
+ shutdown path because an extra read or write call might be avoided.
If an error happens while polling, `status` will be < 0 and corresponds
- with one of the UV_E* error codes (see :ref:`errors`). The user should
+ with one of the `UV_E*` error codes (see :ref:`errors`). The user should
not close the socket while the handle is active. If the user does that
- anyway, the callback *may* be called reporting an error status, but this
- is **not** guaranteed.
+ anyway, the callback *may* be called reporting an error status, but this is
+ **not** guaranteed.
.. note::
- Calling :c:func:`uv_poll_start` on a handle that is already active is fine. Doing so
- will update the events mask that is being watched for.
+ Calling :c:func:`uv_poll_start` on a handle that is already active is
+ fine. Doing so will update the events mask that is being watched for.
.. note::
- Though UV_DISCONNECT can be set, it is unsupported on AIX and as such will not be set
- on the `events` field in the callback.
+ Though `UV_DISCONNECT` can be set, it is unsupported on AIX and as such
+ will not be set on the `events` field in the callback.
- .. versionchanged:: 1.9.0 Added the UV_DISCONNECT event.
- .. versionchanged:: 1.14.0 Added the UV_PRIORITIZED event.
+ .. note::
+ If one of the events `UV_READABLE` or `UV_WRITABLE` are set, the
+ callback will be called again, as long as the given fd/socket remains
+ readable or writable accordingly. Particularly in each of the following
+ scenarios:
+
+ * The callback has been called because the socket became
+ readable/writable and the callback did not conduct a read/write on
+ this socket at all.
+ * The callback committed a read on the socket, and has not read all the
+ available data (when `UV_READABLE` is set).
+ * The callback committed a write on the socket, but it remained
+ writable afterwards (when `UV_WRITABLE` is set).
+ * The socket has already became readable/writable before calling
+ :c:func:`uv_poll_start` on a poll handle associated with this socket,
+ and since then the state of the socket did not changed.
+
+ In all of the above listed scenarios, the socket remains readable or
+ writable and hence the callback will be called again (depending on the
+ events set in the bitmask). This behaviour is known as level
+ triggering.
+
+ .. versionchanged:: 1.9.0 Added the `UV_DISCONNECT` event.
+ .. versionchanged:: 1.14.0 Added the `UV_PRIORITIZED` event.
.. c:function:: int uv_poll_stop(uv_poll_t* poll)
Stop polling the file descriptor, the callback will no longer be called.
+ .. note::
+ Calling :c:func:`uv_poll_stop` is effective immediately: any pending
+ callback is also canceled, even if the socket state change notification
+ was already pending.
+
.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/deps/uv/docs/src/process.rst b/deps/uv/docs/src/process.rst
index 8ff19add57..ea6c4b9ad2 100644
--- a/deps/uv/docs/src/process.rst
+++ b/deps/uv/docs/src/process.rst
@@ -119,12 +119,14 @@ Data types
* flags may be specified to create a duplex data stream.
*/
UV_READABLE_PIPE = 0x10,
- UV_WRITABLE_PIPE = 0x20
+ UV_WRITABLE_PIPE = 0x20,
/*
- * Open the child pipe handle in overlapped mode on Windows.
- * On Unix it is silently ignored.
- */
- UV_OVERLAPPED_PIPE = 0x40
+ * When UV_CREATE_PIPE is specified, specifying UV_NONBLOCK_PIPE opens the
+ * handle in non-blocking mode in the child. This may cause loss of data,
+ * if the child is not designed to handle to encounter this mode,
+ * but can also be significantly more efficient.
+ */
+ UV_NONBLOCK_PIPE = 0x40
} uv_stdio_flags;
diff --git a/deps/uv/docs/src/stream.rst b/deps/uv/docs/src/stream.rst
index 2ccb59b51c..429ebdab28 100644
--- a/deps/uv/docs/src/stream.rst
+++ b/deps/uv/docs/src/stream.rst
@@ -139,6 +139,11 @@ API
be made several times until there is no more data to read or
:c:func:`uv_read_stop` is called.
+ .. versionchanged:: 1.38.0 :c:func:`uv_read_start()` now consistently
+ returns `UV_EALREADY` when called twice, and `UV_EINVAL` when the
+ stream is closing. With older libuv versions, it returns `UV_EALREADY`
+ on Windows but not UNIX, and `UV_EINVAL` on UNIX but not Windows.
+
.. c:function:: int uv_read_stop(uv_stream_t*)
Stop reading data from the stream. The :c:type:`uv_read_cb` callback will
diff --git a/deps/uv/docs/src/tcp.rst b/deps/uv/docs/src/tcp.rst
index 3cc8efaac1..cccc86bbfc 100644
--- a/deps/uv/docs/src/tcp.rst
+++ b/deps/uv/docs/src/tcp.rst
@@ -81,10 +81,9 @@ API
initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``.
When the port is already taken, you can expect to see an ``UV_EADDRINUSE``
- error from either :c:func:`uv_tcp_bind`, :c:func:`uv_listen` or
- :c:func:`uv_tcp_connect`. That is, a successful call to this function does
- not guarantee that the call to :c:func:`uv_listen` or :c:func:`uv_tcp_connect`
- will succeed as well.
+ error from :c:func:`uv_listen` or :c:func:`uv_tcp_connect`. That is,
+ a successful call to this function does not guarantee that the call
+ to :c:func:`uv_listen` or :c:func:`uv_tcp_connect` will succeed as well.
`flags` can contain ``UV_TCP_IPV6ONLY``, in which case dual-stack support
is disabled and only IPv6 is used.
@@ -128,3 +127,20 @@ API
:c:func:`uv_tcp_close_reset` calls is not allowed.
.. versionadded:: 1.32.0
+
+.. c:function:: int uv_socketpair(int type, int protocol, uv_os_sock_t socket_vector[2], int flags0, int flags1)
+
+ Create a pair of connected sockets with the specified properties.
+ The resulting handles can be passed to `uv_tcp_open`, used with `uv_spawn`,
+ or for any other purpose.
+
+ Valid values for `flags0` and `flags1` are:
+
+ - UV_NONBLOCK_PIPE: Opens the specified socket handle for `OVERLAPPED`
+ or `FIONBIO`/`O_NONBLOCK` I/O usage.
+ This is recommended for handles that will be used by libuv,
+ and not usually recommended otherwise.
+
+ Equivalent to :man:`socketpair(2)` with a domain of AF_UNIX.
+
+ .. versionadded:: 1.41.0
diff --git a/deps/uv/docs/src/udp.rst b/deps/uv/docs/src/udp.rst
index 30aa4593f0..827fbaad6c 100644
--- a/deps/uv/docs/src/udp.rst
+++ b/deps/uv/docs/src/udp.rst
@@ -73,7 +73,8 @@ Data types
* `nread`: Number of bytes that have been received.
0 if there is no more data to read. Note that 0 may also mean that an
empty datagram was received (in this case `addr` is not NULL). < 0 if
- a transmission error was detected.
+ a transmission error was detected; if using :man:`recvmmsg(2)` no more
+ chunks will be received and the buffer can be freed safely.
* `buf`: :c:type:`uv_buf_t` with the received data.
* `addr`: ``struct sockaddr*`` containing the address of the sender.
Can be NULL. Valid for the duration of the callback only.
@@ -84,10 +85,11 @@ Data types
on error.
When using :man:`recvmmsg(2)`, chunks will have the `UV_UDP_MMSG_CHUNK` flag set,
- those must not be freed. There will be a final callback with `nread` set to 0,
- `addr` set to NULL and the buffer pointing at the initially allocated data with
- the `UV_UDP_MMSG_CHUNK` flag cleared and the `UV_UDP_MMSG_FREE` flag set.
- The callee can now safely free the provided buffer.
+ those must not be freed. If no errors occur, there will be a final callback with
+ `nread` set to 0, `addr` set to NULL and the buffer pointing at the initially
+ allocated data with the `UV_UDP_MMSG_CHUNK` flag cleared and the `UV_UDP_MMSG_FREE`
+ flag set. If a UDP socket error occurs, `nread` will be < 0. In either scenario,
+ the callee can now safely free the provided buffer.
.. versionchanged:: 1.40.0 added the `UV_UDP_MMSG_FREE` flag.
diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h
index 2557961eed..1e1fc94bfc 100644
--- a/deps/uv/include/uv.h
+++ b/deps/uv/include/uv.h
@@ -475,6 +475,12 @@ UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd);
UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
+UV_EXTERN int uv_pipe(uv_file fds[2], int read_flags, int write_flags);
+UV_EXTERN int uv_socketpair(int type,
+ int protocol,
+ uv_os_sock_t socket_vector[2],
+ int flags0,
+ int flags1);
#define UV_STREAM_FIELDS \
/* number of bytes queued for writing */ \
@@ -933,10 +939,13 @@ typedef enum {
UV_WRITABLE_PIPE = 0x20,
/*
- * Open the child pipe handle in overlapped mode on Windows.
- * On Unix it is silently ignored.
+ * When UV_CREATE_PIPE is specified, specifying UV_NONBLOCK_PIPE opens the
+ * handle in non-blocking mode in the child. This may cause loss of data,
+ * if the child is not designed to handle to encounter this mode,
+ * but can also be significantly more efficient.
*/
- UV_OVERLAPPED_PIPE = 0x40
+ UV_NONBLOCK_PIPE = 0x40,
+ UV_OVERLAPPED_PIPE = 0x40 /* old name, for compatibility */
} uv_stdio_flags;
typedef struct uv_stdio_container_s {
diff --git a/deps/uv/include/uv/version.h b/deps/uv/include/uv/version.h
index 5272008a34..e94f1e02e1 100644
--- a/deps/uv/include/uv/version.h
+++ b/deps/uv/include/uv/version.h
@@ -31,7 +31,7 @@
*/
#define UV_VERSION_MAJOR 1
-#define UV_VERSION_MINOR 40
+#define UV_VERSION_MINOR 41
#define UV_VERSION_PATCH 0
#define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX ""
diff --git a/deps/uv/src/timer.c b/deps/uv/src/timer.c
index 1bea2a8bd2..bc680e71a9 100644
--- a/deps/uv/src/timer.c
+++ b/deps/uv/src/timer.c
@@ -58,6 +58,7 @@ static int timer_less_than(const struct heap_node* ha,
int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
handle->timer_cb = NULL;
+ handle->timeout = 0;
handle->repeat = 0;
return 0;
}
diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c
index 5f58fb88d6..e1805c3237 100644
--- a/deps/uv/src/unix/async.c
+++ b/deps/uv/src/unix/async.c
@@ -214,7 +214,7 @@ static int uv__async_start(uv_loop_t* loop) {
pipefd[0] = err;
pipefd[1] = -1;
#else
- err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
+ err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE);
if (err < 0)
return err;
#endif
diff --git a/deps/uv/src/unix/bsd-ifaddrs.c b/deps/uv/src/unix/bsd-ifaddrs.c
index 5223ab4879..e48934bce2 100644
--- a/deps/uv/src/unix/bsd-ifaddrs.c
+++ b/deps/uv/src/unix/bsd-ifaddrs.c
@@ -42,8 +42,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
return 1;
#if !defined(__CYGWIN__) && !defined(__MSYS__)
/*
- * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family`
- * equals to `AF_LINK` or not. Otherwise, the result depends on the operation
+ * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, return whether `sa_family`
+ * equals `AF_LINK`. Otherwise, the result depends on the operating
* system with `AF_LINK` or `PF_INET`.
*/
if (exclude_type == UV__EXCLUDE_IFPHYS)
@@ -53,7 +53,7 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
defined(__HAIKU__)
/*
* On BSD getifaddrs returns information related to the raw underlying
- * devices. We're not interested in this information.
+ * devices. We're not interested in this information.
*/
if (ent->ifa_addr->sa_family == AF_LINK)
return 1;
diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c
index 1597828c86..63f268f795 100644
--- a/deps/uv/src/unix/core.c
+++ b/deps/uv/src/unix/core.c
@@ -925,13 +925,12 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
if (w->pevents == 0) {
QUEUE_REMOVE(&w->watcher_queue);
QUEUE_INIT(&w->watcher_queue);
+ w->events = 0;
- if (loop->watchers[w->fd] != NULL) {
- assert(loop->watchers[w->fd] == w);
+ if (w == loop->watchers[w->fd]) {
assert(loop->nfds > 0);
loop->watchers[w->fd] = NULL;
loop->nfds--;
- w->events = 0;
}
}
else if (QUEUE_EMPTY(&w->watcher_queue))
diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c
index 556fd103c3..fd7ae08755 100644
--- a/deps/uv/src/unix/fs.c
+++ b/deps/uv/src/unix/fs.c
@@ -58,6 +58,7 @@
#if defined(__linux__) || defined(__sun)
# include <sys/sendfile.h>
+# include <sys/sysmacros.h>
#endif
#if defined(__APPLE__)
@@ -212,14 +213,30 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) {
struct timespec ts;
ts.tv_sec = time;
- ts.tv_nsec = (uint64_t)(time * 1000000) % 1000000 * 1000;
+ ts.tv_nsec = (time - ts.tv_sec) * 1e9;
+
+ /* TODO(bnoordhuis) Remove this. utimesat() has nanosecond resolution but we
+ * stick to microsecond resolution for the sake of consistency with other
+ * platforms. I'm the original author of this compatibility hack but I'm
+ * less convinced it's useful nowadays.
+ */
+ ts.tv_nsec -= ts.tv_nsec % 1000;
+
+ if (ts.tv_nsec < 0) {
+ ts.tv_nsec += 1e9;
+ ts.tv_sec -= 1;
+ }
return ts;
}
UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) {
struct timeval tv;
tv.tv_sec = time;
- tv.tv_usec = (uint64_t)(time * 1000000) % 1000000;
+ tv.tv_usec = (time - tv.tv_sec) * 1e6;
+ if (tv.tv_usec < 0) {
+ tv.tv_usec += 1e6;
+ tv.tv_sec -= 1;
+ }
return tv;
}
@@ -227,9 +244,6 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
#if defined(__linux__) \
|| defined(_AIX71) \
|| defined(__HAIKU__)
- /* utimesat() has nanosecond resolution but we stick to microseconds
- * for the sake of consistency with other platforms.
- */
struct timespec ts[2];
ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime);
@@ -906,11 +920,17 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
static int copy_file_range_support = 1;
if (copy_file_range_support) {
- r = uv__fs_copy_file_range(in_fd, NULL, out_fd, &off, req->bufsml[0].len, 0);
+ r = uv__fs_copy_file_range(in_fd, &off, out_fd, NULL, req->bufsml[0].len, 0);
if (r == -1 && errno == ENOSYS) {
+ /* ENOSYS - it will never work */
errno = 0;
copy_file_range_support = 0;
+ } else if (r == -1 && (errno == ENOTSUP || errno == EXDEV)) {
+ /* ENOTSUP - it could work on another file system type */
+ /* EXDEV - it will not work when in_fd and out_fd are not on the same
+ mounted filesystem (pre Linux 5.3) */
+ errno = 0;
} else {
goto ok;
}
@@ -1010,9 +1030,6 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
|| defined(_AIX71) \
|| defined(__sun) \
|| defined(__HAIKU__)
- /* utimesat() has nanosecond resolution but we stick to microseconds
- * for the sake of consistency with other platforms.
- */
struct timespec ts[2];
ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime);
@@ -1220,7 +1237,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
if (fstatfs(dstfd, &s) == -1)
goto out;
- if (s.f_type != /* CIFS */ 0xFF534D42u)
+ if ((unsigned) s.f_type != /* CIFS */ 0xFF534D42u)
goto out;
}
@@ -1420,8 +1437,9 @@ static int uv__fs_statx(int fd,
case -1:
/* EPERM happens when a seccomp filter rejects the system call.
* Has been observed with libseccomp < 2.3.3 and docker < 18.04.
+ * EOPNOTSUPP is used on DVS exported filesystems
*/
- if (errno != EINVAL && errno != EPERM && errno != ENOSYS)
+ if (errno != EINVAL && errno != EPERM && errno != ENOSYS && errno != EOPNOTSUPP)
return -1;
/* Fall through. */
default:
@@ -1434,12 +1452,12 @@ static int uv__fs_statx(int fd,
return UV_ENOSYS;
}
- buf->st_dev = 256 * statxbuf.stx_dev_major + statxbuf.stx_dev_minor;
+ buf->st_dev = makedev(statxbuf.stx_dev_major, statxbuf.stx_dev_minor);
buf->st_mode = statxbuf.stx_mode;
buf->st_nlink = statxbuf.stx_nlink;
buf->st_uid = statxbuf.stx_uid;
buf->st_gid = statxbuf.stx_gid;
- buf->st_rdev = statxbuf.stx_rdev_major;
+ buf->st_rdev = makedev(statxbuf.stx_rdev_major, statxbuf.stx_rdev_minor);
buf->st_ino = statxbuf.stx_ino;
buf->st_size = statxbuf.stx_size;
buf->st_blksize = statxbuf.stx_blksize;
diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h
index 570274ed60..3bdf7283bd 100644
--- a/deps/uv/src/unix/internal.h
+++ b/deps/uv/src/unix/internal.h
@@ -282,12 +282,6 @@ int uv___stream_fd(const uv_stream_t* handle);
#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
#endif /* defined(__APPLE__) */
-#ifdef O_NONBLOCK
-# define UV__F_NONBLOCK O_NONBLOCK
-#else
-# define UV__F_NONBLOCK 1
-#endif
-
int uv__make_pipe(int fds[2], int flags);
#if defined(__APPLE__)
diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c
index 4db2f05053..c356e96d2d 100644
--- a/deps/uv/src/unix/linux-core.c
+++ b/deps/uv/src/unix/linux-core.c
@@ -602,22 +602,53 @@ err:
return UV_EINVAL;
}
+static int uv__slurp(const char* filename, char* buf, size_t len) {
+ ssize_t n;
+ int fd;
+
+ assert(len > 0);
+
+ fd = uv__open_cloexec(filename, O_RDONLY);
+ if (fd < 0)
+ return fd;
+
+ do
+ n = read(fd, buf, len - 1);
+ while (n == -1 && errno == EINTR);
+
+ if (uv__close_nocheckstdio(fd))
+ abort();
+
+ if (n < 0)
+ return UV__ERR(errno);
+
+ buf[n] = '\0';
+
+ return 0;
+}
int uv_uptime(double* uptime) {
static volatile int no_clock_boottime;
+ char buf[128];
struct timespec now;
int r;
+ /* Try /proc/uptime first, then fallback to clock_gettime(). */
+
+ if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf)))
+ if (1 == sscanf(buf, "%lf", uptime))
+ return 0;
+
/* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available
* (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system
* is suspended.
*/
if (no_clock_boottime) {
- retry: r = clock_gettime(CLOCK_MONOTONIC, &now);
+ retry_clock_gettime: r = clock_gettime(CLOCK_MONOTONIC, &now);
}
else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) {
no_clock_boottime = 1;
- goto retry;
+ goto retry_clock_gettime;
}
if (r)
@@ -1025,32 +1056,6 @@ void uv__set_process_title(const char* title) {
}
-static int uv__slurp(const char* filename, char* buf, size_t len) {
- ssize_t n;
- int fd;
-
- assert(len > 0);
-
- fd = uv__open_cloexec(filename, O_RDONLY);
- if (fd < 0)
- return fd;
-
- do
- n = read(fd, buf, len - 1);
- while (n == -1 && errno == EINTR);
-
- if (uv__close_nocheckstdio(fd))
- abort();
-
- if (n < 0)
- return UV__ERR(errno);
-
- buf[n] = '\0';
-
- return 0;
-}
-
-
static uint64_t uv__read_proc_meminfo(const char* what) {
uint64_t rc;
char* p;
diff --git a/deps/uv/src/unix/linux-syscalls.c b/deps/uv/src/unix/linux-syscalls.c
index 44daaf12d4..5071cd56d1 100644
--- a/deps/uv/src/unix/linux-syscalls.c
+++ b/deps/uv/src/unix/linux-syscalls.c
@@ -194,37 +194,37 @@ int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
-#if defined(__NR_preadv)
- return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
-#else
+#if !defined(__NR_preadv) || defined(__ANDROID_API__) && __ANDROID_API__ < 24
return errno = ENOSYS, -1;
+#else
+ return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
#endif
}
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
-#if defined(__NR_pwritev)
- return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
-#else
+#if !defined(__NR_pwritev) || defined(__ANDROID_API__) && __ANDROID_API__ < 24
return errno = ENOSYS, -1;
+#else
+ return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
#endif
}
int uv__dup3(int oldfd, int newfd, int flags) {
-#if defined(__NR_dup3)
- return syscall(__NR_dup3, oldfd, newfd, flags);
-#else
+#if !defined(__NR_dup3) || defined(__ANDROID_API__) && __ANDROID_API__ < 21
return errno = ENOSYS, -1;
+#else
+ return syscall(__NR_dup3, oldfd, newfd, flags);
#endif
}
ssize_t
uv__fs_copy_file_range(int fd_in,
- ssize_t* off_in,
+ off_t* off_in,
int fd_out,
- ssize_t* off_out,
+ off_t* off_out,
size_t len,
unsigned int flags)
{
@@ -247,21 +247,18 @@ int uv__statx(int dirfd,
int flags,
unsigned int mask,
struct uv__statx* statxbuf) {
- /* __NR_statx make Android box killed by SIGSYS.
- * That looks like a seccomp2 sandbox filter rejecting the system call.
- */
-#if defined(__NR_statx) && !defined(__ANDROID__)
- return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
-#else
+#if !defined(__NR_statx) || defined(__ANDROID_API__) && __ANDROID_API__ < 30
return errno = ENOSYS, -1;
+#else
+ return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
#endif
}
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) {
-#if defined(__NR_getrandom)
- return syscall(__NR_getrandom, buf, buflen, flags);
-#else
+#if !defined(__NR_getrandom) || defined(__ANDROID_API__) && __ANDROID_API__ < 28
return errno = ENOSYS, -1;
+#else
+ return syscall(__NR_getrandom, buf, buflen, flags);
#endif
}
diff --git a/deps/uv/src/unix/linux-syscalls.h b/deps/uv/src/unix/linux-syscalls.h
index 761ff32e21..c85231f6bf 100644
--- a/deps/uv/src/unix/linux-syscalls.h
+++ b/deps/uv/src/unix/linux-syscalls.h
@@ -66,9 +66,9 @@ ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset)
int uv__dup3(int oldfd, int newfd, int flags);
ssize_t
uv__fs_copy_file_range(int fd_in,
- ssize_t* off_in,
+ off_t* off_in,
int fd_out,
- ssize_t* off_out,
+ off_t* off_out,
size_t len,
unsigned int flags);
int uv__statx(int dirfd,
diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c
index 040d57817f..788e038e8a 100644
--- a/deps/uv/src/unix/pipe.c
+++ b/deps/uv/src/unix/pipe.c
@@ -379,3 +379,57 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
return r != -1 ? 0 : UV__ERR(errno);
}
+
+
+int uv_pipe(uv_os_fd_t fds[2], int read_flags, int write_flags) {
+ uv_os_fd_t temp[2];
+ int err;
+#if defined(__FreeBSD__) || defined(__linux__)
+ int flags = O_CLOEXEC;
+
+ if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE))
+ flags |= UV_FS_O_NONBLOCK;
+
+ if (pipe2(temp, flags))
+ return UV__ERR(errno);
+
+ if (flags & UV_FS_O_NONBLOCK) {
+ fds[0] = temp[0];
+ fds[1] = temp[1];
+ return 0;
+ }
+#else
+ if (pipe(temp))
+ return UV__ERR(errno);
+
+ if ((err = uv__cloexec(temp[0], 1)))
+ goto fail;
+
+ if ((err = uv__cloexec(temp[1], 1)))
+ goto fail;
+#endif
+
+ if (read_flags & UV_NONBLOCK_PIPE)
+ if ((err = uv__nonblock(temp[0], 1)))
+ goto fail;
+
+ if (write_flags & UV_NONBLOCK_PIPE)
+ if ((err = uv__nonblock(temp[1], 1)))
+ goto fail;
+
+ fds[0] = temp[0];
+ fds[1] = temp[1];
+ return 0;
+
+fail:
+ uv__close(temp[0]);
+ uv__close(temp[1]);
+ return err;
+}
+
+
+int uv__make_pipe(int fds[2], int flags) {
+ return uv_pipe(fds,
+ flags & UV_NONBLOCK_PIPE,
+ flags & UV_NONBLOCK_PIPE);
+}
diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c
index 3d5022b22e..7a1bc7b9dd 100644
--- a/deps/uv/src/unix/poll.c
+++ b/deps/uv/src/unix/poll.c
@@ -116,12 +116,21 @@ int uv_poll_stop(uv_poll_t* handle) {
int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
+ uv__io_t** watchers;
+ uv__io_t* w;
int events;
assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
UV_PRIORITIZED)) == 0);
assert(!uv__is_closing(handle));
+ watchers = handle->loop->watchers;
+ w = &handle->io_watcher;
+
+ if (uv__fd_exists(handle->loop, w->fd))
+ if (watchers[w->fd] != w)
+ return UV_EEXIST;
+
uv__poll_stop(handle);
if (pevents == 0)
diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c
index b021aaeba8..8f94c53b24 100644
--- a/deps/uv/src/unix/process.c
+++ b/deps/uv/src/unix/process.c
@@ -111,68 +111,6 @@ static void uv__chld(uv_signal_t* handle, int signum) {
assert(QUEUE_EMPTY(&pending));
}
-
-static int uv__make_socketpair(int fds[2]) {
-#if defined(__FreeBSD__) || defined(__linux__)
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds))
- return UV__ERR(errno);
-
- return 0;
-#else
- int err;
-
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
- return UV__ERR(errno);
-
- err = uv__cloexec(fds[0], 1);
- if (err == 0)
- err = uv__cloexec(fds[1], 1);
-
- if (err != 0) {
- uv__close(fds[0]);
- uv__close(fds[1]);
- return UV__ERR(errno);
- }
-
- return 0;
-#endif
-}
-
-
-int uv__make_pipe(int fds[2], int flags) {
-#if defined(__FreeBSD__) || defined(__linux__)
- if (pipe2(fds, flags | O_CLOEXEC))
- return UV__ERR(errno);
-
- return 0;
-#else
- if (pipe(fds))
- return UV__ERR(errno);
-
- if (uv__cloexec(fds[0], 1))
- goto fail;
-
- if (uv__cloexec(fds[1], 1))
- goto fail;
-
- if (flags & UV__F_NONBLOCK) {
- if (uv__nonblock(fds[0], 1))
- goto fail;
-
- if (uv__nonblock(fds[1], 1))
- goto fail;
- }
-
- return 0;
-
-fail:
- uv__close(fds[0]);
- uv__close(fds[1]);
- return UV__ERR(errno);
-#endif
-}
-
-
/*
* Used for initializing stdio streams like options.stdin_stream. Returns
* zero on success. See also the cleanup section in uv_spawn().
@@ -192,7 +130,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
if (container->data.stream->type != UV_NAMED_PIPE)
return UV_EINVAL;
else
- return uv__make_socketpair(fds);
+ return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0);
case UV_INHERIT_FD:
case UV_INHERIT_STREAM:
diff --git a/deps/uv/src/unix/proctitle.c b/deps/uv/src/unix/proctitle.c
index 9ffe5b629c..9e39545e44 100644
--- a/deps/uv/src/unix/proctitle.c
+++ b/deps/uv/src/unix/proctitle.c
@@ -119,6 +119,7 @@ int uv_set_process_title(const char* title) {
memcpy(pt->str, title, len);
memset(pt->str + len, '\0', pt->cap - len);
pt->len = len;
+ uv__set_process_title(pt->str);
uv_mutex_unlock(&process_title_mutex);
diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c
index f40a3e54eb..1133c73a95 100644
--- a/deps/uv/src/unix/signal.c
+++ b/deps/uv/src/unix/signal.c
@@ -265,7 +265,7 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) {
if (loop->signal_pipefd[0] != -1)
return 0;
- err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK);
+ err = uv__make_pipe(loop->signal_pipefd, UV_NONBLOCK_PIPE);
if (err)
return err;
diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c
index 8327f9ccfc..106785e457 100644
--- a/deps/uv/src/unix/stream.c
+++ b/deps/uv/src/unix/stream.c
@@ -1552,18 +1552,12 @@ int uv_try_write(uv_stream_t* stream,
}
-int uv_read_start(uv_stream_t* stream,
- uv_alloc_cb alloc_cb,
- uv_read_cb read_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);
- if (stream->flags & UV_HANDLE_CLOSING)
- return UV_EINVAL;
-
- if (!(stream->flags & UV_HANDLE_READABLE))
- return UV_ENOTCONN;
-
/* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just
* expresses the desired state of the user.
*/
diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c
index 18acd20df1..bc0fb661f1 100644
--- a/deps/uv/src/unix/tcp.c
+++ b/deps/uv/src/unix/tcp.c
@@ -214,14 +214,15 @@ int uv__tcp_connect(uv_connect_t* req,
if (handle->connect_req != NULL)
return UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */
+ if (handle->delayed_error != 0)
+ goto out;
+
err = maybe_new_socket(handle,
addr->sa_family,
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
if (err)
return err;
- handle->delayed_error = 0;
-
do {
errno = 0;
r = connect(uv__stream_fd(handle), addr, addrlen);
@@ -249,6 +250,8 @@ int uv__tcp_connect(uv_connect_t* req,
return UV__ERR(errno);
}
+out:
+
uv__req_init(handle->loop, req, UV_CONNECT);
req->cb = cb;
req->handle = (uv_stream_t*) handle;
@@ -459,3 +462,49 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
void uv__tcp_close(uv_tcp_t* handle) {
uv__stream_close((uv_stream_t*)handle);
}
+
+
+int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) {
+ uv_os_sock_t temp[2];
+ int err;
+#if defined(__FreeBSD__) || defined(__linux__)
+ int flags;
+
+ flags = type | SOCK_CLOEXEC;
+ if ((flags0 & UV_NONBLOCK_PIPE) && (flags1 & UV_NONBLOCK_PIPE))
+ flags |= SOCK_NONBLOCK;
+
+ if (socketpair(AF_UNIX, flags, protocol, temp))
+ return UV__ERR(errno);
+
+ if (flags & UV_FS_O_NONBLOCK) {
+ fds[0] = temp[0];
+ fds[1] = temp[1];
+ return 0;
+ }
+#else
+ if (socketpair(AF_UNIX, type, protocol, temp))
+ return UV__ERR(errno);
+
+ if ((err = uv__cloexec(temp[0], 1)))
+ goto fail;
+ if ((err = uv__cloexec(temp[1], 1)))
+ goto fail;
+#endif
+
+ if (flags0 & UV_NONBLOCK_PIPE)
+ if ((err = uv__nonblock(temp[0], 1)))
+ goto fail;
+ if (flags1 & UV_NONBLOCK_PIPE)
+ if ((err = uv__nonblock(temp[1], 1)))
+ goto fail;
+
+ fds[0] = temp[0];
+ fds[1] = temp[1];
+ return 0;
+
+fail:
+ uv__close(temp[0]);
+ uv__close(temp[1]);
+ return err;
+}
diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c
index 602e5f492f..dd559a11d1 100644
--- a/deps/uv/src/uv-common.c
+++ b/deps/uv/src/uv-common.c
@@ -832,6 +832,25 @@ void uv_loop_delete(uv_loop_t* loop) {
}
+int uv_read_start(uv_stream_t* stream,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ if (stream == NULL || alloc_cb == NULL || read_cb == NULL)
+ return UV_EINVAL;
+
+ if (stream->flags & UV_HANDLE_CLOSING)
+ return UV_EINVAL;
+
+ if (stream->flags & UV_HANDLE_READING)
+ return UV_EALREADY;
+
+ if (!(stream->flags & UV_HANDLE_READABLE))
+ return UV_ENOTCONN;
+
+ return uv__read_start(stream, alloc_cb, read_cb);
+}
+
+
void uv_os_free_environ(uv_env_item_t* envitems, int count) {
int i;
diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h
index e851291cc0..a92912fdb1 100644
--- a/deps/uv/src/uv-common.h
+++ b/deps/uv/src/uv-common.h
@@ -136,6 +136,10 @@ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
void uv__loop_close(uv_loop_t* loop);
+int uv__read_start(uv_stream_t* stream,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+
int uv__tcp_bind(uv_tcp_t* tcp,
const struct sockaddr* addr,
unsigned int addrlen,
diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c
index 8a801749d4..a083b5e82c 100644
--- a/deps/uv/src/win/fs.c
+++ b/deps/uv/src/win/fs.c
@@ -92,30 +92,24 @@
return; \
}
-#define MILLIONu (1000U * 1000U)
-#define BILLIONu (1000U * 1000U * 1000U)
+#define MILLION ((int64_t) 1000 * 1000)
+#define BILLION ((int64_t) 1000 * 1000 * 1000)
-#define FILETIME_TO_UINT(filetime) \
- (*((uint64_t*) &(filetime)) - (uint64_t) 116444736 * BILLIONu)
-
-#define FILETIME_TO_TIME_T(filetime) \
- (FILETIME_TO_UINT(filetime) / (10u * MILLIONu))
-
-#define FILETIME_TO_TIME_NS(filetime, secs) \
- ((FILETIME_TO_UINT(filetime) - (secs * (uint64_t) 10 * MILLIONu)) * 100U)
-
-#define FILETIME_TO_TIMESPEC(ts, filetime) \
- do { \
- (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \
- (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \
- } while(0)
+static void uv__filetime_to_timespec(uv_timespec_t *ts, int64_t filetime) {
+ filetime -= 116444736 * BILLION;
+ ts->tv_sec = (long) (filetime / (10 * MILLION));
+ ts->tv_nsec = (long) ((filetime - ts->tv_sec * 10 * MILLION) * 100U);
+ if (ts->tv_nsec < 0) {
+ ts->tv_sec -= 1;
+ ts->tv_nsec += 1e9;
+ }
+}
#define TIME_T_TO_FILETIME(time, filetime_ptr) \
do { \
- uint64_t bigtime = ((uint64_t) ((time) * (uint64_t) 10 * MILLIONu)) + \
- (uint64_t) 116444736 * BILLIONu; \
- (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
- (filetime_ptr)->dwHighDateTime = bigtime >> 32; \
+ int64_t bigtime = ((time) * 10 * MILLION + 116444736 * BILLION); \
+ (filetime_ptr)->dwLowDateTime = (uint64_t) bigtime & 0xFFFFFFFF; \
+ (filetime_ptr)->dwHighDateTime = (uint64_t) bigtime >> 32; \
} while(0)
#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
@@ -1224,7 +1218,8 @@ void fs__mkdir(uv_fs_t* req) {
SET_REQ_RESULT(req, 0);
} else {
SET_REQ_WIN32_ERROR(req, GetLastError());
- if (req->sys_errno_ == ERROR_INVALID_NAME)
+ if (req->sys_errno_ == ERROR_INVALID_NAME ||
+ req->sys_errno_ == ERROR_DIRECTORY)
req->result = UV_EINVAL;
}
}
@@ -1791,10 +1786,14 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
((_S_IREAD | _S_IWRITE) >> 6);
- FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime);
- FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime);
- FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime);
- FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime);
+ uv__filetime_to_timespec(&statbuf->st_atim,
+ file_info.BasicInformation.LastAccessTime.QuadPart);
+ uv__filetime_to_timespec(&statbuf->st_ctim,
+ file_info.BasicInformation.ChangeTime.QuadPart);
+ uv__filetime_to_timespec(&statbuf->st_mtim,
+ file_info.BasicInformation.LastWriteTime.QuadPart);
+ uv__filetime_to_timespec(&statbuf->st_birthtim,
+ file_info.BasicInformation.CreationTime.QuadPart);
statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart;
diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h
index b096255e4d..b1b25b4c78 100644
--- a/deps/uv/src/win/internal.h
+++ b/deps/uv/src/win/internal.h
@@ -115,8 +115,8 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
/*
* Pipes
*/
-int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
- char* name, size_t nameSize);
+int uv__create_stdio_pipe_pair(uv_loop_t* loop,
+ uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags);
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);
diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c
index f81245ec60..88ba99bbc0 100644
--- a/deps/uv/src/win/pipe.c
+++ b/deps/uv/src/win/pipe.c
@@ -202,17 +202,17 @@ static void close_pipe(uv_pipe_t* pipe) {
}
-int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
- char* name, size_t nameSize) {
+static int uv__pipe_server(
+ HANDLE* pipeHandle_ptr, DWORD access,
+ char* name, size_t nameSize, char* random) {
HANDLE pipeHandle;
int err;
- char* ptr = (char*)handle;
for (;;) {
- uv_unique_pipe_name(ptr, name, nameSize);
+ uv_unique_pipe_name(random, name, nameSize);
pipeHandle = CreateNamedPipeA(name,
- access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
+ access | FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
NULL);
@@ -226,26 +226,225 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
goto error;
}
- /* Pipe name collision. Increment the pointer and try again. */
- ptr++;
+ /* Pipe name collision. Increment the random number and try again. */
+ random++;
}
- if (CreateIoCompletionPort(pipeHandle,
+ *pipeHandle_ptr = pipeHandle;
+
+ return 0;
+
+ error:
+ if (pipeHandle != INVALID_HANDLE_VALUE)
+ CloseHandle(pipeHandle);
+
+ return err;
+}
+
+
+static int uv__create_pipe_pair(
+ HANDLE* server_pipe_ptr, HANDLE* client_pipe_ptr,
+ unsigned int server_flags, unsigned int client_flags,
+ int inherit_client, char* random) {
+ /* allowed flags are: UV_READABLE_PIPE | UV_WRITABLE_PIPE | UV_NONBLOCK_PIPE */
+ char pipe_name[64];
+ SECURITY_ATTRIBUTES sa;
+ DWORD server_access;
+ DWORD client_access;
+ HANDLE server_pipe;
+ HANDLE client_pipe;
+ int err;
+
+ server_pipe = INVALID_HANDLE_VALUE;
+ client_pipe = INVALID_HANDLE_VALUE;
+
+ server_access = 0;
+ if (server_flags & UV_READABLE_PIPE)
+ server_access |= PIPE_ACCESS_INBOUND;
+ if (server_flags & UV_WRITABLE_PIPE)
+ server_access |= PIPE_ACCESS_OUTBOUND;
+ if (server_flags & UV_NONBLOCK_PIPE)
+ server_access |= FILE_FLAG_OVERLAPPED;
+ server_access |= WRITE_DAC;
+
+ client_access = 0;
+ if (client_flags & UV_READABLE_PIPE)
+ client_access |= GENERIC_READ;
+ else
+ client_access |= FILE_READ_ATTRIBUTES;
+ if (client_flags & UV_WRITABLE_PIPE)
+ client_access |= GENERIC_WRITE;
+ else
+ client_access |= FILE_WRITE_ATTRIBUTES;
+ client_access |= WRITE_DAC;
+
+ /* Create server pipe handle. */
+ err = uv__pipe_server(&server_pipe,
+ server_access,
+ pipe_name,
+ sizeof(pipe_name),
+ random);
+ if (err)
+ goto error;
+
+ /* Create client pipe handle. */
+ sa.nLength = sizeof sa;
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = inherit_client;
+
+ client_pipe = CreateFileA(pipe_name,
+ client_access,
+ 0,
+ &sa,
+ OPEN_EXISTING,
+ (client_flags & UV_NONBLOCK_PIPE) ? FILE_FLAG_OVERLAPPED : 0,
+ NULL);
+ if (client_pipe == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
+ goto error;
+ }
+
+#ifndef NDEBUG
+ /* Validate that the pipe was opened in the right mode. */
+ {
+ DWORD mode;
+ BOOL r;
+ r = GetNamedPipeHandleState(client_pipe, &mode, NULL, NULL, NULL, NULL, 0);
+ if (r == TRUE) {
+ assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
+ } else {
+ fprintf(stderr, "libuv assertion failure: GetNamedPipeHandleState failed\n");
+ }
+ }
+#endif
+
+ /* Do a blocking ConnectNamedPipe. This should not block because we have
+ * both ends of the pipe created. */
+ if (!ConnectNamedPipe(server_pipe, NULL)) {
+ if (GetLastError() != ERROR_PIPE_CONNECTED) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+
+ *client_pipe_ptr = client_pipe;
+ *server_pipe_ptr = server_pipe;
+ return 0;
+
+ error:
+ if (server_pipe != INVALID_HANDLE_VALUE)
+ CloseHandle(server_pipe);
+
+ if (client_pipe != INVALID_HANDLE_VALUE)
+ CloseHandle(client_pipe);
+
+ return err;
+}
+
+
+int uv_pipe(uv_file fds[2], int read_flags, int write_flags) {
+ uv_file temp[2];
+ int err;
+ HANDLE readh;
+ HANDLE writeh;
+
+ /* Make the server side the inbound (read) end, */
+ /* so that both ends will have FILE_READ_ATTRIBUTES permission. */
+ /* TODO: better source of local randomness than &fds? */
+ read_flags |= UV_READABLE_PIPE;
+ write_flags |= UV_WRITABLE_PIPE;
+ err = uv__create_pipe_pair(&readh, &writeh, read_flags, write_flags, 0, (char*) &fds[0]);
+ if (err != 0)
+ return err;
+ temp[0] = _open_osfhandle((intptr_t) readh, 0);
+ if (temp[0] == -1) {
+ if (errno == UV_EMFILE)
+ err = UV_EMFILE;
+ else
+ err = UV_UNKNOWN;
+ CloseHandle(readh);
+ CloseHandle(writeh);
+ return err;
+ }
+ temp[1] = _open_osfhandle((intptr_t) writeh, 0);
+ if (temp[1] == -1) {
+ if (errno == UV_EMFILE)
+ err = UV_EMFILE;
+ else
+ err = UV_UNKNOWN;
+ _close(temp[0]);
+ CloseHandle(writeh);
+ return err;
+ }
+ fds[0] = temp[0];
+ fds[1] = temp[1];
+ return 0;
+}
+
+
+int uv__create_stdio_pipe_pair(uv_loop_t* loop,
+ uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
+ /* The parent_pipe is always the server_pipe and kept by libuv.
+ * The child_pipe is always the client_pipe and is passed to the child.
+ * The flags are specified with respect to their usage in the child. */
+ HANDLE server_pipe;
+ HANDLE client_pipe;
+ unsigned int server_flags;
+ unsigned int client_flags;
+ int err;
+
+ server_pipe = INVALID_HANDLE_VALUE;
+ client_pipe = INVALID_HANDLE_VALUE;
+
+ server_flags = 0;
+ client_flags = 0;
+ if (flags & UV_READABLE_PIPE) {
+ /* The server needs inbound (read) access too, otherwise CreateNamedPipe()
+ * won't give us the FILE_READ_ATTRIBUTES permission. We need that to probe
+ * the state of the write buffer when we're trying to shutdown the pipe. */
+ server_flags |= UV_READABLE_PIPE | UV_WRITABLE_PIPE;
+ client_flags |= UV_READABLE_PIPE;
+ }
+ if (flags & UV_WRITABLE_PIPE) {
+ server_flags |= UV_READABLE_PIPE;
+ client_flags |= UV_WRITABLE_PIPE;
+ }
+ server_flags |= UV_NONBLOCK_PIPE;
+ if (flags & UV_NONBLOCK_PIPE || parent_pipe->ipc) {
+ client_flags |= UV_NONBLOCK_PIPE;
+ }
+
+ err = uv__create_pipe_pair(&server_pipe, &client_pipe,
+ server_flags, client_flags, 1, (char*) server_pipe);
+ if (err)
+ goto error;
+
+ if (CreateIoCompletionPort(server_pipe,
loop->iocp,
- (ULONG_PTR)handle,
+ (ULONG_PTR) parent_pipe,
0) == NULL) {
err = GetLastError();
goto error;
}
- uv_pipe_connection_init(handle);
- handle->handle = pipeHandle;
+ uv_pipe_connection_init(parent_pipe);
+ parent_pipe->handle = server_pipe;
+ *child_pipe_ptr = client_pipe;
+
+ /* The server end is now readable and/or writable. */
+ if (flags & UV_READABLE_PIPE)
+ parent_pipe->flags |= UV_HANDLE_WRITABLE;
+ if (flags & UV_WRITABLE_PIPE)
+ parent_pipe->flags |= UV_HANDLE_READABLE;
return 0;
error:
- if (pipeHandle != INVALID_HANDLE_VALUE)
- CloseHandle(pipeHandle);
+ if (server_pipe != INVALID_HANDLE_VALUE)
+ CloseHandle(server_pipe);
+
+ if (client_pipe != INVALID_HANDLE_VALUE)
+ CloseHandle(client_pipe);
return err;
}
@@ -712,9 +911,8 @@ error:
handle->name = NULL;
}
- if (pipeHandle != INVALID_HANDLE_VALUE) {
+ if (pipeHandle != INVALID_HANDLE_VALUE)
CloseHandle(pipeHandle);
- }
/* Make this req pending reporting an error. */
SET_REQ_ERROR(req, err);
diff --git a/deps/uv/src/win/process-stdio.c b/deps/uv/src/win/process-stdio.c
index 355d618808..0db3572373 100644
--- a/deps/uv/src/win/process-stdio.c
+++ b/deps/uv/src/win/process-stdio.c
@@ -95,102 +95,6 @@ void uv_disable_stdio_inheritance(void) {
}
-static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
- uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
- char pipe_name[64];
- SECURITY_ATTRIBUTES sa;
- DWORD server_access = 0;
- DWORD client_access = 0;
- HANDLE child_pipe = INVALID_HANDLE_VALUE;
- int err;
- int overlap;
-
- if (flags & UV_READABLE_PIPE) {
- /* The server needs inbound access too, otherwise CreateNamedPipe() won't
- * give us the FILE_READ_ATTRIBUTES permission. We need that to probe the
- * state of the write buffer when we're trying to shutdown the pipe. */
- server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
- client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
- }
- if (flags & UV_WRITABLE_PIPE) {
- server_access |= PIPE_ACCESS_INBOUND;
- client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
- }
-
- /* Create server pipe handle. */
- err = uv_stdio_pipe_server(loop,
- server_pipe,
- server_access,
- pipe_name,
- sizeof(pipe_name));
- if (err)
- goto error;
-
- /* Create child pipe handle. */
- sa.nLength = sizeof sa;
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = TRUE;
-
- overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE);
- child_pipe = CreateFileA(pipe_name,
- client_access,
- 0,
- &sa,
- OPEN_EXISTING,
- overlap ? FILE_FLAG_OVERLAPPED : 0,
- NULL);
- if (child_pipe == INVALID_HANDLE_VALUE) {
- err = GetLastError();
- goto error;
- }
-
-#ifndef NDEBUG
- /* Validate that the pipe was opened in the right mode. */
- {
- DWORD mode;
- BOOL r = GetNamedPipeHandleState(child_pipe,
- &mode,
- NULL,
- NULL,
- NULL,
- NULL,
- 0);
- assert(r == TRUE);
- assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
- }
-#endif
-
- /* Do a blocking ConnectNamedPipe. This should not block because we have both
- * ends of the pipe created. */
- if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
- if (GetLastError() != ERROR_PIPE_CONNECTED) {
- err = GetLastError();
- goto error;
- }
- }
-
- /* The server end is now readable and/or writable. */
- if (flags & UV_READABLE_PIPE)
- server_pipe->flags |= UV_HANDLE_WRITABLE;
- if (flags & UV_WRITABLE_PIPE)
- server_pipe->flags |= UV_HANDLE_READABLE;
-
- *child_pipe_ptr = child_pipe;
- return 0;
-
- error:
- if (server_pipe->handle != INVALID_HANDLE_VALUE) {
- uv_pipe_cleanup(loop, server_pipe);
- }
-
- if (child_pipe != INVALID_HANDLE_VALUE) {
- CloseHandle(child_pipe);
- }
-
- return err;
-}
-
-
static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
HANDLE current_process;
diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c
index 46a0709a38..ebb5fe5cb7 100644
--- a/deps/uv/src/win/stream.c
+++ b/deps/uv/src/win/stream.c
@@ -65,18 +65,11 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
}
-int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
- uv_read_cb read_cb) {
+int uv__read_start(uv_stream_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_read_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_TCP:
diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c
index 0dcaa97df7..517700e66d 100644
--- a/deps/uv/src/win/tcp.c
+++ b/deps/uv/src/win/tcp.c
@@ -800,9 +800,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
if (err)
return err;
- if (handle->delayed_error) {
- return handle->delayed_error;
- }
+ if (handle->delayed_error != 0)
+ goto out;
if (!(handle->flags & UV_HANDLE_BOUND)) {
if (addrlen == sizeof(uv_addr_ip4_any_)) {
@@ -815,8 +814,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
if (err)
return err;
- if (handle->delayed_error)
- return handle->delayed_error;
+ if (handle->delayed_error != 0)
+ goto out;
}
if (!handle->tcp.conn.func_connectex) {
@@ -844,11 +843,21 @@ static int uv_tcp_try_connect(uv_connect_t* req,
NULL);
}
+out:
+
UV_REQ_INIT(req, UV_CONNECT);
req->handle = (uv_stream_t*) handle;
req->cb = cb;
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+ if (handle->delayed_error != 0) {
+ /* Process the req without IOCP. */
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ return 0;
+ }
+
success = handle->tcp.conn.func_connectex(handle->socket,
(const struct sockaddr*) &converted,
addrlen,
@@ -1215,7 +1224,14 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
UNREGISTER_HANDLE_REQ(loop, handle, req);
err = 0;
- if (REQ_SUCCESS(req)) {
+ if (handle->delayed_error) {
+ /* To smooth over the differences between unixes errors that
+ * were reported synchronously on the first connect can be delayed
+ * until the next tick--which is now.
+ */
+ err = handle->delayed_error;
+ handle->delayed_error = 0;
+ } else if (REQ_SUCCESS(req)) {
if (handle->flags & UV_HANDLE_CLOSING) {
/* use UV_ECANCELED for consistency with Unix */
err = ERROR_OPERATION_ABORTED;
@@ -1571,3 +1587,118 @@ int uv__tcp_connect(uv_connect_t* req,
return 0;
}
+
+#ifndef WSA_FLAG_NO_HANDLE_INHERIT
+/* Added in Windows 7 SP1. Specify this to avoid race conditions, */
+/* but also manually clear the inherit flag in case this failed. */
+#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
+#endif
+
+int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) {
+ SOCKET server = INVALID_SOCKET;
+ SOCKET client0 = INVALID_SOCKET;
+ SOCKET client1 = INVALID_SOCKET;
+ SOCKADDR_IN name;
+ LPFN_ACCEPTEX func_acceptex;
+ WSAOVERLAPPED overlap;
+ char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32];
+ int namelen;
+ int err;
+ DWORD bytes;
+ DWORD flags;
+ DWORD client0_flags = WSA_FLAG_NO_HANDLE_INHERIT;
+ DWORD client1_flags = WSA_FLAG_NO_HANDLE_INHERIT;
+
+ if (flags0 & UV_NONBLOCK_PIPE)
+ client0_flags |= WSA_FLAG_OVERLAPPED;
+ if (flags1 & UV_NONBLOCK_PIPE)
+ client1_flags |= WSA_FLAG_OVERLAPPED;
+
+ server = WSASocketW(AF_INET, type, protocol, NULL, 0,
+ WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT);
+ if (server == INVALID_SOCKET)
+ goto wsaerror;
+ if (!SetHandleInformation((HANDLE) server, HANDLE_FLAG_INHERIT, 0))
+ goto error;
+ name.sin_family = AF_INET;
+ name.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ name.sin_port = 0;
+ if (bind(server, (SOCKADDR*) &name, sizeof(name)) != 0)
+ goto wsaerror;
+ if (listen(server, 1) != 0)
+ goto wsaerror;
+ namelen = sizeof(name);
+ if (getsockname(server, (SOCKADDR*) &name, &namelen) != 0)
+ goto wsaerror;
+ client0 = WSASocketW(AF_INET, type, protocol, NULL, 0, client0_flags);
+ if (client0 == INVALID_SOCKET)
+ goto wsaerror;
+ if (!SetHandleInformation((HANDLE) client0, HANDLE_FLAG_INHERIT, 0))
+ goto error;
+ if (connect(client0, (SOCKADDR*) &name, sizeof(name)) != 0)
+ goto wsaerror;
+ client1 = WSASocketW(AF_INET, type, protocol, NULL, 0, client1_flags);
+ if (client1 == INVALID_SOCKET)
+ goto wsaerror;
+ if (!SetHandleInformation((HANDLE) client1, HANDLE_FLAG_INHERIT, 0))
+ goto error;
+ if (!uv_get_acceptex_function(server, &func_acceptex)) {
+ err = WSAEAFNOSUPPORT;
+ goto cleanup;
+ }
+ memset(&overlap, 0, sizeof(overlap));
+ if (!func_acceptex(server,
+ client1,
+ accept_buffer,
+ 0,
+ sizeof(struct sockaddr_storage),
+ sizeof(struct sockaddr_storage),
+ &bytes,
+ &overlap)) {
+ err = WSAGetLastError();
+ if (err == ERROR_IO_PENDING) {
+ /* Result should complete immediately, since we already called connect,
+ * but emperically, we sometimes have to poll the kernel a couple times
+ * until it notices that. */
+ while (!WSAGetOverlappedResult(client1, &overlap, &bytes, FALSE, &flags)) {
+ err = WSAGetLastError();
+ if (err != WSA_IO_INCOMPLETE)
+ goto cleanup;
+ SwitchToThread();
+ }
+ }
+ else {
+ goto cleanup;
+ }
+ }
+ if (setsockopt(client1, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ (char*) &server, sizeof(server)) != 0) {
+ goto wsaerror;
+ }
+
+ closesocket(server);
+
+ fds[0] = client0;
+ fds[1] = client1;
+
+ return 0;
+
+ wsaerror:
+ err = WSAGetLastError();
+ goto cleanup;
+
+ error:
+ err = GetLastError();
+ goto cleanup;
+
+ cleanup:
+ if (server != INVALID_SOCKET)
+ closesocket(server);
+ if (client0 != INVALID_SOCKET)
+ closesocket(client0);
+ if (client1 != INVALID_SOCKET)
+ closesocket(client1);
+
+ assert(err);
+ return uv_translate_sys_error(err);
+}
diff --git a/deps/uv/test/benchmark-pump.c b/deps/uv/test/benchmark-pump.c
index 8685258e05..7d3977dfc3 100644
--- a/deps/uv/test/benchmark-pump.c
+++ b/deps/uv/test/benchmark-pump.c
@@ -390,6 +390,7 @@ HELPER_IMPL(tcp_pump_server) {
r = uv_listen((uv_stream_t*)&tcpServer, MAX_WRITE_HANDLES, connection_cb);
ASSERT(r == 0);
+ notify_parent_process();
uv_run(loop, UV_RUN_DEFAULT);
return 0;
@@ -411,6 +412,7 @@ HELPER_IMPL(pipe_pump_server) {
r = uv_listen((uv_stream_t*)&pipeServer, MAX_WRITE_HANDLES, connection_cb);
ASSERT(r == 0);
+ notify_parent_process();
uv_run(loop, UV_RUN_DEFAULT);
MAKE_VALGRIND_HAPPY();
diff --git a/deps/uv/test/blackhole-server.c b/deps/uv/test/blackhole-server.c
index ad878b35c6..9b21d1e0e0 100644
--- a/deps/uv/test/blackhole-server.c
+++ b/deps/uv/test/blackhole-server.c
@@ -114,6 +114,7 @@ HELPER_IMPL(tcp4_blackhole_server) {
r = uv_listen((uv_stream_t*)&tcp_server, 128, connection_cb);
ASSERT(r == 0);
+ notify_parent_process();
r = uv_run(loop, UV_RUN_DEFAULT);
ASSERT(0 && "Blackhole server dropped out of event loop.");
diff --git a/deps/uv/test/echo-server.c b/deps/uv/test/echo-server.c
index c65142ff90..69d0abc980 100644
--- a/deps/uv/test/echo-server.c
+++ b/deps/uv/test/echo-server.c
@@ -209,6 +209,7 @@ static void on_recv(uv_udp_t* handle,
const struct sockaddr* addr,
unsigned flags) {
uv_buf_t sndbuf;
+ uv_udp_send_t* req;
if (nread == 0) {
/* Everything OK, but nothing read. */
@@ -218,7 +219,7 @@ static void on_recv(uv_udp_t* handle,
ASSERT(nread > 0);
ASSERT(addr->sa_family == AF_INET);
- uv_udp_send_t* req = send_alloc();
+ req = send_alloc();
ASSERT(req != NULL);
sndbuf = uv_buf_init(rcvbuf->base, nread);
ASSERT(0 <= uv_udp_send(req, handle, &sndbuf, 1, addr, on_send));
@@ -228,7 +229,7 @@ static int tcp4_echo_start(int port) {
struct sockaddr_in addr;
int r;
- ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr));
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", port, &addr));
server = (uv_handle_t*)&tcpServer;
serverType = TCP;
diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c
index e5e75e17c8..fc8a79a9eb 100644
--- a/deps/uv/test/run-tests.c
+++ b/deps/uv/test/run-tests.c
@@ -50,6 +50,10 @@ int spawn_tcp_server_helper(void);
static int maybe_run_test(int argc, char **argv);
+#ifdef _WIN32
+typedef BOOL (WINAPI *sCompareObjectHandles)(_In_ HANDLE, _In_ HANDLE);
+#endif
+
int main(int argc, char **argv) {
#ifndef _WIN32
@@ -202,22 +206,36 @@ static int maybe_run_test(int argc, char **argv) {
return 1;
}
-#ifndef _WIN32
if (strcmp(argv[1], "spawn_helper8") == 0) {
- int fd;
-
+ uv_os_fd_t closed_fd;
+ uv_os_fd_t open_fd;
+#ifdef _WIN32
+ DWORD flags;
+ HMODULE kernelbase_module;
+ sCompareObjectHandles pCompareObjectHandles; /* function introduced in Windows 10 */
+#endif
notify_parent_process();
- ASSERT(sizeof(fd) == read(0, &fd, sizeof(fd)));
- ASSERT(fd > 2);
+ ASSERT(sizeof(closed_fd) == read(0, &closed_fd, sizeof(closed_fd)));
+ ASSERT(sizeof(open_fd) == read(0, &open_fd, sizeof(open_fd)));
+#ifdef _WIN32
+ ASSERT((intptr_t) closed_fd > 0);
+ ASSERT((intptr_t) open_fd > 0);
+ ASSERT(0 != GetHandleInformation(open_fd, &flags));
+ kernelbase_module = GetModuleHandleA("kernelbase.dll");
+ pCompareObjectHandles = (sCompareObjectHandles)
+ GetProcAddress(kernelbase_module, "CompareObjectHandles");
+ ASSERT(pCompareObjectHandles == NULL || !pCompareObjectHandles(open_fd, closed_fd));
+#else
+ ASSERT(open_fd > 2);
+ ASSERT(closed_fd > 2);
# if defined(__PASE__) /* On IBMi PASE, write() returns 1 */
- ASSERT(1 == write(fd, "x", 1));
+ ASSERT(1 == write(closed_fd, "x", 1));
# else
- ASSERT(-1 == write(fd, "x", 1));
+ ASSERT(-1 == write(closed_fd, "x", 1));
# endif /* !__PASE__ */
-
+#endif
return 1;
}
-#endif /* !_WIN32 */
if (strcmp(argv[1], "spawn_helper9") == 0) {
notify_parent_process();
diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h
index 8250f949b2..4e7e2f07f5 100644
--- a/deps/uv/test/task.h
+++ b/deps/uv/test/task.h
@@ -113,8 +113,8 @@ typedef enum {
#define ASSERT_BASE(a, operator, b, type, conv) \
do { \
- type eval_a = (type) (a); \
- type eval_b = (type) (b); \
+ volatile type eval_a = (type) (a); \
+ volatile type eval_b = (type) (b); \
if (!(eval_a operator eval_b)) { \
fprintf(stderr, \
"Assertion failed in %s on line %d: `%s %s %s` " \
@@ -196,22 +196,26 @@ typedef enum {
} \
} while (0)
-#define ASSERT_INT_BASE(a, operator, b, type, conv) \
- ASSERT_BASE(a, operator, b, type, conv)
-
-#define ASSERT_EQ(a, b) ASSERT_INT_BASE(a, ==, b, int64_t, PRId64)
-#define ASSERT_GE(a, b) ASSERT_INT_BASE(a, >=, b, int64_t, PRId64)
-#define ASSERT_GT(a, b) ASSERT_INT_BASE(a, >, b, int64_t, PRId64)
-#define ASSERT_LE(a, b) ASSERT_INT_BASE(a, <=, b, int64_t, PRId64)
-#define ASSERT_LT(a, b) ASSERT_INT_BASE(a, <, b, int64_t, PRId64)
-#define ASSERT_NE(a, b) ASSERT_INT_BASE(a, !=, b, int64_t, PRId64)
-
-#define ASSERT_UINT64_EQ(a, b) ASSERT_INT_BASE(a, ==, b, uint64_t, PRIu64)
-#define ASSERT_UINT64_GE(a, b) ASSERT_INT_BASE(a, >=, b, uint64_t, PRIu64)
-#define ASSERT_UINT64_GT(a, b) ASSERT_INT_BASE(a, >, b, uint64_t, PRIu64)
-#define ASSERT_UINT64_LE(a, b) ASSERT_INT_BASE(a, <=, b, uint64_t, PRIu64)
-#define ASSERT_UINT64_LT(a, b) ASSERT_INT_BASE(a, <, b, uint64_t, PRIu64)
-#define ASSERT_UINT64_NE(a, b) ASSERT_INT_BASE(a, !=, b, uint64_t, PRIu64)
+#define ASSERT_EQ(a, b) ASSERT_BASE(a, ==, b, int64_t, PRId64)
+#define ASSERT_GE(a, b) ASSERT_BASE(a, >=, b, int64_t, PRId64)
+#define ASSERT_GT(a, b) ASSERT_BASE(a, >, b, int64_t, PRId64)
+#define ASSERT_LE(a, b) ASSERT_BASE(a, <=, b, int64_t, PRId64)
+#define ASSERT_LT(a, b) ASSERT_BASE(a, <, b, int64_t, PRId64)
+#define ASSERT_NE(a, b) ASSERT_BASE(a, !=, b, int64_t, PRId64)
+
+#define ASSERT_UINT64_EQ(a, b) ASSERT_BASE(a, ==, b, uint64_t, PRIu64)
+#define ASSERT_UINT64_GE(a, b) ASSERT_BASE(a, >=, b, uint64_t, PRIu64)
+#define ASSERT_UINT64_GT(a, b) ASSERT_BASE(a, >, b, uint64_t, PRIu64)
+#define ASSERT_UINT64_LE(a, b) ASSERT_BASE(a, <=, b, uint64_t, PRIu64)
+#define ASSERT_UINT64_LT(a, b) ASSERT_BASE(a, <, b, uint64_t, PRIu64)
+#define ASSERT_UINT64_NE(a, b) ASSERT_BASE(a, !=, b, uint64_t, PRIu64)
+
+#define ASSERT_DOUBLE_EQ(a, b) ASSERT_BASE(a, ==, b, double, "f")
+#define ASSERT_DOUBLE_GE(a, b) ASSERT_BASE(a, >=, b, double, "f")
+#define ASSERT_DOUBLE_GT(a, b) ASSERT_BASE(a, >, b, double, "f")
+#define ASSERT_DOUBLE_LE(a, b) ASSERT_BASE(a, <=, b, double, "f")
+#define ASSERT_DOUBLE_LT(a, b) ASSERT_BASE(a, <, b, double, "f")
+#define ASSERT_DOUBLE_NE(a, b) ASSERT_BASE(a, !=, b, double, "f")
#define ASSERT_STR_EQ(a, b) \
ASSERT_BASE_STR(strcmp(a, b) == 0, a, == , b, char*, "s")
diff --git a/deps/uv/test/test-close-fd.c b/deps/uv/test/test-close-fd.c
index cea4a1b0b8..0d3927f652 100644
--- a/deps/uv/test/test-close-fd.c
+++ b/deps/uv/test/test-close-fd.c
@@ -19,12 +19,11 @@
* IN THE SOFTWARE.
*/
-#if !defined(_WIN32)
-
#include "uv.h"
#include "task.h"
-#include <fcntl.h>
+#ifndef _WIN32
#include <unistd.h>
+#endif
static unsigned int read_cb_called;
@@ -51,14 +50,25 @@ static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
TEST_IMPL(close_fd) {
uv_pipe_t pipe_handle;
- int fd[2];
+ uv_fs_t req;
+ uv_buf_t bufs[1];
+ uv_file fd[2];
+ bufs[0] = uv_buf_init("", 1);
- ASSERT(0 == pipe(fd));
+ ASSERT(0 == uv_pipe(fd, 0, 0));
ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
- fd[0] = -1; /* uv_pipe_open() takes ownership of the file descriptor. */
- ASSERT(1 == write(fd[1], "", 1));
+ /* uv_pipe_open() takes ownership of the file descriptor. */
+ fd[0] = -1;
+
+ ASSERT(1 == uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL));
+ ASSERT(1 == req.result);
+ uv_fs_req_cleanup(&req);
+#ifdef _WIN32
+ ASSERT(0 == _close(fd[1]));
+#else
ASSERT(0 == close(fd[1]));
+#endif
fd[1] = -1;
ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb));
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
@@ -72,9 +82,3 @@ TEST_IMPL(close_fd) {
MAKE_VALGRIND_HAPPY();
return 0;
}
-
-#else
-
-typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
-
-#endif /* !_WIN32 */
diff --git a/deps/uv/test/test-error.c b/deps/uv/test/test-error.c
index 7f44f4a1bc..35d108a4a1 100644
--- a/deps/uv/test/test-error.c
+++ b/deps/uv/test/test-error.c
@@ -37,6 +37,9 @@
* See https://github.com/joyent/libuv/issues/210
*/
TEST_IMPL(error_message) {
+#if defined(__ASAN__)
+ RETURN_SKIP("Test does not currently work in ASAN");
+#endif
char buf[32];
/* Cop out. Can't do proper checks on systems with
diff --git a/deps/uv/test/test-fs-copyfile.c b/deps/uv/test/test-fs-copyfile.c
index c785a4b51f..fa00fe4ee8 100644
--- a/deps/uv/test/test-fs-copyfile.c
+++ b/deps/uv/test/test-fs-copyfile.c
@@ -96,6 +96,9 @@ static void touch_file(const char* name, unsigned int size) {
TEST_IMPL(fs_copyfile) {
+#if defined(__ASAN__)
+ RETURN_SKIP("Test does not currently work in ASAN");
+#endif
const char src[] = "test_file_src";
uv_loop_t* loop;
uv_fs_t req;
diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c
index 28a6a1ebb3..0992d5989e 100644
--- a/deps/uv/test/test-fs-event.c
+++ b/deps/uv/test/test-fs-event.c
@@ -674,6 +674,9 @@ TEST_IMPL(fs_event_watch_file_twice) {
#if defined(NO_FS_EVENTS)
RETURN_SKIP(NO_FS_EVENTS);
#endif
+#if defined(__ASAN__)
+ RETURN_SKIP("Test does not currently work in ASAN");
+#endif
const char path[] = "test/fixtures/empty_file";
uv_fs_event_t watchers[2];
uv_timer_t timer;
diff --git a/deps/uv/test/test-fs-readdir.c b/deps/uv/test/test-fs-readdir.c
index 5efc853cc6..cccaa7438b 100644
--- a/deps/uv/test/test-fs-readdir.c
+++ b/deps/uv/test/test-fs-readdir.c
@@ -230,6 +230,9 @@ static void file_opendir_cb(uv_fs_t* req) {
}
TEST_IMPL(fs_readdir_file) {
+#if defined(__ASAN__)
+ RETURN_SKIP("Test does not currently work in ASAN");
+#endif
const char* path;
int r;
diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c
index 63189d01d5..0292a96b48 100644
--- a/deps/uv/test/test-fs.c
+++ b/deps/uv/test/test-fs.c
@@ -673,7 +673,7 @@ static void stat_cb(uv_fs_t* req) {
static void sendfile_cb(uv_fs_t* req) {
ASSERT(req == &sendfile_req);
ASSERT(req->fs_type == UV_FS_SENDFILE);
- ASSERT(req->result == 65546);
+ ASSERT(req->result == 65545);
sendfile_cb_count++;
uv_fs_req_cleanup(req);
}
@@ -816,13 +816,44 @@ static void check_utime(const char* path,
else
r = uv_fs_stat(loop, &req, path, NULL);
- ASSERT(r == 0);
+ ASSERT_EQ(r, 0);
- ASSERT(req.result == 0);
+ ASSERT_EQ(req.result, 0);
s = &req.statbuf;
- ASSERT(s->st_atim.tv_sec + (s->st_atim.tv_nsec / 1000000000.0) == atime);
- ASSERT(s->st_mtim.tv_sec + (s->st_mtim.tv_nsec / 1000000000.0) == mtime);
+ if (s->st_atim.tv_nsec == 0 && s->st_mtim.tv_nsec == 0) {
+ /*
+ * Test sub-second timestamps only when supported (such as Windows with
+ * NTFS). Some other platforms support sub-second timestamps, but that
+ * support is filesystem-dependent. Notably OS X (HFS Plus) does NOT
+ * support sub-second timestamps. But kernels may round or truncate in
+ * either direction, so we may accept either possible answer.
+ */
+#ifdef _WIN32
+ ASSERT_DOUBLE_EQ(atime, (long) atime);
+ ASSERT_DOUBLE_EQ(mtime, (long) atime);
+#endif
+ if (atime > 0 || (long) atime == atime)
+ ASSERT_EQ(s->st_atim.tv_sec, (long) atime);
+ if (mtime > 0 || (long) mtime == mtime)
+ ASSERT_EQ(s->st_mtim.tv_sec, (long) mtime);
+ ASSERT_GE(s->st_atim.tv_sec, (long) atime - 1);
+ ASSERT_GE(s->st_mtim.tv_sec, (long) mtime - 1);
+ ASSERT_LE(s->st_atim.tv_sec, (long) atime);
+ ASSERT_LE(s->st_mtim.tv_sec, (long) mtime);
+ } else {
+ double st_atim;
+ double st_mtim;
+#ifndef __APPLE__
+ /* TODO(vtjnash): would it be better to normalize this? */
+ ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0);
+ ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0);
+#endif
+ st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9;
+ st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9;
+ ASSERT_DOUBLE_EQ(st_atim, atime);
+ ASSERT_DOUBLE_EQ(st_mtim, mtime);
+ }
uv_fs_req_cleanup(&req);
}
@@ -1159,6 +1190,8 @@ TEST_IMPL(fs_async_dir) {
static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) {
int f, r;
struct stat s1, s2;
+ uv_fs_t req;
+ char buf1[1];
loop = uv_default_loop();
@@ -1188,7 +1221,7 @@ static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) {
uv_fs_req_cleanup(&open_req2);
r = uv_fs_sendfile(loop, &sendfile_req, open_req2.result, open_req1.result,
- 0, 131072, cb);
+ 1, 131072, cb);
ASSERT(r == 0);
uv_run(loop, UV_RUN_DEFAULT);
@@ -1203,9 +1236,26 @@ static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) {
ASSERT(0 == stat("test_file", &s1));
ASSERT(0 == stat("test_file2", &s2));
- ASSERT(s1.st_size == s2.st_size);
ASSERT(s2.st_size == expected_size);
+ if (expected_size > 0) {
+ ASSERT_UINT64_EQ(s1.st_size, s2.st_size + 1);
+ r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ memset(buf1, 0, sizeof(buf1));
+ iov = uv_buf_init(buf1, sizeof(buf1));
+ r = uv_fs_read(NULL, &req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ ASSERT_EQ(buf1[0], 'e'); /* 'e' from begin */
+ uv_fs_req_cleanup(&req);
+ } else {
+ ASSERT_UINT64_EQ(s1.st_size, s2.st_size);
+ }
+
/* Cleanup. */
unlink("test_file");
unlink("test_file2");
@@ -1223,7 +1273,7 @@ static void sendfile_setup(int f) {
TEST_IMPL(fs_async_sendfile) {
- return test_sendfile(sendfile_setup, sendfile_cb, 65546);
+ return test_sendfile(sendfile_setup, sendfile_cb, 65545);
}
@@ -2523,29 +2573,16 @@ TEST_IMPL(fs_utime) {
uv_fs_req_cleanup(&req);
uv_fs_close(loop, &req, r, NULL);
- atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
-
- /*
- * Test sub-second timestamps only on Windows (assuming NTFS). Some other
- * platforms support sub-second timestamps, but that support is filesystem-
- * dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps.
- */
-#ifdef _WIN32
- mtime += 0.444; /* 1982-09-10 11:22:33.444 */
-#endif
+ atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
ASSERT(r == 0);
ASSERT(req.result == 0);
uv_fs_req_cleanup(&req);
- r = uv_fs_stat(NULL, &req, path, NULL);
- ASSERT(r == 0);
- ASSERT(req.result == 0);
check_utime(path, atime, mtime, /* test_lutime */ 0);
- uv_fs_req_cleanup(&req);
- atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
+ atime = mtime = 1291404900.25; /* 2010-12-03 20:35:00.25 - mees <3 */
checkme.path = path;
checkme.atime = atime;
checkme.mtime = mtime;
@@ -2565,6 +2602,45 @@ TEST_IMPL(fs_utime) {
}
+TEST_IMPL(fs_utime_round) {
+ const char path[] = "test_file";
+ double atime;
+ double mtime;
+ uv_fs_t req;
+ int r;
+
+ loop = uv_default_loop();
+ unlink(path);
+ r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL);
+ ASSERT_GE(r, 0);
+ ASSERT_GE(req.result, 0);
+ uv_fs_req_cleanup(&req);
+ ASSERT_EQ(0, uv_fs_close(loop, &req, r, NULL));
+
+ atime = mtime = -14245440.25; /* 1969-07-20T02:56:00.25Z */
+
+ r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
+#if !defined(__linux__) && \
+ !defined(_WIN32) && \
+ !defined(__APPLE__) && \
+ !defined(__FreeBSD__) && \
+ !defined(__sun)
+ if (r != 0) {
+ ASSERT_EQ(r, UV_EINVAL);
+ RETURN_SKIP("utime on some OS (z/OS, IBM i PASE, AIX) or filesystems may reject pre-epoch timestamps");
+ }
+#endif
+ ASSERT_EQ(0, r);
+ ASSERT_EQ(0, req.result);
+ uv_fs_req_cleanup(&req);
+ check_utime(path, atime, mtime, /* test_lutime */ 0);
+ unlink(path);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
#ifdef _WIN32
TEST_IMPL(fs_stat_root) {
int r;
@@ -2618,16 +2694,7 @@ TEST_IMPL(fs_futime) {
uv_fs_req_cleanup(&req);
uv_fs_close(loop, &req, r, NULL);
- atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
-
- /*
- * Test sub-second timestamps only on Windows (assuming NTFS). Some other
- * platforms support sub-second timestamps, but that support is filesystem-
- * dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps.
- */
-#ifdef _WIN32
- mtime += 0.444; /* 1982-09-10 11:22:33.444 */
-#endif
+ atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
r = uv_fs_open(NULL, &req, path, O_RDWR, 0, NULL);
ASSERT(r >= 0);
@@ -2645,11 +2712,7 @@ TEST_IMPL(fs_futime) {
#endif
uv_fs_req_cleanup(&req);
- r = uv_fs_stat(NULL, &req, path, NULL);
- ASSERT(r == 0);
- ASSERT(req.result == 0);
check_utime(path, atime, mtime, /* test_lutime */ 0);
- uv_fs_req_cleanup(&req);
atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
@@ -2708,11 +2771,7 @@ TEST_IMPL(fs_lutime) {
uv_fs_req_cleanup(&req);
/* Test the synchronous version. */
- atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
-
-#ifdef _WIN32
- mtime += 0.444; /* 1982-09-10 11:22:33.444 */
-#endif
+ atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
checkme.atime = atime;
checkme.mtime = mtime;
@@ -2837,6 +2896,9 @@ TEST_IMPL(fs_scandir_non_existent_dir) {
}
TEST_IMPL(fs_scandir_file) {
+#if defined(__ASAN__)
+ RETURN_SKIP("Test does not currently work in ASAN");
+#endif
const char* path;
int r;
@@ -3083,6 +3145,9 @@ static void fs_read_bufs(int add_flags) {
uv_fs_req_cleanup(&close_req);
}
TEST_IMPL(fs_read_bufs) {
+#if defined(__ASAN__)
+ RETURN_SKIP("Test does not currently work in ASAN");
+#endif
fs_read_bufs(0);
fs_read_bufs(UV_FS_O_FILEMAP);
@@ -4372,6 +4437,7 @@ TEST_IMPL(fs_invalid_mkdir_name) {
loop = uv_default_loop();
r = uv_fs_mkdir(loop, &req, "invalid>", 0, NULL);
ASSERT(r == UV_EINVAL);
+ ASSERT_EQ(UV_EINVAL, uv_fs_mkdir(loop, &req, "test:lol", 0, NULL));
return 0;
}
diff --git a/deps/uv/test/test-getaddrinfo.c b/deps/uv/test/test-getaddrinfo.c
index 628e4d13cc..b1fc312349 100644
--- a/deps/uv/test/test-getaddrinfo.c
+++ b/deps/uv/test/test-getaddrinfo.c
@@ -100,7 +100,7 @@ TEST_IMPL(getaddrinfo_fail) {
ASSERT(0 == uv_getaddrinfo(uv_default_loop(),
&req,
getaddrinfo_fail_cb,
- "xyzzy.xyzzy.xyzzy.",
+ "example.invalid.",
NULL,
NULL));
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
@@ -122,7 +122,7 @@ TEST_IMPL(getaddrinfo_fail_sync) {
ASSERT(0 > uv_getaddrinfo(uv_default_loop(),
&req,
NULL,
- "xyzzy.xyzzy.xyzzy.",
+ "example.invalid.",
NULL,
NULL));
uv_freeaddrinfo(req.addrinfo);
diff --git a/deps/uv/test/test-ipc.c b/deps/uv/test/test-ipc.c
index 39ef4f1175..ba3ba73748 100644
--- a/deps/uv/test/test-ipc.c
+++ b/deps/uv/test/test-ipc.c
@@ -693,6 +693,11 @@ static void ipc_on_connection(uv_stream_t* server, int status) {
}
+static void close_and_free_cb(uv_handle_t* handle) {
+ close_cb_called++;
+ free(handle);
+}
+
static void ipc_on_connection_tcp_conn(uv_stream_t* server, int status) {
int r;
uv_buf_t buf;
@@ -721,7 +726,7 @@ static void ipc_on_connection_tcp_conn(uv_stream_t* server, int status) {
on_tcp_child_process_read);
ASSERT_EQ(r, 0);
- uv_close((uv_handle_t*)conn, close_cb);
+ uv_close((uv_handle_t*)conn, close_and_free_cb);
}
diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h
index 52b17a6914..d7c7b086f0 100644
--- a/deps/uv/test/test-list.h
+++ b/deps/uv/test/test-list.h
@@ -116,7 +116,8 @@ TEST_DECLARE (tcp_open_bound)
TEST_DECLARE (tcp_open_connected)
TEST_DECLARE (tcp_connect_error_after_write)
TEST_DECLARE (tcp_shutdown_after_write)
-TEST_DECLARE (tcp_bind_error_addrinuse)
+TEST_DECLARE (tcp_bind_error_addrinuse_connect)
+TEST_DECLARE (tcp_bind_error_addrinuse_listen)
TEST_DECLARE (tcp_bind_error_addrnotavail_1)
TEST_DECLARE (tcp_bind_error_addrnotavail_2)
TEST_DECLARE (tcp_bind_error_fault)
@@ -359,6 +360,7 @@ TEST_DECLARE (fs_open_flags)
TEST_DECLARE (fs_fd_hash)
#endif
TEST_DECLARE (fs_utime)
+TEST_DECLARE (fs_utime_round)
TEST_DECLARE (fs_futime)
TEST_DECLARE (fs_lutime)
TEST_DECLARE (fs_file_open_append)
@@ -451,12 +453,16 @@ TEST_DECLARE (poll_nested_epoll)
#ifdef UV_HAVE_KQUEUE
TEST_DECLARE (poll_nested_kqueue)
#endif
+TEST_DECLARE (poll_multiple_handles)
TEST_DECLARE (ip4_addr)
TEST_DECLARE (ip6_addr_link_local)
TEST_DECLARE (poll_close_doesnt_corrupt_stack)
TEST_DECLARE (poll_closesocket)
+TEST_DECLARE (close_fd)
+TEST_DECLARE (closed_fd_events)
+TEST_DECLARE (spawn_fs_open)
#ifdef _WIN32
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
#if !defined(USING_UV_SHARED)
@@ -471,8 +477,6 @@ TEST_DECLARE (ipc_listen_after_bind_twice)
TEST_DECLARE (win32_signum_number)
#else
TEST_DECLARE (emfile)
-TEST_DECLARE (close_fd)
-TEST_DECLARE (spawn_fs_open)
TEST_DECLARE (spawn_setuid_setgid)
TEST_DECLARE (we_get_signal)
TEST_DECLARE (we_get_signals)
@@ -481,7 +485,6 @@ TEST_DECLARE (we_get_signals_mixed)
TEST_DECLARE (signal_multiple_loops)
TEST_DECLARE (signal_pending_on_close)
TEST_DECLARE (signal_close_loop_alive)
-TEST_DECLARE (closed_fd_events)
#endif
#ifdef __APPLE__
TEST_DECLARE (osx_select)
@@ -567,7 +570,8 @@ TASK_LIST_START
#ifndef _WIN32
TEST_ENTRY (pipe_close_stdout_read_stdin)
#endif
- TEST_ENTRY (pipe_set_non_blocking)
+ /* Seems to be either about 0.5s or 5s, depending on the OS. */
+ TEST_ENTRY_CUSTOM (pipe_set_non_blocking, 0, 0, 20000)
TEST_ENTRY (pipe_set_chmod)
TEST_ENTRY (tty)
#ifdef _WIN32
@@ -671,7 +675,13 @@ TASK_LIST_START
TEST_HELPER (tcp_shutdown_after_write, tcp4_echo_server)
TEST_ENTRY (tcp_connect_error_after_write)
- TEST_ENTRY (tcp_bind_error_addrinuse)
+ TEST_ENTRY (tcp_bind_error_addrinuse_connect)
+ /* tcp4_echo_server steals the port. It needs to be a separate process
+ * because libuv sets setsockopt(SO_REUSEADDR) that lets you steal an
+ * existing bind if it originates from the same process.
+ */
+ TEST_HELPER (tcp_bind_error_addrinuse_connect, tcp4_echo_server)
+ TEST_ENTRY (tcp_bind_error_addrinuse_listen)
TEST_ENTRY (tcp_bind_error_addrnotavail_1)
TEST_ENTRY (tcp_bind_error_addrnotavail_2)
TEST_ENTRY (tcp_bind_error_fault)
@@ -894,6 +904,7 @@ TASK_LIST_START
#ifdef UV_HAVE_KQUEUE
TEST_ENTRY (poll_nested_kqueue)
#endif
+ TEST_ENTRY (poll_multiple_handles)
TEST_ENTRY (socket_buffer_size)
@@ -935,6 +946,9 @@ TASK_LIST_START
TEST_ENTRY (poll_close_doesnt_corrupt_stack)
TEST_ENTRY (poll_closesocket)
+ TEST_ENTRY (close_fd)
+ TEST_ENTRY (closed_fd_events)
+ TEST_ENTRY (spawn_fs_open)
#ifdef _WIN32
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
#if !defined(USING_UV_SHARED)
@@ -949,8 +963,6 @@ TASK_LIST_START
TEST_ENTRY (win32_signum_number)
#else
TEST_ENTRY (emfile)
- TEST_ENTRY (close_fd)
- TEST_ENTRY (spawn_fs_open)
TEST_ENTRY (spawn_setuid_setgid)
TEST_ENTRY (we_get_signal)
TEST_ENTRY (we_get_signals)
@@ -959,7 +971,6 @@ TASK_LIST_START
TEST_ENTRY (signal_multiple_loops)
TEST_ENTRY (signal_pending_on_close)
TEST_ENTRY (signal_close_loop_alive)
- TEST_ENTRY (closed_fd_events)
#endif
#ifdef __APPLE__
@@ -988,6 +999,7 @@ TASK_LIST_START
#endif
TEST_ENTRY (fs_chown)
TEST_ENTRY (fs_utime)
+ TEST_ENTRY (fs_utime_round)
TEST_ENTRY (fs_futime)
TEST_ENTRY (fs_lutime)
TEST_ENTRY (fs_readlink)
diff --git a/deps/uv/test/test-ping-pong.c b/deps/uv/test/test-ping-pong.c
index 7f7758b3b2..4a26e4dee1 100644
--- a/deps/uv/test/test-ping-pong.c
+++ b/deps/uv/test/test-ping-pong.c
@@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h> /* strlen */
static int completed_pingers = 0;
@@ -33,23 +34,21 @@ static int completed_pingers = 0;
#define NUM_PINGS 1000
#endif
-/* 64 bytes is enough for a pinger */
-#define BUFSIZE 10240
-
static char PING[] = "PING\n";
+static char PONG[] = "PONG\n";
static int pinger_on_connect_count;
typedef struct {
int vectored_writes;
- int pongs;
- int state;
+ unsigned pongs;
+ unsigned state;
union {
uv_tcp_t tcp;
uv_pipe_t pipe;
} stream;
uv_connect_t connect_req;
- char read_buffer[BUFSIZE];
+ char* pong;
} pinger_t;
@@ -59,28 +58,44 @@ static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
}
+static void ponger_on_close(uv_handle_t* handle) {
+ if (handle->data)
+ free(handle->data);
+ else
+ free(handle);
+}
+
+
static void pinger_on_close(uv_handle_t* handle) {
- pinger_t* pinger = (pinger_t*)handle->data;
+ pinger_t* pinger = (pinger_t*) handle->data;
- ASSERT(NUM_PINGS == pinger->pongs);
+ ASSERT_EQ(NUM_PINGS, pinger->pongs);
- free(pinger);
+ if (handle == (uv_handle_t*) &pinger->stream.tcp) {
+ free(pinger); /* also frees handle */
+ } else {
+ uv_close((uv_handle_t*) &pinger->stream.tcp, ponger_on_close);
+ free(handle);
+ }
completed_pingers++;
}
static void pinger_after_write(uv_write_t* req, int status) {
- ASSERT(status == 0);
+ ASSERT_EQ(status, 0);
free(req);
}
static void pinger_write_ping(pinger_t* pinger) {
+ uv_stream_t* stream;
uv_write_t* req;
uv_buf_t bufs[sizeof PING - 1];
int i, nbufs;
+ stream = (uv_stream_t*) &pinger->stream.tcp;
+
if (!pinger->vectored_writes) {
/* Write a single buffer. */
nbufs = 1;
@@ -94,13 +109,8 @@ static void pinger_write_ping(pinger_t* pinger) {
}
req = malloc(sizeof(*req));
- if (uv_write(req,
- (uv_stream_t*) &pinger->stream.tcp,
- bufs,
- nbufs,
- pinger_after_write)) {
- FATAL("uv_write failed");
- }
+ ASSERT_NOT_NULL(req);
+ ASSERT_EQ(0, uv_write(req, stream, bufs, nbufs, pinger_after_write));
puts("PING");
}
@@ -115,20 +125,20 @@ static void pinger_read_cb(uv_stream_t* stream,
pinger = (pinger_t*) stream->data;
if (nread < 0) {
- ASSERT(nread == UV_EOF);
+ ASSERT_EQ(nread, UV_EOF);
puts("got EOF");
free(buf->base);
- uv_close((uv_handle_t*)(&pinger->stream.tcp), pinger_on_close);
+ uv_close((uv_handle_t*) stream, pinger_on_close);
return;
}
- /* Now we count the pings */
+ /* Now we count the pongs */
for (i = 0; i < nread; i++) {
- ASSERT(buf->base[i] == PING[pinger->state]);
- pinger->state = (pinger->state + 1) % (sizeof(PING) - 1);
+ ASSERT_EQ(buf->base[i], pinger->pong[pinger->state]);
+ pinger->state = (pinger->state + 1) % strlen(pinger->pong);
if (pinger->state != 0)
continue;
@@ -139,7 +149,7 @@ static void pinger_read_cb(uv_stream_t* stream,
if (pinger->pongs < NUM_PINGS) {
pinger_write_ping(pinger);
} else {
- uv_close((uv_handle_t*)(&pinger->stream.tcp), pinger_on_close);
+ uv_close((uv_handle_t*) stream, pinger_on_close);
break;
}
}
@@ -148,20 +158,53 @@ static void pinger_read_cb(uv_stream_t* stream,
}
+static void ponger_read_cb(uv_stream_t* stream,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_buf_t writebuf;
+ uv_write_t* req;
+ int i;
+
+ if (nread < 0) {
+ ASSERT_EQ(nread, UV_EOF);
+
+ puts("got EOF");
+ free(buf->base);
+
+ uv_close((uv_handle_t*) stream, ponger_on_close);
+
+ return;
+ }
+
+ /* Echo back */
+ for (i = 0; i < nread; i++) {
+ if (buf->base[i] == 'I')
+ buf->base[i] = 'O';
+ }
+
+ writebuf = uv_buf_init(buf->base, nread);
+ req = malloc(sizeof(*req));
+ ASSERT_NOT_NULL(req);
+ ASSERT_EQ(0, uv_write(req, stream, &writebuf, 1, pinger_after_write));
+}
+
+
static void pinger_on_connect(uv_connect_t* req, int status) {
- pinger_t* pinger = (pinger_t*)req->handle->data;
+ pinger_t* pinger = (pinger_t*) req->handle->data;
pinger_on_connect_count++;
- ASSERT(status == 0);
+ ASSERT_EQ(status, 0);
- ASSERT(1 == uv_is_readable(req->handle));
- ASSERT(1 == uv_is_writable(req->handle));
- ASSERT(0 == uv_is_closing((uv_handle_t *) req->handle));
+ ASSERT_EQ(1, uv_is_readable(req->handle));
+ ASSERT_EQ(1, uv_is_writable(req->handle));
+ ASSERT_EQ(0, uv_is_closing((uv_handle_t *) req->handle));
pinger_write_ping(pinger);
- uv_read_start((uv_stream_t*)(req->handle), alloc_cb, pinger_read_cb);
+ ASSERT_EQ(0, uv_read_start((uv_stream_t*) req->handle,
+ alloc_cb,
+ pinger_read_cb));
}
@@ -172,17 +215,18 @@ static void tcp_pinger_v6_new(int vectored_writes) {
pinger_t* pinger;
- ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &server_addr));
+ ASSERT_EQ(0, uv_ip6_addr("::1", TEST_PORT, &server_addr));
pinger = malloc(sizeof(*pinger));
- ASSERT(pinger != NULL);
+ ASSERT_NOT_NULL(pinger);
pinger->vectored_writes = vectored_writes;
pinger->state = 0;
pinger->pongs = 0;
+ pinger->pong = PING;
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
pinger->stream.tcp.data = pinger;
- ASSERT(!r);
+ ASSERT_EQ(0, r);
/* We are never doing multiple reads/connects at a time anyway, so these
* handles can be pre-initialized. */
@@ -190,10 +234,10 @@ static void tcp_pinger_v6_new(int vectored_writes) {
&pinger->stream.tcp,
(const struct sockaddr*) &server_addr,
pinger_on_connect);
- ASSERT(!r);
+ ASSERT_EQ(0, r);
/* Synchronous connect callbacks are not allowed. */
- ASSERT(pinger_on_connect_count == 0);
+ ASSERT_EQ(pinger_on_connect_count, 0);
}
@@ -202,17 +246,18 @@ static void tcp_pinger_new(int vectored_writes) {
struct sockaddr_in server_addr;
pinger_t* pinger;
- ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+ ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
pinger = malloc(sizeof(*pinger));
- ASSERT(pinger != NULL);
+ ASSERT_NOT_NULL(pinger);
pinger->vectored_writes = vectored_writes;
pinger->state = 0;
pinger->pongs = 0;
+ pinger->pong = PING;
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
pinger->stream.tcp.data = pinger;
- ASSERT(!r);
+ ASSERT_EQ(0, r);
/* We are never doing multiple reads/connects at a time anyway, so these
* handles can be pre-initialized. */
@@ -220,10 +265,10 @@ static void tcp_pinger_new(int vectored_writes) {
&pinger->stream.tcp,
(const struct sockaddr*) &server_addr,
pinger_on_connect);
- ASSERT(!r);
+ ASSERT_EQ(0, r);
/* Synchronous connect callbacks are not allowed. */
- ASSERT(pinger_on_connect_count == 0);
+ ASSERT_EQ(pinger_on_connect_count, 0);
}
@@ -232,15 +277,16 @@ static void pipe_pinger_new(int vectored_writes) {
pinger_t* pinger;
pinger = malloc(sizeof(*pinger));
- ASSERT(pinger != NULL);
+ ASSERT_NOT_NULL(pinger);
pinger->vectored_writes = vectored_writes;
pinger->state = 0;
pinger->pongs = 0;
+ pinger->pong = PING;
/* Try to connect to the server and do NUM_PINGS ping-pongs. */
r = uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0);
pinger->stream.pipe.data = pinger;
- ASSERT(!r);
+ ASSERT_EQ(0, r);
/* We are never doing multiple reads/connects at a time anyway, so these
* handles can be pre-initialized. */
@@ -248,13 +294,86 @@ static void pipe_pinger_new(int vectored_writes) {
pinger_on_connect);
/* Synchronous connect callbacks are not allowed. */
- ASSERT(pinger_on_connect_count == 0);
+ ASSERT_EQ(pinger_on_connect_count, 0);
}
+static void socketpair_pinger_new(int vectored_writes) {
+ pinger_t* pinger;
+ uv_os_sock_t fds[2];
+ uv_tcp_t* ponger;
+
+ pinger = malloc(sizeof(*pinger));
+ ASSERT_NOT_NULL(pinger);
+ pinger->vectored_writes = vectored_writes;
+ pinger->state = 0;
+ pinger->pongs = 0;
+ pinger->pong = PONG;
+
+ /* Try to make a socketpair and do NUM_PINGS ping-pongs. */
+ (void)uv_default_loop(); /* ensure WSAStartup has been performed */
+ ASSERT_EQ(0, uv_socketpair(SOCK_STREAM, 0, fds, UV_NONBLOCK_PIPE, UV_NONBLOCK_PIPE));
+#ifndef _WIN32
+ /* On Windows, this is actually a UV_TCP, but libuv doesn't detect that. */
+ ASSERT_EQ(uv_guess_handle((uv_file) fds[0]), UV_NAMED_PIPE);
+ ASSERT_EQ(uv_guess_handle((uv_file) fds[1]), UV_NAMED_PIPE);
+#endif
+
+ ASSERT_EQ(0, uv_tcp_init(uv_default_loop(), &pinger->stream.tcp));
+ pinger->stream.pipe.data = pinger;
+ ASSERT_EQ(0, uv_tcp_open(&pinger->stream.tcp, fds[1]));
+
+ ponger = malloc(sizeof(*ponger));
+ ASSERT_NOT_NULL(ponger);
+ ponger->data = NULL;
+ ASSERT_EQ(0, uv_tcp_init(uv_default_loop(), ponger));
+ ASSERT_EQ(0, uv_tcp_open(ponger, fds[0]));
+
+ pinger_write_ping(pinger);
+
+ ASSERT_EQ(0, uv_read_start((uv_stream_t*) &pinger->stream.tcp,
+ alloc_cb,
+ pinger_read_cb));
+ ASSERT_EQ(0, uv_read_start((uv_stream_t*) ponger,
+ alloc_cb,
+ ponger_read_cb));
+}
+
+
+static void pipe2_pinger_new(int vectored_writes) {
+ uv_file fds[2];
+ pinger_t* pinger;
+ uv_pipe_t* ponger;
+
+ /* Try to make a pipe and do NUM_PINGS pings. */
+ ASSERT_EQ(0, uv_pipe(fds, UV_NONBLOCK_PIPE, UV_NONBLOCK_PIPE));
+ ASSERT_EQ(uv_guess_handle(fds[0]), UV_NAMED_PIPE);
+ ASSERT_EQ(uv_guess_handle(fds[1]), UV_NAMED_PIPE);
+
+ ponger = malloc(sizeof(*ponger));
+ ASSERT_NOT_NULL(ponger);
+ ASSERT_EQ(0, uv_pipe_init(uv_default_loop(), ponger, 0));
+ ASSERT_EQ(0, uv_pipe_open(ponger, fds[0]));
+
+ pinger = malloc(sizeof(*pinger));
+ ASSERT_NOT_NULL(pinger);
+ pinger->vectored_writes = vectored_writes;
+ pinger->state = 0;
+ pinger->pongs = 0;
+ pinger->pong = PING;
+ ASSERT_EQ(0, uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0));
+ ASSERT_EQ(0, uv_pipe_open(&pinger->stream.pipe, fds[1]));
+ pinger->stream.pipe.data = pinger; /* record for close_cb */
+ ponger->data = pinger; /* record for read_cb */
+
+ pinger_write_ping(pinger);
+
+ ASSERT_EQ(0, uv_read_start((uv_stream_t*) ponger, alloc_cb, pinger_read_cb));
+}
+
static int run_ping_pong_test(void) {
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
- ASSERT(completed_pingers == 1);
+ ASSERT_EQ(completed_pingers, 1);
MAKE_VALGRIND_HAPPY();
return 0;
@@ -263,12 +382,20 @@ static int run_ping_pong_test(void) {
TEST_IMPL(tcp_ping_pong) {
tcp_pinger_new(0);
+ run_ping_pong_test();
+
+ completed_pingers = 0;
+ socketpair_pinger_new(0);
return run_ping_pong_test();
}
TEST_IMPL(tcp_ping_pong_vec) {
tcp_pinger_new(1);
+ run_ping_pong_test();
+
+ completed_pingers = 0;
+ socketpair_pinger_new(1);
return run_ping_pong_test();
}
@@ -291,11 +418,19 @@ TEST_IMPL(tcp6_ping_pong_vec) {
TEST_IMPL(pipe_ping_pong) {
pipe_pinger_new(0);
+ run_ping_pong_test();
+
+ completed_pingers = 0;
+ pipe2_pinger_new(0);
return run_ping_pong_test();
}
TEST_IMPL(pipe_ping_pong_vec) {
pipe_pinger_new(1);
+ run_ping_pong_test();
+
+ completed_pingers = 0;
+ pipe2_pinger_new(1);
return run_ping_pong_test();
}
diff --git a/deps/uv/test/test-pipe-connect-error.c b/deps/uv/test/test-pipe-connect-error.c
index ebb2a6ca82..8bba328a34 100644
--- a/deps/uv/test/test-pipe-connect-error.c
+++ b/deps/uv/test/test-pipe-connect-error.c
@@ -76,6 +76,9 @@ TEST_IMPL(pipe_connect_bad_name) {
TEST_IMPL(pipe_connect_to_file) {
+#if defined(__ASAN__)
+ RETURN_SKIP("Test does not currently work in ASAN");
+#endif
const char* path = "test/fixtures/empty_file";
uv_pipe_t client;
uv_connect_t req;
diff --git a/deps/uv/test/test-pipe-getsockname.c b/deps/uv/test/test-pipe-getsockname.c
index 48ee400e74..5f377dcbb6 100644
--- a/deps/uv/test/test-pipe-getsockname.c
+++ b/deps/uv/test/test-pipe-getsockname.c
@@ -225,7 +225,9 @@ TEST_IMPL(pipe_getsockname_blocking) {
ASSERT(r != -1);
r = uv_pipe_open(&pipe_client, readfd);
ASSERT(r == 0);
- r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
+ r = uv_read_start((uv_stream_t*) &pipe_client,
+ (uv_alloc_cb) abort,
+ (uv_read_cb) abort);
ASSERT(r == 0);
Sleep(100);
r = uv_read_stop((uv_stream_t*)&pipe_client);
@@ -236,7 +238,9 @@ TEST_IMPL(pipe_getsockname_blocking) {
ASSERT(r == 0);
ASSERT(len1 == 0); /* It's an annonymous pipe. */
- r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
+ r = uv_read_start((uv_stream_t*)&pipe_client,
+ (uv_alloc_cb) abort,
+ (uv_read_cb) abort);
ASSERT(r == 0);
Sleep(100);
diff --git a/deps/uv/test/test-pipe-set-non-blocking.c b/deps/uv/test/test-pipe-set-non-blocking.c
index 626b53f09a..c45148f2bd 100644
--- a/deps/uv/test/test-pipe-set-non-blocking.c
+++ b/deps/uv/test/test-pipe-set-non-blocking.c
@@ -16,18 +16,10 @@
#include "uv.h"
#include "task.h"
-#ifdef _WIN32
-
-TEST_IMPL(pipe_set_non_blocking) {
- RETURN_SKIP("Test not implemented on Windows.");
-}
-
-#else /* !_WIN32 */
-
#include <string.h> /* memset */
+#ifndef _WIN32
#include <unistd.h> /* close */
-#include <sys/types.h>
-#include <sys/socket.h>
+#endif
struct thread_ctx {
uv_barrier_t barrier;
@@ -54,8 +46,27 @@ static void thread_main(void* arg) {
uv_fs_req_cleanup(&req);
} while (n > 0 || (n == -1 && uv_errno == UV_EINTR));
+#ifdef _WIN32
+ ASSERT(n == UV_EOF);
+#else
ASSERT(n == 0);
+#endif
+}
+
+
+#ifdef _WIN32
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ req->handle = NULL; /* signal completion of write_cb */
}
+#endif
+
+#ifdef _WIN32
+#define NWRITES (10 << 16)
+#else
+#define NWRITES (10 << 20)
+#endif
+
TEST_IMPL(pipe_set_non_blocking) {
struct thread_ctx ctx;
@@ -66,9 +77,12 @@ TEST_IMPL(pipe_set_non_blocking) {
uv_buf_t buf;
uv_file fd[2];
int n;
+#ifdef _WIN32
+ uv_write_t write_req;
+#endif
ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
- ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fd));
+ ASSERT(0 == uv_pipe(fd, 0, 0));
ASSERT(0 == uv_pipe_open(&pipe_handle, fd[1]));
ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &pipe_handle, 1));
fd[1] = -1; /* fd[1] is owned by pipe_handle now. */
@@ -83,11 +97,20 @@ TEST_IMPL(pipe_set_non_blocking) {
memset(data, '.', sizeof(data));
nwritten = 0;
- while (nwritten < 10 << 20) {
+ while (nwritten < NWRITES) {
/* The stream is in blocking mode so uv_try_write() should always succeed
* with the exact number of bytes that we wanted written.
*/
n = uv_try_write((uv_stream_t*) &pipe_handle, &buf, 1);
+#ifdef _WIN32
+ ASSERT(n == UV_EAGAIN); /* E_NOTIMPL */
+ ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &pipe_handle, &buf, 1, write_cb));
+ ASSERT(write_req.handle != NULL);
+ ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_ONCE)); /* queue write_cb */
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); /* process write_cb */
+ ASSERT(write_req.handle == NULL); /* check for signaled completion of write_cb */
+ n = buf.len;
+#endif
ASSERT(n == sizeof(data));
nwritten += n;
}
@@ -96,12 +119,14 @@ TEST_IMPL(pipe_set_non_blocking) {
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT(0 == uv_thread_join(&thread));
+#ifdef _WIN32
+ ASSERT(0 == _close(fd[0])); /* fd[1] is closed by uv_close(). */
+#else
ASSERT(0 == close(fd[0])); /* fd[1] is closed by uv_close(). */
+#endif
fd[0] = -1;
uv_barrier_destroy(&ctx.barrier);
MAKE_VALGRIND_HAPPY();
return 0;
}
-
-#endif /* !_WIN32 */
diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c
index f547ddfd76..341c7ae54e 100644
--- a/deps/uv/test/test-platform-output.c
+++ b/deps/uv/test/test-platform-output.c
@@ -155,6 +155,7 @@ TEST_IMPL(platform_output) {
printf(" username: %s\n", pwd.username);
printf(" shell: %s\n", pwd.shell);
printf(" home directory: %s\n", pwd.homedir);
+ uv_os_free_passwd(&pwd);
pid = uv_os_getpid();
ASSERT(pid > 0);
diff --git a/deps/uv/test/test-poll-multiple-handles.c b/deps/uv/test/test-poll-multiple-handles.c
new file mode 100644
index 0000000000..fc2205ddec
--- /dev/null
+++ b/deps/uv/test/test-poll-multiple-handles.c
@@ -0,0 +1,99 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+
+#ifndef _WIN32
+# include <fcntl.h>
+# include <sys/socket.h>
+# include <unistd.h>
+#endif
+
+#include "uv.h"
+#include "task.h"
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+static void poll_cb(uv_poll_t* handle, int status, int events) {
+ /* Not a bound socket, linux immediately reports UV_READABLE, other OS do not */
+ ASSERT(events == UV_READABLE);
+}
+
+TEST_IMPL(poll_multiple_handles) {
+ uv_os_sock_t sock;
+ uv_poll_t first_poll_handle, second_poll_handle;
+
+#ifdef _WIN32
+ {
+ struct WSAData wsa_data;
+ int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+ }
+#endif
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+#ifdef _WIN32
+ ASSERT(sock != INVALID_SOCKET);
+#else
+ ASSERT(sock != -1);
+#endif
+ ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &first_poll_handle, sock));
+ ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &second_poll_handle, sock));
+
+ ASSERT(0 == uv_poll_start(&first_poll_handle, UV_READABLE, poll_cb));
+
+ /* We may not start polling while another polling handle is active
+ * on that fd.
+ */
+#ifndef _WIN32
+ /* We do not track handles in an O(1) lookupable way on Windows,
+ * so not checking that here.
+ */
+ ASSERT(uv_poll_start(&second_poll_handle, UV_READABLE, poll_cb) == UV_EEXIST);
+#endif
+
+ /* After stopping the other polling handle, we now should be able to poll */
+ ASSERT(0 == uv_poll_stop(&first_poll_handle));
+ ASSERT(0 == uv_poll_start(&second_poll_handle, UV_READABLE, poll_cb));
+
+ /* Closing an already stopped polling handle is safe in any case */
+ uv_close((uv_handle_t*) &first_poll_handle, close_cb);
+
+ uv_unref((uv_handle_t*) &second_poll_handle);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(close_cb_called == 1);
+ uv_ref((uv_handle_t*) &second_poll_handle);
+
+ ASSERT(uv_is_active((uv_handle_t*) &second_poll_handle));
+ uv_close((uv_handle_t*) &second_poll_handle, close_cb);
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/deps/uv/test/test-shutdown-eof.c b/deps/uv/test/test-shutdown-eof.c
index 9f95e7561f..0abab9175e 100644
--- a/deps/uv/test/test-shutdown-eof.c
+++ b/deps/uv/test/test-shutdown-eof.c
@@ -89,7 +89,13 @@ static void connect_cb(uv_connect_t *req, int status) {
ASSERT(req == &connect_req);
/* Start reading from our connection so we can receive the EOF. */
- uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb);
+ ASSERT_EQ(0, uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb));
+
+ /* Check error handling. */
+ ASSERT_EQ(UV_EALREADY, uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb));
+ ASSERT_EQ(UV_EINVAL, uv_read_start(NULL, alloc_cb, read_cb));
+ ASSERT_EQ(UV_EINVAL, uv_read_start((uv_stream_t*)&tcp, NULL, read_cb));
+ ASSERT_EQ(UV_EINVAL, uv_read_start((uv_stream_t*)&tcp, alloc_cb, NULL));
/*
* Write the letter 'Q' to gracefully kill the echo-server. This will not
diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c
index d1757337a6..886ddaf63b 100644
--- a/deps/uv/test/test-spawn.c
+++ b/deps/uv/test/test-spawn.c
@@ -29,11 +29,9 @@
#include <string.h>
#ifdef _WIN32
-# if defined(__MINGW32__)
-# include <basetyps.h>
-# endif
# include <shellapi.h>
# include <wchar.h>
+ typedef BOOL (WINAPI *sCompareObjectHandles)(_In_ HANDLE, _In_ HANDLE);
#else
# include <unistd.h>
# include <sys/wait.h>
@@ -49,9 +47,7 @@ static char exepath[1024];
static size_t exepath_size = 1024;
static char* args[5];
static int no_term_signal;
-#ifndef _WIN32
static int timer_counter;
-#endif
static uv_tcp_t tcp_server;
#define OUTPUT_SIZE 1024
@@ -140,12 +136,10 @@ static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
}
-#ifndef _WIN32
static void on_read_once(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
uv_read_stop(tcp);
on_read(tcp, nread, buf);
}
-#endif
static void write_cb(uv_write_t* req, int status) {
@@ -154,6 +148,11 @@ static void write_cb(uv_write_t* req, int status) {
}
+static void write_null_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+}
+
+
static void init_process_options(char* test, uv_exit_cb exit_cb) {
/* Note spawn_helper1 defined in test/run-tests.c */
int r = uv_exepath(exepath, &exepath_size);
@@ -177,11 +176,9 @@ static void timer_cb(uv_timer_t* handle) {
}
-#ifndef _WIN32
static void timer_counter_cb(uv_timer_t* handle) {
++timer_counter;
}
-#endif
TEST_IMPL(spawn_fails) {
@@ -1328,9 +1325,8 @@ TEST_IMPL(environment_creation) {
found = 1;
}
}
- if (prev) { /* verify sort order -- requires Vista */
-#if _WIN32_WINNT >= 0x0600 && \
- (!defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR))
+ if (prev) { /* verify sort order */
+#if !defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR)
ASSERT(CompareStringOrdinal(prev, -1, str, -1, TRUE) == 1);
#endif
}
@@ -1579,17 +1575,27 @@ TEST_IMPL(spawn_auto_unref) {
}
-#ifndef _WIN32
TEST_IMPL(spawn_fs_open) {
- int fd;
+ int r;
+ uv_os_fd_t fd;
+ uv_os_fd_t dup_fd;
uv_fs_t fs_req;
uv_pipe_t in;
uv_write_t write_req;
+ uv_write_t write_req2;
uv_buf_t buf;
uv_stdio_container_t stdio[1];
+#ifdef _WIN32
+ const char dev_null[] = "NUL";
+ HMODULE kernelbase_module;
+ sCompareObjectHandles pCompareObjectHandles; /* function introduced in Windows 10 */
+#else
+ const char dev_null[] = "/dev/null";
+#endif
- fd = uv_fs_open(NULL, &fs_req, "/dev/null", O_RDWR, 0, NULL);
- ASSERT(fd >= 0);
+ r = uv_fs_open(NULL, &fs_req, dev_null, O_RDWR, 0, NULL);
+ ASSERT(r != -1);
+ fd = uv_get_osfhandle((uv_file) fs_req.result);
uv_fs_req_cleanup(&fs_req);
init_process_options("spawn_helper8", exit_cb);
@@ -1601,13 +1607,28 @@ TEST_IMPL(spawn_fs_open) {
options.stdio[0].data.stream = (uv_stream_t*) &in;
options.stdio_count = 1;
+ /* make an inheritable copy */
+#ifdef _WIN32
+ ASSERT(0 != DuplicateHandle(GetCurrentProcess(), fd, GetCurrentProcess(), &dup_fd,
+ 0, /* inherit */ TRUE, DUPLICATE_SAME_ACCESS));
+ kernelbase_module = GetModuleHandleA("kernelbase.dll");
+ pCompareObjectHandles = (sCompareObjectHandles)
+ GetProcAddress(kernelbase_module, "CompareObjectHandles");
+ ASSERT(pCompareObjectHandles == NULL || pCompareObjectHandles(fd, dup_fd));
+#else
+ dup_fd = dup(fd);
+#endif
+
ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
buf = uv_buf_init((char*) &fd, sizeof(fd));
- ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));
+ ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_null_cb));
+
+ buf = uv_buf_init((char*) &dup_fd, sizeof(fd));
+ ASSERT(0 == uv_write(&write_req2, (uv_stream_t*) &in, &buf, 1, write_cb));
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
- ASSERT(0 == uv_fs_close(NULL, &fs_req, fd, NULL));
+ ASSERT(0 == uv_fs_close(NULL, &fs_req, r, NULL));
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 2); /* One for `in`, one for process */
@@ -1615,17 +1636,20 @@ TEST_IMPL(spawn_fs_open) {
MAKE_VALGRIND_HAPPY();
return 0;
}
-#endif /* !_WIN32 */
-#ifndef _WIN32
TEST_IMPL(closed_fd_events) {
uv_stdio_container_t stdio[3];
uv_pipe_t pipe_handle;
- int fd[2];
+ uv_fs_t req;
+ uv_buf_t bufs[1];
+ uv_file fd[2];
+ bufs[0] = uv_buf_init("", 1);
/* create a pipe and share it with a child process */
- ASSERT(0 == pipe(fd));
+ ASSERT(0 == uv_pipe(fd, 0, 0));
+ ASSERT(fd[0] > 2);
+ ASSERT(fd[1] > 2);
/* spawn_helper4 blocks indefinitely. */
init_process_options("spawn_helper4", exit_cb);
@@ -1642,12 +1666,18 @@ TEST_IMPL(closed_fd_events) {
/* read from the pipe with uv */
ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
+ /* uv_pipe_open() takes ownership of the file descriptor. */
fd[0] = -1;
ASSERT(0 == uv_read_start((uv_stream_t*) &pipe_handle, on_alloc, on_read_once));
- ASSERT(1 == write(fd[1], "", 1));
+ ASSERT(1 == uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL));
+ ASSERT(req.result == 1);
+ uv_fs_req_cleanup(&req);
+#ifdef _WIN32
+ ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+#endif
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
/* should have received just one byte */
@@ -1656,7 +1686,9 @@ TEST_IMPL(closed_fd_events) {
/* close the pipe and see if we still get events */
uv_close((uv_handle_t*) &pipe_handle, close_cb);
- ASSERT(1 == write(fd[1], "", 1));
+ ASSERT(1 == uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL));
+ ASSERT(req.result == 1);
+ uv_fs_req_cleanup(&req);
ASSERT(0 == uv_timer_init(uv_default_loop(), &timer));
ASSERT(0 == uv_timer_start(&timer, timer_counter_cb, 10, 0));
@@ -1669,13 +1701,17 @@ TEST_IMPL(closed_fd_events) {
ASSERT(timer_counter == 1);
/* cleanup */
- ASSERT(0 == uv_process_kill(&process, /* SIGTERM */ 15));
+ ASSERT(0 == uv_process_kill(&process, SIGTERM));
+#ifdef _WIN32
+ ASSERT(0 == _close(fd[1]));
+#else
ASSERT(0 == close(fd[1]));
+#endif
MAKE_VALGRIND_HAPPY();
return 0;
}
-#endif /* !_WIN32 */
+
TEST_IMPL(spawn_reads_child_path) {
int r;
@@ -1746,38 +1782,6 @@ TEST_IMPL(spawn_reads_child_path) {
return 0;
}
-#ifndef _WIN32
-static int mpipe(int *fds) {
- if (pipe(fds) == -1)
- return -1;
- if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
- fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
- close(fds[0]);
- close(fds[1]);
- return -1;
- }
- return 0;
-}
-#else
-static int mpipe(int *fds) {
- SECURITY_ATTRIBUTES attr;
- HANDLE readh, writeh;
- attr.nLength = sizeof(attr);
- attr.lpSecurityDescriptor = NULL;
- attr.bInheritHandle = FALSE;
- if (!CreatePipe(&readh, &writeh, &attr, 0))
- return -1;
- fds[0] = _open_osfhandle((intptr_t)readh, 0);
- fds[1] = _open_osfhandle((intptr_t)writeh, 0);
- if (fds[0] == -1 || fds[1] == -1) {
- CloseHandle(readh);
- CloseHandle(writeh);
- return -1;
- }
- return 0;
-}
-#endif /* !_WIN32 */
-
TEST_IMPL(spawn_inherit_streams) {
uv_process_t child_req;
uv_stdio_container_t child_stdio[2];
@@ -1803,8 +1807,8 @@ TEST_IMPL(spawn_inherit_streams) {
ASSERT(uv_pipe_init(loop, &pipe_stdin_parent, 0) == 0);
ASSERT(uv_pipe_init(loop, &pipe_stdout_parent, 0) == 0);
- ASSERT(mpipe(fds_stdin) != -1);
- ASSERT(mpipe(fds_stdout) != -1);
+ ASSERT(uv_pipe(fds_stdin, 0, 0) == 0);
+ ASSERT(uv_pipe(fds_stdout, 0, 0) == 0);
ASSERT(uv_pipe_open(&pipe_stdin_child, fds_stdin[0]) == 0);
ASSERT(uv_pipe_open(&pipe_stdout_child, fds_stdout[1]) == 0);
diff --git a/deps/uv/test/test-tcp-bind-error.c b/deps/uv/test/test-tcp-bind-error.c
index f95efd9f0c..7732267f44 100644
--- a/deps/uv/test/test-tcp-bind-error.c
+++ b/deps/uv/test/test-tcp-bind-error.c
@@ -25,6 +25,7 @@
#include <stdlib.h>
+static int connect_cb_called = 0;
static int close_cb_called = 0;
@@ -34,7 +35,49 @@ static void close_cb(uv_handle_t* handle) {
}
-TEST_IMPL(tcp_bind_error_addrinuse) {
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(status == UV_EADDRINUSE);
+ uv_close((uv_handle_t*) req->handle, close_cb);
+ connect_cb_called++;
+}
+
+
+TEST_IMPL(tcp_bind_error_addrinuse_connect) {
+ struct sockaddr_in addr;
+ int addrlen;
+ uv_connect_t req;
+ uv_tcp_t conn;
+
+ /* 127.0.0.1:<TEST_PORT> is already taken by tcp4_echo_server running in
+ * another process. uv_tcp_bind() and uv_tcp_connect() should still succeed
+ * (greatest common denominator across platforms) but the connect callback
+ * should receive an UV_EADDRINUSE error.
+ */
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &conn));
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(0 == uv_tcp_bind(&conn, (const struct sockaddr*) &addr, 0));
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT + 1, &addr));
+ ASSERT(0 == uv_tcp_connect(&req,
+ &conn,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+
+ addrlen = sizeof(addr);
+ ASSERT(UV_EADDRINUSE == uv_tcp_getsockname(&conn,
+ (struct sockaddr*) &addr,
+ &addrlen));
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(connect_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind_error_addrinuse_listen) {
struct sockaddr_in addr;
uv_tcp_t server1, server2;
int r;
@@ -240,7 +283,9 @@ TEST_IMPL(tcp_bind_writable_flags) {
ASSERT(r == UV_EPIPE);
r = uv_shutdown(&shutdown_req, (uv_stream_t*) &server, NULL);
ASSERT(r == UV_ENOTCONN);
- r = uv_read_start((uv_stream_t*) &server, NULL, NULL);
+ r = uv_read_start((uv_stream_t*) &server,
+ (uv_alloc_cb) abort,
+ (uv_read_cb) abort);
ASSERT(r == UV_ENOTCONN);
uv_close((uv_handle_t*)&server, close_cb);
diff --git a/deps/uv/test/test-tcp-connect-timeout.c b/deps/uv/test/test-tcp-connect-timeout.c
index a67d325284..3c34e54ae7 100644
--- a/deps/uv/test/test-tcp-connect-timeout.c
+++ b/deps/uv/test/test-tcp-connect-timeout.c
@@ -111,7 +111,7 @@ static int is_supported_system(void) {
if (cnt != 3) {
return 0;
}
- // relase >= 10.0.16299
+ /* relase >= 10.0.16299 */
for (cnt = 0; cnt < 3; ++cnt) {
if (semver[cnt] > min_semver[cnt])
return 1;
diff --git a/deps/uv/test/test-tty.c b/deps/uv/test/test-tty.c
index a9d38f2211..ff7d388d7c 100644
--- a/deps/uv/test/test-tty.c
+++ b/deps/uv/test/test-tty.c
@@ -426,6 +426,9 @@ TEST_IMPL(tty_pty) {
#if defined(__QEMU__)
RETURN_SKIP("Test does not currently work in QEMU");
#endif
+#if defined(__ASAN__)
+ RETURN_SKIP("Test does not currently work in ASAN");
+#endif
#if defined(__APPLE__) || \
defined(__DragonFly__) || \
diff --git a/deps/uv/test/test-udp-connect.c b/deps/uv/test/test-udp-connect.c
index 41ace117a1..52856f700d 100644
--- a/deps/uv/test/test-udp-connect.c
+++ b/deps/uv/test/test-udp-connect.c
@@ -124,7 +124,7 @@ TEST_IMPL(udp_connect) {
buf = uv_buf_init("EXIT", 4);
- // connect() to INADDR_ANY fails on Windows wih WSAEADDRNOTAVAIL
+ /* connect() to INADDR_ANY fails on Windows wih WSAEADDRNOTAVAIL */
ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &tmp_addr));
r = uv_udp_connect(&client, (const struct sockaddr*) &tmp_addr);
#ifdef _WIN32
diff --git a/deps/uv/tools/make_dist_html.py b/deps/uv/tools/make_dist_html.py
index 7a19d3e115..4833b1b8e3 100644
--- a/deps/uv/tools/make_dist_html.py
+++ b/deps/uv/tools/make_dist_html.py
@@ -1,6 +1,4 @@
-#!/usr/bin/python
-
-from __future__ import print_function
+#!/usr/bin/python3
import itertools
import os
@@ -84,7 +82,7 @@ EXE = r'''
'''
def version(tag):
- return map(int, re.match('^v(\d+)\.(\d+)\.(\d+)', tag).groups())
+ return list(map(int, re.match('^v(\d+)\.(\d+)\.(\d+)', tag).groups()))
def major_minor(tag):
return version(tag)[:2]
@@ -114,7 +112,7 @@ def groups_for(groups, n=4):
if __name__ == '__main__':
os.chdir(os.path.dirname(__file__))
- tags = subprocess.check_output(['git', 'tag'])
+ tags = subprocess.check_output(['git', 'tag'], text=True)
tags = [tag for tag in tags.split('\n') if tag.startswith('v')]
tags.sort(key=version, reverse=True)
groups = [group_for(list(g)) for _, g in itertools.groupby(tags, major_minor)]