diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap index da4214365c4155..5bbe5b26bb5c5e 100644 --- a/deps/uv/.mailmap +++ b/deps/uv/.mailmap @@ -16,6 +16,7 @@ Frank Denis Imran Iqbal Isaac Z. Schlueter Jason Williams +Jesse Gorzinski Justin Venus Keno Fischer Keno Fischer diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index fcb0aac3e83b10..2fdfbcd5322e5e 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -330,3 +330,25 @@ Mason X Jesse Gorzinski Ryuichi KAWAMATA Joyee Cheung +Michael Kilburn +Ruslan Bekenev +Bob Burger +Thomas Versteeg +zzzjim +Alex Arslan +Kyle Farnung +ssrlive <30760636+ssrlive@users.noreply.github.com> +Tobias Nießen +Björn Linse +zyxwvu Shi +Peter Johnson +Paolo Greppi +Shelley Vohr +Ujjwal Sharma +Michał Kozakiewicz +Emil Bay +Jeremiah Senkpiel +Andy Zhang +dmabupt +Ryan Liptak +Ali Ijaz Sheikh diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt new file mode 100644 index 00000000000000..6a631a87c1cb39 --- /dev/null +++ b/deps/uv/CMakeLists.txt @@ -0,0 +1,380 @@ +# TODO: determine CMAKE_SYSTEM_NAME on OS/390. Currently assumes "OS/390". +cmake_minimum_required(VERSION 3.0) +project(libuv) +enable_testing() + +if(MSVC) + list(APPEND uv_cflags /W4) +elseif(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU") + list(APPEND uv_cflags -fvisibility=hidden --std=gnu89) + list(APPEND uv_cflags -Wall -Wextra -Wstrict-prototypes) + list(APPEND uv_cflags -Wno-unused-parameter) +endif() + +set(uv_sources + src/fs-poll.c + src/inet.c + src/threadpool.c + src/timer.c + src/uv-common.c + src/uv-data-getter-setters.c + src/version.c) + +set(uv_test_sources + test/blackhole-server.c + test/echo-server.c + test/run-tests.c + test/runner.c + test/test-active.c + test/test-async-null-cb.c + test/test-async.c + test/test-barrier.c + test/test-callback-order.c + test/test-callback-stack.c + test/test-close-fd.c + test/test-close-order.c + test/test-condvar.c + test/test-connect-unspecified.c + test/test-connection-fail.c + test/test-cwd-and-chdir.c + test/test-default-loop-close.c + test/test-delayed-accept.c + test/test-dlerror.c + test/test-eintr-handling.c + test/test-embed.c + test/test-emfile.c + test/test-env-vars.c + test/test-error.c + test/test-fail-always.c + test/test-fork.c + test/test-fs-copyfile.c + test/test-fs-event.c + test/test-fs-poll.c + test/test-fs.c + test/test-get-currentexe.c + test/test-get-loadavg.c + test/test-get-memory.c + test/test-get-passwd.c + test/test-getaddrinfo.c + test/test-gethostname.c + test/test-getnameinfo.c + test/test-getsockname.c + test/test-getters-setters.c + test/test-handle-fileno.c + test/test-homedir.c + test/test-hrtime.c + test/test-idle.c + test/test-ip4-addr.c + test/test-ip6-addr.c + test/test-ip6-addr.c + test/test-ipc-heavy-traffic-deadlock-bug.c + test/test-ipc-send-recv.c + test/test-ipc.c + test/test-loop-alive.c + test/test-loop-close.c + test/test-loop-configure.c + test/test-loop-handles.c + test/test-loop-stop.c + test/test-loop-time.c + test/test-multiple-listen.c + test/test-mutexes.c + test/test-osx-select.c + test/test-pass-always.c + test/test-ping-pong.c + test/test-pipe-bind-error.c + test/test-pipe-close-stdout-read-stdin.c + test/test-pipe-connect-error.c + test/test-pipe-connect-multiple.c + test/test-pipe-connect-prepare.c + test/test-pipe-getsockname.c + test/test-pipe-pending-instances.c + test/test-pipe-sendmsg.c + test/test-pipe-server-close.c + test/test-pipe-set-fchmod.c + test/test-pipe-set-non-blocking.c + test/test-platform-output.c + test/test-poll-close-doesnt-corrupt-stack.c + test/test-poll-close.c + test/test-poll-closesocket.c + test/test-poll-oob.c + test/test-poll.c + test/test-process-priority.c + test/test-process-title-threadsafe.c + test/test-process-title.c + test/test-queue-foreach-delete.c + test/test-ref.c + test/test-run-nowait.c + test/test-run-once.c + test/test-semaphore.c + test/test-shutdown-close.c + test/test-shutdown-eof.c + test/test-shutdown-twice.c + test/test-signal-multiple-loops.c + test/test-signal.c + test/test-socket-buffer-size.c + test/test-spawn.c + test/test-stdio-over-pipes.c + test/test-tcp-alloc-cb-fail.c + test/test-tcp-bind-error.c + test/test-tcp-bind6-error.c + test/test-tcp-close-accept.c + test/test-tcp-close-while-connecting.c + test/test-tcp-close.c + test/test-tcp-connect-error-after-write.c + test/test-tcp-connect-error.c + test/test-tcp-connect-timeout.c + test/test-tcp-connect6-error.c + test/test-tcp-create-socket-early.c + test/test-tcp-flags.c + test/test-tcp-oob.c + test/test-tcp-open.c + test/test-tcp-read-stop.c + test/test-tcp-shutdown-after-write.c + test/test-tcp-try-write.c + test/test-tcp-unexpected-read.c + test/test-tcp-write-after-connect.c + test/test-tcp-write-fail.c + test/test-tcp-write-queue-order.c + test/test-tcp-write-to-half-open-connection.c + test/test-tcp-writealot.c + test/test-thread-equal.c + test/test-thread.c + test/test-threadpool-cancel.c + test/test-threadpool.c + test/test-timer-again.c + test/test-timer-from-check.c + test/test-timer.c + test/test-tmpdir.c + test/test-tty.c + test/test-udp-alloc-cb-fail.c + test/test-udp-bind.c + test/test-udp-create-socket-early.c + test/test-udp-dgram-too-big.c + test/test-udp-ipv6.c + test/test-udp-multicast-interface.c + test/test-udp-multicast-interface6.c + test/test-udp-multicast-join.c + test/test-udp-multicast-join6.c + test/test-udp-multicast-ttl.c + test/test-udp-open.c + test/test-udp-options.c + test/test-udp-send-and-recv.c + test/test-udp-send-hang-loop.c + test/test-udp-send-immediate.c + test/test-udp-send-unreachable.c + test/test-udp-try-send.c + test/test-walk-handles.c + test/test-watcher-cross-stop.c) + +if(WIN32) + list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0600) + list(APPEND uv_libraries + advapi32 + iphlpapi + psapi + shell32 + user32 + userenv + ws2_32) + list(APPEND uv_sources + src/win/async.c + src/win/core.c + src/win/detect-wakeup.c + src/win/dl.c + src/win/error.c + src/win/fs.c + src/win/fs-event.c + src/win/getaddrinfo.c + src/win/getnameinfo.c + src/win/handle.c + src/win/loop-watcher.c + src/win/pipe.c + src/win/thread.c + src/win/poll.c + src/win/process.c + src/win/process-stdio.c + src/win/signal.c + src/win/snprintf.c + src/win/stream.c + src/win/tcp.c + src/win/tty.c + src/win/udp.c + src/win/util.c + src/win/winapi.c + src/win/winsock.c) + list(APPEND uv_test_libraries ws2_32) + list(APPEND uv_test_sources src/win/snprintf.c test/runner-win.c) +else() + list(APPEND uv_defines _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE) + list(APPEND uv_libraries pthread) + list(APPEND uv_sources + src/unix/async.c + src/unix/core.c + src/unix/dl.c + src/unix/fs.c + src/unix/getaddrinfo.c + src/unix/getnameinfo.c + src/unix/loop-watcher.c + src/unix/loop.c + src/unix/pipe.c + src/unix/poll.c + src/unix/process.c + src/unix/signal.c + src/unix/stream.c + src/unix/tcp.c + src/unix/thread.c + src/unix/tty.c + src/unix/udp.c) + list(APPEND uv_test_sources test/runner-unix.c) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "AIX") + list(APPEND uv_defines + _ALL_SOURCE + _LINUX_SOURCE_COMPAT + _THREAD_SAFE + _XOPEN_SOURCE=500) + list(APPEND uv_libraries perfstat) + list(APPEND uv_sources src/unix/aix.c) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Android") + list(APPEND uv_libs dl) + list(APPEND uv_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/sysinfo-loadavg.c + src/unix/sysinfo-memory.c) +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|Linux|OS/390") + list(APPEND uv_sources src/unix/proctitle.c) +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD") + list(APPEND uv_sources src/unix/freebsd.c) +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|NetBSD|OpenBSD") + list(APPEND uv_sources src/unix/posix-hrtime.c) + list(APPEND uv_libraries kvm) +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin|DragonFly|FreeBSD|NetBSD|OpenBSD") + list(APPEND uv_sources src/unix/bsd-ifaddrs.c src/unix/kqueue.c) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + list(APPEND uv_defines _DARWIN_UNLIMITED_SELECT=1 _DARWIN_USE_64_BIT_INODE=1) + list(APPEND uv_sources + src/unix/darwin-proctitle.c + src/unix/darwin.c + src/unix/fsevents.c) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + list(APPEND uv_defines _GNU_SOURCE _POSIX_C_SOURCE=200112) + list(APPEND uv_libraries dl rt) + list(APPEND uv_sources + src/unix/linux-core.c + src/unix/linux-inotify.c + src/unix/linux-syscalls.c + src/unix/procfs-exepath.c + src/unix/sysinfo-loadavg.c + src/unix/sysinfo-memory.c) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") + list(APPEND uv_sources src/unix/netbsd.c) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + list(APPEND uv_sources src/unix/openbsd.c) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "OS/390") + list(APPEND uv_defines PATH_MAX=255) + list(APPEND uv_defines _AE_BIMODAL) + list(APPEND uv_defines _ALL_SOURCE) + list(APPEND uv_defines _LARGE_TIME_API) + list(APPEND uv_defines _OPEN_MSGQ_EXT) + list(APPEND uv_defines _OPEN_SYS_FILE_EXT) + list(APPEND uv_defines _OPEN_SYS_IF_EXT) + list(APPEND uv_defines _OPEN_SYS_SOCK_IPV6) + list(APPEND uv_defines _UNIX03_SOURCE) + list(APPEND uv_defines _UNIX03_THREADS) + list(APPEND uv_defines _UNIX03_WITHDRAWN) + list(APPEND uv_defines _XOPEN_SOURCE_EXTENDED) + list(APPEND uv_sources + src/unix/pthread-fixes.c + src/unix/pthread-barrier.c + src/unix/os390.c + src/unix/os390-syscalls.c) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") + list(APPEND uv_defines __EXTENSIONS__ _XOPEN_SOURCE=500) + list(APPEND uv_libraries kstat nsl sendfile socket) + list(APPEND uv_sources src/unix/no-proctitle.c src/unix/sunos.c) +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin|DragonFly|FreeBSD|Linux|NetBSD|OpenBSD") + list(APPEND uv_test_libraries util) +endif() + +add_library(uv SHARED ${uv_sources}) +target_compile_definitions(uv PRIVATE ${uv_defines} BUILDING_UV_SHARED=1) +target_compile_options(uv PRIVATE ${uv_cflags}) +target_include_directories(uv PRIVATE include src) +target_link_libraries(uv ${uv_libraries}) + +add_library(uv_a STATIC ${uv_sources}) +target_compile_definitions(uv_a PRIVATE ${uv_defines}) +target_compile_options(uv_a PRIVATE ${uv_cflags}) +target_include_directories(uv_a PRIVATE include src) +target_link_libraries(uv_a ${uv_libraries}) + +if(BUILD_TESTING) + include(CTest) + add_executable(uv_run_tests ${uv_test_sources}) + target_compile_definitions(uv_run_tests PRIVATE ${uv_defines}) + target_compile_options(uv_run_tests PRIVATE ${uv_cflags}) + target_include_directories(uv_run_tests PRIVATE include) + target_link_libraries(uv_run_tests uv ${uv_test_libraries}) + add_test(NAME uv_test + COMMAND uv_run_tests + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + add_executable(uv_run_tests_a ${uv_test_sources}) + target_compile_definitions(uv_run_tests_a PRIVATE ${uv_defines}) + target_compile_options(uv_run_tests_a PRIVATE ${uv_cflags}) + target_include_directories(uv_run_tests_a PRIVATE include) + target_link_libraries(uv_run_tests_a uv_a ${uv_test_libraries}) + add_test(NAME uv_test_a + COMMAND uv_run_tests_a + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +if(UNIX) + # Now for some gibbering horrors from beyond the stars... + include(GNUInstallDirs) + foreach(x ${uv_libraries}) + set(LIBS "${LIBS} -l${x}") + endforeach(x) + file(STRINGS configure.ac configure_ac REGEX ^AC_INIT) + string(REGEX MATCH [0-9]+[.][0-9]+[.][0-9]+ PACKAGE_VERSION "${configure_ac}") + set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}) + set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) + set(prefix ${CMAKE_INSTALL_PREFIX}) + configure_file(libuv.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libuv.pc @ONLY) + + install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) + install(FILES LICENSE ${CMAKE_CURRENT_BINARY_DIR}/libuv.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + install(TARGETS uv LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS uv_a ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() diff --git a/deps/uv/CONTRIBUTING.md b/deps/uv/CONTRIBUTING.md index d9bf0472fb1fc3..f22e124e3b23b9 100644 --- a/deps/uv/CONTRIBUTING.md +++ b/deps/uv/CONTRIBUTING.md @@ -137,7 +137,10 @@ $ git rebase upstream/v1.x # or upstream/master ### TEST Bug fixes and features should come with tests. Add your tests in the -`test/` directory. Each new test needs to be registered in `test/test-list.h`. If you add a new test file, it needs to be registered in two places: +`test/` directory. Each new test needs to be registered in `test/test-list.h`. + +If you add a new test file, it needs to be registered in three places: +- `CMakeLists.txt`: add the file's name to the `uv_test_sources` list. - `Makefile.am`: add the file's name to the `test_run_tests_SOURCES` list. - `uv.gyp`: add the file's name to the `sources` list in the `run-tests` target. diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 509a1d1571d498..7cb675238d3e08 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,344 @@ +2018.10.09, Version 1.23.2 (Stable), 34c12788d2e7308f3ac506c0abcbf74c0d6abd20 + +Changes since version 1.23.1: + +* unix: return 0 retrieving rss on cygwin (cjihrig) + +* unix: initialize uv_interface_address_t.phys_addr (cjihrig) + +* test: handle uv_os_setpriority() windows edge case (cjihrig) + +* tty, win: fix read stop for raw mode (Bartosz Sosnowski) + +* Revert "Revert "unix,fs: fix for potential partial reads/writes"" (Jameson + Nash) + +* unix,readv: always permit partial reads to return (Jameson Nash) + +* win,tty: fix uv_tty_close() (Bartosz Sosnowski) + +* doc: remove extraneous "on" (Ben Noordhuis) + +* unix,win: fix threadpool race condition (Anna Henningsen) + +* unix: rework thread barrier implementation (Ben Noordhuis) + +* aix: switch to libuv's own thread barrier impl (Ben Noordhuis) + +* unix: signal done to last thread barrier waiter (Ben Noordhuis) + +* test: add uv_barrier_wait serial thread test (Ali Ijaz Sheikh) + +* unix: optimize uv_fs_readlink() memory allocation (Ben Noordhuis) + +* win: remove req.c and other cleanup (Carlo Marcelo Arenas Belón) + +* aix: don't EISDIR on read from directory fd (Ben Noordhuis) + + +2018.09.22, Version 1.23.1 (Stable), d2282b3d67821dc53c907c2155fa8c5c6ce25180 + +Changes since version 1.23.0: + +* unix,win: limit concurrent DNS calls to nthreads/2 (Anna Henningsen) + +* doc: add addaleax to maintainers (Anna Henningsen) + +* doc: add missing slash in stream.rst (Emil Bay) + +* unix,fs: use utimes & friends for uv_fs_utime (Jeremiah Senkpiel) + +* unix,fs: remove linux fallback from utimesat() (Jeremiah Senkpiel) + +* unix,fs: remove uv__utimesat() syscall fallback (Jeremiah Senkpiel) + +* doc: fix argument name in tcp.rts (Emil Bay) + +* doc: notes on running tests, benchmarks, tools (Jamie Davis) + +* linux: remove epoll syscall wrappers (Ben Noordhuis) + +* linux: drop code path for epoll_pwait-less kernels (Ben Noordhuis) + +* Partially revert "win,code: remove GetQueuedCompletionStatus-based poller" + (Jameson Nash) + +* build: add compile for android arm64/x86/x86-64 (Andy Zhang) + +* doc: clarify that some remarks apply to windows (Bert Belder) + +* test: fix compiler warnings (Jamie Davis) + +* ibmi: return 0 from uv_resident_set_memory() (dmabupt) + +* win: fix uv_udp_recv_start() error translation (Ryan Liptak) + +* win,doc: improve uv_os_setpriority() documentation (Bartosz Sosnowski) + +* test: increase upper bound in condvar_5 (Jamie Davis) + +* win,tty: remove deadcode (Jameson Nash) + +* stream: autodetect direction (Jameson Nash) + + +2018.08.18, Version 1.23.0 (Stable), 7ebb26225f2eaae6db22f4ef34ce76fa16ff89ec + +Changes since version 1.22.0: + +* win,pipe: restore compatibility with the old IPC framing protocol (Bert + Belder) + +* fs: add uv_open_osfhandle (Bartosz Sosnowski) + +* doc: update Visual C++ Build Tools URL (Michał Kozakiewicz) + +* unix: loop starvation on successful write complete (jBarz) + +* win: add uv__getnameinfo_work() error handling (A. Hauptmann) + +* win: return UV_ENOMEM from uv_loop_init() (cjihrig) + +* unix,win: add uv_os_{get,set}priority() (cjihrig) + +* test: fix warning in test-tcp-open (Santiago Gimeno) + + +2018.07.11, Version 1.22.0 (Stable), 8568f78a777d79d35eb7d6994617267b9fb33967 + +Changes since version 1.21.0: + +* unix: remove checksparse.sh (Ben Noordhuis) + +* win: fix mingw build error (Ben Noordhuis) + +* win: fix -Wunused-function warnings in thread.c (Ben Noordhuis) + +* unix,win: merge timers implementation (Ben Noordhuis) + +* win: fix pointer type in pipe.c (Ben Noordhuis) + +* win: fixing build for older MSVC compilers (Michael Fero) + +* zos: clear poll events on every iteration (jBarz) + +* zos: write-protect message queue (jBarz) + +* zos: use correct pointer type in strnlen (jBarz) + +* unix,win: merge handle flags (Ben Noordhuis) + +* doc: update Imran Iqbal's GitHub handle (cjihrig) + +* src: add new error apis to prevent memory leaks (Shelley Vohr) + +* test: make test-condvar call uv_cond_wait (Jamie Davis) + +* fs: change position of uv_fs_lchown (Ujjwal Sharma) + + +2018.06.23, Version 1.21.0 (Stable), e4983a9b0c152932f7553ff4a9ff189d2314cdcb + +Changes since version 1.20.3: + +* unix,windows: map EFTYPE errno (cjihrig) + +* win: perform case insensitive PATH= comparison (cjihrig) + +* win, fs: uv_fs_fchmod support for -A files (Bartosz Sosnowski) + +* src,lib: fix comments (Tobias Nießen) + +* win,process: allow child pipe handles to be opened in overlapped mode (Björn + Linse) + +* src,test: fix idiosyncratic comment style (Bert Belder) + +* test: fs_fchmod_archive_readonly must return a value (Bert Belder) + +* win,pipe: fix incorrect error code returned from uv_pipe_write_impl() (Bert + Belder) + +* win,pipe: properly set uv_write_t.send_handle in uv_write2() (Bert Belder) + +* test: add vectored uv_write() ping-pong tests (Bert Belder) + +* win,pipe: support vectored uv_write() calls (Bert Belder) + +* win,pipe: refactor pipe read cancellation logic (Bert Belder) + +* test: improve output from IPC test helpers (Bert Belder) + +* test: add test for IPC deadlock on Windows ( + +* win,pipe: fix IPC pipe deadlock (Bert Belder) + +* unix: catch some cases of watching fd twice (Ben Noordhuis) + +* test: use custom timeout for getaddrinfo_fail_sync (Ben Noordhuis) + +* Revert "win: add Windows XP support to uv_if_indextoname()" (Bert Belder) + +* win,thread: remove fallback uv_cond implementation (Bert Belder) + +* src,test: s/olny/only (cjihrig) + +* unix: close signal pipe fds on unload (Ben Noordhuis) + +* win: allow setting udp socket options before bind (cjihrig) + +* unix: return UV_ENOTSUP on FICLONE_FORCE failure (cjihrig) + +* win,pipe: remove unreferenced local variable (Bert Belder) + +* win,code: remove GetQueuedCompletionStatus-based poller (Bert Belder) + +* win: remove the remaining dynamic kernel32 imports (Bert Belder) + +* test: speedup process-title-threadsafe on macOS (cjihrig) + +* core: move all include files except uv.h to uv/ (Saúl Ibarra Corretgé) + +* win: move stdint-msvc2008.h to include/uv/ (Ben Noordhuis) + +* build: fix cygwin install (Ben Noordhuis) + +* build,win: remove MinGW Makefile (Saúl Ibarra Corretgé) + +* build: add a cmake build file (Ben Noordhuis) + +* build: add test suite option to cmake build (Ben Noordhuis) + +* unix: set errno in uv_fs_copyfile() (cjihrig) + +* samples: fix inconsistency in parse_opts vs usage (zyxwvu Shi) + +* linux: handle exclusive POLLHUP with UV_DISCONNECT (Brad King) + +* include: declare uv_cpu_times_s in higher scope (Peter Johnson) + +* doc: add uv_fs_fsync() AIX limitations (jBarz) + +* unix,win: add uv_fs_lchown() (Paolo Greppi) + +* unix: disable clang variable length array warning (Peter Johnson) + +* doc: document uv_pipe_t::ipc (Ed Schouten) + +* doc: undocument uv_req_type's UV_REQ_TYPE_PRIVATE (Ed Schouten) + +* doc: document UV_*_MAP() macros (Ed Schouten) + +* win: remove use of min() macro in pipe.c (Peter Johnson) + +* doc: add jbarz as maintainer ( + + +2018.05.08, Version 1.20.3 (Stable), 8cfd67e59195251dff793ee47c185c9d6a8f3818 + +Changes since version 1.20.2: + +* win: add Windows XP support to uv_if_indextoname() (ssrlive) + +* win: fix `'floor' undefined` compiler warning (ssrlive) + +* win, pipe: stop read for overlapped pipe (Bartosz Sosnowski) + +* build: fix utf-8 name of copyright holder (Jérémy Lal) + +* zos: initialize pollfd revents (jBarz) + +* zos,doc: add system V message queue note (jBarz) + +* linux: don't use uv__nonblock_ioctl() on sparc (Ben Noordhuis) + + +2018.04.23, Version 1.20.2 (Stable), c51fd3f66bbb386a1efdeba6812789f35a372d1e + +Changes since version 1.20.1: + +* zos: use custom semaphore (jBarz) + +* win: fix registry API error handling (Kyle Farnung) + +* build: add support for 64-bit AIX (Richard Lau) + +* aix: guard STATIC_ASSERT for glibc work around (Richard Lau) + + +2018.04.19, Version 1.20.1 (Stable), 36ac2fc8edfd5ff3e9be529be1d4a3f0d5364e94 + +Changes since version 1.20.0: + +* doc,fs: improve documentation (Bob Burger) + +* win: return a floored double from uv_uptime() (Refael Ackermann) + +* doc: clarify platform specific pipe naming (Thomas Versteeg) + +* unix: fix uv_pipe_chmod() on macOS (zzzjim) + +* unix: work around glibc semaphore race condition (Anna Henningsen) + +* tcp,openbsd: disable Unix TCP check for IPV6_ONLY (Alex Arslan) + +* test,openbsd: use RETURN_SKIP in UDP IPv6 tests (Alex Arslan) + +* test,openbsd: fix multicast test (Alex Arslan) + +* Revert "win, fs: use FILE_WRITE_ATTRIBUTES when opening files" (cjihrig) + + +2018.04.03, Version 1.20.0 (Stable), 0012178ee2b04d9e4a2c66c27cf8891ad8325ceb + +Changes since version 1.19.2: + +* unix,spawn: respect user stdio flags for new pipe (Jameson Nash) + +* Revert "Revert "unix,tcp: avoid marking server sockets connected"" (Jameson + Nash) + +* req: revisions to uv_req_t handling (Jameson Nash) + +* win: remove unnecessary initialization (cjihrig) + +* win: update uv_os_homedir() to use uv_os_getenv() (cjihrig) + +* test: fix tcp_oob test flakiness (Santiago Gimeno) + +* posix: fix uv__pollfds_del() for invalidated fd's (Jesse Gorzinski) + +* doc: README: add note on installing gyp (Jamie Davis) + +* unix: refactor uv_os_homedir to use uv_os_getenv (Santiago Gimeno) + +* unix: fix several instances of lost errno (Michael Kilburn) + +* win,tty: update several TODO comments (Ruslan Bekenev) + +* unix: add UV_FS_COPYFILE_FICLONE support (cjihrig) + +* test: fix connect_unspecified (Santiago Gimeno) + +* unix,win: add UV_FS_COPYFILE_FICLONE_FORCE support (cjihrig) + +* win: use long directory name for handle->dirw (Nicholas Vavilov) + +* build: build with -D_FILE_OFFSET_BITS=64 again (Ben Noordhuis) + +* win, fs: fix uv_fs_unlink for +R -A files (Bartosz Sosnowski) + +* win, fs: use FILE_WRITE_ATTRIBUTES when opening files (Bartosz Sosnowski) + +* unix: use __PASE__ on IBM i platforms (Jesse Gorzinski) + +* test,freebsd: fix flaky poll tests (Santiago Gimeno) + +* test: increase connection timeout to 1 second (jBarz) + +* win,tcp: handle canceled connect with ECANCELED (Jameson Nash) + + 2018.02.22, Version 1.19.2 (Stable), c5afc37e2a8a70d8ab0da8dac10b77ba78c0488c Changes since version 1.19.1: diff --git a/deps/uv/MAINTAINERS.md b/deps/uv/MAINTAINERS.md index d85deb0066b131..543dc3cda7bce2 100644 --- a/deps/uv/MAINTAINERS.md +++ b/deps/uv/MAINTAINERS.md @@ -3,6 +3,7 @@ libuv is currently managed by the following individuals: +* **Anna Henningsen** ([@addaleax](https://github.com/addaleax)) * **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz)) * **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis)) - GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis) @@ -12,8 +13,9 @@ libuv is currently managed by the following individuals: - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) -* **Imran Iqbal** ([@iWuzHere](https://github.com/iWuzHere)) +* **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq)) - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) +* **John Barboza** ([@jbarz](https://github.com/jbarz)) * **Santiago Gimeno** ([@santigimeno](https://github.com/santigimeno)) - GPG key: 612F 0EAD 9401 6223 79DF 4402 F28C 3C8D A33C 03BE (pubkey-santigimeno) * **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul)) diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index ae9d96bcf61ef9..2381425403c376 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -17,7 +17,10 @@ ACLOCAL_AMFLAGS = -I m4 AM_CPPFLAGS = -I$(top_srcdir)/include \ -I$(top_srcdir)/src -include_HEADERS=include/uv.h include/uv-errno.h include/uv-threadpool.h include/uv-version.h +include_HEADERS=include/uv.h + +uvincludedir = $(includedir)/uv +uvinclude_HEADERS=include/uv/errno.h include/uv/threadpool.h include/uv/version.h CLEANFILES = @@ -29,6 +32,7 @@ libuv_la_SOURCES = src/fs-poll.c \ src/inet.c \ src/queue.h \ src/threadpool.c \ + src/timer.c \ src/uv-data-getter-setters.c \ src/uv-common.c \ src/uv-common.h \ @@ -42,7 +46,7 @@ endif if WINNT -include_HEADERS += include/uv-win.h include/tree.h +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 @@ -64,14 +68,12 @@ libuv_la_SOURCES += src/win/async.c \ src/win/poll.c \ src/win/process-stdio.c \ src/win/process.c \ - src/win/req.c \ src/win/req-inl.h \ src/win/signal.c \ src/win/stream.c \ src/win/stream-inl.h \ src/win/tcp.c \ src/win/thread.c \ - src/win/timer.c \ src/win/tty.c \ src/win/udp.c \ src/win/util.c \ @@ -82,7 +84,7 @@ libuv_la_SOURCES += src/win/async.c \ else # WINNT -include_HEADERS += include/uv-unix.h +uvinclude_HEADERS += include/uv/unix.h AM_CPPFLAGS += -I$(top_srcdir)/src/unix libuv_la_SOURCES += src/unix/async.c \ src/unix/atomic-ops.h \ @@ -102,7 +104,6 @@ libuv_la_SOURCES += src/unix/async.c \ src/unix/stream.c \ src/unix/tcp.c \ src/unix/thread.c \ - src/unix/timer.c \ src/unix/tty.c \ src/unix/udp.c @@ -121,7 +122,6 @@ EXTRA_DIST = test/fixtures/empty_file \ README.md \ checksparse.sh \ vcbuild.bat \ - Makefile.mingw \ common.gypi \ gyp_uv.py \ uv.gyp @@ -191,6 +191,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-idle.c \ test/test-ip4-addr.c \ test/test-ip6-addr.c \ + test/test-ipc-heavy-traffic-deadlock-bug.c \ test/test-ipc-send-recv.c \ test/test-ipc.c \ test/test-list.h \ @@ -222,6 +223,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-poll-close-doesnt-corrupt-stack.c \ test/test-poll-closesocket.c \ test/test-poll-oob.c \ + test/test-process-priority.c \ test/test-process-title.c \ test/test-process-title-threadsafe.c \ test/test-queue-foreach-delete.c \ @@ -332,19 +334,18 @@ libuv_la_CFLAGS += -D_ALL_SOURCE \ -D_LINUX_SOURCE_COMPAT \ -D_THREAD_SAFE \ -DHAVE_SYS_AHAFS_EVPRODS_H -include_HEADERS += include/uv-aix.h +uvinclude_HEADERS += include/uv/aix.h libuv_la_SOURCES += src/unix/aix.c src/unix/aix-common.c endif if ANDROID -include_HEADERS += include/android-ifaddrs.h \ - include/pthread-barrier.h +uvinclude_HEADERS += include/uv/android-ifaddrs.h libuv_la_SOURCES += src/unix/android-ifaddrs.c \ src/unix/pthread-fixes.c endif if CYGWIN -include_HEADERS += include/uv-posix.h +uvinclude_HEADERS += include/uv/posix.h libuv_la_CFLAGS += -D_GNU_SOURCE libuv_la_SOURCES += src/unix/cygwin.c \ src/unix/bsd-ifaddrs.c \ @@ -358,8 +359,7 @@ libuv_la_SOURCES += src/unix/cygwin.c \ endif if DARWIN -include_HEADERS += include/uv-darwin.h \ - include/pthread-barrier.h +uvinclude_HEADERS += include/uv/darwin.h libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1 libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ @@ -372,7 +372,7 @@ test_run_tests_LDFLAGS += -lutil endif if DRAGONFLY -include_HEADERS += include/uv-bsd.h +uvinclude_HEADERS += include/uv/bsd.h libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/freebsd.c \ src/unix/kqueue.c \ @@ -381,7 +381,7 @@ test_run_tests_LDFLAGS += -lutil endif if FREEBSD -include_HEADERS += include/uv-bsd.h +uvinclude_HEADERS += include/uv/bsd.h libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/freebsd.c \ src/unix/kqueue.c \ @@ -390,7 +390,7 @@ test_run_tests_LDFLAGS += -lutil endif if LINUX -include_HEADERS += include/uv-linux.h +uvinclude_HEADERS += include/uv/linux.h libuv_la_CFLAGS += -D_GNU_SOURCE libuv_la_SOURCES += src/unix/linux-core.c \ src/unix/linux-inotify.c \ @@ -417,7 +417,7 @@ libuv_la_SOURCES += src/unix/cygwin.c \ endif if NETBSD -include_HEADERS += include/uv-bsd.h +uvinclude_HEADERS += include/uv/bsd.h libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/kqueue.c \ src/unix/netbsd.c \ @@ -426,7 +426,7 @@ test_run_tests_LDFLAGS += -lutil endif if OPENBSD -include_HEADERS += include/uv-bsd.h +uvinclude_HEADERS += include/uv/bsd.h libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/kqueue.c \ src/unix/openbsd.c \ @@ -435,14 +435,13 @@ test_run_tests_LDFLAGS += -lutil endif if SUNOS -include_HEADERS += include/uv-sunos.h +uvinclude_HEADERS += include/uv/sunos.h libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 libuv_la_SOURCES += src/unix/no-proctitle.c \ src/unix/sunos.c endif if OS390 -include_HEADERS += include/pthread-barrier.h libuv_la_CFLAGS += -D_UNIX03_THREADS \ -D_UNIX03_SOURCE \ -D_OPEN_SYS_IF_EXT=1 \ diff --git a/deps/uv/Makefile.mingw b/deps/uv/Makefile.mingw deleted file mode 100644 index 3acf9e14a9eab4..00000000000000 --- a/deps/uv/Makefile.mingw +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (c) 2013, Ben Noordhuis -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -CC ?= gcc - -CFLAGS += -Wall \ - -Wextra \ - -Wno-unused-parameter \ - -Wstrict-prototypes \ - -Iinclude \ - -Isrc \ - -Isrc/win \ - -DWIN32_LEAN_AND_MEAN \ - -D_WIN32_WINNT=0x0600 - -INCLUDES = include/stdint-msvc2008.h \ - include/tree.h \ - include/uv-errno.h \ - include/uv-threadpool.h \ - include/uv-version.h \ - include/uv-win.h \ - include/uv.h \ - src/heap-inl.h \ - src/queue.h \ - src/uv-common.h \ - src/win/atomicops-inl.h \ - src/win/handle-inl.h \ - src/win/internal.h \ - src/win/req-inl.h \ - src/win/stream-inl.h \ - src/win/winapi.h \ - src/win/winsock.h - -OBJS = src/fs-poll.o \ - src/inet.o \ - src/threadpool.o \ - src/uv-common.o \ - src/version.o \ - src/win/async.o \ - src/win/core.o \ - src/win/detect-wakeup.o \ - src/win/dl.o \ - src/win/error.o \ - src/win/fs-event.o \ - src/win/fs.o \ - src/win/getaddrinfo.o \ - src/win/getnameinfo.o \ - src/win/handle.o \ - src/win/loop-watcher.o \ - src/win/pipe.o \ - src/win/poll.o \ - src/win/process-stdio.o \ - src/win/process.o \ - src/win/req.o \ - src/win/signal.o \ - src/win/stream.o \ - src/win/tcp.o \ - src/win/thread.o \ - src/win/timer.o \ - src/win/tty.o \ - src/win/udp.o \ - src/win/util.o \ - src/win/winapi.o \ - src/win/winsock.o - -all: libuv.a - -clean: - -$(RM) $(OBJS) libuv.a - -libuv.a: $(OBJS) - $(AR) crs $@ $^ - -$(OBJS): %.o : %.c $(INCLUDES) - $(CC) $(CFLAGS) -c -o $@ $< diff --git a/deps/uv/README.md b/deps/uv/README.md index 733171be085ab5..b24b722612edf3 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -169,6 +169,22 @@ $ make check $ make install ``` +To build with [CMake](https://cmake.org/): + +```bash +$ mkdir -p out/cmake ; cd out/cmake ; cmake -DBUILD_TESTING=ON ../.. +$ make all test +# Or manually: +$ ./uv_run_tests # shared library build +$ ./uv_run_tests_a # static library build +``` + +To build with GYP, first run: + +```bash +$ git clone https://chromium.googlesource.com/external/gyp build/gyp +``` + ### Windows Prerequisites: @@ -266,8 +282,31 @@ Make sure that you specify the architecture you wish to build for in the Run: +For arm + ```bash -$ source ./android-configure NDK_PATH gyp [API_LEVEL] +$ source ./android-configure-arm NDK_PATH gyp [API_LEVEL] +$ make -C out +``` + +or for arm64 + +```bash +$ source ./android-configure-arm64 NDK_PATH gyp [API_LEVEL] +$ make -C out +``` + +or for x86 + +```bash +$ source ./android-configure-x86 NDK_PATH gyp [API_LEVEL] +$ make -C out +``` + +or for x86_64 + +```bash +$ source ./android-configure-x86_64 NDK_PATH gyp [API_LEVEL] $ make -C out ``` @@ -294,14 +333,66 @@ $ ninja -C out/Release ### Running tests -Run: +#### Build + +Build (includes tests): ```bash $ ./gyp_uv.py -f make $ make -C out +``` + +#### Run all tests + +```bash $ ./out/Debug/run-tests ``` +#### Run one test + +The list of all tests is in `test/test-list.h`. + +This invocation will cause the `run-tests` driver to fork and execute `TEST_NAME` in a child process: + +```bash +$ ./out/Debug/run-tests TEST_NAME +``` + +This invocation will cause the `run-tests` driver to execute the test within the `run-tests` process: + +```bash +$ ./out/Debug/run-tests TEST_NAME TEST_NAME +``` + +#### Debugging tools + +When running the test from within the `run-tests` process (`run-tests TEST_NAME TEST_NAME`), tools like gdb and valgrind work normally. +When running the test from a child of the `run-tests` process (`run-tests TEST_NAME`), use these tools in a fork-aware manner. + +##### Fork-aware gdb + +Use the [follow-fork-mode](https://sourceware.org/gdb/onlinedocs/gdb/Forks.html) setting: + +``` +$ gdb --args out/Debug/run-tests TEST_NAME + +(gdb) set follow-fork-mode child +... +``` + +##### Fork-aware valgrind + +Use the `--trace-children=yes` parameter: + +```bash +$ valgrind --trace-children=yes -v --tool=memcheck --leak-check=full --track-origins=yes --leak-resolution=high --show-reachable=yes --log-file=memcheck.log out/Debug/run-tests TEST_NAME +``` + +### Running benchmarks + +See the section on running tests. +The benchmark driver is `out/Debug/run-benchmarks` and the benchmarks are listed in `test/benchmark-list.h`. + ## Supported Platforms Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md). @@ -316,6 +407,13 @@ describes the package in more detail. AIX support for filesystem events is not compiled when building with `gyp`. +### z/OS Notes + +z/OS creates System V semaphores and message queues. These persist on the system +after the process terminates unless the event loop is closed. + +Use the `ipcrm` command to manually clear up System V resources. + ## Patches See the [guidelines for contributing][]. @@ -326,7 +424,7 @@ See the [guidelines for contributing][]. [libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png [x32]: https://en.wikipedia.org/wiki/X32_ABI [Python 2.6 or 2.7]: https://www.python.org/downloads/ -[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools +[Visual C++ Build Tools]: https://visualstudio.microsoft.com/visual-cpp-build-tools/ [Visual Studio 2015 Update 3]: https://www.visualstudio.com/vs/older-downloads/ [Visual Studio 2017]: https://www.visualstudio.com/downloads/ [Git for Windows]: http://git-scm.com/download/win diff --git a/deps/uv/android-configure b/deps/uv/android-configure-arm similarity index 92% rename from deps/uv/android-configure rename to deps/uv/android-configure-arm index b5c11cd40c6873..331fdd9ebcf9f9 100755 --- a/deps/uv/android-configure +++ b/deps/uv/android-configure-arm @@ -1,6 +1,6 @@ #!/bin/bash -export TOOLCHAIN=$PWD/android-toolchain +export TOOLCHAIN=$PWD/android-toolchain-arm mkdir -p $TOOLCHAIN API=${3:-24} $1/build/tools/make-standalone-toolchain.sh \ diff --git a/deps/uv/android-configure-arm64 b/deps/uv/android-configure-arm64 new file mode 100755 index 00000000000000..1acd905d775fd9 --- /dev/null +++ b/deps/uv/android-configure-arm64 @@ -0,0 +1,23 @@ +#!/bin/bash + +export TOOLCHAIN=$PWD/android-toolchain-arm64 +mkdir -p $TOOLCHAIN +API=${3:-24} +$1/build/tools/make-standalone-toolchain.sh \ + --toolchain=aarch64-linux-android-4.9 \ + --arch=arm64 \ + --install-dir=$TOOLCHAIN \ + --platform=android-$API \ + --force +export PATH=$TOOLCHAIN/bin:$PATH +export AR=aarch64-linux-android-ar +export CC=aarch64-linux-android-gcc +export CXX=aarch64-linux-android-g++ +export LINK=aarch64-linux-android-g++ +export PLATFORM=android +export CFLAGS="-D__ANDROID_API__=$API" + +if [[ $2 == 'gyp' ]] + then + ./gyp_uv.py -Dtarget_arch=arm64 -DOS=android -f make-android +fi diff --git a/deps/uv/android-configure-x86 b/deps/uv/android-configure-x86 new file mode 100755 index 00000000000000..a149715f37547f --- /dev/null +++ b/deps/uv/android-configure-x86 @@ -0,0 +1,23 @@ +#!/bin/bash + +export TOOLCHAIN=$PWD/android-toolchain-x86 +mkdir -p $TOOLCHAIN +API=${3:-24} +$1/build/tools/make-standalone-toolchain.sh \ + --toolchain=x86-4.9 \ + --arch=x86 \ + --install-dir=$TOOLCHAIN \ + --platform=android-$API \ + --force +export PATH=$TOOLCHAIN/bin:$PATH +export AR=i686-linux-android-ar +export CC=i686-linux-android-gcc +export CXX=i686-linux-android-g++ +export LINK=i686-linux-android-g++ +export PLATFORM=android +export CFLAGS="-D__ANDROID_API__=$API" + +if [[ $2 == 'gyp' ]] + then + ./gyp_uv.py -Dtarget_arch=x86 -DOS=android -f make-android +fi diff --git a/deps/uv/android-configure-x86_64 b/deps/uv/android-configure-x86_64 new file mode 100755 index 00000000000000..ff045957f7138d --- /dev/null +++ b/deps/uv/android-configure-x86_64 @@ -0,0 +1,25 @@ +#!/bin/bash + +export TOOLCHAIN=$PWD/android-toolchain-x86_64 +mkdir -p $TOOLCHAIN +API=${3:-24} +$1/build/tools/make-standalone-toolchain.sh \ + --toolchain=x86_64-4.9 \ + --arch=x86_64 \ + --install-dir=$TOOLCHAIN \ + --platform=android-$API \ + --force +export PATH=$TOOLCHAIN/bin:$PATH +export AR=x86_64-linux-android-ar +export CC=x86_64-linux-android-gcc +export CXX=x86_64-linux-android-g++ +export LINK=x86_64-linux-android-g++ +export PLATFORM=android +export CFLAGS="-D__ANDROID_API__=$API -fPIC" +export CXXFLAGS="-D__ANDROID_API__=$API -fPIC" +export LDFLAGS="-fPIC" + +if [[ $2 == 'gyp' ]] + then + ./gyp_uv.py -Dtarget_arch=x86_64 -DOS=android -f make-android +fi diff --git a/deps/uv/checksparse.sh b/deps/uv/checksparse.sh deleted file mode 100755 index 27eb529bcae13c..00000000000000 --- a/deps/uv/checksparse.sh +++ /dev/null @@ -1,253 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2013, Ben Noordhuis -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -SPARSE=${SPARSE:-sparse} - -SPARSE_FLAGS=${SPARSE_FLAGS:-" --D__POSIX__ --Wsparse-all --Wno-do-while --Wno-transparent-union --Iinclude --Isrc -"} - -SOURCES=" -include/tree.h -include/uv-unix.h -include/uv.h -src/fs-poll.c -src/inet.c -src/queue.h -src/unix/async.c -src/unix/core.c -src/unix/dl.c -src/unix/fs.c -src/unix/getaddrinfo.c -src/unix/internal.h -src/unix/loop-watcher.c -src/unix/loop.c -src/unix/pipe.c -src/unix/poll.c -src/unix/process.c -src/unix/signal.c -src/unix/stream.c -src/unix/tcp.c -src/unix/thread.c -src/unix/threadpool.c -src/unix/timer.c -src/unix/tty.c -src/unix/udp.c -src/uv-common.c -src/uv-common.h -src/uv-data-getter-setters.c -" - -TESTS=" -test/benchmark-async-pummel.c -test/benchmark-async.c -test/benchmark-fs-stat.c -test/benchmark-getaddrinfo.c -test/benchmark-loop-count.c -test/benchmark-million-async.c -test/benchmark-million-timers.c -test/benchmark-multi-accept.c -test/benchmark-ping-pongs.c -test/benchmark-pound.c -test/benchmark-pump.c -test/benchmark-sizes.c -test/benchmark-spawn.c -test/benchmark-tcp-write-batch.c -test/benchmark-thread.c -test/benchmark-udp-pummel.c -test/blackhole-server.c -test/dns-server.c -test/echo-server.c -test/run-benchmarks.c -test/run-tests.c -test/runner-unix.c -test/runner-unix.h -test/runner.c -test/runner.h -test/task.h -test/test-active.c -test/test-async.c -test/test-barrier.c -test/test-callback-order.c -test/test-callback-stack.c -test/test-condvar.c -test/test-connection-fail.c -test/test-cwd-and-chdir.c -test/test-delayed-accept.c -test/test-dlerror.c -test/test-embed.c -test/test-env-vars.c -test/test-error.c -test/test-fail-always.c -test/test-fs-copyfile.c -test/test-fs-event.c -test/test-fs-poll.c -test/test-fs.c -test/test-getters-setters.c -test/test-get-currentexe.c -test/test-get-loadavg.c -test/test-get-memory.c -test/test-get-passwd.c -test/test-getaddrinfo.c -test/test-gethostname.c -test/test-getsockname.c -test/test-homedir.c -test/test-hrtime.c -test/test-idle.c -test/test-ip6-addr.c -test/test-ipc-send-recv.c -test/test-ipc.c -test/test-loop-handles.c -test/test-multiple-listen.c -test/test-mutexes.c -test/test-pass-always.c -test/test-ping-pong.c -test/test-pipe-bind-error.c -test/test-pipe-connect-error.c -test/test-pipe-sendmsg.c -test/test-pipe-server-close.c -test/test-platform-output.c -test/test-poll-close.c -test/test-poll.c -test/test-process-title.c -test/test-process-title-threadsafe.c -test/test-ref.c -test/test-run-nowait.c -test/test-run-once.c -test/test-semaphore.c -test/test-shutdown-close.c -test/test-shutdown-eof.c -test/test-signal-multiple-loops.c -test/test-signal.c -test/test-spawn.c -test/test-stdio-over-pipes.c -test/test-tcp-bind-error.c -test/test-tcp-bind6-error.c -test/test-tcp-close-while-connecting.c -test/test-tcp-close-accept.c -test/test-tcp-close.c -test/test-tcp-connect-error-after-write.c -test/test-tcp-connect-error.c -test/test-tcp-connect-timeout.c -test/test-tcp-connect6-error.c -test/test-tcp-flags.c -test/test-tcp-open.c -test/test-tcp-read-stop.c -test/test-tcp-shutdown-after-write.c -test/test-tcp-unexpected-read.c -test/test-tcp-oob.c -test/test-tcp-write-error.c -test/test-tcp-write-to-half-open-connection.c -test/test-tcp-writealot.c -test/test-thread.c -test/test-threadpool-cancel.c -test/test-threadpool.c -test/test-timer-again.c -test/test-timer.c -test/test-tmpdir.c -test/test-tty.c -test/test-udp-dgram-too-big.c -test/test-udp-ipv6.c -test/test-udp-multicast-join.c -test/test-udp-multicast-ttl.c -test/test-udp-open.c -test/test-udp-options.c -test/test-udp-send-and-recv.c -test/test-udp-send-hang-loop.c -test/test-walk-handles.c -test/test-watcher-cross-stop.c -" - -case `uname -s` in -AIX) - SPARSE_FLAGS="$SPARSE_FLAGS -D_AIX=1" - SOURCES="$SOURCES - src/unix/aix-common.c - src/unix/aix.c" - ;; -OS400) - SPARSE_FLAGS="$SPARSE_FLAGS -D_PASE=1" - SOURCES="$SOURCES - src/unix/aix-common.c - src/unix/ibmi.c - src/unix/posix-poll.c - src/unix/no-fsevents.c - src/unix/no-proctitle.c" - ;; -Darwin) - SPARSE_FLAGS="$SPARSE_FLAGS -D__APPLE__=1" - SOURCES="$SOURCES - include/uv-bsd.h - src/unix/darwin.c - src/unix/kqueue.c - src/unix/fsevents.c" - ;; -DragonFly) - SPARSE_FLAGS="$SPARSE_FLAGS -D__DragonFly__=1" - SOURCES="$SOURCES - include/uv-bsd.h - src/unix/kqueue.c - src/unix/freebsd.c" - ;; -FreeBSD) - SPARSE_FLAGS="$SPARSE_FLAGS -D__FreeBSD__=1" - SOURCES="$SOURCES - include/uv-bsd.h - src/unix/kqueue.c - src/unix/freebsd.c" - ;; -Linux) - SPARSE_FLAGS="$SPARSE_FLAGS -D__linux__=1" - SOURCES="$SOURCES - include/uv-linux.h - src/unix/linux-inotify.c - src/unix/linux-core.c - src/unix/linux-syscalls.c - src/unix/linux-syscalls.h" - ;; -NetBSD) - SPARSE_FLAGS="$SPARSE_FLAGS -D__NetBSD__=1" - SOURCES="$SOURCES - include/uv-bsd.h - src/unix/kqueue.c - src/unix/netbsd.c" - ;; -OpenBSD) - SPARSE_FLAGS="$SPARSE_FLAGS -D__OpenBSD__=1" - SOURCES="$SOURCES - include/uv-bsd.h - src/unix/kqueue.c - src/unix/openbsd.c" - ;; -SunOS) - SPARSE_FLAGS="$SPARSE_FLAGS -D__sun=1" - SOURCES="$SOURCES - include/uv-sunos.h - src/unix/sunos.c" - ;; -esac - -for ARCH in __i386__ __x86_64__ __arm__ __mips__; do - $SPARSE $SPARSE_FLAGS -D$ARCH=1 $SOURCES -done - -# Tests are architecture independent. -$SPARSE $SPARSE_FLAGS -Itest $TESTS diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi index 572a1633b0b555..2297bdf0fb0c62 100644 --- a/deps/uv/common.gypi +++ b/deps/uv/common.gypi @@ -134,7 +134,7 @@ }] ] }], - ['OS in "freebsd dragonflybsd linux openbsd solaris android"', { + ['OS in "freebsd dragonflybsd linux openbsd solaris android aix"', { 'cflags': [ '-Wall' ], 'cflags_cc': [ '-fno-rtti', '-fno-exceptions' ], 'target_conditions': [ @@ -162,6 +162,10 @@ 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], + [ 'OS=="aix" and target_arch=="ppc64"', { + 'cflags': [ '-maix64' ], + 'ldflags': [ '-maix64' ], + }], ], }], ['OS=="mac"', { diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 4074e77841d489..0d9066bb0225a5 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.19.2], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.23.2], [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]) diff --git a/deps/uv/docs/src/conf.py b/deps/uv/docs/src/conf.py index c9b4ea38c310a5..f6f43253d364c5 100644 --- a/deps/uv/docs/src/conf.py +++ b/deps/uv/docs/src/conf.py @@ -18,7 +18,7 @@ def get_libuv_version(): - with open('../../include/uv-version.h') as f: + with open('../../include/uv/version.h') as f: data = f.read() try: m = re.search(r"""^#define UV_VERSION_MAJOR (\d+)$""", data, re.MULTILINE) diff --git a/deps/uv/docs/src/design.rst b/deps/uv/docs/src/design.rst index 487d08ba6255ad..001b12334d2354 100644 --- a/deps/uv/docs/src/design.rst +++ b/deps/uv/docs/src/design.rst @@ -126,7 +126,7 @@ so the current approach is to run blocking file I/O operations in a thread pool. For a thorough explanation of the cross-platform file I/O landscape, checkout `this post `_. -libuv currently uses a global thread pool on which all loops can queue work on. 3 types of +libuv currently uses a global thread pool on which all loops can queue work. 3 types of operations are currently run on this pool: * File system operations diff --git a/deps/uv/docs/src/errors.rst b/deps/uv/docs/src/errors.rst index 4e30447bf1f896..b8f971f5763511 100644 --- a/deps/uv/docs/src/errors.rst +++ b/deps/uv/docs/src/errors.rst @@ -323,16 +323,37 @@ Error constants API --- +.. c:function:: UV_ERRNO_MAP(iter_macro) + + Macro that expands to a series of invocations of `iter_macro` for + each of the error constants above. `iter_macro` is invoked with two + arguments: the name of the error constant without the `UV_` prefix, + and the error message string literal. + .. c:function:: const char* uv_strerror(int err) Returns the error message for the given error code. Leaks a few bytes of memory when you call it with an unknown error code. +.. c:function:: char* uv_strerror_r(int err, char* buf, size_t buflen) + + Returns the error message for the given error code. The zero-terminated + message is stored in the user-supplied buffer `buf` of at most `buflen` bytes. + + .. versionadded:: 1.22.0 + .. c:function:: const char* uv_err_name(int err) Returns the error name for the given error code. Leaks a few bytes of memory when you call it with an unknown error code. +.. c:function:: char* uv_err_name_r(int err, char* buf, size_t buflen) + + Returns the error name for the given error code. The zero-terminated + name is stored in the user-supplied buffer `buf` of at most `buflen` bytes. + + .. versionadded:: 1.22.0 + .. c:function:: int uv_translate_sys_error(int sys_errno) Returns the libuv error code equivalent to the given platform dependent error diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index 87af828a28a7fa..fcf70a35a1f66d 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -93,7 +93,8 @@ Data types UV_FS_CHOWN, UV_FS_FCHOWN, UV_FS_REALPATH, - UV_FS_COPYFILE + UV_FS_COPYFILE, + UV_FS_LCHOWN } uv_fs_type; .. c:type:: uv_dirent_t @@ -148,8 +149,8 @@ Public members .. c:member:: void* uv_fs_t.ptr - Stores the result of :c:func:`uv_fs_readlink` and serves as an alias to - `statbuf`. + Stores the result of :c:func:`uv_fs_readlink` and + :c:func:`uv_fs_realpath` and serves as an alias to `statbuf`. .. seealso:: The :c:type:`uv_req_t` members also apply. @@ -234,6 +235,10 @@ API Equivalent to :man:`fsync(2)`. + .. note:: + For AIX, `uv_fs_fsync` returns `UV_EBADF` on file descriptors referencing + non regular files. + .. c:function:: int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) Equivalent to :man:`fdatasync(2)`. @@ -249,6 +254,12 @@ API - `UV_FS_COPYFILE_EXCL`: If present, `uv_fs_copyfile()` will fail with `UV_EEXIST` if the destination path already exists. The default behavior is to overwrite the destination if it exists. + - `UV_FS_COPYFILE_FICLONE`: If present, `uv_fs_copyfile()` will attempt to + create a copy-on-write reflink. If the underlying platform does not + support copy-on-write, then a fallback copy mechanism is used. + - `UV_FS_COPYFILE_FICLONE_FORCE`: If present, `uv_fs_copyfile()` will + attempt to create a copy-on-write reflink. If the underlying platform does + not support copy-on-write, then an error is returned. .. warning:: If the destination path is created, but an error occurs while copying @@ -258,6 +269,9 @@ API .. versionadded:: 1.14.0 + .. versionchanged:: 1.20.0 `UV_FS_COPYFILE_FICLONE` and + `UV_FS_COPYFILE_FICLONE_FORCE` are supported. + .. c:function:: int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb) Limited equivalent to :man:`sendfile(2)`. @@ -302,10 +316,12 @@ API .. c:function:: int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) Equivalent to :man:`readlink(2)`. + The resulting string is stored in `req->ptr`. .. c:function:: int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) Equivalent to :man:`realpath(3)` on Unix. Windows uses `GetFinalPathNameByHandle `_. + The resulting string is stored in `req->ptr`. .. warning:: This function has certain platform-specific caveats that were discovered when used in Node. @@ -334,12 +350,15 @@ API .. c:function:: int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) .. c:function:: int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) +.. c:function:: int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) - Equivalent to :man:`chown(2)` and :man:`fchown(2)` respectively. + Equivalent to :man:`chown(2)`, :man:`fchown(2)` and :man:`lchown(2)` respectively. .. note:: These functions are not implemented on Windows. + .. versionchanged:: 1.21.0 implemented uv_fs_lchown + .. c:function:: uv_fs_type uv_fs_get_type(const uv_fs_t* req) Returns `req->fs_type`. @@ -384,6 +403,15 @@ Helper functions .. versionadded:: 1.12.0 +.. c:function:: int uv_open_osfhandle(uv_os_fd_t os_fd) + + For a OS-dependent handle, get the file descriptor in the C runtime. + On UNIX, returns the ``os_fd`` intact. On Windows, this calls `_open_osfhandle `_. + Note that the return value is still owned by the CRT, + any attempts to close it or to use it after closing the handle may lead to malfunction. + + .. versionadded:: 1.23.0 + File open constants ------------------- diff --git a/deps/uv/docs/src/handle.rst b/deps/uv/docs/src/handle.rst index cdfb76bf8c8928..86fa811d3f7eed 100644 --- a/deps/uv/docs/src/handle.rst +++ b/deps/uv/docs/src/handle.rst @@ -101,6 +101,14 @@ Public members API --- +.. c:function:: UV_HANDLE_TYPE_MAP(iter_macro) + + Macro that expands to a series of invocations of `iter_macro` for + each of the handle types. `iter_macro` is invoked with two + arguments: the name of the `uv_handle_type` element without the + `UV_` prefix, and the name of the corresponding structure type + without the `uv_` prefix and `_t` suffix. + .. c:function:: int uv_is_active(const uv_handle_t* handle) Returns non-zero if the handle is active, zero if it's inactive. What diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index 07908c98ff8e9c..cf4a7895cd147b 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -517,3 +517,35 @@ API storage required to hold the value. .. versionadded:: 1.12.0 + +.. c:function:: int uv_os_getpriority(uv_pid_t pid, int* priority) + + Retrieves the scheduling priority of the process specified by `pid`. The + returned value of `priority` is between -20 (high priority) and 19 (low + priority). + + .. note:: + On Windows, the returned priority will equal one of the `UV_PRIORITY` + constants. + + .. versionadded:: 1.23.0 + +.. c:function:: int uv_os_setpriority(uv_pid_t pid, int priority) + + Sets the scheduling priority of the process specified by `pid`. The + `priority` value range is between -20 (high priority) and 19 (low priority). + The constants `UV_PRIORITY_LOW`, `UV_PRIORITY_BELOW_NORMAL`, + `UV_PRIORITY_NORMAL`, `UV_PRIORITY_ABOVE_NORMAL`, `UV_PRIORITY_HIGH`, and + `UV_PRIORITY_HIGHEST` are also provided for convenience. + + .. note:: + On Windows, this function utilizes `SetPriorityClass()`. The `priority` + argument is mapped to a Windows priority class. When retrieving the + process priority, the result will equal one of the `UV_PRIORITY` + constants, and not necessarily the exact value of `priority`. + + .. note:: + On Windows, setting `PRIORITY_HIGHEST` will only work for elevated user, + for others it will be silently reduced to `PRIORITY_HIGH`. + + .. versionadded:: 1.23.0 diff --git a/deps/uv/docs/src/pipe.rst b/deps/uv/docs/src/pipe.rst index bdaeeba9d435d5..376d6117bbea75 100644 --- a/deps/uv/docs/src/pipe.rst +++ b/deps/uv/docs/src/pipe.rst @@ -21,7 +21,9 @@ Data types Public members ^^^^^^^^^^^^^^ -N/A +.. c:member:: int uv_pipe_t.ipc + + Whether this pipe is suitable for handle passing between processes. .. seealso:: The :c:type:`uv_stream_t` members also apply. diff --git a/deps/uv/docs/src/process.rst b/deps/uv/docs/src/process.rst index ecc3cbf34814eb..bc968554e149f2 100644 --- a/deps/uv/docs/src/process.rst +++ b/deps/uv/docs/src/process.rst @@ -109,6 +109,11 @@ Data types */ UV_READABLE_PIPE = 0x10, UV_WRITABLE_PIPE = 0x20 + /* + * Open the child pipe handle in overlapped mode on Windows. + * On Unix it is silently ignored. + */ + UV_OVERLAPPED_PIPE = 0x40 } uv_stdio_flags; diff --git a/deps/uv/docs/src/request.rst b/deps/uv/docs/src/request.rst index 54d9a2f30939da..56038287b2ae11 100644 --- a/deps/uv/docs/src/request.rst +++ b/deps/uv/docs/src/request.rst @@ -46,7 +46,6 @@ Public members UV_WORK, UV_GETADDRINFO, UV_GETNAMEINFO, - UV_REQ_TYPE_PRIVATE, UV_REQ_TYPE_MAX, } uv_req_type; @@ -54,6 +53,14 @@ Public members API --- +.. c:function:: UV_REQ_TYPE_MAP(iter_macro) + + Macro that expands to a series of invocations of `iter_macro` for + each of the request types. `iter_macro` is invoked with two + arguments: the name of the `uv_req_type` element without the `UV_` + prefix, and the name of the corresponding structure type without the + `uv_` prefix and `_t` suffix. + .. c:function:: int uv_cancel(uv_req_t* req) Cancel a pending request. Fails if the request is executing or has finished diff --git a/deps/uv/docs/src/signal.rst b/deps/uv/docs/src/signal.rst index 24354e4f7c1329..f52b64706ab890 100644 --- a/deps/uv/docs/src/signal.rst +++ b/deps/uv/docs/src/signal.rst @@ -17,12 +17,12 @@ Reception of some signals is emulated on Windows: program is given approximately 10 seconds to perform cleanup. After that Windows will unconditionally terminate it. -Watchers for other signals can be successfully created, but these signals -are never received. These signals are: `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`, -`SIGTERM` and `SIGKILL.` +* Watchers for other signals can be successfully created, but these signals + are never received. These signals are: `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`, + `SIGTERM` and `SIGKILL.` -Calls to raise() or abort() to programmatically raise a signal are -not detected by libuv; these will not trigger a signal watcher. +* Calls to raise() or abort() to programmatically raise a signal are + not detected by libuv; these will not trigger a signal watcher. .. note:: On Linux SIGRT0 and SIGRT1 (signals 32 and 33) are used by the NPTL pthreads library to diff --git a/deps/uv/docs/src/stream.rst b/deps/uv/docs/src/stream.rst index 9ec23622512519..6a704367b1b361 100644 --- a/deps/uv/docs/src/stream.rst +++ b/deps/uv/docs/src/stream.rst @@ -45,7 +45,7 @@ Data types `nread` might be 0, which does *not* indicate an error or EOF. This is equivalent to ``EAGAIN`` or ``EWOULDBLOCK`` under ``read(2)``. - The callee is responsible for stopping closing the stream when an error happens + The callee is responsible for stopping/closing the stream when an error happens by calling :c:func:`uv_read_stop` or :c:func:`uv_close`. Trying to read from the stream again is undefined. diff --git a/deps/uv/docs/src/tcp.rst b/deps/uv/docs/src/tcp.rst index e761b460d0e636..d20a6362af94d5 100644 --- a/deps/uv/docs/src/tcp.rst +++ b/deps/uv/docs/src/tcp.rst @@ -86,13 +86,13 @@ API .. c:function:: int uv_tcp_getsockname(const uv_tcp_t* handle, struct sockaddr* name, int* namelen) - Get the current address to which the handle is bound. `addr` must point to + Get the current address to which the handle is bound. `name` must point to a valid and big enough chunk of memory, ``struct sockaddr_storage`` is recommended for IPv4 and IPv6 support. .. c:function:: int uv_tcp_getpeername(const uv_tcp_t* handle, struct sockaddr* name, int* namelen) - Get the address of the peer connected to the handle. `addr` must point to + Get the address of the peer connected to the handle. `name` must point to a valid and big enough chunk of memory, ``struct sockaddr_storage`` is recommended for IPv4 and IPv6 support. diff --git a/deps/uv/docs/src/tty.rst b/deps/uv/docs/src/tty.rst index 01a0585287affc..9889a0a0b6465b 100644 --- a/deps/uv/docs/src/tty.rst +++ b/deps/uv/docs/src/tty.rst @@ -46,7 +46,7 @@ N/A API --- -.. c:function:: int uv_tty_init(uv_loop_t* loop, uv_tty_t* handle, uv_file fd, int readable) +.. c:function:: int uv_tty_init(uv_loop_t* loop, uv_tty_t* handle, uv_file fd, int unused) Initialize a new TTY stream with the given file descriptor. Usually the file descriptor will be: @@ -55,9 +55,6 @@ API * 1 = stdout * 2 = stderr - `readable`, specifies if you plan on calling :c:func:`uv_read_start` with - this stream. stdin is readable, stdout is not. - On Unix this function will determine the path of the fd of the terminal using :man:`ttyname_r(3)`, open it, and use it if the passed file descriptor refers to a TTY. This lets libuv put the tty in non-blocking mode without @@ -67,8 +64,10 @@ API ioctl TIOCGPTN or TIOCPTYGNAME, for instance OpenBSD and Solaris. .. note:: - If reopening the TTY fails, libuv falls back to blocking writes for - non-readable TTY streams. + If reopening the TTY fails, libuv falls back to blocking writes. + + .. versionchanged:: 1.23.1: the `readable` parameter is now unused and ignored. + The correct value will now be auto-detected from the kernel. .. versionchanged:: 1.9.0: the path of the TTY is determined by :man:`ttyname_r(3)`. In earlier versions libuv opened diff --git a/deps/uv/include/pthread-barrier.h b/deps/uv/include/pthread-barrier.h deleted file mode 100644 index 07db9b8a6a27e0..00000000000000 --- a/deps/uv/include/pthread-barrier.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright (c) 2016, Kari Tristan Helgason - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef _UV_PTHREAD_BARRIER_ -#define _UV_PTHREAD_BARRIER_ -#include -#include -#if !defined(__MVS__) -#include /* sem_t */ -#endif - -#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 -#define UV__PTHREAD_BARRIER_FALLBACK 1 - -/* - * To maintain ABI compatibility with - * libuv v1.x struct is padded according - * to target platform - */ -#if defined(__ANDROID__) -# define UV_BARRIER_STRUCT_PADDING \ - sizeof(pthread_mutex_t) + \ - sizeof(pthread_cond_t) + \ - sizeof(unsigned int) - \ - sizeof(void *) -#elif defined(__APPLE__) -# define UV_BARRIER_STRUCT_PADDING \ - sizeof(pthread_mutex_t) + \ - 2 * sizeof(sem_t) + \ - 2 * sizeof(unsigned int) - \ - sizeof(void *) -#else -# define UV_BARRIER_STRUCT_PADDING 0 -#endif - -typedef struct { - pthread_mutex_t mutex; - pthread_cond_t cond; - unsigned threshold; - unsigned in; - unsigned out; -} _uv_barrier; - -typedef struct { - _uv_barrier* b; - char _pad[UV_BARRIER_STRUCT_PADDING]; -} pthread_barrier_t; - -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* barrier_attr, - unsigned count); - -int pthread_barrier_wait(pthread_barrier_t* barrier); -int pthread_barrier_destroy(pthread_barrier_t *barrier); - -#endif /* _UV_PTHREAD_BARRIER_ */ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 9794d9969b620e..717c2e570b9eb9 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -45,21 +45,21 @@ extern "C" { # define UV_EXTERN /* nothing */ #endif -#include "uv-errno.h" -#include "uv-version.h" +#include "uv/errno.h" +#include "uv/version.h" #include #include #if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" +# include "uv/stdint-msvc2008.h" #else # include #endif #if defined(_WIN32) -# include "uv-win.h" +# include "uv/win.h" #else -# include "uv-unix.h" +# include "uv/unix.h" #endif /* Expand this list if necessary. */ @@ -142,6 +142,7 @@ extern "C" { XX(EHOSTDOWN, "host is down") \ XX(EREMOTEIO, "remote I/O error") \ XX(ENOTTY, "inappropriate ioctl for device") \ + XX(EFTYPE, "inappropriate file type or format") \ #define UV_HANDLE_TYPE_MAP(XX) \ XX(ASYNC, async) \ @@ -369,7 +370,10 @@ typedef enum { UV_EXTERN int uv_translate_sys_error(int sys_errno); UV_EXTERN const char* uv_strerror(int err); +UV_EXTERN char* uv_strerror_r(int err, char* buf, size_t buflen); + UV_EXTERN const char* uv_err_name(int err); +UV_EXTERN char* uv_err_name_r(int err, char* buf, size_t buflen); #define UV_REQ_FIELDS \ @@ -378,8 +382,7 @@ UV_EXTERN const char* uv_err_name(int err); /* read-only */ \ uv_req_type type; \ /* private */ \ - void* active_queue[2]; \ - void* reserved[4]; \ + void* reserved[6]; \ UV_REQ_PRIVATE_FIELDS \ /* Abstract base class of all requests. */ @@ -504,7 +507,7 @@ UV_EXTERN int uv_try_write(uv_stream_t* handle, struct uv_write_s { UV_REQ_FIELDS uv_write_cb cb; - uv_stream_t* send_handle; + uv_stream_t* send_handle; /* TODO: make private and unix-only in v2.x. */ uv_stream_t* handle; UV_WRITE_PRIVATE_FIELDS }; @@ -866,7 +869,13 @@ typedef enum { * 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 } uv_stdio_flags; typedef struct uv_stdio_container_s { @@ -998,16 +1007,18 @@ UV_EXTERN int uv_queue_work(uv_loop_t* loop, UV_EXTERN int uv_cancel(uv_req_t* req); +struct uv_cpu_times_s { + uint64_t user; + uint64_t nice; + uint64_t sys; + uint64_t idle; + uint64_t irq; +}; + struct uv_cpu_info_s { char* model; int speed; - struct uv_cpu_times_s { - uint64_t user; - uint64_t nice; - uint64_t sys; - uint64_t idle; - uint64_t irq; - } cpu_times; + struct uv_cpu_times_s cpu_times; }; struct uv_interface_address_s { @@ -1054,6 +1065,7 @@ UV_EXTERN int uv_set_process_title(const char* title); UV_EXTERN int uv_resident_set_memory(size_t* rss); UV_EXTERN int uv_uptime(double* uptime); UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd); +UV_EXTERN int uv_open_osfhandle(uv_os_fd_t os_fd); typedef struct { long tv_sec; @@ -1088,6 +1100,16 @@ UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); UV_EXTERN uv_pid_t uv_os_getpid(void); UV_EXTERN uv_pid_t uv_os_getppid(void); +#define UV_PRIORITY_LOW 19 +#define UV_PRIORITY_BELOW_NORMAL 10 +#define UV_PRIORITY_NORMAL 0 +#define UV_PRIORITY_ABOVE_NORMAL -7 +#define UV_PRIORITY_HIGH -14 +#define UV_PRIORITY_HIGHEST -20 + +UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority); +UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority); + UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); @@ -1134,7 +1156,8 @@ typedef enum { UV_FS_CHOWN, UV_FS_FCHOWN, UV_FS_REALPATH, - UV_FS_COPYFILE + UV_FS_COPYFILE, + UV_FS_LCHOWN } uv_fs_type; /* uv_fs_t is a subclass of uv_req_t. */ @@ -1191,6 +1214,18 @@ UV_EXTERN int uv_fs_write(uv_loop_t* loop, */ #define UV_FS_COPYFILE_EXCL 0x0001 +/* + * This flag can be used with uv_fs_copyfile() to attempt to create a reflink. + * If copy-on-write is not supported, a fallback copy mechanism is used. + */ +#define UV_FS_COPYFILE_FICLONE 0x0002 + +/* + * This flag can be used with uv_fs_copyfile() to attempt to create a reflink. + * If copy-on-write is not supported, an error is returned. + */ +#define UV_FS_COPYFILE_FICLONE_FORCE 0x0004 + UV_EXTERN int uv_fs_copyfile(uv_loop_t* loop, uv_fs_t* req, const char* path, @@ -1325,6 +1360,12 @@ UV_EXTERN int uv_fs_fchown(uv_loop_t* loop, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb); +UV_EXTERN int uv_fs_lchown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb); enum uv_fs_event { @@ -1531,7 +1572,10 @@ struct uv_loop_s { /* Loop reference counting. */ unsigned int active_handles; void* handle_queue[2]; - void* active_reqs[2]; + union { + void* unused[2]; + unsigned int count; + } active_reqs; /* Internal flag to signal loop stop. */ unsigned int stop_flag; UV_LOOP_PRIVATE_FIELDS diff --git a/deps/uv/include/uv-aix.h b/deps/uv/include/uv/aix.h similarity index 100% rename from deps/uv/include/uv-aix.h rename to deps/uv/include/uv/aix.h diff --git a/deps/uv/include/android-ifaddrs.h b/deps/uv/include/uv/android-ifaddrs.h similarity index 100% rename from deps/uv/include/android-ifaddrs.h rename to deps/uv/include/uv/android-ifaddrs.h diff --git a/deps/uv/include/uv-bsd.h b/deps/uv/include/uv/bsd.h similarity index 100% rename from deps/uv/include/uv-bsd.h rename to deps/uv/include/uv/bsd.h diff --git a/deps/uv/include/uv-darwin.h b/deps/uv/include/uv/darwin.h similarity index 100% rename from deps/uv/include/uv-darwin.h rename to deps/uv/include/uv/darwin.h diff --git a/deps/uv/include/uv-errno.h b/deps/uv/include/uv/errno.h similarity index 98% rename from deps/uv/include/uv-errno.h rename to deps/uv/include/uv/errno.h index aa4d4509f60dd1..8eeb95de31b065 100644 --- a/deps/uv/include/uv-errno.h +++ b/deps/uv/include/uv/errno.h @@ -433,5 +433,11 @@ # define UV__ENOTTY (-4029) #endif +#if defined(EFTYPE) && !defined(_WIN32) +# define UV__EFTYPE UV__ERR(EFTYPE) +#else +# define UV__EFTYPE (-4028) +#endif + #endif /* UV_ERRNO_H_ */ diff --git a/deps/uv/include/uv-linux.h b/deps/uv/include/uv/linux.h similarity index 100% rename from deps/uv/include/uv-linux.h rename to deps/uv/include/uv/linux.h diff --git a/deps/uv/include/uv-os390.h b/deps/uv/include/uv/os390.h similarity index 98% rename from deps/uv/include/uv-os390.h rename to deps/uv/include/uv/os390.h index 39e7384db31a5b..0267d74cbd02c9 100644 --- a/deps/uv/include/uv-os390.h +++ b/deps/uv/include/uv/os390.h @@ -22,7 +22,7 @@ #ifndef UV_MVS_H #define UV_MVS_H -#define UV_PLATFORM_SEM_T int +#define UV_PLATFORM_SEM_T long #define UV_PLATFORM_LOOP_FIELDS \ void* ep; \ diff --git a/deps/uv/include/uv-posix.h b/deps/uv/include/uv/posix.h similarity index 100% rename from deps/uv/include/uv-posix.h rename to deps/uv/include/uv/posix.h diff --git a/deps/uv/include/stdint-msvc2008.h b/deps/uv/include/uv/stdint-msvc2008.h similarity index 100% rename from deps/uv/include/stdint-msvc2008.h rename to deps/uv/include/uv/stdint-msvc2008.h diff --git a/deps/uv/include/uv-sunos.h b/deps/uv/include/uv/sunos.h similarity index 100% rename from deps/uv/include/uv-sunos.h rename to deps/uv/include/uv/sunos.h diff --git a/deps/uv/include/uv-threadpool.h b/deps/uv/include/uv/threadpool.h similarity index 100% rename from deps/uv/include/uv-threadpool.h rename to deps/uv/include/uv/threadpool.h diff --git a/deps/uv/include/tree.h b/deps/uv/include/uv/tree.h similarity index 100% rename from deps/uv/include/tree.h rename to deps/uv/include/uv/tree.h diff --git a/deps/uv/include/uv-unix.h b/deps/uv/include/uv/unix.h similarity index 95% rename from deps/uv/include/uv-unix.h rename to deps/uv/include/uv/unix.h index da32f86e8476fa..7208557b560ce8 100644 --- a/deps/uv/include/uv-unix.h +++ b/deps/uv/include/uv/unix.h @@ -42,32 +42,28 @@ #include #include -#include "uv-threadpool.h" +#include "uv/threadpool.h" #if defined(__linux__) -# include "uv-linux.h" +# include "uv/linux.h" #elif defined (__MVS__) -# include "uv-os390.h" -#elif defined(_PASE) -# include "uv-posix.h" +# include "uv/os390.h" +#elif defined(__PASE__) +# include "uv/posix.h" #elif defined(_AIX) -# include "uv-aix.h" +# include "uv/aix.h" #elif defined(__sun) -# include "uv-sunos.h" +# include "uv/sunos.h" #elif defined(__APPLE__) -# include "uv-darwin.h" +# include "uv/darwin.h" #elif defined(__DragonFly__) || \ defined(__FreeBSD__) || \ defined(__FreeBSD_kernel__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) -# include "uv-bsd.h" +# include "uv/bsd.h" #elif defined(__CYGWIN__) || defined(__MSYS__) -# include "uv-posix.h" -#endif - -#ifndef PTHREAD_BARRIER_SERIAL_THREAD -# include "pthread-barrier.h" +# include "uv/posix.h" #endif #ifndef NI_MAXHOST @@ -136,8 +132,28 @@ typedef pthread_rwlock_t uv_rwlock_t; typedef UV_PLATFORM_SEM_T uv_sem_t; typedef pthread_cond_t uv_cond_t; typedef pthread_key_t uv_key_t; -typedef pthread_barrier_t uv_barrier_t; +/* Note: guard clauses should match uv_barrier_init's in src/unix/thread.c. */ +#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD) +/* TODO(bnoordhuis) Merge into uv_barrier_t in v2. */ +struct _uv_barrier { + uv_mutex_t mutex; + uv_cond_t cond; + unsigned threshold; + unsigned in; + unsigned out; +}; + +typedef struct { + struct _uv_barrier* b; +# if defined(PTHREAD_BARRIER_SERIAL_THREAD) + /* TODO(bnoordhuis) Remove padding in v2. */ + char pad[sizeof(pthread_barrier_t) - sizeof(struct _uv_barrier*)]; +# endif +} uv_barrier_t; +#else +typedef pthread_barrier_t uv_barrier_t; +#endif /* Platform-specific definitions for uv_spawn support. */ typedef gid_t uv_gid_t; diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv/version.h similarity index 98% rename from deps/uv/include/uv-version.h rename to deps/uv/include/uv/version.h index c2753d51c7c36e..cc064e2fd87ce8 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 19 +#define UV_VERSION_MINOR 23 #define UV_VERSION_PATCH 2 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv/win.h similarity index 95% rename from deps/uv/include/uv-win.h rename to deps/uv/include/uv/win.h index 4c6c50a29c357e..d6b8b3a7f7b9a2 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv/win.h @@ -53,13 +53,13 @@ typedef struct pollfd { #include #if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" +# include "uv/stdint-msvc2008.h" #else # include #endif -#include "tree.h" -#include "uv-threadpool.h" +#include "uv/tree.h" +#include "uv/threadpool.h" #define MAX_PIPENAME_LEN 256 @@ -86,8 +86,8 @@ typedef struct pollfd { #define SIGKILL 9 #define SIGWINCH 28 -/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many */ -/* unix-like platforms. However MinGW doesn't define it, so we do. */ +/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many unix-like + * platforms. However MinGW doesn't define it, so we do. */ #ifndef SIGABRT_COMPAT # define SIGABRT_COMPAT 6 #endif @@ -244,7 +244,7 @@ typedef union { CRITICAL_SECTION waiters_count_lock; HANDLE signal_event; HANDLE broadcast_event; - } fallback; + } unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */ } uv_cond_t; typedef union { @@ -308,8 +308,6 @@ typedef struct { char* errmsg; } uv_lib_t; -RB_HEAD(uv_timer_tree_s, uv_timer_s); - #define UV_LOOP_PRIVATE_FIELDS \ /* The loop's I/O completion port */ \ HANDLE iocp; \ @@ -321,8 +319,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); uv_req_t* pending_reqs_tail; \ /* Head of a single-linked list of closed handles */ \ uv_handle_t* endgame_handles; \ - /* The head of the timers tree */ \ - struct uv_timer_tree_s timers; \ + /* TODO(bnoordhuis) Stop heap-allocating |timer_heap| in libuv v2.x. */ \ + void* timer_heap; \ /* Lists of active loop (prepare / check / idle) watchers */ \ uv_prepare_t* prepare_handles; \ uv_check_t* check_handles; \ @@ -368,10 +366,10 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); } u; \ struct uv_req_s* next_req; -#define UV_WRITE_PRIVATE_FIELDS \ - int ipc_header; \ - uv_buf_t write_buffer; \ - HANDLE event_handle; \ +#define UV_WRITE_PRIVATE_FIELDS \ + int coalesced; \ + uv_buf_t write_buffer; \ + HANDLE event_handle; \ HANDLE wait_handle; #define UV_CONNECT_PRIVATE_FIELDS \ @@ -459,16 +457,17 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #define uv_pipe_connection_fields \ uv_timer_t* eof_timer; \ - uv_write_t ipc_header_write_req; \ - int ipc_pid; \ - uint64_t remaining_ipc_rawdata_bytes; \ - struct { \ - void* queue[2]; \ - int queue_len; \ - } pending_ipc_info; \ + uv_write_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \ + DWORD ipc_remote_pid; \ + union { \ + uint32_t payload_remaining; \ + uint64_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \ + } ipc_data_frame; \ + void* ipc_xfer_queue[2]; \ + int ipc_xfer_queue_length; \ uv_write_t* non_overlapped_writes_tail; \ - uv_mutex_t readfile_mutex; \ - volatile HANDLE readfile_thread; + CRITICAL_SECTION readfile_thread_lock; \ + volatile HANDLE readfile_thread_handle; #define UV_PIPE_PRIVATE_FIELDS \ HANDLE handle; \ @@ -478,8 +477,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); struct { uv_pipe_connection_fields } conn; \ } pipe; -/* TODO: put the parser states in an union - TTY handles are always */ -/* half-duplex so read-state can safely overlap write-state. */ +/* TODO: put the parser states in an union - TTY handles are always half-duplex + * so read-state can safely overlap write-state. */ #define UV_TTY_PRIVATE_FIELDS \ HANDLE handle; \ union { \ @@ -528,8 +527,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); unsigned char events; #define UV_TIMER_PRIVATE_FIELDS \ - RB_ENTRY(uv_timer_s) tree_entry; \ - uint64_t due; \ + void* heap_node[3]; \ + int unused; \ + uint64_t timeout; \ uint64_t repeat; \ uint64_t start_id; \ uv_timer_cb timer_cb; diff --git a/deps/uv/libuv.pc.in b/deps/uv/libuv.pc.in index 55c4b65d5dc5cf..1d7b86f751764c 100644 --- a/deps/uv/libuv.pc.in +++ b/deps/uv/libuv.pc.in @@ -3,7 +3,7 @@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ -Name: @PACKAGE_NAME@ +Name: libuv Version: @PACKAGE_VERSION@ Description: multi-platform support library with a focus on asynchronous I/O. URL: http://libuv.org/ diff --git a/deps/uv/m4/libuv-check-flags.m4 b/deps/uv/m4/libuv-check-flags.m4 index 59c30635577d1a..e347056ae2ef2c 100644 --- a/deps/uv/m4/libuv-check-flags.m4 +++ b/deps/uv/m4/libuv-check-flags.m4 @@ -1,5 +1,5 @@ dnl Macros to check the presence of generic (non-typed) symbols. -dnl Copyright (c) 2006-2008 Diego Pettenà +dnl Copyright (c) 2006-2008 Diego Pettenò dnl Copyright (c) 2006-2008 xine project dnl dnl This program is free software; you can redistribute it and/or modify @@ -316,4 +316,4 @@ AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], [Define the highest alignment supported]) fi -]) \ No newline at end of file +]) diff --git a/deps/uv/samples/socks5-proxy/main.c b/deps/uv/samples/socks5-proxy/main.c index 04020cbd3addd8..e77c7c69078dd6 100644 --- a/deps/uv/samples/socks5-proxy/main.c +++ b/deps/uv/samples/socks5-proxy/main.c @@ -63,9 +63,9 @@ const char *_getprogname(void) { static void parse_opts(server_config *cf, int argc, char **argv) { int opt; - while (-1 != (opt = getopt(argc, argv, "H:hp:"))) { + while (-1 != (opt = getopt(argc, argv, "b:hp:"))) { switch (opt) { - case 'H': + case 'b': cf->bind_host = optarg; break; @@ -85,7 +85,7 @@ static void parse_opts(server_config *cf, int argc, char **argv) { static void usage(void) { printf("Usage:\n" "\n" - " %s [-b
[-h] [-p ]\n" + " %s [-b
] [-h] [-p ]\n" "\n" "Options:\n" "\n" diff --git a/deps/uv/src/fs-poll.c b/deps/uv/src/fs-poll.c index ee73d5a2e6e949..6c82dfc1d76302 100644 --- a/deps/uv/src/fs-poll.c +++ b/deps/uv/src/fs-poll.c @@ -83,7 +83,7 @@ int uv_fs_poll_start(uv_fs_poll_t* handle, if (err < 0) goto error; - ctx->timer_handle.flags |= UV__HANDLE_INTERNAL; + ctx->timer_handle.flags |= UV_HANDLE_INTERNAL; uv__handle_unref(&ctx->timer_handle); err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb); @@ -248,7 +248,7 @@ static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) { #include "win/handle-inl.h" void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) { - assert(handle->flags & UV__HANDLE_CLOSING); + assert(handle->flags & UV_HANDLE_CLOSING); assert(!(handle->flags & UV_HANDLE_CLOSED)); uv__handle_close(handle); } diff --git a/deps/uv/src/inet.c b/deps/uv/src/inet.c index da63a688c4e424..4598ca1e9f9670 100644 --- a/deps/uv/src/inet.c +++ b/deps/uv/src/inet.c @@ -19,7 +19,7 @@ #include #if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" +# include "uv/stdint-msvc2008.h" #else # include #endif diff --git a/deps/uv/src/threadpool.c b/deps/uv/src/threadpool.c index 413d1c204c2660..4258933c724782 100644 --- a/deps/uv/src/threadpool.c +++ b/deps/uv/src/threadpool.c @@ -33,12 +33,18 @@ static uv_once_t once = UV_ONCE_INIT; static uv_cond_t cond; static uv_mutex_t mutex; static unsigned int idle_threads; +static unsigned int slow_io_work_running; static unsigned int nthreads; static uv_thread_t* threads; static uv_thread_t default_threads[4]; static QUEUE exit_message; static QUEUE wq; +static QUEUE run_slow_work_message; +static QUEUE slow_io_pending_wq; +static unsigned int slow_work_thread_threshold(void) { + return (nthreads + 1) / 2; +} static void uv__cancelled(struct uv__work* w) { abort(); @@ -51,34 +57,67 @@ static void uv__cancelled(struct uv__work* w) { static void worker(void* arg) { struct uv__work* w; QUEUE* q; + int is_slow_work; uv_sem_post((uv_sem_t*) arg); arg = NULL; + uv_mutex_lock(&mutex); for (;;) { - uv_mutex_lock(&mutex); - - while (QUEUE_EMPTY(&wq)) { + /* `mutex` should always be locked at this point. */ + + /* Keep waiting while either no work is present or only slow I/O + and we're at the threshold for that. */ + while (QUEUE_EMPTY(&wq) || + (QUEUE_HEAD(&wq) == &run_slow_work_message && + QUEUE_NEXT(&run_slow_work_message) == &wq && + slow_io_work_running >= slow_work_thread_threshold())) { idle_threads += 1; uv_cond_wait(&cond, &mutex); idle_threads -= 1; } q = QUEUE_HEAD(&wq); - - if (q == &exit_message) + if (q == &exit_message) { uv_cond_signal(&cond); - else { + uv_mutex_unlock(&mutex); + break; + } + + QUEUE_REMOVE(q); + QUEUE_INIT(q); /* Signal uv_cancel() that the work req is executing. */ + + is_slow_work = 0; + if (q == &run_slow_work_message) { + /* If we're at the slow I/O threshold, re-schedule until after all + other work in the queue is done. */ + if (slow_io_work_running >= slow_work_thread_threshold()) { + QUEUE_INSERT_TAIL(&wq, q); + continue; + } + + /* If we encountered a request to run slow I/O work but there is none + to run, that means it's cancelled => Start over. */ + if (QUEUE_EMPTY(&slow_io_pending_wq)) + continue; + + is_slow_work = 1; + slow_io_work_running++; + + q = QUEUE_HEAD(&slow_io_pending_wq); QUEUE_REMOVE(q); - QUEUE_INIT(q); /* Signal uv_cancel() that the work req is - executing. */ + QUEUE_INIT(q); + + /* If there is more slow I/O work, schedule it to be run as well. */ + if (!QUEUE_EMPTY(&slow_io_pending_wq)) { + QUEUE_INSERT_TAIL(&wq, &run_slow_work_message); + if (idle_threads > 0) + uv_cond_signal(&cond); + } } uv_mutex_unlock(&mutex); - if (q == &exit_message) - break; - w = QUEUE_DATA(q, struct uv__work, wq); w->work(w); @@ -88,12 +127,32 @@ static void worker(void* arg) { QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq); uv_async_send(&w->loop->wq_async); uv_mutex_unlock(&w->loop->wq_mutex); + + /* Lock `mutex` since that is expected at the start of the next + * iteration. */ + uv_mutex_lock(&mutex); + if (is_slow_work) { + /* `slow_io_work_running` is protected by `mutex`. */ + slow_io_work_running--; + } } } -static void post(QUEUE* q) { +static void post(QUEUE* q, enum uv__work_kind kind) { uv_mutex_lock(&mutex); + if (kind == UV__WORK_SLOW_IO) { + /* Insert into a separate queue. */ + QUEUE_INSERT_TAIL(&slow_io_pending_wq, q); + if (!QUEUE_EMPTY(&run_slow_work_message)) { + /* Running slow I/O tasks is already scheduled => Nothing to do here. + The worker that runs said other task will schedule this one as well. */ + uv_mutex_unlock(&mutex); + return; + } + q = &run_slow_work_message; + } + QUEUE_INSERT_TAIL(&wq, q); if (idle_threads > 0) uv_cond_signal(&cond); @@ -108,7 +167,7 @@ UV_DESTRUCTOR(static void cleanup(void)) { if (nthreads == 0) return; - post(&exit_message); + post(&exit_message, UV__WORK_CPU); for (i = 0; i < nthreads; i++) if (uv_thread_join(threads + i)) @@ -156,6 +215,8 @@ static void init_threads(void) { abort(); QUEUE_INIT(&wq); + QUEUE_INIT(&slow_io_pending_wq); + QUEUE_INIT(&run_slow_work_message); if (uv_sem_init(&sem, 0)) abort(); @@ -194,13 +255,14 @@ static void init_once(void) { void uv__work_submit(uv_loop_t* loop, struct uv__work* w, + enum uv__work_kind kind, void (*work)(struct uv__work* w), void (*done)(struct uv__work* w, int status)) { uv_once(&once, init_once); w->loop = loop; w->work = work; w->done = done; - post(&w->wq); + post(&w->wq, kind); } @@ -284,7 +346,11 @@ int uv_queue_work(uv_loop_t* loop, req->loop = loop; req->work_cb = work_cb; req->after_work_cb = after_work_cb; - uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done); + uv__work_submit(loop, + &req->work_req, + UV__WORK_CPU, + uv__queue_work, + uv__queue_done); return 0; } diff --git a/deps/uv/src/unix/timer.c b/deps/uv/src/timer.c similarity index 92% rename from deps/uv/src/unix/timer.c rename to deps/uv/src/timer.c index 54dabfe7df9e27..2bf449a736c2bb 100644 --- a/deps/uv/src/unix/timer.c +++ b/deps/uv/src/timer.c @@ -19,13 +19,22 @@ */ #include "uv.h" -#include "internal.h" +#include "uv-common.h" #include "heap-inl.h" #include #include +static struct heap *timer_heap(const uv_loop_t* loop) { +#ifdef _WIN32 + return (struct heap*) loop->timer_heap; +#else + return (struct heap*) &loop->timer_heap; +#endif +} + + static int timer_less_than(const struct heap_node* ha, const struct heap_node* hb) { const uv_timer_t* a; @@ -81,7 +90,7 @@ int uv_timer_start(uv_timer_t* handle, /* start_id is the second index to be compared in uv__timer_cmp() */ handle->start_id = handle->loop->timer_counter++; - heap_insert((struct heap*) &handle->loop->timer_heap, + heap_insert(timer_heap(handle->loop), (struct heap_node*) &handle->heap_node, timer_less_than); uv__handle_start(handle); @@ -94,7 +103,7 @@ int uv_timer_stop(uv_timer_t* handle) { if (!uv__is_active(handle)) return 0; - heap_remove((struct heap*) &handle->loop->timer_heap, + heap_remove(timer_heap(handle->loop), (struct heap_node*) &handle->heap_node, timer_less_than); uv__handle_stop(handle); @@ -131,7 +140,7 @@ int uv__next_timeout(const uv_loop_t* loop) { const uv_timer_t* handle; uint64_t diff; - heap_node = heap_min((const struct heap*) &loop->timer_heap); + heap_node = heap_min(timer_heap(loop)); if (heap_node == NULL) return -1; /* block indefinitely */ @@ -152,7 +161,7 @@ void uv__run_timers(uv_loop_t* loop) { uv_timer_t* handle; for (;;) { - heap_node = heap_min((struct heap*) &loop->timer_heap); + heap_node = heap_min(timer_heap(loop)); if (heap_node == NULL) break; diff --git a/deps/uv/src/unix/android-ifaddrs.c b/deps/uv/src/unix/android-ifaddrs.c index bf30b14179509d..99fb25a43b4279 100644 --- a/deps/uv/src/unix/android-ifaddrs.c +++ b/deps/uv/src/unix/android-ifaddrs.c @@ -23,7 +23,7 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "android-ifaddrs.h" +#include "uv/android-ifaddrs.h" #include "uv-common.h" #include diff --git a/deps/uv/src/unix/bsd-ifaddrs.c b/deps/uv/src/unix/bsd-ifaddrs.c index 0d0215448640a4..9825b1c4db4865 100644 --- a/deps/uv/src/unix/bsd-ifaddrs.c +++ b/deps/uv/src/unix/bsd-ifaddrs.c @@ -119,16 +119,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { continue; address = *addresses; + memset(address->phys_addr, 0, sizeof(address->phys_addr)); for (i = 0; i < *count; i++) { if (strcmp(address->name, ent->ifa_name) == 0) { -#if defined(__CYGWIN__) || defined(__MSYS__) - memset(address->phys_addr, 0, sizeof(address->phys_addr)); -#else struct sockaddr_dl* sa_addr; sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); -#endif } address++; } diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 3741c1d06b2d79..f92446ff42b86b 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -116,7 +116,7 @@ uint64_t uv_hrtime(void) { void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { assert(!uv__is_closing(handle)); - handle->flags |= UV_CLOSING; + handle->flags |= UV_HANDLE_CLOSING; handle->close_cb = close_cb; switch (handle->type) { @@ -174,8 +174,8 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { case UV_SIGNAL: uv__signal_close((uv_signal_t*) handle); - /* Signal handles may not be closed immediately. The signal code will */ - /* itself close uv__make_close_pending whenever appropriate. */ + /* Signal handles may not be closed immediately. The signal code will + * itself close uv__make_close_pending whenever appropriate. */ return; default: @@ -214,8 +214,8 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { } void uv__make_close_pending(uv_handle_t* handle) { - assert(handle->flags & UV_CLOSING); - assert(!(handle->flags & UV_CLOSED)); + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->next_closing = handle->loop->closing_handles; handle->loop->closing_handles = handle; } @@ -241,15 +241,17 @@ int uv__getiovmax(void) { static void uv__finish_close(uv_handle_t* handle) { - /* Note: while the handle is in the UV_CLOSING state now, it's still possible - * for it to be active in the sense that uv__is_active() returns true. + /* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still + * possible for it to be active in the sense that uv__is_active() returns + * true. + * * A good example is when the user calls uv_shutdown(), immediately followed * by uv_close(). The handle is considered active at this point because the * completion of the shutdown req is still pending. */ - assert(handle->flags & UV_CLOSING); - assert(!(handle->flags & UV_CLOSED)); - handle->flags |= UV_CLOSED; + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + handle->flags |= UV_HANDLE_CLOSED; switch (handle->type) { case UV_PREPARE: @@ -536,7 +538,7 @@ int uv__close_nocheckstdio(int fd) { int uv__close(int fd) { assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ #if defined(__MVS__) - epoll_file_close(fd); + SAVE_ERRNO(epoll_file_close(fd)); #endif return uv__close_nocheckstdio(fd); } @@ -927,6 +929,11 @@ int uv__io_active(const uv__io_t* w, unsigned int events) { } +int uv__fd_exists(uv_loop_t* loop, int fd) { + return (unsigned) fd < loop->nwatchers && loop->watchers[fd] != NULL; +} + + int uv_getrusage(uv_rusage_t* rusage) { struct rusage usage; @@ -1048,29 +1055,16 @@ int uv__dup2_cloexec(int oldfd, int newfd) { int uv_os_homedir(char* buffer, size_t* size) { uv_passwd_t pwd; - char* buf; size_t len; int r; - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - /* Check if the HOME environment variable is set first */ - buf = getenv("HOME"); + /* Check if the HOME environment variable is set first. The task of + performing input validation on buffer and size is taken care of by + uv_os_getenv(). */ + r = uv_os_getenv("HOME", buffer, size); - if (buf != NULL) { - len = strlen(buf); - - if (len >= *size) { - *size = len + 1; - return UV_ENOBUFS; - } - - memcpy(buffer, buf, len + 1); - *size = len; - - return 0; - } + if (r != UV_ENOENT) + return r; /* HOME is not set, so call uv__getpwuid_r() */ r = uv__getpwuid_r(&pwd); @@ -1344,6 +1338,9 @@ uv_os_fd_t uv_get_osfhandle(int fd) { return fd; } +int uv_open_osfhandle(uv_os_fd_t os_fd) { + return os_fd; +} uv_pid_t uv_os_getpid(void) { return getpid(); @@ -1353,3 +1350,31 @@ uv_pid_t uv_os_getpid(void) { uv_pid_t uv_os_getppid(void) { return getppid(); } + + +int uv_os_getpriority(uv_pid_t pid, int* priority) { + int r; + + if (priority == NULL) + return UV_EINVAL; + + errno = 0; + r = getpriority(PRIO_PROCESS, (int) pid); + + if (r == -1 && errno != 0) + return UV__ERR(errno); + + *priority = r; + return 0; +} + + +int uv_os_setpriority(uv_pid_t pid, int priority) { + if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW) + return UV_EINVAL; + + if (setpriority(PRIO_PROCESS, (int) pid, priority) != 0) + return UV__ERR(errno); + + return 0; +} diff --git a/deps/uv/src/unix/cygwin.c b/deps/uv/src/unix/cygwin.c index 9fe4093ef46fb0..9da20e203aa238 100644 --- a/deps/uv/src/unix/cygwin.c +++ b/deps/uv/src/unix/cygwin.c @@ -38,7 +38,7 @@ int uv_uptime(double* uptime) { int uv_resident_set_memory(size_t* rss) { /* FIXME: read /proc/meminfo? */ *rss = 0; - return UV_ENOSYS; + return 0; } int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 92e2d255702fd7..3db5f89c9503d2 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #if defined(__DragonFly__) || \ @@ -62,6 +61,13 @@ #if defined(__APPLE__) # include +#elif defined(__linux__) && !defined(FICLONE) +# include +# define FICLONE _IOW(0x94, 9, int) +#endif + +#if defined(_AIX) && !defined(_AIX71) +# include #endif #define INIT(subtype) \ @@ -117,7 +123,11 @@ do { \ if (cb != NULL) { \ uv__req_register(loop, req); \ - uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \ + uv__work_submit(loop, \ + &req->work_req, \ + UV__WORK_FAST_IO, \ + uv__fs_work, \ + uv__fs_done); \ return 0; \ } \ else { \ @@ -162,59 +172,17 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { static ssize_t uv__fs_futime(uv_fs_t* req) { -#if defined(__linux__) +#if defined(__linux__) \ + || defined(_AIX71) /* utimesat() has nanosecond resolution but we stick to microseconds * for the sake of consistency with other platforms. */ - static int no_utimesat; struct timespec ts[2]; - struct timeval tv[2]; - char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)]; - int r; - - if (no_utimesat) - goto skip; - ts[0].tv_sec = req->atime; ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; ts[1].tv_sec = req->mtime; ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; - - r = uv__utimesat(req->file, NULL, ts, 0); - if (r == 0) - return r; - - if (errno != ENOSYS) - return r; - - no_utimesat = 1; - -skip: - - tv[0].tv_sec = req->atime; - tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; - tv[1].tv_sec = req->mtime; - tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; - snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file); - - r = utimes(path, tv); - if (r == 0) - return r; - - switch (errno) { - case ENOENT: - if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF) - break; - /* Fall through. */ - - case EACCES: - case ENOTDIR: - errno = ENOSYS; - break; - } - - return r; - + return futimens(req->file, ts); #elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ @@ -232,13 +200,6 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { # else return futimes(req->file, tv); # endif -#elif defined(_AIX71) - struct timespec ts[2]; - ts[0].tv_sec = req->atime; - ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; - ts[1].tv_sec = req->mtime; - ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; - return futimens(req->file, ts); #elif defined(__MVS__) attrib_t atr; memset(&atr, 0, sizeof(atr)); @@ -301,17 +262,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) { #if defined(__linux__) static int no_preadv; #endif + unsigned int iovmax; ssize_t result; -#if defined(_AIX) - struct stat buf; - if(fstat(req->file, &buf)) - return -1; - if(S_ISDIR(buf.st_mode)) { - errno = EISDIR; - return -1; - } -#endif /* defined(_AIX) */ + iovmax = uv__getiovmax(); + if (req->nbufs > iovmax) + req->nbufs = iovmax; + if (req->off < 0) { if (req->nbufs == 1) result = read(req->file, req->bufs[0].base, req->bufs[0].len); @@ -330,25 +287,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) { if (no_preadv) retry: # endif { - off_t nread; - size_t index; - - nread = 0; - index = 0; - result = 1; - do { - if (req->bufs[index].len > 0) { - result = pread(req->file, - req->bufs[index].base, - req->bufs[index].len, - req->off + nread); - if (result > 0) - nread += result; - } - index++; - } while (index < req->nbufs && result > 0); - if (nread > 0) - result = nread; + result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off); } # if defined(__linux__) else { @@ -366,6 +305,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) { } done: + /* Early cleanup of bufs allocation, since we're done with it. */ + if (req->bufs != req->bufsml) + uv__free(req->bufs); + + req->bufs = NULL; + req->nbufs = 0; + return result; } @@ -430,11 +376,13 @@ static ssize_t uv__fs_pathmax_size(const char* path) { } static ssize_t uv__fs_readlink(uv_fs_t* req) { + ssize_t maxlen; ssize_t len; char* buf; + char* newbuf; - len = uv__fs_pathmax_size(req->path); - buf = uv__malloc(len + 1); + maxlen = uv__fs_pathmax_size(req->path); + buf = uv__malloc(maxlen); if (buf == NULL) { errno = ENOMEM; @@ -442,17 +390,28 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) { } #if defined(__MVS__) - len = os390_readlink(req->path, buf, len); + len = os390_readlink(req->path, buf, maxlen); #else - len = readlink(req->path, buf, len); + len = readlink(req->path, buf, maxlen); #endif - if (len == -1) { uv__free(buf); return -1; } + /* Uncommon case: resize to make room for the trailing nul byte. */ + if (len == maxlen) { + newbuf = uv__realloc(buf, len + 1); + + if (newbuf == NULL) { + uv__free(buf); + return -1; + } + + buf = newbuf; + } + buf[len] = '\0'; req->ptr = buf; @@ -695,10 +654,48 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { static ssize_t uv__fs_utime(uv_fs_t* req) { +#if defined(__linux__) \ + || defined(_AIX71) \ + || defined(__sun) + /* utimesat() has nanosecond resolution but we stick to microseconds + * for the sake of consistency with other platforms. + */ + struct timespec ts[2]; + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; + return utimensat(AT_FDCWD, req->path, ts, 0); +#elif defined(__APPLE__) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__FreeBSD_kernel__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) + struct timeval tv[2]; + tv[0].tv_sec = req->atime; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; + return utimes(req->path, tv); +#elif defined(_AIX) \ + && !defined(_AIX71) struct utimbuf buf; buf.actime = req->atime; buf.modtime = req->mtime; - return utime(req->path, &buf); /* TODO use utimes() where available */ + return utime(req->path, &buf); +#elif defined(__MVS__) + attrib_t atr; + memset(&atr, 0, sizeof(atr)); + atr.att_mtimechg = 1; + atr.att_atimechg = 1; + atr.att_mtime = req->mtime; + atr.att_atime = req->atime; + return __lchattr(req->path, &atr, sizeof(atr)); +#else + errno = ENOSYS; + return -1; +#endif } @@ -736,25 +733,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) { if (no_pwritev) retry: # endif { - off_t written; - size_t index; - - written = 0; - index = 0; - r = 0; - do { - if (req->bufs[index].len > 0) { - r = pwrite(req->file, - req->bufs[index].base, - req->bufs[index].len, - req->off + written); - if (r > 0) - written += r; - } - index++; - } while (index < req->nbufs && r >= 0); - if (written > 0) - r = written; + r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off); } # if defined(__linux__) else { @@ -790,6 +769,19 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { if (req->flags & UV_FS_COPYFILE_EXCL) flags |= COPYFILE_EXCL; +#ifdef COPYFILE_CLONE + if (req->flags & UV_FS_COPYFILE_FICLONE) + flags |= COPYFILE_CLONE; +#endif + + if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { +#ifdef COPYFILE_CLONE_FORCE + flags |= COPYFILE_CLONE_FORCE; +#else + return UV_ENOSYS; +#endif + } + return copyfile(req->path, req->new_path, NULL, flags); #else uv_fs_t fs_req; @@ -842,6 +834,31 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { goto out; } +#ifdef FICLONE + if (req->flags & UV_FS_COPYFILE_FICLONE || + req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { + if (ioctl(dstfd, FICLONE, srcfd) == -1) { + /* If an error occurred that the sendfile fallback also won't handle, or + this is a force clone then exit. Otherwise, fall through to try using + sendfile(). */ + if (errno != ENOTTY && errno != EOPNOTSUPP && errno != EXDEV) { + err = UV__ERR(errno); + goto out; + } else if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { + err = UV_ENOTSUP; + goto out; + } + } else { + goto out; + } + } +#else + if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { + err = UV_ENOSYS; + goto out; + } +#endif + bytes_to_send = statsbuf.st_size; in_offset = 0; while (bytes_to_send != 0) { @@ -888,7 +905,11 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { } } - return result; + if (result == 0) + return 0; + + errno = UV__ERR(result); + return -1; #endif } @@ -1004,9 +1025,21 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) { return ret; } +static size_t uv__fs_buf_offset(uv_buf_t* bufs, size_t size) { + size_t offset; + /* Figure out which bufs are done */ + for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset) + size -= bufs[offset].len; -typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req); -static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) { + /* Fix a partial read/write */ + if (size > 0) { + bufs[offset].base += size; + bufs[offset].len -= size; + } + return offset; +} + +static ssize_t uv__fs_write_all(uv_fs_t* req) { unsigned int iovmax; unsigned int nbufs; uv_buf_t* bufs; @@ -1023,7 +1056,10 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) if (req->nbufs > iovmax) req->nbufs = iovmax; - result = process(req); + do + result = uv__fs_write(req); + while (result < 0 && errno == EINTR); + if (result <= 0) { if (total == 0) total = result; @@ -1033,14 +1069,12 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) if (req->off >= 0) req->off += result; + req->nbufs = uv__fs_buf_offset(req->bufs, result); req->bufs += req->nbufs; nbufs -= req->nbufs; total += result; } - if (errno == EINTR && total == -1) - return total; - if (bufs != req->bufsml) uv__free(bufs); @@ -1057,7 +1091,8 @@ static void uv__fs_work(struct uv__work* w) { ssize_t r; req = container_of(w, uv_fs_t, work_req); - retry_on_eintr = !(req->fs_type == UV_FS_CLOSE); + retry_on_eintr = !(req->fs_type == UV_FS_CLOSE || + req->fs_type == UV_FS_READ); do { errno = 0; @@ -1075,6 +1110,7 @@ static void uv__fs_work(struct uv__work* w) { X(COPYFILE, uv__fs_copyfile(req)); X(FCHMOD, fchmod(req->file, req->mode)); X(FCHOWN, fchown(req->file, req->uid, req->gid)); + X(LCHOWN, lchown(req->path, req->uid, req->gid)); X(FDATASYNC, uv__fs_fdatasync(req)); X(FSTAT, uv__fs_fstat(req->file, &req->statbuf)); X(FSYNC, uv__fs_fsync(req)); @@ -1085,7 +1121,7 @@ static void uv__fs_work(struct uv__work* w) { X(MKDIR, mkdir(req->path, req->mode)); X(MKDTEMP, uv__fs_mkdtemp(req)); X(OPEN, uv__fs_open(req)); - X(READ, uv__fs_buf_iter(req, uv__fs_read)); + X(READ, uv__fs_read(req)); X(SCANDIR, uv__fs_scandir(req)); X(READLINK, uv__fs_readlink(req)); X(REALPATH, uv__fs_realpath(req)); @@ -1096,7 +1132,7 @@ static void uv__fs_work(struct uv__work* w) { X(SYMLINK, symlink(req->path, req->new_path)); X(UNLINK, unlink(req->path)); X(UTIME, uv__fs_utime(req)); - X(WRITE, uv__fs_buf_iter(req, uv__fs_write)); + X(WRITE, uv__fs_write_all(req)); default: abort(); } #undef X @@ -1201,6 +1237,20 @@ int uv_fs_fchown(uv_loop_t* loop, } +int uv_fs_lchown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb) { + INIT(LCHOWN); + PATH; + req->uid = uid; + req->gid = gid; + POST; +} + + int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { INIT(FDATASYNC); req->file = file; @@ -1504,8 +1554,11 @@ int uv_fs_copyfile(uv_loop_t* loop, uv_fs_cb cb) { INIT(COPYFILE); - if (flags & ~UV_FS_COPYFILE_EXCL) + if (flags & ~(UV_FS_COPYFILE_EXCL | + UV_FS_COPYFILE_FICLONE | + UV_FS_COPYFILE_FICLONE_FORCE)) { return UV_EINVAL; + } PATH2; req->flags = flags; diff --git a/deps/uv/src/unix/fsevents.c b/deps/uv/src/unix/fsevents.c index 47d8024b6d51ba..ee45299b791294 100644 --- a/deps/uv/src/unix/fsevents.c +++ b/deps/uv/src/unix/fsevents.c @@ -836,7 +836,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) { handle->cf_cb->data = handle; uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb); - handle->cf_cb->flags |= UV__HANDLE_INTERNAL; + handle->cf_cb->flags |= UV_HANDLE_INTERNAL; uv_unref((uv_handle_t*) handle->cf_cb); err = uv_mutex_init(&handle->cf_mutex); diff --git a/deps/uv/src/unix/getaddrinfo.c b/deps/uv/src/unix/getaddrinfo.c index 10e8afd75e831b..25827c1feeb6b3 100644 --- a/deps/uv/src/unix/getaddrinfo.c +++ b/deps/uv/src/unix/getaddrinfo.c @@ -186,6 +186,7 @@ int uv_getaddrinfo(uv_loop_t* loop, if (cb) { uv__work_submit(loop, &req->work_req, + UV__WORK_SLOW_IO, uv__getaddrinfo_work, uv__getaddrinfo_done); return 0; diff --git a/deps/uv/src/unix/getnameinfo.c b/deps/uv/src/unix/getnameinfo.c index 9a4367224c7fa6..991002a67d7072 100644 --- a/deps/uv/src/unix/getnameinfo.c +++ b/deps/uv/src/unix/getnameinfo.c @@ -109,6 +109,7 @@ int uv_getnameinfo(uv_loop_t* loop, if (getnameinfo_cb) { uv__work_submit(loop, &req->work_req, + UV__WORK_SLOW_IO, uv__getnameinfo_work, uv__getnameinfo_done); return 0; diff --git a/deps/uv/src/unix/ibmi.c b/deps/uv/src/unix/ibmi.c index c50a4e76f84119..b1ab549c23f4b9 100644 --- a/deps/uv/src/unix/ibmi.c +++ b/deps/uv/src/unix/ibmi.c @@ -72,7 +72,8 @@ void uv_loadavg(double avg[3]) { int uv_resident_set_memory(size_t* rss) { - return UV_ENOSYS; + *rss = 0; + return 0; } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 2bb3773c068d8e..cd79037102013e 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -127,26 +127,6 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t; -/* handle flags */ -enum { - UV_CLOSING = 0x01, /* uv_close() called but not finished. */ - UV_CLOSED = 0x02, /* close(2) finished. */ - UV_STREAM_READING = 0x04, /* uv_read_start() called. */ - UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */ - UV_STREAM_SHUT = 0x10, /* Write side closed. */ - UV_STREAM_READABLE = 0x20, /* The stream is readable */ - UV_STREAM_WRITABLE = 0x40, /* The stream is writable */ - UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */ - UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */ - UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */ - UV_TCP_NODELAY = 0x400, /* Disable Nagle. */ - UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */ - UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */ - UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */ - UV_UDP_PROCESSING = 0x20000, /* Handle is running the send callback queue. */ - UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */ -}; - /* loop flags */ enum { UV_LOOP_BLOCK_SIGPROF = 1 @@ -185,12 +165,24 @@ struct uv__stream_queued_fds_s { #define uv__nonblock uv__nonblock_fcntl #endif +/* On Linux, uv__nonblock_fcntl() and uv__nonblock_ioctl() do not commute + * when O_NDELAY is not equal to O_NONBLOCK. Case in point: linux/sparc32 + * and linux/sparc64, where O_NDELAY is O_NONBLOCK + another bit. + * + * Libuv uses uv__nonblock_fcntl() directly sometimes so ensure that it + * commutes with uv__nonblock(). + */ +#if defined(__linux__) && O_NDELAY != O_NONBLOCK +#undef uv__nonblock +#define uv__nonblock uv__nonblock_fcntl +#endif + /* core */ int uv__cloexec_ioctl(int fd, int set); int uv__cloexec_fcntl(int fd, int set); int uv__nonblock_ioctl(int fd, int set); int uv__nonblock_fcntl(int fd, int set); -int uv__close(int fd); +int uv__close(int fd); /* preserves errno */ int uv__close_nocheckstdio(int fd); int uv__socket(int domain, int type, int protocol); int uv__dup(int fd); @@ -207,6 +199,7 @@ int uv__io_active(const uv__io_t* w, unsigned int events); int uv__io_check_fd(uv_loop_t* loop, int fd); void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ int uv__io_fork(uv_loop_t* loop); +int uv__fd_exists(uv_loop_t* loop, int fd); /* async */ void uv__async_stop(uv_loop_t* loop); @@ -239,10 +232,6 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay); /* pipe */ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); -/* timer */ -void uv__run_timers(uv_loop_t* loop); -int uv__next_timeout(const uv_loop_t* loop); - /* signal */ void uv__signal_close(uv_signal_t* handle); void uv__signal_global_once_init(void); @@ -267,7 +256,6 @@ void uv__prepare_close(uv_prepare_t* handle); void uv__process_close(uv_process_t* handle); void uv__stream_close(uv_stream_t* handle); void uv__tcp_close(uv_tcp_t* handle); -void uv__timer_close(uv_timer_t* handle); void uv__udp_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle); uv_handle_type uv__handle_type(int fd); diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index a30fd730ff872e..930f2da7126a5d 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -261,8 +261,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w = loop->watchers[fd]; if (w == NULL) { - /* File descriptor that we've stopped watching, disarm it. */ - /* TODO batch up */ + /* File descriptor that we've stopped watching, disarm it. + * TODO: batch up. */ struct kevent events[1]; EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index b63c25f3c2258f..75362eb76d7f5d 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -20,7 +20,7 @@ /* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their * EPOLL* counterparts. We use the POLL* variants in this file because that - * is what libuv uses elsewhere and it avoids a dependency on . + * is what libuv uses elsewhere. */ #include "uv.h" @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -51,7 +52,7 @@ #ifdef HAVE_IFADDRS_H # if defined(__ANDROID__) -# include "android-ifaddrs.h" +# include "uv/android-ifaddrs.h" # else # include # endif @@ -84,13 +85,13 @@ static unsigned long read_cpufreq(unsigned int cpunum); int uv__platform_loop_init(uv_loop_t* loop) { int fd; - fd = uv__epoll_create1(UV__EPOLL_CLOEXEC); + fd = epoll_create1(EPOLL_CLOEXEC); /* epoll_create1() can fail either because it's not implemented (old kernel) * or because it doesn't understand the EPOLL_CLOEXEC flag. */ if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) { - fd = uv__epoll_create(256); + fd = epoll_create(256); if (fd != -1) uv__cloexec(fd, 1); @@ -134,20 +135,20 @@ void uv__platform_loop_delete(uv_loop_t* loop) { void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { - struct uv__epoll_event* events; - struct uv__epoll_event dummy; + struct epoll_event* events; + struct epoll_event dummy; uintptr_t i; uintptr_t nfds; assert(loop->watchers != NULL); - events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers]; + events = (struct epoll_event*) loop->watchers[loop->nwatchers]; nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; if (events != NULL) /* Invalidate events with same file descriptor */ for (i = 0; i < nfds; i++) - if ((int) events[i].data == fd) - events[i].data = -1; + if (events[i].data.fd == fd) + events[i].data.fd = -1; /* Remove the file descriptor from the epoll. * This avoids a problem where the same file description remains open @@ -160,25 +161,25 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. */ memset(&dummy, 0, sizeof(dummy)); - uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy); + epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy); } } int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct uv__epoll_event e; + struct epoll_event e; int rc; e.events = POLLIN; - e.data = -1; + e.data.fd = -1; rc = 0; - if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e)) + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e)) if (errno != EEXIST) rc = UV__ERR(errno); if (rc == 0) - if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e)) + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e)) abort(); return rc; @@ -195,16 +196,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * that being the largest value I have seen in the wild (and only once.) */ static const int max_safe_timeout = 1789569; - static int no_epoll_pwait; - static int no_epoll_wait; - struct uv__epoll_event events[1024]; - struct uv__epoll_event* pe; - struct uv__epoll_event e; + struct epoll_event events[1024]; + struct epoll_event* pe; + struct epoll_event e; int real_timeout; QUEUE* q; uv__io_t* w; sigset_t sigset; - uint64_t sigmask; + sigset_t* psigset; uint64_t base; int have_signals; int nevents; @@ -230,35 +229,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { assert(w->fd < (int) loop->nwatchers); e.events = w->pevents; - e.data = w->fd; + e.data.fd = w->fd; if (w->events == 0) - op = UV__EPOLL_CTL_ADD; + op = EPOLL_CTL_ADD; else - op = UV__EPOLL_CTL_MOD; + op = EPOLL_CTL_MOD; /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching * events, skip the syscall and squelch the events after epoll_wait(). */ - if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) { + if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) { if (errno != EEXIST) abort(); - assert(op == UV__EPOLL_CTL_ADD); + assert(op == EPOLL_CTL_ADD); /* We've reactivated a file descriptor that's been watched before. */ - if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e)) + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e)) abort(); } w->events = w->pevents; } - sigmask = 0; + psigset = NULL; if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { sigemptyset(&sigset); sigaddset(&sigset, SIGPROF); - sigmask |= 1 << (SIGPROF - 1); + psigset = &sigset; } assert(timeout >= -1); @@ -273,30 +272,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) timeout = max_safe_timeout; - if (sigmask != 0 && no_epoll_pwait != 0) - if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) - abort(); - - if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) { - nfds = uv__epoll_pwait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout, - sigmask); - if (nfds == -1 && errno == ENOSYS) - no_epoll_pwait = 1; - } else { - nfds = uv__epoll_wait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout); - if (nfds == -1 && errno == ENOSYS) - no_epoll_wait = 1; - } - - if (sigmask != 0 && no_epoll_pwait != 0) - if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)) - abort(); + nfds = epoll_pwait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout, + psigset); /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the @@ -317,12 +297,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (nfds == -1) { - if (errno == ENOSYS) { - /* epoll_wait() or epoll_pwait() failed, try the other system call. */ - assert(no_epoll_wait == 0 || no_epoll_pwait == 0); - continue; - } - if (errno != EINTR) abort(); @@ -344,7 +318,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; for (i = 0; i < nfds; i++) { pe = events + i; - fd = pe->data; + fd = pe->data.fd; /* Skip invalidated events, see uv__platform_invalidate_fd */ if (fd == -1) @@ -361,7 +335,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * Ignore all errors because we may be racing with another thread * when the file descriptor is closed. */ - uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe); + epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe); continue; } @@ -388,7 +362,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * free when we switch over to edge-triggered I/O. */ if (pe->events == POLLERR || pe->events == POLLHUP) - pe->events |= w->pevents & (POLLIN | POLLOUT | UV__POLLPRI); + pe->events |= + w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); if (pe->events != 0) { /* Run signal watchers last. This also affects child process watchers @@ -915,6 +890,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, continue; address = *addresses; + memset(address->phys_addr, 0, sizeof(address->phys_addr)); for (i = 0; i < (*count); i++) { if (strcmp(address->name, ent->ifa_name) == 0) { diff --git a/deps/uv/src/unix/linux-inotify.c b/deps/uv/src/unix/linux-inotify.c index bcad630fabf112..7797f842524ed3 100644 --- a/deps/uv/src/unix/linux-inotify.c +++ b/deps/uv/src/unix/linux-inotify.c @@ -19,7 +19,7 @@ */ #include "uv.h" -#include "tree.h" +#include "uv/tree.h" #include "internal.h" #include diff --git a/deps/uv/src/unix/linux-syscalls.c b/deps/uv/src/unix/linux-syscalls.c index 89998ded26b17c..bfd75448793388 100644 --- a/deps/uv/src/unix/linux-syscalls.c +++ b/deps/uv/src/unix/linux-syscalls.c @@ -77,56 +77,6 @@ # endif #endif /* __NR_eventfd2 */ -#ifndef __NR_epoll_create -# if defined(__x86_64__) -# define __NR_epoll_create 213 -# elif defined(__i386__) -# define __NR_epoll_create 254 -# elif defined(__arm__) -# define __NR_epoll_create (UV_SYSCALL_BASE + 250) -# endif -#endif /* __NR_epoll_create */ - -#ifndef __NR_epoll_create1 -# if defined(__x86_64__) -# define __NR_epoll_create1 291 -# elif defined(__i386__) -# define __NR_epoll_create1 329 -# elif defined(__arm__) -# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357) -# endif -#endif /* __NR_epoll_create1 */ - -#ifndef __NR_epoll_ctl -# if defined(__x86_64__) -# define __NR_epoll_ctl 233 /* used to be 214 */ -# elif defined(__i386__) -# define __NR_epoll_ctl 255 -# elif defined(__arm__) -# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251) -# endif -#endif /* __NR_epoll_ctl */ - -#ifndef __NR_epoll_wait -# if defined(__x86_64__) -# define __NR_epoll_wait 232 /* used to be 215 */ -# elif defined(__i386__) -# define __NR_epoll_wait 256 -# elif defined(__arm__) -# define __NR_epoll_wait (UV_SYSCALL_BASE + 252) -# endif -#endif /* __NR_epoll_wait */ - -#ifndef __NR_epoll_pwait -# if defined(__x86_64__) -# define __NR_epoll_pwait 281 -# elif defined(__i386__) -# define __NR_epoll_pwait 319 -# elif defined(__arm__) -# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346) -# endif -#endif /* __NR_epoll_pwait */ - #ifndef __NR_inotify_init # if defined(__x86_64__) # define __NR_inotify_init 253 @@ -285,76 +235,6 @@ int uv__eventfd2(unsigned int count, int flags) { } -int uv__epoll_create(int size) { -#if defined(__NR_epoll_create) - return syscall(__NR_epoll_create, size); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__epoll_create1(int flags) { -#if defined(__NR_epoll_create1) - return syscall(__NR_epoll_create1, flags); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) { -#if defined(__NR_epoll_ctl) - return syscall(__NR_epoll_ctl, epfd, op, fd, events); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__epoll_wait(int epfd, - struct uv__epoll_event* events, - int nevents, - int timeout) { -#if defined(__NR_epoll_wait) - int result; - result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout); -#if MSAN_ACTIVE - if (result > 0) - __msan_unpoison(events, sizeof(events[0]) * result); -#endif - return result; -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__epoll_pwait(int epfd, - struct uv__epoll_event* events, - int nevents, - int timeout, - uint64_t sigmask) { -#if defined(__NR_epoll_pwait) - int result; - result = syscall(__NR_epoll_pwait, - epfd, - events, - nevents, - timeout, - &sigmask, - sizeof(sigmask)); -#if MSAN_ACTIVE - if (result > 0) - __msan_unpoison(events, sizeof(events[0]) * result); -#endif - return result; -#else - return errno = ENOSYS, -1; -#endif -} - - int uv__inotify_init(void) { #if defined(__NR_inotify_init) return syscall(__NR_inotify_init); @@ -431,19 +311,6 @@ int uv__recvmmsg(int fd, } -int uv__utimesat(int dirfd, - const char* path, - const struct timespec times[2], - int flags) -{ -#if defined(__NR_utimensat) - return syscall(__NR_utimensat, dirfd, path, times, flags); -#else - return errno = ENOSYS, -1; -#endif -} - - 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)); diff --git a/deps/uv/src/unix/linux-syscalls.h b/deps/uv/src/unix/linux-syscalls.h index 4c095e9b537996..3dfd329d6c84b5 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -66,12 +66,6 @@ # define UV__SOCK_NONBLOCK UV__O_NONBLOCK #endif -/* epoll flags */ -#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC -#define UV__EPOLL_CTL_ADD 1 -#define UV__EPOLL_CTL_DEL 2 -#define UV__EPOLL_CTL_MOD 3 - /* inotify flags */ #define UV__IN_ACCESS 0x001 #define UV__IN_MODIFY 0x002 @@ -86,18 +80,6 @@ #define UV__IN_DELETE_SELF 0x400 #define UV__IN_MOVE_SELF 0x800 -#if defined(__x86_64__) -struct uv__epoll_event { - uint32_t events; - uint64_t data; -} __attribute__((packed)); -#else -struct uv__epoll_event { - uint32_t events; - uint64_t data; -}; -#endif - struct uv__inotify_event { int32_t wd; uint32_t mask; @@ -113,18 +95,6 @@ struct uv__mmsghdr { int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags); int uv__eventfd(unsigned int count); -int uv__epoll_create(int size); -int uv__epoll_create1(int flags); -int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev); -int uv__epoll_wait(int epfd, - struct uv__epoll_event* events, - int nevents, - int timeout); -int uv__epoll_pwait(int epfd, - struct uv__epoll_event* events, - int nevents, - int timeout, - uint64_t sigmask); int uv__eventfd2(unsigned int count, int flags); int uv__inotify_init(void); int uv__inotify_init1(int flags); @@ -140,10 +110,6 @@ int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen, unsigned int flags); -int uv__utimesat(int dirfd, - const char* path, - const struct timespec times[2], - int flags); ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset); ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset); int uv__dup3(int oldfd, int newfd, int flags); diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index 5b5b0e095bbc2f..c2a03d770f3764 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -20,7 +20,7 @@ */ #include "uv.h" -#include "tree.h" +#include "uv/tree.h" #include "internal.h" #include "heap-inl.h" #include @@ -38,13 +38,14 @@ int uv_loop_init(uv_loop_t* loop) { heap_init((struct heap*) &loop->timer_heap); QUEUE_INIT(&loop->wq); - QUEUE_INIT(&loop->active_reqs); QUEUE_INIT(&loop->idle_handles); QUEUE_INIT(&loop->async_handles); QUEUE_INIT(&loop->check_handles); QUEUE_INIT(&loop->prepare_handles); QUEUE_INIT(&loop->handle_queue); + loop->active_handles = 0; + loop->active_reqs.count = 0; loop->nfds = 0; loop->watchers = NULL; loop->nwatchers = 0; @@ -73,7 +74,7 @@ int uv_loop_init(uv_loop_t* loop) { goto fail_signal_init; uv__handle_unref(&loop->child_watcher); - loop->child_watcher.flags |= UV__HANDLE_INTERNAL; + loop->child_watcher.flags |= UV_HANDLE_INTERNAL; QUEUE_INIT(&loop->process_handles); err = uv_rwlock_init(&loop->cloexec_lock); @@ -89,7 +90,7 @@ int uv_loop_init(uv_loop_t* loop) { goto fail_async_init; uv__handle_unref(&loop->wq_async); - loop->wq_async.flags |= UV__HANDLE_INTERNAL; + loop->wq_async.flags |= UV_HANDLE_INTERNAL; return 0; diff --git a/deps/uv/src/unix/os390-syscalls.c b/deps/uv/src/unix/os390-syscalls.c index 21558ea8689a00..1040d66979da04 100644 --- a/deps/uv/src/unix/os390-syscalls.c +++ b/deps/uv/src/unix/os390-syscalls.c @@ -141,7 +141,7 @@ static void init_message_queue(uv__os390_epoll* lst) { } msg; /* initialize message queue */ - lst->msg_queue = msgget(IPC_PRIVATE, 0622 | IPC_CREAT); + lst->msg_queue = msgget(IPC_PRIVATE, 0600 | IPC_CREAT); if (lst->msg_queue == -1) abort(); @@ -215,6 +215,7 @@ uv__os390_epoll* epoll_create1(int flags) { maybe_resize(lst, 1); lst->items[lst->size - 1].fd = lst->msg_queue; lst->items[lst->size - 1].events = POLLIN; + lst->items[lst->size - 1].revents = 0; uv_once(&once, epoll_init); uv_mutex_lock(&global_epoll_lock); QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); @@ -252,13 +253,15 @@ int epoll_ctl(uv__os390_epoll* lst, } lst->items[fd].fd = fd; lst->items[fd].events = event->events; + lst->items[fd].revents = 0; } else if (op == EPOLL_CTL_MOD) { - if (fd >= lst->size || lst->items[fd].fd == -1) { + if (fd >= lst->size - 1 || lst->items[fd].fd == -1) { uv_mutex_unlock(&global_epoll_lock); errno = ENOENT; return -1; } lst->items[fd].events = event->events; + lst->items[fd].revents = 0; } else abort(); @@ -273,8 +276,9 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, struct pollfd* pfds; int pollret; int reventcount; + int nevents; - size = _SET_FDS_MSGS(size, 1, lst->size - 1); + _SET_FDS_MSGS(size, 1, lst->size - 1); pfds = lst->items; pollret = poll(pfds, size, timeout); if (pollret <= 0) @@ -283,19 +287,28 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, pollret = _NFDS(pollret) + _NMSGS(pollret); reventcount = 0; + nevents = 0; for (int i = 0; i < lst->size && i < maxevents && reventcount < pollret; ++i) { struct epoll_event ev; + struct pollfd* pfd; - if (pfds[i].fd == -1 || pfds[i].revents == 0) + pfd = &pfds[i]; + if (pfd->fd == -1 || pfd->revents == 0) continue; - ev.fd = pfds[i].fd; - ev.events = pfds[i].revents; - events[reventcount++] = ev; + ev.fd = pfd->fd; + ev.events = pfd->revents; + if (pfd->revents & POLLIN && pfd->revents & POLLOUT) + reventcount += 2; + else if (pfd->revents & (POLLIN | POLLOUT)) + ++reventcount; + + pfd->revents = 0; + events[nevents++] = ev; } - return reventcount; + return nevents; } @@ -491,7 +504,7 @@ ssize_t os390_readlink(const char* path, char* buf, size_t len) { size_t strnlen(const char* str, size_t maxlen) { - void* p = memchr(str, 0, maxlen); + char* p = memchr(str, 0, maxlen); if (p == NULL) return maxlen; else diff --git a/deps/uv/src/unix/os390-syscalls.h b/deps/uv/src/unix/os390-syscalls.h index 6e34a88cb95d1b..ea599107b30281 100644 --- a/deps/uv/src/unix/os390-syscalls.h +++ b/deps/uv/src/unix/os390-syscalls.h @@ -36,10 +36,6 @@ #define MAX_ITEMS_PER_EPOLL 1024 #define UV__O_CLOEXEC 0x80000 -#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC -#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD -#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL -#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD struct epoll_event { int events; diff --git a/deps/uv/src/unix/os390.c b/deps/uv/src/unix/os390.c index f766b393395ee7..65e9b708303668 100644 --- a/deps/uv/src/unix/os390.c +++ b/deps/uv/src/unix/os390.c @@ -512,7 +512,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0; - + memset(address->phys_addr, 0, sizeof(address->phys_addr)); address++; } @@ -624,6 +624,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; + memset(address->phys_addr, 0, sizeof(address->phys_addr)); address++; } @@ -662,7 +663,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { /* Remove the file descriptor from the epoll. */ if (loop->ep != NULL) - epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy); + epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, &dummy); } @@ -838,9 +839,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { e.fd = w->fd; if (w->events == 0) - op = UV__EPOLL_CTL_ADD; + op = EPOLL_CTL_ADD; else - op = UV__EPOLL_CTL_MOD; + op = EPOLL_CTL_MOD; /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching * events, skip the syscall and squelch the events after epoll_wait(). @@ -849,10 +850,10 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (errno != EEXIST) abort(); - assert(op == UV__EPOLL_CTL_ADD); + assert(op == EPOLL_CTL_ADD); /* We've reactivated a file descriptor that's been watched before. */ - if (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e)) + if (epoll_ctl(loop->ep, EPOLL_CTL_MOD, w->fd, &e)) abort(); } @@ -934,7 +935,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * Ignore all errors because we may be racing with another thread * when the file descriptor is closed. */ - epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, pe); + epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, pe); continue; } diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index e640bf29fc1754..e450a30e9c7e0c 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -132,7 +132,20 @@ void uv__pipe_close(uv_pipe_t* handle) { int uv_pipe_open(uv_pipe_t* handle, uv_file fd) { + int flags; + int mode; int err; + flags = 0; + + if (uv__fd_exists(handle->loop, fd)) + return UV_EEXIST; + + do + mode = fcntl(fd, F_GETFL); + while (mode == -1 && errno == EINTR); + + if (mode == -1) + return UV__ERR(errno); /* according to docs, must be EBADF */ err = uv__nonblock(fd, 1); if (err) @@ -144,9 +157,13 @@ int uv_pipe_open(uv_pipe_t* handle, uv_file fd) { return err; #endif /* defined(__APPLE__) */ - return uv__stream_open((uv_stream_t*)handle, - fd, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + mode &= O_ACCMODE; + if (mode != O_WRONLY) + flags |= UV_HANDLE_READABLE; + if (mode != O_RDONLY) + flags |= UV_HANDLE_WRITABLE; + + return uv__stream_open((uv_stream_t*)handle, fd, flags); } @@ -196,7 +213,7 @@ void uv_pipe_connect(uv_connect_t* req, if (new_sock) { err = uv__stream_open((uv_stream_t*)handle, uv__stream_fd(handle), - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); } if (err == 0) @@ -319,21 +336,6 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { mode != (UV_WRITABLE | UV_READABLE)) return UV_EINVAL; - if (fstat(uv__stream_fd(handle), &pipe_stat) == -1) - return UV__ERR(errno); - - desired_mode = 0; - if (mode & UV_READABLE) - desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; - if (mode & UV_WRITABLE) - desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; - - /* Exit early if pipe already has desired mode. */ - if ((pipe_stat.st_mode & desired_mode) == desired_mode) - return 0; - - pipe_stat.st_mode |= desired_mode; - /* Unfortunately fchmod does not work on all platforms, we will use chmod. */ name_len = 0; r = uv_pipe_getsockname(handle, NULL, &name_len); @@ -350,6 +352,26 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { return r; } + /* stat must be used as fstat has a bug on Darwin */ + if (stat(name_buffer, &pipe_stat) == -1) { + uv__free(name_buffer); + return -errno; + } + + desired_mode = 0; + if (mode & UV_READABLE) + desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; + if (mode & UV_WRITABLE) + desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; + + /* Exit early if pipe already has desired mode. */ + if ((pipe_stat.st_mode & desired_mode) == desired_mode) { + uv__free(name_buffer); + return 0; + } + + pipe_stat.st_mode |= desired_mode; + r = chmod(name_buffer, pipe_stat.st_mode); uv__free(name_buffer); diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c index f3b0bf4e433942..3d5022b22e85b6 100644 --- a/deps/uv/src/unix/poll.c +++ b/deps/uv/src/unix/poll.c @@ -68,6 +68,9 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { int err; + if (uv__fd_exists(loop, fd)) + return UV_EEXIST; + err = uv__io_check_fd(loop, fd); if (err) return err; diff --git a/deps/uv/src/unix/posix-poll.c b/deps/uv/src/unix/posix-poll.c index f356e76c79daec..f3181f9b726278 100644 --- a/deps/uv/src/unix/posix-poll.c +++ b/deps/uv/src/unix/posix-poll.c @@ -107,7 +107,7 @@ static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) { static void uv__pollfds_del(uv_loop_t* loop, int fd) { size_t i; assert(!loop->poll_fds_iterating); - for (i = 0; i < loop->poll_fds_used; ++i) { + for (i = 0; i < loop->poll_fds_used;) { if (loop->poll_fds[i].fd == fd) { /* swap to last position and remove */ --loop->poll_fds_used; @@ -115,7 +115,17 @@ static void uv__pollfds_del(uv_loop_t* loop, int fd) { loop->poll_fds[loop->poll_fds_used].fd = -1; loop->poll_fds[loop->poll_fds_used].events = 0; loop->poll_fds[loop->poll_fds_used].revents = 0; - return; + /* This method is called with an fd of -1 to purge the invalidated fds, + * so we may possibly have multiples to remove. + */ + if (-1 != fd) + return; + } else { + /* We must only increment the loop counter when the fds do not match. + * Otherwise, when we are purging an invalidated fd, the value just + * swapped here from the previous end of the array will be skipped. + */ + ++i; } } } diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 74113e3a696cc2..101c9c53dfafe3 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -223,8 +223,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { static int uv__process_open_stream(uv_stdio_container_t* container, - int pipefds[2], - int writable) { + int pipefds[2]) { int flags; int err; @@ -238,13 +237,11 @@ static int uv__process_open_stream(uv_stdio_container_t* container, pipefds[1] = -1; uv__nonblock(pipefds[0], 1); - if (container->data.stream->type == UV_NAMED_PIPE && - ((uv_pipe_t*)container->data.stream)->ipc) - flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE; - else if (writable) - flags = UV_STREAM_WRITABLE; - else - flags = UV_STREAM_READABLE; + flags = 0; + if (container->flags & UV_WRITABLE_PIPE) + flags |= UV_HANDLE_READABLE; + if (container->flags & UV_READABLE_PIPE) + flags |= UV_HANDLE_WRITABLE; return uv__stream_open(container->data.stream, pipefds[0], flags); } @@ -533,7 +530,7 @@ int uv_spawn(uv_loop_t* loop, uv__close_nocheckstdio(signal_pipe[0]); for (i = 0; i < options->stdio_count; i++) { - err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0); + err = uv__process_open_stream(options->stdio + i, pipes[i]); if (err == 0) continue; diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c index b9d0a56084c6b3..01aa55f3fe7c66 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/src/unix/signal.c @@ -54,8 +54,7 @@ static void uv__signal_unregister_handler(int signum); static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT; static struct uv__signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); -static int uv__signal_lock_pipefd[2]; - +static int uv__signal_lock_pipefd[2] = { -1, -1 }; RB_GENERATE_STATIC(uv__signal_tree_s, uv_signal_s, tree_entry, @@ -64,7 +63,7 @@ RB_GENERATE_STATIC(uv__signal_tree_s, static void uv__signal_global_reinit(void); static void uv__signal_global_init(void) { - if (!uv__signal_lock_pipefd[0]) + if (uv__signal_lock_pipefd[0] == -1) /* pthread_atfork can register before and after handlers, one * for each child. This only registers one for the child. That * state is both persistent and cumulative, so if we keep doing @@ -74,15 +73,11 @@ static void uv__signal_global_init(void) { if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit)) abort(); - if (uv__make_pipe(uv__signal_lock_pipefd, 0)) - abort(); - - if (uv__signal_unlock()) - abort(); + uv__signal_global_reinit(); } -static void uv__signal_global_reinit(void) { +UV_DESTRUCTOR(static void uv__signal_global_fini(void)) { /* We can only use signal-safe functions here. * That includes read/write and close, fortunately. * We do all of this directly here instead of resetting @@ -90,11 +85,26 @@ static void uv__signal_global_reinit(void) { * uv__signal_global_once_init is only called from uv_loop_init * and this needs to function in existing loops. */ - uv__close(uv__signal_lock_pipefd[0]); - uv__signal_lock_pipefd[0] = -1; - uv__close(uv__signal_lock_pipefd[1]); - uv__signal_lock_pipefd[1] = -1; - uv__signal_global_init(); + if (uv__signal_lock_pipefd[0] != -1) { + uv__close(uv__signal_lock_pipefd[0]); + uv__signal_lock_pipefd[0] = -1; + } + + if (uv__signal_lock_pipefd[1] != -1) { + uv__close(uv__signal_lock_pipefd[1]); + uv__signal_lock_pipefd[1] = -1; + } +} + + +static void uv__signal_global_reinit(void) { + uv__signal_global_fini(); + + if (uv__make_pipe(uv__signal_lock_pipefd, 0)) + abort(); + + if (uv__signal_unlock()) + abort(); } @@ -103,7 +113,6 @@ void uv__signal_global_once_init(void) { } - static int uv__signal_lock(void) { int r; char data; @@ -387,7 +396,7 @@ static int uv__signal_start(uv_signal_t* handle, */ first_handle = uv__signal_first_handle(signum); if (first_handle == NULL || - (!oneshot && (first_handle->flags & UV__SIGNAL_ONE_SHOT))) { + (!oneshot && (first_handle->flags & UV_SIGNAL_ONE_SHOT))) { err = uv__signal_register_handler(signum, oneshot); if (err) { /* Registering the signal handler failed. Must be an invalid signal. */ @@ -398,7 +407,7 @@ static int uv__signal_start(uv_signal_t* handle, handle->signum = signum; if (oneshot) - handle->flags |= UV__SIGNAL_ONE_SHOT; + handle->flags |= UV_SIGNAL_ONE_SHOT; RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle); @@ -455,20 +464,20 @@ static void uv__signal_event(uv_loop_t* loop, handle = msg->handle; if (msg->signum == handle->signum) { - assert(!(handle->flags & UV_CLOSING)); + assert(!(handle->flags & UV_HANDLE_CLOSING)); handle->signal_cb(handle, handle->signum); } handle->dispatched_signals++; - if (handle->flags & UV__SIGNAL_ONE_SHOT) + if (handle->flags & UV_SIGNAL_ONE_SHOT) uv__signal_stop(handle); /* If uv_close was called while there were caught signals that were not * yet dispatched, the uv__finish_close was deferred. Make close pending * now if this has happened. */ - if ((handle->flags & UV_CLOSING) && + if ((handle->flags & UV_HANDLE_CLOSING) && (handle->caught_signals == handle->dispatched_signals)) { uv__make_close_pending((uv_handle_t*) handle); } @@ -496,11 +505,11 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { if (w1->signum < w2->signum) return -1; if (w1->signum > w2->signum) return 1; - /* Handlers without UV__SIGNAL_ONE_SHOT set will come first, so if the first + /* Handlers without UV_SIGNAL_ONE_SHOT set will come first, so if the first * handler returned is a one-shot handler, the rest will be too. */ - f1 = w1->flags & UV__SIGNAL_ONE_SHOT; - f2 = w2->flags & UV__SIGNAL_ONE_SHOT; + f1 = w1->flags & UV_SIGNAL_ONE_SHOT; + f2 = w2->flags & UV_SIGNAL_ONE_SHOT; if (f1 < f2) return -1; if (f1 > f2) return 1; @@ -549,8 +558,8 @@ static void uv__signal_stop(uv_signal_t* handle) { if (first_handle == NULL) { uv__signal_unregister_handler(handle->signum); } else { - rem_oneshot = handle->flags & UV__SIGNAL_ONE_SHOT; - first_oneshot = first_handle->flags & UV__SIGNAL_ONE_SHOT; + rem_oneshot = handle->flags & UV_SIGNAL_ONE_SHOT; + first_oneshot = first_handle->flags & UV_SIGNAL_ONE_SHOT; if (first_oneshot && !rem_oneshot) { ret = uv__signal_register_handler(handle->signum, 1); assert(ret == 0); diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 3e786abee015c4..2e84eeeb82877e 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -220,7 +220,7 @@ static void uv__stream_osx_select(void* arg) { uv_sem_wait(&s->async_sem); /* Should be processed at this stage */ - assert((s->events == 0) || (stream->flags & UV_CLOSING)); + assert((s->events == 0) || (stream->flags & UV_HANDLE_CLOSING)); } } } @@ -248,7 +248,7 @@ static void uv__stream_osx_select_cb(uv_async_t* handle) { if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT)) uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT); - if (stream->flags & UV_CLOSING) + if (stream->flags & UV_HANDLE_CLOSING) return; /* NOTE: It is important to do it here, otherwise `select()` might be called @@ -342,7 +342,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { if (err) goto failed_async_init; - s->async.flags |= UV__HANDLE_INTERNAL; + s->async.flags |= UV_HANDLE_INTERNAL; uv__handle_unref(&s->async); err = uv_sem_init(&s->close_sem, 0); @@ -407,12 +407,14 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { stream->flags |= flags; if (stream->type == UV_TCP) { - if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) + if ((stream->flags & UV_HANDLE_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) return UV__ERR(errno); /* TODO Use delay the user passed in. */ - if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60)) + if ((stream->flags & UV_HANDLE_TCP_KEEPALIVE) && + uv__tcp_keepalive(fd, 1, 60)) { return UV__ERR(errno); + } } #if defined(__APPLE__) @@ -447,7 +449,7 @@ void uv__stream_flush_write_queue(uv_stream_t* stream, int error) { void uv__stream_destroy(uv_stream_t* stream) { assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT)); - assert(stream->flags & UV_CLOSED); + assert(stream->flags & UV_HANDLE_CLOSED); if (stream->connect_req) { uv__req_unregister(stream->loop, stream->connect_req); @@ -522,7 +524,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { stream = container_of(w, uv_stream_t, io_watcher); assert(events & POLLIN); assert(stream->accepted_fd == -1); - assert(!(stream->flags & UV_CLOSING)); + assert(!(stream->flags & UV_HANDLE_CLOSING)); uv__io_start(stream->loop, &stream->io_watcher, POLLIN); @@ -565,7 +567,8 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { return; } - if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) { + if (stream->type == UV_TCP && + (stream->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) { /* Give other processes a chance to accept connections. */ struct timespec timeout = { 0, 1 }; nanosleep(&timeout, NULL); @@ -590,7 +593,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { case UV_TCP: err = uv__stream_open(client, server->accepted_fd, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); if (err) { /* TODO handle error */ uv__close(server->accepted_fd); @@ -674,14 +677,14 @@ static void uv__drain(uv_stream_t* stream) { uv__stream_osx_interrupt_select(stream); /* Shutdown? */ - if ((stream->flags & UV_STREAM_SHUTTING) && - !(stream->flags & UV_CLOSING) && - !(stream->flags & UV_STREAM_SHUT)) { + if ((stream->flags & UV_HANDLE_SHUTTING) && + !(stream->flags & UV_HANDLE_CLOSING) && + !(stream->flags & UV_HANDLE_SHUT)) { assert(stream->shutdown_req); req = stream->shutdown_req; stream->shutdown_req = NULL; - stream->flags &= ~UV_STREAM_SHUTTING; + stream->flags &= ~UV_HANDLE_SHUTTING; uv__req_unregister(stream->loop, req); err = 0; @@ -689,7 +692,7 @@ static void uv__drain(uv_stream_t* stream) { err = UV__ERR(errno); if (err == 0) - stream->flags |= UV_STREAM_SHUT; + stream->flags |= UV_HANDLE_SHUT; if (req->cb != NULL) req->cb(req, err); @@ -868,7 +871,7 @@ static void uv__write(uv_stream_t* stream) { if (!WRITE_RETRY_ON_ERROR(req->send_handle)) { err = UV__ERR(errno); goto error; - } else if (stream->flags & UV_STREAM_BLOCKING) { + } else if (stream->flags & UV_HANDLE_BLOCKING_WRITES) { /* If this is a blocking stream, try again. */ goto start; } @@ -888,7 +891,7 @@ static void uv__write(uv_stream_t* stream) { n = 0; /* There is more to write. */ - if (stream->flags & UV_STREAM_BLOCKING) { + if (stream->flags & UV_HANDLE_BLOCKING_WRITES) { /* * If we're blocking then we should not be enabling the write * watcher - instead we need to try again. @@ -924,7 +927,7 @@ static void uv__write(uv_stream_t* stream) { assert(n == 0 || n == -1); /* Only non-blocking streams should use the write_watcher. */ - assert(!(stream->flags & UV_STREAM_BLOCKING)); + assert(!(stream->flags & UV_HANDLE_BLOCKING_WRITES)); /* We're not done. */ uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); @@ -947,10 +950,16 @@ static void uv__write(uv_stream_t* stream) { static void uv__write_callbacks(uv_stream_t* stream) { uv_write_t* req; QUEUE* q; + QUEUE pq; + + if (QUEUE_EMPTY(&stream->write_completed_queue)) + return; + + QUEUE_MOVE(&stream->write_completed_queue, &pq); - while (!QUEUE_EMPTY(&stream->write_completed_queue)) { + while (!QUEUE_EMPTY(&pq)) { /* Pop a req off write_completed_queue. */ - q = QUEUE_HEAD(&stream->write_completed_queue); + q = QUEUE_HEAD(&pq); req = QUEUE_DATA(q, uv_write_t, queue); QUEUE_REMOVE(q); uv__req_unregister(stream->loop, req); @@ -966,8 +975,6 @@ static void uv__write_callbacks(uv_stream_t* stream) { if (req->cb) req->cb(req, req->error); } - - assert(QUEUE_EMPTY(&stream->write_completed_queue)); } @@ -1015,13 +1022,13 @@ uv_handle_type uv__handle_type(int fd) { static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { - stream->flags |= UV_STREAM_READ_EOF; + stream->flags |= UV_HANDLE_READ_EOF; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); stream->read_cb(stream, UV_EOF, buf); - stream->flags &= ~UV_STREAM_READING; + stream->flags &= ~UV_HANDLE_READING; } @@ -1121,6 +1128,7 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wgnu-folding-constant" +# pragma clang diagnostic ignored "-Wvla-extension" #endif static void uv__read(uv_stream_t* stream) { @@ -1132,7 +1140,7 @@ static void uv__read(uv_stream_t* stream) { int err; int is_ipc; - stream->flags &= ~UV_STREAM_READ_PARTIAL; + stream->flags &= ~UV_HANDLE_READ_PARTIAL; /* Prevent loop starvation when the data comes in as fast as (or faster than) * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. @@ -1141,11 +1149,11 @@ static void uv__read(uv_stream_t* stream) { is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc; - /* XXX: Maybe instead of having UV_STREAM_READING we just test if + /* XXX: Maybe instead of having UV_HANDLE_READING we just test if * tcp->read_cb is NULL or not? */ while (stream->read_cb - && (stream->flags & UV_STREAM_READING) + && (stream->flags & UV_HANDLE_READING) && (count-- > 0)) { assert(stream->alloc_cb != NULL); @@ -1186,7 +1194,7 @@ static void uv__read(uv_stream_t* stream) { /* Error */ if (errno == EAGAIN || errno == EWOULDBLOCK) { /* Wait for the next one. */ - if (stream->flags & UV_STREAM_READING) { + if (stream->flags & UV_HANDLE_READING) { uv__io_start(stream->loop, &stream->io_watcher, POLLIN); uv__stream_osx_interrupt_select(stream); } @@ -1199,8 +1207,8 @@ static void uv__read(uv_stream_t* stream) { } else { /* Error. User should call uv_close(). */ stream->read_cb(stream, UV__ERR(errno), &buf); - if (stream->flags & UV_STREAM_READING) { - stream->flags &= ~UV_STREAM_READING; + if (stream->flags & UV_HANDLE_READING) { + stream->flags &= ~UV_HANDLE_READING; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); @@ -1250,7 +1258,7 @@ static void uv__read(uv_stream_t* stream) { /* Return if we didn't fill the buffer, there is no more data to read. */ if (nread < buflen) { - stream->flags |= UV_STREAM_READ_PARTIAL; + stream->flags |= UV_HANDLE_READ_PARTIAL; return; } } @@ -1271,9 +1279,9 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { stream->type == UV_TTY || stream->type == UV_NAMED_PIPE); - if (!(stream->flags & UV_STREAM_WRITABLE) || - stream->flags & UV_STREAM_SHUT || - stream->flags & UV_STREAM_SHUTTING || + if (!(stream->flags & UV_HANDLE_WRITABLE) || + stream->flags & UV_HANDLE_SHUT || + stream->flags & UV_HANDLE_SHUTTING || uv__is_closing(stream)) { return UV_ENOTCONN; } @@ -1285,7 +1293,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { req->handle = stream; req->cb = cb; stream->shutdown_req = req; - stream->flags |= UV_STREAM_SHUTTING; + stream->flags |= UV_HANDLE_SHUTTING; uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); @@ -1302,7 +1310,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY); - assert(!(stream->flags & UV_CLOSING)); + assert(!(stream->flags & UV_HANDLE_CLOSING)); if (stream->connect_req) { uv__stream_connect(stream); @@ -1311,7 +1319,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(uv__stream_fd(stream) >= 0); - /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */ + /* Ignore POLLHUP here. Even if it's set, there may still be data to read. */ if (events & (POLLIN | POLLERR | POLLHUP)) uv__read(stream); @@ -1325,9 +1333,9 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { * report the EOF yet because there is still data to read. */ if ((events & POLLHUP) && - (stream->flags & UV_STREAM_READING) && - (stream->flags & UV_STREAM_READ_PARTIAL) && - !(stream->flags & UV_STREAM_READ_EOF)) { + (stream->flags & UV_HANDLE_READING) && + (stream->flags & UV_HANDLE_READ_PARTIAL) && + !(stream->flags & UV_HANDLE_READ_EOF)) { uv_buf_t buf = { NULL, 0 }; uv__stream_eof(stream, &buf); } @@ -1417,6 +1425,9 @@ int uv_write2(uv_write_t* req, if (uv__stream_fd(stream) < 0) return UV_EBADF; + if (!(stream->flags & UV_HANDLE_WRITABLE)) + return -EPIPE; + if (send_handle) { if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) return UV_EINVAL; @@ -1484,7 +1495,7 @@ int uv_write2(uv_write_t* req, * if this assert fires then somehow the blocking stream isn't being * sufficiently flushed in uv__write. */ - assert(!(stream->flags & UV_STREAM_BLOCKING)); + assert(!(stream->flags & UV_HANDLE_BLOCKING_WRITES)); uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); } @@ -1565,13 +1576,16 @@ int uv_read_start(uv_stream_t* stream, assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY); - if (stream->flags & UV_CLOSING) + if (stream->flags & UV_HANDLE_CLOSING) return UV_EINVAL; - /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just + if (!(stream->flags & UV_HANDLE_READABLE)) + return -ENOTCONN; + + /* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just * expresses the desired state of the user. */ - stream->flags |= UV_STREAM_READING; + stream->flags |= UV_HANDLE_READING; /* TODO: try to do the read inline? */ /* TODO: keep track of tcp state. If we've gotten a EOF then we should @@ -1592,10 +1606,10 @@ int uv_read_start(uv_stream_t* stream, int uv_read_stop(uv_stream_t* stream) { - if (!(stream->flags & UV_STREAM_READING)) + if (!(stream->flags & UV_HANDLE_READING)) return 0; - stream->flags &= ~UV_STREAM_READING; + stream->flags &= ~UV_HANDLE_READING; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); @@ -1608,12 +1622,12 @@ int uv_read_stop(uv_stream_t* stream) { int uv_is_readable(const uv_stream_t* stream) { - return !!(stream->flags & UV_STREAM_READABLE); + return !!(stream->flags & UV_HANDLE_READABLE); } int uv_is_writable(const uv_stream_t* stream) { - return !!(stream->flags & UV_STREAM_WRITABLE); + return !!(stream->flags & UV_HANDLE_WRITABLE); } @@ -1662,6 +1676,7 @@ void uv__stream_close(uv_stream_t* handle) { uv__io_close(handle->loop, &handle->io_watcher); uv_read_stop(handle); uv__handle_stop(handle); + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); if (handle->io_watcher.fd != -1) { /* Don't close stdio file descriptors. Nothing good comes from it. */ diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index 96f89312def0eb..2982851dc6eaa1 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -49,16 +49,14 @@ static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { /* Bind this new socket to an arbitrary port */ slen = sizeof(saddr); memset(&saddr, 0, sizeof(saddr)); - err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen); - if (err) { + if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) { uv__close(sockfd); - return err; + return UV__ERR(errno); } - err = bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen); - if (err) { + if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) { uv__close(sockfd); - return err; + return UV__ERR(errno); } } @@ -158,9 +156,7 @@ int uv__tcp_bind(uv_tcp_t* tcp, if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6) return UV_EINVAL; - err = maybe_new_socket(tcp, - addr->sa_family, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + err = maybe_new_socket(tcp, addr->sa_family, 0); if (err) return err; @@ -168,6 +164,7 @@ int uv__tcp_bind(uv_tcp_t* tcp, if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) return UV__ERR(errno); +#ifndef __OpenBSD__ #ifdef IPV6_V6ONLY if (addr->sa_family == AF_INET6) { on = (flags & UV_TCP_IPV6ONLY) != 0; @@ -183,6 +180,7 @@ int uv__tcp_bind(uv_tcp_t* tcp, return UV__ERR(errno); } } +#endif #endif errno = 0; @@ -218,7 +216,7 @@ int uv__tcp_connect(uv_connect_t* req, err = maybe_new_socket(handle, addr->sa_family, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); if (err) return err; @@ -265,13 +263,16 @@ int uv__tcp_connect(uv_connect_t* req, int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { int err; + if (uv__fd_exists(handle->loop, sock)) + return UV_EEXIST; + err = uv__nonblock(sock, 1); if (err) return err; return uv__stream_open((uv_stream_t*)handle, sock, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); } @@ -333,16 +334,16 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { } if (single_accept) - tcp->flags |= UV_TCP_SINGLE_ACCEPT; + tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; - flags = UV_STREAM_READABLE; + flags = 0; #if defined(__MVS__) /* on zOS the listen call does not bind automatically if the socket is unbound. Hence the manual binding to an arbitrary port is required to be done manually */ flags |= UV_HANDLE_BOUND; -#endif +#endif err = maybe_new_socket(tcp, AF_INET, flags); if (err) return err; @@ -400,9 +401,9 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int on) { } if (on) - handle->flags |= UV_TCP_NODELAY; + handle->flags |= UV_HANDLE_TCP_NODELAY; else - handle->flags &= ~UV_TCP_NODELAY; + handle->flags &= ~UV_HANDLE_TCP_NODELAY; return 0; } @@ -418,9 +419,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { } if (on) - handle->flags |= UV_TCP_KEEPALIVE; + handle->flags |= UV_HANDLE_TCP_KEEPALIVE; else - handle->flags &= ~UV_TCP_KEEPALIVE; + handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge * uv_tcp_t with an int that's almost never used... @@ -432,9 +433,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { if (enable) - handle->flags &= ~UV_TCP_SINGLE_ACCEPT; + handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT; else - handle->flags |= UV_TCP_SINGLE_ACCEPT; + handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; return 0; } diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index 3def29457aafb6..29004707a41947 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -37,111 +37,126 @@ #include #endif +#ifdef __GLIBC__ +#include /* gnu_get_libc_version() */ +#endif + #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) +#if defined(PTHREAD_BARRIER_SERIAL_THREAD) +STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t)); +#endif -#if defined(UV__PTHREAD_BARRIER_FALLBACK) -/* TODO: support barrier_attr */ -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* barrier_attr, - unsigned count) { +/* Note: guard clauses should match uv_barrier_t's in include/uv/uv-unix.h. */ +#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD) +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + struct _uv_barrier* b; int rc; - _uv_barrier* b; if (barrier == NULL || count == 0) - return EINVAL; - - if (barrier_attr != NULL) - return ENOTSUP; + return UV_EINVAL; b = uv__malloc(sizeof(*b)); if (b == NULL) - return ENOMEM; + return UV_ENOMEM; b->in = 0; b->out = 0; b->threshold = count; - if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) + rc = uv_mutex_init(&b->mutex); + if (rc != 0) goto error2; - if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) + + rc = uv_cond_init(&b->cond); + if (rc != 0) goto error; barrier->b = b; return 0; error: - pthread_mutex_destroy(&b->mutex); + uv_mutex_destroy(&b->mutex); error2: uv__free(b); return rc; } -int pthread_barrier_wait(pthread_barrier_t* barrier) { - int rc; - _uv_barrier* b; + +int uv_barrier_wait(uv_barrier_t* barrier) { + struct _uv_barrier* b; + int last; if (barrier == NULL || barrier->b == NULL) - return EINVAL; + return UV_EINVAL; b = barrier->b; - /* Lock the mutex*/ - if ((rc = pthread_mutex_lock(&b->mutex)) != 0) - return rc; + uv_mutex_lock(&b->mutex); - /* Increment the count. If this is the first thread to reach the threshold, - wake up waiters, unlock the mutex, then return - PTHREAD_BARRIER_SERIAL_THREAD. */ if (++b->in == b->threshold) { b->in = 0; - b->out = b->threshold - 1; - rc = pthread_cond_signal(&b->cond); - assert(rc == 0); - - pthread_mutex_unlock(&b->mutex); - return PTHREAD_BARRIER_SERIAL_THREAD; + b->out = b->threshold; + uv_cond_signal(&b->cond); + } else { + do + uv_cond_wait(&b->cond, &b->mutex); + while (b->in != 0); } - /* Otherwise, wait for other threads until in is set to 0, - then return 0 to indicate this is not the first thread. */ - do { - if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) - break; - } while (b->in != 0); - - /* mark thread exit */ - b->out--; - pthread_cond_signal(&b->cond); - pthread_mutex_unlock(&b->mutex); - return rc; + + last = (--b->out == 0); + if (!last) + uv_cond_signal(&b->cond); /* Not needed for last thread. */ + + uv_mutex_unlock(&b->mutex); + return last; } -int pthread_barrier_destroy(pthread_barrier_t* barrier) { - int rc; - _uv_barrier* b; - if (barrier == NULL || barrier->b == NULL) - return EINVAL; +void uv_barrier_destroy(uv_barrier_t* barrier) { + struct _uv_barrier* b; b = barrier->b; + uv_mutex_lock(&b->mutex); - if ((rc = pthread_mutex_lock(&b->mutex)) != 0) - return rc; - - if (b->in > 0 || b->out > 0) - rc = EBUSY; + assert(b->in == 0); + assert(b->out == 0); - pthread_mutex_unlock(&b->mutex); + if (b->in != 0 || b->out != 0) + abort(); - if (rc) - return rc; + uv_mutex_unlock(&b->mutex); + uv_mutex_destroy(&b->mutex); + uv_cond_destroy(&b->cond); - pthread_cond_destroy(&b->cond); - pthread_mutex_destroy(&b->mutex); uv__free(barrier->b); barrier->b = NULL; - return 0; } + +#else + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + return UV__ERR(pthread_barrier_init(barrier, NULL, count)); +} + + +int uv_barrier_wait(uv_barrier_t* barrier) { + int rc; + + rc = pthread_barrier_wait(barrier); + if (rc != 0) + if (rc != PTHREAD_BARRIER_SERIAL_THREAD) + abort(); + + return rc == PTHREAD_BARRIER_SERIAL_THREAD; +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { + if (pthread_barrier_destroy(barrier)) + abort(); +} + #endif @@ -419,109 +434,145 @@ int uv_sem_trywait(uv_sem_t* sem) { return UV_EINVAL; /* Satisfy the compiler. */ } +#else /* !(defined(__APPLE__) && defined(__MACH__)) */ + +#ifdef __GLIBC__ + +/* Hack around https://sourceware.org/bugzilla/show_bug.cgi?id=12674 + * by providing a custom implementation for glibc < 2.21 in terms of other + * concurrency primitives. + * Refs: https://github.com/nodejs/node/issues/19903 */ + +/* To preserve ABI compatibility, we treat the uv_sem_t as storage for + * a pointer to the actual struct we're using underneath. */ + +static uv_once_t glibc_version_check_once = UV_ONCE_INIT; +static int platform_needs_custom_semaphore = 0; + +static void glibc_version_check(void) { + const char* version = gnu_get_libc_version(); + platform_needs_custom_semaphore = + version[0] == '2' && version[1] == '.' && + atoi(version + 2) < 21; +} + #elif defined(__MVS__) -int uv_sem_init(uv_sem_t* sem, unsigned int value) { - uv_sem_t semid; +#define platform_needs_custom_semaphore 1 + +#else /* !defined(__GLIBC__) && !defined(__MVS__) */ + +#define platform_needs_custom_semaphore 0 + +#endif + +typedef struct uv_semaphore_s { + uv_mutex_t mutex; + uv_cond_t cond; + unsigned int value; +} uv_semaphore_t; + +#if defined(__GLIBC__) || platform_needs_custom_semaphore +STATIC_ASSERT(sizeof(uv_sem_t) >= sizeof(uv_semaphore_t*)); +#endif + +static int uv__custom_sem_init(uv_sem_t* sem_, unsigned int value) { int err; - union { - int val; - struct semid_ds* buf; - unsigned short* array; - } arg; + uv_semaphore_t* sem; + sem = uv__malloc(sizeof(*sem)); + if (sem == NULL) + return UV_ENOMEM; - semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); - if (semid == -1) - return UV__ERR(errno); + if ((err = uv_mutex_init(&sem->mutex)) != 0) { + uv__free(sem); + return err; + } - arg.val = value; - if (-1 == semctl(semid, 0, SETVAL, arg)) { - err = errno; - if (-1 == semctl(*sem, 0, IPC_RMID)) - abort(); - return UV__ERR(err); + if ((err = uv_cond_init(&sem->cond)) != 0) { + uv_mutex_destroy(&sem->mutex); + uv__free(sem); + return err; } - *sem = semid; + sem->value = value; + *(uv_semaphore_t**)sem_ = sem; return 0; } -void uv_sem_destroy(uv_sem_t* sem) { - if (-1 == semctl(*sem, 0, IPC_RMID)) - abort(); + +static void uv__custom_sem_destroy(uv_sem_t* sem_) { + uv_semaphore_t* sem; + + sem = *(uv_semaphore_t**)sem_; + uv_cond_destroy(&sem->cond); + uv_mutex_destroy(&sem->mutex); + uv__free(sem); } -void uv_sem_post(uv_sem_t* sem) { - struct sembuf buf; - buf.sem_num = 0; - buf.sem_op = 1; - buf.sem_flg = 0; +static void uv__custom_sem_post(uv_sem_t* sem_) { + uv_semaphore_t* sem; - if (-1 == semop(*sem, &buf, 1)) - abort(); + sem = *(uv_semaphore_t**)sem_; + uv_mutex_lock(&sem->mutex); + sem->value++; + if (sem->value == 1) + uv_cond_signal(&sem->cond); + uv_mutex_unlock(&sem->mutex); } -void uv_sem_wait(uv_sem_t* sem) { - struct sembuf buf; - int op_status; - - buf.sem_num = 0; - buf.sem_op = -1; - buf.sem_flg = 0; - do - op_status = semop(*sem, &buf, 1); - while (op_status == -1 && errno == EINTR); +static void uv__custom_sem_wait(uv_sem_t* sem_) { + uv_semaphore_t* sem; - if (op_status) - abort(); + sem = *(uv_semaphore_t**)sem_; + uv_mutex_lock(&sem->mutex); + while (sem->value == 0) + uv_cond_wait(&sem->cond, &sem->mutex); + sem->value--; + uv_mutex_unlock(&sem->mutex); } -int uv_sem_trywait(uv_sem_t* sem) { - struct sembuf buf; - int op_status; - buf.sem_num = 0; - buf.sem_op = -1; - buf.sem_flg = IPC_NOWAIT; +static int uv__custom_sem_trywait(uv_sem_t* sem_) { + uv_semaphore_t* sem; - do - op_status = semop(*sem, &buf, 1); - while (op_status == -1 && errno == EINTR); + sem = *(uv_semaphore_t**)sem_; + if (uv_mutex_trylock(&sem->mutex) != 0) + return UV_EAGAIN; - if (op_status) { - if (errno == EAGAIN) - return UV_EAGAIN; - abort(); + if (sem->value == 0) { + uv_mutex_unlock(&sem->mutex); + return UV_EAGAIN; } + sem->value--; + uv_mutex_unlock(&sem->mutex); + return 0; } -#else /* !(defined(__APPLE__) && defined(__MACH__)) */ - -int uv_sem_init(uv_sem_t* sem, unsigned int value) { +static int uv__sem_init(uv_sem_t* sem, unsigned int value) { if (sem_init(sem, 0, value)) return UV__ERR(errno); return 0; } -void uv_sem_destroy(uv_sem_t* sem) { +static void uv__sem_destroy(uv_sem_t* sem) { if (sem_destroy(sem)) abort(); } -void uv_sem_post(uv_sem_t* sem) { +static void uv__sem_post(uv_sem_t* sem) { if (sem_post(sem)) abort(); } -void uv_sem_wait(uv_sem_t* sem) { +static void uv__sem_wait(uv_sem_t* sem) { int r; do @@ -533,7 +584,7 @@ void uv_sem_wait(uv_sem_t* sem) { } -int uv_sem_trywait(uv_sem_t* sem) { +static int uv__sem_trywait(uv_sem_t* sem) { int r; do @@ -549,6 +600,49 @@ int uv_sem_trywait(uv_sem_t* sem) { return 0; } +int uv_sem_init(uv_sem_t* sem, unsigned int value) { +#ifdef __GLIBC__ + uv_once(&glibc_version_check_once, glibc_version_check); +#endif + + if (platform_needs_custom_semaphore) + return uv__custom_sem_init(sem, value); + else + return uv__sem_init(sem, value); +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (platform_needs_custom_semaphore) + uv__custom_sem_destroy(sem); + else + uv__sem_destroy(sem); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (platform_needs_custom_semaphore) + uv__custom_sem_post(sem); + else + uv__sem_post(sem); +} + + +void uv_sem_wait(uv_sem_t* sem) { + if (platform_needs_custom_semaphore) + uv__custom_sem_wait(sem); + else + uv__sem_wait(sem); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + if (platform_needs_custom_semaphore) + return uv__custom_sem_trywait(sem); + else + return uv__sem_trywait(sem); +} + #endif /* defined(__APPLE__) && defined(__MACH__) */ @@ -688,25 +782,6 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { } -int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { - return UV__ERR(pthread_barrier_init(barrier, NULL, count)); -} - - -void uv_barrier_destroy(uv_barrier_t* barrier) { - if (pthread_barrier_destroy(barrier)) - abort(); -} - - -int uv_barrier_wait(uv_barrier_t* barrier) { - int r = pthread_barrier_wait(barrier); - if (r && r != PTHREAD_BARRIER_SERIAL_THREAD) - abort(); - return r == PTHREAD_BARRIER_SERIAL_THREAD; -} - - int uv_key_create(uv_key_t* key) { return UV__ERR(pthread_key_create(key, NULL)); } diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index f22b3b80de061f..74d3d75d7615d9 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -92,13 +92,15 @@ static int uv__tty_is_slave(const int fd) { return result; } -int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { +int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) { uv_handle_type type; int flags; int newfd; int r; int saved_flags; + int mode; char path[256]; + (void)unused; /* deprecated parameter is no longer needed */ /* File descriptors that refer to files cannot be monitored with epoll. * That restriction also applies to character devices like /dev/random @@ -111,6 +113,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { flags = 0; newfd = -1; + /* Save the fd flags in case we need to restore them due to an error. */ + do + saved_flags = fcntl(fd, F_GETFL); + while (saved_flags == -1 && errno == EINTR); + + if (saved_flags == -1) + return UV__ERR(errno); + mode = saved_flags & O_ACCMODE; + /* Reopen the file descriptor when it refers to a tty. This lets us put the * tty in non-blocking mode without affecting other processes that share it * with us. @@ -128,14 +139,14 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { * slave device. */ if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) - r = uv__open_cloexec(path, O_RDWR); + r = uv__open_cloexec(path, mode); else r = -1; if (r < 0) { /* fallback to using blocking writes */ - if (!readable) - flags |= UV_STREAM_BLOCKING; + if (mode != O_RDONLY) + flags |= UV_HANDLE_BLOCKING_WRITES; goto skip; } @@ -154,22 +165,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { fd = newfd; } -#if defined(__APPLE__) - /* Save the fd flags in case we need to restore them due to an error. */ - do - saved_flags = fcntl(fd, F_GETFL); - while (saved_flags == -1 && errno == EINTR); - - if (saved_flags == -1) { - if (newfd != -1) - uv__close(newfd); - return UV__ERR(errno); - } -#endif - - /* Pacify the compiler. */ - (void) &saved_flags; - skip: uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); @@ -177,7 +172,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { * the handle queue, since it was added by uv__handle_init in uv_stream_init. */ - if (!(flags & UV_STREAM_BLOCKING)) + if (!(flags & UV_HANDLE_BLOCKING_WRITES)) uv__nonblock(fd, 1); #if defined(__APPLE__) @@ -194,10 +189,10 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { } #endif - if (readable) - flags |= UV_STREAM_READABLE; - else - flags |= UV_STREAM_WRITABLE; + if (mode != O_WRONLY) + flags |= UV_HANDLE_READABLE; + if (mode != O_RDONLY) + flags |= UV_HANDLE_WRITABLE; uv__stream_open((uv_stream_t*) tty, fd, flags); tty->mode = UV_TTY_MODE_NORMAL; diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 74d613b6843b7d..e6668a012c5c27 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -92,8 +92,8 @@ static void uv__udp_run_completed(uv_udp_t* handle) { uv_udp_send_t* req; QUEUE* q; - assert(!(handle->flags & UV_UDP_PROCESSING)); - handle->flags |= UV_UDP_PROCESSING; + assert(!(handle->flags & UV_HANDLE_UDP_PROCESSING)); + handle->flags |= UV_HANDLE_UDP_PROCESSING; while (!QUEUE_EMPTY(&handle->write_completed_queue)) { q = QUEUE_HEAD(&handle->write_completed_queue); @@ -128,7 +128,7 @@ static void uv__udp_run_completed(uv_udp_t* handle) { uv__handle_stop(handle); } - handle->flags &= ~UV_UDP_PROCESSING; + handle->flags &= ~UV_HANDLE_UDP_PROCESSING; } @@ -427,7 +427,7 @@ int uv__udp_send(uv_udp_send_t* req, QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue); uv__handle_start(handle); - if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) { + if (empty_queue && !(handle->flags & UV_HANDLE_UDP_PROCESSING)) { uv__udp_sendmsg(handle); /* `uv__udp_sendmsg` may not be able to do non-blocking write straight @@ -624,6 +624,9 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { if (handle->io_watcher.fd != -1) return UV_EBUSY; + if (uv__fd_exists(handle->loop, sock)) + return UV_EEXIST; + err = uv__nonblock(sock, 1); if (err) return err; diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index bc7d1379d131f2..f0aec452606cb8 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -155,6 +155,18 @@ static const char* uv__unknown_err_code(int err) { return copy != NULL ? copy : "Unknown system error"; } +#define UV_ERR_NAME_GEN_R(name, _) \ +case UV_## name: \ + snprintf(buf, buflen, "%s", #name); break; +char* uv_err_name_r(int err, char* buf, size_t buflen) { + switch (err) { + UV_ERRNO_MAP(UV_ERR_NAME_GEN_R) + default: snprintf(buf, buflen, "Unknown system error %d", err); + } + return buf; +} +#undef UV_ERR_NAME_GEN_R + #define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name; const char* uv_err_name(int err) { @@ -166,6 +178,19 @@ const char* uv_err_name(int err) { #undef UV_ERR_NAME_GEN +#define UV_STRERROR_GEN_R(name, msg) \ +case UV_ ## name: \ + snprintf(buf, buflen, "%s", msg); break; +char* uv_strerror_r(int err, char* buf, size_t buflen) { + switch (err) { + UV_ERRNO_MAP(UV_STRERROR_GEN_R) + default: snprintf(buf, buflen, "Unknown system error %d", err); + } + return buf; +} +#undef UV_STRERROR_GEN_R + + #define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg; const char* uv_strerror(int err) { switch (err) { @@ -357,7 +382,7 @@ void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { QUEUE_REMOVE(q); QUEUE_INSERT_TAIL(&loop->handle_queue, q); - if (h->flags & UV__HANDLE_INTERNAL) continue; + if (h->flags & UV_HANDLE_INTERNAL) continue; walk_cb(h, arg); } } @@ -386,9 +411,9 @@ static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) { fprintf(stream, "[%c%c%c] %-8s %p\n", - "R-"[!(h->flags & UV__HANDLE_REF)], - "A-"[!(h->flags & UV__HANDLE_ACTIVE)], - "I-"[!(h->flags & UV__HANDLE_INTERNAL)], + "R-"[!(h->flags & UV_HANDLE_REF)], + "A-"[!(h->flags & UV_HANDLE_ACTIVE)], + "I-"[!(h->flags & UV_HANDLE_INTERNAL)], type, (void*)h); } @@ -627,12 +652,12 @@ int uv_loop_close(uv_loop_t* loop) { void* saved_data; #endif - if (!QUEUE_EMPTY(&(loop)->active_reqs)) + if (uv__has_active_reqs(loop)) return UV_EBUSY; QUEUE_FOREACH(q, &loop->handle_queue) { h = QUEUE_DATA(q, uv_handle_t, handle_queue); - if (!(h->flags & UV__HANDLE_INTERNAL)) + if (!(h->flags & UV_HANDLE_INTERNAL)) return UV_EBUSY; } diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index d4fa22aaef6add..5555f83aee4864 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -32,13 +32,13 @@ #include #if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" +# include "uv/stdint-msvc2008.h" #else # include #endif #include "uv.h" -#include "tree.h" +#include "uv/tree.h" #include "queue.h" #if EDOM > 0 @@ -59,22 +59,67 @@ extern int snprintf(char*, size_t, const char*, ...); #define STATIC_ASSERT(expr) \ void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)]) -#ifndef _WIN32 +/* Handle flags. Some flags are specific to Windows or UNIX. */ enum { - UV__SIGNAL_ONE_SHOT = 0x80000, /* On signal reception remove sighandler */ - UV__HANDLE_INTERNAL = 0x8000, - UV__HANDLE_ACTIVE = 0x4000, - UV__HANDLE_REF = 0x2000, - UV__HANDLE_CLOSING = 0 /* no-op on unix */ + /* Used by all handles. */ + UV_HANDLE_CLOSING = 0x00000001, + UV_HANDLE_CLOSED = 0x00000002, + UV_HANDLE_ACTIVE = 0x00000004, + UV_HANDLE_REF = 0x00000008, + UV_HANDLE_INTERNAL = 0x00000010, + UV_HANDLE_ENDGAME_QUEUED = 0x00000020, + + /* Used by streams. */ + UV_HANDLE_LISTENING = 0x00000040, + UV_HANDLE_CONNECTION = 0x00000080, + UV_HANDLE_SHUTTING = 0x00000100, + UV_HANDLE_SHUT = 0x00000200, + UV_HANDLE_READ_PARTIAL = 0x00000400, + UV_HANDLE_READ_EOF = 0x00000800, + + /* Used by streams and UDP handles. */ + UV_HANDLE_READING = 0x00001000, + UV_HANDLE_BOUND = 0x00002000, + UV_HANDLE_READABLE = 0x00004000, + UV_HANDLE_WRITABLE = 0x00008000, + UV_HANDLE_READ_PENDING = 0x00010000, + UV_HANDLE_SYNC_BYPASS_IOCP = 0x00020000, + UV_HANDLE_ZERO_READ = 0x00040000, + UV_HANDLE_EMULATE_IOCP = 0x00080000, + UV_HANDLE_BLOCKING_WRITES = 0x00100000, + UV_HANDLE_CANCELLATION_PENDING = 0x00200000, + + /* Used by uv_tcp_t and uv_udp_t handles */ + UV_HANDLE_IPV6 = 0x00400000, + + /* Only used by uv_tcp_t handles. */ + UV_HANDLE_TCP_NODELAY = 0x01000000, + UV_HANDLE_TCP_KEEPALIVE = 0x02000000, + UV_HANDLE_TCP_SINGLE_ACCEPT = 0x04000000, + UV_HANDLE_TCP_ACCEPT_STATE_CHANGING = 0x08000000, + UV_HANDLE_TCP_SOCKET_CLOSED = 0x10000000, + UV_HANDLE_SHARED_TCP_SOCKET = 0x20000000, + + /* Only used by uv_udp_t handles. */ + UV_HANDLE_UDP_PROCESSING = 0x01000000, + + /* Only used by uv_pipe_t handles. */ + UV_HANDLE_NON_OVERLAPPED_PIPE = 0x01000000, + UV_HANDLE_PIPESERVER = 0x02000000, + + /* Only used by uv_tty_t handles. */ + UV_HANDLE_TTY_READABLE = 0x01000000, + UV_HANDLE_TTY_RAW = 0x02000000, + UV_HANDLE_TTY_SAVED_POSITION = 0x04000000, + UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000, + + /* Only used by uv_signal_t handles. */ + UV_SIGNAL_ONE_SHOT_DISPATCHED = 0x01000000, + UV_SIGNAL_ONE_SHOT = 0x02000000, + + /* Only used by uv_poll_t handles. */ + UV_HANDLE_POLL_SLOW = 0x01000000 }; -#else -# define UV__SIGNAL_ONE_SHOT_DISPATCHED 0x200 -# define UV__SIGNAL_ONE_SHOT 0x100 -# define UV__HANDLE_INTERNAL 0x80 -# define UV__HANDLE_ACTIVE 0x40 -# define UV__HANDLE_REF 0x20 -# define UV__HANDLE_CLOSING 0x01 -#endif int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); @@ -119,8 +164,15 @@ void uv__fs_poll_close(uv_fs_poll_t* handle); int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */ +enum uv__work_kind { + UV__WORK_CPU, + UV__WORK_FAST_IO, + UV__WORK_SLOW_IO +}; + void uv__work_submit(uv_loop_t* loop, struct uv__work *w, + enum uv__work_kind kind, void (*work)(struct uv__work *w), void (*done)(struct uv__work *w, int status)); @@ -132,19 +184,23 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value); void uv__fs_scandir_cleanup(uv_fs_t* req); +int uv__next_timeout(const uv_loop_t* loop); +void uv__run_timers(uv_loop_t* loop); +void uv__timer_close(uv_timer_t* handle); + #define uv__has_active_reqs(loop) \ - (QUEUE_EMPTY(&(loop)->active_reqs) == 0) + ((loop)->active_reqs.count > 0) #define uv__req_register(loop, req) \ do { \ - QUEUE_INSERT_TAIL(&(loop)->active_reqs, &(req)->active_queue); \ + (loop)->active_reqs.count++; \ } \ while (0) #define uv__req_unregister(loop, req) \ do { \ assert(uv__has_active_reqs(loop)); \ - QUEUE_REMOVE(&(req)->active_queue); \ + (loop)->active_reqs.count--; \ } \ while (0) @@ -164,49 +220,47 @@ void uv__fs_scandir_cleanup(uv_fs_t* req); while (0) #define uv__is_active(h) \ - (((h)->flags & UV__HANDLE_ACTIVE) != 0) + (((h)->flags & UV_HANDLE_ACTIVE) != 0) #define uv__is_closing(h) \ - (((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0) + (((h)->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED)) != 0) #define uv__handle_start(h) \ do { \ - assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \ - if (((h)->flags & UV__HANDLE_ACTIVE) != 0) break; \ - (h)->flags |= UV__HANDLE_ACTIVE; \ - if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(h); \ + if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break; \ + (h)->flags |= UV_HANDLE_ACTIVE; \ + if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_add(h); \ } \ while (0) #define uv__handle_stop(h) \ do { \ - assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \ - if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break; \ - (h)->flags &= ~UV__HANDLE_ACTIVE; \ - if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h); \ + if (((h)->flags & UV_HANDLE_ACTIVE) == 0) break; \ + (h)->flags &= ~UV_HANDLE_ACTIVE; \ + if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_rm(h); \ } \ while (0) #define uv__handle_ref(h) \ do { \ - if (((h)->flags & UV__HANDLE_REF) != 0) break; \ - (h)->flags |= UV__HANDLE_REF; \ - if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \ - if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \ + if (((h)->flags & UV_HANDLE_REF) != 0) break; \ + (h)->flags |= UV_HANDLE_REF; \ + if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \ + if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \ } \ while (0) #define uv__handle_unref(h) \ do { \ - if (((h)->flags & UV__HANDLE_REF) == 0) break; \ - (h)->flags &= ~UV__HANDLE_REF; \ - if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \ - if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \ + if (((h)->flags & UV_HANDLE_REF) == 0) break; \ + (h)->flags &= ~UV_HANDLE_REF; \ + if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \ + if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \ } \ while (0) #define uv__has_ref(h) \ - (((h)->flags & UV__HANDLE_REF) != 0) + (((h)->flags & UV_HANDLE_REF) != 0) #if defined(_WIN32) # define uv__handle_platform_init(h) ((h)->u.fd = -1) @@ -218,7 +272,7 @@ void uv__fs_scandir_cleanup(uv_fs_t* req); do { \ (h)->loop = (loop_); \ (h)->type = (type_); \ - (h)->flags = UV__HANDLE_REF; /* Ref the loop when active. */ \ + (h)->flags = UV_HANDLE_REF; /* Ref the loop when active. */ \ QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \ uv__handle_platform_init(h); \ } \ diff --git a/deps/uv/src/win/async.c b/deps/uv/src/win/async.c index 0b636ed1e9137a..d787f6604eaedd 100644 --- a/deps/uv/src/win/async.c +++ b/deps/uv/src/win/async.c @@ -29,7 +29,7 @@ void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { - if (handle->flags & UV__HANDLE_CLOSING && + if (handle->flags & UV_HANDLE_CLOSING && !handle->async_sent) { assert(!(handle->flags & UV_HANDLE_CLOSED)); uv__handle_close(handle); @@ -71,9 +71,9 @@ int uv_async_send(uv_async_t* handle) { return -1; } - /* The user should make sure never to call uv_async_send to a closing */ - /* or closed handle. */ - assert(!(handle->flags & UV__HANDLE_CLOSING)); + /* The user should make sure never to call uv_async_send to a closing or + * closed handle. */ + assert(!(handle->flags & UV_HANDLE_CLOSING)); if (!uv__atomic_exchange_set(&handle->async_sent)) { POST_COMPLETION_FOR_REQ(loop, &handle->async_req); @@ -90,7 +90,7 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, handle->async_sent = 0; - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { uv_want_endgame(loop, (uv_handle_t*)handle); } else if (handle->async_cb != NULL) { handle->async_cb(handle); diff --git a/deps/uv/src/win/atomicops-inl.h b/deps/uv/src/win/atomicops-inl.h index 6d8126f6921bbb..52713cf305feb5 100644 --- a/deps/uv/src/win/atomicops-inl.h +++ b/deps/uv/src/win/atomicops-inl.h @@ -29,10 +29,10 @@ /* Atomic set operation on char */ #ifdef _MSC_VER /* MSVC */ -/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */ -/* efficient than InterlockedExchange, but InterlockedExchange8 does not */ -/* exist, and interlocked operations on larger targets might require the */ -/* target to be aligned. */ +/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less + * efficient than InterlockedExchange, but InterlockedExchange8 does not exist, + * and interlocked operations on larger targets might require the target to be + * aligned. */ #pragma intrinsic(_InterlockedOr8) static char INLINE uv__atomic_exchange_set(char volatile* target) { diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index 9ed4e824c6e96b..bf80d77e273920 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -33,6 +33,7 @@ #include "internal.h" #include "queue.h" #include "handle-inl.h" +#include "heap-inl.h" #include "req-inl.h" /* uv_once initialization guards */ @@ -221,6 +222,7 @@ static void uv_init(void) { int uv_loop_init(uv_loop_t* loop) { + struct heap* timer_heap; int err; /* Initialize libuv itself first */ @@ -239,14 +241,20 @@ int uv_loop_init(uv_loop_t* loop) { QUEUE_INIT(&loop->wq); QUEUE_INIT(&loop->handle_queue); - QUEUE_INIT(&loop->active_reqs); + loop->active_reqs.count = 0; loop->active_handles = 0; loop->pending_reqs_tail = NULL; loop->endgame_handles = NULL; - RB_INIT(&loop->timers); + loop->timer_heap = timer_heap = uv__malloc(sizeof(*timer_heap)); + if (timer_heap == NULL) { + err = UV_ENOMEM; + goto fail_timers_alloc; + } + + heap_init(timer_heap); loop->check_handles = NULL; loop->prepare_handles = NULL; @@ -273,7 +281,7 @@ int uv_loop_init(uv_loop_t* loop) { goto fail_async_init; uv__handle_unref(&loop->wq_async); - loop->wq_async.flags |= UV__HANDLE_INTERNAL; + loop->wq_async.flags |= UV_HANDLE_INTERNAL; err = uv__loops_add(loop); if (err) @@ -285,6 +293,10 @@ int uv_loop_init(uv_loop_t* loop) { uv_mutex_destroy(&loop->wq_mutex); fail_mutex_init: + uv__free(timer_heap); + loop->timer_heap = NULL; + +fail_timers_alloc: CloseHandle(loop->iocp); loop->iocp = INVALID_HANDLE_VALUE; @@ -292,6 +304,13 @@ int uv_loop_init(uv_loop_t* loop) { } +void uv_update_time(uv_loop_t* loop) { + uint64_t new_time = uv__hrtime(1000); + assert(new_time >= loop->time); + loop->time = new_time; +} + + void uv__once_init(void) { uv_once(&uv_init_guard_, uv_init); } @@ -320,6 +339,9 @@ void uv__loop_close(uv_loop_t* loop) { uv_mutex_unlock(&loop->wq_mutex); uv_mutex_destroy(&loop->wq_mutex); + uv__free(loop->timer_heap); + loop->timer_heap = NULL; + CloseHandle(loop->iocp); } @@ -359,7 +381,7 @@ int uv_backend_timeout(const uv_loop_t* loop) { } -static void uv_poll(uv_loop_t* loop, DWORD timeout) { +static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { DWORD bytes; ULONG_PTR key; OVERLAPPED* overlapped; @@ -410,7 +432,7 @@ static void uv_poll(uv_loop_t* loop, DWORD timeout) { } -static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { +static void uv__poll(uv_loop_t* loop, DWORD timeout) { BOOL success; uv_req_t* req; OVERLAPPED_ENTRY overlappeds[128]; @@ -422,12 +444,12 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { timeout_time = loop->time + timeout; for (repeat = 0; ; repeat++) { - success = pGetQueuedCompletionStatusEx(loop->iocp, - overlappeds, - ARRAY_SIZE(overlappeds), - &count, - timeout, - FALSE); + success = GetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); if (success) { for (i = 0; i < count; i++) { @@ -470,8 +492,8 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { static int uv__loop_alive(const uv_loop_t* loop) { - return loop->active_handles > 0 || - !QUEUE_EMPTY(&loop->active_reqs) || + return uv__has_active_handles(loop) || + uv__has_active_reqs(loop) || loop->endgame_handles != NULL; } @@ -485,12 +507,6 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { DWORD timeout; int r; int ran_pending; - void (*poll)(uv_loop_t* loop, DWORD timeout); - - if (pGetQueuedCompletionStatusEx) - poll = &uv_poll_ex; - else - poll = &uv_poll; r = uv__loop_alive(loop); if (!r) @@ -498,7 +514,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { while (r != 0 && loop->stop_flag == 0) { uv_update_time(loop); - uv_process_timers(loop); + uv__run_timers(loop); ran_pending = uv_process_reqs(loop); uv_idle_invoke(loop); @@ -508,7 +524,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) timeout = uv_backend_timeout(loop); - (*poll)(loop, timeout); + if (pGetQueuedCompletionStatusEx) + uv__poll(loop, timeout); + else + uv__poll_wine(loop, timeout); + uv_check_invoke(loop); uv_process_endgames(loop); @@ -522,7 +542,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from * the check. */ - uv_process_timers(loop); + uv__run_timers(loop); } r = uv__loop_alive(loop); diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c index 9b03bfef6b5d71..24924ba81ef3b2 100644 --- a/deps/uv/src/win/error.c +++ b/deps/uv/src/win/error.c @@ -46,8 +46,8 @@ void uv_fatal_error(const int errorno, const char* syscall) { errmsg = "Unknown error"; } - /* FormatMessage messages include a newline character already, */ - /* so don't add another. */ + /* FormatMessage messages include a newline character already, so don't add + * another. */ if (syscall) { fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg); } else { diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 95f843ad08edee..25809ea4f2f605 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -69,6 +69,7 @@ static void uv_relative_path(const WCHAR* filename, size_t relpathlen; size_t filenamelen = wcslen(filename); size_t dirlen = wcslen(dir); + assert(!_wcsnicmp(filename, dir, dirlen)); if (dirlen > 0 && dir[dirlen - 1] == '\\') dirlen--; relpathlen = filenamelen - dirlen - 1; @@ -82,7 +83,7 @@ static void uv_relative_path(const WCHAR* filename, static int uv_split_path(const WCHAR* filename, WCHAR** dir, WCHAR** file) { size_t len, i; - + if (filename == NULL) { if (dir != NULL) *dir = NULL; @@ -151,11 +152,11 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags) { - int name_size, is_path_dir; + int name_size, is_path_dir, size; DWORD attr, last_error; WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL; WCHAR short_path_buffer[MAX_PATH]; - WCHAR* short_path; + WCHAR* short_path, *long_path; if (uv__is_active(handle)) return UV_EINVAL; @@ -197,6 +198,30 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (is_path_dir) { /* path is a directory, so that's the directory that we will watch. */ + + /* Convert to long path. */ + size = GetLongPathNameW(pathw, NULL, 0); + + if (size) { + long_path = (WCHAR*)uv__malloc(size * sizeof(WCHAR)); + if (!long_path) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + size = GetLongPathNameW(pathw, long_path, size); + if (size) { + long_path[size] = '\0'; + } else { + uv__free(long_path); + long_path = NULL; + } + } + + if (long_path) { + uv__free(pathw); + pathw = long_path; + } + dir_to_watch = pathw; } else { /* @@ -394,7 +419,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, * - We are not active, just ignore the callback */ if (!uv__is_active(handle)) { - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { uv_want_endgame(loop, (uv_handle_t*) handle); } return; @@ -518,7 +543,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } offset = file_info->NextEntryOffset; - } while (offset && !(handle->flags & UV__HANDLE_CLOSING)); + } while (offset && !(handle->flags & UV_HANDLE_CLOSING)); } else { handle->cb(handle, NULL, UV_CHANGE, 0); } @@ -527,7 +552,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); } - if (!(handle->flags & UV__HANDLE_CLOSING)) { + if (!(handle->flags & UV_HANDLE_CLOSING)) { uv_fs_event_queue_readdirchanges(loop, handle); } else { uv_want_endgame(loop, (uv_handle_t*)handle); @@ -548,7 +573,7 @@ void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) { void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { - if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) { + if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) { assert(!(handle->flags & UV_HANDLE_CLOSED)); if (handle->buffer) { diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 6e0bdc7bb20e66..812c1a6de583d2 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -55,7 +55,11 @@ do { \ if (cb != NULL) { \ uv__req_register(loop, req); \ - uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \ + uv__work_submit(loop, \ + &req->work_req, \ + UV__WORK_FAST_IO, \ + uv__fs_work, \ + uv__fs_done); \ return 0; \ } else { \ uv__fs_work(&req->work_req); \ @@ -245,7 +249,6 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, req->ptr = NULL; req->path = NULL; req->cb = cb; - req->fs.info.bufs = NULL; memset(&req->fs, 0, sizeof(req->fs)); } @@ -327,12 +330,11 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR); - /* Real symlinks can contain pretty much everything, but the only thing */ - /* we really care about is undoing the implicit conversion to an NT */ - /* namespaced path that CreateSymbolicLink will perform on absolute */ - /* paths. If the path is win32-namespaced then the user must have */ - /* explicitly made it so, and we better just return the unmodified */ - /* reparse data. */ + /* Real symlinks can contain pretty much everything, but the only thing we + * really care about is undoing the implicit conversion to an NT namespaced + * path that CreateSymbolicLink will perform on absolute paths. If the path + * is win32-namespaced then the user must have explicitly made it so, and + * we better just return the unmodified reparse data. */ if (w_target_len >= 4 && w_target[0] == L'\\' && w_target[1] == L'?' && @@ -353,8 +355,8 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, (w_target[5] == L'N' || w_target[5] == L'n') && (w_target[6] == L'C' || w_target[6] == L'c') && w_target[7] == L'\\') { - /* \??\UNC\\\ - make sure the final path looks like */ - /* \\\\ */ + /* \??\UNC\\\ - make sure the final path looks like + * \\\\ */ w_target += 6; w_target[0] = L'\\'; w_target_len -= 6; @@ -369,11 +371,11 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR); - /* Only treat junctions that look like \??\:\ as symlink. */ - /* Junctions can also be used as mount points, like \??\Volume{}, */ - /* but that's confusing for programs since they wouldn't be able to */ - /* actually understand such a path when returned by uv_readlink(). */ - /* UNC paths are never valid for junctions so we don't care about them. */ + /* Only treat junctions that look like \??\:\ as symlink. Junctions + * can also be used as mount points, like \??\Volume{}, but that's + * confusing for programs since they wouldn't be able to actually + * understand such a path when returned by uv_readlink(). UNC paths are + * never valid for junctions so we don't care about them. */ if (!(w_target_len >= 6 && w_target[0] == L'\\' && w_target[1] == L'?' && @@ -410,8 +412,8 @@ void fs__open(uv_fs_t* req) { int fd, current_umask; int flags = req->fs.info.file_flags; - /* Obtain the active umask. umask() never fails and returns the previous */ - /* umask. */ + /* Obtain the active umask. umask() never fails and returns the previous + * umask. */ current_umask = umask(0); umask(current_umask); @@ -531,8 +533,8 @@ void fs__open(uv_fs_t* req) { DWORD error = GetLastError(); if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) && !(flags & UV_FS_O_EXCL)) { - /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was */ - /* specified, it means the path referred to a directory. */ + /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was + * specified, it means the path referred to a directory. */ SET_REQ_UV_ERROR(req, UV_EISDIR, error); } else { SET_REQ_WIN32_ERROR(req, GetLastError()); @@ -757,9 +759,9 @@ void fs__unlink(uv_fs_t* req) { } if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - /* Do not allow deletion of directories, unless it is a symlink. When */ - /* the path refers to a non-symlink directory, report EPERM as mandated */ - /* by POSIX.1. */ + /* Do not allow deletion of directories, unless it is a symlink. When the + * path refers to a non-symlink directory, report EPERM as mandated by + * POSIX.1. */ /* Check if it is a reparse point. If it's not, it's a normal directory. */ if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { @@ -768,8 +770,8 @@ void fs__unlink(uv_fs_t* req) { return; } - /* Read the reparse point and check if it is a valid symlink. */ - /* If not, don't unlink. */ + /* Read the reparse point and check if it is a valid symlink. If not, don't + * unlink. */ if (fs__readlink_handle(handle, NULL, NULL) < 0) { DWORD error = GetLastError(); if (error == ERROR_SYMLINK_NOT_SUPPORTED) @@ -784,7 +786,9 @@ void fs__unlink(uv_fs_t* req) { /* Remove read-only attribute */ FILE_BASIC_INFORMATION basic = { 0 }; - basic.FileAttributes = info.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY); + basic.FileAttributes = info.dwFileAttributes + & ~(FILE_ATTRIBUTE_READONLY) + | FILE_ATTRIBUTE_ARCHIVE; status = pNtSetInformationFile(handle, &iosb, @@ -1391,6 +1395,12 @@ static void fs__copyfile(uv_fs_t* req) { int overwrite; flags = req->fs.info.file_flags; + + if (flags & UV_FS_COPYFILE_FICLONE_FORCE) { + SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); + return; + } + overwrite = flags & UV_FS_COPYFILE_EXCL; if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) == 0) { @@ -1483,6 +1493,7 @@ static void fs__chmod(uv_fs_t* req) { static void fs__fchmod(uv_fs_t* req) { int fd = req->file.fd; + int clear_archive_flag; HANDLE handle; NTSTATUS nt_status; IO_STATUS_BLOCK io_status; @@ -1490,7 +1501,11 @@ static void fs__fchmod(uv_fs_t* req) { VERIFY_FD(fd, req); - handle = uv__get_osfhandle(fd); + handle = ReOpenFile(uv__get_osfhandle(fd), FILE_WRITE_ATTRIBUTES, 0, 0); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } nt_status = pNtQueryInformationFile(handle, &io_status, @@ -1500,7 +1515,27 @@ static void fs__fchmod(uv_fs_t* req) { if (!NT_SUCCESS(nt_status)) { SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); - return; + goto fchmod_cleanup; + } + + /* Test if the Archive attribute is cleared */ + if ((file_info.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == 0) { + /* Set Archive flag, otherwise setting or clearing the read-only + flag will not work */ + file_info.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; + nt_status = pNtSetInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileBasicInformation); + if (!NT_SUCCESS(nt_status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); + goto fchmod_cleanup; + } + /* Remeber to clear the flag later on */ + clear_archive_flag = 1; + } else { + clear_archive_flag = 0; } if (req->fs.info.mode & _S_IWRITE) { @@ -1517,10 +1552,28 @@ static void fs__fchmod(uv_fs_t* req) { if (!NT_SUCCESS(nt_status)) { SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); - return; + goto fchmod_cleanup; + } + + if (clear_archive_flag) { + file_info.FileAttributes &= ~FILE_ATTRIBUTE_ARCHIVE; + if (file_info.FileAttributes == 0) { + file_info.FileAttributes = FILE_ATTRIBUTE_NORMAL; + } + nt_status = pNtSetInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileBasicInformation); + if (!NT_SUCCESS(nt_status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); + goto fchmod_cleanup; + } } SET_REQ_SUCCESS(req); +fchmod_cleanup: + CloseHandle(handle); } @@ -1780,17 +1833,13 @@ static void fs__symlink(uv_fs_t* req) { fs__create_junction(req, pathw, new_pathw); return; } - if (!pCreateSymbolicLinkW) { - SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); - return; - } if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR) flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag; else flags = uv__file_symlink_usermode_flag; - if (pCreateSymbolicLinkW(new_pathw, pathw, flags)) { + if (CreateSymbolicLinkW(new_pathw, pathw, flags)) { SET_REQ_RESULT(req, 0); return; } @@ -1847,7 +1896,7 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { WCHAR* w_realpath_ptr = NULL; WCHAR* w_realpath_buf; - w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); + w_realpath_len = GetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); if (w_realpath_len == 0) { return -1; } @@ -1859,10 +1908,8 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { } w_realpath_ptr = w_realpath_buf; - if (pGetFinalPathNameByHandleW(handle, - w_realpath_ptr, - w_realpath_len, - VOLUME_NAME_DOS) == 0) { + if (GetFinalPathNameByHandleW( + handle, w_realpath_ptr, w_realpath_len, VOLUME_NAME_DOS) == 0) { uv__free(w_realpath_buf); SetLastError(ERROR_INVALID_HANDLE); return -1; @@ -1894,11 +1941,6 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { static void fs__realpath(uv_fs_t* req) { HANDLE handle; - if (!pGetFinalPathNameByHandleW) { - SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); - return; - } - handle = CreateFileW(req->file.pathw, 0, 0, @@ -1933,6 +1975,10 @@ static void fs__fchown(uv_fs_t* req) { } +static void fs__lchown(uv_fs_t* req) { + req->result = 0; +} + static void uv__fs_work(struct uv__work* w) { uv_fs_t* req; @@ -1970,6 +2016,7 @@ static void uv__fs_work(struct uv__work* w) { XX(REALPATH, realpath) XX(CHOWN, chown) XX(FCHOWN, fchown); + XX(LCHOWN, lchown); default: assert(!"bad uv_fs_type"); } @@ -2255,6 +2302,19 @@ int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid, } +int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { + int err; + + INIT(UV_FS_LCHOWN); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + POST; +} + + int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; @@ -2335,8 +2395,11 @@ int uv_fs_copyfile(uv_loop_t* loop, INIT(UV_FS_COPYFILE); - if (flags & ~UV_FS_COPYFILE_EXCL) + if (flags & ~(UV_FS_COPYFILE_EXCL | + UV_FS_COPYFILE_FICLONE | + UV_FS_COPYFILE_FICLONE_FORCE)) { return UV_EINVAL; + } err = fs__capture_path(req, path, new_path, cb != NULL); diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index 282d919cf75513..614ea8e376e8af 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -71,8 +71,8 @@ int uv__getaddrinfo_translate_error(int sys_err) { #endif -/* adjust size value to be multiple of 4. Use to keep pointer aligned */ -/* Do we need different versions of this for different architectures? */ +/* Adjust size value to be multiple of 4. Use to keep pointer aligned. + * Do we need different versions of this for different architectures? */ #define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2) #ifndef NDIS_IF_MAX_STRING_SIZE @@ -124,8 +124,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { } if (req->retcode == 0) { - /* convert addrinfoW to addrinfo */ - /* first calculate required length */ + /* Convert addrinfoW to addrinfo. First calculate required length. */ addrinfow_ptr = req->addrinfow; while (addrinfow_ptr != NULL) { addrinfo_len += addrinfo_struct_len + @@ -313,8 +312,8 @@ int uv_getaddrinfo(uv_loop_t* loop, /* save alloc_ptr now so we can free if error */ req->alloc = (void*)alloc_ptr; - /* convert node string to UTF16 into allocated memory and save pointer in */ - /* the request. */ + /* Convert node string to UTF16 into allocated memory and save pointer in the + * request. */ if (node != NULL) { req->node = (WCHAR*)alloc_ptr; if (MultiByteToWideChar(CP_UTF8, @@ -331,8 +330,8 @@ int uv_getaddrinfo(uv_loop_t* loop, req->node = NULL; } - /* convert service string to UTF16 into allocated memory and save pointer */ - /* in the req. */ + /* Convert service string to UTF16 into allocated memory and save pointer in + * the req. */ if (service != NULL) { req->service = (WCHAR*)alloc_ptr; if (MultiByteToWideChar(CP_UTF8, @@ -369,6 +368,7 @@ int uv_getaddrinfo(uv_loop_t* loop, if (getaddrinfo_cb) { uv__work_submit(loop, &req->work_req, + UV__WORK_SLOW_IO, uv__getaddrinfo_work, uv__getaddrinfo_done); return 0; diff --git a/deps/uv/src/win/getnameinfo.c b/deps/uv/src/win/getnameinfo.c index 9f10cd2a5a1432..b3773380c21d70 100644 --- a/deps/uv/src/win/getnameinfo.c +++ b/deps/uv/src/win/getnameinfo.c @@ -42,7 +42,7 @@ static void uv__getnameinfo_work(struct uv__work* w) { uv_getnameinfo_t* req; WCHAR host[NI_MAXHOST]; WCHAR service[NI_MAXSERV]; - int ret = 0; + int ret; req = container_of(w, uv_getnameinfo_t, work_req); if (GetNameInfoW((struct sockaddr*)&req->storage, @@ -53,27 +53,34 @@ static void uv__getnameinfo_work(struct uv__work* w) { ARRAY_SIZE(service), req->flags)) { ret = WSAGetLastError(); + req->retcode = uv__getaddrinfo_translate_error(ret); + return; + } + + ret = WideCharToMultiByte(CP_UTF8, + 0, + host, + -1, + req->host, + sizeof(req->host), + NULL, + NULL); + if (ret == 0) { + req->retcode = uv_translate_sys_error(GetLastError()); + return; + } + + ret = WideCharToMultiByte(CP_UTF8, + 0, + service, + -1, + req->service, + sizeof(req->service), + NULL, + NULL); + if (ret == 0) { + req->retcode = uv_translate_sys_error(GetLastError()); } - req->retcode = uv__getaddrinfo_translate_error(ret); - - /* convert results to UTF-8 */ - WideCharToMultiByte(CP_UTF8, - 0, - host, - -1, - req->host, - sizeof(req->host), - NULL, - NULL); - - WideCharToMultiByte(CP_UTF8, - 0, - service, - -1, - req->service, - sizeof(req->service), - NULL, - NULL); } @@ -138,6 +145,7 @@ int uv_getnameinfo(uv_loop_t* loop, if (getnameinfo_cb) { uv__work_submit(loop, &req->work_req, + UV__WORK_SLOW_IO, uv__getnameinfo_work, uv__getnameinfo_done); return 0; diff --git a/deps/uv/src/win/handle-inl.h b/deps/uv/src/win/handle-inl.h index 8d0334cc52a75c..82c657d579fb04 100644 --- a/deps/uv/src/win/handle-inl.h +++ b/deps/uv/src/win/handle-inl.h @@ -32,7 +32,7 @@ #define DECREASE_ACTIVE_COUNT(loop, handle) \ do { \ if (--(handle)->activecnt == 0 && \ - !((handle)->flags & UV__HANDLE_CLOSING)) { \ + !((handle)->flags & UV_HANDLE_CLOSING)) { \ uv__handle_stop((handle)); \ } \ assert((handle)->activecnt >= 0); \ @@ -53,7 +53,7 @@ assert(handle->reqs_pending > 0); \ handle->reqs_pending--; \ \ - if (handle->flags & UV__HANDLE_CLOSING && \ + if (handle->flags & UV_HANDLE_CLOSING && \ handle->reqs_pending == 0) { \ uv_want_endgame(loop, (uv_handle_t*)handle); \ } \ @@ -62,14 +62,14 @@ #define uv__handle_closing(handle) \ do { \ - assert(!((handle)->flags & UV__HANDLE_CLOSING)); \ + assert(!((handle)->flags & UV_HANDLE_CLOSING)); \ \ - if (!(((handle)->flags & UV__HANDLE_ACTIVE) && \ - ((handle)->flags & UV__HANDLE_REF))) \ + if (!(((handle)->flags & UV_HANDLE_ACTIVE) && \ + ((handle)->flags & UV_HANDLE_REF))) \ uv__active_handle_add((uv_handle_t*) (handle)); \ \ - (handle)->flags |= UV__HANDLE_CLOSING; \ - (handle)->flags &= ~UV__HANDLE_ACTIVE; \ + (handle)->flags |= UV_HANDLE_CLOSING; \ + (handle)->flags &= ~UV_HANDLE_ACTIVE; \ } while (0) @@ -126,7 +126,8 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) { break; case UV_TIMER: - uv_timer_endgame(loop, (uv_timer_t*) handle); + uv__timer_close((uv_timer_t*) handle); + uv__handle_close(handle); break; case UV_PREPARE: @@ -164,10 +165,10 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) { INLINE static HANDLE uv__get_osfhandle(int fd) { - /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */ - /* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */ - /* for invalid FDs in release builds (or if you let the assert continue). */ - /* So this wrapper function disables asserts when calling _get_osfhandle. */ + /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. + * But it also correctly checks the FD and returns INVALID_HANDLE_VALUE for + * invalid FDs in release builds (or if you let the assert continue). So this + * wrapper function disables asserts when calling _get_osfhandle. */ HANDLE handle; UV_BEGIN_DISABLE_CRT_ASSERT(); diff --git a/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c index 39150702ddcd07..9d76c3f5420997 100644 --- a/deps/uv/src/win/handle.c +++ b/deps/uv/src/win/handle.c @@ -59,15 +59,15 @@ uv_handle_type uv_guess_handle(uv_file file) { int uv_is_active(const uv_handle_t* handle) { - return (handle->flags & UV__HANDLE_ACTIVE) && - !(handle->flags & UV__HANDLE_CLOSING); + return (handle->flags & UV_HANDLE_ACTIVE) && + !(handle->flags & UV_HANDLE_CLOSING); } void uv_close(uv_handle_t* handle, uv_close_cb cb) { uv_loop_t* loop = handle->loop; - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { assert(0); return; } @@ -150,10 +150,14 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { int uv_is_closing(const uv_handle_t* handle) { - return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED)); + return !!(handle->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED)); } uv_os_fd_t uv_get_osfhandle(int fd) { return uv__get_osfhandle(fd); } + +int uv_open_osfhandle(uv_os_fd_t os_fd) { + return _open_osfhandle((intptr_t) os_fd, 0); +} diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 217fcdb5d7678e..634b9f776ccc67 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -25,7 +25,7 @@ #include "uv.h" #include "../uv-common.h" -#include "tree.h" +#include "uv/tree.h" #include "winapi.h" #include "winsock.h" @@ -57,78 +57,20 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled; #define UV_END_DISABLE_CRT_ASSERT() #endif -/* - * Handles - * (also see handle-inl.h) - */ - -/* Used by all handles. */ -#define UV_HANDLE_CLOSED 0x00000002 -#define UV_HANDLE_ENDGAME_QUEUED 0x00000008 - -/* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */ -/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */ -/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */ -/* uv-common.h: #define UV_HANDLE_INTERNAL 0x00000080 */ - -/* Used by streams and UDP handles. */ -#define UV_HANDLE_READING 0x00000100 -#define UV_HANDLE_BOUND 0x00000200 -#define UV_HANDLE_LISTENING 0x00000800 -#define UV_HANDLE_CONNECTION 0x00001000 -#define UV_HANDLE_READABLE 0x00008000 -#define UV_HANDLE_WRITABLE 0x00010000 -#define UV_HANDLE_READ_PENDING 0x00020000 -#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000 -#define UV_HANDLE_ZERO_READ 0x00080000 -#define UV_HANDLE_EMULATE_IOCP 0x00100000 -#define UV_HANDLE_BLOCKING_WRITES 0x00200000 -#define UV_HANDLE_CANCELLATION_PENDING 0x00400000 - -/* Used by uv_tcp_t and uv_udp_t handles */ -#define UV_HANDLE_IPV6 0x01000000 - -/* Only used by uv_tcp_t handles. */ -#define UV_HANDLE_TCP_NODELAY 0x02000000 -#define UV_HANDLE_TCP_KEEPALIVE 0x04000000 -#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000 -#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000 -#define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000 -#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000 - -/* Only used by uv_pipe_t handles. */ -#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000 -#define UV_HANDLE_PIPESERVER 0x02000000 -#define UV_HANDLE_PIPE_READ_CANCELABLE 0x04000000 - -/* Only used by uv_tty_t handles. */ -#define UV_HANDLE_TTY_READABLE 0x01000000 -#define UV_HANDLE_TTY_RAW 0x02000000 -#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000 -#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000 - -/* Only used by uv_poll_t handles. */ -#define UV_HANDLE_POLL_SLOW 0x02000000 - - -/* - * Requests: see req-inl.h - */ - - -/* - * Streams: see stream-inl.h - */ - - /* * TCP */ +typedef enum { + UV__IPC_SOCKET_XFER_NONE = 0, + UV__IPC_SOCKET_XFER_TCP_CONNECTION, + UV__IPC_SOCKET_XFER_TCP_SERVER +} uv__ipc_socket_xfer_type_t; + typedef struct { WSAPROTOCOL_INFOW socket_info; - int delayed_error; -} uv__ipc_socket_info_ex; + uint32_t delayed_error; +} uv__ipc_socket_xfer_info_t; int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb); int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client); @@ -150,11 +92,13 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp); void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); -int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex, - int tcp_connection); - -int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, - LPWSAPROTOCOL_INFOW protocol_info); +int uv__tcp_xfer_export(uv_tcp_t* handle, + int pid, + uv__ipc_socket_xfer_type_t* xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info); +int uv__tcp_xfer_import(uv_tcp_t* tcp, + uv__ipc_socket_xfer_type_t xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info); /* @@ -178,14 +122,14 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client); int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb); -int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, - const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); -int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, - const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, - uv_write_cb cb); -void uv__pipe_pause_read(uv_pipe_t* handle); -void uv__pipe_unpause_read(uv_pipe_t* handle); -void uv__pipe_stop_read(uv_pipe_t* handle); +void uv__pipe_read_stop(uv_pipe_t* handle); +int uv__pipe_write(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + size_t nbufs, + uv_stream_t* send_handle, + uv_write_cb cb); void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, uv_req_t* req); @@ -221,10 +165,16 @@ void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, uv_req_t* req); void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, uv_write_t* req); -/* TODO: remove me */ +/* + * uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working + * TODO: find a way to remove it + */ void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, uv_req_t* raw_req); -/* TODO: remove me */ +/* + * uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working + * TODO: find a way to remove it + */ void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, uv_connect_t* req); @@ -241,15 +191,6 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle); void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); -/* - * Timers - */ -void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); - -DWORD uv__next_timeout(const uv_loop_t* loop); -void uv_process_timers(uv_loop_t* loop); - - /* * Loop watchers */ @@ -326,7 +267,6 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle); void uv__util_init(void); uint64_t uv__hrtime(double scale); -int uv_current_pid(void); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); int uv__getpwuid_r(uv_passwd_t* pwd); int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); diff --git a/deps/uv/src/win/loop-watcher.c b/deps/uv/src/win/loop-watcher.c index 20e4509f838c05..ad7fbea169717f 100644 --- a/deps/uv/src/win/loop-watcher.c +++ b/deps/uv/src/win/loop-watcher.c @@ -27,7 +27,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; uv__handle_close(handle); diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 1a7c4dc15e0b30..9a3cbc8a1e26e1 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -21,39 +21,28 @@ #include #include -#include #include #include +#include -#include "uv.h" -#include "internal.h" #include "handle-inl.h" -#include "stream-inl.h" +#include "internal.h" #include "req-inl.h" +#include "stream-inl.h" +#include "uv-common.h" +#include "uv.h" #include #include -typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t; - -struct uv__ipc_queue_item_s { - /* - * NOTE: It is important for socket_info_ex to be the first field, - * because we will we assigning it to the pending_ipc_info.socket_info - */ - uv__ipc_socket_info_ex socket_info_ex; - QUEUE member; - int tcp_connection; -}; - /* A zero-size buffer for use by uv_pipe_read */ static char uv_zero_[] = ""; /* Null uv_buf_t */ static const uv_buf_t uv_null_buf_ = { 0, NULL }; -/* The timeout that the pipe will wait for the remote end to write data */ -/* when the local ends wants to shut it down. */ +/* The timeout that the pipe will wait for the remote end to write data when + * the local ends wants to shut it down. */ static const int64_t eof_timeout = 50; /* ms */ static const int default_pending_pipe_instances = 4; @@ -62,22 +51,44 @@ static const int default_pending_pipe_instances = 4; static char pipe_prefix[] = "\\\\?\\pipe"; static const int pipe_prefix_len = sizeof(pipe_prefix) - 1; -/* IPC protocol flags. */ -#define UV_IPC_RAW_DATA 0x0001 -#define UV_IPC_TCP_SERVER 0x0002 -#define UV_IPC_TCP_CONNECTION 0x0004 +/* IPC incoming xfer queue item. */ +typedef struct { + uv__ipc_socket_xfer_type_t xfer_type; + uv__ipc_socket_xfer_info_t xfer_info; + QUEUE member; +} uv__ipc_xfer_queue_item_t; + +/* IPC frame header flags. */ +/* clang-format off */ +enum { + UV__IPC_FRAME_HAS_DATA = 0x01, + UV__IPC_FRAME_HAS_SOCKET_XFER = 0x02, + UV__IPC_FRAME_XFER_IS_TCP_CONNECTION = 0x04, + /* These are combinations of the flags above. */ + UV__IPC_FRAME_XFER_FLAGS = 0x06, + UV__IPC_FRAME_VALID_FLAGS = 0x07 +}; +/* clang-format on */ /* IPC frame header. */ typedef struct { - int flags; - uint64_t raw_data_length; -} uv_ipc_frame_header_t; - -/* IPC frame, which contains an imported TCP socket stream. */ + uint32_t flags; + uint32_t reserved1; /* Ignored. */ + uint32_t data_length; /* Must be zero if there is no data. */ + uint32_t reserved2; /* Must be zero. */ +} uv__ipc_frame_header_t; + +/* To implement the IPC protocol correctly, these structures must have exactly + * the right size. */ +STATIC_ASSERT(sizeof(uv__ipc_frame_header_t) == 16); +STATIC_ASSERT(sizeof(uv__ipc_socket_xfer_info_t) == 632); + +/* Coalesced write request. */ typedef struct { - uv_ipc_frame_header_t header; - uv__ipc_socket_info_ex socket_info_ex; -} uv_ipc_frame_uv_stream; + uv_write_t req; /* Internal heap-allocated write request. */ + uv_write_t* user_req; /* Pointer to user-specified uv_write_t. */ +} uv__coalesced_write_t; + static void eof_timer_init(uv_pipe_t* pipe); static void eof_timer_start(uv_pipe_t* pipe); @@ -98,15 +109,12 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { handle->reqs_pending = 0; handle->handle = INVALID_HANDLE_VALUE; handle->name = NULL; - handle->pipe.conn.ipc_pid = 0; - handle->pipe.conn.remaining_ipc_rawdata_bytes = 0; - QUEUE_INIT(&handle->pipe.conn.pending_ipc_info.queue); - handle->pipe.conn.pending_ipc_info.queue_len = 0; + handle->pipe.conn.ipc_remote_pid = 0; + handle->pipe.conn.ipc_data_frame.payload_remaining = 0; + QUEUE_INIT(&handle->pipe.conn.ipc_xfer_queue); + handle->pipe.conn.ipc_xfer_queue_length = 0; handle->ipc = ipc; handle->pipe.conn.non_overlapped_writes_tail = NULL; - handle->pipe.conn.readfile_thread = NULL; - - UV_REQ_INIT(&handle->pipe.conn.ipc_header_write_req, UV_UNKNOWN_REQ); return 0; } @@ -117,10 +125,9 @@ static void uv_pipe_connection_init(uv_pipe_t* handle) { handle->read_req.data = handle; handle->pipe.conn.eof_timer = NULL; assert(!(handle->flags & UV_HANDLE_PIPESERVER)); - if (pCancelSynchronousIo && - handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { - uv_mutex_init(&handle->pipe.conn.readfile_mutex); - handle->flags |= UV_HANDLE_PIPE_READ_CANCELABLE; + if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + handle->pipe.conn.readfile_thread_handle = NULL; + InitializeCriticalSection(&handle->pipe.conn.readfile_thread_lock); } } @@ -347,12 +354,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { NTSTATUS nt_status; IO_STATUS_BLOCK io_status; FILE_PIPE_LOCAL_INFORMATION pipe_info; - uv__ipc_queue_item_t* item; - - if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { - handle->flags &= ~UV_HANDLE_PIPE_READ_CANCELABLE; - uv_mutex_destroy(&handle->pipe.conn.readfile_mutex); - } + uv__ipc_xfer_queue_item_t* xfer_queue_item; if ((handle->flags & UV_HANDLE_CONNECTION) && handle->stream.conn.shutdown_req != NULL && @@ -362,7 +364,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { /* Clear the shutdown_req field so we don't go here again. */ handle->stream.conn.shutdown_req = NULL; - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { UNREGISTER_HANDLE_REQ(loop, handle, req); /* Already closing. Cancel the shutdown. */ @@ -423,33 +425,33 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { } } - if (handle->flags & UV__HANDLE_CLOSING && + if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); if (handle->flags & UV_HANDLE_CONNECTION) { /* Free pending sockets */ - while (!QUEUE_EMPTY(&handle->pipe.conn.pending_ipc_info.queue)) { + while (!QUEUE_EMPTY(&handle->pipe.conn.ipc_xfer_queue)) { QUEUE* q; SOCKET socket; - q = QUEUE_HEAD(&handle->pipe.conn.pending_ipc_info.queue); + q = QUEUE_HEAD(&handle->pipe.conn.ipc_xfer_queue); QUEUE_REMOVE(q); - item = QUEUE_DATA(q, uv__ipc_queue_item_t, member); + xfer_queue_item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member); /* Materialize socket and close it */ socket = WSASocketW(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, - &item->socket_info_ex.socket_info, + &xfer_queue_item->xfer_info.socket_info, 0, WSA_FLAG_OVERLAPPED); - uv__free(item); + uv__free(xfer_queue_item); if (socket != INVALID_SOCKET) closesocket(socket); } - handle->pipe.conn.pending_ipc_info.queue_len = 0; + handle->pipe.conn.ipc_xfer_queue_length = 0; if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { @@ -461,6 +463,9 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { handle->read_req.event_handle = NULL; } } + + if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) + DeleteCriticalSection(&handle->pipe.conn.readfile_thread_lock); } if (handle->flags & UV_HANDLE_PIPESERVER) { @@ -595,8 +600,8 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { loop = handle->loop; assert(loop); - /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */ - /* We wait for the pipe to become available with WaitNamedPipe. */ + /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait + * for the pipe to become available with WaitNamedPipe. */ while (WaitNamedPipeW(handle->name, 30000)) { /* The pipe is now available, try to connect. */ pipeHandle = open_named_pipe(handle->name, &duplex_flags); @@ -706,48 +711,68 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, } -void uv__pipe_pause_read(uv_pipe_t* handle) { - if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { - /* Pause the ReadFile task briefly, to work - around the Windows kernel bug that causes - any access to a NamedPipe to deadlock if - any process has called ReadFile */ - HANDLE h; - uv_mutex_lock(&handle->pipe.conn.readfile_mutex); - h = handle->pipe.conn.readfile_thread; - while (h) { - /* spinlock: we expect this to finish quickly, - or we are probably about to deadlock anyways - (in the kernel), so it doesn't matter */ - pCancelSynchronousIo(h); - SwitchToThread(); /* yield thread control briefly */ - h = handle->pipe.conn.readfile_thread; - } - } -} +void uv__pipe_interrupt_read(uv_pipe_t* handle) { + BOOL r; + + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + return; /* No pending reads. */ + if (handle->flags & UV_HANDLE_CANCELLATION_PENDING) + return; /* Already cancelled. */ + if (handle->handle == INVALID_HANDLE_VALUE) + return; /* Pipe handle closed. */ + if (!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)) { + /* Cancel asynchronous read. */ + r = CancelIoEx(handle->handle, &handle->read_req.u.io.overlapped); + assert(r || GetLastError() == ERROR_NOT_FOUND); -void uv__pipe_unpause_read(uv_pipe_t* handle) { - if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { - uv_mutex_unlock(&handle->pipe.conn.readfile_mutex); + } else { + /* Cancel synchronous read (which is happening in the thread pool). */ + HANDLE thread; + volatile HANDLE* thread_ptr = &handle->pipe.conn.readfile_thread_handle; + + EnterCriticalSection(&handle->pipe.conn.readfile_thread_lock); + + thread = *thread_ptr; + if (thread == NULL) { + /* The thread pool thread has not yet reached the point of blocking, we + * can pre-empt it by setting thread_handle to INVALID_HANDLE_VALUE. */ + *thread_ptr = INVALID_HANDLE_VALUE; + + } else { + /* Spin until the thread has acknowledged (by setting the thread to + * INVALID_HANDLE_VALUE) that it is past the point of blocking. */ + while (thread != INVALID_HANDLE_VALUE) { + r = CancelSynchronousIo(thread); + assert(r || GetLastError() == ERROR_NOT_FOUND); + SwitchToThread(); /* Yield thread. */ + thread = *thread_ptr; + } + } + + LeaveCriticalSection(&handle->pipe.conn.readfile_thread_lock); } + + /* Set flag to indicate that read has been cancelled. */ + handle->flags |= UV_HANDLE_CANCELLATION_PENDING; } -void uv__pipe_stop_read(uv_pipe_t* handle) { +void uv__pipe_read_stop(uv_pipe_t* handle) { handle->flags &= ~UV_HANDLE_READING; - uv__pipe_pause_read((uv_pipe_t*)handle); - uv__pipe_unpause_read((uv_pipe_t*)handle); + DECREASE_ACTIVE_COUNT(handle->loop, handle); + + uv__pipe_interrupt_read(handle); } -/* Cleans up uv_pipe_t (server or connection) and all resources associated */ -/* with it. */ +/* Cleans up uv_pipe_t (server or connection) and all resources associated with + * it. */ void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { int i; HANDLE pipeHandle; - uv__pipe_stop_read(handle); + uv__pipe_interrupt_read(handle); if (handle->name) { uv__free(handle->name); @@ -847,6 +872,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, return; } + /* Wait for completion via IOCP */ handle->reqs_pending++; } @@ -856,23 +882,22 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { uv_pipe_t* pipe_client; uv_pipe_accept_t* req; QUEUE* q; - uv__ipc_queue_item_t* item; + uv__ipc_xfer_queue_item_t* item; int err; if (server->ipc) { - if (QUEUE_EMPTY(&server->pipe.conn.pending_ipc_info.queue)) { + if (QUEUE_EMPTY(&server->pipe.conn.ipc_xfer_queue)) { /* No valid pending sockets. */ return WSAEWOULDBLOCK; } - q = QUEUE_HEAD(&server->pipe.conn.pending_ipc_info.queue); + q = QUEUE_HEAD(&server->pipe.conn.ipc_xfer_queue); QUEUE_REMOVE(q); - server->pipe.conn.pending_ipc_info.queue_len--; - item = QUEUE_DATA(q, uv__ipc_queue_item_t, member); + server->pipe.conn.ipc_xfer_queue_length--; + item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member); - err = uv_tcp_import((uv_tcp_t*)client, - &item->socket_info_ex, - item->tcp_connection); + err = uv__tcp_xfer_import( + (uv_tcp_t*) client, item->xfer_type, &item->xfer_info); if (err != 0) return err; @@ -881,8 +906,8 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { } else { pipe_client = (uv_pipe_t*)client; - /* Find a connection instance that has been connected, but not yet */ - /* accepted. */ + /* Find a connection instance that has been connected, but not yet + * accepted. */ req = server->pipe.serv.pending_accepts; if (!req) { @@ -900,7 +925,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { req->next_pending = NULL; req->pipeHandle = INVALID_HANDLE_VALUE; - if (!(server->flags & UV__HANDLE_CLOSING)) { + if (!(server->flags & UV_HANDLE_CLOSING)) { uv_pipe_queue_accept(loop, server, req, FALSE); } } @@ -945,74 +970,75 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { } -static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) { - int result; - DWORD bytes; - uv_read_t* req = (uv_read_t*) parameter; +static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* arg) { + uv_read_t* req = (uv_read_t*) arg; uv_pipe_t* handle = (uv_pipe_t*) req->data; uv_loop_t* loop = handle->loop; - HANDLE hThread = NULL; + volatile HANDLE* thread_ptr = &handle->pipe.conn.readfile_thread_handle; + CRITICAL_SECTION* lock = &handle->pipe.conn.readfile_thread_lock; + HANDLE thread; + DWORD bytes; DWORD err; - uv_mutex_t *m = &handle->pipe.conn.readfile_mutex; - assert(req != NULL); assert(req->type == UV_READ); assert(handle->type == UV_NAMED_PIPE); - if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { - uv_mutex_lock(m); /* mutex controls *setting* of readfile_thread */ - if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &hThread, - 0, FALSE, DUPLICATE_SAME_ACCESS)) { - handle->pipe.conn.readfile_thread = hThread; - } else { - hThread = NULL; - } - uv_mutex_unlock(m); + err = 0; + + /* Create a handle to the current thread. */ + if (!DuplicateHandle(GetCurrentProcess(), + GetCurrentThread(), + GetCurrentProcess(), + &thread, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + err = GetLastError(); + goto out1; } -restart_readfile: - if (handle->flags & UV_HANDLE_READING) { - result = ReadFile(handle->handle, - &uv_zero_, - 0, - &bytes, - NULL); - if (!result) { - err = GetLastError(); - if (err == ERROR_OPERATION_ABORTED && - handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { - if (handle->flags & UV_HANDLE_READING) { - /* just a brief break to do something else */ - handle->pipe.conn.readfile_thread = NULL; - /* resume after it is finished */ - uv_mutex_lock(m); - handle->pipe.conn.readfile_thread = hThread; - uv_mutex_unlock(m); - goto restart_readfile; - } else { - result = 1; /* successfully stopped reading */ - } - } - } + + /* The lock needs to be held when thread handle is modified. */ + EnterCriticalSection(lock); + if (*thread_ptr == INVALID_HANDLE_VALUE) { + /* uv__pipe_interrupt_read() cancelled reading before we got here. */ + err = ERROR_OPERATION_ABORTED; } else { - result = 1; /* successfully aborted read before it even started */ - } - if (hThread) { - assert(hThread == handle->pipe.conn.readfile_thread); - /* mutex does not control clearing readfile_thread */ - handle->pipe.conn.readfile_thread = NULL; - uv_mutex_lock(m); - /* only when we hold the mutex lock is it safe to - open or close the handle */ - CloseHandle(hThread); - uv_mutex_unlock(m); + /* Let main thread know which worker thread is doing the blocking read. */ + assert(*thread_ptr == NULL); + *thread_ptr = thread; } + LeaveCriticalSection(lock); - if (!result) { - SET_REQ_ERROR(req, err); - } + if (err) + goto out2; + + /* Block the thread until data is available on the pipe, or the read is + * cancelled. */ + if (!ReadFile(handle->handle, &uv_zero_, 0, &bytes, NULL)) + err = GetLastError(); + + /* Let the main thread know the worker is past the point of blocking. */ + assert(thread == *thread_ptr); + *thread_ptr = INVALID_HANDLE_VALUE; + + /* Briefly acquire the mutex. Since the main thread holds the lock while it + * is spinning trying to cancel this thread's I/O, we will block here until + * it stops doing that. */ + EnterCriticalSection(lock); + LeaveCriticalSection(lock); + +out2: + /* Close the handle to the current thread. */ + CloseHandle(thread); +out1: + /* Set request status and post a completion record to the IOCP. */ + if (err) + SET_REQ_ERROR(req, err); + else + SET_REQ_SUCCESS(req); POST_COMPLETION_FOR_REQ(loop, req); + return 0; } @@ -1094,6 +1120,7 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { req = &handle->read_req; if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + handle->pipe.conn.readfile_thread_handle = NULL; /* Reset cancellation. */ if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc, req, WT_EXECUTELONGFUNCTION)) { @@ -1161,8 +1188,8 @@ int uv_pipe_read_start(uv_pipe_t* handle, handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; - /* If reading was stopped and then started again, there could still be a */ - /* read request pending. */ + /* If reading was stopped and then started again, there could still be a read + * request pending. */ if (!(handle->flags & UV_HANDLE_READ_PENDING)) uv_pipe_queue_read(loop, handle); @@ -1218,154 +1245,111 @@ static void uv_queue_non_overlapped_write(uv_pipe_t* handle) { } -static int uv_pipe_write_impl(uv_loop_t* loop, - uv_write_t* req, - uv_pipe_t* handle, - const uv_buf_t bufs[], - unsigned int nbufs, - uv_stream_t* send_handle, - uv_write_cb cb) { - int err; - int result; - uv_tcp_t* tcp_send_handle; - uv_write_t* ipc_header_req = NULL; - uv_ipc_frame_uv_stream ipc_frame; +static int uv__build_coalesced_write_req(uv_write_t* user_req, + const uv_buf_t bufs[], + size_t nbufs, + uv_write_t** req_out, + uv_buf_t* write_buf_out) { + /* Pack into a single heap-allocated buffer: + * (a) a uv_write_t structure where libuv stores the actual state. + * (b) a pointer to the original uv_write_t. + * (c) data from all `bufs` entries. + */ + char* heap_buffer; + size_t heap_buffer_length, heap_buffer_offset; + uv__coalesced_write_t* coalesced_write_req; /* (a) + (b) */ + char* data_start; /* (c) */ + size_t data_length; + unsigned int i; + + /* Compute combined size of all combined buffers from `bufs`. */ + data_length = 0; + for (i = 0; i < nbufs; i++) + data_length += bufs[i].len; + + /* The total combined size of data buffers should not exceed UINT32_MAX, + * because WriteFile() won't accept buffers larger than that. */ + if (data_length > UINT32_MAX) + return WSAENOBUFS; /* Maps to UV_ENOBUFS. */ + + /* Compute heap buffer size. */ + heap_buffer_length = sizeof *coalesced_write_req + /* (a) + (b) */ + data_length; /* (c) */ + + /* Allocate buffer. */ + heap_buffer = uv__malloc(heap_buffer_length); + if (heap_buffer == NULL) + return ERROR_NOT_ENOUGH_MEMORY; /* Maps to UV_ENOMEM. */ + + /* Copy uv_write_t information to the buffer. */ + coalesced_write_req = (uv__coalesced_write_t*) heap_buffer; + coalesced_write_req->req = *user_req; /* copy (a) */ + coalesced_write_req->req.coalesced = 1; + coalesced_write_req->user_req = user_req; /* copy (b) */ + heap_buffer_offset = sizeof *coalesced_write_req; /* offset (a) + (b) */ + + /* Copy data buffers to the heap buffer. */ + data_start = &heap_buffer[heap_buffer_offset]; + for (i = 0; i < nbufs; i++) { + memcpy(&heap_buffer[heap_buffer_offset], + bufs[i].base, + bufs[i].len); /* copy (c) */ + heap_buffer_offset += bufs[i].len; /* offset (c) */ + } + assert(heap_buffer_offset == heap_buffer_length); + + /* Set out arguments and return. */ + *req_out = &coalesced_write_req->req; + *write_buf_out = uv_buf_init(data_start, (unsigned int) data_length); + return 0; +} - if (nbufs != 1 && (nbufs != 0 || !send_handle)) { - return ERROR_NOT_SUPPORTED; - } - /* Only TCP handles are supported for sharing. */ - if (send_handle && ((send_handle->type != UV_TCP) || - (!(send_handle->flags & UV_HANDLE_BOUND) && - !(send_handle->flags & UV_HANDLE_CONNECTION)))) { - return ERROR_NOT_SUPPORTED; - } +static int uv__pipe_write_data(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + size_t nbufs, + uv_stream_t* send_handle, + uv_write_cb cb, + int copy_always) { + int err; + int result; + uv_buf_t write_buf; assert(handle->handle != INVALID_HANDLE_VALUE); UV_REQ_INIT(req, UV_WRITE); req->handle = (uv_stream_t*) handle; + req->send_handle = send_handle; req->cb = cb; - req->ipc_header = 0; + /* Private fields. */ + req->coalesced = 0; req->event_handle = NULL; req->wait_handle = INVALID_HANDLE_VALUE; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); - - if (handle->ipc) { - assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); - ipc_frame.header.flags = 0; - - /* Use the IPC framing protocol. */ - if (send_handle) { - tcp_send_handle = (uv_tcp_t*)send_handle; - - if (handle->pipe.conn.ipc_pid == 0) { - handle->pipe.conn.ipc_pid = uv_current_pid(); - } - - err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid, - &ipc_frame.socket_info_ex.socket_info); - if (err) { - return err; - } - - ipc_frame.socket_info_ex.delayed_error = tcp_send_handle->delayed_error; - - ipc_frame.header.flags |= UV_IPC_TCP_SERVER; - - if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) { - ipc_frame.header.flags |= UV_IPC_TCP_CONNECTION; - } - } - - if (nbufs == 1) { - ipc_frame.header.flags |= UV_IPC_RAW_DATA; - ipc_frame.header.raw_data_length = bufs[0].len; - } - - /* - * Use the provided req if we're only doing a single write. - * If we're doing multiple writes, use ipc_header_write_req to do - * the first write, and then use the provided req for the second write. - */ - if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) { - ipc_header_req = req; - } else { - /* - * Try to use the preallocated write req if it's available. - * Otherwise allocate a new one. - */ - if (handle->pipe.conn.ipc_header_write_req.type != UV_WRITE) { - ipc_header_req = (uv_write_t*)&handle->pipe.conn.ipc_header_write_req; - } else { - ipc_header_req = (uv_write_t*)uv__malloc(sizeof(uv_write_t)); - if (!ipc_header_req) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - } - - UV_REQ_INIT(ipc_header_req, UV_WRITE); - ipc_header_req->handle = (uv_stream_t*) handle; - ipc_header_req->cb = NULL; - ipc_header_req->ipc_header = 1; - } - - /* Write the header or the whole frame. */ - memset(&ipc_header_req->u.io.overlapped, 0, - sizeof(ipc_header_req->u.io.overlapped)); - - /* Using overlapped IO, but wait for completion before returning. - This write is blocking because ipc_frame is on stack. */ - ipc_header_req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL); - if (!ipc_header_req->u.io.overlapped.hEvent) { - uv_fatal_error(GetLastError(), "CreateEvent"); - } - - result = WriteFile(handle->handle, - &ipc_frame, - ipc_frame.header.flags & UV_IPC_TCP_SERVER ? - sizeof(ipc_frame) : sizeof(ipc_frame.header), - NULL, - &ipc_header_req->u.io.overlapped); - if (!result && GetLastError() != ERROR_IO_PENDING) { - err = GetLastError(); - CloseHandle(ipc_header_req->u.io.overlapped.hEvent); + req->write_buffer = uv_null_buf_; + + if (nbufs == 0) { + /* Write empty buffer. */ + write_buf = uv_null_buf_; + } else if (nbufs == 1 && !copy_always) { + /* Write directly from bufs[0]. */ + write_buf = bufs[0]; + } else { + /* Coalesce all `bufs` into one big buffer. This also creates a new + * write-request structure that replaces the old one. */ + err = uv__build_coalesced_write_req(req, bufs, nbufs, &req, &write_buf); + if (err != 0) return err; - } - - if (!result) { - /* Request not completed immediately. Wait for it.*/ - if (WaitForSingleObject(ipc_header_req->u.io.overlapped.hEvent, INFINITE) != - WAIT_OBJECT_0) { - err = GetLastError(); - CloseHandle(ipc_header_req->u.io.overlapped.hEvent); - return err; - } - } - ipc_header_req->u.io.queued_bytes = 0; - CloseHandle(ipc_header_req->u.io.overlapped.hEvent); - ipc_header_req->u.io.overlapped.hEvent = NULL; - - REGISTER_HANDLE_REQ(loop, handle, ipc_header_req); - handle->reqs_pending++; - handle->stream.conn.write_reqs_pending++; - - /* If we don't have any raw data to write - we're done. */ - if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) { - return 0; - } } if ((handle->flags & (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) == (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) { DWORD bytes; - result = WriteFile(handle->handle, - bufs[0].base, - bufs[0].len, - &bytes, - NULL); + result = + WriteFile(handle->handle, write_buf.base, write_buf.len, &bytes, NULL); if (!result) { err = GetLastError(); @@ -1381,14 +1365,14 @@ static int uv_pipe_write_impl(uv_loop_t* loop, POST_COMPLETION_FOR_REQ(loop, req); return 0; } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { - req->write_buffer = bufs[0]; + req->write_buffer = write_buf; uv_insert_non_overlapped_write_req(handle, req); if (handle->stream.conn.write_reqs_pending == 0) { uv_queue_non_overlapped_write(handle); } /* Request queued by the kernel. */ - req->u.io.queued_bytes = bufs[0].len; + req->u.io.queued_bytes = write_buf.len; handle->write_queue_size += req->u.io.queued_bytes; } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) { /* Using overlapped IO, but wait for completion before returning */ @@ -1398,8 +1382,8 @@ static int uv_pipe_write_impl(uv_loop_t* loop, } result = WriteFile(handle->handle, - bufs[0].base, - bufs[0].len, + write_buf.base, + write_buf.len, NULL, &req->u.io.overlapped); @@ -1414,13 +1398,13 @@ static int uv_pipe_write_impl(uv_loop_t* loop, req->u.io.queued_bytes = 0; } else { /* Request queued by the kernel. */ - req->u.io.queued_bytes = bufs[0].len; + req->u.io.queued_bytes = write_buf.len; handle->write_queue_size += req->u.io.queued_bytes; if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) != WAIT_OBJECT_0) { err = GetLastError(); CloseHandle(req->u.io.overlapped.hEvent); - return uv_translate_sys_error(err); + return err; } } CloseHandle(req->u.io.overlapped.hEvent); @@ -1431,8 +1415,8 @@ static int uv_pipe_write_impl(uv_loop_t* loop, return 0; } else { result = WriteFile(handle->handle, - bufs[0].base, - bufs[0].len, + write_buf.base, + write_buf.len, NULL, &req->u.io.overlapped); @@ -1445,7 +1429,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, req->u.io.queued_bytes = 0; } else { /* Request queued by the kernel. */ - req->u.io.queued_bytes = bufs[0].len; + req->u.io.queued_bytes = write_buf.len; handle->write_queue_size += req->u.io.queued_bytes; } @@ -1470,35 +1454,145 @@ static int uv_pipe_write_impl(uv_loop_t* loop, } -int uv_pipe_write(uv_loop_t* loop, - uv_write_t* req, - uv_pipe_t* handle, - const uv_buf_t bufs[], - unsigned int nbufs, - uv_write_cb cb) { - return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, NULL, cb); +static DWORD uv__pipe_get_ipc_remote_pid(uv_pipe_t* handle) { + DWORD* pid = &handle->pipe.conn.ipc_remote_pid; + + /* If the both ends of the IPC pipe are owned by the same process, + * the remote end pid may not yet be set. If so, do it here. + * TODO: this is weird; it'd probably better to use a handshake. */ + if (*pid == 0) + *pid = GetCurrentProcessId(); + + return *pid; +} + + +int uv__pipe_write_ipc(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t data_bufs[], + size_t data_buf_count, + uv_stream_t* send_handle, + uv_write_cb cb) { + uv_buf_t stack_bufs[6]; + uv_buf_t* bufs; + size_t buf_count, buf_index; + uv__ipc_frame_header_t frame_header; + uv__ipc_socket_xfer_type_t xfer_type = UV__IPC_SOCKET_XFER_NONE; + uv__ipc_socket_xfer_info_t xfer_info; + uint64_t data_length; + size_t i; + int err; + + /* Compute the combined size of data buffers. */ + data_length = 0; + for (i = 0; i < data_buf_count; i++) + data_length += data_bufs[i].len; + if (data_length > UINT32_MAX) + return WSAENOBUFS; /* Maps to UV_ENOBUFS. */ + + /* Prepare the frame's socket xfer payload. */ + if (send_handle != NULL) { + uv_tcp_t* send_tcp_handle = (uv_tcp_t*) send_handle; + + /* Verify that `send_handle` it is indeed a tcp handle. */ + if (send_tcp_handle->type != UV_TCP) + return ERROR_NOT_SUPPORTED; + + /* Export the tcp handle. */ + err = uv__tcp_xfer_export(send_tcp_handle, + uv__pipe_get_ipc_remote_pid(handle), + &xfer_type, + &xfer_info); + if (err != 0) + return err; + } + + /* Compute the number of uv_buf_t's required. */ + buf_count = 1 + data_buf_count; /* Frame header and data buffers. */ + if (send_handle != NULL) + buf_count += 1; /* One extra for the socket xfer information. */ + + /* Use the on-stack buffer array if it is big enough; otherwise allocate + * space for it on the heap. */ + if (buf_count < ARRAY_SIZE(stack_bufs)) { + /* Use on-stack buffer array. */ + bufs = stack_bufs; + } else { + /* Use heap-allocated buffer array. */ + bufs = uv__calloc(buf_count, sizeof(uv_buf_t)); + if (bufs == NULL) + return ERROR_NOT_ENOUGH_MEMORY; /* Maps to UV_ENOMEM. */ + } + buf_index = 0; + + /* Initialize frame header and add it to the buffers list. */ + memset(&frame_header, 0, sizeof frame_header); + bufs[buf_index++] = uv_buf_init((char*) &frame_header, sizeof frame_header); + + if (send_handle != NULL) { + /* Add frame header flags. */ + switch (xfer_type) { + case UV__IPC_SOCKET_XFER_TCP_CONNECTION: + frame_header.flags |= UV__IPC_FRAME_HAS_SOCKET_XFER | + UV__IPC_FRAME_XFER_IS_TCP_CONNECTION; + break; + case UV__IPC_SOCKET_XFER_TCP_SERVER: + frame_header.flags |= UV__IPC_FRAME_HAS_SOCKET_XFER; + break; + default: + assert(0); // Unreachable. + } + /* Add xfer info buffer. */ + bufs[buf_index++] = uv_buf_init((char*) &xfer_info, sizeof xfer_info); + } + + if (data_length > 0) { + /* Update frame header. */ + frame_header.flags |= UV__IPC_FRAME_HAS_DATA; + frame_header.data_length = (uint32_t) data_length; + /* Add data buffers to buffers list. */ + for (i = 0; i < data_buf_count; i++) + bufs[buf_index++] = data_bufs[i]; + } + + /* Write buffers. We set the `always_copy` flag, so it is not a problem that + * some of the written data lives on the stack. */ + err = uv__pipe_write_data( + loop, req, handle, bufs, buf_count, send_handle, cb, 1); + + /* If we had to heap-allocate the bufs array, free it now. */ + if (bufs != stack_bufs) { + uv__free(bufs); + } + + return err; } -int uv_pipe_write2(uv_loop_t* loop, +int uv__pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, const uv_buf_t bufs[], - unsigned int nbufs, + size_t nbufs, uv_stream_t* send_handle, uv_write_cb cb) { - if (!handle->ipc) { - return WSAEINVAL; + if (handle->ipc) { + /* IPC pipe write: use framing protocol. */ + return uv__pipe_write_ipc(loop, req, handle, bufs, nbufs, send_handle, cb); + } else { + /* Non-IPC pipe write: put data on the wire directly. */ + assert(send_handle == NULL); + return uv__pipe_write_data( + loop, req, handle, bufs, nbufs, NULL, cb, 0); } - - return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, send_handle, cb); } static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, uv_buf_t buf) { - /* If there is an eof timer running, we don't need it any more, */ - /* so discard it. */ + /* If there is an eof timer running, we don't need it any more, so discard + * it. */ eof_timer_destroy(handle); handle->flags &= ~UV_HANDLE_READABLE; @@ -1510,8 +1604,8 @@ static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error, uv_buf_t buf) { - /* If there is an eof timer running, we don't need it any more, */ - /* so discard it. */ + /* If there is an eof timer running, we don't need it any more, so discard + * it. */ eof_timer_destroy(handle); uv_read_stop((uv_stream_t*) handle); @@ -1522,10 +1616,7 @@ static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error, static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle, int error, uv_buf_t buf) { - if (error == ERROR_OPERATION_ABORTED) { - /* do nothing (equivalent to EINTR) */ - } - else if (error == ERROR_BROKEN_PIPE) { + if (error == ERROR_BROKEN_PIPE) { uv_pipe_read_eof(loop, handle, buf); } else { uv_pipe_read_error(loop, handle, error, buf); @@ -1533,152 +1624,228 @@ static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle, } -void uv__pipe_insert_pending_socket(uv_pipe_t* handle, - uv__ipc_socket_info_ex* info, - int tcp_connection) { - uv__ipc_queue_item_t* item; +static void uv__pipe_queue_ipc_xfer_info( + uv_pipe_t* handle, + uv__ipc_socket_xfer_type_t xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info) { + uv__ipc_xfer_queue_item_t* item; - item = (uv__ipc_queue_item_t*) uv__malloc(sizeof(*item)); + item = (uv__ipc_xfer_queue_item_t*) uv__malloc(sizeof(*item)); if (item == NULL) uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex)); - item->tcp_connection = tcp_connection; - QUEUE_INSERT_TAIL(&handle->pipe.conn.pending_ipc_info.queue, &item->member); - handle->pipe.conn.pending_ipc_info.queue_len++; + item->xfer_type = xfer_type; + item->xfer_info = *xfer_info; + + QUEUE_INSERT_TAIL(&handle->pipe.conn.ipc_xfer_queue, &item->member); + handle->pipe.conn.ipc_xfer_queue_length++; +} + + +/* Read an exact number of bytes from a pipe. If an error or end-of-file is + * encountered before the requested number of bytes are read, an error is + * returned. */ +static int uv__pipe_read_exactly(HANDLE h, void* buffer, DWORD count) { + DWORD bytes_read, bytes_read_now; + + bytes_read = 0; + while (bytes_read < count) { + if (!ReadFile(h, + (char*) buffer + bytes_read, + count - bytes_read, + &bytes_read_now, + NULL)) { + return GetLastError(); + } + + bytes_read += bytes_read_now; + } + + assert(bytes_read == count); + return 0; } -void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, - uv_req_t* req) { - DWORD bytes, avail; +static DWORD uv__pipe_read_data(uv_loop_t* loop, + uv_pipe_t* handle, + DWORD suggested_bytes, + DWORD max_bytes) { + DWORD bytes_read; uv_buf_t buf; - uv_ipc_frame_uv_stream ipc_frame; + /* Ask the user for a buffer to read data into. */ + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, suggested_bytes, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + return 0; /* Break out of read loop. */ + } + + /* Ensure we read at most the smaller of: + * (a) the length of the user-allocated buffer. + * (b) the maximum data length as specified by the `max_bytes` argument. + */ + if (max_bytes > buf.len) + max_bytes = buf.len; + + /* Read into the user buffer. */ + if (!ReadFile(handle->handle, buf.base, max_bytes, &bytes_read, NULL)) { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf); + return 0; /* Break out of read loop. */ + } + + /* Call the read callback. */ + handle->read_cb((uv_stream_t*) handle, bytes_read, &buf); + + return bytes_read; +} + + +static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) { + uint32_t* data_remaining = &handle->pipe.conn.ipc_data_frame.payload_remaining; + int err; + + if (*data_remaining > 0) { + /* Read frame data payload. */ + DWORD bytes_read = + uv__pipe_read_data(loop, handle, *data_remaining, *data_remaining); + *data_remaining -= bytes_read; + return bytes_read; + + } else { + /* Start of a new IPC frame. */ + uv__ipc_frame_header_t frame_header; + uint32_t xfer_flags; + uv__ipc_socket_xfer_type_t xfer_type; + uv__ipc_socket_xfer_info_t xfer_info; + + /* Read the IPC frame header. */ + err = uv__pipe_read_exactly( + handle->handle, &frame_header, sizeof frame_header); + if (err) + goto error; + + /* Validate that flags are valid. */ + if ((frame_header.flags & ~UV__IPC_FRAME_VALID_FLAGS) != 0) + goto invalid; + /* Validate that reserved2 is zero. */ + if (frame_header.reserved2 != 0) + goto invalid; + + /* Parse xfer flags. */ + xfer_flags = frame_header.flags & UV__IPC_FRAME_XFER_FLAGS; + if (xfer_flags & UV__IPC_FRAME_HAS_SOCKET_XFER) { + /* Socket coming -- determine the type. */ + xfer_type = xfer_flags & UV__IPC_FRAME_XFER_IS_TCP_CONNECTION + ? UV__IPC_SOCKET_XFER_TCP_CONNECTION + : UV__IPC_SOCKET_XFER_TCP_SERVER; + } else if (xfer_flags == 0) { + /* No socket. */ + xfer_type = UV__IPC_SOCKET_XFER_NONE; + } else { + /* Invalid flags. */ + goto invalid; + } + + /* Parse data frame information. */ + if (frame_header.flags & UV__IPC_FRAME_HAS_DATA) { + *data_remaining = frame_header.data_length; + } else if (frame_header.data_length != 0) { + /* Data length greater than zero but data flag not set -- invalid. */ + goto invalid; + } + + /* If no socket xfer info follows, return here. Data will be read in a + * subsequent invocation of uv__pipe_read_ipc(). */ + if (xfer_type == UV__IPC_SOCKET_XFER_NONE) + return sizeof frame_header; /* Number of bytes read. */ + + /* Read transferred socket information. */ + err = uv__pipe_read_exactly(handle->handle, &xfer_info, sizeof xfer_info); + if (err) + goto error; + + /* Store the pending socket info. */ + uv__pipe_queue_ipc_xfer_info(handle, xfer_type, &xfer_info); + + /* Return number of bytes read. */ + return sizeof frame_header + sizeof xfer_info; + } + +invalid: + /* Invalid frame. */ + err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */ + +error: + uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_); + return 0; /* Break out of read loop. */ +} + + +void uv_process_pipe_read_req(uv_loop_t* loop, + uv_pipe_t* handle, + uv_req_t* req) { assert(handle->type == UV_NAMED_PIPE); - handle->flags &= ~UV_HANDLE_READ_PENDING; + handle->flags &= ~(UV_HANDLE_READ_PENDING | UV_HANDLE_CANCELLATION_PENDING); + DECREASE_PENDING_REQ_COUNT(handle); eof_timer_stop(handle); - if (!REQ_SUCCESS(req)) { - /* An error occurred doing the 0-read. */ - if (handle->flags & UV_HANDLE_READING) { - uv_pipe_read_error_or_eof(loop, - handle, - GET_REQ_ERROR(req), - uv_null_buf_); - } - } else { - /* Do non-blocking reads until the buffer is empty */ - while (handle->flags & UV_HANDLE_READING) { - if (!PeekNamedPipe(handle->handle, - NULL, - 0, - NULL, - &avail, - NULL)) { - uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_); - break; - } + /* At this point, we're done with bookkeeping. If the user has stopped + * reading the pipe in the meantime, there is nothing left to do, since there + * is no callback that we can call. */ + if (!(handle->flags & UV_HANDLE_READING)) + return; - if (avail == 0) { - /* There is nothing to read after all. */ - break; - } + if (!REQ_SUCCESS(req)) { + /* An error occurred doing the zero-read. */ + DWORD err = GET_REQ_ERROR(req); - if (handle->ipc) { - /* Use the IPC framing protocol to read the incoming data. */ - if (handle->pipe.conn.remaining_ipc_rawdata_bytes == 0) { - /* We're reading a new frame. First, read the header. */ - assert(avail >= sizeof(ipc_frame.header)); - - if (!ReadFile(handle->handle, - &ipc_frame.header, - sizeof(ipc_frame.header), - &bytes, - NULL)) { - uv_pipe_read_error_or_eof(loop, handle, GetLastError(), - uv_null_buf_); - break; - } - - assert(bytes == sizeof(ipc_frame.header)); - assert(ipc_frame.header.flags <= (UV_IPC_TCP_SERVER | UV_IPC_RAW_DATA | - UV_IPC_TCP_CONNECTION)); - - if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) { - assert(avail - sizeof(ipc_frame.header) >= - sizeof(ipc_frame.socket_info_ex)); - - /* Read the TCP socket info. */ - if (!ReadFile(handle->handle, - &ipc_frame.socket_info_ex, - sizeof(ipc_frame) - sizeof(ipc_frame.header), - &bytes, - NULL)) { - uv_pipe_read_error_or_eof(loop, handle, GetLastError(), - uv_null_buf_); - break; - } - - assert(bytes == sizeof(ipc_frame) - sizeof(ipc_frame.header)); - - /* Store the pending socket info. */ - uv__pipe_insert_pending_socket( - handle, - &ipc_frame.socket_info_ex, - ipc_frame.header.flags & UV_IPC_TCP_CONNECTION); - } - - if (ipc_frame.header.flags & UV_IPC_RAW_DATA) { - handle->pipe.conn.remaining_ipc_rawdata_bytes = - ipc_frame.header.raw_data_length; - continue; - } - } else { - avail = min(avail, (DWORD)handle->pipe.conn.remaining_ipc_rawdata_bytes); - } - } + /* If the read was cancelled by uv__pipe_interrupt_read(), the request may + * indicate an ERROR_OPERATION_ABORTED error. This error isn't relevant to + * the user; we'll start a new zero-read at the end of this function. */ + if (err != ERROR_OPERATION_ABORTED) + uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_); - buf = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, avail, &buf); - if (buf.base == NULL || buf.len == 0) { - handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + } else { + /* The zero-read completed without error, indicating there is data + * available in the kernel buffer. */ + DWORD avail; + + /* Get the number of bytes available. */ + avail = 0; + if (!PeekNamedPipe(handle->handle, NULL, 0, NULL, &avail, NULL)) + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_); + + /* Read until we've either read all the bytes available, or the 'reading' + * flag is cleared. */ + while (avail > 0 && handle->flags & UV_HANDLE_READING) { + /* Depending on the type of pipe, read either IPC frames or raw data. */ + DWORD bytes_read = + handle->ipc ? uv__pipe_read_ipc(loop, handle) + : uv__pipe_read_data(loop, handle, avail, (DWORD) -1); + + /* If no bytes were read, treat this as an indication that an error + * occurred, and break out of the read loop. */ + if (bytes_read == 0) break; - } - assert(buf.base != NULL); - - if (ReadFile(handle->handle, - buf.base, - min(buf.len, avail), - &bytes, - NULL)) { - /* Successful read */ - if (handle->ipc) { - assert(handle->pipe.conn.remaining_ipc_rawdata_bytes >= bytes); - handle->pipe.conn.remaining_ipc_rawdata_bytes = - handle->pipe.conn.remaining_ipc_rawdata_bytes - bytes; - } - handle->read_cb((uv_stream_t*)handle, bytes, &buf); - /* Read again only if bytes == buf.len */ - if (bytes <= buf.len) { - break; - } - } else { - uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf); + /* It is possible that more bytes were read than we thought were + * available. To prevent `avail` from underflowing, break out of the loop + * if this is the case. */ + if (bytes_read > avail) break; - } - } - /* Post another 0-read if still reading and not closing. */ - if ((handle->flags & UV_HANDLE_READING) && - !(handle->flags & UV_HANDLE_READ_PENDING)) { - uv_pipe_queue_read(loop, handle); + /* Recompute the number of bytes available. */ + avail -= bytes_read; } } - DECREASE_PENDING_REQ_COUNT(handle); + /* Start another zero-read request if necessary. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_pipe_queue_read(loop, handle); + } } @@ -1704,17 +1871,19 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, } } - if (req->ipc_header) { - if (req == &handle->pipe.conn.ipc_header_write_req) { - req->type = UV_UNKNOWN_REQ; - } else { - uv__free(req); - } - } else { - if (req->cb) { - err = GET_REQ_ERROR(req); - req->cb(req, uv_translate_sys_error(err)); - } + err = GET_REQ_ERROR(req); + + /* If this was a coalesced write, extract pointer to the user_provided + * uv_write_t structure so we can pass the expected pointer to the callback, + * then free the heap-allocated write req. */ + if (req->coalesced) { + uv__coalesced_write_t* coalesced_write = + container_of(req, uv__coalesced_write_t, req); + req = coalesced_write->user_req; + uv__free(coalesced_write); + } + if (req->cb) { + req->cb(req, uv_translate_sys_error(err)); } handle->stream.conn.write_reqs_pending--; @@ -1740,7 +1909,7 @@ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, assert(handle->type == UV_NAMED_PIPE); - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { /* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */ assert(req->pipeHandle == INVALID_HANDLE_VALUE); DECREASE_PENDING_REQ_COUNT(handle); @@ -1760,7 +1929,7 @@ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, CloseHandle(req->pipeHandle); req->pipeHandle = INVALID_HANDLE_VALUE; } - if (!(handle->flags & UV__HANDLE_CLOSING)) { + if (!(handle->flags & UV_HANDLE_CLOSING)) { uv_pipe_queue_accept(loop, handle, req, FALSE); } } @@ -1798,19 +1967,19 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, UNREGISTER_HANDLE_REQ(loop, handle, req); if (handle->flags & UV_HANDLE_READABLE) { - /* Initialize and optionally start the eof timer. Only do this if the */ - /* pipe is readable and we haven't seen EOF come in ourselves. */ + /* Initialize and optionally start the eof timer. Only do this if the pipe + * is readable and we haven't seen EOF come in ourselves. */ eof_timer_init(handle); - /* If reading start the timer right now. */ - /* Otherwise uv_pipe_queue_read will start it. */ + /* If reading start the timer right now. Otherwise uv_pipe_queue_read will + * start it. */ if (handle->flags & UV_HANDLE_READ_PENDING) { eof_timer_start(handle); } } else { - /* This pipe is not readable. We can just close it to let the other end */ - /* know that we're done writing. */ + /* This pipe is not readable. We can just close it to let the other end + * know that we're done writing. */ close_pipe(handle); } @@ -1861,17 +2030,16 @@ static void eof_timer_cb(uv_timer_t* timer) { assert(pipe->type == UV_NAMED_PIPE); - /* This should always be true, since we start the timer only */ - /* in uv_pipe_queue_read after successfully calling ReadFile, */ - /* or in uv_process_pipe_shutdown_req if a read is pending, */ - /* and we always immediately stop the timer in */ - /* uv_process_pipe_read_req. */ + /* This should always be true, since we start the timer only in + * uv_pipe_queue_read after successfully calling ReadFile, or in + * uv_process_pipe_shutdown_req if a read is pending, and we always + * immediately stop the timer in uv_process_pipe_read_req. */ assert(pipe->flags & UV_HANDLE_READ_PENDING); - /* If there are many packets coming off the iocp then the timer callback */ - /* may be called before the read request is coming off the queue. */ - /* Therefore we check here if the read request has completed but will */ - /* be processed later. */ + /* If there are many packets coming off the iocp then the timer callback may + * be called before the read request is coming off the queue. Therefore we + * check here if the read request has completed but will be processed later. + */ if ((pipe->flags & UV_HANDLE_READ_PENDING) && HasOverlappedIoCompleted(&pipe->read_req.u.io.overlapped)) { return; @@ -1880,12 +2048,12 @@ static void eof_timer_cb(uv_timer_t* timer) { /* Force both ends off the pipe. */ close_pipe(pipe); - /* Stop reading, so the pending read that is going to fail will */ - /* not be reported to the user. */ + /* Stop reading, so the pending read that is going to fail will not be + * reported to the user. */ uv_read_stop((uv_stream_t*) pipe); - /* Report the eof and update flags. This will get reported even if the */ - /* user stopped reading in the meantime. TODO: is that okay? */ + /* Report the eof and update flags. This will get reported even if the user + * stopped reading in the meantime. TODO: is that okay? */ uv_pipe_read_eof(loop, pipe, uv_null_buf_); } @@ -1972,8 +2140,8 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { if (pipe->ipc) { assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); - pipe->pipe.conn.ipc_pid = uv_os_getppid(); - assert(pipe->pipe.conn.ipc_pid != -1); + pipe->pipe.conn.ipc_remote_pid = uv_os_getppid(); + assert(pipe->pipe.conn.ipc_remote_pid != -1); } return 0; } @@ -1998,7 +2166,15 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) return UV_EINVAL; } - uv__pipe_pause_read((uv_pipe_t*)handle); /* cast away const warning */ + /* NtQueryInformationFile will block if another thread is performing a + * blocking operation on the queried handle. If the pipe handle is + * synchronous, there may be a worker thread currently calling ReadFile() on + * the pipe handle, which could cause a deadlock. To avoid this, interrupt + * the read. */ + if (handle->flags & UV_HANDLE_CONNECTION && + handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + uv__pipe_interrupt_read((uv_pipe_t*) handle); /* cast away const warning */ + } nt_status = pNtQueryInformationFile(handle->handle, &io_status, @@ -2089,7 +2265,6 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) uv__free(name_info); cleanup: - uv__pipe_unpause_read((uv_pipe_t*)handle); /* cast away const warning */ return err; } @@ -2097,7 +2272,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) int uv_pipe_pending_count(uv_pipe_t* handle) { if (!handle->ipc) return 0; - return handle->pipe.conn.pending_ipc_info.queue_len; + return handle->pipe.conn.ipc_xfer_queue_length; } @@ -2130,7 +2305,7 @@ int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) { uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { if (!handle->ipc) return UV_UNKNOWN_HANDLE; - if (handle->pipe.conn.pending_ipc_info.queue_len == 0) + if (handle->pipe.conn.ipc_xfer_queue_length == 0) return UV_UNKNOWN_HANDLE; else return UV_TCP; @@ -2172,7 +2347,7 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { error = GetLastError(); goto clean_sid; } - + memset(&ea, 0, sizeof(EXPLICIT_ACCESS)); if (mode & UV_READABLE) ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c index a648ba711d569a..77eb071c85a338 100644 --- a/deps/uv/src/win/poll.c +++ b/deps/uv/src/win/poll.c @@ -91,16 +91,16 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { handle->mask_events_1 = handle->events; handle->mask_events_2 = 0; } else { - /* Just wait until there's an unsubmitted req. */ - /* This will happen almost immediately as one of the 2 outstanding */ - /* requests is about to return. When this happens, */ - /* uv__fast_poll_process_poll_req will be called, and the pending */ - /* events, if needed, will be processed in a subsequent request. */ + /* Just wait until there's an unsubmitted req. This will happen almost + * immediately as one of the 2 outstanding requests is about to return. + * When this happens, uv__fast_poll_process_poll_req will be called, and + * the pending events, if needed, will be processed in a subsequent + * request. */ return; } - /* Setting Exclusive to TRUE makes the other poll request return if there */ - /* is any. */ + /* Setting Exclusive to TRUE makes the other poll request return if there is + * any. */ afd_poll_info->Exclusive = TRUE; afd_poll_info->NumberOfHandles = 1; afd_poll_info->Timeout.QuadPart = INT64_MAX; @@ -218,7 +218,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, if ((handle->events & ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) { uv__fast_poll_submit_poll_req(loop, handle); - } else if ((handle->flags & UV__HANDLE_CLOSING) && + } else if ((handle->flags & UV_HANDLE_CLOSING) && handle->submitted_events_1 == 0 && handle->submitted_events_2 == 0) { uv_want_endgame(loop, (uv_handle_t*) handle); @@ -228,7 +228,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { assert(handle->type == UV_POLL); - assert(!(handle->flags & UV__HANDLE_CLOSING)); + assert(!(handle->flags & UV_HANDLE_CLOSING)); assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); handle->events = events; @@ -257,8 +257,8 @@ static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) { uv_want_endgame(loop, (uv_handle_t*) handle); return 0; } else { - /* Cancel outstanding poll requests by executing another, unique poll */ - /* request that forces the outstanding ones to return. */ + /* Cancel outstanding poll requests by executing another, unique poll + * request that forces the outstanding ones to return. */ return uv__fast_poll_cancel_poll_req(loop, handle); } } @@ -316,9 +316,8 @@ static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop, return INVALID_SOCKET; } - /* If we didn't (try) to create a peer socket yet, try to make one. Don't */ - /* try again if the peer socket creation failed earlier for the same */ - /* protocol. */ + /* If we didn't (try) to create a peer socket yet, try to make one. Don't try + * again if the peer socket creation failed earlier for the same protocol. */ peer_socket = loop->poll_peer_sockets[index]; if (peer_socket == 0) { peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info); @@ -357,8 +356,8 @@ static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) { efds.fd_count = 0; } - /* Make the select() time out after 3 minutes. If select() hangs because */ - /* the user closed the socket, we will at least not hang indefinitely. */ + /* Make the select() time out after 3 minutes. If select() hangs because the + * user closed the socket, we will at least not hang indefinitely. */ timeout.tv_sec = 3 * 60; timeout.tv_usec = 0; @@ -462,7 +461,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, if ((handle->events & ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) { uv__slow_poll_submit_poll_req(loop, handle); - } else if ((handle->flags & UV__HANDLE_CLOSING) && + } else if ((handle->flags & UV_HANDLE_CLOSING) && handle->submitted_events_1 == 0 && handle->submitted_events_2 == 0) { uv_want_endgame(loop, (uv_handle_t*) handle); @@ -472,7 +471,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { assert(handle->type == UV_POLL); - assert(!(handle->flags & UV__HANDLE_CLOSING)); + assert(!(handle->flags & UV_HANDLE_CLOSING)); assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); handle->events = events; @@ -522,10 +521,10 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) return uv_translate_sys_error(WSAGetLastError()); - /* Try to obtain a base handle for the socket. This increases this chances */ - /* that we find an AFD handle and are able to use the fast poll mechanism. */ - /* This will always fail on windows XP/2k3, since they don't support the */ - /* SIO_BASE_HANDLE ioctl. */ +/* Try to obtain a base handle for the socket. This increases this chances that + * we find an AFD handle and are able to use the fast poll mechanism. This will + * always fail on windows XP/2k3, since they don't support the. SIO_BASE_HANDLE + * ioctl. */ #ifndef NDEBUG base_socket = INVALID_SOCKET; #endif @@ -557,9 +556,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, return uv_translate_sys_error(WSAGetLastError()); } - /* Get the peer socket that is needed to enable fast poll. If the returned */ - /* value is NULL, the protocol is not implemented by MSAFD and we'll have */ - /* to use slow mode. */ + /* Get the peer socket that is needed to enable fast poll. If the returned + * value is NULL, the protocol is not implemented by MSAFD and we'll have to + * use slow mode. */ peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info); if (peer_socket != INVALID_SOCKET) { @@ -634,7 +633,7 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) { void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) { - assert(handle->flags & UV__HANDLE_CLOSING); + assert(handle->flags & UV_HANDLE_CLOSING); assert(!(handle->flags & UV_HANDLE_CLOSED)); assert(handle->submitted_events_1 == 0); diff --git a/deps/uv/src/win/process-stdio.c b/deps/uv/src/win/process-stdio.c index 032e30935cc194..355d6188088b4a 100644 --- a/deps/uv/src/win/process-stdio.c +++ b/deps/uv/src/win/process-stdio.c @@ -103,12 +103,12 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, 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. */ + /* 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; } @@ -131,12 +131,13 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, 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, - server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0, + overlap ? FILE_FLAG_OVERLAPPED : 0, NULL); if (child_pipe == INVALID_HANDLE_VALUE) { err = GetLastError(); @@ -159,8 +160,8 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, } #endif - /* Do a blocking ConnectNamedPipe. This should not block because we have */ - /* both ends of the pipe created. */ + /* 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(); @@ -194,11 +195,11 @@ static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) { HANDLE current_process; - /* _get_osfhandle will sometimes return -2 in case of an error. This seems */ - /* to happen when fd <= 2 and the process' corresponding stdio handle is */ - /* set to NULL. Unfortunately DuplicateHandle will happily duplicate */ - /* (HANDLE) -2, so this situation goes unnoticed until someone tries to */ - /* use the duplicate. Therefore we filter out known-invalid handles here. */ + /* _get_osfhandle will sometimes return -2 in case of an error. This seems to + * happen when fd <= 2 and the process' corresponding stdio handle is set to + * NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so + * this situation goes unnoticed until someone tries to use the duplicate. + * Therefore we filter out known-invalid handles here. */ if (handle == INVALID_HANDLE_VALUE || handle == NULL || handle == (HANDLE) -2) { @@ -284,8 +285,8 @@ int uv__stdio_create(uv_loop_t* loop, return ERROR_OUTOFMEMORY; } - /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */ - /* clean up on failure. */ + /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean + * up on failure. */ CHILD_STDIO_COUNT(buffer) = count; for (i = 0; i < count; i++) { CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; @@ -303,12 +304,12 @@ int uv__stdio_create(uv_loop_t* loop, switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM)) { case UV_IGNORE: - /* Starting a process with no stdin/stout/stderr can confuse it. */ - /* So no matter what the user specified, we make sure the first */ - /* three FDs are always open in their typical modes, e.g. stdin */ - /* be readable and stdout/err should be writable. For FDs > 2, don't */ - /* do anything - all handles in the stdio buffer are initialized with */ - /* INVALID_HANDLE_VALUE, which should be okay. */ + /* Starting a process with no stdin/stout/stderr can confuse it. So no + * matter what the user specified, we make sure the first three FDs are + * always open in their typical modes, e. g. stdin be readable and + * stdout/err should be writable. For FDs > 2, don't do anything - all + * handles in the stdio buffer are initialized with. + * INVALID_HANDLE_VALUE, which should be okay. */ if (i <= 2) { DWORD access = (i == 0) ? FILE_GENERIC_READ : FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES; @@ -323,14 +324,14 @@ int uv__stdio_create(uv_loop_t* loop, break; case UV_CREATE_PIPE: { - /* Create a pair of two connected pipe ends; one end is turned into */ - /* an uv_pipe_t for use by the parent. The other one is given to */ - /* the child. */ + /* Create a pair of two connected pipe ends; one end is turned into an + * uv_pipe_t for use by the parent. The other one is given to the + * child. */ uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream; HANDLE child_pipe = INVALID_HANDLE_VALUE; - /* Create a new, connected pipe pair. stdio[i].stream should point */ - /* to an uninitialized, but not connected pipe handle. */ + /* Create a new, connected pipe pair. stdio[i]. stream should point to + * an uninitialized, but not connected pipe handle. */ assert(fdopt.data.stream->type == UV_NAMED_PIPE); assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION)); assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER)); @@ -354,8 +355,8 @@ int uv__stdio_create(uv_loop_t* loop, /* Make an inheritable duplicate of the handle. */ err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle); if (err) { - /* If fdopt.data.fd is not valid and fd fd <= 2, then ignore the */ - /* error. */ + /* If fdopt. data. fd is not valid and fd <= 2, then ignore the + * error. */ if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) { CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE; @@ -418,8 +419,8 @@ int uv__stdio_create(uv_loop_t* loop, if (stream_handle == NULL || stream_handle == INVALID_HANDLE_VALUE) { - /* The handle is already closed, or not yet created, or the */ - /* stream type is not supported. */ + /* The handle is already closed, or not yet created, or the stream + * type is not supported. */ err = ERROR_NOT_SUPPORTED; goto error; } diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 7523522217392e..b47f203e9d9c7f 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -360,8 +360,8 @@ static WCHAR* search_path(const WCHAR *file, return NULL; } - /* Find the start of the filename so we can split the directory from the */ - /* name. */ + /* Find the start of the filename so we can split the directory from the + * name. */ for (file_name_start = (WCHAR*)file + file_len; file_name_start > file && file_name_start[-1] != L'\\' @@ -556,8 +556,8 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { arg_count++; } - /* Adjust for potential quotes. Also assume the worst-case scenario */ - /* that every character needs escaping, so we need twice as much space. */ + /* Adjust for potential quotes. Also assume the worst-case scenario that + * every character needs escaping, so we need twice as much space. */ dst_len = dst_len * 2 + arg_count * 2; /* Allocate buffer for the final command line. */ @@ -831,8 +831,13 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { */ static WCHAR* find_path(WCHAR *env) { for (; env != NULL && *env != 0; env += wcslen(env) + 1) { - if (wcsncmp(env, L"PATH=", 5) == 0) + if ((env[0] == L'P' || env[0] == L'p') && + (env[1] == L'A' || env[1] == L'a') && + (env[2] == L'T' || env[2] == L't') && + (env[3] == L'H' || env[3] == L'h') && + (env[4] == L'=')) { return &env[5]; + } } return NULL; @@ -865,9 +870,9 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { assert(handle->exit_cb_pending); handle->exit_cb_pending = 0; - /* If we're closing, don't call the exit callback. Just schedule a close */ - /* callback now. */ - if (handle->flags & UV__HANDLE_CLOSING) { + /* If we're closing, don't call the exit callback. Just schedule a close + * callback now. */ + if (handle->flags & UV_HANDLE_CLOSING) { uv_want_endgame(loop, (uv_handle_t*) handle); return; } @@ -878,14 +883,14 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { handle->wait_handle = INVALID_HANDLE_VALUE; } - /* Set the handle to inactive: no callbacks will be made after the exit */ - /* callback.*/ + /* Set the handle to inactive: no callbacks will be made after the exit + * callback. */ uv__handle_stop(handle); if (GetExitCodeProcess(handle->process_handle, &status)) { exit_code = status; } else { - /* Unable to to obtain the exit code. This should never happen. */ + /* Unable to obtain the exit code. This should never happen. */ exit_code = uv_translate_sys_error(GetLastError()); } @@ -900,8 +905,8 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { uv__handle_closing(handle); if (handle->wait_handle != INVALID_HANDLE_VALUE) { - /* This blocks until either the wait was cancelled, or the callback has */ - /* completed. */ + /* This blocks until either the wait was cancelled, or the callback has + * completed. */ BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE); if (!r) { /* This should never happen, and if it happens, we can't recover... */ @@ -919,7 +924,7 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) { assert(!handle->exit_cb_pending); - assert(handle->flags & UV__HANDLE_CLOSING); + assert(handle->flags & UV_HANDLE_CLOSING); assert(!(handle->flags & UV_HANDLE_CLOSED)); /* Clean-up the process handle. */ @@ -1104,14 +1109,13 @@ int uv_spawn(uv_loop_t* loop, goto done; } - /* Spawn succeeded */ - /* Beyond this point, failure is reported asynchronously. */ + /* Spawn succeeded. Beyond this point, failure is reported asynchronously. */ process->process_handle = info.hProcess; process->pid = info.dwProcessId; - /* If the process isn't spawned as detached, assign to the global job */ - /* object so windows will kill it when the parent process dies. */ + /* If the process isn't spawned as detached, assign to the global job object + * so windows will kill it when the parent process dies. */ if (!(options->flags & UV_PROCESS_DETACHED)) { uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle); @@ -1138,7 +1142,8 @@ int uv_spawn(uv_loop_t* loop, if (fdopt->flags & UV_CREATE_PIPE && fdopt->data.stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) fdopt->data.stream)->ipc) { - ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId; + ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_remote_pid = + info.dwProcessId; } } @@ -1154,8 +1159,8 @@ int uv_spawn(uv_loop_t* loop, assert(!err); - /* Make the handle active. It will remain active until the exit callback */ - /* is made or the handle is closed, whichever happens first. */ + /* Make the handle active. It will remain active until the exit callback is + * made or the handle is closed, whichever happens first. */ uv__handle_start(process); /* Cleanup, whether we succeeded or failed. */ @@ -1186,16 +1191,16 @@ static int uv__kill(HANDLE process_handle, int signum) { case SIGTERM: case SIGKILL: case SIGINT: { - /* Unconditionally terminate the process. On Windows, killed processes */ - /* normally return 1. */ + /* Unconditionally terminate the process. On Windows, killed processes + * normally return 1. */ DWORD status; int err; if (TerminateProcess(process_handle, 1)) return 0; - /* If the process already exited before TerminateProcess was called, */ - /* TerminateProcess will fail with ERROR_ACCESS_DENIED. */ + /* If the process already exited before TerminateProcess was called,. + * TerminateProcess will fail with ERROR_ACCESS_DENIED. */ err = GetLastError(); if (err == ERROR_ACCESS_DENIED && GetExitCodeProcess(process_handle, &status) && diff --git a/deps/uv/src/win/req.c b/deps/uv/src/win/req.c deleted file mode 100644 index 111cc5e28936fc..00000000000000 --- a/deps/uv/src/win/req.c +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include - -#include "uv.h" -#include "internal.h" diff --git a/deps/uv/src/win/signal.c b/deps/uv/src/win/signal.c index a174da1f760d62..3d0b8a35b93ace 100644 --- a/deps/uv/src/win/signal.c +++ b/deps/uv/src/win/signal.c @@ -47,13 +47,13 @@ void uv_signals_init(void) { static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { - /* Compare signums first so all watchers with the same signnum end up */ - /* adjacent. */ + /* Compare signums first so all watchers with the same signnum end up + * adjacent. */ if (w1->signum < w2->signum) return -1; if (w1->signum > w2->signum) return 1; - /* Sort by loop pointer, so we can easily look up the first item after */ - /* { .signum = x, .loop = NULL } */ + /* Sort by loop pointer, so we can easily look up the first item after + * { .signum = x, .loop = NULL }. */ if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1; if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1; @@ -90,7 +90,7 @@ int uv__signal_dispatch(int signum) { unsigned long previous = InterlockedExchange( (volatile LONG*) &handle->pending_signum, signum); - if (handle->flags & UV__SIGNAL_ONE_SHOT_DISPATCHED) + if (handle->flags & UV_SIGNAL_ONE_SHOT_DISPATCHED) continue; if (!previous) { @@ -98,8 +98,8 @@ int uv__signal_dispatch(int signum) { } dispatched = 1; - if (handle->flags & UV__SIGNAL_ONE_SHOT) - handle->flags |= UV__SIGNAL_ONE_SHOT_DISPATCHED; + if (handle->flags & UV_SIGNAL_ONE_SHOT) + handle->flags |= UV_SIGNAL_ONE_SHOT_DISPATCHED; } LeaveCriticalSection(&uv__signal_lock); @@ -118,10 +118,10 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) { case CTRL_CLOSE_EVENT: if (uv__signal_dispatch(SIGHUP)) { - /* Windows will terminate the process after the control handler */ - /* returns. After that it will just terminate our process. Therefore */ - /* block the signal handler so the main loop has some time to pick */ - /* up the signal and do something for a few seconds. */ + /* Windows will terminate the process after the control handler + * returns. After that it will just terminate our process. Therefore + * block the signal handler so the main loop has some time to pick up + * the signal and do something for a few seconds. */ Sleep(INFINITE); return TRUE; } @@ -129,8 +129,8 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: - /* These signals are only sent to services. Services have their own */ - /* notification mechanism, so there's no point in handling these. */ + /* These signals are only sent to services. Services have their own + * notification mechanism, so there's no point in handling these. */ default: /* We don't handle these. */ @@ -193,10 +193,10 @@ int uv__signal_start(uv_signal_t* handle, if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG)) return UV_EINVAL; - /* Short circuit: if the signal watcher is already watching {signum} don't */ - /* go through the process of deregistering and registering the handler. */ - /* Additionally, this avoids pending signals getting lost in the (small) */ - /* time frame that handle->signum == 0. */ + /* Short circuit: if the signal watcher is already watching {signum} don't go + * through the process of deregistering and registering the handler. + * Additionally, this avoids pending signals getting lost in the (small) time + * frame that handle->signum == 0. */ if (signum == handle->signum) { handle->signal_cb = signal_cb; return 0; @@ -213,7 +213,7 @@ int uv__signal_start(uv_signal_t* handle, handle->signum = signum; if (oneshot) - handle->flags |= UV__SIGNAL_ONE_SHOT; + handle->flags |= UV_SIGNAL_ONE_SHOT; RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle); @@ -237,16 +237,16 @@ void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, (volatile LONG*) &handle->pending_signum, 0); assert(dispatched_signum != 0); - /* Check if the pending signal equals the signum that we are watching for. */ - /* These can get out of sync when the handler is stopped and restarted */ - /* while the signal_req is pending. */ + /* Check if the pending signal equals the signum that we are watching for. + * These can get out of sync when the handler is stopped and restarted while + * the signal_req is pending. */ if (dispatched_signum == handle->signum) handle->signal_cb(handle, dispatched_signum); - if (handle->flags & UV__SIGNAL_ONE_SHOT) + if (handle->flags & UV_SIGNAL_ONE_SHOT) uv_signal_stop(handle); - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { /* When it is closing, it must be stopped at this point. */ assert(handle->signum == 0); uv_want_endgame(loop, (uv_handle_t*) handle); @@ -265,7 +265,7 @@ void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) { void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) { - assert(handle->flags & UV__HANDLE_CLOSING); + assert(handle->flags & UV_HANDLE_CLOSING); assert(!(handle->flags & UV_HANDLE_CLOSED)); assert(handle->signum == 0); diff --git a/deps/uv/src/win/stream-inl.h b/deps/uv/src/win/stream-inl.h index dba03747043be7..40f5ddd51ea5a5 100644 --- a/deps/uv/src/win/stream-inl.h +++ b/deps/uv/src/win/stream-inl.h @@ -37,11 +37,6 @@ INLINE static void uv_stream_init(uv_loop_t* loop, handle->write_queue_size = 0; handle->activecnt = 0; handle->stream.conn.shutdown_req = NULL; -} - - -INLINE static void uv_connection_init(uv_stream_t* handle) { - handle->flags |= UV_HANDLE_CONNECTION; handle->stream.conn.write_reqs_pending = 0; UV_REQ_INIT(&handle->read_req, UV_READ); @@ -51,4 +46,9 @@ INLINE static void uv_connection_init(uv_stream_t* handle) { } +INLINE static void uv_connection_init(uv_stream_t* handle) { + handle->flags |= UV_HANDLE_CONNECTION; +} + + #endif /* UV_WIN_STREAM_INL_H_ */ diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c index 13cbfdcb9e6e5f..7656627e902da0 100644 --- a/deps/uv/src/win/stream.c +++ b/deps/uv/src/win/stream.c @@ -105,12 +105,10 @@ int uv_read_stop(uv_stream_t* handle) { err = 0; if (handle->type == UV_TTY) { err = uv_tty_read_stop((uv_tty_t*) handle); + } else if (handle->type == UV_NAMED_PIPE) { + uv__pipe_read_stop((uv_pipe_t*) handle); } else { - if (handle->type == UV_NAMED_PIPE) { - uv__pipe_stop_read((uv_pipe_t*) handle); - } else { - handle->flags &= ~UV_HANDLE_READING; - } + handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(handle->loop, handle); } @@ -136,7 +134,8 @@ int uv_write(uv_write_t* req, err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb); break; case UV_NAMED_PIPE: - err = uv_pipe_write(loop, req, (uv_pipe_t*) handle, bufs, nbufs, cb); + err = uv__pipe_write( + loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb); break; case UV_TTY: err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb); @@ -158,25 +157,18 @@ int uv_write2(uv_write_t* req, uv_loop_t* loop = handle->loop; int err; - if (!(handle->flags & UV_HANDLE_WRITABLE)) { - return UV_EPIPE; + if (send_handle == NULL) { + return uv_write(req, handle, bufs, nbufs, cb); } - err = ERROR_INVALID_PARAMETER; - switch (handle->type) { - case UV_NAMED_PIPE: - err = uv_pipe_write2(loop, - req, - (uv_pipe_t*) handle, - bufs, - nbufs, - send_handle, - cb); - break; - default: - assert(0); + if (handle->type != UV_NAMED_PIPE || !((uv_pipe_t*) handle)->ipc) { + return UV_EINVAL; + } else if (!(handle->flags & UV_HANDLE_WRITABLE)) { + return UV_EPIPE; } + err = uv__pipe_write( + loop, req, (uv_pipe_t*) handle, bufs, nbufs, send_handle, cb); return uv_translate_sys_error(err); } @@ -184,7 +176,7 @@ int uv_write2(uv_write_t* req, int uv_try_write(uv_stream_t* stream, const uv_buf_t bufs[], unsigned int nbufs) { - if (stream->flags & UV__HANDLE_CLOSING) + if (stream->flags & UV_HANDLE_CLOSING) return UV_EBADF; if (!(stream->flags & UV_HANDLE_WRITABLE)) return UV_EPIPE; diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index fd6efbaf891d64..8b6f0a5c99bd70 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -99,8 +99,8 @@ static int uv_tcp_set_socket(uv_loop_t* loop, if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0)) return GetLastError(); - /* Associate it with the I/O completion port. */ - /* Use uv_handle_t pointer as completion key. */ + /* Associate it with the I/O completion port. Use uv_handle_t pointer as + * completion key. */ if (CreateIoCompletionPort((HANDLE)socket, loop->iocp, (ULONG_PTR)socket, @@ -118,15 +118,12 @@ static int uv_tcp_set_socket(uv_loop_t* loop, non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4; } - if (pSetFileCompletionNotificationModes && - !(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) { - if (pSetFileCompletionNotificationModes((HANDLE) socket, - FILE_SKIP_SET_EVENT_ON_HANDLE | - FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { - handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; - } else if (GetLastError() != ERROR_INVALID_FUNCTION) { + if (!(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) { + UCHAR sfcnm_flags = + FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; + if (!SetFileCompletionNotificationModes((HANDLE) socket, sfcnm_flags)) return GetLastError(); - } + handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; } if (handle->flags & UV_HANDLE_TCP_NODELAY) { @@ -220,7 +217,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req); err = 0; - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { err = ERROR_OPERATION_ABORTED; } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) { err = WSAGetLastError(); @@ -236,7 +233,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { return; } - if (handle->flags & UV__HANDLE_CLOSING && + if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); @@ -326,9 +323,9 @@ static int uv_tcp_try_bind(uv_tcp_t* handle, on = (flags & UV_TCP_IPV6ONLY) != 0; - /* TODO: how to handle errors? This may fail if there is no ipv4 stack */ - /* available, or when run on XP/2003 which have no support for dualstack */ - /* sockets. For now we're silently ignoring the error. */ + /* TODO: how to handle errors? This may fail if there is no ipv4 stack + * available, or when run on XP/2003 which have no support for dualstack + * sockets. For now we're silently ignoring the error. */ setsockopt(handle->socket, IPPROTO_IPV6, IPV6_V6ONLY, @@ -459,8 +456,6 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { INFINITE, WT_EXECUTEINWAITTHREAD)) { SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); - handle->reqs_pending++; - return; } } else { /* Make this req pending reporting an error. */ @@ -628,9 +623,9 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { uv_tcp_queue_accept(handle, req); } - /* Initialize other unused requests too, because uv_tcp_endgame */ - /* doesn't know how how many requests were initialized, so it will */ - /* try to clean up {uv_simultaneous_server_accepts} requests. */ + /* Initialize other unused requests too, because uv_tcp_endgame doesn't + * know how many requests were initialized, so it will try to clean up + * {uv_simultaneous_server_accepts} requests. */ for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) { req = &handle->tcp.serv.accept_reqs[i]; UV_REQ_INIT(req, UV_ACCEPT); @@ -685,7 +680,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { req->next_pending = NULL; req->accept_socket = INVALID_SOCKET; - if (!(server->flags & UV__HANDLE_CLOSING)) { + if (!(server->flags & UV_HANDLE_CLOSING)) { /* Check if we're in a middle of changing the number of pending accepts. */ if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) { uv_tcp_queue_accept(server, req); @@ -723,8 +718,8 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, handle->alloc_cb = alloc_cb; INCREASE_ACTIVE_COUNT(loop, handle); - /* If reading was stopped and then started again, there could still be a */ - /* read request pending. */ + /* If reading was stopped and then started again, there could still be a read + * request pending. */ if (!(handle->flags & UV_HANDLE_READ_PENDING)) { if (handle->flags & UV_HANDLE_EMULATE_IOCP && !handle->read_req.event_handle) { @@ -967,8 +962,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, err = GET_REQ_SOCK_ERROR(req); if (err == WSAECONNABORTED) { - /* - * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix. + /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix. */ err = WSAECONNRESET; } @@ -1048,8 +1042,8 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, DECREASE_ACTIVE_COUNT(loop, handle); if (err == WSAECONNABORTED) { - /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */ - /* Unix. */ + /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with + * Unix. */ err = WSAECONNRESET; } @@ -1121,10 +1115,9 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, assert(handle->type == UV_TCP); - /* If handle->accepted_socket is not a valid socket, then */ - /* uv_queue_accept must have failed. This is a serious error. We stop */ - /* accepting connections and report this error to the connection */ - /* callback. */ + /* If handle->accepted_socket is not a valid socket, then uv_queue_accept + * must have failed. This is a serious error. We stop accepting connections + * and report this error to the connection callback. */ if (req->accept_socket == INVALID_SOCKET) { if (handle->flags & UV_HANDLE_LISTENING) { handle->flags &= ~UV_HANDLE_LISTENING; @@ -1149,9 +1142,9 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, handle->stream.serv.connection_cb((uv_stream_t*)handle, 0); } } else { - /* Error related to accepted socket is ignored because the server */ - /* socket may still be healthy. If the server socket is broken */ - /* uv_queue_accept will detect it. */ + /* Error related to accepted socket is ignored because the server socket + * may still be healthy. If the server socket is broken uv_queue_accept + * will detect it. */ closesocket(req->accept_socket); req->accept_socket = INVALID_SOCKET; if (handle->flags & UV_HANDLE_LISTENING) { @@ -1173,11 +1166,14 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, err = 0; if (REQ_SUCCESS(req)) { - if (setsockopt(handle->socket, - SOL_SOCKET, - SO_UPDATE_CONNECT_CONTEXT, - NULL, - 0) == 0) { + if (handle->flags & UV_HANDLE_CLOSING) { + /* use UV_ECANCELED for consistency with Unix */ + err = ERROR_OPERATION_ABORTED; + } else if (setsockopt(handle->socket, + SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, + NULL, + 0) == 0) { uv_connection_init((uv_stream_t*)handle); handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; loop->active_tcp_streams++; @@ -1193,40 +1189,76 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, } -int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex, - int tcp_connection) { +int uv__tcp_xfer_export(uv_tcp_t* handle, + int target_pid, + uv__ipc_socket_xfer_type_t* xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info) { + if (handle->flags & UV_HANDLE_CONNECTION) { + *xfer_type = UV__IPC_SOCKET_XFER_TCP_CONNECTION; + } else { + *xfer_type = UV__IPC_SOCKET_XFER_TCP_SERVER; + /* We're about to share the socket with another process. Because this is a + * listening socket, we assume that the other process will be accepting + * connections on it. Thus, before sharing the socket with another process, + * we call listen here in the parent process. */ + if (!(handle->flags & UV_HANDLE_LISTENING)) { + if (!(handle->flags & UV_HANDLE_BOUND)) { + return ERROR_NOT_SUPPORTED; + } + if (handle->delayed_error == 0 && + listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { + handle->delayed_error = WSAGetLastError(); + } + } + } + + if (WSADuplicateSocketW(handle->socket, target_pid, &xfer_info->socket_info)) + return WSAGetLastError(); + xfer_info->delayed_error = handle->delayed_error; + + /* Mark the local copy of the handle as 'shared' so we behave in a way that's + * friendly to the process(es) that we share the socket with. */ + handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET; + + return 0; +} + + +int uv__tcp_xfer_import(uv_tcp_t* tcp, + uv__ipc_socket_xfer_type_t xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info) { int err; - SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO, - FROM_PROTOCOL_INFO, - FROM_PROTOCOL_INFO, - &socket_info_ex->socket_info, - 0, - WSA_FLAG_OVERLAPPED); + SOCKET socket; + + assert(xfer_type == UV__IPC_SOCKET_XFER_TCP_SERVER || + xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION); + + socket = WSASocketW(FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + &xfer_info->socket_info, + 0, + WSA_FLAG_OVERLAPPED); if (socket == INVALID_SOCKET) { return WSAGetLastError(); } - err = uv_tcp_set_socket(tcp->loop, - tcp, - socket, - socket_info_ex->socket_info.iAddressFamily, - 1); + err = uv_tcp_set_socket( + tcp->loop, tcp, socket, xfer_info->socket_info.iAddressFamily, 1); if (err) { closesocket(socket); return err; } - if (tcp_connection) { + tcp->delayed_error = xfer_info->delayed_error; + tcp->flags |= UV_HANDLE_BOUND | UV_HANDLE_SHARED_TCP_SOCKET; + + if (xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION) { uv_connection_init((uv_stream_t*)tcp); tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; } - tcp->flags |= UV_HANDLE_BOUND; - tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET; - - tcp->delayed_error = socket_info_ex->delayed_error; - tcp->loop->active_tcp_streams++; return 0; } @@ -1272,39 +1304,6 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { } -int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, - LPWSAPROTOCOL_INFOW protocol_info) { - if (!(handle->flags & UV_HANDLE_CONNECTION)) { - /* - * We're about to share the socket with another process. Because - * this is a listening socket, we assume that the other process will - * be accepting connections on it. So, before sharing the socket - * with another process, we call listen here in the parent process. - */ - - if (!(handle->flags & UV_HANDLE_LISTENING)) { - if (!(handle->flags & UV_HANDLE_BOUND)) { - return ERROR_INVALID_PARAMETER; - } - - if (!(handle->delayed_error)) { - if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { - handle->delayed_error = WSAGetLastError(); - } - } - } - } - - if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) { - return WSAGetLastError(); - } - - handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET; - - return 0; -} - - int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { if (handle->flags & UV_HANDLE_CONNECTION) { return UV_EINVAL; @@ -1345,8 +1344,8 @@ static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) { non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : uv_tcp_non_ifs_lsp_ipv4; - /* If there are non-ifs LSPs then try to obtain a base handle for the */ - /* socket. This will always fail on Windows XP/3k. */ + /* If there are non-ifs LSPs then try to obtain a base handle for the socket. + * This will always fail on Windows XP/3k. */ if (non_ifs_lsp) { DWORD bytes; if (WSAIoctl(socket, @@ -1378,38 +1377,37 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { int close_socket = 1; if (tcp->flags & UV_HANDLE_READ_PENDING) { - /* In order for winsock to do a graceful close there must not be any */ - /* any pending reads, or the socket must be shut down for writing */ + /* In order for winsock to do a graceful close there must not be any any + * pending reads, or the socket must be shut down for writing */ if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) { /* Just do shutdown on non-shared sockets, which ensures graceful close. */ shutdown(tcp->socket, SD_SEND); } else if (uv_tcp_try_cancel_io(tcp) == 0) { - /* In case of a shared socket, we try to cancel all outstanding I/O, */ - /* If that works, don't close the socket yet - wait for the read req to */ - /* return and close the socket in uv_tcp_endgame. */ + /* In case of a shared socket, we try to cancel all outstanding I/O,. If + * that works, don't close the socket yet - wait for the read req to + * return and close the socket in uv_tcp_endgame. */ close_socket = 0; } else { - /* When cancelling isn't possible - which could happen when an LSP is */ - /* present on an old Windows version, we will have to close the socket */ - /* with a read pending. That is not nice because trailing sent bytes */ - /* may not make it to the other side. */ + /* When cancelling isn't possible - which could happen when an LSP is + * present on an old Windows version, we will have to close the socket + * with a read pending. That is not nice because trailing sent bytes may + * not make it to the other side. */ } } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) && tcp->tcp.serv.accept_reqs != NULL) { - /* Under normal circumstances closesocket() will ensure that all pending */ - /* accept reqs are canceled. However, when the socket is shared the */ - /* presence of another reference to the socket in another process will */ - /* keep the accept reqs going, so we have to ensure that these are */ - /* canceled. */ + /* Under normal circumstances closesocket() will ensure that all pending + * accept reqs are canceled. However, when the socket is shared the + * presence of another reference to the socket in another process will keep + * the accept reqs going, so we have to ensure that these are canceled. */ if (uv_tcp_try_cancel_io(tcp) != 0) { - /* When cancellation is not possible, there is another option: we can */ - /* close the incoming sockets, which will also cancel the accept */ - /* operations. However this is not cool because we might inadvertently */ - /* close a socket that just accepted a new connection, which will */ - /* cause the connection to be aborted. */ + /* When cancellation is not possible, there is another option: we can + * close the incoming sockets, which will also cancel the accept + * operations. However this is not cool because we might inadvertently + * close a socket that just accepted a new connection, which will cause + * the connection to be aborted. */ unsigned int i; for (i = 0; i < uv_simultaneous_server_accepts; i++) { uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i]; diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c index 9eaad77cd02c97..56ca41aab0b759 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -26,26 +26,6 @@ #include "uv.h" #include "internal.h" - -#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL) - -static int uv_cond_fallback_init(uv_cond_t* cond); -static void uv_cond_fallback_destroy(uv_cond_t* cond); -static void uv_cond_fallback_signal(uv_cond_t* cond); -static void uv_cond_fallback_broadcast(uv_cond_t* cond); -static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex); -static int uv_cond_fallback_timedwait(uv_cond_t* cond, - uv_mutex_t* mutex, uint64_t timeout); - -static int uv_cond_condvar_init(uv_cond_t* cond); -static void uv_cond_condvar_destroy(uv_cond_t* cond); -static void uv_cond_condvar_signal(uv_cond_t* cond); -static void uv_cond_condvar_broadcast(uv_cond_t* cond); -static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex); -static int uv_cond_condvar_timedwait(uv_cond_t* cond, - uv_mutex_t* mutex, uint64_t timeout); - - static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) { DWORD result; HANDLE existing_event, created_event; @@ -69,8 +49,8 @@ static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) { guard->ran = 1; } else { - /* We lost the race. Destroy the event we created and wait for the */ - /* existing one to become signaled. */ + /* We lost the race. Destroy the event we created and wait for the existing + * one to become signaled. */ CloseHandle(created_event); result = WaitForSingleObject(existing_event, INFINITE); assert(result == WAIT_OBJECT_0); @@ -138,7 +118,7 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { ctx->arg = arg; /* Create the thread in suspended state so we have a chance to pass - * its own creation handle to it */ + * its own creation handle to it */ thread = (HANDLE) _beginthreadex(NULL, 0, uv__thread_start, @@ -377,220 +357,35 @@ int uv_sem_trywait(uv_sem_t* sem) { } -/* This condition variable implementation is based on the SetEvent solution - * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html - * We could not use the SignalObjectAndWait solution (section 3.4) because - * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and - * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs. - */ - -static int uv_cond_fallback_init(uv_cond_t* cond) { - int err; - - /* Initialize the count to 0. */ - cond->fallback.waiters_count = 0; - - InitializeCriticalSection(&cond->fallback.waiters_count_lock); - - /* Create an auto-reset event. */ - cond->fallback.signal_event = CreateEvent(NULL, /* no security */ - FALSE, /* auto-reset event */ - FALSE, /* non-signaled initially */ - NULL); /* unnamed */ - if (!cond->fallback.signal_event) { - err = GetLastError(); - goto error2; - } - - /* Create a manual-reset event. */ - cond->fallback.broadcast_event = CreateEvent(NULL, /* no security */ - TRUE, /* manual-reset */ - FALSE, /* non-signaled */ - NULL); /* unnamed */ - if (!cond->fallback.broadcast_event) { - err = GetLastError(); - goto error; - } - - return 0; - -error: - CloseHandle(cond->fallback.signal_event); -error2: - DeleteCriticalSection(&cond->fallback.waiters_count_lock); - return uv_translate_sys_error(err); -} - - -static int uv_cond_condvar_init(uv_cond_t* cond) { - pInitializeConditionVariable(&cond->cond_var); - return 0; -} - - int uv_cond_init(uv_cond_t* cond) { - uv__once_init(); - - if (HAVE_CONDVAR_API()) - return uv_cond_condvar_init(cond); - else - return uv_cond_fallback_init(cond); -} - - -static void uv_cond_fallback_destroy(uv_cond_t* cond) { - if (!CloseHandle(cond->fallback.broadcast_event)) - abort(); - if (!CloseHandle(cond->fallback.signal_event)) - abort(); - DeleteCriticalSection(&cond->fallback.waiters_count_lock); -} - - -static void uv_cond_condvar_destroy(uv_cond_t* cond) { - /* nothing to do */ + InitializeConditionVariable(&cond->cond_var); + return 0; } void uv_cond_destroy(uv_cond_t* cond) { - if (HAVE_CONDVAR_API()) - uv_cond_condvar_destroy(cond); - else - uv_cond_fallback_destroy(cond); -} - - -static void uv_cond_fallback_signal(uv_cond_t* cond) { - int have_waiters; - - /* Avoid race conditions. */ - EnterCriticalSection(&cond->fallback.waiters_count_lock); - have_waiters = cond->fallback.waiters_count > 0; - LeaveCriticalSection(&cond->fallback.waiters_count_lock); - - if (have_waiters) - SetEvent(cond->fallback.signal_event); -} - - -static void uv_cond_condvar_signal(uv_cond_t* cond) { - pWakeConditionVariable(&cond->cond_var); + /* nothing to do */ + (void) &cond; } void uv_cond_signal(uv_cond_t* cond) { - if (HAVE_CONDVAR_API()) - uv_cond_condvar_signal(cond); - else - uv_cond_fallback_signal(cond); -} - - -static void uv_cond_fallback_broadcast(uv_cond_t* cond) { - int have_waiters; - - /* Avoid race conditions. */ - EnterCriticalSection(&cond->fallback.waiters_count_lock); - have_waiters = cond->fallback.waiters_count > 0; - LeaveCriticalSection(&cond->fallback.waiters_count_lock); - - if (have_waiters) - SetEvent(cond->fallback.broadcast_event); -} - - -static void uv_cond_condvar_broadcast(uv_cond_t* cond) { - pWakeAllConditionVariable(&cond->cond_var); + WakeConditionVariable(&cond->cond_var); } void uv_cond_broadcast(uv_cond_t* cond) { - if (HAVE_CONDVAR_API()) - uv_cond_condvar_broadcast(cond); - else - uv_cond_fallback_broadcast(cond); -} - - -static int uv_cond_wait_helper(uv_cond_t* cond, uv_mutex_t* mutex, - DWORD dwMilliseconds) { - DWORD result; - int last_waiter; - HANDLE handles[2] = { - cond->fallback.signal_event, - cond->fallback.broadcast_event - }; - - /* Avoid race conditions. */ - EnterCriticalSection(&cond->fallback.waiters_count_lock); - cond->fallback.waiters_count++; - LeaveCriticalSection(&cond->fallback.waiters_count_lock); - - /* It's ok to release the here since Win32 manual-reset events */ - /* maintain state when used with . This avoids the "lost wakeup" */ - /* bug. */ - uv_mutex_unlock(mutex); - - /* Wait for either event to become signaled due to being */ - /* called or being called. */ - result = WaitForMultipleObjects(2, handles, FALSE, dwMilliseconds); - - EnterCriticalSection(&cond->fallback.waiters_count_lock); - cond->fallback.waiters_count--; - last_waiter = result == WAIT_OBJECT_0 + 1 - && cond->fallback.waiters_count == 0; - LeaveCriticalSection(&cond->fallback.waiters_count_lock); - - /* Some thread called . */ - if (last_waiter) { - /* We're the last waiter to be notified or to stop waiting, so reset the */ - /* the manual-reset event. */ - ResetEvent(cond->fallback.broadcast_event); - } - - /* Reacquire the . */ - uv_mutex_lock(mutex); - - if (result == WAIT_OBJECT_0 || result == WAIT_OBJECT_0 + 1) - return 0; - - if (result == WAIT_TIMEOUT) - return UV_ETIMEDOUT; - - abort(); - return -1; /* Satisfy the compiler. */ -} - - -static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex) { - if (uv_cond_wait_helper(cond, mutex, INFINITE)) - abort(); -} - - -static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex) { - if (!pSleepConditionVariableCS(&cond->cond_var, mutex, INFINITE)) - abort(); + WakeAllConditionVariable(&cond->cond_var); } void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { - if (HAVE_CONDVAR_API()) - uv_cond_condvar_wait(cond, mutex); - else - uv_cond_fallback_wait(cond, mutex); -} - - -static int uv_cond_fallback_timedwait(uv_cond_t* cond, - uv_mutex_t* mutex, uint64_t timeout) { - return uv_cond_wait_helper(cond, mutex, (DWORD)(timeout / 1e6)); + if (!SleepConditionVariableCS(&cond->cond_var, mutex, INFINITE)) + abort(); } - -static int uv_cond_condvar_timedwait(uv_cond_t* cond, - uv_mutex_t* mutex, uint64_t timeout) { - if (pSleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6))) +int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { + if (SleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6))) return 0; if (GetLastError() != ERROR_TIMEOUT) abort(); @@ -598,15 +393,6 @@ static int uv_cond_condvar_timedwait(uv_cond_t* cond, } -int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, - uint64_t timeout) { - if (HAVE_CONDVAR_API()) - return uv_cond_condvar_timedwait(cond, mutex, timeout); - else - return uv_cond_fallback_timedwait(cond, mutex, timeout); -} - - int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { int err; diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c deleted file mode 100644 index 7e006fedfaf3ee..00000000000000 --- a/deps/uv/src/win/timer.c +++ /dev/null @@ -1,195 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include -#include - -#include "uv.h" -#include "internal.h" -#include "tree.h" -#include "handle-inl.h" - - -/* The number of milliseconds in one second. */ -#define UV__MILLISEC 1000 - - -void uv_update_time(uv_loop_t* loop) { - uint64_t new_time = uv__hrtime(UV__MILLISEC); - assert(new_time >= loop->time); - loop->time = new_time; -} - - -static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) { - if (a->due < b->due) - return -1; - if (a->due > b->due) - return 1; - /* - * compare start_id when both has the same due. start_id is - * allocated with loop->timer_counter in uv_timer_start(). - */ - if (a->start_id < b->start_id) - return -1; - if (a->start_id > b->start_id) - return 1; - return 0; -} - - -RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare) - - -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->repeat = 0; - - return 0; -} - - -void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) { - if (handle->flags & UV__HANDLE_CLOSING) { - assert(!(handle->flags & UV_HANDLE_CLOSED)); - uv__handle_close(handle); - } -} - - -static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) { - uint64_t clamped_timeout; - - clamped_timeout = loop_time + timeout; - if (clamped_timeout < timeout) - clamped_timeout = (uint64_t) -1; - - return clamped_timeout; -} - - -int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout, - uint64_t repeat) { - uv_loop_t* loop = handle->loop; - uv_timer_t* old; - - if (timer_cb == NULL) - return UV_EINVAL; - - if (uv__is_active(handle)) - uv_timer_stop(handle); - - handle->timer_cb = timer_cb; - handle->due = get_clamped_due_time(loop->time, timeout); - handle->repeat = repeat; - uv__handle_start(handle); - - /* start_id is the second index to be compared in uv__timer_cmp() */ - handle->start_id = handle->loop->timer_counter++; - - old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle); - assert(old == NULL); - - return 0; -} - - -int uv_timer_stop(uv_timer_t* handle) { - uv_loop_t* loop = handle->loop; - - if (!uv__is_active(handle)) - return 0; - - RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); - uv__handle_stop(handle); - - return 0; -} - - -int uv_timer_again(uv_timer_t* handle) { - /* If timer_cb is NULL that means that the timer was never started. */ - if (!handle->timer_cb) { - return UV_EINVAL; - } - - if (handle->repeat) { - uv_timer_stop(handle); - uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat); - } - - return 0; -} - - -void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) { - assert(handle->type == UV_TIMER); - handle->repeat = repeat; -} - - -uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { - assert(handle->type == UV_TIMER); - return handle->repeat; -} - - -DWORD uv__next_timeout(const uv_loop_t* loop) { - uv_timer_t* timer; - int64_t delta; - - /* Check if there are any running timers - * Need to cast away const first, since RB_MIN doesn't know what we are - * going to do with this return value, it can't be marked const - */ - timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers); - if (timer) { - delta = timer->due - loop->time; - if (delta >= UINT_MAX - 1) { - /* A timeout value of UINT_MAX means infinite, so that's no good. */ - return UINT_MAX - 1; - } else if (delta < 0) { - /* Negative timeout values are not allowed */ - return 0; - } else { - return (DWORD)delta; - } - } else { - /* No timers */ - return INFINITE; - } -} - - -void uv_process_timers(uv_loop_t* loop) { - uv_timer_t* timer; - - /* Call timer callbacks */ - for (timer = RB_MIN(uv_timer_tree_s, &loop->timers); - timer != NULL && timer->due <= loop->time; - timer = RB_MIN(uv_timer_tree_s, &loop->timers)) { - - uv_timer_stop(timer); - uv_timer_again(timer); - timer->timer_cb((uv_timer_t*) timer); - } -} diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 05a11e88305ff4..32ccf74ca8cb6a 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -25,7 +25,7 @@ #include #if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" +# include "uv/stdint-msvc2008.h" #else # include #endif @@ -172,9 +172,12 @@ void uv_console_init(void) { } -int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { +int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { + BOOL readable; + DWORD NumberOfEvents; HANDLE handle; CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; + (void)unused; uv__once_init(); handle = (HANDLE) uv__get_osfhandle(fd); @@ -199,14 +202,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { fd = -1; } + readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents); if (!readable) { /* Obtain the screen buffer info with the output handle. */ if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) { return uv_translate_sys_error(GetLastError()); } - /* Obtain the the tty_output_lock because the virtual window state is */ - /* shared between all uv_tty_t handles. */ + /* Obtain the tty_output_lock because the virtual window state is shared + * between all uv_tty_t handles. */ uv_sem_wait(&uv_tty_output_lock); if (uv__vterm_state == UV_UNCHECKED) @@ -382,12 +386,6 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { } -int uv_is_tty(uv_file file) { - DWORD result; - return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0; -} - - int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { CONSOLE_SCREEN_BUFFER_INFO info; @@ -484,8 +482,8 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { bytes = MAX_INPUT_BUFFER_LENGTH; } - /* At last, unicode! */ - /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */ + /* At last, unicode! One utf-16 codeunit never takes more than 3 utf-8 + * codeunits to encode. */ chars = bytes / 3; status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS); @@ -620,10 +618,10 @@ static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl, } switch (code) { - /* These mappings are the same as Cygwin's. Unmodified and alt-modified */ - /* keypad keys comply with linux console, modifiers comply with xterm */ - /* modifier usage. F1..f12 and shift-f1..f10 comply with linux console, */ - /* f6..f12 with and without modifiers comply with rxvt. */ + /* These mappings are the same as Cygwin's. Unmodified and alt-modified + * keypad keys comply with linux console, modifiers comply with xterm + * modifier usage. F1. f12 and shift-f1. f10 comply with linux console, f6. + * f12 with and without modifiers comply with rxvt. */ VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~") VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~") VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B") @@ -706,8 +704,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, goto out; } - /* Windows sends a lot of events that we're not interested in, so buf */ - /* will be allocated on demand, when there's actually something to emit. */ + /* Windows sends a lot of events that we're not interested in, so buf will be + * allocated on demand, when there's actually something to emit. */ buf = uv_null_buf_; buf_used = 0; @@ -733,16 +731,16 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, continue; } - /* Ignore keyup events, unless the left alt key was held and a valid */ - /* unicode character was emitted. */ + /* Ignore keyup events, unless the left alt key was held and a valid + * unicode character was emitted. */ if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) || KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) { continue; } - /* Ignore keypresses to numpad number keys if the left alt is held */ - /* because the user is composing a character, or windows simulating */ - /* this. */ + /* Ignore keypresses to numpad number keys if the left alt is held + * because the user is composing a character, or windows simulating this. + */ if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) && !(KEV.dwControlKeyState & ENHANCED_KEY) && (KEV.wVirtualKeyCode == VK_INSERT || @@ -779,8 +777,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, continue; } - /* Prefix with \u033 if alt was held, but alt was not used as part */ - /* a compose sequence. */ + /* Prefix with \u033 if alt was held, but alt was not used as part a + * compose sequence. */ if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) { @@ -818,8 +816,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, /* Whatever happened, the last character wasn't a high surrogate. */ handle->tty.rd.last_utf16_high_surrogate = 0; - /* If the utf16 character(s) couldn't be converted something must */ - /* be wrong. */ + /* If the utf16 character(s) couldn't be converted something must be + * wrong. */ if (!char_len) { handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(loop, handle); @@ -950,8 +948,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, } else { if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { - /* Read successful */ - /* TODO: read unicode, convert to utf-8 */ + /* Read successful. TODO: read unicode, convert to utf-8 */ DWORD bytes = req->u.io.overlapped.InternalHigh; handle->read_cb((uv_stream_t*) handle, bytes, &buf); } else { @@ -975,9 +972,9 @@ void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, assert(handle->type == UV_TTY); assert(handle->flags & UV_HANDLE_TTY_READABLE); - /* If the read_line_buffer member is zero, it must have been an raw read. */ - /* Otherwise it was a line-buffered read. */ - /* FIXME: This is quite obscure. Use a flag or something. */ + /* If the read_line_buffer member is zero, it must have been an raw read. + * Otherwise it was a line-buffered read. FIXME: This is quite obscure. Use a + * flag or something. */ if (handle->tty.rd.read_line_buffer.len == 0) { uv_process_tty_read_raw_req(loop, handle, req); } else { @@ -999,14 +996,14 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; - /* If reading was stopped and then started again, there could still be a */ - /* read request pending. */ + /* If reading was stopped and then started again, there could still be a read + * request pending. */ if (handle->flags & UV_HANDLE_READ_PENDING) { return 0; } - /* Maybe the user stopped reading half-way while processing key events. */ - /* Short-circuit if this could be the case. */ + /* Maybe the user stopped reading half-way while processing key events. + * Short-circuit if this could be the case. */ if (handle->tty.rd.last_key_len > 0) { SET_REQ_SUCCESS(&handle->read_req); uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req); @@ -1033,9 +1030,10 @@ int uv_tty_read_stop(uv_tty_t* handle) { return 0; if (handle->flags & UV_HANDLE_TTY_RAW) { - /* Cancel raw read */ - /* Write some bullshit event to force the console wait to return. */ + /* Cancel raw read. Write some bullshit event to force the console wait to + * return. */ memset(&record, 0, sizeof record); + record.EventType = FOCUS_EVENT; if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { return GetLastError(); } @@ -1116,8 +1114,8 @@ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { uv_tty_virtual_offset = info->dwCursorPosition.Y; } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y - uv_tty_virtual_height + 1) { - /* If suddenly find the cursor outside of the virtual window, it must */ - /* have somehow scrolled. Update the virtual window offset. */ + /* If suddenly find the cursor outside of the virtual window, it must have + * somehow scrolled. Update the virtual window offset. */ uv_tty_virtual_offset = info->dwCursorPosition.Y - uv_tty_virtual_height + 1; } @@ -1304,8 +1302,8 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen, x2 = 0; x2r = 1; } else { - /* Clear to end of row. We pretend the console is 65536 characters wide, */ - /* uv_tty_make_real_coord will clip it to the actual console width. */ + /* Clear to end of row. We pretend the console is 65536 characters wide, + * uv_tty_make_real_coord will clip it to the actual console width. */ x2 = 0xffff; x2r = 0; } @@ -1613,8 +1611,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, const uv_buf_t bufs[], unsigned int nbufs, DWORD* error) { - /* We can only write 8k characters at a time. Windows can't handle */ - /* much more characters in a single console write anyway. */ + /* We can only write 8k characters at a time. Windows can't handle much more + * characters in a single console write anyway. */ WCHAR utf16_buf[MAX_CONSOLE_CHAR]; WCHAR* utf16_buffer; DWORD utf16_buf_used = 0; @@ -1650,9 +1648,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, unsigned char previous_eol = handle->tty.wr.previous_eol; unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state; - /* Store the error here. If we encounter an error, stop trying to do i/o */ - /* but keep parsing the buffer so we leave the parser in a consistent */ - /* state. */ + /* Store the error here. If we encounter an error, stop trying to do i/o but + * keep parsing the buffer so we leave the parser in a consistent state. */ *error = ERROR_SUCCESS; utf16_buffer = utf16_buf; @@ -1700,9 +1697,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle, for (j = 0; j < buf.len; j++) { unsigned char c = buf.base[j]; - /* Run the character through the utf8 decoder We happily accept non */ - /* shortest form encodings and invalid code points - there's no real */ - /* harm that can be done. */ + /* Run the character through the utf8 decoder We happily accept non + * shortest form encodings and invalid code points - there's no real harm + * that can be done. */ if (utf8_bytes_left == 0) { /* Read utf-8 start byte */ DWORD first_zero_bit; @@ -1742,8 +1739,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, /* Start byte where continuation was expected. */ utf8_bytes_left = 0; utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; - /* Patch buf offset so this character will be parsed again as a */ - /* start byte. */ + /* Patch buf offset so this character will be parsed again as a start + * byte. */ j--; } @@ -1776,8 +1773,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, case '_': case 'P': case ']': - /* Not supported, but we'll have to parse until we see a stop */ - /* code, e.g. ESC \ or BEL. */ + /* Not supported, but we'll have to parse until we see a stop code, + * e. g. ESC \ or BEL. */ ansi_parser_state = ANSI_ST_CONTROL; continue; @@ -1859,8 +1856,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle, continue; } else { - /* If ANSI_IN_ARG is not set, add another argument and */ - /* default it to 0. */ + /* If ANSI_IN_ARG is not set, add another argument and default it + * to 0. */ + /* Check for too many arguments */ if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) { ansi_parser_state |= ANSI_IGNORE; @@ -1874,9 +1872,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle, } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) && handle->tty.wr.ansi_csi_argc == 0) { - /* Ignores '?' if it is the first character after CSI[ */ - /* This is an extension character from the VT100 codeset */ - /* that is supported and used by most ANSI terminals today. */ + /* Ignores '?' if it is the first character after CSI[. This is an + * extension character from the VT100 codeset that is supported and + * used by most ANSI terminals today. */ continue; } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' && @@ -2006,8 +2004,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, continue; } else { - /* We don't support commands that use private mode characters or */ - /* intermediaries. Ignore the rest of the sequence. */ + /* We don't support commands that use private mode characters or + * intermediaries. Ignore the rest of the sequence. */ ansi_parser_state |= ANSI_IGNORE; continue; } @@ -2020,8 +2018,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, } } else if (ansi_parser_state & ANSI_ST_CONTROL) { - /* Unsupported control code */ - /* Ignore everything until we see BEL or ESC \ */ + /* Unsupported control code. + * Ignore everything until we see `BEL` or `ESC \`. */ if (ansi_parser_state & ANSI_IN_STRING) { if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) { if (utf8_codepoint == '"') { @@ -2055,9 +2053,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle, abort(); } - /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */ - /* windows console doesn't really support UTF-16, so just emit the */ - /* replacement character. */ + /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the windows + * console doesn't really support UTF-16, so just emit the replacement + * character. */ if (utf8_codepoint > 0xffff) { utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; } @@ -2071,10 +2069,10 @@ static int uv_tty_write_bufs(uv_tty_t* handle, utf16_buf[utf16_buf_used++] = L'\r'; utf16_buf[utf16_buf_used++] = L'\n'; } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) { - /* \n was followed by \r; do not print the \r, since */ - /* the source was either \r\n\r (so the second \r is */ - /* redundant) or was \n\r (so the \n was processed */ - /* by the last case and an \r automatically inserted). */ + /* \n was followed by \r; do not print the \r, since the source was + * either \r\n\r (so the second \r is redundant) or was \n\r (so the + * \n was processed by the last case and an \r automatically + * inserted). */ } else { /* \r without \n; print \r as-is. */ ENSURE_BUFFER_SPACE(1); @@ -2182,14 +2180,14 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, void uv_tty_close(uv_tty_t* handle) { assert(handle->u.fd == -1 || handle->u.fd > 2); + if (handle->flags & UV_HANDLE_READING) + uv_tty_read_stop(handle); + if (handle->u.fd == -1) CloseHandle(handle->handle); else close(handle->u.fd); - if (handle->flags & UV_HANDLE_READING) - uv_tty_read_stop(handle); - handle->u.fd = -1; handle->handle = INVALID_HANDLE_VALUE; handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); @@ -2209,7 +2207,7 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { /* TTY shutdown is really just a no-op */ if (handle->stream.conn.shutdown_req->cb) { - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED); } else { handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0); @@ -2222,10 +2220,10 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { return; } - if (handle->flags & UV__HANDLE_CLOSING && + if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { - /* The wait handle used for raw reading should be unregistered when the */ - /* wait callback runs. */ + /* The wait handle used for raw reading should be unregistered when the + * wait callback runs. */ assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || handle->tty.rd.read_raw_wait == NULL); @@ -2235,14 +2233,20 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { } -/* TODO: remove me */ +/* + * uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working + * TODO: find a way to remove it + */ void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, uv_req_t* raw_req) { abort(); } -/* TODO: remove me */ +/* + * uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working + * TODO: find a way to remove it + */ void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, uv_connect_t* req) { abort(); diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index cd1d0e07b23cb9..37df849f8faf20 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -74,8 +74,8 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, return GetLastError(); } - /* Associate it with the I/O completion port. */ - /* Use uv_handle_t pointer as completion key. */ + /* Associate it with the I/O completion port. Use uv_handle_t pointer as + * completion key. */ if (CreateIoCompletionPort((HANDLE)socket, loop->iocp, (ULONG_PTR)socket, @@ -83,31 +83,28 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, return GetLastError(); } - if (pSetFileCompletionNotificationModes) { - /* All known Windows that support SetFileCompletionNotificationModes */ - /* have a bug that makes it impossible to use this function in */ - /* conjunction with datagram sockets. We can work around that but only */ - /* if the user is using the default UDP driver (AFD) and has no other */ - /* LSPs stacked on top. Here we check whether that is the case. */ - opt_len = (int) sizeof info; - if (getsockopt(socket, - SOL_SOCKET, - SO_PROTOCOL_INFOW, - (char*) &info, - &opt_len) == SOCKET_ERROR) { - return GetLastError(); - } + /* All known Windows that support SetFileCompletionNotificationModes have a + * bug that makes it impossible to use this function in conjunction with + * datagram sockets. We can work around that but only if the user is using + * the default UDP driver (AFD) and has no other. LSPs stacked on top. Here + * we check whether that is the case. */ + opt_len = (int) sizeof info; + if (getsockopt( + socket, SOL_SOCKET, SO_PROTOCOL_INFOW, (char*) &info, &opt_len) == + SOCKET_ERROR) { + return GetLastError(); + } - if (info.ProtocolChain.ChainLen == 1) { - if (pSetFileCompletionNotificationModes((HANDLE)socket, - FILE_SKIP_SET_EVENT_ON_HANDLE | - FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { - handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; - handle->func_wsarecv = uv_wsarecv_workaround; - handle->func_wsarecvfrom = uv_wsarecvfrom_workaround; - } else if (GetLastError() != ERROR_INVALID_FUNCTION) { - return GetLastError(); - } + if (info.ProtocolChain.ChainLen == 1) { + if (SetFileCompletionNotificationModes( + (HANDLE) socket, + FILE_SKIP_SET_EVENT_ON_HANDLE | + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { + handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; + handle->func_wsarecv = uv_wsarecv_workaround; + handle->func_wsarecvfrom = uv_wsarecvfrom_workaround; + } else if (GetLastError() != ERROR_INVALID_FUNCTION) { + return GetLastError(); } } @@ -191,7 +188,7 @@ void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) { void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) { - if (handle->flags & UV__HANDLE_CLOSING && + if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); uv__handle_close(handle); @@ -245,12 +242,12 @@ static int uv_udp_maybe_bind(uv_udp_t* handle, handle->flags |= UV_HANDLE_IPV6; if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) { - /* On windows IPV6ONLY is on by default. */ - /* If the user doesn't specify it libuv turns it off. */ + /* On windows IPV6ONLY is on by default. If the user doesn't specify it + * libuv turns it off. */ - /* TODO: how to handle errors? This may fail if there is no ipv4 stack */ - /* available, or when run on XP/2003 which have no support for dualstack */ - /* sockets. For now we're silently ignoring the error. */ + /* TODO: how to handle errors? This may fail if there is no ipv4 stack + * available, or when run on XP/2003 which have no support for dualstack + * sockets. For now we're silently ignoring the error. */ setsockopt(handle->socket, IPPROTO_IPV6, IPV6_V6ONLY, @@ -369,7 +366,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, int err; if (handle->flags & UV_HANDLE_READING) { - return WSAEALREADY; + return UV_EALREADY; } err = uv_udp_maybe_bind(handle, @@ -377,7 +374,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, sizeof(uv_addr_ip4_any_), 0); if (err) - return err; + return uv_translate_sys_error(err); handle->flags |= UV_HANDLE_READING; INCREASE_ACTIVE_COUNT(loop, handle); @@ -386,8 +383,8 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, handle->recv_cb = recv_cb; handle->alloc_cb = alloc_cb; - /* If reading was stopped and then started again, there could still be a */ - /* recv request pending. */ + /* If reading was stopped and then started again, there could still be a recv + * request pending. */ if (!(handle->flags & UV_HANDLE_READ_PENDING)) uv_udp_queue_recv(loop, handle); @@ -467,19 +464,19 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, if (!REQ_SUCCESS(req)) { DWORD err = GET_REQ_SOCK_ERROR(req); if (err == WSAEMSGSIZE) { - /* Not a real error, it just indicates that the received packet */ - /* was bigger than the receive buffer. */ + /* Not a real error, it just indicates that the received packet was + * bigger than the receive buffer. */ } else if (err == WSAECONNRESET || err == WSAENETRESET) { - /* A previous sendto operation failed; ignore this error. If */ - /* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */ - /* MSG_PEEK flag to clear out the error queue. For nonzero reads, */ - /* immediately queue a new receive. */ + /* A previous sendto operation failed; ignore this error. If zero-reading + * we need to call WSARecv/WSARecvFrom _without_ the. MSG_PEEK flag to + * clear out the error queue. For nonzero reads, immediately queue a new + * receive. */ if (!(handle->flags & UV_HANDLE_ZERO_READ)) { goto done; } } else { - /* A real error occurred. Report the error to the user only if we're */ - /* currently reading. */ + /* A real error occurred. Report the error to the user only if we're + * currently reading. */ if (handle->flags & UV_HANDLE_READING) { uv_udp_recv_stop(handle); buf = (handle->flags & UV_HANDLE_ZERO_READ) ? @@ -503,8 +500,8 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, struct sockaddr_storage from; int from_len; - /* Do a nonblocking receive */ - /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */ + /* Do a nonblocking receive. + * TODO: try to read multiple datagrams at once. FIONREAD maybe? */ buf = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); if (buf.base == NULL || buf.len == 0) { @@ -741,7 +738,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) return UV_EINVAL; } - if (!(handle->flags & UV_HANDLE_BOUND)) + if (handle->socket == INVALID_SOCKET) return UV_EBADF; if (addr_st.ss_family == AF_INET) { @@ -772,7 +769,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) int uv_udp_set_broadcast(uv_udp_t* handle, int value) { BOOL optval = (BOOL) value; - if (!(handle->flags & UV_HANDLE_BOUND)) + if (handle->socket == INVALID_SOCKET) return UV_EBADF; if (setsockopt(handle->socket, @@ -818,7 +815,7 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { return UV_EINVAL; \ } \ \ - if (!(handle->flags & UV_HANDLE_BOUND)) \ + if (handle->socket == INVALID_SOCKET) \ return UV_EBADF; \ \ if (!(handle->flags & UV_HANDLE_IPV6)) { \ diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 3100bc23ad3e09..c994984fe65a25 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -37,7 +37,7 @@ #include #include #include - +#include /* * Max title length; the only thing MSDN tells us about the maximum length @@ -74,10 +74,6 @@ static char *process_title; static CRITICAL_SECTION process_title_lock; -/* Cached copy of the process id, written once. */ -static DWORD current_pid = 0; - - /* Interval (in seconds) of the high-resolution clock. */ static double hrtime_interval_ = 0; @@ -149,8 +145,8 @@ int uv_exepath(char* buffer, size_t* size_ptr) { uv__free(utf16_buffer); - /* utf8_len *does* include the terminating null at this point, but the */ - /* returned size shouldn't. */ + /* utf8_len *does* include the terminating null at this point, but the + * returned size shouldn't. */ *size_ptr = utf8_len - 1; return 0; @@ -173,16 +169,16 @@ int uv_cwd(char* buffer, size_t* size) { if (utf16_len == 0) { return uv_translate_sys_error(GetLastError()); } else if (utf16_len > MAX_PATH) { - /* This should be impossible; however the CRT has a code path to deal */ - /* with this scenario, so I added a check anyway. */ + /* This should be impossible; however the CRT has a code path to deal with + * this scenario, so I added a check anyway. */ return UV_EIO; } /* utf16_len contains the length, *not* including the terminating null. */ utf16_buffer[utf16_len] = L'\0'; - /* The returned directory should not have a trailing slash, unless it */ - /* points at a drive root, like c:\. Remove it if needed.*/ + /* The returned directory should not have a trailing slash, unless it points + * at a drive root, like c:\. Remove it if needed. */ if (utf16_buffer[utf16_len - 1] == L'\\' && !(utf16_len == 3 && utf16_buffer[1] == L':')) { utf16_len--; @@ -239,9 +235,9 @@ int uv_chdir(const char* dir) { utf16_buffer, MAX_PATH) == 0) { DWORD error = GetLastError(); - /* The maximum length of the current working directory is 260 chars, */ - /* including terminating null. If it doesn't fit, the path name must be */ - /* too long. */ + /* The maximum length of the current working directory is 260 chars, + * including terminating null. If it doesn't fit, the path name must be too + * long. */ if (error == ERROR_INSUFFICIENT_BUFFER) { return UV_ENAMETOOLONG; } else { @@ -253,9 +249,9 @@ int uv_chdir(const char* dir) { return uv_translate_sys_error(GetLastError()); } - /* Windows stores the drive-local path in an "hidden" environment variable, */ - /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */ - /* update this, so we'll have to do it. */ + /* Windows stores the drive-local path in an "hidden" environment variable, + * which has the form "=C:=C:\Windows". SetCurrentDirectory does not update + * this, so we'll have to do it. */ utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); if (utf16_len == 0) { return uv_translate_sys_error(GetLastError()); @@ -263,8 +259,8 @@ int uv_chdir(const char* dir) { return UV_EIO; } - /* The returned directory should not have a trailing slash, unless it */ - /* points at a drive root, like c:\. Remove it if needed. */ + /* The returned directory should not have a trailing slash, unless it points + * at a drive root, like c:\. Remove it if needed. */ if (utf16_buffer[utf16_len - 1] == L'\\' && !(utf16_len == 3 && utf16_buffer[1] == L':')) { utf16_len--; @@ -272,8 +268,8 @@ int uv_chdir(const char* dir) { } if (utf16_len < 2 || utf16_buffer[1] != L':') { - /* Doesn't look like a drive letter could be there - probably an UNC */ - /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */ + /* Doesn't look like a drive letter could be there - probably an UNC path. + * TODO: Need to handle win32 namespaces like \\?\C:\ ? */ drive_letter = 0; } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') { drive_letter = utf16_buffer[0]; @@ -359,14 +355,6 @@ uv_pid_t uv_os_getppid(void) { } -int uv_current_pid(void) { - if (current_pid == 0) { - current_pid = GetCurrentProcessId(); - } - return current_pid; -} - - char** uv_setup_args(int argc, char** argv) { return argv; } @@ -587,8 +575,8 @@ int uv_uptime(double* uptime) { BYTE* address = (BYTE*) object_type + object_type->DefinitionLength + counter_definition->CounterOffset; uint64_t value = *((uint64_t*) address); - *uptime = (double) (object_type->PerfTime.QuadPart - value) / - (double) object_type->PerfFreq.QuadPart; + *uptime = floor((double) (object_type->PerfTime.QuadPart - value) / + (double) object_type->PerfFreq.QuadPart); uv__free(malloced_buffer); return 0; } @@ -615,7 +603,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; DWORD sppi_size; SYSTEM_INFO system_info; - DWORD cpu_count, r, i; + DWORD cpu_count, i; NTSTATUS status; ULONG result_size; int err; @@ -670,34 +658,33 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { assert(len > 0 && len < ARRAY_SIZE(key_name)); - r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - key_name, - 0, - KEY_QUERY_VALUE, - &processor_key); - if (r != ERROR_SUCCESS) { - err = GetLastError(); + err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + key_name, + 0, + KEY_QUERY_VALUE, + &processor_key); + if (err != ERROR_SUCCESS) { goto error; } - if (RegQueryValueExW(processor_key, - L"~MHz", - NULL, - NULL, - (BYTE*) &cpu_speed, - &cpu_speed_size) != ERROR_SUCCESS) { - err = GetLastError(); + err = RegQueryValueExW(processor_key, + L"~MHz", + NULL, + NULL, + (BYTE*)&cpu_speed, + &cpu_speed_size); + if (err != ERROR_SUCCESS) { RegCloseKey(processor_key); goto error; } - if (RegQueryValueExW(processor_key, - L"ProcessorNameString", - NULL, - NULL, - (BYTE*) &cpu_brand, - &cpu_brand_size) != ERROR_SUCCESS) { - err = GetLastError(); + err = RegQueryValueExW(processor_key, + L"ProcessorNameString", + NULL, + NULL, + (BYTE*)&cpu_brand, + &cpu_brand_size); + if (err != ERROR_SUCCESS) { RegCloseKey(processor_key); goto error; } @@ -843,17 +830,17 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, } - /* Fetch the size of the adapters reported by windows, and then get the */ - /* list itself. */ + /* Fetch the size of the adapters reported by windows, and then get the list + * itself. */ win_address_buf_size = 0; win_address_buf = NULL; for (;;) { ULONG r; - /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */ - /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */ - /* win_address_buf_size. */ + /* If win_address_buf is 0, then GetAdaptersAddresses will fail with. + * ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in + * win_address_buf_size. */ r = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, @@ -867,8 +854,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, switch (r) { case ERROR_BUFFER_OVERFLOW: - /* This happens when win_address_buf is NULL or too small to hold */ - /* all adapters. */ + /* This happens when win_address_buf is NULL or too small to hold all + * adapters. */ win_address_buf = uv__malloc(win_address_buf_size); if (win_address_buf == NULL) return UV_ENOMEM; @@ -902,15 +889,15 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, return UV_ENOBUFS; default: - /* Other (unspecified) errors can happen, but we don't have any */ - /* special meaning for them. */ + /* Other (unspecified) errors can happen, but we don't have any special + * meaning for them. */ assert(r != ERROR_SUCCESS); return uv_translate_sys_error(r); } } - /* Count the number of enabled interfaces and compute how much space is */ - /* needed to store their info. */ + /* Count the number of enabled interfaces and compute how much space is + * needed to store their info. */ count = 0; uv_address_buf_size = 0; @@ -920,9 +907,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, IP_ADAPTER_UNICAST_ADDRESS* unicast_address; int name_size; - /* Interfaces that are not 'up' should not be reported. Also skip */ - /* interfaces that have no associated unicast address, as to avoid */ - /* allocating space for the name for this interface. */ + /* Interfaces that are not 'up' should not be reported. Also skip + * interfaces that have no associated unicast address, as to avoid + * allocating space for the name for this interface. */ if (adapter->OperStatus != IfOperStatusUp || adapter->FirstUnicastAddress == NULL) continue; @@ -942,8 +929,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, } uv_address_buf_size += name_size; - /* Count the number of addresses associated with this interface, and */ - /* compute the size. */ + /* Count the number of addresses associated with this interface, and + * compute the size. */ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*) adapter->FirstUnicastAddress; unicast_address != NULL; @@ -960,8 +947,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, return UV_ENOMEM; } - /* Compute the start of the uv_interface_address_t array, and the place in */ - /* the buffer where the interface names will be stored. */ + /* Compute the start of the uv_interface_address_t array, and the place in + * the buffer where the interface names will be stored. */ uv_address = uv_address_buf; name_buf = (char*) (uv_address_buf + count); @@ -1148,53 +1135,17 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { int uv_os_homedir(char* buffer, size_t* size) { uv_passwd_t pwd; - wchar_t path[MAX_PATH]; - DWORD bufsize; size_t len; int r; - if (buffer == NULL || size == NULL || *size == 0) - return UV_EINVAL; - - /* Check if the USERPROFILE environment variable is set first */ - len = GetEnvironmentVariableW(L"USERPROFILE", path, MAX_PATH); - - if (len == 0) { - r = GetLastError(); - - /* Don't return an error if USERPROFILE was not found */ - if (r != ERROR_ENVVAR_NOT_FOUND) - return uv_translate_sys_error(r); - } else if (len > MAX_PATH) { - /* This should not be possible */ - return UV_EIO; - } else { - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); - - if (bufsize == 0) { - return uv_translate_sys_error(GetLastError()); - } else if (bufsize > *size) { - *size = bufsize; - return UV_ENOBUFS; - } + /* Check if the USERPROFILE environment variable is set first. The task of + performing input validation on buffer and size is taken care of by + uv_os_getenv(). */ + r = uv_os_getenv("USERPROFILE", buffer, size); - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - path, - -1, - buffer, - *size, - NULL, - NULL); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - *size = bufsize - 1; - return 0; - } + /* Don't return an error if USERPROFILE was not found. */ + if (r != UV_ENOENT) + return r; /* USERPROFILE is not set, so call uv__getpwuid_r() */ r = uv__getpwuid_r(&pwd); @@ -1236,8 +1187,8 @@ int uv_os_tmpdir(char* buffer, size_t* size) { return UV_EIO; } - /* The returned directory should not have a trailing slash, unless it */ - /* points at a drive root, like c:\. Remove it if needed.*/ + /* The returned directory should not have a trailing slash, unless it points + * at a drive root, like c:\. Remove it if needed. */ if (path[len - 1] == L'\\' && !(len == 3 && path[1] == L':')) { len--; @@ -1579,3 +1530,97 @@ int uv_os_gethostname(char* buffer, size_t* size) { *size = len; return 0; } + + +static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) { + int r; + + if (pid == 0) + *handle = GetCurrentProcess(); + else + *handle = OpenProcess(access, FALSE, pid); + + if (*handle == NULL) { + r = GetLastError(); + + if (r == ERROR_INVALID_PARAMETER) + return UV_ESRCH; + else + return uv_translate_sys_error(r); + } + + return 0; +} + + +int uv_os_getpriority(uv_pid_t pid, int* priority) { + HANDLE handle; + int r; + + if (priority == NULL) + return UV_EINVAL; + + r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle); + + if (r != 0) + return r; + + r = GetPriorityClass(handle); + + if (r == 0) { + r = uv_translate_sys_error(GetLastError()); + } else { + /* Map Windows priority classes to Unix nice values. */ + if (r == REALTIME_PRIORITY_CLASS) + *priority = UV_PRIORITY_HIGHEST; + else if (r == HIGH_PRIORITY_CLASS) + *priority = UV_PRIORITY_HIGH; + else if (r == ABOVE_NORMAL_PRIORITY_CLASS) + *priority = UV_PRIORITY_ABOVE_NORMAL; + else if (r == NORMAL_PRIORITY_CLASS) + *priority = UV_PRIORITY_NORMAL; + else if (r == BELOW_NORMAL_PRIORITY_CLASS) + *priority = UV_PRIORITY_BELOW_NORMAL; + else /* IDLE_PRIORITY_CLASS */ + *priority = UV_PRIORITY_LOW; + + r = 0; + } + + CloseHandle(handle); + return r; +} + + +int uv_os_setpriority(uv_pid_t pid, int priority) { + HANDLE handle; + int priority_class; + int r; + + /* Map Unix nice values to Windows priority classes. */ + if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW) + return UV_EINVAL; + else if (priority < UV_PRIORITY_HIGH) + priority_class = REALTIME_PRIORITY_CLASS; + else if (priority < UV_PRIORITY_ABOVE_NORMAL) + priority_class = HIGH_PRIORITY_CLASS; + else if (priority < UV_PRIORITY_NORMAL) + priority_class = ABOVE_NORMAL_PRIORITY_CLASS; + else if (priority < UV_PRIORITY_BELOW_NORMAL) + priority_class = NORMAL_PRIORITY_CLASS; + else if (priority < UV_PRIORITY_LOW) + priority_class = BELOW_NORMAL_PRIORITY_CLASS; + else + priority_class = IDLE_PRIORITY_CLASS; + + r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle); + + if (r != 0) + return r; + + if (SetPriorityClass(handle, priority_class) == 0) + r = uv_translate_sys_error(GetLastError()); + + CloseHandle(handle); + return r; +} diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index 4ccdf0a5f97ca2..2c09b448a95c01 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -34,20 +34,8 @@ sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; sNtQueryDirectoryFile pNtQueryDirectoryFile; sNtQuerySystemInformation pNtQuerySystemInformation; - /* Kernel32 function pointers */ sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; -sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; -sCreateSymbolicLinkW pCreateSymbolicLinkW; -sCancelIoEx pCancelIoEx; -sInitializeConditionVariable pInitializeConditionVariable; -sSleepConditionVariableCS pSleepConditionVariableCS; -sSleepConditionVariableSRW pSleepConditionVariableSRW; -sWakeAllConditionVariable pWakeAllConditionVariable; -sWakeConditionVariable pWakeConditionVariable; -sCancelSynchronousIo pCancelSynchronousIo; -sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; - /* Powrprof.dll function pointer */ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; @@ -58,9 +46,9 @@ sSetWinEventHook pSetWinEventHook; void uv_winapi_init(void) { HMODULE ntdll_module; - HMODULE kernel32_module; HMODULE powrprof_module; HMODULE user32_module; + HMODULE kernel32_module; ntdll_module = GetModuleHandleA("ntdll.dll"); if (ntdll_module == NULL) { @@ -123,37 +111,6 @@ void uv_winapi_init(void) { kernel32_module, "GetQueuedCompletionStatusEx"); - pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes) - GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes"); - - pCreateSymbolicLinkW = (sCreateSymbolicLinkW) - GetProcAddress(kernel32_module, "CreateSymbolicLinkW"); - - pCancelIoEx = (sCancelIoEx) - GetProcAddress(kernel32_module, "CancelIoEx"); - - pInitializeConditionVariable = (sInitializeConditionVariable) - GetProcAddress(kernel32_module, "InitializeConditionVariable"); - - pSleepConditionVariableCS = (sSleepConditionVariableCS) - GetProcAddress(kernel32_module, "SleepConditionVariableCS"); - - pSleepConditionVariableSRW = (sSleepConditionVariableSRW) - GetProcAddress(kernel32_module, "SleepConditionVariableSRW"); - - pWakeAllConditionVariable = (sWakeAllConditionVariable) - GetProcAddress(kernel32_module, "WakeAllConditionVariable"); - - pWakeConditionVariable = (sWakeConditionVariable) - GetProcAddress(kernel32_module, "WakeConditionVariable"); - - pCancelSynchronousIo = (sCancelSynchronousIo) - GetProcAddress(kernel32_module, "CancelSynchronousIo"); - - pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW) - GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW"); - - powrprof_module = LoadLibraryA("powrprof.dll"); if (powrprof_module != NULL) { pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index cc54b79b08dd19..cfbac52eb1d6f4 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4076,8 +4076,8 @@ # define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L) #endif -/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the */ -/* DDK got it wrong! */ +/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the DDK + * got it wrong! */ #ifdef NTSTATUS_FROM_WIN32 # undef NTSTATUS_FROM_WIN32 #endif @@ -4650,48 +4650,6 @@ typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx) DWORD dwMilliseconds, BOOL fAlertable); -typedef BOOL (WINAPI* sSetFileCompletionNotificationModes) - (HANDLE FileHandle, - UCHAR Flags); - -typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW) - (LPCWSTR lpSymlinkFileName, - LPCWSTR lpTargetFileName, - DWORD dwFlags); - -typedef BOOL (WINAPI* sCancelIoEx) - (HANDLE hFile, - LPOVERLAPPED lpOverlapped); - -typedef VOID (WINAPI* sInitializeConditionVariable) - (PCONDITION_VARIABLE ConditionVariable); - -typedef BOOL (WINAPI* sSleepConditionVariableCS) - (PCONDITION_VARIABLE ConditionVariable, - PCRITICAL_SECTION CriticalSection, - DWORD dwMilliseconds); - -typedef BOOL (WINAPI* sSleepConditionVariableSRW) - (PCONDITION_VARIABLE ConditionVariable, - PSRWLOCK SRWLock, - DWORD dwMilliseconds, - ULONG Flags); - -typedef VOID (WINAPI* sWakeAllConditionVariable) - (PCONDITION_VARIABLE ConditionVariable); - -typedef VOID (WINAPI* sWakeConditionVariable) - (PCONDITION_VARIABLE ConditionVariable); - -typedef BOOL (WINAPI* sCancelSynchronousIo) - (HANDLE hThread); - -typedef DWORD (WINAPI* sGetFinalPathNameByHandleW) - (HANDLE hFile, - LPWSTR lpszFilePath, - DWORD cchFilePath, - DWORD dwFlags); - /* from powerbase.h */ #ifndef DEVICE_NOTIFY_CALLBACK # define DEVICE_NOTIFY_CALLBACK 2 @@ -4754,20 +4712,8 @@ extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; extern sNtQueryDirectoryFile pNtQueryDirectoryFile; extern sNtQuerySystemInformation pNtQuerySystemInformation; - /* Kernel32 function pointers */ extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; -extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; -extern sCreateSymbolicLinkW pCreateSymbolicLinkW; -extern sCancelIoEx pCancelIoEx; -extern sInitializeConditionVariable pInitializeConditionVariable; -extern sSleepConditionVariableCS pSleepConditionVariableCS; -extern sSleepConditionVariableSRW pSleepConditionVariableSRW; -extern sWakeAllConditionVariable pWakeAllConditionVariable; -extern sWakeConditionVariable pWakeConditionVariable; -extern sCancelSynchronousIo pCancelSynchronousIo; -extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; - /* Powrprof.dll function pointer */ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; diff --git a/deps/uv/src/win/winsock.c b/deps/uv/src/win/winsock.c index 84188954d815f1..5e7da2a8f25293 100644 --- a/deps/uv/src/win/winsock.c +++ b/deps/uv/src/win/winsock.c @@ -256,8 +256,8 @@ int uv_ntstatus_to_winsock_error(NTSTATUS status) { default: if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) && (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) { - /* It's a windows error that has been previously mapped to an */ - /* ntstatus code. */ + /* It's a windows error that has been previously mapped to an ntstatus + * code. */ return (DWORD) (status & 0xffff); } else { /* The default fallback for unmappable ntstatus codes. */ @@ -519,8 +519,8 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, sizeof *info_out); if (overlapped == NULL) { - /* If this is a blocking operation, wait for the event to become */ - /* signaled, and then grab the real status from the io status block. */ + /* If this is a blocking operation, wait for the event to become signaled, + * and then grab the real status from the io status block. */ if (status == STATUS_PENDING) { DWORD r = WaitForSingleObject(event, INFINITE); diff --git a/deps/uv/test/benchmark-async-pummel.c b/deps/uv/test/benchmark-async-pummel.c index cca3de1062bc59..119ae5eee5a28c 100644 --- a/deps/uv/test/benchmark-async-pummel.c +++ b/deps/uv/test/benchmark-async-pummel.c @@ -41,7 +41,7 @@ static void async_cb(uv_async_t* handle) { /* Tell the pummel thread to stop. */ ACCESS_ONCE(const char*, handle->data) = stop; - /* Wait for for the pummel thread to acknowledge that it has stoppped. */ + /* Wait for the pummel thread to acknowledge that it has stoppped. */ while (ACCESS_ONCE(const char*, handle->data) != stopped) uv_sleep(0); diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c index da4ac82e431124..9b8af0460877bd 100644 --- a/deps/uv/test/run-tests.c +++ b/deps/uv/test/run-tests.c @@ -37,6 +37,7 @@ #include "test-list.h" int ipc_helper(int listen_after_write); +int ipc_helper_heavy_traffic_deadlock_bug(void); int ipc_helper_tcp_connection(void); int ipc_helper_closed_handle(void); int ipc_send_recv_helper(void); @@ -83,6 +84,10 @@ static int maybe_run_test(int argc, char **argv) { return ipc_helper(1); } + if (strcmp(argv[1], "ipc_helper_heavy_traffic_deadlock_bug") == 0) { + return ipc_helper_heavy_traffic_deadlock_bug(); + } + if (strcmp(argv[1], "ipc_send_recv_helper") == 0) { return ipc_send_recv_helper(); } diff --git a/deps/uv/test/runner-unix.c b/deps/uv/test/runner-unix.c index 3167ed44bf695a..de0db0cc486d6a 100644 --- a/deps/uv/test/runner-unix.c +++ b/deps/uv/test/runner-unix.c @@ -57,8 +57,8 @@ int platform_init(int argc, char **argv) { } -/* Invoke "argv[0] test-name [test-part]". Store process info in *p. */ -/* Make sure that all stdio output of the processes is buffered up. */ +/* Invoke "argv[0] test-name [test-part]". Store process info in *p. Make sure + * that all stdio output of the processes is buffered up. */ int process_start(char* name, char* part, process_info_t* p, int is_helper) { FILE* stdout_file; int stdout_fd; @@ -161,9 +161,9 @@ static void* dowait(void* data) { } -/* Wait for all `n` processes in `vec` to terminate. */ -/* Time out after `timeout` msec, or never if timeout == -1 */ -/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */ +/* Wait for all `n` processes in `vec` to terminate. Time out after `timeout` + * msec, or never if timeout == -1. Return 0 if all processes are terminated, + * -1 on error, -2 on timeout. */ int process_wait(process_info_t* vec, int n, int timeout) { int i; int r; @@ -358,8 +358,7 @@ int process_terminate(process_info_t *p) { } -/* Return the exit code of process p. */ -/* On error, return -1. */ +/* Return the exit code of process p. On error, return -1. */ int process_reap(process_info_t *p) { if (WIFEXITED(p->status)) { return WEXITSTATUS(p->status); diff --git a/deps/uv/test/runner-win.c b/deps/uv/test/runner-win.c index d86fda3c5d7b8c..aa52d7cc5aa9a6 100644 --- a/deps/uv/test/runner-win.c +++ b/deps/uv/test/runner-win.c @@ -165,8 +165,8 @@ int process_start(char *name, char *part, process_info_t *p, int is_helper) { } -/* Timeout is is msecs. Set timeout < 0 to never time out. */ -/* Returns 0 when all processes are terminated, -2 on timeout. */ +/* Timeout is in msecs. Set timeout < 0 to never time out. Returns 0 when all + * processes are terminated, -2 on timeout. */ int process_wait(process_info_t *vec, int n, int timeout) { int i; HANDLE handles[MAXIMUM_WAIT_OBJECTS]; @@ -228,7 +228,7 @@ int process_copy_output(process_info_t* p, FILE* stream) { while (fgets(buf, sizeof(buf), f) != NULL) print_lines(buf, strlen(buf), stream); - + if (ferror(f)) return -1; diff --git a/deps/uv/test/runner.h b/deps/uv/test/runner.h index 555f2f8eb72075..1a33950852de15 100644 --- a/deps/uv/test/runner.h +++ b/deps/uv/test/runner.h @@ -138,13 +138,13 @@ void print_lines(const char* buffer, size_t size, FILE* stream); /* Do platform-specific initialization. */ int platform_init(int argc, char** argv); -/* Invoke "argv[0] test-name [test-part]". Store process info in *p. */ -/* Make sure that all stdio output of the processes is buffered up. */ +/* Invoke "argv[0] test-name [test-part]". Store process info in *p. Make sure + * that all stdio output of the processes is buffered up. */ int process_start(char *name, char* part, process_info_t *p, int is_helper); -/* Wait for all `n` processes in `vec` to terminate. */ -/* Time out after `timeout` msec, or never if timeout == -1 */ -/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */ +/* Wait for all `n` processes in `vec` to terminate. Time out after `timeout` + * msec, or never if timeout == -1. Return 0 if all processes are terminated, + * -1 on error, -2 on timeout. */ int process_wait(process_info_t *vec, int n, int timeout); /* Returns the number of bytes in the stdio output buffer for process `p`. */ @@ -164,8 +164,7 @@ char* process_get_name(process_info_t *p); /* Terminate process `p`. */ int process_terminate(process_info_t *p); -/* Return the exit code of process p. */ -/* On error, return -1. */ +/* Return the exit code of process p. On error, return -1. */ int process_reap(process_info_t *p); /* Clean up after terminating process `p` (e.g. free the output buffer etc.). */ diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h index af99d92fb45414..92a90a540be34f 100644 --- a/deps/uv/test/task.h +++ b/deps/uv/test/task.h @@ -29,7 +29,7 @@ #include #if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" +# include "uv/stdint-msvc2008.h" #else # include #endif diff --git a/deps/uv/test/test-barrier.c b/deps/uv/test/test-barrier.c index dfd2dbdef1b1d0..89858db5711482 100644 --- a/deps/uv/test/test-barrier.c +++ b/deps/uv/test/test-barrier.c @@ -104,3 +104,45 @@ TEST_IMPL(barrier_3) { return 0; } + +static void serial_worker(void* data) { + uv_barrier_t* barrier; + + barrier = data; + if (uv_barrier_wait(barrier) > 0) + uv_barrier_destroy(barrier); + + uv_sleep(100); /* Wait a bit before terminating. */ +} + +/* Ensure that uv_barrier_wait returns positive only after all threads have + * exited the barrier. If this value is returned too early and the barrier is + * destroyed prematurely, then this test may see a crash. */ +TEST_IMPL(barrier_serial_thread) { + uv_thread_t threads[4]; + uv_barrier_t barrier; + unsigned i; + + ASSERT(0 == uv_barrier_init(&barrier, ARRAY_SIZE(threads) + 1)); + + for (i = 0; i < ARRAY_SIZE(threads); ++i) + ASSERT(0 == uv_thread_create(&threads[i], serial_worker, &barrier)); + + if (uv_barrier_wait(&barrier) > 0) + uv_barrier_destroy(&barrier); + + for (i = 0; i < ARRAY_SIZE(threads); ++i) + ASSERT(0 == uv_thread_join(&threads[i])); + + return 0; +} + +/* Single thread uv_barrier_wait should return correct return value. */ +TEST_IMPL(barrier_serial_thread_single) { + uv_barrier_t barrier; + + ASSERT(0 == uv_barrier_init(&barrier, 1)); + ASSERT(0 < uv_barrier_wait(&barrier)); + uv_barrier_destroy(&barrier); + return 0; +} diff --git a/deps/uv/test/test-callback-stack.c b/deps/uv/test/test-callback-stack.c index 8855c0841b3937..1871e7e98196d1 100644 --- a/deps/uv/test/test-callback-stack.c +++ b/deps/uv/test/test-callback-stack.c @@ -88,10 +88,9 @@ static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { bytes_received += nread; - /* We call shutdown here because when bytes_received == sizeof MESSAGE */ - /* there will be no more data sent nor received, so here it would be */ - /* possible for a backend to to call shutdown_cb immediately and *not* */ - /* from a fresh stack. */ + /* We call shutdown here because when bytes_received == sizeof MESSAGE there + * will be no more data sent nor received, so here it would be possible for a + * backend to call shutdown_cb immediately and *not* from a fresh stack. */ if (bytes_received == sizeof MESSAGE) { nested++; @@ -131,10 +130,10 @@ static void write_cb(uv_write_t* req, int status) { puts("Data written. 500ms timeout..."); - /* After the data has been sent, we're going to wait for a while, then */ - /* start reading. This makes us certain that the message has been echoed */ - /* back to our receive buffer when we start reading. This maximizes the */ - /* temptation for the backend to use dirty stack for calling read_cb. */ + /* After the data has been sent, we're going to wait for a while, then start + * reading. This makes us certain that the message has been echoed back to + * our receive buffer when we start reading. This maximizes the temptation + * for the backend to use dirty stack for calling read_cb. */ nested++; r = uv_timer_init(uv_default_loop(), &timer); ASSERT(r == 0); diff --git a/deps/uv/test/test-condvar.c b/deps/uv/test/test-condvar.c index d956efef3c5a00..50f3c047c00cd2 100644 --- a/deps/uv/test/test-condvar.c +++ b/deps/uv/test/test-condvar.c @@ -25,221 +25,243 @@ #include #include +struct worker_config; + +typedef void (*signal_func)(struct worker_config* c, int* flag); +typedef int (*wait_func)(struct worker_config* c, const int* flag); + typedef struct worker_config { + uv_sem_t sem_waiting; /* post before waiting. */ + uv_sem_t sem_signaled; /* post after signaling. */ uv_mutex_t mutex; uv_cond_t cond; - int signal_delay; - int wait_delay; int use_broadcast; - volatile int posted_1; - volatile int posted_2; - void (*signal_cond)(struct worker_config* c, volatile int* flag); - int (*wait_cond)(struct worker_config* c, const volatile int* flag); + int posted_1; + int posted_2; + signal_func signal_cond; + wait_func wait_cond; } worker_config; +void worker_config_init(worker_config* wc, + int use_broadcast, + signal_func signal_f, + wait_func wait_f) { + /* Wipe. */ + memset(wc, 0, sizeof(*wc)); + + /* Copy vars. */ + wc->signal_cond = signal_f; + wc->wait_cond = wait_f; + wc->use_broadcast = use_broadcast; + + /* Init. */ + ASSERT(0 == uv_sem_init(&wc->sem_waiting, 0)); + ASSERT(0 == uv_sem_init(&wc->sem_signaled, 0)); + ASSERT(0 == uv_cond_init(&wc->cond)); + ASSERT(0 == uv_mutex_init(&wc->mutex)); +} +void worker_config_destroy(worker_config* wc) { + uv_mutex_destroy(&wc->mutex); + uv_cond_destroy(&wc->cond); + uv_sem_destroy(&wc->sem_signaled); + uv_sem_destroy(&wc->sem_waiting); +} + +/* arg is a worker_config. + * Call signal_cond then wait_cond. + * Partner should call wait then signal. */ static void worker(void* arg) { worker_config* c = arg; c->signal_cond(c, &c->posted_1); c->wait_cond(c, &c->posted_2); } -static void noop_worker(void* arg) { - return; -} - -static void condvar_signal(worker_config* c, volatile int* flag) { - if (c->signal_delay) - uv_sleep(c->signal_delay); +/* 1. Signal a waiting waiter. + * 2. Tell waiter we finished. */ +static void condvar_signal(worker_config* c, int* flag) { + /* Wait until waiter holds mutex and is preparing to wait. */ + uv_sem_wait(&c->sem_waiting); + /* Make sure waiter has begun waiting. */ uv_mutex_lock(&c->mutex); + + /* Help waiter differentiate between spurious and legitimate wakeup. */ ASSERT(*flag == 0); *flag = 1; + if (c->use_broadcast) uv_cond_broadcast(&c->cond); else uv_cond_signal(&c->cond); + uv_mutex_unlock(&c->mutex); -} + /* Done signaling. */ + uv_sem_post(&c->sem_signaled); +} -static int condvar_wait(worker_config* c, const volatile int* flag) { +/* 1. Wait on a signal. + * 2. Ensure that the signaler finished. */ +static int condvar_wait(worker_config* c, const int* flag) { uv_mutex_lock(&c->mutex); - if (c->wait_delay) - uv_sleep(c->wait_delay); - while (*flag == 0) { + + /* Tell signal'er that I am waiting. */ + uv_sem_post(&c->sem_waiting); + + /* Wait until I get a non-spurious signal. */ + do { uv_cond_wait(&c->cond, &c->mutex); - } + } while (*flag == 0); ASSERT(*flag == 1); + uv_mutex_unlock(&c->mutex); + /* Wait for my signal'er to finish. */ + uv_sem_wait(&c->sem_signaled); + return 0; } - +/* uv_cond_wait: One thread signals, the other waits. */ TEST_IMPL(condvar_1) { - uv_thread_t thread; worker_config wc; + uv_thread_t thread; - memset(&wc, 0, sizeof(wc)); - wc.wait_delay = 100; - wc.signal_cond = condvar_signal; - wc.wait_cond = condvar_wait; - - ASSERT(0 == uv_cond_init(&wc.cond)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); + /* Helper signal-then-wait. */ + worker_config_init(&wc, 0, condvar_signal, condvar_wait); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + /* We wait-then-signal. */ ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); - uv_mutex_destroy(&wc.mutex); - uv_cond_destroy(&wc.cond); + worker_config_destroy(&wc); return 0; } - +/* uv_cond_wait: One thread broadcasts, the other waits. */ TEST_IMPL(condvar_2) { - uv_thread_t thread; worker_config wc; + uv_thread_t thread; - memset(&wc, 0, sizeof(wc)); - wc.signal_delay = 100; - wc.signal_cond = condvar_signal; - wc.wait_cond = condvar_wait; - - ASSERT(0 == uv_cond_init(&wc.cond)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); + /* Helper to signal-then-wait. */ + worker_config_init(&wc, 1, condvar_signal, condvar_wait); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + /* We wait-then-signal. */ ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); - uv_mutex_destroy(&wc.mutex); - uv_cond_destroy(&wc.cond); + worker_config_destroy(&wc); return 0; } - -static int condvar_timedwait(worker_config* c, const volatile int* flag) { +/* 1. Wait on a signal (hopefully not timeout, else we'll hang). + * 2. Ensure that the signaler finished. */ +static int condvar_timedwait(worker_config* c, const int* flag) { int r; r = 0; uv_mutex_lock(&c->mutex); - if (c->wait_delay) - uv_sleep(c->wait_delay); - while (*flag == 0) { - r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(150 * 1e6)); - ASSERT(r == 0 || r == UV_ETIMEDOUT); - if (r == UV_ETIMEDOUT) - break; - } + + /* Tell signal'er that I am waiting. */ + uv_sem_post(&c->sem_waiting); + + /* Wait until I get a non-spurious signal. */ + do { + r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(1 * 1e9)); /* 1 s */ + ASSERT(r == 0); /* Should not time out. */ + } while (*flag == 0); + ASSERT(*flag == 1); + uv_mutex_unlock(&c->mutex); + /* Wait for my signal'er to finish. */ + uv_sem_wait(&c->sem_signaled); return r; } -/* Test that uv_cond_timedwait will return early when cond is signaled. */ +/* uv_cond_timedwait: One thread signals, the other timedwaits. */ TEST_IMPL(condvar_3) { - uv_thread_t thread; worker_config wc; + uv_thread_t thread; - memset(&wc, 0, sizeof(wc)); - wc.signal_delay = 100; - wc.signal_cond = condvar_signal; - wc.wait_cond = condvar_timedwait; - - ASSERT(0 == uv_cond_init(&wc.cond)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); + /* Helper to signal-then-wait. */ + worker_config_init(&wc, 0, condvar_signal, condvar_timedwait); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); + /* We wait-then-signal. */ + wc.wait_cond(&wc, &wc.posted_1); wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); - uv_mutex_destroy(&wc.mutex); - uv_cond_destroy(&wc.cond); + worker_config_destroy(&wc); return 0; } - +/* uv_cond_timedwait: One thread broadcasts, the other waits. */ TEST_IMPL(condvar_4) { - uv_thread_t thread; worker_config wc; + uv_thread_t thread; - memset(&wc, 0, sizeof(wc)); - wc.signal_delay = 100; - wc.signal_cond = condvar_signal; - wc.wait_cond = condvar_timedwait; - - ASSERT(0 == uv_cond_init(&wc.cond)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); + /* Helper to signal-then-wait. */ + worker_config_init(&wc, 1, condvar_signal, condvar_timedwait); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + /* We wait-then-signal. */ wc.wait_cond(&wc, &wc.posted_1); wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); - uv_mutex_destroy(&wc.mutex); - uv_cond_destroy(&wc.cond); + worker_config_destroy(&wc); return 0; } - +/* uv_cond_timedwait: One thread waits, no signal. Timeout should be delivered. */ TEST_IMPL(condvar_5) { - uv_thread_t thread; worker_config wc; + int r; + /* ns */ + uint64_t before; + uint64_t after; + uint64_t elapsed; + uint64_t timeout; - memset(&wc, 0, sizeof(wc)); - wc.use_broadcast = 1; - wc.signal_delay = 100; - wc.signal_cond = condvar_signal; - wc.wait_cond = condvar_wait; - - ASSERT(0 == uv_cond_init(&wc.cond)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - - wc.wait_cond(&wc, &wc.posted_1); - wc.signal_cond(&wc, &wc.posted_2); + timeout = 100 * 1e6; /* 100 ms in ns */ - ASSERT(0 == uv_thread_join(&thread)); - uv_mutex_destroy(&wc.mutex); - uv_cond_destroy(&wc.cond); + /* Mostly irrelevant. We need cond and mutex initialized. */ + worker_config_init(&wc, 0, NULL, NULL); - return 0; -} + uv_mutex_lock(&wc.mutex); -/* Test that uv_cond_timedwait will time out when cond is not signaled. */ -TEST_IMPL(condvar_6) { - uv_thread_t thread; - worker_config wc; - int r; + /* We wait. + * No signaler, so this will only return if timeout is delivered. */ + before = uv_hrtime(); + r = uv_cond_timedwait(&wc.cond, &wc.mutex, timeout); + after = uv_hrtime(); - memset(&wc, 0, sizeof(wc)); - wc.signal_delay = 100; - wc.signal_cond = condvar_signal; - wc.wait_cond = condvar_timedwait; + uv_mutex_unlock(&wc.mutex); - ASSERT(0 == uv_cond_init(&wc.cond)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); - ASSERT(0 == uv_thread_create(&thread, noop_worker, &wc)); - - /* This can only return having timed out, because otherwise we - * loop forever in condvar_timedwait. */ - r = wc.wait_cond(&wc, &wc.posted_1); + /* It timed out. */ ASSERT(r == UV_ETIMEDOUT); - ASSERT(0 == uv_thread_join(&thread)); - uv_mutex_destroy(&wc.mutex); - uv_cond_destroy(&wc.cond); + /* It must have taken at least timeout, modulo system timer ticks. + * But it should not take too much longer. + * cf. MSDN docs: + * https://msdn.microsoft.com/en-us/library/ms687069(VS.85).aspx */ + elapsed = after - before; + ASSERT(0.75 * timeout <= elapsed); /* 1.0 too large for Windows. */ + ASSERT(elapsed <= 5.0 * timeout); /* MacOS has reported failures up to 1.75. */ + + worker_config_destroy(&wc); return 0; } diff --git a/deps/uv/test/test-connect-unspecified.c b/deps/uv/test/test-connect-unspecified.c index 04e1c8a5f7c682..5f32b67a6a4daa 100644 --- a/deps/uv/test/test-connect-unspecified.c +++ b/deps/uv/test/test-connect-unspecified.c @@ -48,12 +48,14 @@ TEST_IMPL(connect_unspecified) { (const struct sockaddr*) &addr4, connect_4) == 0); - ASSERT(uv_tcp_init(loop, &socket6) == 0); - ASSERT(uv_ip6_addr("::", TEST_PORT, &addr6) == 0); - ASSERT(uv_tcp_connect(&connect6, - &socket6, - (const struct sockaddr*) &addr6, - connect_6) == 0); + if (can_ipv6()) { + ASSERT(uv_tcp_init(loop, &socket6) == 0); + ASSERT(uv_ip6_addr("::", TEST_PORT, &addr6) == 0); + ASSERT(uv_tcp_connect(&connect6, + &socket6, + (const struct sockaddr*) &addr6, + connect_6) == 0); + } ASSERT(uv_run(loop, UV_RUN_DEFAULT) == 0); diff --git a/deps/uv/test/test-connection-fail.c b/deps/uv/test/test-connection-fail.c index 328bff46e7d08c..8338cacdec3c5f 100644 --- a/deps/uv/test/test-connection-fail.c +++ b/deps/uv/test/test-connection-fail.c @@ -98,8 +98,8 @@ static void connection_fail(uv_connect_cb connect_cb) { r = uv_tcp_init(uv_default_loop(), &tcp); ASSERT(!r); - /* We are never doing multiple reads/connects at a time anyway. */ - /* so these handles can be pre-initialized. */ + /* We are never doing multiple reads/connects at a time anyway. so these + * handles can be pre-initialized. */ ASSERT(0 == uv_tcp_bind(&tcp, (const struct sockaddr*) &client_addr, 0)); r = uv_tcp_connect(&req, diff --git a/deps/uv/test/test-delayed-accept.c b/deps/uv/test/test-delayed-accept.c index 4a7998909c3f7d..513e69bd5b7d23 100644 --- a/deps/uv/test/test-delayed-accept.c +++ b/deps/uv/test/test-delayed-accept.c @@ -138,8 +138,8 @@ static void connect_cb(uv_connect_t* req, int status) { ASSERT(req != NULL); ASSERT(status == 0); - /* Not that the server will send anything, but otherwise we'll never know */ - /* when the server closes the connection. */ + /* Not that the server will send anything, but otherwise we'll never know + * when the server closes the connection. */ r = uv_read_start((uv_stream_t*)(req->handle), alloc_cb, read_cb); ASSERT(r == 0); diff --git a/deps/uv/test/test-error.c b/deps/uv/test/test-error.c index a2d559a4ee1564..7f44f4a1bc606d 100644 --- a/deps/uv/test/test-error.c +++ b/deps/uv/test/test-error.c @@ -37,6 +37,8 @@ * See https://github.com/joyent/libuv/issues/210 */ TEST_IMPL(error_message) { + char buf[32]; + /* Cop out. Can't do proper checks on systems with * i18n-ized error messages... */ @@ -49,6 +51,10 @@ TEST_IMPL(error_message) { ASSERT(strcmp(uv_strerror(1337), "Unknown error") == 0); ASSERT(strcmp(uv_strerror(-1337), "Unknown error") == 0); + ASSERT(strstr(uv_strerror_r(UV_EINVAL, buf, sizeof(buf)), "Success") == NULL); + ASSERT(strstr(uv_strerror_r(1337, buf, sizeof(buf)), "1337") != NULL); + ASSERT(strstr(uv_strerror_r(-1337, buf, sizeof(buf)), "-1337") != NULL); + return 0; } diff --git a/deps/uv/test/test-fork.c b/deps/uv/test/test-fork.c index 39b59c8f20ebb4..f47ae3e656299e 100644 --- a/deps/uv/test/test-fork.c +++ b/deps/uv/test/test-fork.c @@ -283,6 +283,7 @@ TEST_IMPL(fork_signal_to_child_closed) { int sync_pipe[2]; int sync_pipe2[2]; char sync_buf[1]; + int r; fork_signal_cb_called = 0; /* reset */ @@ -317,8 +318,7 @@ TEST_IMPL(fork_signal_to_child_closed) { printf("Waiting for child in parent\n"); assert_wait_child(child_pid); } else { - /* child */ - /* Our signal handler should still be installed. */ + /* Child. Our signal handler should still be installed. */ ASSERT(0 == uv_loop_fork(uv_default_loop())); printf("Checking loop in child\n"); ASSERT(0 != uv_loop_alive(uv_default_loop())); @@ -327,9 +327,10 @@ TEST_IMPL(fork_signal_to_child_closed) { /* Don't run the loop. Wait for the parent to call us */ printf("Waiting on parent in child\n"); /* Wait for parent. read may fail if the parent tripped an ASSERT - and exited, so this isn't in an ASSERT. + and exited, so this ASSERT is generous. */ - read(sync_pipe2[0], sync_buf, 1); + r = read(sync_pipe2[0], sync_buf, 1); + ASSERT(-1 <= r && r <= 1); ASSERT(0 == fork_signal_cb_called); printf("Exiting child \n"); /* Note that we're deliberately not running the loop @@ -652,13 +653,11 @@ TEST_IMPL(fork_threadpool_queue_work_simple) { ASSERT(child_pid != -1); if (child_pid != 0) { - /* parent */ - /* We can still run work. */ + /* Parent. We can still run work. */ assert_run_work(uv_default_loop()); assert_wait_child(child_pid); } else { - /* child */ - /* We can work in a new loop. */ + /* Child. We can work in a new loop. */ printf("Running child in %d\n", getpid()); uv_loop_init(&loop); printf("Child first watch\n"); diff --git a/deps/uv/test/test-fs-copyfile.c b/deps/uv/test/test-fs-copyfile.c index 4b1fdc5e798280..eadff542bcb43c 100644 --- a/deps/uv/test/test-fs-copyfile.c +++ b/deps/uv/test/test-fs-copyfile.c @@ -168,6 +168,22 @@ TEST_IMPL(fs_copyfile) { r = uv_fs_copyfile(loop, &req, fixture, dst, -1, fail_cb); ASSERT(r == UV_EINVAL); uv_run(loop, UV_RUN_DEFAULT); + + /* Copies file using UV_FS_COPYFILE_FICLONE. */ + unlink(dst); + r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_FICLONE, NULL); + ASSERT(r == 0); + handle_result(&req); + + /* Copies file using UV_FS_COPYFILE_FICLONE_FORCE. */ + unlink(dst); + r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_FICLONE_FORCE, + NULL); + ASSERT(r == 0 || r == UV_ENOSYS || r == UV_ENOTSUP); + + if (r == 0) + handle_result(&req); + unlink(dst); /* Cleanup */ return 0; } diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index 39d73300dc2b61..5ddccffd0a98e9 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -129,7 +129,7 @@ static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename, ++fs_event_cb_called; ASSERT(handle == &fs_event); ASSERT(status == 0); - ASSERT(events == UV_RENAME); + ASSERT(events == UV_CHANGE); #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) ASSERT(strcmp(filename, "file1") == 0); #else @@ -477,6 +477,42 @@ TEST_IMPL(fs_event_watch_dir_recursive) { #endif } +#ifdef _WIN32 +TEST_IMPL(fs_event_watch_dir_short_path) { + uv_loop_t* loop; + int r; + + /* Setup */ + loop = uv_default_loop(); + remove("watch_dir/file1"); + remove("watch_dir/"); + create_dir("watch_dir"); + create_file("watch_dir/file1"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_cb_dir, "watch_~1", 0); + ASSERT(r == 0); + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + r = uv_timer_start(&timer, timer_cb_file, 100, 0); + ASSERT(r == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(fs_event_cb_called == 1); + ASSERT(timer_cb_called == 1); + ASSERT(close_cb_called == 1); + + /* Cleanup */ + remove("watch_dir/file1"); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + TEST_IMPL(fs_event_watch_file) { #if defined(NO_FS_EVENTS) diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 3318b86649de50..01f5a7b0236514 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -26,6 +26,7 @@ #include /* memset */ #include #include +#include /* INT_MAX, PATH_MAX, IOV_MAX */ /* FIXME we shouldn't need to branch in this file */ #if defined(__unix__) || defined(__POSIX__) || \ @@ -84,6 +85,7 @@ static int chmod_cb_count; static int fchmod_cb_count; static int chown_cb_count; static int fchown_cb_count; +static int lchown_cb_count; static int link_cb_count; static int symlink_cb_count; static int readlink_cb_count; @@ -119,6 +121,31 @@ static char test_buf[] = "test-buffer\n"; static char test_buf2[] = "second-buffer\n"; static uv_buf_t iov; +#ifdef _WIN32 +int uv_test_getiovmax(void) { + return INT32_MAX; /* Emulated by libuv, so no real limit. */ +} +#else +int uv_test_getiovmax(void) { +#if defined(IOV_MAX) + return IOV_MAX; +#elif defined(_SC_IOV_MAX) + static int iovmax = -1; + if (iovmax == -1) { + iovmax = sysconf(_SC_IOV_MAX); + /* On some embedded devices (arm-linux-uclibc based ip camera), + * sysconf(_SC_IOV_MAX) can not get the correct value. The return + * value is -1 and the errno is EINPROGRESS. Degrade the value to 1. + */ + if (iovmax == -1) iovmax = 1; + } + return iovmax; +#else + return 1024; +#endif +} +#endif + #ifdef _WIN32 /* * This tag and guid have no special meaning, and don't conflict with @@ -253,6 +280,13 @@ static void chown_cb(uv_fs_t* req) { uv_fs_req_cleanup(req); } +static void lchown_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_LCHOWN); + ASSERT(req->result == 0); + lchown_cb_count++; + uv_fs_req_cleanup(req); +} + static void chown_root_cb(uv_fs_t* req) { ASSERT(req->fs_type == UV_FS_CHOWN); #if defined(_WIN32) || defined(__MSYS__) @@ -1474,6 +1508,64 @@ TEST_IMPL(fs_unlink_readonly) { return 0; } +#ifdef _WIN32 +TEST_IMPL(fs_unlink_archive_readonly) { + int r; + uv_fs_t req; + uv_file file; + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + r = uv_fs_open(NULL, + &req, + "test_file", + O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + file = req.result; + uv_fs_req_cleanup(&req); + + iov = uv_buf_init(test_buf, sizeof(test_buf)); + r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL); + ASSERT(r == sizeof(test_buf)); + ASSERT(req.result == sizeof(test_buf)); + uv_fs_req_cleanup(&req); + + close(file); + + /* Make the file read-only and clear archive flag */ + r = SetFileAttributes("test_file", FILE_ATTRIBUTE_READONLY); + ASSERT(r != 0); + uv_fs_req_cleanup(&req); + + check_permission("test_file", 0400); + + /* Try to unlink the file */ + r = uv_fs_unlink(NULL, &req, "test_file", NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + /* + * Run the loop just to check we don't have make any extraneous uv_ref() + * calls. This should drop out immediately. + */ + uv_run(loop, UV_RUN_DEFAULT); + + /* Cleanup. */ + uv_fs_chmod(NULL, &req, "test_file", 0600, NULL); + uv_fs_req_cleanup(&req); + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif TEST_IMPL(fs_chown) { int r; @@ -1482,6 +1574,7 @@ TEST_IMPL(fs_chown) { /* Setup. */ unlink("test_file"); + unlink("test_file_link"); loop = uv_default_loop(); @@ -1525,7 +1618,29 @@ TEST_IMPL(fs_chown) { uv_run(loop, UV_RUN_DEFAULT); ASSERT(fchown_cb_count == 1); - close(file); + /* sync link */ + r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + /* sync lchown */ + r = uv_fs_lchown(NULL, &req, "test_file_link", -1, -1, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + /* async lchown */ + r = uv_fs_lchown(loop, &req, "test_file_link", -1, -1, lchown_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(lchown_cb_count == 1); + + /* Close file */ + r = uv_fs_close(NULL, &req, file, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); /* * Run the loop just to check we don't have make any extraneous uv_ref() @@ -1535,6 +1650,7 @@ TEST_IMPL(fs_chown) { /* Cleanup. */ unlink("test_file"); + unlink("test_file_link"); MAKE_VALGRIND_HAPPY(); return 0; @@ -2662,19 +2778,44 @@ TEST_IMPL(fs_write_multiple_bufs) { memset(buf, 0, sizeof(buf)); memset(buf2, 0, sizeof(buf2)); + /* Read the strings back to separate buffers. */ + iovs[0] = uv_buf_init(buf, sizeof(test_buf)); + iovs[1] = uv_buf_init(buf2, sizeof(test_buf2)); + ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0); + r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, -1, NULL); + ASSERT(r >= 0); + ASSERT(read_req.result == sizeof(test_buf) + sizeof(test_buf2)); + ASSERT(strcmp(buf, test_buf) == 0); + ASSERT(strcmp(buf2, test_buf2) == 0); + uv_fs_req_cleanup(&read_req); + + iov = uv_buf_init(buf, sizeof(buf)); + r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL); + ASSERT(r == 0); + ASSERT(read_req.result == 0); + uv_fs_req_cleanup(&read_req); + /* Read the strings back to separate buffers. */ iovs[0] = uv_buf_init(buf, sizeof(test_buf)); iovs[1] = uv_buf_init(buf2, sizeof(test_buf2)); r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, 0, NULL); ASSERT(r >= 0); - ASSERT(read_req.result >= 0); + if (read_req.result == sizeof(test_buf)) { + /* Infer that preadv is not available. */ + uv_fs_req_cleanup(&read_req); + r = uv_fs_read(NULL, &read_req, open_req1.result, &iovs[1], 1, read_req.result, NULL); + ASSERT(r >= 0); + ASSERT(read_req.result == sizeof(test_buf2)); + } else { + ASSERT(read_req.result == sizeof(test_buf) + sizeof(test_buf2)); + } ASSERT(strcmp(buf, test_buf) == 0); ASSERT(strcmp(buf2, test_buf2) == 0); uv_fs_req_cleanup(&read_req); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, - read_req.result, NULL); + sizeof(test_buf) + sizeof(test_buf2), NULL); ASSERT(r == 0); ASSERT(read_req.result == 0); uv_fs_req_cleanup(&read_req); @@ -2693,12 +2834,15 @@ TEST_IMPL(fs_write_multiple_bufs) { TEST_IMPL(fs_write_alotof_bufs) { - const size_t iovcount = 54321; + size_t iovcount; + size_t iovmax; uv_buf_t* iovs; char* buffer; size_t index; int r; + iovcount = 54321; + /* Setup. */ unlink("test_file"); @@ -2706,6 +2850,7 @@ TEST_IMPL(fs_write_alotof_bufs) { iovs = malloc(sizeof(*iovs) * iovcount); ASSERT(iovs != NULL); + iovmax = uv_test_getiovmax(); r = uv_fs_open(NULL, &open_req1, @@ -2739,7 +2884,10 @@ TEST_IMPL(fs_write_alotof_bufs) { iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf), sizeof(test_buf)); - r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, 0, NULL); + ASSERT(lseek(open_req1.result, 0, SEEK_SET) == 0); + r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, -1, NULL); + if (iovcount > iovmax) + iovcount = iovmax; ASSERT(r >= 0); ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount); @@ -2751,13 +2899,14 @@ TEST_IMPL(fs_write_alotof_bufs) { uv_fs_req_cleanup(&read_req); free(buffer); + ASSERT(lseek(open_req1.result, write_req.result, SEEK_SET) == write_req.result); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, - read_req.result, + -1, NULL); ASSERT(r == 0); ASSERT(read_req.result == 0); @@ -2778,14 +2927,19 @@ TEST_IMPL(fs_write_alotof_bufs) { TEST_IMPL(fs_write_alotof_bufs_with_offset) { - const size_t iovcount = 54321; + size_t iovcount; + size_t iovmax; uv_buf_t* iovs; char* buffer; size_t index; int r; int64_t offset; - char* filler = "0123456789"; - int filler_len = strlen(filler); + char* filler; + int filler_len; + + filler = "0123456789"; + filler_len = strlen(filler); + iovcount = 54321; /* Setup. */ unlink("test_file"); @@ -2794,6 +2948,7 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) { iovs = malloc(sizeof(*iovs) * iovcount); ASSERT(iovs != NULL); + iovmax = uv_test_getiovmax(); r = uv_fs_open(NULL, &open_req1, @@ -2837,6 +2992,10 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) { r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, offset, NULL); ASSERT(r >= 0); + if (r == sizeof(test_buf)) + iovcount = 1; /* Infer that preadv is not available. */ + else if (iovcount > iovmax) + iovcount = iovmax; ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount); for (index = 0; index < iovcount; ++index) @@ -2850,7 +3009,7 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) { r = uv_fs_stat(NULL, &stat_req, "test_file", NULL); ASSERT(r == 0); ASSERT((int64_t)((uv_stat_t*)stat_req.ptr)->st_size == - offset + (int64_t)(iovcount * sizeof(test_buf))); + offset + (int64_t)write_req.result); uv_fs_req_cleanup(&stat_req); iov = uv_buf_init(buf, sizeof(buf)); @@ -2859,7 +3018,7 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) { open_req1.result, &iov, 1, - read_req.result + offset, + offset + write_req.result, NULL); ASSERT(r == 0); ASSERT(read_req.result == 0); @@ -2879,6 +3038,175 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) { } +#ifdef _WIN32 + +TEST_IMPL(fs_partial_read) { + RETURN_SKIP("Test not implemented on Windows."); +} + +TEST_IMPL(fs_partial_write) { + RETURN_SKIP("Test not implemented on Windows."); +} + +#else /* !_WIN32 */ + +struct thread_ctx { + pthread_t pid; + int fd; + char* data; + int size; + int interval; + int doread; +}; + +static void thread_main(void* arg) { + const struct thread_ctx* ctx; + int size; + char* data; + + ctx = (struct thread_ctx*)arg; + size = ctx->size; + data = ctx->data; + + while (size > 0) { + ssize_t result; + int nbytes; + nbytes = size < ctx->interval ? size : ctx->interval; + if (ctx->doread) { + result = write(ctx->fd, data, nbytes); + /* Should not see EINTR (or other errors) */ + ASSERT(result == nbytes); + } else { + result = read(ctx->fd, data, nbytes); + /* Should not see EINTR (or other errors), + * but might get a partial read if we are faster than the writer + */ + ASSERT(result > 0 && result <= nbytes); + } + + pthread_kill(ctx->pid, SIGUSR1); + size -= result; + data += result; + } +} + +static void sig_func(uv_signal_t* handle, int signum) { + uv_signal_stop(handle); +} + +static size_t uv_test_fs_buf_offset(uv_buf_t* bufs, size_t size) { + size_t offset; + /* Figure out which bufs are done */ + for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset) + size -= bufs[offset].len; + + /* Fix a partial read/write */ + if (size > 0) { + bufs[offset].base += size; + bufs[offset].len -= size; + } + return offset; +} + +static void test_fs_partial(int doread) { + struct thread_ctx ctx; + uv_thread_t thread; + uv_signal_t signal; + int pipe_fds[2]; + size_t iovcount; + uv_buf_t* iovs; + char* buffer; + size_t index; + + iovcount = 54321; + + iovs = malloc(sizeof(*iovs) * iovcount); + ASSERT(iovs != NULL); + + ctx.pid = pthread_self(); + ctx.doread = doread; + ctx.interval = 1000; + ctx.size = sizeof(test_buf) * iovcount; + ctx.data = malloc(ctx.size); + ASSERT(ctx.data != NULL); + buffer = malloc(ctx.size); + ASSERT(buffer != NULL); + + for (index = 0; index < iovcount; ++index) + iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf), sizeof(test_buf)); + + loop = uv_default_loop(); + + ASSERT(0 == uv_signal_init(loop, &signal)); + ASSERT(0 == uv_signal_start(&signal, sig_func, SIGUSR1)); + + ASSERT(0 == pipe(pipe_fds)); + + ctx.fd = pipe_fds[doread]; + ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); + + if (doread) { + uv_buf_t* read_iovs; + int nread; + read_iovs = iovs; + nread = 0; + while (nread < ctx.size) { + int result; + result = uv_fs_read(loop, &read_req, pipe_fds[0], read_iovs, iovcount, -1, NULL); + if (result > 0) { + size_t read_iovcount; + read_iovcount = uv_test_fs_buf_offset(read_iovs, result); + read_iovs += read_iovcount; + iovcount -= read_iovcount; + nread += result; + } else { + ASSERT(result == UV_EINTR); + } + uv_fs_req_cleanup(&read_req); + } + } else { + int result; + result = uv_fs_write(loop, &write_req, pipe_fds[1], iovs, iovcount, -1, NULL); + ASSERT(write_req.result == result); + ASSERT(result == ctx.size); + uv_fs_req_cleanup(&write_req); + } + + ASSERT(0 == memcmp(buffer, ctx.data, ctx.size)); + + ASSERT(0 == uv_thread_join(&thread)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(0 == close(pipe_fds[1])); + uv_close((uv_handle_t*) &signal, NULL); + + { /* Make sure we read everything that we wrote. */ + int result; + result = uv_fs_read(loop, &read_req, pipe_fds[0], iovs, 1, -1, NULL); + ASSERT(result == 0); + uv_fs_req_cleanup(&read_req); + } + ASSERT(0 == close(pipe_fds[0])); + + free(iovs); + free(buffer); + free(ctx.data); + + MAKE_VALGRIND_HAPPY(); +} + +TEST_IMPL(fs_partial_read) { + test_fs_partial(1); + return 0; +} + +TEST_IMPL(fs_partial_write) { + test_fs_partial(0); + return 0; +} + +#endif/* _WIN32 */ + TEST_IMPL(fs_read_write_null_arguments) { int r; @@ -2979,6 +3307,52 @@ TEST_IMPL(get_osfhandle_valid_handle) { return 0; } +TEST_IMPL(open_osfhandle_valid_handle) { + int r; + uv_os_fd_t handle; + int fd; + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + r = uv_fs_open(NULL, + &open_req1, + "test_file", + O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + handle = uv_get_osfhandle(open_req1.result); +#ifdef _WIN32 + ASSERT(handle != INVALID_HANDLE_VALUE); +#else + ASSERT(handle >= 0); +#endif + + fd = uv_open_osfhandle(handle); +#ifdef _WIN32 + ASSERT(fd > 0); +#else + ASSERT(fd == open_req1.result); +#endif + + r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + /* Cleanup. */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + TEST_IMPL(fs_file_pos_after_op_with_offset) { int r; @@ -3172,3 +3546,138 @@ TEST_IMPL(fs_exclusive_sharing_mode) { return 0; } #endif + +#ifdef _WIN32 +int call_icacls(const char* command, ...) { + char icacls_command[1024]; + va_list args; + + va_start(args, command); + vsnprintf(icacls_command, ARRAYSIZE(icacls_command), command, args); + va_end(args); + return system(icacls_command); +} + +TEST_IMPL(fs_open_readonly_acl) { + uv_passwd_t pwd; + uv_fs_t req; + int r; + + /* + Based on Node.js test from + https://github.com/nodejs/node/commit/3ba81e34e86a5c32658e218cb6e65b13e8326bc5 + + If anything goes wrong, you can delte the test_fle_icacls with: + + icacls test_file_icacls /remove "%USERNAME%" /inheritance:e + attrib -r test_file_icacls + del test_file_icacls + */ + + /* Setup - clear the ACL and remove the file */ + loop = uv_default_loop(); + r = uv_os_get_passwd(&pwd); + ASSERT(r == 0); + call_icacls("icacls test_file_icacls /remove \"%s\" /inheritance:e", + pwd.username); + uv_fs_chmod(loop, &req, "test_file_icacls", S_IWUSR, NULL); + unlink("test_file_icacls"); + + /* Create the file */ + r = uv_fs_open(loop, + &open_req1, + "test_file_icacls", + O_RDONLY | O_CREAT, + S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + /* Set up ACL */ + r = call_icacls("icacls test_file_icacls /inheritance:r /remove \"%s\"", + pwd.username); + if (r != 0) { + goto acl_cleanup; + } + r = call_icacls("icacls test_file_icacls /grant \"%s\":RX", pwd.username); + if (r != 0) { + goto acl_cleanup; + } + + /* Try opening the file */ + r = uv_fs_open(NULL, &open_req1, "test_file_icacls", O_RDONLY, 0, NULL); + if (r < 0) { + goto acl_cleanup; + } + uv_fs_req_cleanup(&open_req1); + r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); + if (r != 0) { + goto acl_cleanup; + } + uv_fs_req_cleanup(&close_req); + + acl_cleanup: + /* Cleanup */ + call_icacls("icacls test_file_icacls /remove \"%s\" /inheritance:e", + pwd.username); + unlink("test_file_icacls"); + uv_os_free_passwd(&pwd); + ASSERT(r == 0); + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + +#ifdef _WIN32 +TEST_IMPL(fs_fchmod_archive_readonly) { + uv_fs_t req; + uv_file file; + int r; + /* Test clearing read-only flag from files with Archive flag cleared */ + + /* Setup*/ + unlink("test_file"); + r = uv_fs_open(NULL, + &req, + "test_file", + O_WRONLY | O_CREAT, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + file = req.result; + uv_fs_req_cleanup(&req); + r = uv_fs_close(NULL, &req, file, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + /* Make the file read-only and clear archive flag */ + r = SetFileAttributes("test_file", FILE_ATTRIBUTE_READONLY); + ASSERT(r != 0); + check_permission("test_file", 0400); + /* Try fchmod */ + r = uv_fs_open(NULL, &req, "test_file", O_RDONLY, 0, NULL); + ASSERT(r >= 0); + ASSERT(req.result >= 0); + file = req.result; + uv_fs_req_cleanup(&req); + r = uv_fs_fchmod(NULL, &req, file, S_IWUSR, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + r = uv_fs_close(NULL, &req, file, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + check_permission("test_file", S_IWUSR); + + /* Restore Archive flag for rest of the tests */ + r = SetFileAttributes("test_file", FILE_ATTRIBUTE_ARCHIVE); + ASSERT(r != 0); + + return 0; +} +#endif diff --git a/deps/uv/test/test-handle-fileno.c b/deps/uv/test/test-handle-fileno.c index 3fe933adebdd87..8a093e2ea46e2c 100644 --- a/deps/uv/test/test-handle-fileno.c +++ b/deps/uv/test/test-handle-fileno.c @@ -27,7 +27,7 @@ static int get_tty_fd(void) { /* Make sure we have an FD that refers to a tty */ #ifdef _WIN32 HANDLE handle; - handle = CreateFileA("conout$", + handle = CreateFileA("conin$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, @@ -107,11 +107,15 @@ TEST_IMPL(handle_fileno) { } else { r = uv_tty_init(loop, &tty, tty_fd, 0); ASSERT(r == 0); + ASSERT(uv_is_readable((uv_stream_t*) &tty)); + ASSERT(!uv_is_writable((uv_stream_t*) &tty)); r = uv_fileno((uv_handle_t*) &tty, &fd); ASSERT(r == 0); uv_close((uv_handle_t*) &tty, NULL); r = uv_fileno((uv_handle_t*) &tty, &fd); ASSERT(r == UV_EBADF); + ASSERT(!uv_is_readable((uv_stream_t*) &tty)); + ASSERT(!uv_is_writable((uv_stream_t*) &tty)); } uv_run(loop, UV_RUN_DEFAULT); diff --git a/deps/uv/test/test-hrtime.c b/deps/uv/test/test-hrtime.c index 72a4d4b181db4e..fbe9a68bfc70d2 100644 --- a/deps/uv/test/test-hrtime.c +++ b/deps/uv/test/test-hrtime.c @@ -43,9 +43,9 @@ TEST_IMPL(hrtime) { /* printf("i= %d diff = %llu\n", i, (unsigned long long int) diff); */ - /* The windows Sleep() function has only a resolution of 10-20 ms. */ - /* Check that the difference between the two hrtime values is somewhat in */ - /* the range we expect it to be. */ + /* The windows Sleep() function has only a resolution of 10-20 ms. Check + * that the difference between the two hrtime values is somewhat in the + * range we expect it to be. */ ASSERT(diff > (uint64_t) 25 * NANOSEC / MILLISEC); ASSERT(diff < (uint64_t) 80 * NANOSEC / MILLISEC); --i; diff --git a/deps/uv/test/test-ipc-heavy-traffic-deadlock-bug.c b/deps/uv/test/test-ipc-heavy-traffic-deadlock-bug.c new file mode 100644 index 00000000000000..240fc64588b413 --- /dev/null +++ b/deps/uv/test/test-ipc-heavy-traffic-deadlock-bug.c @@ -0,0 +1,158 @@ +/* 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 "task.h" +#include "uv.h" + +#include + +/* See test-ipc.c */ +void spawn_helper(uv_pipe_t* channel, + uv_process_t* process, + const char* helper); + +#define NUM_WRITES 256 +#define BUFFERS_PER_WRITE 3 +#define BUFFER_SIZE 0x2000 /* 8 kb. */ +#define BUFFER_CONTENT 42 + +#define XFER_SIZE (NUM_WRITES * BUFFERS_PER_WRITE * BUFFER_SIZE) + +struct write_info { + uv_write_t write_req; + char buffers[BUFFER_SIZE][BUFFERS_PER_WRITE]; +}; + +static uv_shutdown_t shutdown_req; + +static size_t bytes_written; +static size_t bytes_read; + +static void write_cb(uv_write_t* req, int status) { + struct write_info* write_info = + container_of(req, struct write_info, write_req); + ASSERT(status == 0); + bytes_written += BUFFERS_PER_WRITE * BUFFER_SIZE; + free(write_info); +} + +static void shutdown_cb(uv_shutdown_t* req, int status) { + ASSERT(status == 0); + uv_close((uv_handle_t*) req->handle, NULL); +} + +static void do_write(uv_stream_t* handle) { + struct write_info* write_info; + uv_buf_t bufs[BUFFERS_PER_WRITE]; + size_t i; + int r; + + write_info = malloc(sizeof *write_info); + ASSERT(write_info != NULL); + + for (i = 0; i < BUFFERS_PER_WRITE; i++) { + memset(&write_info->buffers[i], BUFFER_CONTENT, BUFFER_SIZE); + bufs[i] = uv_buf_init(write_info->buffers[i], BUFFER_SIZE); + } + + r = uv_write( + &write_info->write_req, handle, bufs, BUFFERS_PER_WRITE, write_cb); + ASSERT(r == 0); +} + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = (int) suggested_size; +} + +#ifndef _WIN32 +#include +#include +#endif + +static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { + ssize_t i; + int r; + + ASSERT(nread >= 0); + bytes_read += nread; + + for (i = 0; i < nread; i++) + ASSERT(buf->base[i] == BUFFER_CONTENT); + free(buf->base); + + if (bytes_read >= XFER_SIZE) { + r = uv_read_stop(handle); + ASSERT(r == 0); + r = uv_shutdown(&shutdown_req, handle, shutdown_cb); + ASSERT(r == 0); + } +} + +static void do_writes_and_reads(uv_stream_t* handle) { + size_t i; + int r; + + bytes_written = 0; + bytes_read = 0; + + for (i = 0; i < NUM_WRITES; i++) { + do_write(handle); + } + + r = uv_read_start(handle, alloc_cb, read_cb); + ASSERT(r == 0); + + r = uv_run(handle->loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(bytes_written == XFER_SIZE); + ASSERT(bytes_read == XFER_SIZE); +} + +TEST_IMPL(ipc_heavy_traffic_deadlock_bug) { + uv_pipe_t pipe; + uv_process_t process; + + spawn_helper(&pipe, &process, "ipc_helper_heavy_traffic_deadlock_bug"); + do_writes_and_reads((uv_stream_t*) &pipe); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +int ipc_helper_heavy_traffic_deadlock_bug(void) { + uv_pipe_t pipe; + int r; + + r = uv_pipe_init(uv_default_loop(), &pipe, 1); + ASSERT(r == 0); + r = uv_pipe_open(&pipe, 0); + ASSERT(r == 0); + + do_writes_and_reads((uv_stream_t*) &pipe); + uv_sleep(100); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-ipc-send-recv.c b/deps/uv/test/test-ipc-send-recv.c index 917744cbaed978..3dedc86b8b0170 100644 --- a/deps/uv/test/test-ipc-send-recv.c +++ b/deps/uv/test/test-ipc-send-recv.c @@ -25,7 +25,7 @@ #include #include -/* See test-ipc.ctx */ +/* See test-ipc.c */ void spawn_helper(uv_pipe_t* channel, uv_process_t* process, const char* helper); @@ -149,6 +149,7 @@ static void connect_cb(uv_connect_t* req, int status) { &ctx.send.stream, NULL); ASSERT(r == 0); + ASSERT(ctx.write_req.send_handle == &ctx.send.stream); /* Perform two writes to the same pipe to make sure that on Windows we are * not running into issue 505: @@ -160,6 +161,7 @@ static void connect_cb(uv_connect_t* req, int status) { &ctx.send2.stream, NULL); ASSERT(r == 0); + ASSERT(ctx.write_req2.send_handle == &ctx.send2.stream); r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb); ASSERT(r == 0); @@ -344,6 +346,7 @@ static void read_cb(uv_stream_t* handle, &recv->stream, write2_cb); ASSERT(r == 0); + ASSERT(write_req->send_handle == &recv->stream); } while (uv_pipe_pending_count(pipe) > 0); } diff --git a/deps/uv/test/test-ipc.c b/deps/uv/test/test-ipc.c index 88d63d4dc670a7..200f68d6000a77 100644 --- a/deps/uv/test/test-ipc.c +++ b/deps/uv/test/test-ipc.c @@ -281,7 +281,7 @@ void spawn_helper(uv_pipe_t* channel, char exepath[1024]; char* args[3]; int r; - uv_stdio_container_t stdio[1]; + uv_stdio_container_t stdio[3]; r = uv_pipe_init(uv_default_loop(), channel, 1); ASSERT(r == 0); @@ -300,12 +300,15 @@ void spawn_helper(uv_pipe_t* channel, options.file = exepath; options.args = args; options.exit_cb = exit_cb; - options.stdio = stdio; - options.stdio[0].flags = UV_CREATE_PIPE | - UV_READABLE_PIPE | UV_WRITABLE_PIPE; - options.stdio[0].data.stream = (uv_stream_t*)channel; - options.stdio_count = 1; + options.stdio_count = ARRAY_SIZE(stdio); + + stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE; + stdio[0].data.stream = (uv_stream_t*) channel; + stdio[1].flags = UV_INHERIT_FD; + stdio[1].data.fd = 1; + stdio[2].flags = UV_INHERIT_FD; + stdio[2].data.fd = 2; r = uv_spawn(uv_default_loop(), process, &options); ASSERT(r == 0); diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index ff0a31d16bb940..1bd062da3d2e4b 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -37,12 +37,13 @@ TEST_DECLARE (default_loop_close) TEST_DECLARE (barrier_1) TEST_DECLARE (barrier_2) TEST_DECLARE (barrier_3) +TEST_DECLARE (barrier_serial_thread) +TEST_DECLARE (barrier_serial_thread_single) TEST_DECLARE (condvar_1) TEST_DECLARE (condvar_2) TEST_DECLARE (condvar_3) TEST_DECLARE (condvar_4) TEST_DECLARE (condvar_5) -TEST_DECLARE (condvar_6) TEST_DECLARE (semaphore_1) TEST_DECLARE (semaphore_2) TEST_DECLARE (semaphore_3) @@ -51,12 +52,14 @@ TEST_DECLARE (tty) TEST_DECLARE (tty_raw) TEST_DECLARE (tty_empty_write) TEST_DECLARE (tty_large_write) +TEST_DECLARE (tty_raw_cancel) #endif TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) TEST_DECLARE (stdio_over_pipes) TEST_DECLARE (ip6_pton) TEST_DECLARE (connect_unspecified) +TEST_DECLARE (ipc_heavy_traffic_deadlock_bug) TEST_DECLARE (ipc_listen_before_write) TEST_DECLARE (ipc_listen_after_write) #ifndef _WIN32 @@ -71,8 +74,11 @@ TEST_DECLARE (ipc_closed_handle) #endif TEST_DECLARE (tcp_alloc_cb_fail) TEST_DECLARE (tcp_ping_pong) -TEST_DECLARE (tcp_ping_pong_v6) +TEST_DECLARE (tcp_ping_pong_vec) +TEST_DECLARE (tcp6_ping_pong) +TEST_DECLARE (tcp6_ping_pong_vec) TEST_DECLARE (pipe_ping_pong) +TEST_DECLARE (pipe_ping_pong_vec) TEST_DECLARE (delayed_accept) TEST_DECLARE (multiple_listen) #ifndef _WIN32 @@ -95,6 +101,7 @@ TEST_DECLARE (tcp_bind_error_fault) TEST_DECLARE (tcp_bind_error_inval) TEST_DECLARE (tcp_bind_localhost_ok) TEST_DECLARE (tcp_bind_invalid_flags) +TEST_DECLARE (tcp_bind_writable_flags) TEST_DECLARE (tcp_listen_without_bind) TEST_DECLARE (tcp_connect_error_fault) TEST_DECLARE (tcp_connect_timeout) @@ -117,6 +124,7 @@ TEST_DECLARE (tcp_bind6_error_addrnotavail) TEST_DECLARE (tcp_bind6_error_fault) TEST_DECLARE (tcp_bind6_error_inval) TEST_DECLARE (tcp_bind6_localhost_ok) +TEST_DECLARE (tcp_write_ready) TEST_DECLARE (udp_alloc_cb_fail) TEST_DECLARE (udp_bind) TEST_DECLARE (udp_bind_reuseaddr) @@ -209,6 +217,7 @@ TEST_DECLARE (pipe_close_stdout_read_stdin) TEST_DECLARE (pipe_set_non_blocking) TEST_DECLARE (pipe_set_chmod) TEST_DECLARE (process_ref) +TEST_DECLARE (process_priority) TEST_DECLARE (has_ref) TEST_DECLARE (active) TEST_DECLARE (embed) @@ -283,6 +292,9 @@ TEST_DECLARE (fs_access) TEST_DECLARE (fs_chmod) TEST_DECLARE (fs_copyfile) TEST_DECLARE (fs_unlink_readonly) +#ifdef _WIN32 +TEST_DECLARE (fs_unlink_archive_readonly) +#endif TEST_DECLARE (fs_chown) TEST_DECLARE (fs_link) TEST_DECLARE (fs_readlink) @@ -300,6 +312,9 @@ TEST_DECLARE (fs_stat_missing_path) TEST_DECLARE (fs_read_file_eof) TEST_DECLARE (fs_event_watch_dir) TEST_DECLARE (fs_event_watch_dir_recursive) +#ifdef _WIN32 +TEST_DECLARE (fs_event_watch_dir_short_path) +#endif TEST_DECLARE (fs_event_watch_file) TEST_DECLARE (fs_event_watch_file_exact_path) TEST_DECLARE (fs_event_watch_file_twice) @@ -324,12 +339,17 @@ TEST_DECLARE (fs_rename_to_existing_file) TEST_DECLARE (fs_write_multiple_bufs) TEST_DECLARE (fs_read_write_null_arguments) TEST_DECLARE (get_osfhandle_valid_handle) +TEST_DECLARE (open_osfhandle_valid_handle) TEST_DECLARE (fs_write_alotof_bufs) TEST_DECLARE (fs_write_alotof_bufs_with_offset) +TEST_DECLARE (fs_partial_read) +TEST_DECLARE (fs_partial_write) TEST_DECLARE (fs_file_pos_after_op_with_offset) TEST_DECLARE (fs_null_req) #ifdef _WIN32 TEST_DECLARE (fs_exclusive_sharing_mode) +TEST_DECLARE (fs_open_readonly_acl) +TEST_DECLARE (fs_fchmod_archive_readonly) #endif TEST_DECLARE (threadpool_queue_work_simple) TEST_DECLARE (threadpool_queue_work_einval) @@ -441,12 +461,13 @@ TASK_LIST_START TEST_ENTRY (barrier_1) TEST_ENTRY (barrier_2) TEST_ENTRY (barrier_3) + TEST_ENTRY (barrier_serial_thread) + TEST_ENTRY (barrier_serial_thread_single) TEST_ENTRY (condvar_1) TEST_ENTRY (condvar_2) TEST_ENTRY (condvar_3) TEST_ENTRY (condvar_4) TEST_ENTRY (condvar_5) - TEST_ENTRY (condvar_6) TEST_ENTRY (semaphore_1) TEST_ENTRY (semaphore_2) TEST_ENTRY (semaphore_3) @@ -466,12 +487,14 @@ TASK_LIST_START TEST_ENTRY (tty_raw) TEST_ENTRY (tty_empty_write) TEST_ENTRY (tty_large_write) + TEST_ENTRY (tty_raw_cancel) #endif TEST_ENTRY (tty_file) TEST_ENTRY (tty_pty) TEST_ENTRY (stdio_over_pipes) TEST_ENTRY (ip6_pton) TEST_ENTRY (connect_unspecified) + TEST_ENTRY (ipc_heavy_traffic_deadlock_bug) TEST_ENTRY (ipc_listen_before_write) TEST_ENTRY (ipc_listen_after_write) #ifndef _WIN32 @@ -490,12 +513,21 @@ TASK_LIST_START TEST_ENTRY (tcp_ping_pong) TEST_HELPER (tcp_ping_pong, tcp4_echo_server) - TEST_ENTRY (tcp_ping_pong_v6) - TEST_HELPER (tcp_ping_pong_v6, tcp6_echo_server) + TEST_ENTRY (tcp_ping_pong_vec) + TEST_HELPER (tcp_ping_pong_vec, tcp4_echo_server) + + TEST_ENTRY (tcp6_ping_pong) + TEST_HELPER (tcp6_ping_pong, tcp6_echo_server) + + TEST_ENTRY (tcp6_ping_pong_vec) + TEST_HELPER (tcp6_ping_pong_vec, tcp6_echo_server) TEST_ENTRY (pipe_ping_pong) TEST_HELPER (pipe_ping_pong, pipe_echo_server) + TEST_ENTRY (pipe_ping_pong_vec) + TEST_HELPER (pipe_ping_pong_vec, pipe_echo_server) + TEST_ENTRY (delayed_accept) TEST_ENTRY (multiple_listen) @@ -523,6 +555,8 @@ TASK_LIST_START TEST_ENTRY (tcp_open_bound) TEST_ENTRY (tcp_open_connected) TEST_HELPER (tcp_open_connected, tcp4_echo_server) + TEST_ENTRY (tcp_write_ready) + TEST_HELPER (tcp_write_ready, tcp4_echo_server) TEST_ENTRY (tcp_shutdown_after_write) TEST_HELPER (tcp_shutdown_after_write, tcp4_echo_server) @@ -535,6 +569,7 @@ TASK_LIST_START TEST_ENTRY (tcp_bind_error_inval) TEST_ENTRY (tcp_bind_localhost_ok) TEST_ENTRY (tcp_bind_invalid_flags) + TEST_ENTRY (tcp_bind_writable_flags) TEST_ENTRY (tcp_listen_without_bind) TEST_ENTRY (tcp_connect_error_fault) TEST_ENTRY (tcp_connect_timeout) @@ -663,6 +698,7 @@ TASK_LIST_START TEST_ENTRY (pipe_ref4) TEST_HELPER (pipe_ref4, pipe_echo_server) TEST_ENTRY (process_ref) + TEST_ENTRY (process_priority) TEST_ENTRY (has_ref) TEST_ENTRY (loop_handles) @@ -700,7 +736,7 @@ TASK_LIST_START TEST_ENTRY (hrtime) TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000) - TEST_ENTRY (getaddrinfo_fail_sync) + TEST_ENTRY_CUSTOM (getaddrinfo_fail_sync, 0, 0, 10000) TEST_ENTRY (getaddrinfo_basic) TEST_ENTRY (getaddrinfo_basic_sync) @@ -810,6 +846,9 @@ TASK_LIST_START TEST_ENTRY (fs_chmod) TEST_ENTRY (fs_copyfile) TEST_ENTRY (fs_unlink_readonly) +#ifdef _WIN32 + TEST_ENTRY (fs_unlink_archive_readonly) +#endif TEST_ENTRY (fs_chown) TEST_ENTRY (fs_utime) TEST_ENTRY (fs_futime) @@ -826,6 +865,9 @@ TASK_LIST_START TEST_ENTRY (fs_file_open_append) TEST_ENTRY (fs_event_watch_dir) TEST_ENTRY (fs_event_watch_dir_recursive) +#ifdef _WIN32 + TEST_ENTRY (fs_event_watch_dir_short_path) +#endif TEST_ENTRY (fs_event_watch_file) TEST_ENTRY (fs_event_watch_file_exact_path) TEST_ENTRY (fs_event_watch_file_twice) @@ -850,13 +892,18 @@ TASK_LIST_START TEST_ENTRY (fs_write_multiple_bufs) TEST_ENTRY (fs_write_alotof_bufs) TEST_ENTRY (fs_write_alotof_bufs_with_offset) + TEST_ENTRY (fs_partial_read) + TEST_ENTRY (fs_partial_write) TEST_ENTRY (fs_read_write_null_arguments) TEST_ENTRY (fs_file_pos_after_op_with_offset) TEST_ENTRY (fs_null_req) #ifdef _WIN32 TEST_ENTRY (fs_exclusive_sharing_mode) + TEST_ENTRY (fs_open_readonly_acl) + TEST_ENTRY (fs_fchmod_archive_readonly) #endif TEST_ENTRY (get_osfhandle_valid_handle) + TEST_ENTRY (open_osfhandle_valid_handle) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) TEST_ENTRY (threadpool_multiple_event_loops) diff --git a/deps/uv/test/test-loop-handles.c b/deps/uv/test/test-loop-handles.c index c3e8498ae90a6b..6471cd08b32fc4 100644 --- a/deps/uv/test/test-loop-handles.c +++ b/deps/uv/test/test-loop-handles.c @@ -228,8 +228,8 @@ static void check_cb(uv_check_t* handle) { uv_close((uv_handle_t*)&idle_1_handles[i], idle_1_close_cb); } - /* This handle is closed/recreated every time, close it only if it is */ - /* active.*/ + /* This handle is closed/recreated every time, close it only if it is + * active. */ if (idle_2_is_active) { uv_close((uv_handle_t*)&idle_2_handle, idle_2_close_cb); } @@ -246,10 +246,10 @@ static void prepare_2_cb(uv_prepare_t* handle) { fflush(stderr); ASSERT(handle == &prepare_2_handle); - /* prepare_2 gets started by prepare_1 when (loop_iteration % 2 == 0), */ - /* and it stops itself immediately. A started watcher is not queued */ - /* until the next round, so when this callback is made */ - /* (loop_iteration % 2 == 0) cannot be true. */ + /* Prepare_2 gets started by prepare_1 when (loop_iteration % 2 == 0), and it + * stops itself immediately. A started watcher is not queued until the next + * round, so when this callback is made (loop_iteration % 2 == 0) cannot be + * true. */ ASSERT(loop_iteration % 2 != 0); r = uv_prepare_stop((uv_prepare_t*)handle); @@ -304,8 +304,8 @@ TEST_IMPL(loop_handles) { /* don't init or start idle_2, both is done by idle_1_cb */ - /* the timer callback is there to keep the event loop polling */ - /* unref it as it is not supposed to keep the loop alive */ + /* The timer callback is there to keep the event loop polling unref it as it + * is not supposed to keep the loop alive */ r = uv_timer_init(uv_default_loop(), &timer_handle); ASSERT(r == 0); r = uv_timer_start(&timer_handle, timer_cb, TIMEOUT, TIMEOUT); diff --git a/deps/uv/test/test-ping-pong.c b/deps/uv/test/test-ping-pong.c index 508f0db67bcf77..c86a3f4a66592f 100644 --- a/deps/uv/test/test-ping-pong.c +++ b/deps/uv/test/test-ping-pong.c @@ -22,8 +22,8 @@ #include "uv.h" #include "task.h" -#include #include +#include static int completed_pingers = 0; @@ -41,6 +41,7 @@ static int pinger_on_connect_count; typedef struct { + int vectored_writes; int pongs; int state; union { @@ -77,15 +78,26 @@ static void pinger_after_write(uv_write_t *req, int status) { static void pinger_write_ping(pinger_t* pinger) { uv_write_t *req; - uv_buf_t buf; - - buf = uv_buf_init(PING, sizeof(PING) - 1); + uv_buf_t bufs[sizeof PING - 1]; + int i, nbufs; + + if (!pinger->vectored_writes) { + /* Write a single buffer. */ + nbufs = 1; + bufs[0] = uv_buf_init(PING, sizeof PING - 1); + } else { + /* Write multiple buffers, each with one byte in them. */ + nbufs = sizeof PING - 1; + for (i = 0; i < nbufs; i++) { + bufs[i] = uv_buf_init(&PING[i], 1); + } + } req = malloc(sizeof(*req)); if (uv_write(req, (uv_stream_t*) &pinger->stream.tcp, - &buf, - 1, + bufs, + nbufs, pinger_after_write)) { FATAL("uv_write failed"); } @@ -154,7 +166,7 @@ static void pinger_on_connect(uv_connect_t *req, int status) { /* same ping-pong test, but using IPv6 connection */ -static void tcp_pinger_v6_new(void) { +static void tcp_pinger_v6_new(int vectored_writes) { int r; struct sockaddr_in6 server_addr; pinger_t *pinger; @@ -163,6 +175,7 @@ static void tcp_pinger_v6_new(void) { ASSERT(0 ==uv_ip6_addr("::1", TEST_PORT, &server_addr)); pinger = malloc(sizeof(*pinger)); ASSERT(pinger != NULL); + pinger->vectored_writes = vectored_writes; pinger->state = 0; pinger->pongs = 0; @@ -171,8 +184,8 @@ static void tcp_pinger_v6_new(void) { pinger->stream.tcp.data = pinger; ASSERT(!r); - /* We are never doing multiple reads/connects at a time anyway. */ - /* so these handles can be pre-initialized. */ + /* We are never doing multiple reads/connects at a time anyway, so these + * handles can be pre-initialized. */ r = uv_tcp_connect(&pinger->connect_req, &pinger->stream.tcp, (const struct sockaddr*) &server_addr, @@ -184,7 +197,7 @@ static void tcp_pinger_v6_new(void) { } -static void tcp_pinger_new(void) { +static void tcp_pinger_new(int vectored_writes) { int r; struct sockaddr_in server_addr; pinger_t *pinger; @@ -192,6 +205,7 @@ static void tcp_pinger_new(void) { ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); pinger = malloc(sizeof(*pinger)); ASSERT(pinger != NULL); + pinger->vectored_writes = vectored_writes; pinger->state = 0; pinger->pongs = 0; @@ -200,8 +214,8 @@ static void tcp_pinger_new(void) { pinger->stream.tcp.data = pinger; ASSERT(!r); - /* We are never doing multiple reads/connects at a time anyway. */ - /* so these handles can be pre-initialized. */ + /* We are never doing multiple reads/connects at a time anyway, so these + * handles can be pre-initialized. */ r = uv_tcp_connect(&pinger->connect_req, &pinger->stream.tcp, (const struct sockaddr*) &server_addr, @@ -213,12 +227,13 @@ static void tcp_pinger_new(void) { } -static void pipe_pinger_new(void) { +static void pipe_pinger_new(int vectored_writes) { int r; pinger_t *pinger; pinger = (pinger_t*)malloc(sizeof(*pinger)); ASSERT(pinger != NULL); + pinger->vectored_writes = vectored_writes; pinger->state = 0; pinger->pongs = 0; @@ -227,9 +242,8 @@ static void pipe_pinger_new(void) { pinger->stream.pipe.data = pinger; ASSERT(!r); - /* We are never doing multiple reads/connects at a time anyway. */ - /* so these handles can be pre-initialized. */ - + /* We are never doing multiple reads/connects at a time anyway, so these + * handles can be pre-initialized. */ uv_pipe_connect(&pinger->connect_req, &pinger->stream.pipe, TEST_PIPENAME, pinger_on_connect); @@ -238,10 +252,8 @@ static void pipe_pinger_new(void) { } -TEST_IMPL(tcp_ping_pong) { - tcp_pinger_new(); +static int run_ping_pong_test(void) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(completed_pingers == 1); MAKE_VALGRIND_HAPPY(); @@ -249,26 +261,41 @@ TEST_IMPL(tcp_ping_pong) { } -TEST_IMPL(tcp_ping_pong_v6) { +TEST_IMPL(tcp_ping_pong) { + tcp_pinger_new(0); + return run_ping_pong_test(); +} + + +TEST_IMPL(tcp_ping_pong_vec) { + tcp_pinger_new(1); + return run_ping_pong_test(); +} + + +TEST_IMPL(tcp6_ping_pong) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); + tcp_pinger_v6_new(0); + return run_ping_pong_test(); +} - tcp_pinger_v6_new(); - uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(completed_pingers == 1); - - MAKE_VALGRIND_HAPPY(); - return 0; +TEST_IMPL(tcp6_ping_pong_vec) { + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + tcp_pinger_v6_new(1); + return run_ping_pong_test(); } TEST_IMPL(pipe_ping_pong) { - pipe_pinger_new(); - uv_run(uv_default_loop(), UV_RUN_DEFAULT); + pipe_pinger_new(0); + return run_ping_pong_test(); +} - ASSERT(completed_pingers == 1); - MAKE_VALGRIND_HAPPY(); - return 0; +TEST_IMPL(pipe_ping_pong_vec) { + pipe_pinger_new(1); + return run_ping_pong_test(); } diff --git a/deps/uv/test/test-pipe-close-stdout-read-stdin.c b/deps/uv/test/test-pipe-close-stdout-read-stdin.c index 4ab14789a3858b..c8804b0e189249 100644 --- a/deps/uv/test/test-pipe-close-stdout-read-stdin.c +++ b/deps/uv/test/test-pipe-close-stdout-read-stdin.c @@ -66,7 +66,8 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { */ close(fd[1]); /* block until write end of pipe is closed */ - read(fd[0], &buf, 1); + r = read(fd[0], &buf, 1); + ASSERT(-1 <= r && r <= 1); close(0); r = dup(fd[0]); ASSERT(r != -1); diff --git a/deps/uv/test/test-pipe-set-fchmod.c b/deps/uv/test/test-pipe-set-fchmod.c index 59f0e6f5454f89..91e476652e027f 100644 --- a/deps/uv/test/test-pipe-set-fchmod.c +++ b/deps/uv/test/test-pipe-set-fchmod.c @@ -27,6 +27,9 @@ TEST_IMPL(pipe_set_chmod) { uv_pipe_t pipe_handle; uv_loop_t* loop; int r; +#ifndef _WIN32 + struct stat stat_buf; +#endif loop = uv_default_loop(); @@ -36,20 +39,41 @@ TEST_IMPL(pipe_set_chmod) { r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME); ASSERT(r == 0); - /* No easy way to test if this works, we will only make sure that */ - /* the call is successful. */ + /* No easy way to test if this works, we will only make sure that the call is + * successful. */ r = uv_pipe_chmod(&pipe_handle, UV_READABLE); if (r == UV_EPERM) { MAKE_VALGRIND_HAPPY(); RETURN_SKIP("Insufficient privileges to alter pipe fmode"); } ASSERT(r == 0); +#ifndef _WIN32 + stat(TEST_PIPENAME, &stat_buf); + ASSERT(stat_buf.st_mode & S_IRUSR); + ASSERT(stat_buf.st_mode & S_IRGRP); + ASSERT(stat_buf.st_mode & S_IROTH); +#endif r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE); ASSERT(r == 0); +#ifndef _WIN32 + stat(TEST_PIPENAME, &stat_buf); + ASSERT(stat_buf.st_mode & S_IWUSR); + ASSERT(stat_buf.st_mode & S_IWGRP); + ASSERT(stat_buf.st_mode & S_IWOTH); +#endif r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); ASSERT(r == 0); +#ifndef _WIN32 + stat(TEST_PIPENAME, &stat_buf); + ASSERT(stat_buf.st_mode & S_IRUSR); + ASSERT(stat_buf.st_mode & S_IRGRP); + ASSERT(stat_buf.st_mode & S_IROTH); + ASSERT(stat_buf.st_mode & S_IWUSR); + ASSERT(stat_buf.st_mode & S_IWGRP); + ASSERT(stat_buf.st_mode & S_IWOTH); +#endif r = uv_pipe_chmod(NULL, UV_WRITABLE | UV_READABLE); ASSERT(r == UV_EBADF); diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c index e828addbb48225..0d1b1d7ec9540c 100644 --- a/deps/uv/test/test-poll.c +++ b/deps/uv/test/test-poll.c @@ -134,7 +134,10 @@ static void close_socket(uv_os_sock_t sock) { #else r = close(sock); #endif - ASSERT(r == 0); + /* On FreeBSD close() can fail with ECONNRESET if the socket was shutdown by + * the peer before all pending data was delivered. + */ + ASSERT(r == 0 || errno == ECONNRESET); } diff --git a/deps/uv/test/test-process-priority.c b/deps/uv/test/test-process-priority.c new file mode 100644 index 00000000000000..b3d0a85bdd70ec --- /dev/null +++ b/deps/uv/test/test-process-priority.c @@ -0,0 +1,83 @@ +/* Copyright libuv contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + + +TEST_IMPL(process_priority) { + int priority; + int r; + int i; + +#if defined(__MVS__) + if (uv_os_setpriority(0, 0) == UV_ENOSYS) + RETURN_SKIP("functionality not supported on zOS"); +#endif + + /* Verify that passing a NULL pointer returns UV_EINVAL. */ + r = uv_os_getpriority(0, NULL); + ASSERT(r == UV_EINVAL); + + /* Verify that all valid values work. */ + for (i = UV_PRIORITY_HIGHEST; i <= UV_PRIORITY_LOW; i++) { + r = uv_os_setpriority(0, i); + + /* If UV_EACCES is returned, the current user doesn't have permission to + set this specific priority. */ + if (r == UV_EACCES) + continue; + + ASSERT(r == 0); + ASSERT(uv_os_getpriority(0, &priority) == 0); + + /* Verify that the priority values match on Unix, and are range mapped + on Windows. */ +#ifndef _WIN32 + ASSERT(priority == i); +#else + /* On Windows, only elevated users can set UV_PRIORITY_HIGHEST. Other + users will silently be set to UV_PRIORITY_HIGH. */ + if (i < UV_PRIORITY_HIGH) + ASSERT(priority == UV_PRIORITY_HIGHEST || priority == UV_PRIORITY_HIGH); + else if (i < UV_PRIORITY_ABOVE_NORMAL) + ASSERT(priority == UV_PRIORITY_HIGH); + else if (i < UV_PRIORITY_NORMAL) + ASSERT(priority == UV_PRIORITY_ABOVE_NORMAL); + else if (i < UV_PRIORITY_BELOW_NORMAL) + ASSERT(priority == UV_PRIORITY_NORMAL); + else if (i < UV_PRIORITY_LOW) + ASSERT(priority == UV_PRIORITY_BELOW_NORMAL); + else + ASSERT(priority == UV_PRIORITY_LOW); +#endif + + /* Verify that the current PID and 0 are equivalent. */ + ASSERT(uv_os_getpriority(uv_os_getpid(), &r) == 0); + ASSERT(priority == r); + } + + /* Verify that invalid priorities return UV_EINVAL. */ + ASSERT(uv_os_setpriority(0, UV_PRIORITY_HIGHEST - 1) == UV_EINVAL); + ASSERT(uv_os_setpriority(0, UV_PRIORITY_LOW + 1) == UV_EINVAL); + + return 0; +} diff --git a/deps/uv/test/test-process-title-threadsafe.c b/deps/uv/test/test-process-title-threadsafe.c index d986576ed93c02..cc3fd41a136833 100644 --- a/deps/uv/test/test-process-title-threadsafe.c +++ b/deps/uv/test/test-process-title-threadsafe.c @@ -26,7 +26,7 @@ #include #ifdef __APPLE__ -# define NUM_ITERATIONS 20 +# define NUM_ITERATIONS 10 #else # define NUM_ITERATIONS 50 #endif diff --git a/deps/uv/test/test-signal-multiple-loops.c b/deps/uv/test/test-signal-multiple-loops.c index 1272d4576fd968..79242fc9fa99e7 100644 --- a/deps/uv/test/test-signal-multiple-loops.c +++ b/deps/uv/test/test-signal-multiple-loops.c @@ -249,7 +249,7 @@ TEST_IMPL(signal_multiple_loops) { uv_sem_wait(&sem); /* Block all signals to this thread, so we are sure that from here the signal - * handler runs in another thread. This is is more likely to catch thread and + * handler runs in another thread. This is more likely to catch thread and * signal safety issues if there are any. */ sigfillset(&sigset); diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index 4a2869a18afa43..4fcd905eed7500 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -1637,8 +1637,8 @@ TEST_IMPL(spawn_reads_child_path) { static const char dyld_path_var[] = "LD_LIBRARY_PATH"; #endif - /* Set up the process, but make sure that the file to run is relative and */ - /* requires a lookup into PATH */ + /* Set up the process, but make sure that the file to run is relative and + * requires a lookup into PATH. */ init_process_options("spawn_helper1", exit_cb); /* Set up the PATH env variable */ @@ -1733,6 +1733,7 @@ TEST_IMPL(spawn_inherit_streams) { uv_buf_t buf; unsigned int i; int r; + int bidir; uv_write_t write_req; uv_loop_t* loop; @@ -1751,6 +1752,15 @@ TEST_IMPL(spawn_inherit_streams) { ASSERT(uv_pipe_open(&pipe_stdout_child, fds_stdout[1]) == 0); ASSERT(uv_pipe_open(&pipe_stdin_parent, fds_stdin[1]) == 0); ASSERT(uv_pipe_open(&pipe_stdout_parent, fds_stdout[0]) == 0); + ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_child)); + ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_child)); + ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdin_parent)); + ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_parent)); + /* Some systems (SVR4) open a bidirectional pipe, most don't. */ + bidir = uv_is_writable((uv_stream_t*) &pipe_stdin_child); + ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_child) == bidir); + ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_parent) == bidir); + ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_parent) == bidir); child_stdio[0].flags = UV_INHERIT_STREAM; child_stdio[0].data.stream = (uv_stream_t *)&pipe_stdin_child; @@ -1805,8 +1815,8 @@ TEST_IMPL(spawn_quoted_path) { options.args = args; options.exit_cb = exit_cb; options.flags = 0; - /* We test if search_path works correctly with semicolons in quoted path. */ - /* We will use invalid drive, so we are sure no executable is spawned */ + /* We test if search_path works correctly with semicolons in quoted path. We + * will use an invalid drive, so we are sure no executable is spawned. */ quoted_path_env[0] = "PATH=\"xyz:\\test;\";xyz:\\other"; quoted_path_env[1] = NULL; options.env = quoted_path_env; diff --git a/deps/uv/test/test-tcp-bind-error.c b/deps/uv/test/test-tcp-bind-error.c index 10ed68e10ec26e..1456d081ae6374 100644 --- a/deps/uv/test/test-tcp-bind-error.c +++ b/deps/uv/test/test-tcp-bind-error.c @@ -214,3 +214,45 @@ TEST_IMPL(tcp_listen_without_bind) { MAKE_VALGRIND_HAPPY(); return 0; } + + +TEST_IMPL(tcp_bind_writable_flags) { + struct sockaddr_in addr; + uv_tcp_t server; + uv_buf_t buf; + uv_write_t write_req; + uv_shutdown_t shutdown_req; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + r = uv_listen((uv_stream_t*)&server, 128, NULL); + ASSERT(r == 0); + + ASSERT(0 == uv_is_writable((uv_stream_t*) &server)); + ASSERT(0 == uv_is_readable((uv_stream_t*) &server)); + + buf = uv_buf_init("PING", 4); + r = uv_write(&write_req, (uv_stream_t*) &server, &buf, 1, NULL); + ASSERT(r == UV_EPIPE); + r = uv_shutdown(&shutdown_req, (uv_stream_t*) &server, NULL); +#ifdef _WIN32 + ASSERT(r == UV_EPIPE); +#else + ASSERT(r == UV_ENOTCONN); +#endif + r = uv_read_start((uv_stream_t*) &server, NULL, NULL); + ASSERT(r == UV_ENOTCONN); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-tcp-oob.c b/deps/uv/test/test-tcp-oob.c index 4f1397a82ffed7..ca2361f9bb776d 100644 --- a/deps/uv/test/test-tcp-oob.c +++ b/deps/uv/test/test-tcp-oob.c @@ -61,7 +61,7 @@ static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { #endif uv_os_fd_t fd; - ASSERT(nread > 0); + ASSERT(nread >= 0); ASSERT(0 == uv_fileno((uv_handle_t*)handle, &fd)); ASSERT(0 == uv_idle_start(&idle, idle_cb)); diff --git a/deps/uv/test/test-tcp-open.c b/deps/uv/test/test-tcp-open.c index cb74c50e2c9929..0d92886d61f225 100644 --- a/deps/uv/test/test-tcp-open.c +++ b/deps/uv/test/test-tcp-open.c @@ -30,6 +30,7 @@ #endif static int shutdown_cb_called = 0; +static int shutdown_requested = 0; static int connect_cb_called = 0; static int write_cb_called = 0; static int close_cb_called = 0; @@ -37,6 +38,8 @@ static int close_cb_called = 0; static uv_connect_t connect_req; static uv_shutdown_t shutdown_req; static uv_write_t write_req; +static uv_timer_t tm; +static uv_tcp_t client; static void startup(void) { @@ -115,6 +118,20 @@ static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { ASSERT(memcmp("PING", buf->base, nread) == 0); } else { + ASSERT(nread == UV_EOF); + uv_close((uv_handle_t*)tcp, close_cb); + } +} + + +static void read1_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { + int i; + ASSERT(tcp != NULL); + + if (nread >= 0) { + for (i = 0; i < nread; ++i) + ASSERT(buf->base[i] == 'P'); + } else { ASSERT(nread == UV_EOF); printf("GOT EOF\n"); uv_close((uv_handle_t*)tcp, close_cb); @@ -134,6 +151,37 @@ static void write_cb(uv_write_t* req, int status) { } +static void write1_cb(uv_write_t* req, int status) { + uv_buf_t buf; + int r; + + ASSERT(req != NULL); + if (status) { + ASSERT(shutdown_cb_called); + return; + } + + if (shutdown_requested) + return; + + buf = uv_buf_init("P", 1); + r = uv_write(&write_req, req->handle, &buf, 1, write1_cb); + ASSERT(r == 0); + + write_cb_called++; +} + + +static void timer_cb(uv_timer_t* handle) { + int r; + + /* Shutdown on drain. */ + r = uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb); + ASSERT(r == 0); + shutdown_requested++; +} + + static void connect_cb(uv_connect_t* req, int status) { uv_buf_t buf = uv_buf_init("PING", 4); uv_stream_t* stream; @@ -158,9 +206,35 @@ static void connect_cb(uv_connect_t* req, int status) { } +static void connect1_cb(uv_connect_t* req, int status) { + uv_buf_t buf; + uv_stream_t* stream; + int r; + + ASSERT(req == &connect_req); + ASSERT(status == 0); + + stream = req->handle; + connect_cb_called++; + + r = uv_timer_init(uv_default_loop(), &tm); + ASSERT(r == 0); + + r = uv_timer_start(&tm, timer_cb, 2000, 0); + ASSERT(r == 0); + + buf = uv_buf_init("P", 1); + r = uv_write(&write_req, stream, &buf, 1, write1_cb); + ASSERT(r == 0); + + /* Start reading */ + r = uv_read_start(stream, alloc_cb, read1_cb); + ASSERT(r == 0); +} + + TEST_IMPL(tcp_open) { struct sockaddr_in addr; - uv_tcp_t client; uv_os_sock_t sock; int r; @@ -181,6 +255,20 @@ TEST_IMPL(tcp_open) { connect_cb); ASSERT(r == 0); +#ifndef _WIN32 + { + uv_tcp_t client2; + + r = uv_tcp_init(uv_default_loop(), &client2); + ASSERT(r == 0); + + r = uv_tcp_open(&client2, sock); + ASSERT(r == UV_EEXIST); + + uv_close((uv_handle_t*) &client2, NULL); + } +#endif /* !_WIN32 */ + uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(shutdown_cb_called == 1); @@ -275,3 +363,38 @@ TEST_IMPL(tcp_open_connected) { MAKE_VALGRIND_HAPPY(); return 0; } + + +TEST_IMPL(tcp_write_ready) { + struct sockaddr_in addr; + uv_os_sock_t sock; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + startup(); + sock = create_tcp_socket(); + + r = uv_tcp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + r = uv_tcp_open(&client, sock); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, + &client, + (const struct sockaddr*) &addr, + connect1_cb); + ASSERT(r == 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(shutdown_cb_called == 1); + ASSERT(shutdown_requested == 1); + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called > 0); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-tcp-write-queue-order.c b/deps/uv/test/test-tcp-write-queue-order.c index 5119be6d330932..1ff9c517cec1c6 100644 --- a/deps/uv/test/test-tcp-write-queue-order.c +++ b/deps/uv/test/test-tcp-write-queue-order.c @@ -90,7 +90,7 @@ static void connection_cb(uv_stream_t* tcp, int status) { ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming)); ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); - ASSERT(0 == uv_timer_start(&timer, timer_cb, 1, 0)); + ASSERT(0 == uv_timer_start(&timer, timer_cb, 1000, 0)); connection_cb_called++; } diff --git a/deps/uv/test/test-timer-again.c b/deps/uv/test/test-timer-again.c index f93c509be5dc0a..e87d2edf18f121 100644 --- a/deps/uv/test/test-timer-again.c +++ b/deps/uv/test/test-timer-again.c @@ -58,8 +58,8 @@ static void repeat_1_cb(uv_timer_t* handle) { if (repeat_1_cb_called == 10) { uv_close((uv_handle_t*)handle, close_cb); - /* We're not calling uv_timer_again on repeat_2 any more, so after this */ - /* timer_2_cb is expected. */ + /* We're not calling uv_timer_again on repeat_2 any more, so after this + * timer_2_cb is expected. */ repeat_2_cb_allowed = 1; return; } diff --git a/deps/uv/test/test-tty.c b/deps/uv/test/test-tty.c index e761822fa349fc..979a6ec38d7fcd 100644 --- a/deps/uv/test/test-tty.c +++ b/deps/uv/test/test-tty.c @@ -96,9 +96,13 @@ TEST_IMPL(tty) { r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ ASSERT(r == 0); + ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); + ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ ASSERT(r == 0); + ASSERT(!uv_is_readable((uv_stream_t*) &tty_out)); + ASSERT(uv_is_writable((uv_stream_t*) &tty_out)); r = uv_tty_get_winsize(&tty_out, &width, &height); ASSERT(r == 0); @@ -186,6 +190,8 @@ TEST_IMPL(tty_raw) { r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ ASSERT(r == 0); + ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); + ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read); ASSERT(r == 0); @@ -242,6 +248,8 @@ TEST_IMPL(tty_empty_write) { r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ ASSERT(r == 0); + ASSERT(!uv_is_readable((uv_stream_t*) &tty_out)); + ASSERT(uv_is_writable((uv_stream_t*) &tty_out)); bufs[0].len = 0; bufs[0].base = &dummy[0]; @@ -302,6 +310,41 @@ TEST_IMPL(tty_large_write) { MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(tty_raw_cancel) { + int r; + int ttyin_fd; + uv_tty_t tty_in; + uv_loop_t* loop; + HANDLE handle; + + loop = uv_default_loop(); + /* Make sure we have an FD that refers to a tty */ + handle = CreateFileA("conin$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT(handle != INVALID_HANDLE_VALUE); + ttyin_fd = _open_osfhandle((intptr_t) handle, 0); + ASSERT(ttyin_fd >= 0); + ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ + ASSERT(r == 0); + r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); + ASSERT(r == 0); + r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read); + ASSERT(r == 0); + + r = uv_read_stop((uv_stream_t*) &tty_in); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} #endif @@ -309,6 +352,8 @@ TEST_IMPL(tty_file) { #ifndef _WIN32 uv_loop_t loop; uv_tty_t tty; + uv_tty_t tty_ro; + uv_tty_t tty_wo; int fd; ASSERT(0 == uv_loop_init(&loop)); @@ -334,13 +379,40 @@ TEST_IMPL(tty_file) { ASSERT(0 == close(fd)); } - fd = open("/dev/tty", O_RDONLY); + fd = open("/dev/tty", O_RDWR); if (fd != -1) { ASSERT(0 == uv_tty_init(&loop, &tty, fd, 1)); - ASSERT(0 == close(fd)); + ASSERT(0 == close(fd)); /* TODO: it's indeterminate who owns fd now */ + ASSERT(uv_is_readable((uv_stream_t*) &tty)); + ASSERT(uv_is_writable((uv_stream_t*) &tty)); uv_close((uv_handle_t*) &tty, NULL); + ASSERT(!uv_is_readable((uv_stream_t*) &tty)); + ASSERT(!uv_is_writable((uv_stream_t*) &tty)); + } + + fd = open("/dev/tty", O_RDONLY); + if (fd != -1) { + ASSERT(0 == uv_tty_init(&loop, &tty_ro, fd, 1)); + ASSERT(0 == close(fd)); /* TODO: it's indeterminate who owns fd now */ + ASSERT(uv_is_readable((uv_stream_t*) &tty_ro)); + ASSERT(!uv_is_writable((uv_stream_t*) &tty_ro)); + uv_close((uv_handle_t*) &tty_ro, NULL); + ASSERT(!uv_is_readable((uv_stream_t*) &tty_ro)); + ASSERT(!uv_is_writable((uv_stream_t*) &tty_ro)); } + fd = open("/dev/tty", O_WRONLY); + if (fd != -1) { + ASSERT(0 == uv_tty_init(&loop, &tty_wo, fd, 0)); + ASSERT(0 == close(fd)); /* TODO: it's indeterminate who owns fd now */ + ASSERT(!uv_is_readable((uv_stream_t*) &tty_wo)); + ASSERT(uv_is_writable((uv_stream_t*) &tty_wo)); + uv_close((uv_handle_t*) &tty_wo, NULL); + ASSERT(!uv_is_readable((uv_stream_t*) &tty_wo)); + ASSERT(!uv_is_writable((uv_stream_t*) &tty_wo)); + } + + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); ASSERT(0 == uv_loop_close(&loop)); @@ -370,13 +442,17 @@ TEST_IMPL(tty_pty) { ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0)); ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0)); + ASSERT(uv_is_readable((uv_stream_t*) &slave_tty)); + ASSERT(uv_is_writable((uv_stream_t*) &slave_tty)); + ASSERT(uv_is_readable((uv_stream_t*) &master_tty)); + ASSERT(uv_is_writable((uv_stream_t*) &master_tty)); /* Check if the file descriptor was reopened. If it is, - * UV_STREAM_BLOCKING (value 0x80) isn't set on flags. + * UV_HANDLE_BLOCKING_WRITES (value 0x100000) isn't set on flags. */ - ASSERT(0 == (slave_tty.flags & 0x80)); + ASSERT(0 == (slave_tty.flags & 0x100000)); /* The master_fd of a pty should never be reopened. */ - ASSERT(master_tty.flags & 0x80); + ASSERT(master_tty.flags & 0x100000); ASSERT(0 == close(slave_fd)); uv_close((uv_handle_t*) &slave_tty, NULL); ASSERT(0 == close(master_fd)); diff --git a/deps/uv/test/test-udp-alloc-cb-fail.c b/deps/uv/test/test-udp-alloc-cb-fail.c index 05b871e921c094..0cee09c942ef2c 100644 --- a/deps/uv/test/test-udp-alloc-cb-fail.c +++ b/deps/uv/test/test-udp-alloc-cb-fail.c @@ -120,8 +120,7 @@ static void sv_recv_cb(uv_udp_t* handle, } if (nread == 0) { - /* Returning unused buffer */ - /* Don't count towards sv_recv_cb_called */ + /* Returning unused buffer. Don't count towards sv_recv_cb_called */ ASSERT(addr == NULL); return; } diff --git a/deps/uv/test/test-udp-ipv6.c b/deps/uv/test/test-udp-ipv6.c index 000079185557a4..9d4db2bc4fedf0 100644 --- a/deps/uv/test/test-udp-ipv6.c +++ b/deps/uv/test/test-udp-ipv6.c @@ -174,6 +174,8 @@ TEST_IMPL(udp_dual_stack) { #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) if (!can_ipv6_ipv4_dual()) RETURN_SKIP("IPv6-IPv4 dual stack not supported"); +#elif defined(__OpenBSD__) + RETURN_SKIP("IPv6-IPv4 dual stack not supported"); #endif do_test(ipv6_recv_ok, 0); diff --git a/deps/uv/test/test-udp-multicast-join.c b/deps/uv/test/test-udp-multicast-join.c index 6110a8d922a0b9..053d2f791498f7 100644 --- a/deps/uv/test/test-udp-multicast-join.c +++ b/deps/uv/test/test-udp-multicast-join.c @@ -81,8 +81,7 @@ static void cl_recv_cb(uv_udp_t* handle, } if (nread == 0) { - /* Returning unused buffer */ - /* Don't count towards cl_recv_cb_called */ + /* Returning unused buffer. Don't count towards cl_recv_cb_called */ ASSERT(addr == NULL); return; } diff --git a/deps/uv/test/test-udp-multicast-join6.c b/deps/uv/test/test-udp-multicast-join6.c index 8814b5ad13c6ff..bda5e20ea70403 100644 --- a/deps/uv/test/test-udp-multicast-join6.c +++ b/deps/uv/test/test-udp-multicast-join6.c @@ -82,8 +82,7 @@ static void cl_recv_cb(uv_udp_t* handle, } if (nread == 0) { - /* Returning unused buffer */ - /* Don't count towards cl_recv_cb_called */ + /* Returning unused buffer. Don't count towards cl_recv_cb_called */ ASSERT(addr == NULL); return; } @@ -123,7 +122,8 @@ TEST_IMPL(udp_multicast_join6) { defined(_AIX) || \ defined(__MVS__) || \ defined(__FreeBSD_kernel__) || \ - defined(__NetBSD__) + defined(__NetBSD__) || \ + defined(__OpenBSD__) r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP); #else r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP); diff --git a/deps/uv/test/test-udp-open.c b/deps/uv/test/test-udp-open.c index 4d77f45d367eae..ee04c99f61bae2 100644 --- a/deps/uv/test/test-udp-open.c +++ b/deps/uv/test/test-udp-open.c @@ -106,8 +106,7 @@ static void recv_cb(uv_udp_t* handle, } if (nread == 0) { - /* Returning unused buffer */ - /* Don't count towards sv_recv_cb_called */ + /* Returning unused buffer. Don't count towards sv_recv_cb_called */ ASSERT(addr == NULL); return; } @@ -165,6 +164,20 @@ TEST_IMPL(udp_open) { send_cb); ASSERT(r == 0); +#ifndef _WIN32 + { + uv_udp_t client2; + + r = uv_udp_init(uv_default_loop(), &client2); + ASSERT(r == 0); + + r = uv_udp_open(&client2, sock); + ASSERT(r == UV_EEXIST); + + uv_close((uv_handle_t*) &client2, NULL); + } +#endif /* !_WIN32 */ + uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(send_cb_called == 1); diff --git a/deps/uv/test/test-udp-options.c b/deps/uv/test/test-udp-options.c index 8f91367590388b..d8c9d68d81b428 100644 --- a/deps/uv/test/test-udp-options.c +++ b/deps/uv/test/test-udp-options.c @@ -114,9 +114,11 @@ TEST_IMPL(udp_options6) { TEST_IMPL(udp_no_autobind) { uv_loop_t* loop; uv_udp_t h; + uv_udp_t h2; loop = uv_default_loop(); + /* Test a lazy initialized socket. */ ASSERT(0 == uv_udp_init(loop, &h)); ASSERT(UV_EBADF == uv_udp_set_multicast_ttl(&h, 32)); ASSERT(UV_EBADF == uv_udp_set_broadcast(&h, 1)); @@ -130,6 +132,23 @@ TEST_IMPL(udp_no_autobind) { uv_close((uv_handle_t*) &h, NULL); + /* Test a non-lazily initialized socket. */ + ASSERT(0 == uv_udp_init_ex(loop, &h2, AF_INET)); + ASSERT(0 == uv_udp_set_multicast_ttl(&h2, 32)); + ASSERT(0 == uv_udp_set_broadcast(&h2, 1)); + +#if defined(__MVS__) + /* zOS only supports setting ttl for IPv6 sockets. */ + ASSERT(UV_ENOTSUP == uv_udp_set_ttl(&h2, 1)); +#else + ASSERT(0 == uv_udp_set_ttl(&h2, 1)); +#endif + + ASSERT(0 == uv_udp_set_multicast_loop(&h2, 1)); + ASSERT(0 == uv_udp_set_multicast_interface(&h2, "0.0.0.0")); + + uv_close((uv_handle_t*) &h2, NULL); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(); diff --git a/deps/uv/test/test-udp-send-and-recv.c b/deps/uv/test/test-udp-send-and-recv.c index 633a16727b2a85..1f01188b274a49 100644 --- a/deps/uv/test/test-udp-send-and-recv.c +++ b/deps/uv/test/test-udp-send-and-recv.c @@ -72,8 +72,7 @@ static void cl_recv_cb(uv_udp_t* handle, } if (nread == 0) { - /* Returning unused buffer */ - /* Don't count towards cl_recv_cb_called */ + /* Returning unused buffer. Don't count towards cl_recv_cb_called */ ASSERT(addr == NULL); return; } @@ -128,8 +127,7 @@ static void sv_recv_cb(uv_udp_t* handle, } if (nread == 0) { - /* Returning unused buffer */ - /* Don't count towards sv_recv_cb_called */ + /* Returning unused buffer. Don't count towards sv_recv_cb_called */ ASSERT(addr == NULL); return; } diff --git a/deps/uv/test/test-udp-send-immediate.c b/deps/uv/test/test-udp-send-immediate.c index 215f72257233a1..1011aa467e0541 100644 --- a/deps/uv/test/test-udp-send-immediate.c +++ b/deps/uv/test/test-udp-send-immediate.c @@ -74,8 +74,7 @@ static void sv_recv_cb(uv_udp_t* handle, } if (nread == 0) { - /* Returning unused buffer */ - /* Don't count towards sv_recv_cb_called */ + /* Returning unused buffer. Don't count towards sv_recv_cb_called */ ASSERT(addr == NULL); return; } diff --git a/deps/uv/test/test.gyp b/deps/uv/test/test.gyp index 480e5a26c4176d..855eda1c50003a 100644 --- a/deps/uv/test/test.gyp +++ b/deps/uv/test/test.gyp @@ -47,8 +47,9 @@ 'test-hrtime.c', 'test-idle.c', 'test-ip6-addr.c', - 'test-ipc.c', + 'test-ipc-heavy-traffic-deadlock-bug.c', 'test-ipc-send-recv.c', + 'test-ipc.c', 'test-list.h', 'test-loop-handles.c', 'test-loop-alive.c', @@ -79,6 +80,7 @@ 'test-poll-close-doesnt-corrupt-stack.c', 'test-poll-closesocket.c', 'test-poll-oob.c', + 'test-process-priority.c', 'test-process-title.c', 'test-process-title-threadsafe.c', 'test-queue-foreach-delete.c', diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index a5046b87ea5b3c..5148a850ab4c15 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -2,12 +2,12 @@ 'variables': { 'conditions': [ ['OS=="win"', { + 'shared_unix_defines': [ ], + }, { 'shared_unix_defines': [ '_LARGEFILE_SOURCE', '_FILE_OFFSET_BITS=64', ], - }, { - 'shared_unix_defines': [ ], }], ['OS in "mac ios"', { 'shared_mac_defines': [ '_DARWIN_USE_64_BIT_INODE=1' ], @@ -64,15 +64,16 @@ 'sources': [ 'common.gypi', 'include/uv.h', - 'include/tree.h', - 'include/uv-errno.h', - 'include/uv-threadpool.h', - 'include/uv-version.h', + 'include/uv/tree.h', + 'include/uv/errno.h', + 'include/uv/threadpool.h', + 'include/uv/version.h', 'src/fs-poll.c', 'src/heap-inl.h', 'src/inet.c', 'src/queue.h', 'src/threadpool.c', + 'src/timer.c', 'src/uv-data-getter-setters.c', 'src/uv-common.c', 'src/uv-common.h', @@ -95,7 +96,7 @@ '_GNU_SOURCE', ], 'sources': [ - 'include/uv-win.h', + 'include/uv/win.h', 'src/win/async.c', 'src/win/atomicops-inl.h', 'src/win/core.c', @@ -115,7 +116,6 @@ 'src/win/poll.c', 'src/win/process.c', 'src/win/process-stdio.c', - 'src/win/req.c', 'src/win/req-inl.h', 'src/win/signal.c', 'src/win/snprintf.c', @@ -123,7 +123,6 @@ 'src/win/stream-inl.h', 'src/win/tcp.c', 'src/win/tty.c', - 'src/win/timer.c', 'src/win/udp.c', 'src/win/util.c', 'src/win/winapi.c', @@ -144,12 +143,12 @@ }, }, { # Not Windows i.e. POSIX 'sources': [ - 'include/uv-unix.h', - 'include/uv-linux.h', - 'include/uv-sunos.h', - 'include/uv-darwin.h', - 'include/uv-bsd.h', - 'include/uv-aix.h', + 'include/uv/unix.h', + 'include/uv/linux.h', + 'include/uv/sunos.h', + 'include/uv/darwin.h', + 'include/uv/bsd.h', + 'include/uv/aix.h', 'src/unix/async.c', 'src/unix/atomic-ops.h', 'src/unix/core.c', @@ -168,7 +167,6 @@ 'src/unix/stream.c', 'src/unix/tcp.c', 'src/unix/thread.c', - 'src/unix/timer.c', 'src/unix/tty.c', 'src/unix/udp.c', ], @@ -199,7 +197,7 @@ ['uv_library=="shared_library" and OS!="mac" and OS!="zos"', { # This will cause gyp to set soname # Must correspond with UV_VERSION_MAJOR - # in include/uv-version.h + # in include/uv/version.h 'product_extension': 'so.1', }], ], @@ -300,9 +298,6 @@ 'src/unix/no-fsevents.c', 'src/unix/no-proctitle.c', ], - 'defines': [ - '_PASE=1' - ], }, { 'sources': [ 'src/unix/aix.c' diff --git a/lib/internal/process/stdio.js b/lib/internal/process/stdio.js index 45568ae631698b..7faef381f895bf 100644 --- a/lib/internal/process/stdio.js +++ b/lib/internal/process/stdio.js @@ -161,11 +161,24 @@ function createWritableStdioStream(fd) { case 'PIPE': case 'TCP': var net = require('net'); - stream = new net.Socket({ - fd: fd, - readable: false, - writable: true - }); + + // If fd is already being used for the IPC channel, libuv will return + // an error when trying to use it again. In that case, create the socket + // using the existing handle instead of the fd. + if (process.channel && process.channel.fd === fd) { + stream = new net.Socket({ + handle: process.channel, + readable: false, + writable: true + }); + } else { + stream = new net.Socket({ + fd, + readable: false, + writable: true + }); + } + stream._type = 'pipe'; break; diff --git a/test/parallel/test-fs-readfile-error.js b/test/parallel/test-fs-readfile-error.js index 616760b06695a1..8f4da1e9b1c86f 100644 --- a/test/parallel/test-fs-readfile-error.js +++ b/test/parallel/test-fs-readfile-error.js @@ -24,9 +24,9 @@ const common = require('../common'); // Test that fs.readFile fails correctly on a non-existent file. -// `fs.readFile('/')` does not fail on FreeBSD, because you can open and read -// the directory there. -if (common.isFreeBSD) +// `fs.readFile('/')` does not fail on AIX and FreeBSD because you can open +// and read the directory there. +if (common.isAIX || common.isFreeBSD) common.skip('platform not supported.'); const assert = require('assert');