diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap index f5d5375e044e18..b8adf7b6a5d743 100644 --- a/deps/uv/.mailmap +++ b/deps/uv/.mailmap @@ -27,8 +27,10 @@ Jesse Gorzinski Jesse Gorzinski Juan José Arboleda Justin Venus +Keno Fischer Keno Fischer Keno Fischer +Lawrence Stubbs Leith Bade Leonard Hecker Lewis Russell @@ -42,7 +44,8 @@ Nick Logan Olivier Valentin Rasmus Christian Pedersen Rasmus Christian Pedersen -Richard Lau +Richard Lau +Richard Lau Robert Mustacchi Ryan Dahl Ryan Emery diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 89a3d9db05c877..f33c1f84af340d 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -210,7 +210,7 @@ guworks RossBencina Roger A. Light chenttuuvv -Richard Lau +Richard Lau ronkorving Corbin Simpson Zachary Hamm @@ -604,3 +604,30 @@ mugitya03 Itay Bookstein crupest AE1020 <68134252+AE1020@users.noreply.github.com> +dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> +jhnh204 <51738134+jhnh204@users.noreply.github.com> +chemodax <53048645+chemodax@users.noreply.github.com> +Deep C +Luca Saccarola <96259932+saccarosium@users.noreply.github.com> +wisemanny <118970226+wisemanny@users.noreply.github.com> +Sean Dewar <6256228+seandewar@users.noreply.github.com> +Lawrence Stubbs +Emily +Anton Kirilov +Savas Sahin +m0cg +moe li +green-br +Christian Guinard <28689358+christiangnrd@users.noreply.github.com> +Gang Zhuo +Ayush Kumar +Ambuj Vashistha +Bart Louwers +Kartik Puri <84309847+BOXER78@users.noreply.github.com> +Oblivionsage <126214490+Oblivionsage@users.noreply.github.com> +Cody Tapscott <84105208+topolarity@users.noreply.github.com> +tobil4sk +Han Gao +mischief +StefanStojanovic +Przemysław Sobala diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt index 73d5aff8926ed5..53dff4215fd44b 100644 --- a/deps/uv/CMakeLists.txt +++ b/deps/uv/CMakeLists.txt @@ -700,6 +700,7 @@ if(LIBUV_BUILD_TESTS) test/test-udp-send-immediate.c test/test-udp-sendmmsg-error.c test/test-udp-send-unreachable.c + test/test-udp-recvmsg-unreachable-error.c test/test-udp-try-send.c test/test-udp-recv-in-a-row.c test/test-udp-reuseport.c @@ -747,6 +748,14 @@ if(LIBUV_BUILD_TESTS) "$" "$/uv_run_tests_a_no_ext") endif() + + if(QNX) + install(TARGETS uv_run_tests uv_run_tests_a uv_run_benchmarks_a + DESTINATION ${CMAKE_INSTALL_BINDIR}/libuv_tests) + + install(DIRECTORY test/fixtures + DESTINATION ${CMAKE_INSTALL_BINDIR}/libuv_tests) + endif() endif() # Now for some gibbering horrors from beyond the stars... @@ -774,6 +783,11 @@ install(TARGETS uv_a EXPORT libuvConfig install(EXPORT libuvConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libuv NAMESPACE libuv::) +write_basic_package_version_file(libuvConfigVersion.cmake + VERSION ${PACKAGE_VERSION} + COMPATIBILITY SameMajorVersion) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libuvConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libuv) if(LIBUV_BUILD_SHARED) # The version in the filename is mirroring the behaviour of autotools. diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 787963715772d0..9f175be51f10a5 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,4 +1,241 @@ -2025.04.25, Version 1.51.0 (Stable) +2026.02.11, Version 1.52.0 (Stable) + +Changes since version 1.51.0: + +* src: remove unused include of in timer.c (Juan José Arboleda) + +* test: skip `udp_multicast_join` if not system-wide available (Juan José + Arboleda) + +* test: remove unused include of in runner.h (Juan José Arboleda) + +* doc: don't mention UV_LOOP_ENABLE_IO_URING_SQPOLL (Poul T Lomholt) + +* unix: fix uv_thread_{get,set}priority error codes (Ryan Liptak) + +* build: dedup sanitizer jobs using matrix strategy (Juan José Arboleda) + +* doc: update ncurses link (Saúl Ibarra Corretgé) + +* tcp: support customizing TCP_KEEPINTVL and TCP_KEEPCNT (Andy Pan) + +* linux: fix -Wformat-truncation warning (Ben Noordhuis) + +* src: fix nullptr dereference in uv__print_handles (jhnh204) + +* build: make automake link libm on bsd-likes (Juan José Arboleda) + +* include: remove unused macro undefs from uv.h (Juan José Arboleda) + +* win: handle empty string in uv_get_process_title (Ben Noordhuis) + +* win: use WSA_FLAG_NO_HANDLE_INHERIT in WSASocketW (chemodax) + +* unix: handle possible `ENOMEM` in `uv__tcp_listen` (Juan José Arboleda) + +* win: replace GetModuleHandleA with GetModuleHandleW (chemodax) + +* qnx: add qnx 8 support (Deep C) + +* mailmap: update email address for Richard Lau (Richard Lau) + +* win: remove obsolete comment (Ben Noordhuis) + +* unix: handle possible `ENOMEM` in `uv__pipe_listen` (Juan José Arboleda) + +* unix: deduplicate uv_free_interface_addresses (Juan José Arboleda) + +* test: pass correct string type to GetModuleHandleW (Ben Noordhuis) + +* win: remove unnecessary inlining from fs.c (Ben Noordhuis) + +* win: move uv__process_reqs to core.c (Ben Noordhuis) + +* win: remove unnecessary inlining from header file (Ben Noordhuis) + +* test: skip slow process title test on asan+macos (Ben Noordhuis) + +* win: dissolve atomicops-inl.h (Ben Noordhuis) + +* win: move uv__process_endgames to core.c (Ben Noordhuis) + +* win: move uv__insert_pending_req to core.c (Ben Noordhuis) + +* win: replace inline asm with compiler intrinsic (Ben Noordhuis) + +* win,pipe: minimal fix to uv_read_cb->uv_read_start recursion bug (Jameson + Nash) + +* doc: make requirements work with newer python (Luca Saccarola) + +* win: fix -Wcast-function-type warnings in winapi.c (Ben Noordhuis) + +* win: fix -Wsign-compare warnings (Ben Noordhuis) + +* test: simplify ASSERT_OK macro for static analysis (Jameson Nash) + +* win: add arm64 machine type to uv_os_uname (wisemanny) + +* win: use ProcessPrng (Ben Noordhuis) + +* win: work around wine bug in uv_fs_{unlink,rmdir} (Keno Fischer) + +* doc: fix return value for uv_pipe_connect2 (Sean Dewar) + +* unix: fix udp sendmmsg fallback path (Ben Noordhuis) + +* doc: add binding `C framework` uv_coroutine to LINKS.md (Lawrence Stubbs) + +* linux: handle cgroups cpu.max with limit < period (Ben Noordhuis) + +* doc: update link, repo name change to c-asio (Lawrence Stubbs) + +* build(deps): bump actions/download-artifact from 4 to 5 (dependabot[bot]) + +* doc: remove nodeuv from LINKS.md (Ben Noordhuis) + +* test: use relative paths for pipes and unix sockets (Emily) + +* build(deps): bump actions/checkout from 4 to 5 (dependabot[bot]) + +* unix: improve uv__cpu_relax() on arm (Anton Kirilov) + +* win: fix compiler warnings (Savas Sahin) + +* unix: replace uv__io_t callback pointer with enum (Ben Noordhuis) + +* test,win: fix -Wunused-function warnings (Ben Noordhuis) + +* test,win: fix -Wcast-function-type warnings (Ben Noordhuis) + +* test,win: fix -Wattributes warnings (Ben Noordhuis) + +* win: shrink fd hash table from 2592k to 162k (Ben Noordhuis) + +* unix: fix build on the bsds (Ben Noordhuis) + +* netbsd: fix thread affinity compilation error (Santiago Gimeno) + +* unix: remove UV__SIGNAL_EVENT dispatch from uv__io_cb (Juan José Arboleda) + +* build: add -Werror when testing -Wflags (Jameson Nash) + +* win: fix path size calculation (Ben Noordhuis) + +* doc: correct uv_cancel return value (m0cg) + +* unix,win: look up UV_THREADPOOL_SIZE with uv_os_getenv (moe li) + +* build(deps): bump actions/setup-python from 5 to 6 (dependabot[bot]) + +* unix: fix uv__signal_loop_cleanup call in init (Jameson Nash) + +* aix: fix nullptr check in uv__skip_lines (Ben Noordhuis) + +* unix: add neoverse-v2 cpu identifier (green-br) + +* test: make `thread_priority` robust against system default nice levels + + (Juan José Arboleda) + +* unix,win: implement `uv_udp_open_ex` (Juan José Arboleda) + +* aix: add stub function to satisfy linker (Ben Noordhuis) + +* linux: add MSG_ERRQUEUE ipv4/ipv6 udp support (Juan José Arboleda) + +* ibmi: add stub function to satisfy linker (Ben Noordhuis) + +* darwin: better heuristic for available memory (Christian Guinard) + +* build(deps): bump actions/download-artifact from 5 to 6 (dependabot[bot]) + +* build(deps): bump actions/upload-artifact from 4 to 5 (dependabot[bot]) + +* unix: fix use of uninitialized variable (Ben Noordhuis) + +* doc: fix documentation for uv_utf16_to_wtf8() function (Gang Zhuo) + +* win: rename minimal_windows10_version1709() for libuv's convention (Andy Pan) + +* build(deps): bump actions/checkout from 5 to 6 (dependabot[bot]) + +* win: fix race in uv_fs_event_start() (Ben Noordhuis) + +* unix: support nanosecond resolution in uv__fs_to_timespec (Ayush Kumar) + +* win: handle sshfs-win quirk in uv_fs_readdir() (Ben Noordhuis) + +* unix,win: fix leak in uv_os_environ error path (Ambuj Vashistha) + +* test: add macros to run fs tests with io_uring (Santiago Gimeno) + +* linux: fix uv_fs_ftruncate io_uring implementation (Santiago Gimeno) + +* Update OS X reference to macOS in README (Bart Louwers) + +* ci: update macos runner images (Ben Noordhuis) + +* doc: add example usage for uv_sleep (Kartik Puri) + +* ci: add macos-15-intel to matrix (Ben Noordhuis) + +* win: Optimize file/directory delete. (chemodax) + +* build(deps): bump actions/download-artifact from 6 to 7 (dependabot[bot]) + +* build(deps): bump actions/upload-artifact from 5 to 6 (dependabot[bot]) + +* test: run more fs tests using io_uring too (Santiago Gimeno) + +* doc: add handle and request usage guidelines (Ben Noordhuis) + +* unix: remove handle from queue on uv_spawn() error (Oblivionsage) + +* doc: remove hp-ux from supported platforms list (Ben Noordhuis) + +* unix,win: add f_frsize field to uv_statfs_t (Ben Noordhuis) + +* test: fix -Wuninitialized-const-pointer warning (Ben Noordhuis) + +* test: fix -Wstringop-overread warning (Ben Noordhuis) + +* test: make pty test work under asan (Ben Noordhuis) + +* win: readlink support for IO_REPARSE_TAG_LX_SYMLINK (Cody Tapscott) + +* unix: fix partial read handling after POLLHUP (Ben Noordhuis) + +* unix: factor out common i/o poll code (Ben Noordhuis) + +* test: disable udp_reuseport test under qemu (Ben Noordhuis) + +* test: disable tcp_reuseport test under qemu (Ben Noordhuis) + +* unix,win: check nbufs argument is reasonable (Ben Noordhuis) + +* win: refactor to support large statfs blocks (Santiago Gimeno) + +* unix: remove sunpro references (Ben Noordhuis) + +* idna: fix assert in wtf8_to_utf16 conversion (tobil4sk) + +* aix,ibmi: fix test suite build breakage (Ben Noordhuis) + +* unix: implement cpu_relax() for riscv64 (Han Gao) + +* doc: add setuid warning to uv_exepath (Ben Noordhuis) + +* unix: make OpenBSD uv_exepath work (mischief) + +* win: fix uv_get_process_title (StefanStojanovic) + +* unix,udp: fix -Wgnu-folding-constant warning (Saúl Ibarra Corretgé) + +* cmake: add libuvConfigVersion.cmake file (Przemysław Sobala) + + +2025.04.25, Version 1.51.0 (Stable), 5152db2cbfeb5582e9c27c5ea1dba2cd9e10759b Changes since version 1.50.0: diff --git a/deps/uv/LINKS.md b/deps/uv/LINKS.md index 9f286ea3e9201f..c73c455223c47b 100644 --- a/deps/uv/LINKS.md +++ b/deps/uv/LINKS.md @@ -30,7 +30,6 @@ * [node9](https://github.com/jvburnes/node9): A portable, hybrid, distributed OS based on Inferno, LuaJIT and Libuv * [node.js](http://www.nodejs.org/): Javascript (using Google's V8) + libuv * [node.native](https://github.com/d5/node.native): node.js-like API for C++11 -* [nodeuv](https://github.com/nodeuv): An organization with several c++ wrappers for libs which are used in node.js. * [phastlight](https://github.com/phastlight/phastlight): Command line tool and web server written in PHP 5.3+ inspired by Node.js * [pilight](https://www.pilight.org/): home automation ("domotica") * [pixie](https://github.com/pixie-lang/pixie): clojure-inspired lisp with a tracing JIT @@ -109,4 +108,6 @@ * Haskell * [Z.Haskell](https://z.haskell.world) * C3 - * [libuv.c3l](https://github.com/velikoss/libuv.c3l) + * [libuv.c3l](https://github.com/velikoss/libuv.c3l) +* C + * [c-asio](https://github.com/zelang-dev/c-asio) A memory safe focus *C framework*, combining [c-raii](https://zelang-dev.github.io/c-raii), `libuv`, **coroutine** and other concurrency primitives. diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index f3808b696ce3db..797efc83e6223b 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -61,7 +61,6 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/win \ -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0A00 libuv_la_SOURCES += src/win/async.c \ - src/win/atomicops-inl.h \ src/win/core.c \ src/win/detect-wakeup.c \ src/win/dl.c \ @@ -326,6 +325,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-udp-send-immediate.c \ test/test-udp-sendmmsg-error.c \ test/test-udp-send-unreachable.c \ + test/test-udp-recvmsg-unreachable-error.c \ test/test-udp-try-send.c \ test/test-udp-recv-in-a-row.c \ test/test-udp-reuseport.c \ @@ -438,7 +438,7 @@ libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/kqueue.c \ src/unix/proctitle.c \ src/unix/random-getentropy.c -test_run_tests_LDFLAGS += -lutil +test_run_tests_LDFLAGS += -lutil -lm endif if DRAGONFLY @@ -448,7 +448,7 @@ libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/freebsd.c \ src/unix/kqueue.c \ src/unix/posix-hrtime.c -test_run_tests_LDFLAGS += -lutil +test_run_tests_LDFLAGS += -lutil -lm endif if FREEBSD @@ -459,7 +459,7 @@ libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/kqueue.c \ src/unix/posix-hrtime.c \ src/unix/random-getrandom.c -test_run_tests_LDFLAGS += -lutil +test_run_tests_LDFLAGS += -lutil -lm endif if HAIKU @@ -491,7 +491,7 @@ libuv_la_SOURCES += src/unix/linux.c \ src/unix/proctitle.c \ src/unix/random-getrandom.c \ src/unix/random-sysctl-linux.c -test_run_tests_LDFLAGS += -lutil +test_run_tests_LDFLAGS += -lutil -lm endif if MSYS @@ -514,7 +514,7 @@ libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/kqueue.c \ src/unix/netbsd.c \ src/unix/posix-hrtime.c -test_run_tests_LDFLAGS += -lutil +test_run_tests_LDFLAGS += -lutil -lm endif if OPENBSD @@ -525,7 +525,7 @@ libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/openbsd.c \ src/unix/posix-hrtime.c \ src/unix/random-getentropy.c -test_run_tests_LDFLAGS += -lutil +test_run_tests_LDFLAGS += -lutil -lm endif if SUNOS diff --git a/deps/uv/README.md b/deps/uv/README.md index 7cc9d2dd53c27c..1f1fdbfe3f7059 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -215,7 +215,7 @@ $ cmake ../.. \ $ brew install --HEAD libuv ``` -Note to OS X users: +Note to macOS users: Make sure that you specify the architecture you wish to build for in the "ARCHS" flag. You can specify more than one by delimiting with a space diff --git a/deps/uv/SUPPORTED_PLATFORMS.md b/deps/uv/SUPPORTED_PLATFORMS.md index c560aa1086b981..b317da6f45c66f 100644 --- a/deps/uv/SUPPORTED_PLATFORMS.md +++ b/deps/uv/SUPPORTED_PLATFORMS.md @@ -12,7 +12,6 @@ | Linux with musl | Tier 2 | musl >= 1.0 | | | Android | Tier 3 | NDK >= r15b | Android 7.0, `-DANDROID_PLATFORM=android-24` | | MinGW | Tier 3 | MinGW-w64 | | -| SunOS | Tier 3 | Solaris 121 and later | | | Other | Tier 3 | N/A | | ## Support types diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index a4b03b8f5075ee..5911ec8c7226df 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.51.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.52.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) @@ -27,7 +27,7 @@ AC_PROG_CC AM_PROG_CC_C_O CC_ATTRIBUTE_VISIBILITY([default], [ - CC_FLAG_VISIBILITY([CFLAGS="${CFLAGS} -fvisibility=hidden"]) + CC_CHECK_CFLAG_APPEND([-fvisibility=hidden]) ]) # Xlc has a flag "-f". Need to use CC_CHECK_FLAG_SUPPORTED_APPEND so # we exclude -fno-strict-aliasing for xlc diff --git a/deps/uv/docs/requirements.txt b/deps/uv/docs/requirements.txt index 2e310ebe7283af..0319b30871d114 100644 --- a/deps/uv/docs/requirements.txt +++ b/deps/uv/docs/requirements.txt @@ -1,36 +1,29 @@ # primary -furo==2023.5.20 -Sphinx==6.1.3 +furo==2024.8.6 +Sphinx==7.0.1 # dependencies -alabaster==0.7.13 -Babel==2.11.0 -beautifulsoup4==4.12.2 -certifi==2022.12.7 -charset-normalizer==3.0.1 -colorama==0.4.6 -docutils==0.19 -idna==3.4 +alabaster==0.7.16 +babel==2.17.0 +beautifulsoup4==4.13.3 +certifi==2025.1.31 +charset-normalizer==3.4.1 +docutils==0.20.1 +idna==3.10 imagesize==1.4.1 -importlib-metadata==6.0.0 -Jinja2==3.1.2 -livereload==2.6.3 -MarkupSafe==2.1.2 -packaging==23.0 -Pygments==2.14.0 -pytz==2022.7.1 -requests==2.28.2 -six==1.16.0 +Jinja2==3.1.6 +MarkupSafe==3.0.2 +packaging==24.2 +Pygments==2.19.1 +requests==2.32.3 snowballstemmer==2.2.0 -soupsieve==2.4.1 -sphinx-autobuild==2021.3.14 +soupsieve==2.6 sphinx-basic-ng==1.0.0b2 -sphinxcontrib-devhelp==1.0.2 -sphinxcontrib-htmlhelp==2.0.0 +sphinxcontrib-applehelp==2.0.0 +sphinxcontrib-devhelp==2.0.0 +sphinxcontrib-htmlhelp==2.1.0 sphinxcontrib-jsmath==1.0.1 -sphinxcontrib-qthelp==1.0.3 -sphinxcontrib-serializinghtml==1.1.5 -sphinxcontrib.applehelp==1.0.3 -tornado==6.3.2 -urllib3==1.26.14 -zipp==3.11.0 +sphinxcontrib-qthelp==2.0.0 +sphinxcontrib-serializinghtml==2.0.0 +typing_extensions==4.13.0 +urllib3==2.3.0 diff --git a/deps/uv/docs/src/design.rst b/deps/uv/docs/src/design.rst index 5a20595c3b42ce..7ad62076f33d7c 100644 --- a/deps/uv/docs/src/design.rst +++ b/deps/uv/docs/src/design.rst @@ -36,6 +36,31 @@ Requests represent (typically) short-lived operations. These operations can be p handle: write requests are used to write data on a handle; or standalone: getaddrinfo requests don't need a handle they run directly on the loop. +Guidelines for dealing with handles and requests: + +1. If `uv_foo_init()` succeeds in initializing the handle, you must call + :c:func:`uv_close()`. If the handle's init function errors, you don't + need to do anything. + +2. Only handles are closed, not requests. For example, :c:type:`uv_tcp_t` + is a handle, :c:type:`uv_write_t` is a request. + +3. The handle's memory can only be reclaimed or reused from inside the + :c:type:`uv_close_cb` or afterwards, not before. + +4. Most handles have init + start/stop functions; some handles don't. + Example: :c:type:`uv_tcp_t` vs. :c:type:`uv_process_t`; :c:func:`uv_spawn()` + combines handle initialization and process start into one. + +5. Requests are closed automatically when they complete, or when they are + cancelled with :c:func:`uv_cancel()`. + +6. No additional cleanup is needed except for :c:type:`uv_fs_t` and + :c:type:`uv_getaddrinfo_t` requests. For :c:type:`uv_fs_t`, call + :c:func:`uv_fs_req_cleanup()` once you are done with it; for + :c:type:`uv_getaddrinfo_t`, that's :c:func:`uv_freeaddrinfo()`. + +7. The request's memory can only be reclaimed or reused from that point onward. The I/O loop ^^^^^^^^^^^^ diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index 01a48e8edd85d8..99524e70289154 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -19,7 +19,7 @@ observable behavior. Libuv reverts to using its threadpool when the necessary kernel features are unavailable or unsuitable. Starting with libuv v1.49.0 this behavior was reverted and Libuv on Linux by default will be using the threadpool again. In order to enable io_uring the :c:type:`uv_loop_t` instance must be -configured with the :c:type:`UV_LOOP_ENABLE_IO_URING_SQPOLL` option. +configured with the :c:type:`UV_LOOP_USE_IO_URING_SQPOLL` option. .. note:: On Windows `uv_fs_*` functions use utf-8 encoding. @@ -129,7 +129,8 @@ Data types uint64_t f_bavail; uint64_t f_files; uint64_t f_ffree; - uint64_t f_spare[4]; + uint64_t f_frsize; + uint64_t f_spare[3]; } uv_statfs_t; .. c:enum:: uv_dirent_type_t diff --git a/deps/uv/docs/src/loop.rst b/deps/uv/docs/src/loop.rst index d1f41e1c9f4483..3d1973ba4f9f0c 100644 --- a/deps/uv/docs/src/loop.rst +++ b/deps/uv/docs/src/loop.rst @@ -86,12 +86,12 @@ API This option is necessary to use :c:func:`uv_metrics_idle_time`. - - UV_LOOP_ENABLE_IO_URING_SQPOLL: Enable SQPOLL io_uring instance to handle + - UV_LOOP_USE_IO_URING_SQPOLL: Enable SQPOLL io_uring instance to handle asynchronous file system operations. .. versionchanged:: 1.39.0 added the UV_METRICS_IDLE_TIME option. - .. versionchanged:: 1.49.0 added the UV_LOOP_ENABLE_IO_URING_SQPOLL option. + .. versionchanged:: 1.49.0 added the UV_LOOP_USE_IO_URING_SQPOLL option. .. c:function:: int uv_loop_close(uv_loop_t* loop) diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index db95e2dde83ea1..09db6244a0e1dc 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -522,6 +522,10 @@ API Gets the executable path. You *must* call `uv_setup_args` before calling this function. + Be careful in setuid executables. On some platforms the executable path + is an arbitrary string that is controlled by the user. On other platforms + environment variables are consulted that may be under control of the user. + .. c:function:: int uv_cwd(char* buffer, size_t* size) Gets the current working directory, and stores it in `buffer`. If the @@ -892,6 +896,16 @@ API .. versionadded:: 1.34.0 +.. code-block:: c + #include + #include + int main() { + printf("Sleeping for 1 second...\n"); + uv_sleep(1000); + printf("Awake!\n"); + return 0; + } + String manipulation functions ----------------------------- @@ -913,7 +927,7 @@ is not complete. `utf16_len` count (in characters) gives the length of `utf16`. If `utf16` is NUL terminated, `utf16_len` can be set to -1, otherwise it must be specified. If `wtf8_ptr` is `NULL`, no result will be computed, but the - length (equal to `uv_utf16_length_as_wtf8`) will be stored in `wtf8_ptr`. + length (equal to `uv_utf16_length_as_wtf8`) will be stored in `wtf8_len_ptr`. If `*wtf8_ptr` is `NULL`, space for the conversion will be allocated and returned in `wtf8_ptr` and the length will be returned in `wtf8_len_ptr`. Otherwise, the length of `*wtf8_ptr` must be passed in `wtf8_len_ptr`. The diff --git a/deps/uv/docs/src/pipe.rst b/deps/uv/docs/src/pipe.rst index 4abdc65e7153c7..bb77f90e3ce647 100644 --- a/deps/uv/docs/src/pipe.rst +++ b/deps/uv/docs/src/pipe.rst @@ -94,7 +94,7 @@ API Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between 92 and 108 bytes. -.. c:function:: void uv_pipe_connect2(uv_connect_t* req, uv_pipe_t* handle, const char* name, size_t namelen, unsigned int flags, uv_connect_cb cb) +.. c:function:: int uv_pipe_connect2(uv_connect_t* req, uv_pipe_t* handle, const char* name, size_t namelen, unsigned int flags, uv_connect_cb cb) Connect to the Unix domain socket or the Windows named pipe. diff --git a/deps/uv/docs/src/tcp.rst b/deps/uv/docs/src/tcp.rst index f9b203c41997d9..94a3b2741e48f4 100644 --- a/deps/uv/docs/src/tcp.rst +++ b/deps/uv/docs/src/tcp.rst @@ -91,6 +91,34 @@ API .. versionchanged:: 1.49.0 If `delay` is less than 1 then ``UV_EINVAL``` is returned. +.. c:function:: int uv_tcp_keepalive_ex(uv_tcp_t* handle, int on, unsigned int idle, unsigned int intvl, unsigned int cnt) + + Enable / disable TCP keep-alive with all socket options: `TCP_KEEPIDLE`, `TCP_KEEPINTVL` and `TCP_KEEPCNT`. + `idle` is the value for `TCP_KEEPIDLE`, `intvl` is the value for `TCP_KEEPINTVL`, + `cnt` is the value for `TCP_KEEPCNT`, ignored when `on` is zero. + + With TCP keep-alive enabled, `idle` is the time (in seconds) the connection needs to remain idle before + TCP starts sending keep-alive probes. `intvl` is the time (in seconds) between individual keep-alive probes. + TCP will drop the connection after sending `cnt` probes without getting any replies from the peer, then the + handle is destroyed with a ``UV_ETIMEDOUT`` error passed to the corresponding callback. + + If one of `idle`, `intvl`, or `cnt` is less than 1, ``UV_EINVAL`` is returned. + + .. versionchanged:: 1.52.0 added support of setting `TCP_KEEPINTVL` and `TCP_KEEPCNT` socket options. + + .. note:: + Ensure that the socket options are supported by the underlying operating system. + Currently supported platforms: + - AIX + - DragonFlyBSD + - FreeBSD + - illumos + - Linux + - macOS + - NetBSD + - Solaris + - Windows + .. c:function:: int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) Enable / disable simultaneous asynchronous accept requests that are diff --git a/deps/uv/docs/src/udp.rst b/deps/uv/docs/src/udp.rst index 5f225e5cda4011..39fe77f5e1b365 100644 --- a/deps/uv/docs/src/udp.rst +++ b/deps/uv/docs/src/udp.rst @@ -173,6 +173,22 @@ API .. versionadded:: 1.7.0 .. versionchanged:: 1.37.0 added the `UV_UDP_RECVMMSG` flag. +.. c:function:: int uv_udp_open_ex(uv_udp_t* handle, uv_os_sock_t sock, unsigned int flags) + + Opens an existing file descriptor or Windows SOCKET as a UDP handle. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :param sock: An existing socket to associate with the handle. + + :param flags: Flags that control socket behavior, + ``UV_UDP_REUSEADDR``, and ``UV_UDP_REUSEPORT`` are supported. + + :returns: 0 on success, or an error code < 0 on failure. + + .. versionadded:: 1.52.0 + .. c:function:: int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) Opens an existing file descriptor or Windows SOCKET as a UDP handle. @@ -189,6 +205,10 @@ API The passed file descriptor or SOCKET is not checked for its type, but it's required that it represents a valid datagram socket. + Internally sets the SO_REUSEADDR socket option unconditionally. This + means the reuse flag is always enabled, regardless of user intent. For + more control use :c:func:`uv_udp_open_ex`. + .. c:function:: int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags) Bind the UDP handle to an IP address and port. diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 938e998fdc54d1..3ba24e2ff44b6c 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -44,10 +44,8 @@ extern "C" { /* Building static library. */ # define UV_EXTERN /* nothing */ # endif -#elif __GNUC__ >= 4 +#elif defined(__GNUC__) # define UV_EXTERN __attribute__((visibility("default"))) -#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) /* Sun Studio >= 8 */ -# define UV_EXTERN __global #else # define UV_EXTERN /* nothing */ #endif @@ -604,6 +602,11 @@ UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable); UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay); +UV_EXTERN int uv_tcp_keepalive_ex(uv_tcp_t* handle, + int on, + unsigned int idle, + unsigned int intvl, + unsigned int cnt); UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable); enum uv_tcp_flags { @@ -741,6 +744,9 @@ struct uv_udp_send_s { UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle); UV_EXTERN int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, unsigned int flags); UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock); +UV_EXTERN int uv_udp_open_ex(uv_udp_t* handle, + uv_os_sock_t sock, + unsigned int flags); UV_EXTERN int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags); @@ -1254,7 +1260,8 @@ struct uv_statfs_s { uint64_t f_bavail; uint64_t f_files; uint64_t f_ffree; - uint64_t f_spare[4]; + uint64_t f_frsize; + uint64_t f_spare[3]; }; typedef enum { @@ -1964,7 +1971,6 @@ UV_EXTERN void uv_wtf8_to_utf16(const char* wtf8, size_t utf16_len); /* Don't export the private CPP symbols. */ -#undef UV_HANDLE_TYPE_PRIVATE #undef UV_REQ_TYPE_PRIVATE #undef UV_REQ_PRIVATE_FIELDS #undef UV_STREAM_PRIVATE_FIELDS @@ -1976,12 +1982,10 @@ UV_EXTERN void uv_wtf8_to_utf16(const char* wtf8, #undef UV_TIMER_PRIVATE_FIELDS #undef UV_GETADDRINFO_PRIVATE_FIELDS #undef UV_GETNAMEINFO_PRIVATE_FIELDS -#undef UV_FS_REQ_PRIVATE_FIELDS #undef UV_WORK_PRIVATE_FIELDS #undef UV_FS_EVENT_PRIVATE_FIELDS #undef UV_SIGNAL_PRIVATE_FIELDS #undef UV_LOOP_PRIVATE_FIELDS -#undef UV_LOOP_PRIVATE_PLATFORM_FIELDS #undef UV__ERR #ifdef __cplusplus diff --git a/deps/uv/include/uv/unix.h b/deps/uv/include/uv/unix.h index 7c972026f688e8..c6ba419da98b39 100644 --- a/deps/uv/include/uv/unix.h +++ b/deps/uv/include/uv/unix.h @@ -85,13 +85,10 @@ struct uv__io_s; struct uv_loop_s; -typedef void (*uv__io_cb)(struct uv_loop_s* loop, - struct uv__io_s* w, - unsigned int events); typedef struct uv__io_s uv__io_t; struct uv__io_s { - uv__io_cb cb; + uintptr_t bits; struct uv__queue pending_queue; struct uv__queue watcher_queue; unsigned int pevents; /* Pending event mask i.e. mask at next tick. */ diff --git a/deps/uv/include/uv/version.h b/deps/uv/include/uv/version.h index 77432f259588eb..b70cd6f60d08f6 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 51 +#define UV_VERSION_MINOR 52 #define UV_VERSION_PATCH 0 #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 index a88bf29e9ff504..7b4ebd4b7b2e85 100644 --- a/deps/uv/include/uv/win.h +++ b/deps/uv/include/uv/win.h @@ -279,7 +279,7 @@ typedef struct { DWORD tls_index; } uv_key_t; -#define UV_ONCE_INIT { 0, NULL } +#define UV_ONCE_INIT { 0, { NULL } } typedef struct uv_once_s { unsigned char unused; diff --git a/deps/uv/m4/libuv-check-flags.m4 b/deps/uv/m4/libuv-check-flags.m4 index 2a01308d37a0cb..ed3388b3ef0f2d 100644 --- a/deps/uv/m4/libuv-check-flags.m4 +++ b/deps/uv/m4/libuv-check-flags.m4 @@ -50,6 +50,24 @@ AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [ [$2], [$3]) ]) +dnl Check if the flag is supported by compiler with werror +dnl CC_CHECK_CFLAGS_SILENT_WERROR([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_CFLAGS_SILENT_WERROR], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_werror_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror $1" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([int a;])], + [eval "AS_TR_SH([cc_cv_cflags_werror_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_cflags_werror_$1])='no'"]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_werror_$1])[ = xyes], + [$2], [$3]) +]) + dnl Check if the flag is supported by compiler (cacheable) dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) @@ -67,11 +85,11 @@ dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found]) dnl Check for CFLAG and appends them to AM_CFLAGS if supported AC_DEFUN([CC_CHECK_CFLAG_APPEND], [ AC_CACHE_CHECK([if $CC supports $1 flag], - AS_TR_SH([cc_cv_cflags_$1]), - CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! + AS_TR_SH([cc_cv_cflags_werror_$1]), + CC_CHECK_CFLAGS_SILENT_WERROR([$1]) dnl Don't execute actions here! ) - AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_werror_$1])[ = xyes], [AM_CFLAGS="$AM_CFLAGS $1"; DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; $2], [$3]) AC_SUBST([AM_CFLAGS]) @@ -268,24 +286,6 @@ AC_DEFUN([CC_ATTRIBUTE_CONST], [ [$1], [$2]) ]) -AC_DEFUN([CC_FLAG_VISIBILITY], [ - AC_REQUIRE([CC_CHECK_WERROR]) - AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], - [cc_cv_flag_visibility], - [cc_flag_visibility_save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $cc_cv_werror" - CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], - cc_cv_flag_visibility='yes', - cc_cv_flag_visibility='no') - CFLAGS="$cc_flag_visibility_save_CFLAGS"]) - - AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], - [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, - [Define this if the compiler supports the -fvisibility flag]) - $1], - [$2]) -]) - AC_DEFUN([CC_FUNC_EXPECT], [ AC_REQUIRE([CC_CHECK_WERROR]) AC_CACHE_CHECK([if compiler has __builtin_expect function], diff --git a/deps/uv/src/idna.c b/deps/uv/src/idna.c index 5fcaf64c974a8a..4c876df9fd1c30 100644 --- a/deps/uv/src/idna.c +++ b/deps/uv/src/idna.c @@ -394,7 +394,7 @@ void uv_wtf8_to_utf16(const char* source_ptr, /* uv_wtf8_length_as_utf16 should have been called and checked first. */ assert(code_point >= 0); if (code_point > 0xFFFF) { - assert(code_point < 0x10FFFF); + assert(code_point <= 0x10FFFF); *w_target++ = (((code_point - 0x10000) >> 10) + 0xD800); *w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00; w_target_len -= 2; diff --git a/deps/uv/src/random.c b/deps/uv/src/random.c index 57fc0d911da316..402678cb69b504 100644 --- a/deps/uv/src/random.c +++ b/deps/uv/src/random.c @@ -61,7 +61,7 @@ static int uv__random(void* buf, size_t buflen) { # endif #elif defined(_WIN32) uv__once_init(); - rc = uv__random_rtlgenrandom(buf, buflen); + rc = uv__random_winrandom(buf, buflen); #else rc = uv__random_devurandom(buf, buflen); #endif diff --git a/deps/uv/src/threadpool.c b/deps/uv/src/threadpool.c index 98d81cc7b6a4ed..2a129a5d4a581b 100644 --- a/deps/uv/src/threadpool.c +++ b/deps/uv/src/threadpool.c @@ -194,11 +194,21 @@ void uv__threadpool_cleanup(void) { static void init_threads(void) { uv_thread_options_t config; unsigned int i; + size_t buflen; + char buf[16]; const char* val; + int err; + uv_sem_t sem; nthreads = ARRAY_SIZE(default_threads); - val = getenv("UV_THREADPOOL_SIZE"); + + buflen = ARRAY_SIZE(buf); + err = uv_os_getenv("UV_THREADPOOL_SIZE", buf, &buflen); + val = NULL; + if (err == 0) + val = buf; + if (val != NULL) nthreads = atoi(val); if (nthreads == 0) diff --git a/deps/uv/src/timer.c b/deps/uv/src/timer.c index 4525199ddc18c4..7cfca3b1fc04c9 100644 --- a/deps/uv/src/timer.c +++ b/deps/uv/src/timer.c @@ -22,7 +22,6 @@ #include "uv-common.h" #include "heap-inl.h" -#include #include diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index 48da0c9c40c842..30a2a894f2e939 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -229,28 +229,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } for (;;) { - /* Only need to set the provider_entry_time if timeout != 0. The function - * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. - */ - if (timeout != 0) - uv__metrics_set_provider_entry_time(loop); - - /* Store the current timeout in a location that's globally accessible so - * other locations like uv__work_done() can determine whether the queue - * of events in the callback were waiting when poll was called. - */ - lfields->current_timeout = timeout; - + uv__io_poll_prepare(loop, NULL, timeout); nfds = pollset_poll(loop->backend_fd, events, ARRAY_SIZE(events), timeout); - - /* 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 - * operating system didn't reschedule our process while in the syscall. - */ - SAVE_ERRNO(uv__update_time(loop)); + uv__io_poll_check(loop, NULL); if (nfds == 0) { if (reset_timeout != 0) { @@ -324,7 +308,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { have_signals = 1; } else { uv__metrics_update_idle_time(loop); - w->cb(loop, w, pe->revents); + uv__io_cb(loop, w, pe->revents); } nevents++; @@ -339,7 +323,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (have_signals != 0) { uv__metrics_update_idle_time(loop); - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + uv__signal_event(loop, &loop->signal_io_watcher, POLLIN); } loop->watchers[loop->nwatchers] = NULL; @@ -632,7 +616,7 @@ static int uv__skip_lines(char **p, int n) { while(n > 0) { *p = strchr(*p, '\n'); - if (!p) + if (!*p) return lines; (*p)++; @@ -716,7 +700,7 @@ static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) { /* This is the internal callback */ -static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) { +void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) { char result_data[RDWR_BUF_SIZE]; int bytes, rc = 0; uv_fs_event_t* handle; @@ -767,7 +751,11 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int handle->cb(handle, fname, events, 0); } -#endif +#else /* !HAVE_SYS_AHAFS_EVPRODS_H */ +void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) { + /* Stub function to satisfy the linker. */ +} +#endif /* HAVE_SYS_AHAFS_EVPRODS_H */ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { @@ -828,7 +816,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, /* Setup/Initialize all the libuv routines */ uv__handle_start(handle); - uv__io_init(&handle->event_watcher, uv__ahafs_event, fd); + uv__io_init(&handle->event_watcher, UV__AHAFS_EVENT, fd); handle->path = uv__strdup(filename); handle->cb = cb; handle->dir_filename = NULL; @@ -1288,12 +1276,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } -void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - uv__free(addresses); -} - - void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { struct pollfd* events; uintptr_t i; diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c index 538ae7876f2b24..f7995fc35197af 100644 --- a/deps/uv/src/unix/async.c +++ b/deps/uv/src/unix/async.c @@ -157,7 +157,7 @@ void uv__async_close(uv_async_t* handle) { } -static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { +void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { char buf[1024]; ssize_t r; struct uv__queue queue; @@ -308,7 +308,7 @@ static int uv__async_start(uv_loop_t* loop) { return err; #endif - err = uv__io_init_start(loop, &loop->async_io_watcher, uv__async_io, + err = uv__io_init_start(loop, &loop->async_io_watcher, UV__ASYNC_IO, pipefd[0], POLLIN); if (err < 0) { uv__close(pipefd[0]); @@ -409,10 +409,12 @@ static void uv__cpu_relax(void) { #if defined(__i386__) || defined(__x86_64__) __asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */ #elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__) - __asm__ __volatile__ ("yield" ::: "memory"); + __asm__ __volatile__ ("isb" ::: "memory"); #elif (defined(__ppc__) || defined(__ppc64__)) && defined(__APPLE__) __asm volatile ("" : : : "memory"); #elif !defined(__APPLE__) && (defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)) __asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory"); +#elif defined(__riscv) && __riscv_xlen == 64 + __asm__ volatile(".insn 0x0100000f" ::: "memory"); /* FENCE */ #endif } diff --git a/deps/uv/src/unix/bsd-ifaddrs.c b/deps/uv/src/unix/bsd-ifaddrs.c index 8d9ebd25d4306b..6829e2a8573aa6 100644 --- a/deps/uv/src/unix/bsd-ifaddrs.c +++ b/deps/uv/src/unix/bsd-ifaddrs.c @@ -155,10 +155,3 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return 0; } - - -/* TODO(bnoordhuis) share with linux.c */ -void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - uv__free(addresses); -} diff --git a/deps/uv/src/unix/bsd-proctitle.c b/deps/uv/src/unix/bsd-proctitle.c index b0c01e2cb855fc..761603995225d2 100644 --- a/deps/uv/src/unix/bsd-proctitle.c +++ b/deps/uv/src/unix/bsd-proctitle.c @@ -29,7 +29,7 @@ static uv_mutex_t process_title_mutex; static uv_once_t process_title_mutex_once = UV_ONCE_INIT; static char* process_title; - +char* uv_saved_argv0; static void init_process_title_mutex_once(void) { if (uv_mutex_init(&process_title_mutex)) @@ -45,6 +45,7 @@ void uv__process_title_cleanup(void) { char** uv_setup_args(int argc, char** argv) { process_title = argc > 0 ? uv__strdup(argv[0]) : NULL; + uv_saved_argv0 = argc > 0 ? uv__strdup(argv[0]) : NULL; return argv; } diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index bd51b69b8120e8..5d6160cb1b7395 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -275,7 +275,7 @@ void uv__make_close_pending(uv_handle_t* handle) { int uv__getiovmax(void) { #if defined(IOV_MAX) return IOV_MAX; -#elif defined(_SC_IOV_MAX) +#elif defined(_SC_IOV_MAX) && !defined(__QNX__) static _Atomic int iovmax_cached = -1; int iovmax; @@ -851,7 +851,7 @@ static void uv__run_pending(uv_loop_t* loop) { uv__queue_remove(q); uv__queue_init(q); w = uv__queue_data(q, uv__io_t, pending_queue); - w->cb(loop, w, POLLOUT); + uv__io_cb(loop, w, POLLOUT); } } @@ -903,20 +903,58 @@ static int maybe_resize(uv_loop_t* loop, unsigned int len) { } -void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { +void uv__io_cb(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + switch (uv__io_cb_get(w)) { + case UV__AHAFS_EVENT: + uv__ahafs_event(loop, w, events); + break; + case UV__ASYNC_IO: + uv__async_io(loop, w, events); + break; + case UV__FS_EVENT: + uv__fs_event(loop, w, events); + break; + case UV__FS_EVENT_READ: + uv__fs_event_read(loop, w, events); + break; + case UV__INOTIFY_READ: + uv__inotify_read(loop, w, events); + break; + case UV__POLL_IO: + uv__poll_io(loop, w, events); + break; + case UV__SERVER_IO: + uv__server_io(loop, w, events); + break; + case UV__STREAM_IO: + uv__stream_io(loop, w, events); + break; + case UV__UDP_IO: + uv__udp_io(loop, w, events); + break; + default: + UNREACHABLE(); + } +} + + +void uv__io_init(uv__io_t* w, uv__io_cb_t cb, int fd) { assert(fd >= -1); uv__queue_init(&w->pending_queue); uv__queue_init(&w->watcher_queue); - w->cb = cb; w->fd = fd; + w->bits = 0; w->events = 0; w->pevents = 0; + uv__io_cb_set(w, cb); } int uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int err; + assert(uv__io_cb_get(w) >= UV__AHAFS_EVENT); + assert(uv__io_cb_get(w) <= UV__UDP_IO); assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); assert(w->fd >= 0); @@ -950,17 +988,16 @@ int uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int uv__io_init_start(uv_loop_t* loop, uv__io_t* w, - uv__io_cb cb, + uv__io_cb_t cb, int fd, unsigned int events) { int err; - assert(cb != NULL); assert(fd > -1); uv__io_init(w, cb, fd); err = uv__io_start(loop, w, events); if (err) - uv__io_init(w, NULL, -1); + uv__io_init(w, UV__NO_IO_CB, -1); return err; } @@ -1019,6 +1056,39 @@ int uv__io_active(const uv__io_t* w, unsigned int events) { } +void uv__io_poll_prepare(uv_loop_t* loop, sigset_t* pset, int timeout) { + uv__loop_internal_fields_t* lfields; + + /* Only need to set the provider_entry_time if timeout != 0. The function + * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. + */ + if (timeout != 0) + uv__metrics_set_provider_entry_time(loop); + + /* Store the current timeout in a location that's globally accessible so + * other locations like uv__work_done() can determine whether the queue + * of events in the callback were waiting when poll was called. + */ + lfields = uv__get_internal_fields(loop); + lfields->current_timeout = timeout; + + if (pset != NULL) + if (pthread_sigmask(SIG_BLOCK, pset, NULL)) + abort(); +} + +void uv__io_poll_check(uv_loop_t* loop, sigset_t* pset) { + if (pset != NULL) + if (pthread_sigmask(SIG_UNBLOCK, pset, NULL)) + abort(); + + /* 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 + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); +} + int uv__fd_exists(uv_loop_t* loop, int fd) { return (unsigned) fd < loop->nwatchers && loop->watchers[fd] != NULL; } @@ -1496,7 +1566,7 @@ int uv_os_environ(uv_env_item_t** envitems, int* count) { fail: for (i = 0; i < cnt; i++) { - envitem = &(*envitems)[cnt]; + envitem = &(*envitems)[i]; uv__free(envitem->name); } uv__free(*envitems); @@ -1611,6 +1681,10 @@ int uv_cpumask_size(void) { } int uv_os_getpriority(uv_pid_t pid, int* priority) { +#if defined(__QNX__) + /* QNX priority is not process-based */ + return UV_ENOSYS; +#else int r; if (priority == NULL) @@ -1624,10 +1698,15 @@ int uv_os_getpriority(uv_pid_t pid, int* priority) { *priority = r; return 0; +#endif } int uv_os_setpriority(uv_pid_t pid, int priority) { +#if defined(__QNX__) + /* QNX priority is not process-based */ + return UV_ENOSYS; +#else if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW) return UV_EINVAL; @@ -1635,6 +1714,7 @@ int uv_os_setpriority(uv_pid_t pid, int priority) { return UV__ERR(errno); return 0; +#endif } /** @@ -1656,7 +1736,7 @@ int uv_thread_getpriority(uv_thread_t tid, int* priority) { r = pthread_getschedparam(tid, &policy, ¶m); if (r != 0) - return UV__ERR(errno); + return UV__ERR(r); #ifdef __linux__ if (SCHED_OTHER == policy && pthread_equal(tid, pthread_self())) { @@ -1709,7 +1789,7 @@ int uv_thread_setpriority(uv_thread_t tid, int priority) { r = pthread_getschedparam(tid, &policy, ¶m); if (r != 0) - return UV__ERR(errno); + return UV__ERR(r); #ifdef __linux__ /** @@ -1757,7 +1837,7 @@ int uv_thread_setpriority(uv_thread_t tid, int priority) { param.sched_priority = prio; r = pthread_setschedparam(tid, policy, ¶m); if (r != 0) - return UV__ERR(errno); + return UV__ERR(r); } return 0; @@ -1998,8 +2078,8 @@ unsigned int uv_available_parallelism(void) { #elif defined(__NetBSD__) cpuset_t* set = cpuset_create(); if (set != NULL) { - if (0 == sched_getaffinity_np(getpid(), sizeof(set), &set)) - rc = uv__cpu_count(&set); + if (0 == sched_getaffinity_np(getpid(), cpuset_size(set), set)) + rc = uv__cpu_count(set); cpuset_destroy(set); } #elif defined(__APPLE__) diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c index 009efbefaa70ee..98ddf27287580b 100644 --- a/deps/uv/src/unix/darwin.c +++ b/deps/uv/src/unix/darwin.c @@ -126,7 +126,15 @@ uint64_t uv_get_constrained_memory(void) { uint64_t uv_get_available_memory(void) { - return uv_get_free_memory(); + vm_statistics_data_t info; + mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t); + + if (host_statistics(mach_host_self(), HOST_VM_INFO, + (host_info_t)&info, &count) != KERN_SUCCESS) { + return 0; + } + + return ((uint64_t) info.free_count + (uint64_t) info.inactive_count + (uint64_t) info.purgeable_count) * sysconf(_SC_PAGESIZE); } diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 717f3fab36939e..fc0fe0a269116b 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -211,7 +211,8 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { || defined(__NetBSD__) \ || defined(__OpenBSD__) \ || defined(__linux__) \ - || defined(__sun) + || defined(__sun) \ + || defined(__QNX__) static struct timespec uv__fs_to_timespec(double time) { struct timespec ts; @@ -223,13 +224,6 @@ static struct timespec uv__fs_to_timespec(double time) { ts.tv_sec = time; ts.tv_nsec = (time - ts.tv_sec) * 1e9; - /* TODO(bnoordhuis) Remove this. utimesat() has nanosecond resolution but we - * stick to microsecond resolution for the sake of consistency with other - * platforms. I'm the original author of this compatibility hack but I'm - * less convinced it's useful nowadays. - */ - ts.tv_nsec -= ts.tv_nsec % 1000; - if (ts.tv_nsec < 0) { ts.tv_nsec += 1e9; ts.tv_sec -= 1; @@ -248,7 +242,8 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { || defined(__NetBSD__) \ || defined(__OpenBSD__) \ || defined(__linux__) \ - || defined(__sun) + || defined(__sun) \ + || defined(__QNX__) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); @@ -716,6 +711,11 @@ static int uv__fs_statfs(uv_fs_t* req) { stat_fs->f_bavail = buf.f_bavail; stat_fs->f_files = buf.f_files; stat_fs->f_ffree = buf.f_ffree; +#if defined(__linux__) + stat_fs->f_frsize = buf.f_frsize; +#else + stat_fs->f_frsize = buf.f_bsize; +#endif req->ptr = stat_fs; return 0; } @@ -1147,7 +1147,8 @@ static ssize_t uv__fs_utime(uv_fs_t* req) { || defined(__NetBSD__) \ || defined(__OpenBSD__) \ || defined(__linux__) \ - || defined(__sun) + || defined(__sun) \ + || defined(__QNX__) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); @@ -1181,7 +1182,8 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) { || defined(__NetBSD__) \ || defined(__OpenBSD__) \ || defined(__linux__) \ - || defined(__sun) + || defined(__sun) \ + || defined(__QNX__) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); diff --git a/deps/uv/src/unix/getaddrinfo.c b/deps/uv/src/unix/getaddrinfo.c index b7075343666590..6c44012726b53b 100644 --- a/deps/uv/src/unix/getaddrinfo.c +++ b/deps/uv/src/unix/getaddrinfo.c @@ -89,9 +89,7 @@ int uv__getaddrinfo_translate_error(int sys_err) { } assert(!"unknown EAI_* error code"); abort(); -#ifndef __SUNPRO_C return 0; /* Pacify compiler. */ -#endif } diff --git a/deps/uv/src/unix/ibmi.c b/deps/uv/src/unix/ibmi.c index 9d94d2af54468a..f4f8748a8cee6d 100644 --- a/deps/uv/src/unix/ibmi.c +++ b/deps/uv/src/unix/ibmi.c @@ -505,11 +505,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } -void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - uv__free(addresses); -} - char** uv_setup_args(int argc, char** argv) { char exepath[UV__PATH_MAX]; char* s; @@ -543,3 +538,9 @@ int uv_get_process_title(char* buffer, size_t size) { void uv__process_title_cleanup(void) { } + +void uv__ahafs_event(uv_loop_t* loop, + uv__io_t* event_watch, + unsigned int fflags) { + /* Stub function to satisfy the linker. */ +} diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index a1d7d4366308ac..6359694c2a411d 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -141,6 +141,11 @@ union uv__sockaddr { /* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */ #ifdef POLLRDHUP # define UV__POLLRDHUP POLLRDHUP +#elif defined(__QNX__) +/* On QNX, POLLRDHUP is not available and the 0x2000 workaround + * leads to undefined bahavior. + */ +# define UV__POLLRDHUP 0 #else # define UV__POLLRDHUP 0x2000 #endif @@ -256,11 +261,64 @@ ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags); void uv__make_close_pending(uv_handle_t* handle); int uv__getiovmax(void); -void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd); +typedef enum { + UV__NO_IO_CB, + UV__AHAFS_EVENT, + UV__ASYNC_IO, + UV__FS_EVENT, + UV__FS_EVENT_READ, + UV__INOTIFY_READ, + UV__POLL_IO, + UV__SIGNAL_EVENT, + UV__SERVER_IO, + UV__STREAM_IO, + UV__UDP_IO, +} uv__io_cb_t; + +#define uv__io_cb_get(w) ((uv__io_cb_t)((w)->bits & 15)) +#define uv__io_cb_set(w, cb) \ + do { \ + (w)->bits -= uv__io_cb_get(w); \ + (w)->bits |= (cb) & 15; \ + } while (0) + +void uv__ahafs_event(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__fs_event_read(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__inotify_read(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); + +#ifndef _AIX +#define uv__ahafs_event(loop, w, events) UNREACHABLE() +#endif + +#if !defined(__APPLE__) && \ + !defined(__DragonFly__) && \ + !defined(__FreeBSD__) && \ + !defined(__NetBSD__) && \ + !defined(__OpenBSD__) +#define uv__fs_event(loop, w, events) UNREACHABLE() +#endif + +#ifndef __linux__ +#define uv__inotify_read(loop, w, events) UNREACHABLE() +#endif + +#ifndef __sun__ +#define uv__fs_event_read(loop, w, events) UNREACHABLE() +#endif + +void uv__io_cb(uv_loop_t* loop, uv__io_t* w, unsigned int events); +void uv__io_init(uv__io_t* w, uv__io_cb_t cb, int fd); int uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events); int uv__io_init_start(uv_loop_t* loop, uv__io_t* w, - uv__io_cb cb, + uv__io_cb_t cb, int fd, unsigned int events); void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events); @@ -270,6 +328,8 @@ 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); +void uv__io_poll_prepare(uv_loop_t* loop, sigset_t* pset, int timeout); +void uv__io_poll_check(uv_loop_t* loop, sigset_t* pset); int uv__fd_exists(uv_loop_t* loop, int fd); /* async */ @@ -299,7 +359,11 @@ int uv__slurp(const char* filename, char* buf, size_t len); /* tcp */ int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb); int uv__tcp_nodelay(int fd, int on); -int uv__tcp_keepalive(int fd, int on, unsigned int delay); +int uv__tcp_keepalive(int fd, + int on, + unsigned int idle, + unsigned int intvl, + unsigned int cnt); /* tty */ void uv__tty_close(uv_tty_t* handle); @@ -527,4 +591,6 @@ int uv__get_constrained_cpu(long long* quota); #define UV__KQUEUE_EVFILT_USER 0 #endif +extern char* uv_saved_argv0; + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 39b72012c26955..27d28814363371 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -48,8 +48,6 @@ #define EV_OOBAND EV_FLAG1 #endif -static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags); - int uv__kqueue_init(uv_loop_t* loop) { loop->backend_fd = kqueue(); @@ -204,7 +202,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { fflags = 0; op = EV_ADD; - if (w->cb == uv__fs_event) { + if (UV__FS_EVENT == uv__io_cb_get(w)) { filter = EVFILT_VNODE; fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE; @@ -263,32 +261,19 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } for (;; nevents = 0) { - /* Only need to set the provider_entry_time if timeout != 0. The function - * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. - */ - if (timeout != 0) - uv__metrics_set_provider_entry_time(loop); - if (timeout != -1) { spec.tv_sec = timeout / 1000; spec.tv_nsec = (timeout % 1000) * 1000000; } - if (pset != NULL) - pthread_sigmask(SIG_BLOCK, pset, NULL); - - /* Store the current timeout in a location that's globally accessible so - * other locations like uv__work_done() can determine whether the queue - * of events in the callback were waiting when poll was called. - */ - lfields->current_timeout = timeout; - + uv__io_poll_prepare(loop, pset, timeout); nfds = kevent(loop->backend_fd, events, nevents, events, ARRAY_SIZE(events), timeout == -1 ? NULL : &spec); + uv__io_poll_check(loop, pset); if (nfds == -1) assert(errno == EINTR); @@ -296,15 +281,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { /* Unlimited timeout should only return with events or signal. */ assert(timeout != -1); - if (pset != NULL) - pthread_sigmask(SIG_UNBLOCK, pset, NULL); - - /* 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 - * operating system didn't reschedule our process while in the syscall. - */ - uv__update_time(loop); - if (nfds == 0 || nfds == -1) { /* If kqueue is empty or interrupted, we might still have children ready * to reap immediately. */ @@ -366,7 +342,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w = &loop->async_io_watcher; assert(fd == w->fd); uv__metrics_update_idle_time(loop); - w->cb(loop, w, w->events); + uv__io_cb(loop, w, w->events); nevents++; continue; } @@ -376,7 +352,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { assert(w->events == POLLIN); assert(w->pevents == POLLIN); uv__metrics_update_idle_time(loop); - w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ + uv__io_cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ nevents++; continue; } @@ -420,7 +396,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { have_signals = 1; } else { uv__metrics_update_idle_time(loop); - w->cb(loop, w, revents); + uv__io_cb(loop, w, revents); } nevents++; @@ -440,7 +416,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (have_signals != 0) { uv__metrics_update_idle_time(loop); - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + uv__signal_event(loop, &loop->signal_io_watcher, POLLIN); } loop->watchers[loop->nwatchers] = NULL; @@ -496,7 +472,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { } -static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) { +void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) { uv_fs_event_t* handle; struct kevent ev; int events; @@ -622,7 +598,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, r = uv__io_init_start(handle->loop, &handle->event_watcher, - uv__fs_event, + UV__FS_EVENT, fd, POLLIN); diff --git a/deps/uv/src/unix/linux.c b/deps/uv/src/unix/linux.c index ea3e2de0384b2c..60551cbf74b68a 100644 --- a/deps/uv/src/unix/linux.c +++ b/deps/uv/src/unix/linux.c @@ -267,9 +267,6 @@ struct watcher_root { }; static int uv__inotify_fork(uv_loop_t* loop, struct watcher_list* root); -static void uv__inotify_read(uv_loop_t* loop, - uv__io_t* w, - unsigned int revents); static int compare_watchers(const struct watcher_list* a, const struct watcher_list* b); static void maybe_free_watcher_list(struct watcher_list* w, @@ -878,7 +875,7 @@ int uv__iou_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req) { return 0; sqe->fd = req->file; - sqe->len = req->off; + sqe->off = req->off; sqe->opcode = UV__IORING_OP_FTRUNCATE; uv__iou_submit(iou); @@ -1450,25 +1447,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { while (*ctl->sqhead != *ctl->sqtail) uv__epoll_ctl_flush(epollfd, ctl, &prep); - /* Only need to set the provider_entry_time if timeout != 0. The function - * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. - */ - if (timeout != 0) - uv__metrics_set_provider_entry_time(loop); - - /* Store the current timeout in a location that's globally accessible so - * other locations like uv__work_done() can determine whether the queue - * of events in the callback were waiting when poll was called. - */ - lfields->current_timeout = timeout; - + uv__io_poll_prepare(loop, NULL, timeout); nfds = epoll_pwait(epollfd, events, ARRAY_SIZE(events), timeout, sigmask); - - /* 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 - * operating system didn't reschedule our process while in the syscall. - */ - SAVE_ERRNO(uv__update_time(loop)); + uv__io_poll_check(loop, NULL); if (nfds == -1) assert(errno == EINTR); @@ -1562,7 +1543,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { have_signals = 1; } else { uv__metrics_update_idle_time(loop); - w->cb(loop, w, pe->events); + uv__io_cb(loop, w, pe->events); } nevents++; @@ -1578,7 +1559,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (have_signals != 0) { uv__metrics_update_idle_time(loop); - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + uv__signal_event(loop, &loop->signal_io_watcher, POLLIN); } lfields->inv = NULL; @@ -1750,7 +1731,7 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) { "0xd0b\nCortex-A76\n" "0xd0c\nNeoverse-N1\n" "0xd0d\nCortex-A77\n" "0xd0e\nCortex-A76AE\n" "0xd13\nCortex-R52\n" "0xd20\nCortex-M23\n" "0xd21\nCortex-M33\n" "0xd41\nCortex-A78\n" "0xd42\nCortex-A78AE\n" - "0xd4a\nNeoverse-E1\n" "0xd4b\nCortex-A78C\n" + "0xd4a\nNeoverse-E1\n" "0xd4b\nCortex-A78C\n" "0xd4f\nNeoverse-V2\n" #endif ""; struct cpu { @@ -2045,13 +2026,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } -/* TODO(bnoordhuis) share with bsd-ifaddrs.c */ -void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - uv__free(addresses); -} - - void uv__set_process_title(const char* title) { #if defined(PR_SET_NAME) prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */ @@ -2309,8 +2283,8 @@ static int uv__get_cgroupv2_constrained_cpu(const char* cgroup, static const char cgroup_mount[] = "/sys/fs/cgroup"; const char* cgroup_trimmed; char buf[1024]; - char full_path[256]; char path[256]; + char full_path[sizeof(path) + sizeof("/cpu.max")]; char quota_buf[16]; char* last_slash; int cgroup_size; @@ -2370,6 +2344,8 @@ static int uv__get_cgroupv2_constrained_cpu(const char* cgroup, goto next; *quota = limit / period; + if (*quota == 0) + *quota = 1; if (*quota < min_quota) min_quota = *quota; @@ -2499,7 +2475,7 @@ static int init_inotify(uv_loop_t* loop) { if (fd < 0) return UV__ERR(errno); - err = uv__io_init_start(loop, &loop->inotify_read_watcher, uv__inotify_read, + err = uv__io_init_start(loop, &loop->inotify_read_watcher, UV__INOTIFY_READ, fd, POLLIN); if (err) { uv__close(fd); @@ -2595,9 +2571,7 @@ static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) { } -static void uv__inotify_read(uv_loop_t* loop, - uv__io_t* dummy, - unsigned int events) { +void uv__inotify_read(uv_loop_t* loop, uv__io_t* dummy, unsigned int events) { const struct inotify_event* e; struct watcher_list* w; uv_fs_event_t* h; diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index 5d3f0c7a348b33..da9fa3c8b80b86 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -83,7 +83,7 @@ int uv_loop_init(uv_loop_t* loop) { uv__signal_global_once_init(); err = uv__process_init(loop); if (err) - goto fail_signal_init; + goto fail_process_init; uv__queue_init(&loop->process_handles); err = uv_rwlock_init(&loop->cloexec_lock); @@ -110,9 +110,8 @@ int uv_loop_init(uv_loop_t* loop) { uv_rwlock_destroy(&loop->cloexec_lock); fail_rwlock_init: +fail_process_init: uv__signal_loop_cleanup(loop); - -fail_signal_init: uv__platform_loop_delete(loop); if (loop->backend_fd != -1) { diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index cf20fa6658209d..a6d58b948e41dd 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -59,54 +59,13 @@ void uv_loadavg(double avg[3]) { int uv_exepath(char* buffer, size_t* size) { - int mib[4]; - char **argsbuf = NULL; - size_t argsbuf_size = 100U; - size_t exepath_size; - pid_t mypid; - int err; - if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; - mypid = getpid(); - for (;;) { - err = UV_ENOMEM; - argsbuf = uv__reallocf(argsbuf, argsbuf_size); - if (argsbuf == NULL) - goto out; - mib[0] = CTL_KERN; - mib[1] = KERN_PROC_ARGS; - mib[2] = mypid; - mib[3] = KERN_PROC_ARGV; - if (sysctl(mib, ARRAY_SIZE(mib), argsbuf, &argsbuf_size, NULL, 0) == 0) { - break; - } - if (errno != ENOMEM) { - err = UV__ERR(errno); - goto out; - } - argsbuf_size *= 2U; - } - - if (argsbuf[0] == NULL) { - err = UV_EINVAL; /* FIXME(bnoordhuis) More appropriate error. */ - goto out; - } - - *size -= 1; - exepath_size = strlen(argsbuf[0]); - if (*size > exepath_size) - *size = exepath_size; - - memcpy(buffer, argsbuf[0], *size); - buffer[*size] = '\0'; - err = 0; - -out: - uv__free(argsbuf); + if (uv_saved_argv0 == NULL) + return UV_EINVAL; - return err; + return uv__search_path(uv_saved_argv0, buffer, size); } diff --git a/deps/uv/src/unix/os390.c b/deps/uv/src/unix/os390.c index 1b277292aebffb..c049884c4be35c 100644 --- a/deps/uv/src/unix/os390.c +++ b/deps/uv/src/unix/os390.c @@ -892,30 +892,15 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { nfds = 0; for (;;) { - /* Only need to set the provider_entry_time if timeout != 0. The function - * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. - */ - if (timeout != 0) - uv__metrics_set_provider_entry_time(loop); - if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) timeout = max_safe_timeout; - /* Store the current timeout in a location that's globally accessible so - * other locations like uv__work_done() can determine whether the queue - * of events in the callback were waiting when poll was called. - */ - lfields->current_timeout = timeout; - + uv__io_poll_prepare(loop, NULL, timeout); nfds = epoll_wait(loop->ep, events, ARRAY_SIZE(events), timeout); - - /* 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 - * operating system didn't reschedule our process while in the syscall. - */ base = loop->time; - SAVE_ERRNO(uv__update_time(loop)); + uv__io_poll_check(loop, NULL); + if (nfds == 0) { assert(timeout != -1); @@ -1008,7 +993,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { have_signals = 1; } else { uv__metrics_update_idle_time(loop); - w->cb(loop, w, pe->events); + uv__io_cb(loop, w, pe->events); } nevents++; } @@ -1023,7 +1008,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (have_signals != 0) { uv__metrics_update_idle_time(loop); - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + uv__signal_event(loop, &loop->signal_io_watcher, POLLIN); } loop->watchers[loop->nwatchers] = NULL; diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index 68e225e2e17fbb..eb03a47cccbe10 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -170,9 +170,8 @@ int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { return UV__ERR(errno); handle->connection_cb = cb; - handle->io_watcher.cb = uv__server_io; - uv__io_start(handle->loop, &handle->io_watcher, POLLIN); - return 0; + uv__io_cb_set(&handle->io_watcher, UV__SERVER_IO); + return uv__io_start(handle->loop, &handle->io_watcher, POLLIN); } diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c index 535ac6baafc6e0..60c3c20096f2b5 100644 --- a/deps/uv/src/unix/poll.c +++ b/deps/uv/src/unix/poll.c @@ -26,7 +26,7 @@ #include -static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { +void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { uv_poll_t* handle; int pevents; @@ -87,7 +87,7 @@ int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { return err; uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL); - uv__io_init(&handle->io_watcher, uv__poll_io, fd); + uv__io_init(&handle->io_watcher, UV__POLL_IO, fd); handle->poll_cb = NULL; return 0; } diff --git a/deps/uv/src/unix/posix-poll.c b/deps/uv/src/unix/posix-poll.c index 2e016c2fbaed2e..5b7d75c22588de 100644 --- a/deps/uv/src/unix/posix-poll.c +++ b/deps/uv/src/unix/posix-poll.c @@ -195,31 +195,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * our caller then we need to loop around and poll() again. */ for (;;) { - /* Only need to set the provider_entry_time if timeout != 0. The function - * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. - */ - if (timeout != 0) - uv__metrics_set_provider_entry_time(loop); - - /* Store the current timeout in a location that's globally accessible so - * other locations like uv__work_done() can determine whether the queue - * of events in the callback were waiting when poll was called. - */ - lfields->current_timeout = timeout; - - if (pset != NULL) - if (pthread_sigmask(SIG_BLOCK, pset, NULL)) - abort(); + uv__io_poll_prepare(loop, pset, timeout); nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout); - if (pset != NULL) - if (pthread_sigmask(SIG_UNBLOCK, pset, NULL)) - abort(); - - /* 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 - * operating system didn't reschedule our process while in the syscall. - */ - SAVE_ERRNO(uv__update_time(loop)); + uv__io_poll_check(loop, pset); if (nfds == 0) { if (reset_timeout != 0) { @@ -294,7 +272,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { have_signals = 1; } else { uv__metrics_update_idle_time(loop); - w->cb(loop, w, pe->revents); + uv__io_cb(loop, w, pe->revents); } nevents++; @@ -310,7 +288,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (have_signals != 0) { uv__metrics_update_idle_time(loop); - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + uv__signal_event(loop, &loop->signal_io_watcher, POLLIN); } loop->poll_fds_iterating = 0; diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 43e6b798458fc1..539e7d9417d3bf 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -1073,6 +1073,7 @@ int uv_spawn(uv_loop_t* loop, return exec_errorno; error: + uv__queue_remove(&process->handle_queue); if (pipes != NULL) { for (i = 0; i < stdio_count; i++) { if (i < options->stdio_count) diff --git a/deps/uv/src/unix/qnx.c b/deps/uv/src/unix/qnx.c index 57ea9dfd9ccc9c..d873165feee377 100644 --- a/deps/uv/src/unix/qnx.c +++ b/deps/uv/src/unix/qnx.c @@ -28,6 +28,14 @@ #include #include #include +#include +#include +#include +#if __QNX__ >= 800 +#define cpuinfo_val cpuinfo +#else +#define cpuinfo_val new_cpuinfo +#endif static void get_mem_info(uint64_t* totalmem, uint64_t* freemem) { @@ -67,18 +75,44 @@ int uv_exepath(char* buffer, size_t* size) { } +static uint64_t uv__read_pidin_info(const char* what) { + uint64_t rc; + char* p; + char buf[2048]; + + FILE* fp = popen("pidin info", "r"); + if (fp == NULL) + return 0; + + size_t sz = fread(buf, 1, sizeof(buf) - 1, fp); + buf[sz] = '\0'; + + pclose(fp); + + p = strstr(buf, what); + if (p == NULL) + return 0; + + p += strlen(what); + + rc = 0; + sscanf(p, "%" PRIu64 " MB", &rc); + + return rc * 1024 * 1024; +} + uint64_t uv_get_free_memory(void) { - uint64_t totalmem; uint64_t freemem; - get_mem_info(&totalmem, &freemem); + + freemem = uv__read_pidin_info("FreeMem:"); return freemem; } uint64_t uv_get_total_memory(void) { uint64_t totalmem; - uint64_t freemem; - get_mem_info(&totalmem, &freemem); + + totalmem = uv__read_pidin_info("MB/"); return totalmem; } @@ -113,15 +147,17 @@ int uv_resident_set_memory(size_t* rss) { int uv_uptime(double* uptime) { - struct qtime_entry* qtime = _SYSPAGE_ENTRY(_syspage_ptr, qtime); - *uptime = (qtime->nsec / 1000000000.0); + struct timespec ts; + if(clock_gettime(CLOCK_MONOTONIC, &ts)) + return UV__ERR(errno); + *uptime = (double)ts.tv_sec; return 0; } int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { struct cpuinfo_entry* cpuinfo = - (struct cpuinfo_entry*)_SYSPAGE_ENTRY(_syspage_ptr, new_cpuinfo); + (struct cpuinfo_entry*)_SYSPAGE_ENTRY(_syspage_ptr, cpuinfo_val); size_t cpuinfo_size = _SYSPAGE_ELEMENT_SIZE(_syspage_ptr, cpuinfo); struct strings_entry* strings = _SYSPAGE_ENTRY(_syspage_ptr, strings); int num_cpus = _syspage_ptr->num_cpu; diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c index ccaa72db457c59..91fb149464e32e 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/src/unix/signal.c @@ -45,7 +45,6 @@ static int uv__signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum, int oneshot); -static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events); static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2); static void uv__signal_stop(uv_signal_t* handle); static void uv__signal_unregister_handler(int signum); @@ -271,7 +270,7 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) { if (err) return err; - err = uv__io_init_start(loop, &loop->signal_io_watcher, uv__signal_event, + err = uv__io_init_start(loop, &loop->signal_io_watcher, UV__SIGNAL_EVENT, pipefd[0], POLLIN); if (err) { uv__close(pipefd[0]); @@ -436,9 +435,7 @@ static int uv__signal_start(uv_signal_t* handle, } -static void uv__signal_event(uv_loop_t* loop, - uv__io_t* w, - unsigned int events) { +void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events) { uv__signal_msg_t* msg; uv_signal_t* handle; char buf[sizeof(uv__signal_msg_t) * 32]; diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 18763b4744c30a..08a18314b1ec4e 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -73,7 +73,6 @@ STATIC_ASSERT(256 == sizeof(union uv__cmsg)); static void uv__stream_connect(uv_stream_t*); static void uv__write(uv_stream_t* stream); static void uv__read(uv_stream_t* stream); -static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); static void uv__write_callbacks(uv_stream_t* stream); static size_t uv__write_req_size(uv_write_t* req); static void uv__drain(uv_stream_t* stream); @@ -113,7 +112,7 @@ void uv__stream_init(uv_loop_t* loop, stream->select = NULL; #endif /* defined(__APPLE_) */ - uv__io_init(&stream->io_watcher, uv__stream_io, -1); + uv__io_init(&stream->io_watcher, UV__STREAM_IO, -1); } @@ -417,7 +416,7 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { /* TODO Use delay the user passed in. */ if ((stream->flags & UV_HANDLE_TCP_KEEPALIVE) && - uv__tcp_keepalive(fd, 1, 60)) { + uv__tcp_keepalive(fd, 1, 60, 1, 10)) { return UV__ERR(errno); } } @@ -1031,8 +1030,6 @@ static void uv__read(uv_stream_t* stream) { int err; int is_ipc; - 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. */ @@ -1147,11 +1144,15 @@ static void uv__read(uv_stream_t* stream) { #endif stream->read_cb(stream, nread, &buf); - /* Return if we didn't fill the buffer, there is no more data to read. */ - if (nread < buflen) { - stream->flags |= UV_HANDLE_READ_PARTIAL; + /* Save a system call and return if we didn't fill the buffer + * completely, on the assumption the next read() will fail with EOF. + * + * Devices like PTYs sometimes operate in a packet-like mode where + * they don't return all available data in a single read but we'll + * catch it on the next read because of level-triggered I/O. + */ + if (nread < buflen) return; - } } } } @@ -1186,7 +1187,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { } -static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { +void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { uv_stream_t* stream; stream = container_of(w, uv_stream_t, io_watcher); @@ -1203,22 +1204,23 @@ 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 if it's set, there may still be data to read. */ - if (events & (POLLIN | POLLERR | POLLHUP)) + if (events & (POLLIN | POLLERR)) uv__read(stream); if (uv__stream_fd(stream) == -1) return; /* read_cb closed stream. */ /* Short-circuit iff POLLHUP is set, the user is still interested in read - * events and uv__read() reported a partial read but not EOF. If the EOF - * flag is set, uv__read() called read_cb with err=UV_EOF and we don't - * have to do anything. If the partial read flag is not set, we can't - * report the EOF yet because there is still data to read. + * events and uv__read() didn't see EOF. If the EOF flag is set, uv__read() + * called read_cb with err=UV_EOF and we don't have to do anything. + * + * POLLIN should not be set because, at least on Linux and possibly other + * operating systems, devices like PTYs sometimes produce partial reads even + * when more data is available. */ if ((events & POLLHUP) && + !(events & POLLIN) && (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); @@ -1295,12 +1297,18 @@ static void uv__stream_connect(uv_stream_t* stream) { static int uv__check_before_write(uv_stream_t* stream, unsigned int nbufs, uv_stream_t* send_handle) { - assert(nbufs > 0); assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY) && "uv_write (unix) does not yet support other types of streams"); + /* We're not beholden to IOV_MAX but limit the buffer count to catch sign + * conversion bugs where a caller passes in a signed negative number that + * then gets converted to a really large unsigned number. + */ + if (nbufs < 1 || nbufs > 1024*1024) + return UV_EINVAL; + if (uv__stream_fd(stream) < 0) return UV_EBADF; diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index 6c38c31aa00efa..f3fbca3908ca5b 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -210,12 +210,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } for (;;) { - /* Only need to set the provider_entry_time if timeout != 0. The function - * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. - */ - if (timeout != 0) - uv__metrics_set_provider_entry_time(loop); - if (timeout != -1) { spec.tv_sec = timeout / 1000; spec.tv_nsec = (timeout % 1000) * 1000000; @@ -227,17 +221,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { nfds = 1; saved_errno = 0; - if (pset != NULL) - pthread_sigmask(SIG_BLOCK, pset, NULL); - + uv__io_poll_prepare(loop, pset, timeout); err = port_getn(loop->backend_fd, events, ARRAY_SIZE(events), &nfds, timeout == -1 ? NULL : &spec); - - if (pset != NULL) - pthread_sigmask(SIG_UNBLOCK, pset, NULL); + uv__io_poll_check(loop, pset); if (err) { /* Work around another kernel bug: port_getn() may return events even @@ -251,12 +241,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } } - /* 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 - * operating system didn't reschedule our process while in the syscall. - */ - SAVE_ERRNO(uv__update_time(loop)); - if (events[0].portev_source == 0) { if (reset_timeout != 0) { timeout = user_timeout; @@ -307,7 +291,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { have_signals = 1; } else { uv__metrics_update_idle_time(loop); - w->cb(loop, w, pe->portev_events); + uv__io_cb(loop, w, pe->portev_events); } nevents++; @@ -329,7 +313,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (have_signals != 0) { uv__metrics_update_idle_time(loop); - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + uv__signal_event(loop, &loop->signal_io_watcher, POLLIN); } loop->watchers[loop->nwatchers] = NULL; @@ -446,9 +430,7 @@ static int uv__fs_event_rearm(uv_fs_event_t *handle) { } -static void uv__fs_event_read(uv_loop_t* loop, - uv__io_t* w, - unsigned int revents) { +void uv__fs_event_read(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { uv_fs_event_t *handle = NULL; timespec_t timeout; port_event_t pe; @@ -548,7 +530,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (first_run) { err = uv__io_init_start(handle->loop, &handle->loop->fs_event_watcher, - uv__fs_event_read, + UV__FS_EVENT_READ, portfd, POLLIN); if (err) @@ -898,11 +880,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } #endif /* SUNOS_NO_IFADDRS */ -void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - uv__free(addresses); -} - #if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L size_t strnlen(const char* s, size_t maxlen) { diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index 98970d75278e31..aa81c16d6a95fc 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -444,10 +444,9 @@ int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { tcp->flags |= UV_HANDLE_BOUND; /* Start listening for connections. */ - tcp->io_watcher.cb = uv__server_io; - uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN); + uv__io_cb_set(&tcp->io_watcher, UV__SERVER_IO); - return 0; + return uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN); } @@ -466,22 +465,18 @@ int uv__tcp_nodelay(int fd, int on) { #else #define UV_KEEPALIVE_FACTOR(x) #endif -int uv__tcp_keepalive(int fd, int on, unsigned int delay) { - int idle; - int intvl; - int cnt; - - (void) &idle; - (void) &intvl; - (void) &cnt; - +int uv__tcp_keepalive(int fd, + int on, + unsigned int idle, + unsigned int intvl, + unsigned int cnt) { if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) return UV__ERR(errno); if (!on) return 0; - if (delay < 1) + if (idle < 1 || intvl < 1 || cnt < 1) return UV_EINVAL; #ifdef __sun @@ -507,13 +502,16 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { * The TCP connection will be aborted after certain amount of probes, which is set by TCP_KEEPCNT, without receiving response. */ - idle = delay; - /* Kernel expects at least 10 seconds. */ + /* Kernel expects at least 10 seconds for TCP_KEEPIDLE and TCP_KEEPINTVL. */ if (idle < 10) idle = 10; - /* Kernel expects at most 10 days. */ + if (intvl < 10) + intvl = 10; + /* Kernel expects at most 10 days for TCP_KEEPIDLE and TCP_KEEPINTVL. */ if (idle > 10*24*60*60) idle = 10*24*60*60; + if (intvl > 10*24*60*60) + intvl = 10*24*60*60; UV_KEEPALIVE_FACTOR(idle); @@ -523,12 +521,10 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) return UV__ERR(errno); - intvl = 10; /* required at least 10 seconds */ UV_KEEPALIVE_FACTOR(intvl); if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) return UV__ERR(errno); - cnt = 1; /* 1 retry, ensure (TCP_KEEPINTVL * TCP_KEEPCNT) is 10 seconds */ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) return UV__ERR(errno); #else @@ -540,7 +536,7 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { /* Note that the consequent probes will not be sent at equal intervals on Solaris, * but will be sent using the exponential backoff algorithm. */ - int time_to_abort = 10; /* 10 seconds */ + unsigned int time_to_abort = intvl * cnt; UV_KEEPALIVE_FACTOR(time_to_abort); if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort))) return UV__ERR(errno); @@ -548,7 +544,6 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { #else /* !defined(__sun) */ - idle = delay; UV_KEEPALIVE_FACTOR(idle); #ifdef TCP_KEEPIDLE if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) @@ -560,14 +555,12 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { #endif #ifdef TCP_KEEPINTVL - intvl = 1; /* 1 second; same as default on Win32 */ UV_KEEPALIVE_FACTOR(intvl); if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) return UV__ERR(errno); #endif #ifdef TCP_KEEPCNT - cnt = 10; /* 10 retries; same as hardcoded on Win32 */ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) return UV__ERR(errno); #endif @@ -595,11 +588,20 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int on) { } -int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { +int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int idle) { + return uv_tcp_keepalive_ex(handle, on, idle, 1, 10); +} + + +int uv_tcp_keepalive_ex(uv_tcp_t* handle, + int on, + unsigned int idle, + unsigned int intvl, + unsigned int cnt) { int err; if (uv__stream_fd(handle) != -1) { - err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay); + err = uv__tcp_keepalive(uv__stream_fd(handle), on, idle, intvl, cnt); if (err) return err; } @@ -609,7 +611,7 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { else handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; - /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge + /* TODO Store idle if uv__stream_fd(handle) == -1 but don't want to enlarge * uv_tcp_t with an int that's almost never used... */ diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index 34fea364aebe6d..001b6d744ba85f 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -870,9 +870,7 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { return UV_ETIMEDOUT; abort(); -#ifndef __SUNPRO_C return UV_EINVAL; /* Satisfy the compiler. */ -#endif } diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index c4a3559d61e350..8285ea80aea860 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -32,6 +32,10 @@ #endif #include +#if defined(__linux__) +#include +#endif + #if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP) # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP #endif @@ -41,8 +45,7 @@ #endif static void uv__udp_run_completed(uv_udp_t* handle); -static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents); -static void uv__udp_recvmsg(uv_udp_t* handle); +static void uv__udp_recvmsg(uv_udp_t* handle, int flag); static void uv__udp_sendmsg(uv_udp_t* handle); static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain, @@ -136,14 +139,53 @@ static void uv__udp_run_completed(uv_udp_t* handle) { } -static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { +#if defined(__linux__) +static int uv__udp_recvmsg_errqueue(uv_udp_t* handle, + struct msghdr* h, + uv_buf_t* buf, + const struct sockaddr* peer, + int flags) { + struct cmsghdr* cmsg; + struct sock_extended_err* serr; + struct sockaddr* offender; + + if (!(h->msg_flags & MSG_ERRQUEUE)) + return 0; + + flags |= UV_UDP_LINUX_RECVERR; + for (cmsg = CMSG_FIRSTHDR(h); cmsg != NULL; cmsg = CMSG_NXTHDR(h, cmsg)) { + if ((cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) || + (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_RECVERR)) { + serr = (struct sock_extended_err*) CMSG_DATA(cmsg); + + offender = SO_EE_OFFENDER(serr); + handle->recv_cb(handle, + UV__ERR(serr->ee_errno), + buf, + offender, + flags); + return 1; /* handled */ + } + } + return 0; +} +#endif + + +void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { uv_udp_t* handle; handle = container_of(w, uv_udp_t, io_watcher); assert(handle->type == UV_UDP); if (revents & POLLIN) - uv__udp_recvmsg(handle); + uv__udp_recvmsg(handle, 0); + + /* Just Linux support for now. */ +#if defined(__linux__) + if (revents & POLLERR) + uv__udp_recvmsg(handle, MSG_ERRQUEUE); +#endif if (revents & POLLOUT && !uv__is_closing(handle)) { uv__udp_sendmsg(handle); @@ -151,7 +193,7 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { } } -static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { +static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf, int flag) { #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) struct sockaddr_in6 peers[20]; struct iovec iov[ARRAY_SIZE(peers)]; @@ -161,6 +203,9 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { size_t chunks; int flags; size_t k; +#if defined(__linux__) + char control[ARRAY_SIZE(peers)][64]; +#endif /* prepare structures for recvmmsg */ chunks = buf->len / UV__UDP_DGRAM_MAXSIZE; @@ -178,6 +223,12 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { msgs[k].msg_hdr.msg_controllen = 0; msgs[k].msg_hdr.msg_flags = 0; msgs[k].msg_len = 0; +#if defined(__linux__) + if (flag & MSG_ERRQUEUE) { + msgs[k].msg_hdr.msg_control = control[k]; + msgs[k].msg_hdr.msg_controllen = sizeof(control[k]); + } +#endif } #if defined(__APPLE__) @@ -186,7 +237,7 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { while (nread == -1 && errno == EINTR); #else do - nread = recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL); + nread = recvmmsg(handle->io_watcher.fd, msgs, chunks, flag, NULL); while (nread == -1 && errno == EINTR); #endif @@ -203,6 +254,13 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { flags |= UV_UDP_PARTIAL; chunk_buf = uv_buf_init(iov[k].iov_base, iov[k].iov_len); +#if defined(__linux__) + if ((flag & MSG_ERRQUEUE) && + uv__udp_recvmsg_errqueue(handle, &msgs[k].msg_hdr, &chunk_buf, + (const struct sockaddr*) &peers[k], flags)) { + continue; + } +#endif handle->recv_cb(handle, msgs[k].msg_len, &chunk_buf, @@ -220,13 +278,16 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { #endif /* __linux__ || ____FreeBSD__ || __APPLE__ */ } -static void uv__udp_recvmsg(uv_udp_t* handle) { +static void uv__udp_recvmsg(uv_udp_t* handle, int flag) { struct sockaddr_storage peer; struct msghdr h; ssize_t nread; uv_buf_t buf; int flags; int count; +#if defined(__linux__) + char control[256]; +#endif assert(handle->recv_cb != NULL); assert(handle->alloc_cb != NULL); @@ -246,7 +307,7 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { assert(buf.base != NULL); if (uv_udp_using_recvmmsg(handle)) { - nread = uv__udp_recvmmsg(handle, &buf); + nread = uv__udp_recvmmsg(handle, &buf, flag); if (nread > 0) count -= nread; continue; @@ -258,25 +319,36 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { h.msg_namelen = sizeof(peer); h.msg_iov = (void*) &buf; h.msg_iovlen = 1; - - do { - nread = recvmsg(handle->io_watcher.fd, &h, 0); +#if defined(__linux__) + if (flag & MSG_ERRQUEUE) { + h.msg_control = control; + h.msg_controllen = sizeof(control); } +#endif + + do + nread = recvmsg(handle->io_watcher.fd, &h, flag); while (nread == -1 && errno == EINTR); - if (nread == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - handle->recv_cb(handle, 0, &buf, NULL, 0); - else - handle->recv_cb(handle, UV__ERR(errno), &buf, NULL, 0); - } - else { - flags = 0; + flags = 0; + if (nread != -1) if (h.msg_flags & MSG_TRUNC) flags |= UV_UDP_PARTIAL; - handle->recv_cb(handle, nread, &buf, (const struct sockaddr*) &peer, flags); +#if defined(__linux__) + if ((flag & MSG_ERRQUEUE) && + uv__udp_recvmsg_errqueue(handle, &h, &buf, (void*) &peer, flags)) { + count--; + continue; } +#endif + + if (nread != -1) + handle->recv_cb(handle, nread, &buf, (void*) &peer, flags); + else if (errno == EAGAIN || errno == EWOULDBLOCK) + handle->recv_cb(handle, 0, &buf, NULL, 0); + else + handle->recv_cb(handle, UV__ERR(errno), &buf, NULL, 0); count--; } /* recv_cb callback may decide to pause or close the handle */ @@ -560,7 +632,7 @@ int uv__udp_disconnect(uv_udp_t* handle) { } while (r == -1 && errno == EINTR); if (r == -1) { -#if defined(BSD) /* The macro BSD is from sys/param.h */ +#if defined(BSD) || defined(__QNX__) /* The macro BSD is from sys/param.h */ if (errno != EAFNOSUPPORT && errno != EINVAL) return UV__ERR(errno); #else @@ -661,10 +733,10 @@ int uv__udp_try_send(uv_udp_t* handle, } err = uv__udp_sendmsg1(handle->io_watcher.fd, bufs, nbufs, addr); - if (err > 0) - return uv__count_bufs(bufs, nbufs); + if (err) + return err; - return err; + return uv__count_bufs(bufs, nbufs); } @@ -766,8 +838,8 @@ static int uv__udp_set_membership6(uv_udp_t* handle, !defined(__NetBSD__) && \ !defined(__ANDROID__) && \ !defined(__DragonFly__) && \ - !defined(__QNX__) && \ - !defined(__GNU__) + !defined(__GNU__) && \ + !defined(QNX_IOPKT) static int uv__udp_set_source_membership4(uv_udp_t* handle, const struct sockaddr_in* multicast_addr, const char* interface_addr, @@ -881,7 +953,7 @@ int uv__udp_init_ex(uv_loop_t* loop, handle->recv_cb = NULL; handle->send_queue_size = 0; handle->send_queue_count = 0; - uv__io_init(&handle->io_watcher, uv__udp_io, fd); + uv__io_init(&handle->io_watcher, UV__UDP_IO, fd); uv__queue_init(&handle->write_queue); uv__queue_init(&handle->write_completed_queue); @@ -898,9 +970,13 @@ int uv_udp_using_recvmmsg(const uv_udp_t* handle) { } -int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { +int uv_udp_open_ex(uv_udp_t* handle, uv_os_sock_t sock, unsigned int flags) { int err; + /* Check for bad flags. */ + if (flags & ~(UV_UDP_REUSEADDR | UV_UDP_REUSEPORT)) + return UV_EINVAL; + /* Check for already active socket. */ if (handle->io_watcher.fd != -1) return UV_EBUSY; @@ -912,9 +988,17 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { if (err) return err; - err = uv__sock_reuseaddr(sock); - if (err) - return err; + if (flags & UV_UDP_REUSEADDR) { + err = uv__sock_reuseaddr(sock); + if (err) + return err; + } + + if (flags & UV_UDP_REUSEPORT) { + err = uv__sock_reuseport(sock); + if (err) + return err; + } handle->io_watcher.fd = sock; if (uv__udp_is_connected(handle)) @@ -924,6 +1008,15 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { } +int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { + /* + * Keep backward compatibility, always set REUSEADDR. + * Refs: https://github.com/libuv/libuv/issues/4551 + */ + return uv_udp_open_ex(handle, sock, UV_UDP_REUSEADDR); +} + + int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, const char* interface_addr, @@ -957,8 +1050,8 @@ int uv_udp_set_source_membership(uv_udp_t* handle, !defined(__NetBSD__) && \ !defined(__ANDROID__) && \ !defined(__DragonFly__) && \ - !defined(__QNX__) && \ - !defined(__GNU__) + !defined(__GNU__) && \ + !defined(QNX_IOPKT) int err; union uv__sockaddr mcast_addr; union uv__sockaddr src_addr; @@ -1295,7 +1388,7 @@ static int uv__udp_sendmsg1(int fd, /* UDP sockets don't EOF so we don't have to handle r=0 specially, * that only happens when the input was a zero-sized buffer. */ - return 1; + return 0; } @@ -1312,7 +1405,7 @@ static int uv__udp_sendmsgv(int fd, nsent = 0; #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ - (defined(__sun__) && defined(MSG_WAITFORONE)) + (defined(__sun__) && defined(MSG_WAITFORONE)) || defined(__QNX__) if (count > 1) { for (i = 0; i < count; /*empty*/) { struct mmsghdr m[20]; @@ -1340,7 +1433,7 @@ static int uv__udp_sendmsgv(int fd, goto exit; } #endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || - * (defined(__sun__) && defined(MSG_WAITFORONE)) + * (defined(__sun__) && defined(MSG_WAITFORONE)) || defined(__QNX__) */ for (i = 0; i < count; i++, nsent++) @@ -1363,7 +1456,7 @@ static int uv__udp_sendmsgv(int fd, static void uv__udp_sendmsg(uv_udp_t* handle) { - static const int N = 20; + enum { N = 20 }; struct sockaddr* addrs[N]; unsigned int nbufs[N]; uv_buf_t* bufs[N]; diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 60ff56b9dd7391..e5a7632909fc65 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -575,12 +575,17 @@ static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) { struct uv__queue* q; uv_handle_t* h; - if (loop == NULL) - loop = uv_default_loop(); - if (stream == NULL) stream = stderr; + if (loop == NULL) { + loop = uv_default_loop(); + if (loop == NULL) { + fprintf(stream, "uv_default_loop() failed\n"); + return; + } + } + uv__queue_foreach(q, &loop->handle_queue) { h = uv__queue_data(q, uv_handle_t, handle_queue); @@ -1049,3 +1054,11 @@ uint64_t uv_metrics_idle_time(uv_loop_t* loop) { idle_time += uv_hrtime() - entry_time; return idle_time; } + +/* OS390 needs a different implementation, already provided in os390.c. */ +#ifndef __MVS__ +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + uv__free(addresses); +} +#endif /* !__MVS__ */ diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index b9a8e976eefdd6..5452a549388cf9 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -90,7 +90,6 @@ enum { UV_HANDLE_LISTENING = 0x00000040, UV_HANDLE_CONNECTION = 0x00000080, UV_HANDLE_SHUT = 0x00000200, - UV_HANDLE_READ_PARTIAL = 0x00000400, UV_HANDLE_READ_EOF = 0x00000800, /* Used by streams and UDP handles. */ diff --git a/deps/uv/src/win/async.c b/deps/uv/src/win/async.c index b904676e3a72dd..4c2cd265e62e55 100644 --- a/deps/uv/src/win/async.c +++ b/deps/uv/src/win/async.c @@ -23,10 +23,28 @@ #include "uv.h" #include "internal.h" -#include "atomicops-inl.h" #include "handle-inl.h" #include "req-inl.h" +#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. */ +#pragma intrinsic(_InterlockedOr8) + +static char uv__atomic_exchange_set(char volatile* target) { + return _InterlockedOr8(target, 1); +} + +#else /* GCC, Clang in mingw mode */ + +static char uv__atomic_exchange_set(char volatile* target) { + return __sync_fetch_and_or(target, 1); +} + +#endif /* _MSC_VER */ void uv__async_endgame(uv_loop_t* loop, uv_async_t* handle) { if (handle->flags & UV_HANDLE_CLOSING && diff --git a/deps/uv/src/win/atomicops-inl.h b/deps/uv/src/win/atomicops-inl.h deleted file mode 100644 index 2f984c6db0b428..00000000000000 --- a/deps/uv/src/win/atomicops-inl.h +++ /dev/null @@ -1,61 +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. - */ - -#ifndef UV_WIN_ATOMICOPS_INL_H_ -#define UV_WIN_ATOMICOPS_INL_H_ - -#include "uv.h" -#include "internal.h" - - -/* 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. */ -#pragma intrinsic(_InterlockedOr8) - -static char INLINE uv__atomic_exchange_set(char volatile* target) { - return _InterlockedOr8(target, 1); -} - -#else /* GCC, Clang in mingw mode */ - -static inline char uv__atomic_exchange_set(char volatile* target) { -#if defined(__i386__) || defined(__x86_64__) - /* Mingw-32 version, hopefully this works for 64-bit gcc as well. */ - const char one = 1; - char old_value; - __asm__ __volatile__ ("lock xchgb %0, %1\n\t" - : "=r"(old_value), "=m"(*target) - : "0"(one), "m"(*target) - : "memory"); - return old_value; -#else - return __sync_fetch_and_or(target, 1); -#endif -} - -#endif - -#endif /* UV_WIN_ATOMICOPS_INL_H_ */ diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index 5f41c87ad5ed13..317238fd229629 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -428,6 +428,7 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { BOOL success; uv_req_t* req; OVERLAPPED_ENTRY overlappeds[128]; + OVERLAPPED* overlapped; ULONG count; ULONG i; int repeat; @@ -491,7 +492,8 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { if (actual_timeout == 0) uv__metrics_inc_events_waiting(loop, 1); - req = uv__overlapped_to_req(overlappeds[i].lpOverlapped); + overlapped = overlappeds[i].lpOverlapped; + req = container_of(overlapped, uv_req_t, u.io.overlapped); uv__insert_pending_req(loop, req); } } @@ -525,6 +527,177 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { } +#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \ + do { \ + switch (((uv_handle_t*) (req)->handle_at)->type) { \ + case UV_TCP: \ + uv__process_tcp_##method##_req(loop, \ + (uv_tcp_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + case UV_NAMED_PIPE: \ + uv__process_pipe_##method##_req(loop, \ + (uv_pipe_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + case UV_TTY: \ + uv__process_tty_##method##_req(loop, \ + (uv_tty_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + default: \ + assert(0); \ + } \ + } while (0) + + +static void uv__process_reqs(uv_loop_t* loop) { + uv_req_t* req; + uv_req_t* first; + uv_req_t* next; + + if (loop->pending_reqs_tail == NULL) + return; + + first = loop->pending_reqs_tail->next_req; + next = first; + loop->pending_reqs_tail = NULL; + + while (next != NULL) { + req = next; + next = req->next_req != first ? req->next_req : NULL; + + switch (req->type) { + case UV_READ: + DELEGATE_STREAM_REQ(loop, req, read, data); + break; + + case UV_WRITE: + DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle); + break; + + case UV_ACCEPT: + DELEGATE_STREAM_REQ(loop, req, accept, data); + break; + + case UV_CONNECT: + DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle); + break; + + case UV_SHUTDOWN: + DELEGATE_STREAM_REQ(loop, (uv_shutdown_t*) req, shutdown, handle); + break; + + case UV_UDP_RECV: + uv__process_udp_recv_req(loop, (uv_udp_t*) req->data, req); + break; + + case UV_UDP_SEND: + uv__process_udp_send_req(loop, + ((uv_udp_send_t*) req)->handle, + (uv_udp_send_t*) req); + break; + + case UV_WAKEUP: + uv__process_async_wakeup_req(loop, (uv_async_t*) req->data, req); + break; + + case UV_SIGNAL_REQ: + uv__process_signal_req(loop, (uv_signal_t*) req->data, req); + break; + + case UV_POLL_REQ: + uv__process_poll_req(loop, (uv_poll_t*) req->data, req); + break; + + case UV_PROCESS_EXIT: + uv__process_proc_exit(loop, (uv_process_t*) req->data); + break; + + case UV_FS_EVENT_REQ: + uv__process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); + break; + + default: + assert(0); + } + } +} + +#undef DELEGATE_STREAM_REQ + +static void uv__process_endgames(uv_loop_t* loop) { + uv_handle_t* handle; + + while (loop->endgame_handles) { + handle = loop->endgame_handles; + loop->endgame_handles = handle->endgame_next; + + handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED; + + switch (handle->type) { + case UV_TCP: + uv__tcp_endgame(loop, (uv_tcp_t*) handle); + break; + + case UV_NAMED_PIPE: + uv__pipe_endgame(loop, (uv_pipe_t*) handle); + break; + + case UV_TTY: + uv__tty_endgame(loop, (uv_tty_t*) handle); + break; + + case UV_UDP: + uv__udp_endgame(loop, (uv_udp_t*) handle); + break; + + case UV_POLL: + uv__poll_endgame(loop, (uv_poll_t*) handle); + break; + + case UV_TIMER: + uv__timer_close((uv_timer_t*) handle); + uv__handle_close(handle); + break; + + case UV_PREPARE: + case UV_CHECK: + case UV_IDLE: + uv__loop_watcher_endgame(loop, handle); + break; + + case UV_ASYNC: + uv__async_endgame(loop, (uv_async_t*) handle); + break; + + case UV_SIGNAL: + uv__signal_endgame(loop, (uv_signal_t*) handle); + break; + + case UV_PROCESS: + uv__process_endgame(loop, (uv_process_t*) handle); + break; + + case UV_FS_EVENT: + uv__fs_event_endgame(loop, (uv_fs_event_t*) handle); + break; + + case UV_FS_POLL: + uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle); + break; + + default: + assert(0); + break; + } + } +} + + int uv_run(uv_loop_t *loop, uv_run_mode mode) { DWORD timeout; int r; @@ -681,3 +854,26 @@ int uv__getsockpeername(const uv_handle_t* handle, return 0; } + +void uv__insert_pending_req(uv_loop_t* loop, uv_req_t* req) { + req->next_req = NULL; + if (loop->pending_reqs_tail) { +#ifdef _DEBUG + /* Ensure the request is not already in the queue, or the queue + * will get corrupted. + */ + uv_req_t* current = loop->pending_reqs_tail; + do { + assert(req != current); + current = current->next_req; + } while (current != loop->pending_reqs_tail); +#endif + + req->next_req = loop->pending_reqs_tail->next_req; + loop->pending_reqs_tail->next_req = req; + loop->pending_reqs_tail = req; + } else { + req->next_req = req; + loop->pending_reqs_tail = req; + } +} diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 1bbb8c52be2d82..fd77f2a497844a 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -158,14 +158,14 @@ int uv_fs_event_start(uv_fs_event_t* handle, const char* path, unsigned int flags) { int is_path_dir; - size_t size; - DWORD attr, last_error; - WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL; + DWORD last_error; + WCHAR* dir, *pathw = NULL; DWORD short_path_buffer_len; WCHAR *short_path_buffer; - WCHAR* short_path, *long_path; + WCHAR* short_path = NULL; + HANDLE file_handle = INVALID_HANDLE_VALUE; + BY_HANDLE_FILE_INFORMATION info; - short_path = NULL; if (uv__is_active(handle)) return UV_EINVAL; @@ -181,43 +181,26 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (last_error) goto error_uv; - /* Determine whether path is a file or a directory. */ - attr = GetFileAttributesW(pathw); - if (attr == INVALID_FILE_ATTRIBUTES) { + file_handle = CreateFileW(pathw, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, + NULL); + if (file_handle == INVALID_HANDLE_VALUE) { last_error = GetLastError(); goto error; } - is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; - - 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 (!GetFileInformationByHandle(file_handle, &info)) { + last_error = GetLastError(); + goto error; + } - if (long_path) { - uv__free(pathw); - pathw = long_path; - } - } + is_path_dir = (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; - dir_to_watch = pathw; - } else { + if (!is_path_dir) { /* * path is a file. So we split path into dir & file parts, and * watch the dir directory. @@ -252,28 +235,50 @@ int uv_fs_event_start(uv_fs_event_t* handle, goto error; } - dir_to_watch = dir; uv__free(short_path); short_path = NULL; uv__free(pathw); pathw = NULL; - } - handle->dir_handle = CreateFileW(dir_to_watch, - FILE_LIST_DIRECTORY, - FILE_SHARE_READ | FILE_SHARE_DELETE | - FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | - FILE_FLAG_OVERLAPPED, - NULL); - - if (dir) { + /* Open the containing directory and watch that instead. Events for + * other files are filtered out in uv__process_fs_event_req(). + * Not super efficient but c'est ça. + */ + CloseHandle(file_handle); + file_handle = CreateFileW(dir, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, + NULL); uv__free(dir); dir = NULL; + if (file_handle == INVALID_HANDLE_VALUE) { + last_error = GetLastError(); + goto error; + } + + if (!GetFileInformationByHandle(file_handle, &info)) { + last_error = GetLastError(); + goto error; + } + + /* Race with another process: directory foo in foo/bar was replaced + * with a file. Bail out with an error, we're not recursing upwards. + */ + if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + /* TODO(bnoordhuis) ERROR_DIRECTORY is translated to UV_ENOENT, + * there's currently nothing that maps to UV_ENOTDIR. + */ + last_error = ERROR_DIRECTORY; + goto error; + } } + handle->dir_handle = file_handle; + file_handle = INVALID_HANDLE_VALUE; + if (handle->dir_handle == INVALID_HANDLE_VALUE) { last_error = GetLastError(); goto error; @@ -325,6 +330,11 @@ int uv_fs_event_start(uv_fs_event_t* handle, last_error = uv_translate_sys_error(last_error); error_uv: + if (file_handle != INVALID_HANDLE_VALUE) { + CloseHandle(file_handle); + file_handle = INVALID_HANDLE_VALUE; + } + if (handle->path) { uv__free(handle->path); handle->path = NULL; diff --git a/deps/uv/src/win/fs-fd-hash-inl.h b/deps/uv/src/win/fs-fd-hash-inl.h index 0b532af12d4371..94b4c3cc49b681 100644 --- a/deps/uv/src/win/fs-fd-hash-inl.h +++ b/deps/uv/src/win/fs-fd-hash-inl.h @@ -69,11 +69,11 @@ struct uv__fd_hash_bucket_s { static uv_mutex_t uv__fd_hash_mutex; static struct uv__fd_hash_entry_group_s - uv__fd_hash_entry_initial[UV__FD_HASH_SIZE * UV__FD_HASH_GROUP_SIZE]; + uv__fd_hash_entry_initial[UV__FD_HASH_SIZE]; static struct uv__fd_hash_bucket_s uv__fd_hash[UV__FD_HASH_SIZE]; -INLINE static void uv__fd_hash_init(void) { +static void uv__fd_hash_init(void) { size_t i; int err; @@ -82,10 +82,9 @@ INLINE static void uv__fd_hash_init(void) { uv_fatal_error(err, "uv_mutex_init"); } - for (i = 0; i < ARRAY_SIZE(uv__fd_hash); ++i) { + for (i = 0; i < ARRAY_SIZE(uv__fd_hash); i++) { uv__fd_hash[i].size = 0; - uv__fd_hash[i].data = - uv__fd_hash_entry_initial + i * UV__FD_HASH_GROUP_SIZE; + uv__fd_hash[i].data = &uv__fd_hash_entry_initial[i]; } } @@ -119,7 +118,7 @@ INLINE static void uv__fd_hash_init(void) { FIND_IN_GROUP_PTR(UV__FD_HASH_GROUP_SIZE); \ } while (0) -INLINE static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) { +static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) { FIND_COMMON_VARIABLES uv_mutex_lock(&uv__fd_hash_mutex); @@ -134,7 +133,7 @@ INLINE static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) { return entry_ptr != NULL; } -INLINE static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) { +static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) { FIND_COMMON_VARIABLES uv_mutex_lock(&uv__fd_hash_mutex); @@ -164,7 +163,7 @@ INLINE static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) { uv_mutex_unlock(&uv__fd_hash_mutex); } -INLINE static int uv__fd_hash_remove(int fd, struct uv__fd_info_s* info) { +static int uv__fd_hash_remove(int fd, struct uv__fd_info_s* info) { FIND_COMMON_VARIABLES uv_mutex_lock(&uv__fd_hash_mutex); diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 27248f644f381b..4092de0ab31e56 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -167,9 +167,10 @@ typedef enum { FS__STAT_PATH_TRY_SLOW } fs__stat_path_return_t; -INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf); -INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf, - FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat); +static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf); +static void fs__stat_assign_statbuf(uv_stat_t* statbuf, + FILE_STAT_BASIC_INFORMATION stat_info, + int do_lstat); void uv__fs_init(void) { @@ -182,9 +183,9 @@ void uv__fs_init(void) { } -INLINE static int fs__readlink_handle(HANDLE handle, - char** target_ptr, - size_t* target_len_ptr) { +static int fs__readlink_handle(HANDLE handle, + char** target_ptr, + size_t* target_len_ptr) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer; WCHAR* w_target; @@ -246,6 +247,32 @@ INLINE static int fs__readlink_handle(HANDLE handle, } } + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_LX_SYMLINK) { + /* Real (Linux) symlink */ + char* buffer; + char* target; + size_t target_len; + + target_len = (reparse_data->ReparseDataLength - + sizeof(ULONG)); /* Version field */ + buffer = (char*) reparse_data->LinuxSymbolicLinkReparseBuffer.PathBuffer; + + if (target_len_ptr != NULL) { + *target_len_ptr = target_len; + } + + if (target_ptr != NULL) { + assert(*target_ptr == NULL); + target = uv__malloc(target_len + 1); + if (target == NULL) { + return UV_ENOMEM; + } + memcpy(target, buffer, target_len); + target[target_len] = '\0'; + *target_ptr = target; + } + return 0; + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { /* Junction. */ w_target = reparse_data->MountPointReparseBuffer.PathBuffer + @@ -319,8 +346,10 @@ INLINE static int fs__readlink_handle(HANDLE handle, } -INLINE static int fs__capture_path(uv_fs_t* req, const char* path, - const char* new_path, const int copy_path) { +static int fs__capture_path(uv_fs_t* req, + const char* path, + const char* new_path, + const int copy_path) { WCHAR* buf; WCHAR* pos; size_t buf_sz = 0; @@ -394,8 +423,10 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path, } -INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req, - uv_fs_type fs_type, const uv_fs_cb cb) { +static void uv__fs_req_init(uv_loop_t* loop, + uv_fs_t* req, + uv_fs_type fs_type, + const uv_fs_cb cb) { uv__once_init(); UV_REQ_INIT(req, UV_FS); req->loop = loop; @@ -1099,7 +1130,7 @@ void fs__write(uv_fs_t* req) { static void fs__unlink_rmdir(uv_fs_t* req, BOOL isrmdir) { const WCHAR* pathw = req->file.pathw; HANDLE handle; - BY_HANDLE_FILE_INFORMATION info; + FILE_BASIC_INFO info; FILE_DISPOSITION_INFORMATION disposition; FILE_DISPOSITION_INFORMATION_EX disposition_ex; IO_STATUS_BLOCK iosb; @@ -1107,7 +1138,7 @@ static void fs__unlink_rmdir(uv_fs_t* req, BOOL isrmdir) { DWORD error; handle = CreateFileW(pathw, - FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE, + FILE_READ_ATTRIBUTES | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, @@ -1119,13 +1150,13 @@ static void fs__unlink_rmdir(uv_fs_t* req, BOOL isrmdir) { return; } - if (!GetFileInformationByHandle(handle, &info)) { + if (!GetFileInformationByHandleEx(handle, FileBasicInfo, &info, sizeof info)) { SET_REQ_WIN32_ERROR(req, GetLastError()); CloseHandle(handle); return; } - if (isrmdir && !(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + if (isrmdir && !(info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { /* Error if we're in rmdir mode but it is not a dir. * TODO: change it to UV_NOTDIR in v2. */ SET_REQ_UV_ERROR(req, UV_ENOENT, ERROR_DIRECTORY); @@ -1133,13 +1164,13 @@ static void fs__unlink_rmdir(uv_fs_t* req, BOOL isrmdir) { return; } - if (!isrmdir && (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + if (!isrmdir && (info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { /* If not explicitly allowed, 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)) { + if (!(info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED); CloseHandle(handle); return; @@ -1178,18 +1209,37 @@ static void fs__unlink_rmdir(uv_fs_t* req, BOOL isrmdir) { error == ERROR_INVALID_PARAMETER /* pre Windows 10 error */ || error == ERROR_INVALID_FUNCTION /* pre Windows 10 1607 error */) { /* posix delete not supported so try fallback */ - if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + if (info.FileAttributes & FILE_ATTRIBUTE_READONLY) { /* Remove read-only attribute */ FILE_BASIC_INFORMATION basic = { 0 }; - basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) | + /* We opened the handle above without FILE_WRITE_ATTRIBUTES access, which + * is not required in the happy path. On windows, it would probably + * be ok to ask for them anyway, but Wine has a bug that causes such calls + * to fail (https://bugs.winehq.org/show_bug.cgi?id=50771). To work around + * this bug, we re-open the handle here */ + HANDLE write_attributes_handle; + + basic.FileAttributes = (info.FileAttributes & ~FILE_ATTRIBUTE_READONLY) | FILE_ATTRIBUTE_ARCHIVE; - status = pNtSetInformationFile(handle, + write_attributes_handle = ReOpenFile(handle, FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | + FILE_SHARE_DELETE, + FILE_FLAG_OPEN_REPARSE_POINT | + FILE_FLAG_BACKUP_SEMANTICS); + if (write_attributes_handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + status = pNtSetInformationFile(write_attributes_handle, &iosb, &basic, sizeof basic, FileBasicInformation); + CloseHandle(write_attributes_handle); if (!NT_SUCCESS(status)) { SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); CloseHandle(handle); @@ -1264,7 +1314,7 @@ void fs__mktemp(uv_fs_t* req, uv__fs_mktemp_func func) { tries = TMP_MAX; do { - if (uv__random_rtlgenrandom((void *)&v, sizeof(v)) < 0) { + if (uv__random_winrandom(&v, sizeof(v)) < 0) { SET_REQ_UV_ERROR(req, UV_EIO, ERROR_IO_DEVICE); goto clobber; } @@ -1638,6 +1688,21 @@ void fs__readdir(uv_fs_t* req) { dir = req->ptr; dirents = dir->dirents; memset(dirents, 0, dir->nentries * sizeof(*dir->dirents)); + + /* Initial FindFirstFile can fail with ERROR_FILE_NOT_FOUND, meaning + * no matches, which leaves dir_handle set to INVALID_HANDLE_VALUE, + * see fs__opendir(). Not an actual error, just means no results. + * + * sshfs-win apparently works that way but reading an empty directory + * on a regular drive doesn't trigger that particular code path. + * + * See https://github.com/libuv/libuv/issues/4952 + */ + if (dir->dir_handle == INVALID_HANDLE_VALUE) { + SET_REQ_RESULT(req, 0); + return; + } + find_data = &dir->find_data; dirent_idx = 0; @@ -1698,8 +1763,9 @@ void fs__closedir(uv_fs_t* req) { SET_REQ_RESULT(req, 0); } -INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path, - uv_stat_t* statbuf, int do_lstat) { +static fs__stat_path_return_t fs__stat_path(WCHAR* path, + uv_stat_t* statbuf, + int do_lstat) { FILE_STAT_BASIC_INFORMATION stat_info; /* Check if the new fast API is available. */ @@ -1735,8 +1801,7 @@ INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path, return FS__STAT_PATH_SUCCESS; } -INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, - int do_lstat) { +static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, int do_lstat) { size_t target_length = 0; FILE_FS_DEVICE_INFORMATION device_info; FILE_ALL_INFORMATION file_info; @@ -1827,7 +1892,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, return 0; } -INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf) { +static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf) { memset(statbuf, 0, sizeof(uv_stat_t)); statbuf->st_mode = _S_IFCHR; statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | @@ -1837,8 +1902,9 @@ INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf) { statbuf->st_rdev = FILE_DEVICE_NULL << 16; } -INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf, - FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat) { +static void fs__stat_assign_statbuf(uv_stat_t* statbuf, + FILE_STAT_BASIC_INFORMATION stat_info, + int do_lstat) { statbuf->st_dev = stat_info.VolumeSerialNumber.LowPart; /* Todo: st_mode should probably always be 0666 for everyone. We might also @@ -1943,18 +2009,19 @@ INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf, } -INLINE static void fs__stat_prepare_path(WCHAR* pathw) { +static void fs__stat_prepare_path(WCHAR* pathw) { size_t len = wcslen(pathw); - /* TODO: ignore namespaced paths. */ if (len > 1 && pathw[len - 2] != L':' && (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) { pathw[len - 1] = '\0'; } } -INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, - int do_lstat, DWORD ret_error) { +static DWORD fs__stat_directory(WCHAR* path, + uv_stat_t* statbuf, + int do_lstat, + DWORD ret_error) { HANDLE handle = INVALID_HANDLE_VALUE; FILE_STAT_BASIC_INFORMATION stat_info; FILE_ID_FULL_DIR_INFORMATION dir_info; @@ -2127,9 +2194,9 @@ INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, return ret_error; } -INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, - int do_lstat, - uv_stat_t* statbuf) { +static DWORD fs__stat_impl_from_path(WCHAR* path, + int do_lstat, + uv_stat_t* statbuf) { HANDLE handle; DWORD flags; DWORD ret; @@ -2174,7 +2241,7 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, } -INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) { +static void fs__stat_impl(uv_fs_t* req, int do_lstat) { DWORD error; error = fs__stat_impl_from_path(req->file.pathw, do_lstat, &req->statbuf); @@ -2197,7 +2264,7 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) { } -INLINE static int fs__fstat_handle(int fd, HANDLE handle, uv_stat_t* statbuf) { +static int fs__fstat_handle(int fd, HANDLE handle, uv_stat_t* statbuf) { DWORD file_type; /* Each file type is processed differently. */ @@ -2273,7 +2340,7 @@ static void fs__rename(uv_fs_t* req) { } -INLINE static void fs__sync_impl(uv_fs_t* req) { +static void fs__sync_impl(uv_fs_t* req) { int fd = req->file.fd; int result; @@ -2579,7 +2646,7 @@ static void fs__fchmod(uv_fs_t* req) { } -INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { +static int fs__utime_handle(HANDLE handle, double atime, double mtime) { FILETIME filetime_as, *filetime_a = &filetime_as; FILETIME filetime_ms, *filetime_m = &filetime_ms; FILETIME now; @@ -2607,10 +2674,10 @@ INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { return 0; } -INLINE static DWORD fs__utime_impl_from_path(WCHAR* path, - double atime, - double mtime, - int do_lutime) { +static DWORD fs__utime_impl_from_path(WCHAR* path, + double atime, + double mtime, + int do_lutime) { HANDLE handle; DWORD flags; DWORD ret; @@ -2640,7 +2707,7 @@ INLINE static DWORD fs__utime_impl_from_path(WCHAR* path, return ret; } -INLINE static void fs__utime_impl(uv_fs_t* req, int do_lutime) { +static void fs__utime_impl(uv_fs_t* req, int do_lutime) { DWORD error; error = fs__utime_impl_from_path(req->file.pathw, @@ -3042,67 +3109,35 @@ static void fs__lchown(uv_fs_t* req) { static void fs__statfs(uv_fs_t* req) { + FILE_FS_FULL_SIZE_INFORMATION info; + IO_STATUS_BLOCK io_status; uv_statfs_t* stat_fs; - DWORD sectors_per_cluster; - DWORD bytes_per_sector; - DWORD free_clusters; - DWORD total_clusters; - WCHAR* pathw; + NTSTATUS nt_status; + HANDLE handle; - pathw = req->file.pathw; -retry_get_disk_free_space: - if (0 == GetDiskFreeSpaceW(pathw, - §ors_per_cluster, - &bytes_per_sector, - &free_clusters, - &total_clusters)) { - DWORD err; - WCHAR* fpart; - size_t len; - DWORD ret; - BOOL is_second; - - err = GetLastError(); - is_second = pathw != req->file.pathw; - if (err != ERROR_DIRECTORY || is_second) { - if (is_second) - uv__free(pathw); + handle = CreateFileW(req->file.pathw, + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); - SET_REQ_WIN32_ERROR(req, err); - return; - } + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } - len = MAX_PATH + 1; - pathw = uv__malloc(len * sizeof(*pathw)); - if (pathw == NULL) { - SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); - return; - } -retry_get_full_path_name: - ret = GetFullPathNameW(req->file.pathw, - len, - pathw, - &fpart); - if (ret == 0) { - uv__free(pathw); - SET_REQ_WIN32_ERROR(req, err); - return; - } else if (ret > len) { - len = ret; - pathw = uv__reallocf(pathw, len * sizeof(*pathw)); - if (pathw == NULL) { - SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY); - return; - } - goto retry_get_full_path_name; - } - if (fpart != 0) - *fpart = L'\0'; + nt_status = pNtQueryVolumeInformationFile(handle, + &io_status, + &info, + sizeof info, + FileFsFullSizeInformation); + CloseHandle(handle); - goto retry_get_disk_free_space; - } - if (pathw != req->file.pathw) { - uv__free(pathw); + if (NT_ERROR(nt_status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); + return; } stat_fs = uv__malloc(sizeof(*stat_fs)); @@ -3112,10 +3147,12 @@ static void fs__statfs(uv_fs_t* req) { } stat_fs->f_type = 0; - stat_fs->f_bsize = bytes_per_sector * sectors_per_cluster; - stat_fs->f_blocks = total_clusters; - stat_fs->f_bfree = free_clusters; - stat_fs->f_bavail = free_clusters; + stat_fs->f_bsize = (uint64_t)info.SectorsPerAllocationUnit * + info.BytesPerSector; + stat_fs->f_frsize = stat_fs->f_bsize; + stat_fs->f_blocks = info.TotalAllocationUnits.QuadPart; + stat_fs->f_bfree = info.ActualAvailableAllocationUnits.QuadPart; + stat_fs->f_bavail = info.CallerAvailableAllocationUnits.QuadPart; stat_fs->f_files = 0; stat_fs->f_ffree = 0; req->ptr = stat_fs; diff --git a/deps/uv/src/win/handle-inl.h b/deps/uv/src/win/handle-inl.h index 4722e85790ad3c..e30d148cb026a4 100644 --- a/deps/uv/src/win/handle-inl.h +++ b/deps/uv/src/win/handle-inl.h @@ -95,74 +95,6 @@ INLINE static void uv__want_endgame(uv_loop_t* loop, uv_handle_t* handle) { } -INLINE static void uv__process_endgames(uv_loop_t* loop) { - uv_handle_t* handle; - - while (loop->endgame_handles) { - handle = loop->endgame_handles; - loop->endgame_handles = handle->endgame_next; - - handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED; - - switch (handle->type) { - case UV_TCP: - uv__tcp_endgame(loop, (uv_tcp_t*) handle); - break; - - case UV_NAMED_PIPE: - uv__pipe_endgame(loop, (uv_pipe_t*) handle); - break; - - case UV_TTY: - uv__tty_endgame(loop, (uv_tty_t*) handle); - break; - - case UV_UDP: - uv__udp_endgame(loop, (uv_udp_t*) handle); - break; - - case UV_POLL: - uv__poll_endgame(loop, (uv_poll_t*) handle); - break; - - case UV_TIMER: - uv__timer_close((uv_timer_t*) handle); - uv__handle_close(handle); - break; - - case UV_PREPARE: - case UV_CHECK: - case UV_IDLE: - uv__loop_watcher_endgame(loop, handle); - break; - - case UV_ASYNC: - uv__async_endgame(loop, (uv_async_t*) handle); - break; - - case UV_SIGNAL: - uv__signal_endgame(loop, (uv_signal_t*) handle); - break; - - case UV_PROCESS: - uv__process_endgame(loop, (uv_process_t*) handle); - break; - - case UV_FS_EVENT: - uv__fs_event_endgame(loop, (uv_fs_event_t*) handle); - break; - - case UV_FS_POLL: - uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle); - break; - - default: - assert(0); - break; - } - } -} - INLINE static HANDLE uv__get_osfhandle(int fd) { /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index be408af6661026..db488be77d9166 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -269,7 +269,7 @@ int uv__getsockpeername(const uv_handle_t* handle, int* namelen, int delayed_error); -int uv__random_rtlgenrandom(void* buf, size_t buflen); +int uv__random_winrandom(void* buf, size_t buflen); /* diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index d05bfd28aec8b9..8f86a1fee2e4f3 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -2149,7 +2149,8 @@ void uv__process_pipe_read_req(uv_loop_t* loop, } else { /* The zero-read completed without error, indicating there is data * available in the kernel buffer. */ - while (handle->flags & UV_HANDLE_READING) { + while (handle->flags & UV_HANDLE_READING && + !(handle->flags & UV_HANDLE_READ_PENDING)) { bytes_requested = 65536; /* Depending on the type of pipe, read either IPC frames or raw data. */ if (handle->ipc) diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c index 7fec2b99650646..a20867a99809f3 100644 --- a/deps/uv/src/win/poll.c +++ b/deps/uv/src/win/poll.c @@ -211,15 +211,11 @@ static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp, protocol_info->iProtocol, protocol_info, 0, - WSA_FLAG_OVERLAPPED); + WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT); if (sock == INVALID_SOCKET) { return INVALID_SOCKET; } - if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) { - goto error; - }; - if (CreateIoCompletionPort((HANDLE) sock, iocp, (ULONG_PTR) sock, diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 27605ca36f4434..45e85ed9613900 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -1220,7 +1220,7 @@ static int uv__kill(HANDLE process_handle, int signum) { NULL, &localappdata); _snwprintf_s(dump_folder, - sizeof(dump_folder), + ARRAY_SIZE(dump_folder), _TRUNCATE, L"%ls\\CrashDumps", localappdata); @@ -1233,7 +1233,7 @@ static int uv__kill(HANDLE process_handle, int signum) { /* Construct dump filename from process name and PID. */ _snwprintf_s(dump_name, - sizeof(dump_name), + ARRAY_SIZE(dump_name), _TRUNCATE, L"%ls\\%ls.%d.dmp", dump_folder, diff --git a/deps/uv/src/win/req-inl.h b/deps/uv/src/win/req-inl.h index cf16e8ba41fa73..af6fb7522672e5 100644 --- a/deps/uv/src/win/req-inl.h +++ b/deps/uv/src/win/req-inl.h @@ -81,134 +81,6 @@ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \ } - -INLINE static uv_req_t* uv__overlapped_to_req(OVERLAPPED* overlapped) { - return container_of(overlapped, uv_req_t, u.io.overlapped); -} - - -INLINE static void uv__insert_pending_req(uv_loop_t* loop, uv_req_t* req) { - req->next_req = NULL; - if (loop->pending_reqs_tail) { -#ifdef _DEBUG - /* Ensure the request is not already in the queue, or the queue - * will get corrupted. - */ - uv_req_t* current = loop->pending_reqs_tail; - do { - assert(req != current); - current = current->next_req; - } while(current != loop->pending_reqs_tail); -#endif - - req->next_req = loop->pending_reqs_tail->next_req; - loop->pending_reqs_tail->next_req = req; - loop->pending_reqs_tail = req; - } else { - req->next_req = req; - loop->pending_reqs_tail = req; - } -} - - -#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \ - do { \ - switch (((uv_handle_t*) (req)->handle_at)->type) { \ - case UV_TCP: \ - uv__process_tcp_##method##_req(loop, \ - (uv_tcp_t*) ((req)->handle_at), \ - req); \ - break; \ - \ - case UV_NAMED_PIPE: \ - uv__process_pipe_##method##_req(loop, \ - (uv_pipe_t*) ((req)->handle_at), \ - req); \ - break; \ - \ - case UV_TTY: \ - uv__process_tty_##method##_req(loop, \ - (uv_tty_t*) ((req)->handle_at), \ - req); \ - break; \ - \ - default: \ - assert(0); \ - } \ - } while (0) - - -INLINE static void uv__process_reqs(uv_loop_t* loop) { - uv_req_t* req; - uv_req_t* first; - uv_req_t* next; - - if (loop->pending_reqs_tail == NULL) - return; - - first = loop->pending_reqs_tail->next_req; - next = first; - loop->pending_reqs_tail = NULL; - - while (next != NULL) { - req = next; - next = req->next_req != first ? req->next_req : NULL; - - switch (req->type) { - case UV_READ: - DELEGATE_STREAM_REQ(loop, req, read, data); - break; - - case UV_WRITE: - DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle); - break; - - case UV_ACCEPT: - DELEGATE_STREAM_REQ(loop, req, accept, data); - break; - - case UV_CONNECT: - DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle); - break; - - case UV_SHUTDOWN: - DELEGATE_STREAM_REQ(loop, (uv_shutdown_t*) req, shutdown, handle); - break; - - case UV_UDP_RECV: - uv__process_udp_recv_req(loop, (uv_udp_t*) req->data, req); - break; - - case UV_UDP_SEND: - uv__process_udp_send_req(loop, - ((uv_udp_send_t*) req)->handle, - (uv_udp_send_t*) req); - break; - - case UV_WAKEUP: - uv__process_async_wakeup_req(loop, (uv_async_t*) req->data, req); - break; - - case UV_SIGNAL_REQ: - uv__process_signal_req(loop, (uv_signal_t*) req->data, req); - break; - - case UV_POLL_REQ: - uv__process_poll_req(loop, (uv_poll_t*) req->data, req); - break; - - case UV_PROCESS_EXIT: - uv__process_proc_exit(loop, (uv_process_t*) req->data); - break; - - case UV_FS_EVENT_REQ: - uv__process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); - break; - - default: - assert(0); - } - } -} +void uv__insert_pending_req(uv_loop_t* loop, uv_req_t* req); #endif /* UV_WIN_REQ_INL_H_ */ diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c index a53a10b03823e1..ac19d3bdf3882f 100644 --- a/deps/uv/src/win/stream.c +++ b/deps/uv/src/win/stream.c @@ -111,6 +111,23 @@ int uv_read_stop(uv_stream_t* handle) { } +static int uv__check_before_write(uv_stream_t* handle, unsigned int nbufs) { + /* We're not beholden to IOV_MAX but limit the buffer count to catch sign + * conversion bugs where a caller passes in a signed negative number that + * then gets converted to a really large unsigned number. + */ + if (nbufs < 1 || nbufs > 1024*1024) { + return UV_EINVAL; + } + + if (!(handle->flags & UV_HANDLE_WRITABLE)) { + return UV_EPIPE; + } + + return 0; +} + + int uv_write(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], @@ -119,8 +136,9 @@ int uv_write(uv_write_t* req, uv_loop_t* loop = handle->loop; int err; - if (!(handle->flags & UV_HANDLE_WRITABLE)) { - return UV_EPIPE; + err = uv__check_before_write(handle, nbufs); + if (err != 0) { + return err; } err = ERROR_INVALID_PARAMETER; @@ -156,10 +174,13 @@ int uv_write2(uv_write_t* req, return uv_write(req, handle, bufs, nbufs, cb); } + err = uv__check_before_write(handle, nbufs); + if (err != 0) { + return err; + } + 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( @@ -171,10 +192,15 @@ int uv_write2(uv_write_t* req, int uv_try_write(uv_stream_t* stream, const uv_buf_t bufs[], unsigned int nbufs) { + int err; + + err = uv__check_before_write(stream, nbufs); + if (err != 0) { + return err; + } + if (stream->flags & UV_HANDLE_CLOSING) return UV_EBADF; - if (!(stream->flags & UV_HANDLE_WRITABLE)) - return UV_EPIPE; switch (stream->type) { case UV_TCP: diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index c452c12e8f06f1..66e005ff021f63 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -49,29 +49,99 @@ static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) { } -static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) { +/* + * Check if Windows version is 10.0.16299 (Windows 10, version 1709) or later. + */ +static int uv__windows10_version1709(void) { + OSVERSIONINFOW os_info; + if (!pRtlGetVersion) + return 0; + pRtlGetVersion(&os_info); + if (os_info.dwMajorVersion < 10) + return 0; + if (os_info.dwMajorVersion > 10) + return 1; + if (os_info.dwMinorVersion > 0) + return 1; + return os_info.dwBuildNumber >= 16299; +} + + +static int uv__tcp_keepalive(uv_tcp_t* handle, + SOCKET socket, + int on, + unsigned int idle, + unsigned int intvl, + unsigned int cnt) { if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, - (const char*)&enable, - sizeof enable) == -1) { + (const char*)&on, + sizeof on) == -1) { return WSAGetLastError(); } - if (!enable) + if (!on) return 0; - if (delay < 1) + if (idle < 1 || intvl < 1 || cnt < 1) return UV_EINVAL; - if (setsockopt(socket, - IPPROTO_TCP, - TCP_KEEPALIVE, - (const char*)&delay, - sizeof delay) == -1) { - return WSAGetLastError(); + /* Windows 10, version 1709 (build 10.0.16299) and later require second units + * for TCP keepalive options. */ + if (uv__windows10_version1709()) { + if (setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPIDLE, + (const char*)&idle, + sizeof idle) == -1) { + return WSAGetLastError(); + } + + if (setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPINTVL, + (const char*)&intvl, + sizeof intvl) == -1) { + return WSAGetLastError(); + } + + if (setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPCNT, + (const char*)&cnt, + sizeof cnt) == -1) { + return WSAGetLastError(); + } + + return 0; } + /* For those versions prior to Windows 10 version 1709, + * we fall back to SIO_KEEPALIVE_VALS that expects millisecond units. + * The SIO_KEEPALIVE_VALS IOCTL is supported on Windows 2000 + * and later versions of the operating system. */ + struct tcp_keepalive keepalive; + keepalive.onoff = on; + keepalive.keepalivetime = idle * 1000; + keepalive.keepaliveinterval = intvl * 1000; + /* On Windows Vista and later, the number of keep-alive probes + * (data retransmissions) is set to 10 and cannot be changed. + * On Windows Server 2003, Windows XP, and Windows 2000, the default setting + * for number of keep-alive probes is 5 and cannot be changed programmatically. + */ + DWORD dummy; + if (WSAIoctl(socket, + SIO_KEEPALIVE_VALS, + (LPVOID) &keepalive, + sizeof keepalive, + NULL, + 0, + &dummy, + NULL, + NULL) == -1) + return WSAGetLastError(); + return 0; } @@ -132,7 +202,7 @@ static int uv__tcp_set_socket(uv_loop_t* loop, /* TODO: Use stored delay. */ if (handle->flags & UV_HANDLE_TCP_KEEPALIVE) { - err = uv__tcp_keepalive(handle, socket, 1, 60); + err = uv__tcp_keepalive(handle, socket, 1, 60, 1, 10); if (err) return err; } @@ -749,20 +819,6 @@ static int uv__is_loopback(const struct sockaddr_storage* storage) { return 0; } -// Check if Windows version is 10.0.16299 or later -static int uv__is_fast_loopback_fail_supported(void) { - OSVERSIONINFOW os_info; - if (!pRtlGetVersion) - return 0; - pRtlGetVersion(&os_info); - if (os_info.dwMajorVersion < 10) - return 0; - if (os_info.dwMajorVersion > 10) - return 1; - if (os_info.dwMinorVersion > 0) - return 1; - return os_info.dwBuildNumber >= 16299; -} static int uv__tcp_try_connect(uv_connect_t* req, uv_tcp_t* handle, @@ -809,7 +865,7 @@ static int uv__tcp_try_connect(uv_connect_t* req, * is not reachable, instead of waiting for 2s. We do not care if this fails. * This only works on Windows version 10.0.16299 and later. */ - if (uv__is_fast_loopback_fail_supported() && uv__is_loopback(&converted)) { + if (uv__windows10_version1709() && uv__is_loopback(&converted)) { memset(&retransmit_ioctl, 0, sizeof(retransmit_ioctl)); retransmit_ioctl.Rtt = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS; retransmit_ioctl.MaxSynRetransmissions = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS; @@ -1335,22 +1391,30 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int enable) { } -int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { +int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int idle) { + return uv_tcp_keepalive_ex(handle, on, idle, 1, 10); +} + +int uv_tcp_keepalive_ex(uv_tcp_t* handle, + int on, + unsigned int idle, + unsigned int intvl, + unsigned int cnt) { int err; if (handle->socket != INVALID_SOCKET) { - err = uv__tcp_keepalive(handle, handle->socket, enable, delay); + err = uv__tcp_keepalive(handle, handle->socket, on, idle, intvl, cnt); if (err) return uv_translate_sys_error(err); } - if (enable) { + if (on) { handle->flags |= UV_HANDLE_TCP_KEEPALIVE; } else { handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; } - /* TODO: Store delay if handle->socket isn't created yet. */ + /* TODO: Store idle if handle->socket isn't created yet. */ return 0; } diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c index 753cb6a34a5b9a..9c38e3d8b3ca47 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -284,7 +284,7 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { static void uv__thread_name_init_once(void) { HMODULE m; - m = GetModuleHandleA("api-ms-win-core-processthreads-l1-1-3.dll"); + m = GetModuleHandleW(L"api-ms-win-core-processthreads-l1-1-3.dll"); if (m != NULL) { pGetThreadDescription = (void*) GetProcAddress(m, "GetThreadDescription"); pSetThreadDescription = (void*) GetProcAddress(m, "SetThreadDescription"); diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index e0873c2a899c24..08e358a2cf1092 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -204,7 +204,7 @@ static int uv__udp_maybe_bind(uv_udp_t* handle, * so we just return an error directly when UV_UDP_REUSEPORT is requested * for binding the socket. */ if (flags & UV_UDP_REUSEPORT) - return ERROR_NOT_SUPPORTED; + return UV_ENOTSUP; if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) { /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */ @@ -908,11 +908,15 @@ int uv__udp_is_bound(uv_udp_t* handle) { } -int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { +int uv_udp_open_ex(uv_udp_t* handle, uv_os_sock_t sock, unsigned int flags) { WSAPROTOCOL_INFOW protocol_info; int opt_len; int err; + /* Check for bad flags. */ + if (flags & ~(UV_UDP_REUSEADDR | UV_UDP_REUSEPORT)) + return UV_EINVAL; + /* Detect the address family of the socket. */ opt_len = (int) sizeof protocol_info; if (getsockopt(sock, @@ -930,6 +934,25 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { if (err) return uv_translate_sys_error(err); + /* There is no SO_REUSEPORT on Windows, Windows only knows SO_REUSEADDR. + * so we just return an error directly when UV_UDP_REUSEPORT is requested + * for binding the socket. */ + if (flags & UV_UDP_REUSEPORT) + return UV_ENOTSUP; + + if (flags & UV_UDP_REUSEADDR) { + DWORD yes = 1; + /* Set SO_REUSEADDR on the socket. */ + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_REUSEADDR, + (char*) &yes, + sizeof yes) == SOCKET_ERROR) { + err = WSAGetLastError(); + return uv_translate_sys_error(err); + } + } + if (uv__udp_is_bound(handle)) handle->flags |= UV_HANDLE_BOUND; @@ -940,6 +963,11 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { } +int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { + return uv_udp_open_ex(handle, sock, 0); +} + + #define SOCKOPT_SETTER(name, option4, option6, validate) \ int uv_udp_set_##name(uv_udp_t* handle, int value) { \ DWORD optval = (DWORD) value; \ @@ -1149,13 +1177,16 @@ int uv__udp_try_send2(uv_udp_t* handle, uv_buf_t* bufs[/*count*/], unsigned int nbufs[/*count*/], struct sockaddr* addrs[/*count*/]) { - unsigned int i; + int i; int r; - for (i = 0; i < count; i++) { + if (count > INT_MAX) + return UV_EINVAL; + + for (i = 0; i < (int) count; i++) { r = uv_udp_try_send(handle, bufs[i], nbufs[i], addrs[i]); if (r < 0) - return i > 0 ? i : r; /* Error if first packet, else send count. */ + return i > 0 ? i : (int) r; /* Error if first packet, else send count. */ } return i; diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 57061bf8d703fe..fec07b269f7d38 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -376,10 +376,10 @@ int uv_set_process_title(const char* title) { static int uv__get_process_title(void) { - WCHAR title_w[MAX_TITLE_LENGTH]; + WCHAR title_w[MAX_PATH]; DWORD wlen; - wlen = GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR)); + wlen = GetModuleFileNameW(NULL, title_w, MAX_PATH); if (wlen == 0) return uv_translate_sys_error(GetLastError()); @@ -508,15 +508,15 @@ int uv_uptime(double* uptime) { unsigned int uv_available_parallelism(void) { DWORD_PTR procmask; DWORD_PTR sysmask; - int count; - int i; + unsigned count; + unsigned i; /* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems * with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458 */ count = 0; if (GetProcessAffinityMask(GetCurrentProcess(), &procmask, &sysmask)) - for (i = 0; i < 8 * sizeof(procmask); i++) + for (i = 0; i < 8u * sizeof(procmask); i++) count += 1 & (procmask >> i); if (count > 0) @@ -867,12 +867,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, } -void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - uv__free(addresses); -} - - int uv_getrusage(uv_rusage_t *uv_rusage) { FILETIME create_time, exit_time, kernel_time, user_time; SYSTEMTIME kernel_system_time, user_system_time; @@ -1281,7 +1275,7 @@ int uv_os_environ(uv_env_item_t** envitems, int* count) { FreeEnvironmentStringsW(env); for (i = 0; i < cnt; i++) { - envitem = &(*envitems)[cnt]; + envitem = &(*envitems)[i]; uv__free(envitem->name); } uv__free(*envitems); @@ -1519,20 +1513,26 @@ int uv_os_setpriority(uv_pid_t pid, int priority) { } int uv_thread_getpriority(uv_thread_t tid, int* priority) { + DWORD err; int r; if (priority == NULL) return UV_EINVAL; r = GetThreadPriority(tid); - if (r == THREAD_PRIORITY_ERROR_RETURN) - return uv_translate_sys_error(GetLastError()); + if (r == THREAD_PRIORITY_ERROR_RETURN) { + err = GetLastError(); + if (err == ERROR_INVALID_HANDLE) + return UV_ESRCH; + return uv_translate_sys_error(err); + } *priority = r; return 0; } int uv_thread_setpriority(uv_thread_t tid, int priority) { + DWORD err; int r; switch (priority) { @@ -1555,8 +1555,12 @@ int uv_thread_setpriority(uv_thread_t tid, int priority) { return 0; } - if (r == 0) - return uv_translate_sys_error(GetLastError()); + if (r == 0) { + err = GetLastError(); + if (err == ERROR_INVALID_HANDLE) + return UV_ESRCH; + return uv_translate_sys_error(err); + } return 0; } @@ -1703,6 +1707,9 @@ int uv_os_uname(uv_utsname_t* buffer) { case PROCESSOR_ARCHITECTURE_ARM: uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine)); break; + case PROCESSOR_ARCHITECTURE_ARM64: + uv__strscpy(buffer->machine, "arm64", sizeof(buffer->machine)); + break; default: uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine)); break; @@ -1735,10 +1742,13 @@ int uv_gettimeofday(uv_timeval64_t* tv) { return 0; } -int uv__random_rtlgenrandom(void* buf, size_t buflen) { +int uv__random_winrandom(void* buf, size_t buflen) { if (buflen == 0) return 0; + if (pProcessPrng != NULL && pProcessPrng(buf, buflen)) + return 0; + if (SystemFunction036(buf, buflen) == FALSE) return UV_EIO; diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index 315a0d49aff50b..7ed08dd2dc8d88 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -39,6 +39,9 @@ sNtQueryInformationProcess pNtQueryInformationProcess; /* Powrprof.dll function pointer */ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; +/* bcryptprimitives.dll function pointer */ +sProcessPrng pProcessPrng; + /* User32.dll function pointer */ sSetWinEventHook pSetWinEventHook; @@ -53,92 +56,118 @@ void uv__winapi_init(void) { HMODULE powrprof_module; HMODULE user32_module; HMODULE ws2_32_module; + HMODULE bcryptprimitives_module; HMODULE api_win_core_file_module; - ntdll_module = GetModuleHandleA("ntdll.dll"); + union { + FARPROC proc; + sRtlGetVersion pRtlGetVersion; + sRtlNtStatusToDosError pRtlNtStatusToDosError; + sNtDeviceIoControlFile pNtDeviceIoControlFile; + sNtQueryInformationFile pNtQueryInformationFile; + sNtSetInformationFile pNtSetInformationFile; + sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; + sNtQueryDirectoryFile pNtQueryDirectoryFile; + sNtQuerySystemInformation pNtQuerySystemInformation; + sNtQueryInformationProcess pNtQueryInformationProcess; + sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + sProcessPrng pProcessPrng; + sSetWinEventHook pSetWinEventHook; + uv_sGetHostNameW pGetHostNameW; + sGetFileInformationByName pGetFileInformationByName; + } u; + + ntdll_module = GetModuleHandleW(L"ntdll.dll"); if (ntdll_module == NULL) { - uv_fatal_error(GetLastError(), "GetModuleHandleA"); + uv_fatal_error(GetLastError(), "GetModuleHandleW"); } - pRtlGetVersion = (sRtlGetVersion) GetProcAddress(ntdll_module, - "RtlGetVersion"); + u.proc = GetProcAddress(ntdll_module, "RtlGetVersion"); + pRtlGetVersion = u.pRtlGetVersion; - pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress( - ntdll_module, - "RtlNtStatusToDosError"); + u.proc = GetProcAddress(ntdll_module, "RtlNtStatusToDosError"); + pRtlNtStatusToDosError = u.pRtlNtStatusToDosError; if (pRtlNtStatusToDosError == NULL) { uv_fatal_error(GetLastError(), "GetProcAddress"); } - pNtDeviceIoControlFile = (sNtDeviceIoControlFile) GetProcAddress( - ntdll_module, - "NtDeviceIoControlFile"); + u.proc = GetProcAddress(ntdll_module, "NtDeviceIoControlFile"); + pNtDeviceIoControlFile = u.pNtDeviceIoControlFile; if (pNtDeviceIoControlFile == NULL) { uv_fatal_error(GetLastError(), "GetProcAddress"); } - pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress( - ntdll_module, - "NtQueryInformationFile"); + u.proc = GetProcAddress(ntdll_module, "NtQueryInformationFile"); + pNtQueryInformationFile = u.pNtQueryInformationFile; if (pNtQueryInformationFile == NULL) { uv_fatal_error(GetLastError(), "GetProcAddress"); } - pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress( - ntdll_module, - "NtSetInformationFile"); + u.proc = GetProcAddress(ntdll_module, "NtSetInformationFile"); + pNtSetInformationFile = u.pNtSetInformationFile; if (pNtSetInformationFile == NULL) { uv_fatal_error(GetLastError(), "GetProcAddress"); } - pNtQueryVolumeInformationFile = (sNtQueryVolumeInformationFile) - GetProcAddress(ntdll_module, "NtQueryVolumeInformationFile"); + u.proc = GetProcAddress(ntdll_module, "NtQueryVolumeInformationFile"); + pNtQueryVolumeInformationFile = u.pNtQueryVolumeInformationFile; if (pNtQueryVolumeInformationFile == NULL) { uv_fatal_error(GetLastError(), "GetProcAddress"); } - pNtQueryDirectoryFile = (sNtQueryDirectoryFile) - GetProcAddress(ntdll_module, "NtQueryDirectoryFile"); + u.proc = GetProcAddress(ntdll_module, "NtQueryDirectoryFile"); + pNtQueryDirectoryFile = u.pNtQueryDirectoryFile; if (pNtQueryDirectoryFile == NULL) { uv_fatal_error(GetLastError(), "GetProcAddress"); } - pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress( - ntdll_module, - "NtQuerySystemInformation"); + u.proc = GetProcAddress(ntdll_module, "NtQuerySystemInformation"); + pNtQuerySystemInformation = u.pNtQuerySystemInformation; if (pNtQuerySystemInformation == NULL) { uv_fatal_error(GetLastError(), "GetProcAddress"); } - pNtQueryInformationProcess = (sNtQueryInformationProcess) GetProcAddress( - ntdll_module, - "NtQueryInformationProcess"); + u.proc = GetProcAddress(ntdll_module, "NtQueryInformationProcess"); + pNtQueryInformationProcess = u.pNtQueryInformationProcess; if (pNtQueryInformationProcess == NULL) { uv_fatal_error(GetLastError(), "GetProcAddress"); } - powrprof_module = LoadLibraryExA("powrprof.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + powrprof_module = LoadLibraryExA("powrprof.dll", + NULL, + LOAD_LIBRARY_SEARCH_SYSTEM32); if (powrprof_module != NULL) { - pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) - GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification"); + u.proc = GetProcAddress(powrprof_module, + "PowerRegisterSuspendResumeNotification"); + pPowerRegisterSuspendResumeNotification = + u.pPowerRegisterSuspendResumeNotification; + } + + bcryptprimitives_module = LoadLibraryExA("bcryptprimitives.dll", + NULL, + LOAD_LIBRARY_SEARCH_SYSTEM32); + if (bcryptprimitives_module != NULL) { + u.proc = GetProcAddress(bcryptprimitives_module, "ProcessPrng"); + pProcessPrng = u.pProcessPrng; } - user32_module = GetModuleHandleA("user32.dll"); + user32_module = GetModuleHandleW(L"user32.dll"); if (user32_module != NULL) { - pSetWinEventHook = (sSetWinEventHook) - GetProcAddress(user32_module, "SetWinEventHook"); + u.proc = GetProcAddress(user32_module, "SetWinEventHook"); + pSetWinEventHook = u.pSetWinEventHook; } - ws2_32_module = GetModuleHandleA("ws2_32.dll"); + ws2_32_module = GetModuleHandleW(L"ws2_32.dll"); if (ws2_32_module != NULL) { - pGetHostNameW = (uv_sGetHostNameW) GetProcAddress( - ws2_32_module, - "GetHostNameW"); + u.proc = GetProcAddress(ws2_32_module, "GetHostNameW"); + pGetHostNameW = u.pGetHostNameW; } - api_win_core_file_module = GetModuleHandleA("api-ms-win-core-file-l2-1-4.dll"); + api_win_core_file_module = + GetModuleHandleW(L"api-ms-win-core-file-l2-1-4.dll"); if (api_win_core_file_module != NULL) { - pGetFileInformationByName = (sGetFileInformationByName)GetProcAddress( - api_win_core_file_module, "GetFileInformationByName"); + u.proc = GetProcAddress(api_win_core_file_module, + "GetFileInformationByName"); + pGetFileInformationByName = u.pGetFileInformationByName; } } diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index b9c9f1abc8899e..2f25dc55fff9f4 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4163,6 +4163,10 @@ typedef struct _REPARSE_DATA_BUFFER { ULONG Flags; WCHAR PathBuffer[1]; } SymbolicLinkReparseBuffer; + struct { + ULONG Version; + UCHAR PathBuffer[1]; + } LinuxSymbolicLinkReparseBuffer; struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; @@ -4582,6 +4586,9 @@ typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { #ifndef IO_REPARSE_TAG_SYMLINK # define IO_REPARSE_TAG_SYMLINK (0xA000000CL) #endif +#ifndef IO_REPARSE_TAG_LX_SYMLINK +# define IO_REPARSE_TAG_LX_SYMLINK (0xA000001DL) +#endif #ifndef IO_REPARSE_TAG_APPEXECLINK # define IO_REPARSE_TAG_APPEXECLINK (0x8000001BL) #endif @@ -4751,6 +4758,8 @@ typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification) HANDLE Recipient, _PHPOWERNOTIFY RegistrationHandle); +typedef BOOL (WINAPI *sProcessPrng)(/*_Out_*/PBYTE pbData, SIZE_T cbData); + /* from Winuser.h */ typedef VOID (CALLBACK* WINEVENTPROC) (HWINEVENTHOOK hWinEventHook, @@ -4815,6 +4824,9 @@ extern sNtQueryInformationProcess pNtQueryInformationProcess; /* Powrprof.dll function pointer */ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; +/* bcryptprimitives.dll function pointer */ +extern sProcessPrng pProcessPrng; + /* User32.dll function pointer */ extern sSetWinEventHook pSetWinEventHook; diff --git a/deps/uv/src/win/winsock.h b/deps/uv/src/win/winsock.h index bb3808a35c27e6..e14b8b515a9935 100644 --- a/deps/uv/src/win/winsock.h +++ b/deps/uv/src/win/winsock.h @@ -38,10 +38,6 @@ # define SO_UPDATE_CONNECT_CONTEXT 0x7010 #endif -#ifndef TCP_KEEPALIVE -# define TCP_KEEPALIVE 3 -#endif - #ifndef IPV6_V6ONLY # define IPV6_V6ONLY 27 #endif @@ -62,6 +58,30 @@ # define MCAST_LEAVE_SOURCE_GROUP 46 #endif +#ifndef SIO_KEEPALIVE_VALS +#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) +struct tcp_keepalive { + u_long onoff; + u_long keepalivetime; + u_long keepaliveinterval; +}; +#endif + +/* + * TCP keepalive definitions on MinGW are located in . + */ +#ifndef TCP_KEEPIDLE +#define TCP_KEEPIDLE 0x03 /* start keepalives after this period */ +#endif + +#ifndef TCP_KEEPINTVL +#define TCP_KEEPINTVL 0x11 /* interval between keepalives */ +#endif + +#ifndef TCP_KEEPCNT +#define TCP_KEEPCNT 0x10 /* number of keepalives before death */ +#endif + /* * TDI defines that are only in the DDK. * We only need receive flags so far. diff --git a/deps/uv/test/run-benchmarks.c b/deps/uv/test/run-benchmarks.c index 2b343da4c91731..d7290f968e2a4a 100644 --- a/deps/uv/test/run-benchmarks.c +++ b/deps/uv/test/run-benchmarks.c @@ -31,7 +31,7 @@ #ifdef __MVS__ #include "zos-base.h" /* Initialize environment and zoslib */ -__attribute__((constructor)) void init() { +__attribute__((constructor)) void init(void) { zoslib_config_t config; init_zoslib_config(&config); init_zoslib(config); diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c index 17fb0e0cf73d25..9c2574ebf8ab01 100644 --- a/deps/uv/test/run-tests.c +++ b/deps/uv/test/run-tests.c @@ -40,7 +40,7 @@ #ifdef __MVS__ #include "zos-base.h" /* Initialize environment and zoslib */ -__attribute__((constructor)) void init() { +__attribute__((constructor)) void init(void) { zoslib_config_t config; init_zoslib_config(&config); init_zoslib(config); @@ -214,7 +214,10 @@ static int maybe_run_test(int argc, char **argv) { #ifdef _WIN32 DWORD flags; HMODULE kernelbase_module; - sCompareObjectHandles pCompareObjectHandles; /* function introduced in Windows 10 */ + union { + FARPROC proc; + sCompareObjectHandles pCompareObjectHandles; /* Windows >= 10 */ + } u; #endif notify_parent_process(); ASSERT_EQ(sizeof(closed_fd), read(0, &closed_fd, sizeof(closed_fd))); @@ -223,11 +226,10 @@ static int maybe_run_test(int argc, char **argv) { ASSERT_GT((intptr_t) closed_fd, 0); ASSERT_GT((intptr_t) open_fd, 0); ASSERT_NE(0, GetHandleInformation(open_fd, &flags)); - kernelbase_module = GetModuleHandleA("kernelbase.dll"); - pCompareObjectHandles = (sCompareObjectHandles) - GetProcAddress(kernelbase_module, "CompareObjectHandles"); - ASSERT_NE(pCompareObjectHandles == NULL || \ - !pCompareObjectHandles(open_fd, closed_fd), 0); + kernelbase_module = GetModuleHandleW(L"kernelbase.dll"); + u.proc = GetProcAddress(kernelbase_module, "CompareObjectHandles"); + if (u.pCompareObjectHandles != NULL) + ASSERT_EQ(FALSE, u.pCompareObjectHandles(open_fd, closed_fd)); #else ASSERT_GT(open_fd, 2); ASSERT_GT(closed_fd, 2); diff --git a/deps/uv/test/runner-win.c b/deps/uv/test/runner-win.c index 8035ca62f8ec9f..52e0f64debfefd 100644 --- a/deps/uv/test/runner-win.c +++ b/deps/uv/test/runner-win.c @@ -340,7 +340,7 @@ static int clear_line(void) { } -void rewind_cursor() { +void rewind_cursor(void) { if (clear_line() == -1) { /* If clear_line fails (stdout is not a console), print a newline. */ fprintf(stderr, "\n"); diff --git a/deps/uv/test/runner.h b/deps/uv/test/runner.h index ff7d4eec9b6870..23b7aa096a2158 100644 --- a/deps/uv/test/runner.h +++ b/deps/uv/test/runner.h @@ -22,7 +22,6 @@ #ifndef RUNNER_H_ #define RUNNER_H_ -#include /* PATH_MAX */ #include /* FILE */ @@ -57,7 +56,7 @@ typedef struct { task_entry_t TASKS[] = { #define TASK_LIST_END \ - { 0, 0, 0, 0, 0, 0 } \ + { 0, 0, 0, 0, 0, 0 } \ }; #define TEST_DECLARE(name) \ @@ -69,6 +68,23 @@ typedef struct { #define TEST_ENTRY_CUSTOM(name, is_helper, show_output, timeout) \ { #name, #name, &run_test_##name, is_helper, show_output, timeout }, +/* + * Macros for fs tests that, on linux, generate both normal and io_uring + * versions. + */ +#ifdef __linux__ +#define TEST_FS_DECLARE(name) \ + TEST_DECLARE(name) \ + TEST_DECLARE(name##_iouring) + +#define TEST_FS_ENTRY(name) \ + TEST_ENTRY(name) \ + TEST_ENTRY(name##_iouring) +#else +#define TEST_FS_DECLARE(name) TEST_DECLARE(name) +#define TEST_FS_ENTRY(name) TEST_ENTRY(name) +#endif + #define BENCHMARK_DECLARE(name) \ int run_benchmark_##name(void); diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h index e25a9c9a1386aa..45674ff1901d5a 100644 --- a/deps/uv/test/task.h +++ b/deps/uv/test/task.h @@ -53,14 +53,10 @@ # define TEST_PIPENAME "\\\\.\\pipe\\uv-test" # define TEST_PIPENAME_2 "\\\\.\\pipe\\uv-test2" # define TEST_PIPENAME_3 "\\\\.\\pipe\\uv-test3" -#elif __ANDROID__ -# define TEST_PIPENAME "/data/local/tmp/uv-test-sock" -# define TEST_PIPENAME_2 "/data/local/tmp/uv-test-sock2" -# define TEST_PIPENAME_3 "/data/local/tmp/uv-test-sock3" #else -# define TEST_PIPENAME "/tmp/uv-test-sock" -# define TEST_PIPENAME_2 "/tmp/uv-test-sock2" -# define TEST_PIPENAME_3 "/tmp/uv-test-sock3" +# define TEST_PIPENAME "uv-test-sock" +# define TEST_PIPENAME_2 "uv-test-sock2" +# define TEST_PIPENAME_3 "uv-test-sock3" #endif #ifdef _WIN32 @@ -113,8 +109,8 @@ typedef enum { #define ASSERT_BASE(a, operator, b, type, conv) \ do { \ - volatile type eval_a = (type) (a); \ - volatile type eval_b = (type) (b); \ + type const eval_a = (a); \ + type const eval_b = (b); \ if (!(eval_a operator eval_b)) { \ fprintf(stderr, \ "Assertion failed in %s on line %d: `%s %s %s` " \ @@ -131,6 +127,21 @@ typedef enum { } \ } while (0) +#define ASSERT_OK(a) \ + do { \ + int64_t const eval_a = (a); \ + if (eval_a) { \ + fprintf(stderr, \ + "Assertion failed in %s on line %d: `%s` okay " \ + "(error: %"PRId64")\n", \ + __FILE__, \ + __LINE__, \ + #a, \ + eval_a); \ + abort(); \ + } \ + } while (0) + #define ASSERT_BASE_STR(expr, a, operator, b, type, conv) \ do { \ if (!(expr)) { \ @@ -173,8 +184,8 @@ typedef enum { do { \ if (!(expr)) { \ int i; \ - unsigned char* a_ = (unsigned char*)a; \ - unsigned char* b_ = (unsigned char*)b; \ + const unsigned char* a_ = (a); \ + const unsigned char* b_ = (b); \ fprintf(stderr, \ "Assertion failed in %s on line %d: `%s %s %s` (", \ __FILE__, \ @@ -202,7 +213,6 @@ typedef enum { #define ASSERT_LE(a, b) ASSERT_BASE(a, <=, b, int64_t, PRId64) #define ASSERT_LT(a, b) ASSERT_BASE(a, <, b, int64_t, PRId64) #define ASSERT_NE(a, b) ASSERT_BASE(a, !=, b, int64_t, PRId64) -#define ASSERT_OK(a) ASSERT_BASE(a, ==, 0, int64_t, PRId64) #define ASSERT_UINT64_EQ(a, b) ASSERT_BASE(a, ==, b, uint64_t, PRIu64) #define ASSERT_UINT64_GE(a, b) ASSERT_BASE(a, >=, b, uint64_t, PRIu64) @@ -211,12 +221,12 @@ typedef enum { #define ASSERT_UINT64_LT(a, b) ASSERT_BASE(a, <, b, uint64_t, PRIu64) #define ASSERT_UINT64_NE(a, b) ASSERT_BASE(a, !=, b, uint64_t, PRIu64) -#define ASSERT_DOUBLE_EQ(a, b) ASSERT_BASE(a, ==, b, double, "f") -#define ASSERT_DOUBLE_GE(a, b) ASSERT_BASE(a, >=, b, double, "f") -#define ASSERT_DOUBLE_GT(a, b) ASSERT_BASE(a, >, b, double, "f") -#define ASSERT_DOUBLE_LE(a, b) ASSERT_BASE(a, <=, b, double, "f") -#define ASSERT_DOUBLE_LT(a, b) ASSERT_BASE(a, <, b, double, "f") -#define ASSERT_DOUBLE_NE(a, b) ASSERT_BASE(a, !=, b, double, "f") +#define ASSERT_DOUBLE_EQ(a, b) ASSERT_BASE(a, ==, b, volatile double, "f") +#define ASSERT_DOUBLE_GE(a, b) ASSERT_BASE(a, >=, b, volatile double, "f") +#define ASSERT_DOUBLE_GT(a, b) ASSERT_BASE(a, >, b, volatile double, "f") +#define ASSERT_DOUBLE_LE(a, b) ASSERT_BASE(a, <=, b, volatile double, "f") +#define ASSERT_DOUBLE_LT(a, b) ASSERT_BASE(a, <, b, volatile double, "f") +#define ASSERT_DOUBLE_NE(a, b) ASSERT_BASE(a, !=, b, volatile double, "f") #define ASSERT_STR_EQ(a, b) \ ASSERT_BASE_STR(strcmp(a, b) == 0, a, == , b, char*, "s") @@ -237,19 +247,23 @@ typedef enum { ASSERT_BASE_HEX(memcmp(a, b, size) != 0, a, !=, b, size) #define ASSERT_NULL(a) \ - ASSERT_BASE(a, ==, NULL, void*, "p") + ASSERT_BASE(a, ==, NULL, const void*, "p") #define ASSERT_NOT_NULL(a) \ - ASSERT_BASE(a, !=, NULL, void*, "p") + ASSERT_BASE(a, !=, NULL, const void*, "p") #define ASSERT_PTR_EQ(a, b) \ - ASSERT_BASE(a, ==, b, void*, "p") + ASSERT_BASE(a, ==, b, const void*, "p") #define ASSERT_PTR_NE(a, b) \ - ASSERT_BASE(a, !=, b, void*, "p") + ASSERT_BASE(a, !=, b, const void*, "p") #define ASSERT_PTR_LT(a, b) \ - ASSERT_BASE(a, <, b, void*, "p") + ASSERT_BASE(a, <, b, const void*, "p") +#define ASSERT_PTR_LE(a, b) \ + ASSERT_BASE(a, <=, b, const void*, "p") +#define ASSERT_PTR_GE(a, b) \ + ASSERT_BASE(a, >=, b, const void*, "p") /* This macro cleans up the event loop. This is used to avoid valgrind * warnings about memory being "leaked" by the event loop. @@ -270,6 +284,19 @@ typedef enum { int run_benchmark_##name(void); \ int run_benchmark_##name(void) +#ifdef __linux__ +#define TEST_FS_IMPL(name) \ + int run_test_##name(void); \ + int run_test_##name##_iouring(void) { \ + uv_os_setenv("UV_USE_IO_URING", "1"); \ + uv_loop_configure(uv_default_loop(), UV_LOOP_USE_IO_URING_SQPOLL); \ + return run_test_##name(); \ + } \ + int run_test_##name(void) +#else +#define TEST_FS_IMPL(name) TEST_IMPL(name) +#endif + #define HELPER_IMPL(name) \ int run_helper_##name(void); \ int run_helper_##name(void) @@ -358,7 +385,7 @@ UNUSED static int can_ipv6(void) { return supported; } -#if defined(__CYGWIN__) || defined(__MSYS__) || defined(__PASE__) +#if defined(__CYGWIN__) || defined(__MSYS__) || defined(__PASE__) || defined(__QNX__) # define NO_FS_EVENTS "Filesystem watching not supported on this platform." #endif diff --git a/deps/uv/test/test-embed.c b/deps/uv/test/test-embed.c index 6e9917239aa562..84fc7cad31fd49 100644 --- a/deps/uv/test/test-embed.c +++ b/deps/uv/test/test-embed.c @@ -25,7 +25,7 @@ #include #include -#if !defined(_WIN32) && !defined(_AIX) +#if !defined(_WIN32) && !defined(_AIX) && !defined(__QNX__) #include #endif @@ -56,7 +56,7 @@ TEST_IMPL(embed) { ASSERT_LE(0, uv_barrier_wait(&barrier)); while (uv_loop_alive(loop)) { -#if defined(_WIN32) || defined(_AIX) +#if defined(_WIN32) || defined(_AIX) || defined(__QNX__) ASSERT_LE(0, uv_run(loop, UV_RUN_ONCE)); #else int rc; diff --git a/deps/uv/test/test-fs-copyfile.c b/deps/uv/test/test-fs-copyfile.c index f7a0c2363e8f1f..0cdf42aadcb197 100644 --- a/deps/uv/test/test-fs-copyfile.c +++ b/deps/uv/test/test-fs-copyfile.c @@ -102,7 +102,7 @@ static void touch_file(const char* name, unsigned int size) { } -TEST_IMPL(fs_copyfile) { +TEST_FS_IMPL(fs_copyfile) { const char src[] = "test_file_src"; uv_loop_t* loop; uv_fs_t req; @@ -220,8 +220,13 @@ TEST_IMPL(fs_copyfile) { r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); /* On IBMi PASE, qsecofr users can overwrite read-only files */ # ifndef __PASE__ - ASSERT_EQ(req.result, UV_EACCES); - ASSERT_EQ(r, UV_EACCES); + if (0 == getuid()) { /* If root. */ + ASSERT_EQ(req.result, 0); + ASSERT_EQ(r, 0); + } else { + ASSERT_EQ(req.result, UV_EACCES); + ASSERT_EQ(r, UV_EACCES); + } # endif uv_fs_req_cleanup(&req); #endif diff --git a/deps/uv/test/test-fs-fd-hash.c b/deps/uv/test/test-fs-fd-hash.c index 4ed3d548e62171..a9ae25223ba9f3 100644 --- a/deps/uv/test/test-fs-fd-hash.c +++ b/deps/uv/test/test-fs-fd-hash.c @@ -66,17 +66,25 @@ void assert_removal(int fd) { /* Run a function for a set of values up to a very high number */ #define RUN_HASH(function) \ do { \ + uint64_t before = uv_hrtime(); \ for (fd = 0; fd < HASH_MAX; fd += HASH_INC) { \ function(fd); \ } \ + uint64_t after = uv_hrtime(); \ + double seconds = (after - before) / 1e9; \ + printf("%.5f hash %s\n", seconds, #function); \ } while (0) /* Run a function for a set of values that will cause many collisions */ #define RUN_COLLISIONS(function) \ do { \ + uint64_t before = uv_hrtime(); \ for (fd = 1; fd < BUCKET_MAX; fd += BUCKET_INC) { \ function(fd); \ } \ + uint64_t after = uv_hrtime(); \ + double seconds = (after - before) / 1e9; \ + printf("%.5f coll %s\n", seconds, #function); \ } while (0) diff --git a/deps/uv/test/test-fs-readdir.c b/deps/uv/test/test-fs-readdir.c index bacea653587c51..6ecfc077e155e8 100644 --- a/deps/uv/test/test-fs-readdir.c +++ b/deps/uv/test/test-fs-readdir.c @@ -96,7 +96,7 @@ static void empty_opendir_cb(uv_fs_t* req) { * of the uv_fs_opendir() -> uv_fs_readdir() -> uv_fs_closedir() sequence work * as expected when processing an empty directory. */ -TEST_IMPL(fs_readdir_empty_dir) { +TEST_FS_IMPL(fs_readdir_empty_dir) { const char* path; uv_fs_t mkdir_req; uv_fs_t rmdir_req; @@ -178,7 +178,7 @@ static void non_existing_opendir_cb(uv_fs_t* req) { ++non_existing_opendir_cb_count; } -TEST_IMPL(fs_readdir_non_existing_dir) { +TEST_FS_IMPL(fs_readdir_non_existing_dir) { const char* path; int r; @@ -230,7 +230,7 @@ static void file_opendir_cb(uv_fs_t* req) { ++file_opendir_cb_count; } -TEST_IMPL(fs_readdir_file) { +TEST_FS_IMPL(fs_readdir_file) { const char* path; int r; @@ -342,7 +342,7 @@ static void non_empty_opendir_cb(uv_fs_t* req) { ++non_empty_opendir_cb_count; } -TEST_IMPL(fs_readdir_non_empty_dir) { +TEST_FS_IMPL(fs_readdir_non_empty_dir) { size_t entries_count; uv_fs_t mkdir_req; uv_fs_t rmdir_req; @@ -518,7 +518,7 @@ static void cleanup_symlink_test_files(void) { uv_fs_req_cleanup(&req); } -TEST_IMPL(fs_readdir_symlink) { +TEST_FS_IMPL(fs_readdir_symlink) { uv_fs_t mkdir_req; uv_fs_t symlink_req; diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 4761b15bad188b..2a20baf67cdfce 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -23,6 +23,7 @@ #include "task.h" #include +#include /* offsetof */ #include /* memset */ #include #include @@ -37,6 +38,13 @@ # ifndef ERROR_SYMLINK_NOT_SUPPORTED # define ERROR_SYMLINK_NOT_SUPPORTED 1464 # endif +# ifndef REPARSE_DATA_BUFFER_HEADER_SIZE +# define REPARSE_DATA_BUFFER_HEADER_SIZE \ + offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer) +# endif +# ifndef IO_REPARSE_TAG_LX_SYMLINK +# define IO_REPARSE_TAG_LX_SYMLINK (0xA000001DL) +# endif # ifndef S_IFIFO # define S_IFIFO _S_IFIFO # endif @@ -65,18 +73,30 @@ static const int is_win32 = 1; static const int is_win32 = 0; #endif -#if defined(__APPLE__) || defined(__SUNPRO_C) -static const int is_apple_or_sunpro_c = 1; -#else -static const int is_apple_or_sunpro_c = 0; -#endif - typedef struct { const char* path; double atime; double mtime; } utime_check_t; +#ifdef _WIN32 +# ifndef REPARSE_DATA_BUFFER +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + ULONG Version; + UCHAR PathBuffer[1]; + } LinuxSymbolicLinkReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + } DUMMYUNIONNAME; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +# endif +#endif static int dummy_cb_count; static int close_cb_count; @@ -152,7 +172,7 @@ int uv_test_getiovmax(void) { int uv_test_getiovmax(void) { #if defined(IOV_MAX) return IOV_MAX; -#elif defined(_SC_IOV_MAX) +#elif defined(_SC_IOV_MAX) && !defined(__QNX__) static int iovmax = -1; if (iovmax == -1) { iovmax = sysconf(_SC_IOV_MAX); @@ -356,13 +376,14 @@ static void statfs_cb(uv_fs_t* req) { stats = req->ptr; #if defined(_WIN32) || defined(__sun) || defined(_AIX) || defined(__MVS__) || \ - defined(__OpenBSD__) || defined(__NetBSD__) + defined(__OpenBSD__) || defined(__NetBSD__) || defined(__QNX__) ASSERT_OK(stats->f_type); #else ASSERT_UINT64_GT(stats->f_type, 0); #endif ASSERT_GT(stats->f_bsize, 0); + ASSERT_GT(stats->f_frsize, 0); ASSERT_GT(stats->f_blocks, 0); ASSERT_LE(stats->f_bfree, stats->f_blocks); ASSERT_LE(stats->f_bavail, stats->f_bfree); @@ -728,7 +749,7 @@ static void open_loop_cb(uv_fs_t* req) { } -TEST_IMPL(fs_file_noent) { +TEST_FS_IMPL(fs_file_noent) { uv_fs_t req; int r; @@ -753,7 +774,7 @@ TEST_IMPL(fs_file_noent) { return 0; } -TEST_IMPL(fs_file_nametoolong) { +TEST_FS_IMPL(fs_file_nametoolong) { uv_fs_t req; int r; char name[TOO_LONG_NAME_LENGTH + 1]; @@ -779,7 +800,7 @@ TEST_IMPL(fs_file_nametoolong) { return 0; } -TEST_IMPL(fs_file_loop) { +TEST_FS_IMPL(fs_file_loop) { uv_fs_t req; int r; @@ -855,9 +876,10 @@ static void check_utime(const char* path, ASSERT_LE(s->st_atim.tv_sec, (long) atime); } else { double st_atim; +#ifndef __APPLE__ /* TODO(vtjnash): would it be better to normalize this? */ - if (!is_apple_or_sunpro_c) - ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); + ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); +#endif st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; /* Linux does not allow reading reliably the atime of a symlink * since readlink() can update it @@ -890,9 +912,10 @@ static void check_utime(const char* path, ASSERT_LE(s->st_mtim.tv_sec, (long) mtime); } else { double st_mtim; +#ifndef __APPLE__ /* TODO(vtjnash): would it be better to normalize this? */ - if (!is_apple_or_sunpro_c) - ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); + ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); +#endif st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; ASSERT_DOUBLE_EQ(st_mtim, mtime); } @@ -953,7 +976,7 @@ static void lutime_cb(uv_fs_t* req) { } -TEST_IMPL(fs_file_async) { +TEST_FS_IMPL(fs_file_async) { int r; /* Setup. */ @@ -1099,7 +1122,7 @@ static void fs_file_sync(int add_flags) { unlink("test_file"); unlink("test_file2"); } -TEST_IMPL(fs_file_sync) { +TEST_FS_IMPL(fs_file_sync) { fs_file_sync(0); fs_file_sync(UV_FS_O_FILEMAP); @@ -1107,7 +1130,7 @@ TEST_IMPL(fs_file_sync) { return 0; } -TEST_IMPL(fs_posix_delete) { +TEST_FS_IMPL(fs_posix_delete) { int r; /* Setup. */ @@ -1180,7 +1203,7 @@ static void fs_file_write_null_buffer(int add_flags) { unlink("test_file"); } -TEST_IMPL(fs_file_write_null_buffer) { +TEST_FS_IMPL(fs_file_write_null_buffer) { fs_file_write_null_buffer(0); fs_file_write_null_buffer(UV_FS_O_FILEMAP); @@ -1189,7 +1212,7 @@ TEST_IMPL(fs_file_write_null_buffer) { } -TEST_IMPL(fs_async_dir) { +TEST_FS_IMPL(fs_async_dir) { int r; uv_dirent_t dent; @@ -1373,17 +1396,17 @@ static void sendfile_setup(int f) { } -TEST_IMPL(fs_async_sendfile) { +TEST_FS_IMPL(fs_async_sendfile) { return test_sendfile(sendfile_setup, sendfile_cb, 65545); } -TEST_IMPL(fs_async_sendfile_nodata) { +TEST_FS_IMPL(fs_async_sendfile_nodata) { return test_sendfile(NULL, sendfile_nodata_cb, 0); } -TEST_IMPL(fs_mkdtemp) { +TEST_FS_IMPL(fs_mkdtemp) { int r; const char* path_template = "test_dir_XXXXXX"; @@ -1414,7 +1437,7 @@ TEST_IMPL(fs_mkdtemp) { } -TEST_IMPL(fs_mkstemp) { +TEST_FS_IMPL(fs_mkstemp) { int r; int fd; const char path_template[] = "test_file_XXXXXX"; @@ -1482,7 +1505,7 @@ TEST_IMPL(fs_mkstemp) { } -TEST_IMPL(fs_fstat) { +TEST_FS_IMPL(fs_fstat) { int r; uv_fs_t req; uv_file file; @@ -1646,7 +1669,7 @@ TEST_IMPL(fs_fstat) { } -TEST_IMPL(fs_fstat_st_dev) { +TEST_FS_IMPL(fs_fstat_st_dev) { uv_fs_t req; uv_fs_t req_link; uv_loop_t* loop = uv_default_loop(); @@ -1690,7 +1713,7 @@ TEST_IMPL(fs_fstat_st_dev) { } -TEST_IMPL(fs_fstat_stdio) { +TEST_FS_IMPL(fs_fstat_stdio) { int fd; int res; uv_fs_t req; @@ -1729,7 +1752,7 @@ TEST_IMPL(fs_fstat_stdio) { } -TEST_IMPL(fs_access) { +TEST_FS_IMPL(fs_access) { int r; uv_fs_t req; uv_file file; @@ -1805,7 +1828,7 @@ TEST_IMPL(fs_access) { } -TEST_IMPL(fs_chmod) { +TEST_FS_IMPL(fs_chmod) { int r; uv_fs_t req; uv_file file; @@ -1903,7 +1926,7 @@ TEST_IMPL(fs_chmod) { } -TEST_IMPL(fs_unlink_readonly) { +TEST_FS_IMPL(fs_unlink_readonly) { int r; uv_fs_t req; uv_file file; @@ -1960,7 +1983,7 @@ TEST_IMPL(fs_unlink_readonly) { } #ifdef _WIN32 -TEST_IMPL(fs_unlink_archive_readonly) { +TEST_FS_IMPL(fs_unlink_archive_readonly) { int r; uv_fs_t req; uv_file file; @@ -2016,7 +2039,7 @@ TEST_IMPL(fs_unlink_archive_readonly) { } #endif -TEST_IMPL(fs_chown) { +TEST_FS_IMPL(fs_chown) { int r; uv_fs_t req; uv_file file; @@ -2109,7 +2132,7 @@ TEST_IMPL(fs_chown) { } -TEST_IMPL(fs_link) { +TEST_FS_IMPL(fs_link) { int r; uv_fs_t req; uv_file file; @@ -2195,7 +2218,7 @@ TEST_IMPL(fs_link) { } -TEST_IMPL(fs_readlink) { +TEST_FS_IMPL(fs_readlink) { /* Must return UV_ENOENT on an inexistent file */ { uv_fs_t req; @@ -2249,7 +2272,7 @@ TEST_IMPL(fs_readlink) { } -TEST_IMPL(fs_realpath) { +TEST_FS_IMPL(fs_realpath) { uv_fs_t req; loop = uv_default_loop(); @@ -2270,7 +2293,7 @@ TEST_IMPL(fs_realpath) { } -TEST_IMPL(fs_symlink) { +TEST_FS_IMPL(fs_symlink) { int r; uv_fs_t req; uv_file file; @@ -2584,16 +2607,16 @@ int test_symlink_dir_impl(int type) { return 0; } -TEST_IMPL(fs_symlink_dir) { +TEST_FS_IMPL(fs_symlink_dir) { return test_symlink_dir_impl(UV_FS_SYMLINK_DIR); } -TEST_IMPL(fs_symlink_junction) { +TEST_FS_IMPL(fs_symlink_junction) { return test_symlink_dir_impl(UV_FS_SYMLINK_JUNCTION); } #ifdef _WIN32 -TEST_IMPL(fs_non_symlink_reparse_point) { +TEST_FS_IMPL(fs_non_symlink_reparse_point) { uv_fs_t req; int r; HANDLE file_handle; @@ -2693,7 +2716,81 @@ TEST_IMPL(fs_non_symlink_reparse_point) { return 0; } -TEST_IMPL(fs_lstat_windows_store_apps) { +TEST_FS_IMPL(fs_readlink_lx_symlink) { + uv_fs_t req; + int r; + HANDLE file_handle; + REPARSE_DATA_BUFFER* reparse_buffer; + DWORD bytes_returned; + const char* target_path = "target_file"; + size_t target_len = strlen(target_path); + size_t buffer_size; + + /* set-up */ + unlink("test_dir/lx_symlink"); + rmdir("test_dir"); + + loop = uv_default_loop(); + + uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL); + uv_fs_req_cleanup(&req); + + file_handle = CreateFile("test_dir/lx_symlink", + GENERIC_WRITE | FILE_WRITE_ATTRIBUTES, + 0, + NULL, + CREATE_ALWAYS, + FILE_FLAG_OPEN_REPARSE_POINT | + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + ASSERT_PTR_NE(file_handle, INVALID_HANDLE_VALUE); + + /* Allocate buffer for reparse data */ + buffer_size = REPARSE_DATA_BUFFER_HEADER_SIZE + + sizeof(ULONG) + /* Version field */ + target_len; + reparse_buffer = malloc(buffer_size); + ASSERT_NOT_NULL(reparse_buffer); + + /* Set up Linux symlink reparse buffer */ + memset(reparse_buffer, 0, buffer_size); + reparse_buffer->ReparseTag = IO_REPARSE_TAG_LX_SYMLINK; + reparse_buffer->ReparseDataLength = sizeof(ULONG) + target_len; + reparse_buffer->Reserved = 0; + reparse_buffer->LinuxSymbolicLinkReparseBuffer.Version = 2; + memcpy(reparse_buffer->LinuxSymbolicLinkReparseBuffer.PathBuffer, + target_path, + target_len); + + r = DeviceIoControl(file_handle, + FSCTL_SET_REPARSE_POINT, + reparse_buffer, + buffer_size, + NULL, + 0, + &bytes_returned, + NULL); + ASSERT(r); + + CloseHandle(file_handle); + + /* Test that readlink works on the Linux symlink */ + r = uv_fs_readlink(NULL, &req, "test_dir/lx_symlink", NULL); + ASSERT_OK(r); + ASSERT_NOT_NULL(req.ptr); + ASSERT_OK(strcmp(req.ptr, target_path)); + uv_fs_req_cleanup(&req); + + /* clean-up */ + free(reparse_buffer); + unlink("test_dir/lx_symlink"); + rmdir("test_dir"); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + +TEST_FS_IMPL(fs_lstat_windows_store_apps) { uv_loop_t* loop; char localappdata[MAX_PATH]; char windowsapps_path[MAX_PATH]; @@ -2746,7 +2843,7 @@ TEST_IMPL(fs_lstat_windows_store_apps) { #endif -TEST_IMPL(fs_utime) { +TEST_FS_IMPL(fs_utime) { utime_check_t checkme; const char* path = "test_file"; double atime; @@ -2827,13 +2924,15 @@ TEST_IMPL(fs_utime) { } -TEST_IMPL(fs_utime_round) { +TEST_FS_IMPL(fs_utime_round) { const char path[] = "test_file"; double atime; double mtime; uv_fs_t req; int r; - +#if defined(__QNX__) + RETURN_SKIP("Setting time to a negative value is unsupported on QNX"); +#endif loop = uv_default_loop(); unlink(path); r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT, @@ -2869,7 +2968,7 @@ TEST_IMPL(fs_utime_round) { #ifdef _WIN32 -TEST_IMPL(fs_stat_root) { +TEST_FS_IMPL(fs_stat_root) { int r; r = uv_fs_stat(NULL, &stat_req, "\\", NULL); @@ -2900,7 +2999,7 @@ TEST_IMPL(fs_stat_root) { #endif -TEST_IMPL(fs_futime) { +TEST_FS_IMPL(fs_futime) { utime_check_t checkme; const char* path = "test_file"; double atime; @@ -2998,7 +3097,7 @@ TEST_IMPL(fs_futime) { } -TEST_IMPL(fs_lutime) { +TEST_FS_IMPL(fs_lutime) { utime_check_t checkme; const char* path = "test_file"; const char* symlink_path = "test_file_symlink"; @@ -3105,7 +3204,7 @@ TEST_IMPL(fs_lutime) { } -TEST_IMPL(fs_stat_missing_path) { +TEST_FS_IMPL(fs_stat_missing_path) { uv_fs_t req; int r; @@ -3121,7 +3220,7 @@ TEST_IMPL(fs_stat_missing_path) { } -TEST_IMPL(fs_scandir_empty_dir) { +TEST_FS_IMPL(fs_scandir_empty_dir) { const char* path; uv_fs_t req; uv_dirent_t dent; @@ -3158,7 +3257,7 @@ TEST_IMPL(fs_scandir_empty_dir) { } -TEST_IMPL(fs_scandir_non_existent_dir) { +TEST_FS_IMPL(fs_scandir_non_existent_dir) { const char* path; uv_fs_t req; uv_dirent_t dent; @@ -3191,7 +3290,7 @@ TEST_IMPL(fs_scandir_non_existent_dir) { return 0; } -TEST_IMPL(fs_scandir_file) { +TEST_FS_IMPL(fs_scandir_file) { const char* path; int r; @@ -3215,7 +3314,7 @@ TEST_IMPL(fs_scandir_file) { /* Run in Valgrind. Should not leak when the iterator isn't exhausted. */ -TEST_IMPL(fs_scandir_early_exit) { +TEST_FS_IMPL(fs_scandir_early_exit) { uv_dirent_t d; uv_fs_t req; @@ -3232,7 +3331,7 @@ TEST_IMPL(fs_scandir_early_exit) { } -TEST_IMPL(fs_open_dir) { +TEST_FS_IMPL(fs_open_dir) { const char* path; uv_fs_t req; int r, file; @@ -3329,7 +3428,7 @@ static void fs_file_open_append(int add_flags) { /* Cleanup */ unlink("test_file"); } -TEST_IMPL(fs_file_open_append) { +TEST_FS_IMPL(fs_file_open_append) { fs_file_open_append(0); fs_file_open_append(UV_FS_O_FILEMAP); @@ -3338,7 +3437,7 @@ TEST_IMPL(fs_file_open_append) { } -TEST_IMPL(fs_rename_to_existing_file) { +TEST_FS_IMPL(fs_rename_to_existing_file) { int r; /* Setup. */ @@ -3456,7 +3555,7 @@ static void fs_read_bufs(int add_flags) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); } -TEST_IMPL(fs_read_bufs) { +TEST_FS_IMPL(fs_read_bufs) { fs_read_bufs(0); fs_read_bufs(UV_FS_O_FILEMAP); @@ -3523,7 +3622,7 @@ static void fs_read_file_eof(int add_flags) { /* Cleanup */ unlink("test_file"); } -TEST_IMPL(fs_read_file_eof) { +TEST_FS_IMPL(fs_read_file_eof) { fs_read_file_eof(0); fs_read_file_eof(UV_FS_O_FILEMAP); @@ -3618,7 +3717,7 @@ static void fs_write_multiple_bufs(int add_flags) { /* Cleanup */ unlink("test_file"); } -TEST_IMPL(fs_write_multiple_bufs) { +TEST_FS_IMPL(fs_write_multiple_bufs) { fs_write_multiple_bufs(0); fs_write_multiple_bufs(UV_FS_O_FILEMAP); @@ -3726,7 +3825,7 @@ static void fs_write_alotof_bufs(int add_flags) { unlink("test_file"); free(iovs); } -TEST_IMPL(fs_write_alotof_bufs) { +TEST_FS_IMPL(fs_write_alotof_bufs) { fs_write_alotof_bufs(0); fs_write_alotof_bufs(UV_FS_O_FILEMAP); @@ -3842,7 +3941,7 @@ static void fs_write_alotof_bufs_with_offset(int add_flags) { unlink("test_file"); free(iovs); } -TEST_IMPL(fs_write_alotof_bufs_with_offset) { +TEST_FS_IMPL(fs_write_alotof_bufs_with_offset) { fs_write_alotof_bufs_with_offset(0); fs_write_alotof_bufs_with_offset(UV_FS_O_FILEMAP); @@ -3850,7 +3949,7 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) { return 0; } -TEST_IMPL(fs_read_dir) { +TEST_FS_IMPL(fs_read_dir) { int r; char buf[2]; loop = uv_default_loop(); @@ -3889,6 +3988,12 @@ TEST_IMPL(fs_read_dir) { * created on. That is why this assertion is a bit lenient. */ ASSERT((r >= 0) || (r == UV_EISDIR)); +#elif defined(__QNX__) + /* + * If UV_FS_O_DIRECTORY is supplied, QNX returns ENOSYS. Otherwise + * UV_EISDIR is returned. Here we are lenient and accept both. + */ + ASSERT((r == UV_ENOSYS) || (r == UV_EISDIR)); #else ASSERT_EQ(r, UV_EISDIR); #endif @@ -3907,11 +4012,11 @@ TEST_IMPL(fs_read_dir) { #ifdef _WIN32 -TEST_IMPL(fs_partial_read) { +TEST_FS_IMPL(fs_partial_read) { RETURN_SKIP("Test not implemented on Windows."); } -TEST_IMPL(fs_partial_write) { +TEST_FS_IMPL(fs_partial_write) { RETURN_SKIP("Test not implemented on Windows."); } @@ -4063,19 +4168,19 @@ static void test_fs_partial(int doread) { MAKE_VALGRIND_HAPPY(loop); } -TEST_IMPL(fs_partial_read) { +TEST_FS_IMPL(fs_partial_read) { test_fs_partial(1); return 0; } -TEST_IMPL(fs_partial_write) { +TEST_FS_IMPL(fs_partial_write) { test_fs_partial(0); return 0; } #endif/* _WIN32 */ -TEST_IMPL(fs_read_write_null_arguments) { +TEST_FS_IMPL(fs_read_write_null_arguments) { int r; r = uv_fs_read(NULL, &read_req, 0, NULL, 0, -1, NULL); @@ -4138,7 +4243,7 @@ TEST_IMPL(fs_read_write_null_arguments) { } -TEST_IMPL(get_osfhandle_valid_handle) { +TEST_FS_IMPL(get_osfhandle_valid_handle) { int r; uv_os_fd_t fd; @@ -4174,7 +4279,7 @@ TEST_IMPL(get_osfhandle_valid_handle) { return 0; } -TEST_IMPL(open_osfhandle_valid_handle) { +TEST_FS_IMPL(open_osfhandle_valid_handle) { int r; uv_os_fd_t handle; int fd; @@ -4220,7 +4325,7 @@ TEST_IMPL(open_osfhandle_valid_handle) { return 0; } -TEST_IMPL(fs_file_pos_after_op_with_offset) { +TEST_FS_IMPL(fs_file_pos_after_op_with_offset) { int r; /* Setup. */ @@ -4349,7 +4454,7 @@ static void fs_file_pos_write(int add_flags) { fs_file_pos_close_check("aecd", 4); } -TEST_IMPL(fs_file_pos_write) { +TEST_FS_IMPL(fs_file_pos_write) { fs_file_pos_write(0); fs_file_pos_write(UV_FS_O_FILEMAP); @@ -4389,7 +4494,7 @@ static void fs_file_pos_append(int add_flags) { fs_file_pos_close_check("abcde", 5); } -TEST_IMPL(fs_file_pos_append) { +TEST_FS_IMPL(fs_file_pos_append) { fs_file_pos_append(0); fs_file_pos_append(UV_FS_O_FILEMAP); @@ -4398,7 +4503,7 @@ TEST_IMPL(fs_file_pos_append) { } #endif -TEST_IMPL(fs_null_req) { +TEST_FS_IMPL(fs_null_req) { /* Verify that all fs functions return UV_EINVAL when the request is NULL. */ int r; @@ -4502,7 +4607,7 @@ TEST_IMPL(fs_null_req) { } #ifdef _WIN32 -TEST_IMPL(fs_exclusive_sharing_mode) { +TEST_FS_IMPL(fs_exclusive_sharing_mode) { int r; /* Setup. */ @@ -4557,7 +4662,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) { #endif #ifdef _WIN32 -TEST_IMPL(fs_file_flag_no_buffering) { +TEST_FS_IMPL(fs_file_flag_no_buffering) { int r; /* Setup. */ @@ -4614,7 +4719,7 @@ int call_icacls(const char* command, ...) { return system(icacls_command); } -TEST_IMPL(fs_open_readonly_acl) { +TEST_FS_IMPL(fs_open_readonly_acl) { uv_passwd_t pwd; uv_fs_t req; int r; @@ -4689,7 +4794,7 @@ TEST_IMPL(fs_open_readonly_acl) { return 0; } -TEST_IMPL(fs_stat_no_permission) { +TEST_FS_IMPL(fs_stat_no_permission) { uv_passwd_t pwd; uv_fs_t req; int r; @@ -4745,7 +4850,7 @@ TEST_IMPL(fs_stat_no_permission) { #endif #ifdef _WIN32 -TEST_IMPL(fs_fchmod_archive_readonly) { +TEST_FS_IMPL(fs_fchmod_archive_readonly) { uv_fs_t req; uv_file file; int r; @@ -4790,7 +4895,7 @@ TEST_IMPL(fs_fchmod_archive_readonly) { return 0; } -TEST_IMPL(fs_invalid_mkdir_name) { +TEST_FS_IMPL(fs_invalid_mkdir_name) { uv_loop_t* loop; uv_fs_t req; int r; @@ -4804,29 +4909,49 @@ TEST_IMPL(fs_invalid_mkdir_name) { } #endif -TEST_IMPL(fs_statfs) { +TEST_FS_IMPL(fs_statfs) { uv_fs_t req; + uv_fs_t req1; int r; + /* Setup. */ + unlink("test_file"); + + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, + S_IRUSR | S_IWUSR, NULL); + ASSERT_GT(r, 0); + + uv_fs_req_cleanup(&req); + + r = uv_fs_close(NULL, &req, req.result, NULL); + ASSERT_OK(r); + + uv_fs_req_cleanup(&req); + loop = uv_default_loop(); - /* Test the synchronous version. */ + /* Test the synchronous version for both a directory and a file. */ r = uv_fs_statfs(NULL, &req, ".", NULL); ASSERT_OK(r); statfs_cb(&req); - ASSERT_EQ(1, statfs_cb_count); + r = uv_fs_statfs(NULL, &req, "test_file", NULL); + ASSERT_OK(r); + statfs_cb(&req); + ASSERT_EQ(2, statfs_cb_count); - /* Test the asynchronous version. */ + /* Test the asynchronous version too. */ r = uv_fs_statfs(loop, &req, ".", statfs_cb); ASSERT_OK(r); + r = uv_fs_statfs(loop, &req1, "test_file", statfs_cb); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT_EQ(2, statfs_cb_count); + ASSERT_EQ(4, statfs_cb_count); MAKE_VALGRIND_HAPPY(loop); return 0; } -TEST_IMPL(fs_get_system_error) { +TEST_FS_IMPL(fs_get_system_error) { uv_fs_t req; int r; int system_error; @@ -4845,7 +4970,7 @@ TEST_IMPL(fs_get_system_error) { } -TEST_IMPL(fs_stat_batch_multiple) { +TEST_FS_IMPL(fs_stat_batch_multiple) { uv_fs_t req[300]; int r; int i; @@ -4871,7 +4996,7 @@ TEST_IMPL(fs_stat_batch_multiple) { #ifdef _WIN32 -TEST_IMPL(fs_wtf) { +TEST_FS_IMPL(fs_wtf) { int r; HANDLE file_handle; uv_dirent_t dent; diff --git a/deps/uv/test/test-get-currentexe.c b/deps/uv/test/test-get-currentexe.c index c813d3a5c4f883..98acbfd992fe6a 100644 --- a/deps/uv/test/test-get-currentexe.c +++ b/deps/uv/test/test-get-currentexe.c @@ -35,9 +35,6 @@ TEST_IMPL(get_currentexe) { #if defined(__QEMU__) RETURN_SKIP("Test does not currently work in QEMU"); #endif -#if defined(__OpenBSD__) - RETURN_SKIP("Test does not currently work in OpenBSD"); -#endif char buffer[PATHMAX]; char path[PATHMAX]; diff --git a/deps/uv/test/test-idna.c b/deps/uv/test/test-idna.c index 46df9f3c581015..c154bb4de78a7e 100644 --- a/deps/uv/test/test-idna.c +++ b/deps/uv/test/test-idna.c @@ -19,6 +19,14 @@ * IN THE SOFTWARE. */ +/* This blank UV_EXTERN squelches "‘uv_wtf8_to_utf16’ redeclared without + * dllimport attribute: previous dllimport ignored" warnings. We neither want + * or need dllimport or dllexport, we just include the source file verbatim. + * It's kind of sloppy because we end up with duplicate symbols, one in + * libuv.dll and one in this translation unit, but it works out fine in + * the end. + */ +#define UV_EXTERN #include "task.h" #define uv__malloc malloc #include "../src/idna.c" @@ -228,5 +236,13 @@ TEST_IMPL(wtf8) { ASSERT_GT(len, 0); ASSERT_LT(len, ARRAY_SIZE(buf)); uv_wtf8_to_utf16(input, buf, len); + + /* Test 0x10FFFF, max unicode character */ + static const char input_max[] = "\xF4\x8F\xBF\xBF"; + + len = uv_wtf8_length_as_utf16(input_max); + ASSERT_GT(len, 0); + ASSERT_LT(len, ARRAY_SIZE(buf)); + uv_wtf8_to_utf16(input_max, buf, len); return 0; } diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 0dea544699d75f..794a2f8113ac23 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -77,6 +77,7 @@ TEST_DECLARE (tty_escape_sequence_processing) #endif TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) +TEST_DECLARE (tty_pty_partial) TEST_DECLARE (stdio_over_pipes) TEST_DECLARE (stdio_emulate_iocp) TEST_DECLARE (ip6_pton) @@ -175,6 +176,8 @@ TEST_DECLARE (udp_send_and_recv) TEST_DECLARE (udp_send_hang_loop) TEST_DECLARE (udp_send_immediate) TEST_DECLARE (udp_send_unreachable) +TEST_DECLARE (udp_recvmsg_unreachable_error) +TEST_DECLARE (udp_recvmsg_unreachable_error6) TEST_DECLARE (udp_mmsg) TEST_DECLARE (udp_multicast_join) TEST_DECLARE (udp_multicast_join6) @@ -352,53 +355,54 @@ TEST_DECLARE (fs_poll_close_request_multi_stop_start) TEST_DECLARE (fs_poll_close_request_stop_when_active) TEST_DECLARE (kill) TEST_DECLARE (kill_invalid_signum) -TEST_DECLARE (fs_file_noent) -TEST_DECLARE (fs_file_nametoolong) -TEST_DECLARE (fs_file_loop) -TEST_DECLARE (fs_file_async) -TEST_DECLARE (fs_file_sync) -TEST_DECLARE (fs_posix_delete) -TEST_DECLARE (fs_file_write_null_buffer) -TEST_DECLARE (fs_async_dir) -TEST_DECLARE (fs_async_sendfile) -TEST_DECLARE (fs_async_sendfile_nodata) -TEST_DECLARE (fs_mkdtemp) -TEST_DECLARE (fs_mkstemp) -TEST_DECLARE (fs_fstat) -TEST_DECLARE (fs_fstat_stdio) -TEST_DECLARE (fs_fstat_st_dev) -TEST_DECLARE (fs_access) -TEST_DECLARE (fs_chmod) -TEST_DECLARE (fs_copyfile) -TEST_DECLARE (fs_unlink_readonly) +TEST_FS_DECLARE (fs_file_noent) +TEST_FS_DECLARE (fs_file_nametoolong) +TEST_FS_DECLARE (fs_file_loop) +TEST_FS_DECLARE (fs_file_async) +TEST_FS_DECLARE (fs_file_sync) +TEST_FS_DECLARE (fs_posix_delete) +TEST_FS_DECLARE (fs_file_write_null_buffer) +TEST_FS_DECLARE (fs_async_dir) +TEST_FS_DECLARE (fs_async_sendfile) +TEST_FS_DECLARE (fs_async_sendfile_nodata) +TEST_FS_DECLARE (fs_mkdtemp) +TEST_FS_DECLARE (fs_mkstemp) +TEST_FS_DECLARE (fs_fstat) +TEST_FS_DECLARE (fs_fstat_stdio) +TEST_FS_DECLARE (fs_fstat_st_dev) +TEST_FS_DECLARE (fs_access) +TEST_FS_DECLARE (fs_chmod) +TEST_FS_DECLARE (fs_copyfile) +TEST_FS_DECLARE (fs_unlink_readonly) #ifdef _WIN32 -TEST_DECLARE (fs_unlink_archive_readonly) +TEST_FS_DECLARE (fs_unlink_archive_readonly) #endif -TEST_DECLARE (fs_chown) -TEST_DECLARE (fs_link) -TEST_DECLARE (fs_readlink) -TEST_DECLARE (fs_realpath) -TEST_DECLARE (fs_symlink) -TEST_DECLARE (fs_symlink_dir) +TEST_FS_DECLARE (fs_chown) +TEST_FS_DECLARE (fs_link) +TEST_FS_DECLARE (fs_readlink) +TEST_FS_DECLARE (fs_realpath) +TEST_FS_DECLARE (fs_symlink) +TEST_FS_DECLARE (fs_symlink_dir) #ifdef _WIN32 -TEST_DECLARE (fs_symlink_junction) -TEST_DECLARE (fs_non_symlink_reparse_point) -TEST_DECLARE (fs_lstat_windows_store_apps) -TEST_DECLARE (fs_open_flags) +TEST_FS_DECLARE (fs_symlink_junction) +TEST_FS_DECLARE (fs_non_symlink_reparse_point) +TEST_FS_DECLARE (fs_readlink_lx_symlink) +TEST_FS_DECLARE (fs_lstat_windows_store_apps) +TEST_FS_DECLARE (fs_open_flags) #endif #if defined(_WIN32) && !defined(USING_UV_SHARED) -TEST_DECLARE (fs_fd_hash) +TEST_FS_DECLARE (fs_fd_hash) #endif -TEST_DECLARE (fs_utime) -TEST_DECLARE (fs_utime_round) -TEST_DECLARE (fs_futime) -TEST_DECLARE (fs_lutime) -TEST_DECLARE (fs_file_open_append) -TEST_DECLARE (fs_statfs) -TEST_DECLARE (fs_stat_batch_multiple) -TEST_DECLARE (fs_stat_missing_path) -TEST_DECLARE (fs_read_bufs) -TEST_DECLARE (fs_read_file_eof) +TEST_FS_DECLARE (fs_utime) +TEST_FS_DECLARE (fs_utime_round) +TEST_FS_DECLARE (fs_futime) +TEST_FS_DECLARE (fs_lutime) +TEST_FS_DECLARE (fs_file_open_append) +TEST_FS_DECLARE (fs_statfs) +TEST_FS_DECLARE (fs_stat_batch_multiple) +TEST_FS_DECLARE (fs_stat_missing_path) +TEST_FS_DECLARE (fs_read_bufs) +TEST_FS_DECLARE (fs_read_file_eof) TEST_DECLARE (fs_event_watch_dir) TEST_DECLARE (fs_event_watch_delete_dir) TEST_DECLARE (fs_event_watch_dir_recursive) @@ -422,41 +426,41 @@ TEST_DECLARE (fs_event_close_in_callback) TEST_DECLARE (fs_event_start_and_close) TEST_DECLARE (fs_event_getpath) TEST_DECLARE (fs_event_stop_in_cb) -TEST_DECLARE (fs_scandir_empty_dir) -TEST_DECLARE (fs_scandir_non_existent_dir) -TEST_DECLARE (fs_scandir_file) -TEST_DECLARE (fs_scandir_early_exit) -TEST_DECLARE (fs_open_dir) -TEST_DECLARE (fs_readdir_empty_dir) -TEST_DECLARE (fs_readdir_file) -TEST_DECLARE (fs_readdir_non_empty_dir) -TEST_DECLARE (fs_readdir_non_existing_dir) +TEST_FS_DECLARE (fs_scandir_empty_dir) +TEST_FS_DECLARE (fs_scandir_non_existent_dir) +TEST_FS_DECLARE (fs_scandir_file) +TEST_FS_DECLARE (fs_scandir_early_exit) +TEST_FS_DECLARE (fs_open_dir) +TEST_FS_DECLARE (fs_readdir_empty_dir) +TEST_FS_DECLARE (fs_readdir_file) +TEST_FS_DECLARE (fs_readdir_non_empty_dir) +TEST_FS_DECLARE (fs_readdir_non_existing_dir) #ifdef _WIN32 -TEST_DECLARE (fs_readdir_symlink) +TEST_FS_DECLARE (fs_readdir_symlink) #endif -TEST_DECLARE (fs_rename_to_existing_file) -TEST_DECLARE (fs_write_multiple_bufs) -TEST_DECLARE (fs_read_write_null_arguments) +TEST_FS_DECLARE (fs_rename_to_existing_file) +TEST_FS_DECLARE (fs_write_multiple_bufs) +TEST_FS_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) -TEST_DECLARE (fs_read_dir) +TEST_FS_DECLARE (fs_write_alotof_bufs) +TEST_FS_DECLARE (fs_write_alotof_bufs_with_offset) +TEST_FS_DECLARE (fs_partial_read) +TEST_FS_DECLARE (fs_partial_write) +TEST_FS_DECLARE (fs_file_pos_after_op_with_offset) +TEST_FS_DECLARE (fs_null_req) +TEST_FS_DECLARE (fs_read_dir) #ifdef _WIN32 -TEST_DECLARE (fs_file_pos_write) -TEST_DECLARE (fs_file_pos_append) -TEST_DECLARE (fs_exclusive_sharing_mode) -TEST_DECLARE (fs_file_flag_no_buffering) -TEST_DECLARE (fs_open_readonly_acl) -TEST_DECLARE (fs_fchmod_archive_readonly) -TEST_DECLARE (fs_invalid_mkdir_name) -TEST_DECLARE (fs_wtf) +TEST_FS_DECLARE (fs_file_pos_write) +TEST_FS_DECLARE (fs_file_pos_append) +TEST_FS_DECLARE (fs_exclusive_sharing_mode) +TEST_FS_DECLARE (fs_file_flag_no_buffering) +TEST_FS_DECLARE (fs_open_readonly_acl) +TEST_FS_DECLARE (fs_fchmod_archive_readonly) +TEST_FS_DECLARE (fs_invalid_mkdir_name) +TEST_FS_DECLARE (fs_wtf) #endif -TEST_DECLARE (fs_get_system_error) +TEST_FS_DECLARE (fs_get_system_error) TEST_DECLARE (strscpy) TEST_DECLARE (strtok) TEST_DECLARE (threadpool_queue_work_simple) @@ -466,7 +470,7 @@ TEST_DECLARE (threadpool_cancel_getaddrinfo) TEST_DECLARE (threadpool_cancel_getnameinfo) TEST_DECLARE (threadpool_cancel_random) TEST_DECLARE (threadpool_cancel_work) -TEST_DECLARE (threadpool_cancel_fs) +TEST_FS_DECLARE (threadpool_cancel_fs) TEST_DECLARE (threadpool_cancel_single) TEST_DECLARE (threadpool_cancel_when_busy) TEST_DECLARE (thread_detach) @@ -517,8 +521,8 @@ TEST_DECLARE (environment_creation) #endif TEST_DECLARE (listen_with_simultaneous_accepts) TEST_DECLARE (listen_no_simultaneous_accepts) -TEST_DECLARE (fs_stat_root) -TEST_DECLARE (fs_stat_no_permission) +TEST_FS_DECLARE (fs_stat_root) +TEST_FS_DECLARE (fs_stat_no_permission) TEST_DECLARE (spawn_with_an_odd_path) TEST_DECLARE (spawn_no_path) TEST_DECLARE (spawn_no_ext) @@ -662,6 +666,7 @@ TASK_LIST_START #endif TEST_ENTRY (tty_file) TEST_ENTRY (tty_pty) + TEST_ENTRY (tty_pty_partial) TEST_ENTRY (stdio_over_pipes) TEST_ENTRY (stdio_emulate_iocp) TEST_ENTRY (ip6_pton) @@ -805,6 +810,8 @@ TASK_LIST_START TEST_ENTRY (udp_send_hang_loop) TEST_ENTRY (udp_send_immediate) TEST_ENTRY (udp_send_unreachable) + TEST_ENTRY (udp_recvmsg_unreachable_error) + TEST_ENTRY (udp_recvmsg_unreachable_error6) TEST_ENTRY (udp_dgram_too_big) TEST_ENTRY (udp_dual_stack) TEST_ENTRY (udp_ipv6_only) @@ -1049,8 +1056,8 @@ TASK_LIST_START # endif TEST_ENTRY (listen_with_simultaneous_accepts) TEST_ENTRY (listen_no_simultaneous_accepts) - TEST_ENTRY (fs_stat_root) - TEST_ENTRY (fs_stat_no_permission) + TEST_FS_ENTRY (fs_stat_root) + TEST_FS_ENTRY (fs_stat_no_permission) TEST_ENTRY (spawn_with_an_odd_path) TEST_ENTRY (spawn_no_path) TEST_ENTRY (spawn_no_ext) @@ -1074,53 +1081,54 @@ TASK_LIST_START TEST_ENTRY (osx_select_many_fds) #endif - TEST_ENTRY (fs_file_noent) - TEST_ENTRY (fs_file_nametoolong) - TEST_ENTRY (fs_file_loop) - TEST_ENTRY (fs_file_async) - TEST_ENTRY (fs_file_sync) - TEST_ENTRY (fs_posix_delete) - TEST_ENTRY (fs_file_write_null_buffer) - TEST_ENTRY (fs_async_dir) - TEST_ENTRY (fs_async_sendfile) - TEST_ENTRY (fs_async_sendfile_nodata) - TEST_ENTRY (fs_mkdtemp) - TEST_ENTRY (fs_mkstemp) - TEST_ENTRY (fs_fstat) - TEST_ENTRY (fs_fstat_stdio) - TEST_ENTRY (fs_fstat_st_dev) - TEST_ENTRY (fs_access) - TEST_ENTRY (fs_chmod) - TEST_ENTRY (fs_copyfile) - TEST_ENTRY (fs_unlink_readonly) + TEST_FS_ENTRY (fs_file_noent) + TEST_FS_ENTRY (fs_file_nametoolong) + TEST_FS_ENTRY (fs_file_loop) + TEST_FS_ENTRY(fs_file_async) + TEST_FS_ENTRY (fs_file_sync) + TEST_FS_ENTRY (fs_posix_delete) + TEST_FS_ENTRY (fs_file_write_null_buffer) + TEST_FS_ENTRY (fs_async_dir) + TEST_FS_ENTRY (fs_async_sendfile) + TEST_FS_ENTRY (fs_async_sendfile_nodata) + TEST_FS_ENTRY (fs_mkdtemp) + TEST_FS_ENTRY (fs_mkstemp) + TEST_FS_ENTRY (fs_fstat) + TEST_FS_ENTRY (fs_fstat_stdio) + TEST_FS_ENTRY (fs_fstat_st_dev) + TEST_FS_ENTRY (fs_access) + TEST_FS_ENTRY (fs_chmod) + TEST_FS_ENTRY (fs_copyfile) + TEST_FS_ENTRY (fs_unlink_readonly) #ifdef _WIN32 - TEST_ENTRY (fs_unlink_archive_readonly) + TEST_FS_ENTRY (fs_unlink_archive_readonly) #endif - TEST_ENTRY (fs_chown) - TEST_ENTRY (fs_link) - TEST_ENTRY (fs_utime) - TEST_ENTRY (fs_utime_round) - TEST_ENTRY (fs_futime) - TEST_ENTRY (fs_lutime) - TEST_ENTRY (fs_readlink) - TEST_ENTRY (fs_realpath) - TEST_ENTRY (fs_symlink) - TEST_ENTRY (fs_symlink_dir) + TEST_FS_ENTRY (fs_chown) + TEST_FS_ENTRY (fs_link) + TEST_FS_ENTRY (fs_utime) + TEST_FS_ENTRY (fs_utime_round) + TEST_FS_ENTRY (fs_futime) + TEST_FS_ENTRY (fs_lutime) + TEST_FS_ENTRY (fs_readlink) + TEST_FS_ENTRY (fs_realpath) + TEST_FS_ENTRY (fs_symlink) + TEST_FS_ENTRY (fs_symlink_dir) #ifdef _WIN32 - TEST_ENTRY (fs_symlink_junction) - TEST_ENTRY (fs_non_symlink_reparse_point) - TEST_ENTRY (fs_lstat_windows_store_apps) - TEST_ENTRY (fs_open_flags) + TEST_FS_ENTRY (fs_symlink_junction) + TEST_FS_ENTRY (fs_non_symlink_reparse_point) + TEST_FS_ENTRY (fs_readlink_lx_symlink) + TEST_FS_ENTRY (fs_lstat_windows_store_apps) + TEST_FS_ENTRY (fs_open_flags) #endif #if defined(_WIN32) && !defined(USING_UV_SHARED) - TEST_ENTRY (fs_fd_hash) + TEST_FS_ENTRY (fs_fd_hash) #endif - TEST_ENTRY (fs_statfs) - TEST_ENTRY (fs_stat_batch_multiple) - TEST_ENTRY (fs_stat_missing_path) - TEST_ENTRY (fs_read_bufs) - TEST_ENTRY (fs_read_file_eof) - TEST_ENTRY (fs_file_open_append) + TEST_FS_ENTRY (fs_statfs) + TEST_FS_ENTRY (fs_stat_batch_multiple) + TEST_FS_ENTRY (fs_stat_missing_path) + TEST_FS_ENTRY (fs_read_bufs) + TEST_FS_ENTRY (fs_read_file_eof) + TEST_FS_ENTRY (fs_file_open_append) TEST_ENTRY (fs_event_watch_dir) TEST_ENTRY (fs_event_watch_delete_dir) TEST_ENTRY (fs_event_watch_dir_recursive) @@ -1144,39 +1152,39 @@ TASK_LIST_START TEST_ENTRY (fs_event_start_and_close) TEST_ENTRY (fs_event_getpath) TEST_ENTRY (fs_event_stop_in_cb) - TEST_ENTRY (fs_scandir_empty_dir) - TEST_ENTRY (fs_scandir_non_existent_dir) - TEST_ENTRY (fs_scandir_file) - TEST_ENTRY (fs_scandir_early_exit) - TEST_ENTRY (fs_open_dir) - TEST_ENTRY (fs_readdir_empty_dir) - TEST_ENTRY (fs_readdir_file) - TEST_ENTRY (fs_readdir_non_empty_dir) - TEST_ENTRY (fs_readdir_non_existing_dir) + TEST_FS_ENTRY (fs_scandir_empty_dir) + TEST_FS_ENTRY (fs_scandir_non_existent_dir) + TEST_FS_ENTRY (fs_scandir_file) + TEST_FS_ENTRY (fs_scandir_early_exit) + TEST_FS_ENTRY (fs_open_dir) + TEST_FS_ENTRY (fs_readdir_empty_dir) + TEST_FS_ENTRY (fs_readdir_file) + TEST_FS_ENTRY (fs_readdir_non_empty_dir) + TEST_FS_ENTRY (fs_readdir_non_existing_dir) #ifdef _WIN32 - TEST_ENTRY (fs_readdir_symlink) + TEST_FS_ENTRY (fs_readdir_symlink) #endif - TEST_ENTRY (fs_rename_to_existing_file) - 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) - TEST_ENTRY (fs_read_dir) + TEST_FS_ENTRY (fs_rename_to_existing_file) + TEST_FS_ENTRY (fs_write_multiple_bufs) + TEST_FS_ENTRY (fs_write_alotof_bufs) + TEST_FS_ENTRY (fs_write_alotof_bufs_with_offset) + TEST_FS_ENTRY (fs_partial_read) + TEST_FS_ENTRY (fs_partial_write) + TEST_FS_ENTRY (fs_read_write_null_arguments) + TEST_FS_ENTRY (fs_file_pos_after_op_with_offset) + TEST_FS_ENTRY (fs_null_req) + TEST_FS_ENTRY (fs_read_dir) #ifdef _WIN32 - TEST_ENTRY (fs_file_pos_write) - TEST_ENTRY (fs_file_pos_append) - TEST_ENTRY (fs_exclusive_sharing_mode) - TEST_ENTRY (fs_file_flag_no_buffering) - TEST_ENTRY (fs_open_readonly_acl) - TEST_ENTRY (fs_fchmod_archive_readonly) - TEST_ENTRY (fs_invalid_mkdir_name) - TEST_ENTRY (fs_wtf) + TEST_FS_ENTRY (fs_file_pos_write) + TEST_FS_ENTRY (fs_file_pos_append) + TEST_FS_ENTRY (fs_exclusive_sharing_mode) + TEST_FS_ENTRY (fs_file_flag_no_buffering) + TEST_FS_ENTRY (fs_open_readonly_acl) + TEST_FS_ENTRY (fs_fchmod_archive_readonly) + TEST_FS_ENTRY (fs_invalid_mkdir_name) + TEST_FS_ENTRY (fs_wtf) #endif - TEST_ENTRY (fs_get_system_error) + TEST_FS_ENTRY (fs_get_system_error) TEST_ENTRY (get_osfhandle_valid_handle) TEST_ENTRY (open_osfhandle_valid_handle) TEST_ENTRY (strscpy) @@ -1188,7 +1196,7 @@ TASK_LIST_START TEST_ENTRY (threadpool_cancel_getnameinfo) TEST_ENTRY (threadpool_cancel_random) TEST_ENTRY (threadpool_cancel_work) - TEST_ENTRY (threadpool_cancel_fs) + TEST_FS_ENTRY (threadpool_cancel_fs) TEST_ENTRY (threadpool_cancel_single) TEST_ENTRY (threadpool_cancel_when_busy) TEST_ENTRY (thread_detach) diff --git a/deps/uv/test/test-poll-oob.c b/deps/uv/test/test-poll-oob.c index b40c93c3708776..4b119d4dd76fdb 100644 --- a/deps/uv/test/test-poll-oob.c +++ b/deps/uv/test/test-poll-oob.c @@ -91,8 +91,8 @@ static void poll_cb(uv_poll_t* handle, int status, int events) { while (n == -1 && errno == EINTR); ASSERT(n >= 0 || errno != EINVAL); if (cli_rd_check == 1) { - ASSERT_OK(strncmp(buffer, "world", n)); ASSERT_EQ(5, n); + ASSERT_OK(strncmp(buffer, "world", n)); cli_rd_check = 2; } if (cli_rd_check == 0) { diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c index 5161de253768d8..e291e7377ffa7a 100644 --- a/deps/uv/test/test-poll.c +++ b/deps/uv/test/test-poll.c @@ -83,9 +83,9 @@ static int closed_connections = 0; static int valid_writable_wakeups = 0; static int spurious_writable_wakeups = 0; -#if !defined(__sun) && !defined(_AIX) && !defined(__MVS__) +#if !defined(__sun) && !defined(_AIX) && !defined(__MVS__) && !defined(__QNX__) static int disconnects = 0; -#endif /* !__sun && !_AIX && !__MVS__ */ +#endif /* !__sun && !_AIX && !__MVS__ && !__QNX__*/ static int got_eagain(void) { #ifdef _WIN32 @@ -409,7 +409,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { new_events &= ~UV_WRITABLE; } } -#if !defined(__sun) && !defined(_AIX) && !defined(__MVS__) +#if !defined(__sun) && !defined(_AIX) && !defined(__MVS__) && !defined(__QNX__) if (events & UV_DISCONNECT) { context->got_disconnect = 1; ++disconnects; @@ -417,9 +417,9 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { } if (context->got_fin && context->sent_fin && context->got_disconnect) { -#else /* __sun && _AIX && __MVS__ */ +#else /* __sun && _AIX && __MVS__ && __QNX__*/ if (context->got_fin && context->sent_fin) { -#endif /* !__sun && !_AIX && !__MVS__ */ +#endif /* !__sun && !_AIX && !__MVS__ && !__QNX__ */ /* Sent and received FIN. Close and destroy context. */ close_socket(context->sock); destroy_connection_context(context); @@ -587,7 +587,7 @@ static void start_poll_test(void) { spurious_writable_wakeups > 20, 0); ASSERT_EQ(closed_connections, NUM_CLIENTS * 2); -#if !defined(__sun) && !defined(_AIX) && !defined(__MVS__) +#if !defined(__sun) && !defined(_AIX) && !defined(__MVS__) && !defined(__QNX__) ASSERT_EQ(disconnects, NUM_CLIENTS * 2); #endif MAKE_VALGRIND_HAPPY(uv_default_loop()); @@ -633,12 +633,12 @@ TEST_IMPL(poll_unidirectional) { * In addition to regular files, we also disallow FIFOs on Darwin. */ #ifdef __APPLE__ -#define TEST_POLL_FIFO_PATH "/tmp/uv-test-poll-fifo" +#define TEST_POLL_FIFO_PATH "uv-test-poll-fifo" #endif TEST_IMPL(poll_bad_fdtype) { #if !defined(__sun) && \ !defined(_AIX) && !defined(__MVS__) && \ - !defined(__CYGWIN__) && !defined(__MSYS__) + !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__QNX__) uv_poll_t poll_handle; int fd[2]; diff --git a/deps/uv/test/test-process-priority.c b/deps/uv/test/test-process-priority.c index 941e4b36391032..5e61ef4c21d433 100644 --- a/deps/uv/test/test-process-priority.c +++ b/deps/uv/test/test-process-priority.c @@ -28,9 +28,9 @@ TEST_IMPL(process_priority) { int r; int i; -#if defined(__MVS__) +#if defined(__MVS__) || defined(__QNX__) if (uv_os_setpriority(0, 0) == UV_ENOSYS) - RETURN_SKIP("functionality not supported on zOS"); + RETURN_SKIP("functionality not supported on zOS and QNX"); #endif /* Verify that passing a NULL pointer returns UV_EINVAL. */ diff --git a/deps/uv/test/test-process-title-threadsafe.c b/deps/uv/test/test-process-title-threadsafe.c index 05baaf44a453ad..212c715a3d73dd 100644 --- a/deps/uv/test/test-process-title-threadsafe.c +++ b/deps/uv/test/test-process-title-threadsafe.c @@ -85,10 +85,18 @@ TEST_IMPL(process_title_threadsafe) { int i; #if defined(__sun) || defined(__CYGWIN__) || defined(__MSYS__) || \ - defined(__MVS__) || defined(__PASE__) + defined(__MVS__) || defined(__PASE__) || defined(__QNX__) RETURN_SKIP("uv_(get|set)_process_title is not implemented."); #endif +#if defined(__ASAN__) && defined(__APPLE__) + /* uv_set_process_title loads and unloads a bunch of dynamic libraries, + * and that's quite slow and prone to time out when running concurrently + * under AddressSanitizer. + */ + RETURN_SKIP("too slow under ASAN"); +#endif + ASSERT_OK(uv_set_process_title(titles[0])); ASSERT_OK(uv_sem_init(&getter_sem, 0)); diff --git a/deps/uv/test/test-process-title.c b/deps/uv/test/test-process-title.c index 7178cf87da4b52..3478033a9fbb17 100644 --- a/deps/uv/test/test-process-title.c +++ b/deps/uv/test/test-process-title.c @@ -61,7 +61,7 @@ static void uv_get_process_title_edge_cases(void) { TEST_IMPL(process_title) { #if defined(__sun) || defined(__CYGWIN__) || defined(__MSYS__) || \ - defined(__PASE__) + defined(__PASE__) || defined(__QNX__) RETURN_SKIP("uv_(get|set)_process_title is not implemented."); #endif diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index 964c8a86c76eb6..eaaa8bbeac3d00 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -1678,7 +1678,10 @@ TEST_IMPL(spawn_fs_open) { #ifdef _WIN32 const char dev_null[] = "NUL"; HMODULE kernelbase_module; - sCompareObjectHandles pCompareObjectHandles; /* function introduced in Windows 10 */ + union { + FARPROC proc; + sCompareObjectHandles pCompareObjectHandles; /* Windows >= 10 */ + } u; #else const char dev_null[] = "/dev/null"; #endif @@ -1701,12 +1704,10 @@ TEST_IMPL(spawn_fs_open) { #ifdef _WIN32 ASSERT_NE(0, DuplicateHandle(GetCurrentProcess(), fd, GetCurrentProcess(), &dup_fd, 0, /* inherit */ TRUE, DUPLICATE_SAME_ACCESS)); - kernelbase_module = GetModuleHandleA("kernelbase.dll"); - pCompareObjectHandles = (sCompareObjectHandles) - GetProcAddress(kernelbase_module, "CompareObjectHandles"); - ASSERT_NE(pCompareObjectHandles == NULL || - pCompareObjectHandles(fd, dup_fd), - 0); + kernelbase_module = GetModuleHandleW(L"kernelbase.dll"); + u.proc = GetProcAddress(kernelbase_module, "CompareObjectHandles"); + if (u.pCompareObjectHandles != NULL) + ASSERT_EQ(TRUE, u.pCompareObjectHandles(fd, dup_fd)); #else dup_fd = dup(fd); #endif diff --git a/deps/uv/test/test-tcp-close-accept.c b/deps/uv/test/test-tcp-close-accept.c index 4988dd132750c1..30e1f1fac98744 100644 --- a/deps/uv/test/test-tcp-close-accept.c +++ b/deps/uv/test/test-tcp-close-accept.c @@ -69,8 +69,8 @@ static void connect_cb(uv_connect_t* req, int status) { } ASSERT_OK(status); - ASSERT_LE(connect_reqs, req); - ASSERT_LE(req, connect_reqs + ARRAY_SIZE(connect_reqs)); + ASSERT_PTR_LE(connect_reqs, req); + ASSERT_PTR_LE(req, connect_reqs + ARRAY_SIZE(connect_reqs)); i = req - connect_reqs; buf = uv_buf_init("x", 1); diff --git a/deps/uv/test/test-tcp-connect-error-after-write.c b/deps/uv/test/test-tcp-connect-error-after-write.c index 7321259628d5e6..3e660bc6b9ded3 100644 --- a/deps/uv/test/test-tcp-connect-error-after-write.c +++ b/deps/uv/test/test-tcp-connect-error-after-write.c @@ -26,6 +26,17 @@ #include #include +#ifdef _WIN32 +/* + * Try to connect to an address on which nothing listens, get ECONNREFUSED + * (uv errno 12) and get connect_cb() called once with status != 0. + * Related issue: https://github.com/joyent/libuv/issues/443 + */ +TEST_IMPL(tcp_connect_error_after_write) { + RETURN_SKIP("This test is disabled on Windows. " + "See https://github.com/joyent/libuv/issues/444\n"); +} +#else /* !_WIN32 */ static int connect_cb_called; static int write_cb_called; static int close_cb_called; @@ -55,11 +66,6 @@ static void write_cb(uv_write_t* req, int status) { * Related issue: https://github.com/joyent/libuv/issues/443 */ TEST_IMPL(tcp_connect_error_after_write) { -#ifdef _WIN32 - RETURN_SKIP("This test is disabled on Windows for now. " - "See https://github.com/joyent/libuv/issues/444\n"); -#else - uv_connect_t connect_req; struct sockaddr_in addr; uv_write_t write_req; @@ -94,5 +100,5 @@ TEST_IMPL(tcp_connect_error_after_write) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; -#endif } +#endif /* !_WIN32 */ diff --git a/deps/uv/test/test-tcp-flags.c b/deps/uv/test/test-tcp-flags.c index 16218a27f0a3a8..04a238b2c4cd49 100644 --- a/deps/uv/test/test-tcp-flags.c +++ b/deps/uv/test/test-tcp-flags.c @@ -49,6 +49,21 @@ TEST_IMPL(tcp_flags) { r = uv_tcp_keepalive(&handle, 1, 0); ASSERT_EQ(r, UV_EINVAL); + r = uv_tcp_keepalive_ex(&handle, 1, 60, 60, 60); + ASSERT_OK(r); + + r = uv_tcp_keepalive_ex(&handle, 0, 0, 0, 0); + ASSERT_OK(r); + + r = uv_tcp_keepalive_ex(&handle, 1, 0, 10, 10); + ASSERT_EQ(r, UV_EINVAL); + + r = uv_tcp_keepalive_ex(&handle, 1, 10, 0, 10); + ASSERT_EQ(r, UV_EINVAL); + + r = uv_tcp_keepalive_ex(&handle, 1, 10, 10, 0); + ASSERT_EQ(r, UV_EINVAL); + uv_close((uv_handle_t*)&handle, NULL); r = uv_run(loop, UV_RUN_DEFAULT); diff --git a/deps/uv/test/test-tcp-reuseport.c b/deps/uv/test/test-tcp-reuseport.c index f108b9bbe0fe75..db77ff222f56da 100644 --- a/deps/uv/test/test-tcp-reuseport.c +++ b/deps/uv/test/test-tcp-reuseport.c @@ -178,6 +178,17 @@ TEST_IMPL(tcp_reuseport) { int r; int i; +#if defined(__QEMU__) + /* QEMU's user-mode emulator sometimes runs threads in sequence + * instead of in parallel and that throws off the test. + * See https://github.com/libuv/libuv/issues/4777. + */ + RETURN_SKIP("Unreliable under QEMU"); +#endif /* defined(__QEMU__) */ + + if (uv_available_parallelism() < 2) + RETURN_SKIP("Unreliable without thread parallelism"); + r = uv_mutex_init(&mutex); ASSERT_OK(r); diff --git a/deps/uv/test/test-tcp-rst.c b/deps/uv/test/test-tcp-rst.c index 7729f03e607d6a..cd4567037d4f37 100644 --- a/deps/uv/test/test-tcp-rst.c +++ b/deps/uv/test/test-tcp-rst.c @@ -22,6 +22,11 @@ #include "uv.h" #include "task.h" +#ifdef _WIN32 +TEST_IMPL(tcp_rst) { + RETURN_SKIP("Unix only test"); +} +#else /* !_WIN32 */ static uv_tcp_t tcp; static uv_connect_t connect_req; static uv_buf_t qbuf; @@ -76,12 +81,12 @@ static void connect_cb(uv_connect_t *req, int status) { * RST. Test checks that uv_guess_handle still works on a reset TCP handle. */ TEST_IMPL(tcp_rst) { + struct sockaddr_in server_addr; + int r; + #if defined(__OpenBSD__) RETURN_SKIP("Test does not currently work in OpenBSD"); #endif -#ifndef _WIN32 - struct sockaddr_in server_addr; - int r; qbuf.base = "QSH"; qbuf.len = 3; @@ -104,7 +109,5 @@ TEST_IMPL(tcp_rst) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; -#else - RETURN_SKIP("Unix only test"); -#endif } +#endif /* !_WIN32 */ diff --git a/deps/uv/test/test-tcp-write-fail.c b/deps/uv/test/test-tcp-write-fail.c index 530329a3ac63c8..c273c61655fe03 100644 --- a/deps/uv/test/test-tcp-write-fail.c +++ b/deps/uv/test/test-tcp-write-fail.c @@ -91,6 +91,7 @@ static void connect_cb(uv_connect_t* req, int status) { TEST_IMPL(tcp_write_fail) { struct sockaddr_in addr; uv_tcp_t client; + uv_buf_t buf; int r; ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); @@ -98,6 +99,20 @@ TEST_IMPL(tcp_write_fail) { r = uv_tcp_init(uv_default_loop(), &client); ASSERT_OK(r); + r = uv_write(&write_req, + (uv_stream_t*) &client, + &buf, + 0, /* Illegal. Worse, senseless. */ + write_cb); + ASSERT_EQ(UV_EINVAL, r); + + r = uv_write(&write_req, + (uv_stream_t*) &client, + &buf, + -42, /* Undergoes sign conversion. */ + write_cb); + ASSERT_EQ(UV_EINVAL, r); + r = uv_tcp_connect(&connect_req, &client, (const struct sockaddr*) &addr, diff --git a/deps/uv/test/test-tcp-write-in-a-row.c b/deps/uv/test/test-tcp-write-in-a-row.c index 5c17ed496138e1..39762925cca3b4 100644 --- a/deps/uv/test/test-tcp-write-in-a-row.c +++ b/deps/uv/test/test-tcp-write-in-a-row.c @@ -112,13 +112,14 @@ static void start_server(void) { } TEST_IMPL(tcp_write_in_a_row) { + uv_connect_t connect_req; + struct sockaddr_in addr; + #if defined(_WIN32) RETURN_SKIP("tcp_write_in_a_row does not work on Windows"); #elif defined(__PASE__) RETURN_SKIP("tcp_write_in_a_row does not work on IBM i PASE"); -#else - uv_connect_t connect_req; - struct sockaddr_in addr; +#endif start_server(); @@ -139,5 +140,4 @@ TEST_IMPL(tcp_write_in_a_row) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; -#endif } diff --git a/deps/uv/test/test-thread-priority.c b/deps/uv/test/test-thread-priority.c index 0aaf297722b118..acc33855130468 100644 --- a/deps/uv/test/test-thread-priority.c +++ b/deps/uv/test/test-thread-priority.c @@ -88,8 +88,6 @@ TEST_IMPL(thread_priority) { * test set nice value for the calling thread with default schedule policy */ #ifdef __linux__ - ASSERT_OK(uv_thread_getpriority(pthread_self(), &priority)); - ASSERT_EQ(priority, 0); ASSERT_OK(uv_thread_setpriority(pthread_self(), UV_THREAD_PRIORITY_LOWEST)); ASSERT_OK(uv_thread_getpriority(pthread_self(), &priority)); ASSERT_EQ(priority, (0 - UV_THREAD_PRIORITY_LOWEST * 2)); @@ -101,5 +99,11 @@ TEST_IMPL(thread_priority) { uv_sem_destroy(&sem); + /* Now that the thread no longer exists, verify that the relevant error is returned */ +#if !defined(__ANDROID__) + ASSERT_EQ(UV_ESRCH, uv_thread_getpriority(task_id, &priority)); + ASSERT_EQ(UV_ESRCH, uv_thread_setpriority(task_id, UV_THREAD_PRIORITY_LOWEST)); +#endif + return 0; -} \ No newline at end of file +} diff --git a/deps/uv/test/test-threadpool-cancel.c b/deps/uv/test/test-threadpool-cancel.c index 544fbbc348a159..c5e6e9aa384cc5 100644 --- a/deps/uv/test/test-threadpool-cancel.c +++ b/deps/uv/test/test-threadpool-cancel.c @@ -21,6 +21,7 @@ #include "uv.h" #include "task.h" +#include #ifdef _WIN32 # define putenv _putenv @@ -102,6 +103,7 @@ static int known_broken(uv_req_t* req) { case UV_FS_FDATASYNC: case UV_FS_FSTAT: case UV_FS_FSYNC: + case UV_FS_FTRUNCATE: case UV_FS_LINK: case UV_FS_LSTAT: case UV_FS_MKDIR: @@ -217,6 +219,7 @@ TEST_IMPL(threadpool_cancel_getaddrinfo) { r = uv_getaddrinfo(loop, reqs + 2, getaddrinfo_cb, "fail", "fail", NULL); ASSERT_OK(r); + memset(&hints, 0, sizeof(hints)); r = uv_getaddrinfo(loop, reqs + 3, getaddrinfo_cb, "fail", NULL, &hints); ASSERT_OK(r); @@ -313,7 +316,7 @@ TEST_IMPL(threadpool_cancel_work) { } -TEST_IMPL(threadpool_cancel_fs) { +TEST_FS_IMPL(threadpool_cancel_fs) { struct cancel_info ci; uv_fs_t reqs[26]; uv_loop_t* loop; diff --git a/deps/uv/test/test-tty.c b/deps/uv/test/test-tty.c index 1b11303829a137..9ecb3ae52ae5d3 100644 --- a/deps/uv/test/test-tty.c +++ b/deps/uv/test/test-tty.c @@ -421,10 +421,6 @@ TEST_IMPL(tty_pty) { #if defined(__QEMU__) RETURN_SKIP("Test does not currently work in QEMU"); #endif -#if defined(__ASAN__) - RETURN_SKIP("Test does not currently work in ASAN"); -#endif - #if defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ @@ -432,16 +428,14 @@ TEST_IMPL(tty_pty) { defined(__NetBSD__) || \ defined(__OpenBSD__) int master_fd, slave_fd, r; - struct winsize w; uv_loop_t loop; uv_tty_t master_tty, slave_tty; - ASSERT_OK(uv_loop_init(&loop)); - - r = openpty(&master_fd, &slave_fd, NULL, NULL, &w); + r = openpty(&master_fd, &slave_fd, NULL, NULL, NULL); if (r != 0) RETURN_SKIP("No pty available, skipping."); + ASSERT_OK(uv_loop_init(&loop)); ASSERT_OK(uv_tty_init(&loop, &slave_tty, slave_fd, 0)); ASSERT_OK(uv_tty_init(&loop, &master_tty, master_fd, 0)); ASSERT(uv_is_readable((uv_stream_t*) &slave_tty)); @@ -466,3 +460,79 @@ TEST_IMPL(tty_pty) { #endif return 0; } + +#if !defined(__ANDROID__) && !defined(_WIN32) +static int tty_pty_partial_read_count; + +static void tty_pty_partial_feeder(void *arg) { + static char buf[1<<13]; + ssize_t n; + ssize_t r; + int fd; + int i; + + fd = *(int *)arg; + memset(buf, 'x', sizeof(buf)); + for (i = 0; i < 8; i++) { + for (n = 0; n < (int) sizeof(buf); n += r) { + do + r = write(fd, &buf[n], sizeof(buf) - n); + while (r == -1 && errno == EINTR); + ASSERT_GT(r, 0); + } + } + ASSERT_OK(close(fd)); +} + +static void tty_pty_partial_alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t *buf) { + static char slab[1<<16]; + *buf = uv_buf_init(slab, sizeof(slab)); +} + +static void tty_pty_partial_read_cb(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t *buf) { + if (nread > 0) + tty_pty_partial_read_count += nread; + else + uv_close((uv_handle_t*) stream, NULL); +} +#endif /* !defined(__ANDROID__) && !defined(_WIN32) */ + +TEST_IMPL(tty_pty_partial) { +#if !defined(_AIX) && \ + !defined(__ANDROID__) && \ + !defined(__MVS__) && \ + !defined(_WIN32) + int master_fd, slave_fd; + uv_tty_t master_tty; + uv_thread_t tid; + uv_loop_t loop; + int i; + + /* This test is not 100% deterministic. If the bug it is testing for is + * present, then it fails about 1 in 3 times, that's why it runs in a loop. + */ + for (i = 0; i < 10; i++) { + if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL)) + RETURN_SKIP("No pty available, skipping."); + + tty_pty_partial_read_count = 0; + ASSERT_OK(uv_loop_init(&loop)); + ASSERT_OK(uv_tty_init(&loop, &master_tty, master_fd, 0)); + ASSERT_OK(uv_read_start((uv_stream_t*) &master_tty, + tty_pty_partial_alloc_cb, + tty_pty_partial_read_cb)); + ASSERT(uv_is_readable((uv_stream_t*) &master_tty)); + ASSERT(uv_is_writable((uv_stream_t*) &master_tty)); + ASSERT_OK(uv_thread_create(&tid, tty_pty_partial_feeder, &slave_fd)); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_thread_join(&tid)); + ASSERT_EQ(tty_pty_partial_read_count, 65536); + MAKE_VALGRIND_HAPPY(&loop); + } +#endif + return 0; +} diff --git a/deps/uv/test/test-udp-ipv6.c b/deps/uv/test/test-udp-ipv6.c index 8ad80b9b5a9b6d..e21ad0aa5bd834 100644 --- a/deps/uv/test/test-udp-ipv6.c +++ b/deps/uv/test/test-udp-ipv6.c @@ -26,7 +26,7 @@ #include #include -#if defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__QNX__) #include #endif @@ -49,7 +49,7 @@ static int recv_cb_called; static int close_cb_called; static uint16_t client_port; -#if defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__QNX__) static int can_ipv6_ipv4_dual(void) { int v6only; size_t size = sizeof(int); @@ -228,7 +228,7 @@ TEST_IMPL(udp_dual_stack) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); -#if defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__QNX__) if (!can_ipv6_ipv4_dual()) RETURN_SKIP("IPv6-IPv4 dual stack not supported"); #elif defined(__OpenBSD__) diff --git a/deps/uv/test/test-udp-multicast-join.c b/deps/uv/test/test-udp-multicast-join.c index 58b055561c6ded..548bf7414cfa4f 100644 --- a/deps/uv/test/test-udp-multicast-join.c +++ b/deps/uv/test/test-udp-multicast-join.c @@ -144,8 +144,8 @@ static void cl_recv_cb(uv_udp_t* handle, TEST_IMPL(udp_multicast_join) { -#if defined(__OpenBSD__) - RETURN_SKIP("Test does not currently work in OpenBSD"); +#if defined(__OpenBSD__) || defined(QNX_IOPKT) + RETURN_SKIP("Test does not currently work in OpenBSD or QNX"); #endif int r; struct sockaddr_in addr; @@ -168,6 +168,8 @@ TEST_IMPL(udp_multicast_join) { RETURN_SKIP("No multicast support."); if (r == UV_ENOEXEC) RETURN_SKIP("No multicast support (likely a firewall issue)."); + if (r == UV_ENOSYS) + RETURN_SKIP("No multicast support (likely a platform issue)."); ASSERT_OK(r); #if defined(__ANDROID__) /* It returns an ENOSYS error */ diff --git a/deps/uv/test/test-udp-multicast-join6.c b/deps/uv/test/test-udp-multicast-join6.c index 430e4e3321e859..c7d624318e53f9 100644 --- a/deps/uv/test/test-udp-multicast-join6.c +++ b/deps/uv/test/test-udp-multicast-join6.c @@ -35,7 +35,8 @@ defined(__MVS__) || \ defined(__FreeBSD__) || \ defined(__NetBSD__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || \ + defined(__QNX__) #define MULTICAST_ADDR "ff02::1%lo0" #define INTERFACE_ADDR "::1%lo0" #else @@ -167,6 +168,9 @@ static int can_ipv6_external(void) { TEST_IMPL(udp_multicast_join6) { +#if defined(QNX_IOPKT) + RETURN_SKIP("Test does not currently work in QNX"); +#endif int r; struct sockaddr_in6 addr; diff --git a/deps/uv/test/test-udp-recvmsg-unreachable-error.c b/deps/uv/test/test-udp-recvmsg-unreachable-error.c new file mode 100644 index 00000000000000..48990cc6d48681 --- /dev/null +++ b/deps/uv/test/test-udp-recvmsg-unreachable-error.c @@ -0,0 +1,125 @@ +/* Copyright libuv project and 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" + +#include +#include + +#define CLIENT_TEST_PORT 9123 +#define SERVER_TEST_PORT 9124 +#define RECV_CB_MAX_CALL 3 /* ECONNREFUSED, EAGAIN/EWOULDBLOCK, ICMP delivery */ + +static int recv_cb_called = 0; + +static void udp_send_cb(uv_udp_send_t* req, int status) { + ASSERT_EQ(status, 0); +} + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char storage[4]; /* "PING" */ + buf->base = storage; + buf->len = sizeof(storage); +} + +static void read_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + ASSERT(flags == 0 || (flags & UV_UDP_LINUX_RECVERR)); + recv_cb_called++; +} + +static void timer_cb(uv_timer_t* handle) { + uv_udp_t* udp = handle->data; + uv_close((uv_handle_t*) udp, NULL); +} + +TEST_IMPL(udp_recvmsg_unreachable_error) { +#if !defined(__linux__) + RETURN_SKIP("This test is Linux-specific"); +#endif + struct sockaddr_in server_addr, client_addr; + uv_udp_t client; + uv_timer_t timer; + uv_udp_send_t send_req; + uv_buf_t buf = uv_buf_init("PING", 4); + ASSERT_OK(uv_ip4_addr("127.0.0.1", CLIENT_TEST_PORT, &client_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", SERVER_TEST_PORT, &server_addr)); + ASSERT_OK(uv_udp_init(uv_default_loop(), &client)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer)); + ASSERT_OK(uv_udp_bind(&client, + (const struct sockaddr*) &client_addr, + UV_UDP_LINUX_RECVERR)); + ASSERT_OK(uv_udp_recv_start(&client, alloc_cb, read_cb)); + timer.data = &client; + ASSERT_OK(uv_timer_start(&timer, timer_cb, 3000, 0)); + ASSERT_OK(uv_udp_send(&send_req, + &client, + &buf, + 1, + (const struct sockaddr*) &server_addr, + udp_send_cb)); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT_EQ(recv_cb_called, RECV_CB_MAX_CALL); + return 0; +} + +TEST_IMPL(udp_recvmsg_unreachable_error6) { +#if !defined(__linux__) + RETURN_SKIP("This test is Linux-specific"); +#endif + struct sockaddr_in6 server_addr, client_addr; + uv_udp_t client; + uv_timer_t timer; + uv_udp_send_t send_req; + uv_buf_t buf = uv_buf_init("PING", 4); + + ASSERT_OK(uv_ip6_addr("::1", CLIENT_TEST_PORT, &client_addr)); + ASSERT_OK(uv_ip6_addr("::1", SERVER_TEST_PORT, &server_addr)); + + ASSERT_OK(uv_udp_init(uv_default_loop(), &client)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer)); + + ASSERT_OK(uv_udp_bind(&client, + (const struct sockaddr*) &client_addr, + UV_UDP_LINUX_RECVERR)); + ASSERT_OK(uv_udp_recv_start(&client, alloc_cb, read_cb)); + + timer.data = &client; + ASSERT_OK(uv_timer_start(&timer, timer_cb, 3000, 0)); + + ASSERT_OK(uv_udp_send(&send_req, + &client, + &buf, + 1, + (const struct sockaddr*) &server_addr, + udp_send_cb)); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT_EQ(recv_cb_called, RECV_CB_MAX_CALL); + return 0; +} diff --git a/deps/uv/test/test-udp-reuseport.c b/deps/uv/test/test-udp-reuseport.c index 7d4db40806f628..5d0f949654b4e1 100644 --- a/deps/uv/test/test-udp-reuseport.c +++ b/deps/uv/test/test-udp-reuseport.c @@ -215,6 +215,17 @@ TEST_IMPL(udp_reuseport) { int r; int i; +#if defined(__QEMU__) + /* QEMU's user-mode emulator sometimes runs threads in sequence + * instead of in parallel and that throws off the test. + * See https://github.com/libuv/libuv/issues/4777. + */ + RETURN_SKIP("Unreliable under QEMU"); +#endif /* defined(__QEMU__) */ + + if (uv_available_parallelism() < 2) + RETURN_SKIP("Unreliable without thread parallelism"); + r = uv_mutex_init(&mutex); ASSERT_OK(r); diff --git a/deps/uv/test/test-udp-send-unreachable.c b/deps/uv/test/test-udp-send-unreachable.c index 0a2f4a47a97580..a480206e0984be 100644 --- a/deps/uv/test/test-udp-send-unreachable.c +++ b/deps/uv/test/test-udp-send-unreachable.c @@ -83,7 +83,10 @@ static void recv_cb(uv_udp_t* handle, recv_cb_called++; if (nread < 0) { - ASSERT(0 && "unexpected error"); + if (flags && can_recverr) + ASSERT(flags & UV_UDP_LINUX_RECVERR); + else + ASSERT(0 && "unexpected error"); } else if (nread == 0) { /* Returning unused buffer */ ASSERT_NULL(addr);