diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap index 97f5d1f2c004c9..f5d5375e044e18 100644 --- a/deps/uv/.mailmap +++ b/deps/uv/.mailmap @@ -52,6 +52,7 @@ San-Tai Hsu Santiago Gimeno Saúl Ibarra Corretgé Saúl Ibarra Corretgé +Saúl Ibarra Corretgé Shigeki Ohtsu Shuowang (Wayne) Zhang TK-one diff --git a/deps/uv/.readthedocs.yaml b/deps/uv/.readthedocs.yaml index b16bf0d4ab754b..5290ec33e89899 100644 --- a/deps/uv/.readthedocs.yaml +++ b/deps/uv/.readthedocs.yaml @@ -2,7 +2,7 @@ version: 2 sphinx: builder: html - configuration: null + configuration: docs/src/conf.py fail_on_warning: false build: diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 041b7aff610f57..89a3d9db05c877 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -588,5 +588,19 @@ Raihaan Shouhell Rialbat Adam Poul T Lomholt -dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Thad House +Julian A Avar C <28635807+julian-a-avar-c@users.noreply.github.com> +amcgoogan <105525867+amcgoogan@users.noreply.github.com> +Rafael Gonzaga +Morten Engelhardt Olsen +Andrey +Julio Jordán +Jinho Jang +Velikiy Kirill +rainlow <37818892+rainlow@users.noreply.github.com> +Paolo Insogna +Robert Nagy +mugitya03 +Itay Bookstein +crupest +AE1020 <68134252+AE1020@users.noreply.github.com> diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt index 28c6df25666967..73d5aff8926ed5 100644 --- a/deps/uv/CMakeLists.txt +++ b/deps/uv/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.9) +cmake_minimum_required(VERSION 3.10) if(POLICY CMP0091) cmake_policy(SET CMP0091 NEW) # Enable MSVC_RUNTIME_LIBRARY setting @@ -20,7 +20,7 @@ include(CTest) set(CMAKE_C_VISIBILITY_PRESET hidden) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) -set(CMAKE_C_STANDARD 90) +set(CMAKE_C_STANDARD 11) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -186,7 +186,7 @@ set(uv_sources src/version.c) if(WIN32) - list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602 _CRT_DECLARE_NONSTDC_NAMES=0) + list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00 _CRT_DECLARE_NONSTDC_NAMES=0) list(APPEND uv_libraries psapi user32 @@ -434,6 +434,7 @@ endif() if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|Linux|NetBSD|OpenBSD") list(APPEND uv_test_libraries util) + list(APPEND uv_libraries m) endif() if(CYGWIN OR MSYS) @@ -583,6 +584,7 @@ if(LIBUV_BUILD_TESTS) test/test-loop-close.c test/test-loop-configure.c test/test-loop-handles.c + test/test-loop-oom.c test/test-loop-stop.c test/test-loop-time.c test/test-metrics.c @@ -667,6 +669,7 @@ if(LIBUV_BUILD_TESTS) test/test-thread-affinity.c test/test-thread-equal.c test/test-thread.c + test/test-thread-name.c test/test-thread-priority.c test/test-threadpool-cancel.c test/test-threadpool.c diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index dc2dd2790c57d3..787963715772d0 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,4 +1,175 @@ -2024.10.18, Version 1.49.2 (Stable) +2025.04.25, Version 1.51.0 (Stable) + +Changes since version 1.50.0: + +* win: fix leak in uv_os_tmpdir (Saúl Ibarra Corretgé) + +* docs: fix RTD build (Saúl Ibarra Corretgé) + +* win: lazy-load [GS]etThreadDescription symbols (Ben Noordhuis) + +* linux: try preadv64/pwritev64 before preadv/pwritev (Ben Noordhuis) + +* win: check cwd length before spawning a child process (Morten Engelhardt + Olsen) + +* macos,bsd: handle missing /dev/null in chroot env (Andrey) + +* doc: fix README link text (Julio Jordán) + +* win: fix order of FILE_STAT_BASIC_INFORMATION struct fields (Hüseyin Açacak) + +* macos: increase child process stdio buffer size (Jinho Jang) + +* doc: add C3 bindings to LINKS.md (Velikiy Kirill) + +* unix: remove unnecessary errno.h include in poll.c (Juan José Arboleda) + +* win: fix the inconsistency in volume serial number (Hüseyin Açacak) + +* unix: add thread affinity support on openharmony (rainlow) + +* unix: enable getrusage for SunOS (Paolo Insogna) + +* unix,win: accept NAN/INFINITY as file timestamps (Ben Noordhuis) + +* win: add ENABLE_VIRTUAL_TERMINAL_INPUT raw tty mode (Anna Henningsen) + +* test: handle UV_ENOTSUP in platform_output (cjihrig) + +* doc: fix rendering of threading.html (Tobias Nießen) + +* unix,sunos: enable use of sendmmsg on Solaris and Illumos (Stacey Marshall) + +* unix: handle out of memory in iface name copy (Ben Noordhuis) + +* openbsd: do not error out if cpuspeed is not available (Robert Nagy) + +* test: skip thread_name_threadpool on AIX/IBMi (Abdirahim Musse) + +* aix,ibmi: fix undeclared identifiers (Richard Lau) + +* unix,sunos: prefer SO_REUSEPORT for load balancing (Stacey Marshall) + +* doc: free lib pointer before function return (mugitya03) + +* test: link with libm (Juan José Arboleda) + +* style: rename parameter to match definition (Mohammed Keyvanzadeh) + +* test: support partial output lines in test runner (cjihrig) + +* build: switch from c90 to c11 (Ben Noordhuis) + +* linux: allow nul bytes in abstract socket address (Itay Bookstein) + +* sunos: use pipe2 on solaris and illumos (Andy Pan) + +* unix: remove TOCTOU issues from uv_pipe_chmod (Ben Noordhuis) + +* unix: use pipe_fname if getsockname returns nothing (crupest) + +* haiku: use uint32 instead of uint32_t (AE1020) + +* doc: update thread pool stack size comment (Ben Noordhuis) + +* unix: improve uv_loop_init OOM handling (Ben Noordhuis) + +* test: merge uv_tcp_connect callbacks (Juan José Arboleda) + +* test: skip multievent tests on macOS with TSAN enabled (Juan José Arboleda) + +* linux: align CPU quota calculation with Rust (Juan José Arboleda) + +* kqueue: improve fs event watcher OOM handling (Juan José Arboleda) + +* sunos: improve fs event watcher OOM handling (Juan José Arboleda) + +* build: shorten instructions for cmake build (Juan José Arboleda) + + +2025.01.15, Version 1.50.0 (Stable), 8fb9cb919489a48880680a56efecff6a7dfb4504 + +Changes since version 1.49.2: + +* ci: run macOS and iOS tests also on macOS 14 (Saúl Ibarra Corretgé) + +* unix,win: map ENOEXEC errno (Saúl Ibarra Corretgé) + +* test: skip multicast join test on ENOEXEC (Saúl Ibarra Corretgé) + +* ci: make sure the macOS firewall is disabled (Saúl Ibarra Corretgé) + +* darwin,test: squelch EBUSY error on multicast join (Saúl Ibarra Corretgé) + +* build: update minimum cmake to 3.10 (Ben Noordhuis) + +* kqueue: use EVFILT_USER for async if available (Jameson Nash) + +* unix,win: fix off-by-one in uv_wtf8_to_utf16() (Ben Noordhuis) + +* doc: add scala-native-loop to LINKS.md (Julian A Avar C) + +* unix: fix build breakage on haiku, openbsd, etc (Jeffrey H. Johnson) + +* kqueue: lower overhead in uv__io_check_fd (Andy Pan) + +* doc: move cjihrig back to active maintainers (cjihrig) + +* build(deps): bump actions/checkout from 3 to 4 (dependabot[bot]) + +* unix,pipe: fix handling null buffer in uv_pipe_get{sock,peer}name (Saúl + Ibarra Corretgé) + +* unix,win: harmonize buffer checking (Saúl Ibarra Corretgé) + +* unix,win: add support for detached threads (Juan José Arboleda) + +* src: add uv_thread_set/getname() methods (Santiago Gimeno) + +* build: fix qemu builds (Ben Noordhuis) + +* win: drop support for windows 8 (Ben Noordhuis) + +* linux: fix uv_cpu_info() arm cpu model detection (Ben Noordhuis) + +* linux: always use io_uring for epoll batching (Ben Noordhuis) + +* doc: clarify repeating timer behavior more (Ben Noordhuis) + +* unix,win: handle nbufs=0 in uv_udp_try_send (Ben Noordhuis) + +* win: use GetQueuedCompletionStatusEx directly (Saúl Ibarra Corretgé) + +* win: enable uv_thread_{get,set}name on MinGW (Saúl Ibarra Corretgé) + +* win: drop support for the legacy MinGW (Saúl Ibarra Corretgé) + +* win,fs: get (most) fstat when no permission (Jameson Nash) + +* win: plug uv_fs_event_start memory leak (amcgoogan) + +* test: address FreeBSD kernel bug causing NULL path in fsevents (Juan José + Arboleda) + +* unix: refactor udp sendmsg code (Ben Noordhuis) + +* unix,win: add uv_udp_try_send2 (Ben Noordhuis) + +* test: fix flaky flaky udp_mmsg test (Juan José Arboleda) + +* build: enable fdsan in Android (Juan José Arboleda) + +* test: fix udp-multicast-join for FreeBSD (Juan José Arboleda) + +* win: fix leak processing fs event (Saúl Ibarra Corretgé) + +* src: set a default thread name for workers (Rafael Gonzaga) + +* misc: implement uv_getrusage_thread (Juan José Arboleda) + + +2024.10.18, Version 1.49.2 (Stable), e1095c7a4373ce00cd8874d8e820de5afb25776e Changes since version 1.49.1: diff --git a/deps/uv/LINKS.md b/deps/uv/LINKS.md index 3e5800747bc7dd..9f286ea3e9201f 100644 --- a/deps/uv/LINKS.md +++ b/deps/uv/LINKS.md @@ -37,6 +37,7 @@ * [Pixie-io](https://github.com/pixie-io/pixie): Open-source observability tool for Kubernetes applications. * [potion](https://github.com/perl11/potion)/[p2](https://github.com/perl11/p2): runtime * [racer](https://libraries.io/rubygems/racer): Ruby web server written as an C extension +* [scala-native-loop](https://github.com/scala-native/scala-native-loop): Extensible event loop and async-oriented IO for Scala Native; powered by libuv * [Socket Runtime](https://sockets.sh): A runtime for creating native cross-platform software on mobile and desktop using HTML, CSS, and JavaScript * [spider-gazelle](https://github.com/cotag/spider-gazelle): Ruby web server using libuv bindings * [Suave](http://suave.io/): A simple web development F# library providing a lightweight web server and a set of combinators to manipulate route flow and task composition @@ -107,3 +108,5 @@ * [node.pas](https://github.com/vovach777/node.pas) NodeJS-like ecosystem * Haskell * [Z.Haskell](https://z.haskell.world) +* C3 + * [libuv.c3l](https://github.com/velikoss/libuv.c3l) diff --git a/deps/uv/MAINTAINERS.md b/deps/uv/MAINTAINERS.md index 41c60cb383cfbe..ff8be88b7b7cd5 100644 --- a/deps/uv/MAINTAINERS.md +++ b/deps/uv/MAINTAINERS.md @@ -4,6 +4,9 @@ libuv is currently managed by the following individuals: * **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis)) - GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis) +* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) + - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) + - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) * **Jameson Nash** ([@vtjnash](https://github.com/vtjnash)) - GPG key: AEAD 0A4B 6867 6775 1A0E 4AEF 34A2 5FB1 2824 6514 (pubkey-vtjnash) - GPG key: CFBB 9CA9 A5BE AFD7 0E2B 3C5A 79A6 7C55 A367 9C8B (pubkey2022-vtjnash) @@ -24,9 +27,6 @@ libuv is currently managed by the following individuals: * **Anna Henningsen** ([@addaleax](https://github.com/addaleax)) * **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz)) * **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus)) -* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) - - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) - - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) * **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq)) diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index f85a41316c8a43..f3808b696ce3db 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -59,7 +59,7 @@ if WINNT uvinclude_HEADERS += include/uv/win.h include/uv/tree.h AM_CPPFLAGS += -I$(top_srcdir)/src/win \ -DWIN32_LEAN_AND_MEAN \ - -D_WIN32_WINNT=0x0602 + -D_WIN32_WINNT=0x0A00 libuv_la_SOURCES += src/win/async.c \ src/win/atomicops-inl.h \ src/win/core.c \ @@ -206,12 +206,13 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-ipc-send-recv.c \ test/test-ipc.c \ test/test-list.h \ - test/test-loop-handles.c \ test/test-loop-alive.c \ test/test-loop-close.c \ + test/test-loop-configure.c \ + test/test-loop-handles.c \ + test/test-loop-oom.c \ test/test-loop-stop.c \ test/test-loop-time.c \ - test/test-loop-configure.c \ test/test-metrics.c \ test/test-multiple-listen.c \ test/test-mutexes.c \ @@ -294,6 +295,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-thread-equal.c \ test/test-thread.c \ test/test-thread-affinity.c \ + test/test-thread-name.c \ test/test-thread-priority.c \ test/test-threadpool-cancel.c \ test/test-threadpool.c \ diff --git a/deps/uv/README.md b/deps/uv/README.md index 12c3061a894c56..7cc9d2dd53c27c 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -189,9 +189,7 @@ $ make install To build with [CMake][]: ```bash -$ mkdir -p build - -$ (cd build && cmake .. -DBUILD_TESTING=ON) # generate project with tests +$ cmake -B build -DBUILD_TESTING=ON # generate project with tests $ cmake --build build # add `-j ` with cmake >= 3.12 # Run tests: diff --git a/deps/uv/SUPPORTED_PLATFORMS.md b/deps/uv/SUPPORTED_PLATFORMS.md index 8a435d2592e47f..c560aa1086b981 100644 --- a/deps/uv/SUPPORTED_PLATFORMS.md +++ b/deps/uv/SUPPORTED_PLATFORMS.md @@ -4,14 +4,14 @@ |---|---|---|---| | GNU/Linux | Tier 1 | Linux >= 3.10 with glibc >= 2.17 | | | macOS | Tier 1 | macOS >= 11 | Currently supported macOS releases | -| Windows | Tier 1 | >= Windows 8 | VS 2015 and later are supported | +| Windows | Tier 1 | >= Windows 10 | VS 2017 and later are supported | | FreeBSD | Tier 2 | >= 12 | | | AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | | IBM i | Tier 2 | >= IBM i 7.2 | Maintainers: @libuv/ibmi | | z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | | Linux with musl | Tier 2 | musl >= 1.0 | | | Android | Tier 3 | NDK >= r15b | Android 7.0, `-DANDROID_PLATFORM=android-24` | -| MinGW | Tier 3 | MinGW32 and MinGW-w64 | | +| MinGW | Tier 3 | MinGW-w64 | | | SunOS | Tier 3 | Solaris 121 and later | | | Other | Tier 3 | N/A | | diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 98c59363026f86..a4b03b8f5075ee 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.49.2], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.51.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]) @@ -33,7 +33,7 @@ CC_ATTRIBUTE_VISIBILITY([default], [ # we exclude -fno-strict-aliasing for xlc CC_CHECK_FLAG_SUPPORTED_APPEND([-fno-strict-aliasing]) CC_CHECK_CFLAGS_APPEND([-g]) -CC_CHECK_CFLAGS_APPEND([-std=gnu89]) +CC_CHECK_CFLAGS_APPEND([-std=gnu11]) CC_CHECK_CFLAGS_APPEND([-Wall]) CC_CHECK_CFLAGS_APPEND([-Wextra]) CC_CHECK_CFLAGS_APPEND([-Wno-long-long]) diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index 7bc8d0cbfd165d..01a48e8edd85d8 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -430,6 +430,12 @@ API Equivalent to :man:`utime(2)`, :man:`futimes(3)` and :man:`lutimes(3)` respectively. + Passing `UV_FS_UTIME_NOW` as the atime or mtime sets the timestamp to the + current time. + + Passing `UV_FS_UTIME_OMIT` as the atime or mtime leaves the timestamp + untouched. + .. note:: z/OS: `uv_fs_lutime()` is not implemented for z/OS. It can still be called but will return ``UV_ENOSYS``. diff --git a/deps/uv/docs/src/fs_event.rst b/deps/uv/docs/src/fs_event.rst index 983db1a9d5608a..bfdecdd7329cd2 100644 --- a/deps/uv/docs/src/fs_event.rst +++ b/deps/uv/docs/src/fs_event.rst @@ -47,6 +47,11 @@ Data types The `events` parameter is an ORed mask of :c:enum:`uv_fs_event` elements. +.. note:: + For FreeBSD path could sometimes be `NULL` due to a kernel bug. + + .. _Reference: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=197695 + .. c:enum:: uv_fs_event Event types that :c:type:`uv_fs_event_t` handles monitor. diff --git a/deps/uv/docs/src/index.rst b/deps/uv/docs/src/index.rst index 5bdb4be84b6ea1..448de4066d66f7 100644 --- a/deps/uv/docs/src/index.rst +++ b/deps/uv/docs/src/index.rst @@ -58,5 +58,5 @@ libuv can be downloaded from `here `_. Installation ------------ -Installation instructions can be found in `the README `_. +Installation instructions can be found in the `README `_. diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index 61883b7e21e527..db95e2dde83ea1 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -360,6 +360,17 @@ API On Windows not all fields are set, the unsupported fields are filled with zeroes. See :c:type:`uv_rusage_t` for more details. +.. c:function:: int uv_getrusage_thread(uv_rusage_t* rusage) + + Gets the resource usage measures for the calling thread. + + .. versionadded:: 1.50.0 + + .. note:: + Not supported on all platforms. May return `UV_ENOTSUP`. + On macOS and Windows not all fields are set, the unsupported fields are filled with zeroes. + See :c:type:`uv_rusage_t` for more details. + .. c:function:: uv_pid_t uv_os_getpid(void) Returns the current process ID. diff --git a/deps/uv/docs/src/threading.rst b/deps/uv/docs/src/threading.rst index 883218fa829ccb..27c1d6ee28a44d 100644 --- a/deps/uv/docs/src/threading.rst +++ b/deps/uv/docs/src/threading.rst @@ -78,6 +78,14 @@ Threads .. versionchanged:: 1.4.1 returns a UV_E* error code on failure +.. c:function:: int uv_thread_detach(uv_thread_t* tid) + + Detaches a thread. Detached threads automatically release their + resources upon termination, eliminating the need for the application to + call `uv_thread_join`. + + .. versionadded:: 1.50.0 + .. c:function:: int uv_thread_create_ex(uv_thread_t* tid, const uv_thread_options_t* params, uv_thread_cb entry, void* arg) Like :c:func:`uv_thread_create`, but additionally specifies options for creating a new thread. @@ -132,7 +140,29 @@ Threads .. c:function:: int uv_thread_join(uv_thread_t *tid) .. c:function:: int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) +.. c:function:: int uv_thread_setname(const char* name) + + Sets the name of the current thread. Different platforms define different limits on the max number of characters + a thread name can be: Linux, IBM i (16), macOS (64), Windows (32767), and NetBSD (32), etc. `uv_thread_setname()` + will truncate it in case `name` is larger than the limit of the platform. + + Not supported on Windows Server 2016, returns `UV_ENOSYS`. + + .. versionadded:: 1.50.0 + +.. c:function:: int uv_thread_getname(uv_thread_t* tid, char* name, size_t* size) + + Gets the name of the thread specified by `tid`. The thread name is copied, with the trailing NUL, into the buffer + pointed to by `name`. The `size` parameter specifies the size of the buffer pointed to by `name`. + The buffer should be large enough to hold the name of the thread plus the trailing NUL, or it will be truncated to fit + with the trailing NUL. + + Not supported on Windows Server 2016, returns `UV_ENOSYS`. + + .. versionadded:: 1.50.0 + .. c:function:: int uv_thread_setpriority(uv_thread_t tid, int priority) + If the function succeeds, the return value is 0. If the function fails, the return value is less than zero. Sets the scheduling priority of the thread specified by tid. It requires elevated @@ -140,7 +170,9 @@ Threads The priority can be set to the following constants. UV_THREAD_PRIORITY_HIGHEST, UV_THREAD_PRIORITY_ABOVE_NORMAL, UV_THREAD_PRIORITY_NORMAL, UV_THREAD_PRIORITY_BELOW_NORMAL, UV_THREAD_PRIORITY_LOWEST. + .. c:function:: int uv_thread_getpriority(uv_thread_t tid, int* priority) + If the function succeeds, the return value is 0. If the function fails, the return value is less than zero. Retrieves the scheduling priority of the thread specified by tid. The value in the diff --git a/deps/uv/docs/src/threadpool.rst b/deps/uv/docs/src/threadpool.rst index 7cfa797314ca48..d4dc5b8ec56097 100644 --- a/deps/uv/docs/src/threadpool.rst +++ b/deps/uv/docs/src/threadpool.rst @@ -17,11 +17,13 @@ is 1024). .. versionchanged:: 1.45.0 threads now have an 8 MB stack instead of the (sometimes too low) platform default. +.. versionchanged:: 1.50.0 threads now have a default name of libuv-worker. + The threadpool is global and shared across all event loops. When a particular -function makes use of the threadpool (i.e. when using :c:func:`uv_queue_work`) +function makes use of the threadpool (e.g. when using :c:func:`uv_queue_work`) libuv preallocates and initializes the maximum number of threads allowed by -``UV_THREADPOOL_SIZE``. This causes a relatively minor memory overhead -(~1MB for 128 threads) but increases the performance of threading at runtime. +``UV_THREADPOOL_SIZE``. More threads usually means more throughput but a higher +memory footprint. Thread stacks grow lazily on most platforms though. .. note:: Note that even though a global thread pool which is shared across all events diff --git a/deps/uv/docs/src/timer.rst b/deps/uv/docs/src/timer.rst index 070fa79da9d6df..474c6b8c4cd4f6 100644 --- a/deps/uv/docs/src/timer.rst +++ b/deps/uv/docs/src/timer.rst @@ -6,6 +6,15 @@ Timer handles are used to schedule callbacks to be called in the future. +Timers are either single-shot or repeating. Repeating timers do not adjust +for overhead but are rearmed relative to the event loop's idea of "now". + +Libuv updates its idea of "now" right before executing timer callbacks, and +right after waking up from waiting for I/O. See also :c:func:`uv_update_time`. + +Example: a repeating timer with a 50 ms interval whose callback takes 17 ms +to complete, runs again 33 ms later. If other tasks take longer than 33 ms, +the timer callback runs as soon as possible. Data types ---------- @@ -64,11 +73,6 @@ API duration, and will follow normal timer semantics in the case of a time-slice overrun. - For example, if a 50ms repeating timer first runs for 17ms, it will be - scheduled to run again 33ms later. If other tasks consume more than the - 33ms following the first timer callback, then the callback will run as soon - as possible. - .. note:: If the repeat value is set from a timer callback it does not immediately take effect. If the timer was non-repeating before, it will have been stopped. If it was repeating, diff --git a/deps/uv/docs/src/tty.rst b/deps/uv/docs/src/tty.rst index 7a2235210bf62a..b461b24437c187 100644 --- a/deps/uv/docs/src/tty.rst +++ b/deps/uv/docs/src/tty.rst @@ -27,10 +27,15 @@ Data types typedef enum { /* Initial/normal terminal mode */ UV_TTY_MODE_NORMAL, - /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + /* + * Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled). + * May become equivalent to UV_TTY_MODE_RAW_VT in future libuv versions. + */ UV_TTY_MODE_RAW, /* Binary-safe I/O mode for IPC (Unix-only) */ - UV_TTY_MODE_IO + UV_TTY_MODE_IO, + /* Raw input mode. On Windows ENABLE_VIRTUAL_TERMINAL_INPUT is also set. */ + UV_TTY_MODE_RAW_VT } uv_tty_mode_t; .. c:enum:: uv_tty_vtermstate_t diff --git a/deps/uv/docs/src/udp.rst b/deps/uv/docs/src/udp.rst index 31f7f7fd71ff47..5f225e5cda4011 100644 --- a/deps/uv/docs/src/udp.rst +++ b/deps/uv/docs/src/udp.rst @@ -426,6 +426,20 @@ API .. versionchanged:: 1.27.0 added support for connected sockets +.. c:function:: int uv_udp_try_send2(uv_udp_t* handle, unsigned int count, uv_buf_t* bufs[/*count*/], unsigned int nbufs[/*count*/], struct sockaddr* addrs[/*count*/], unsigned int flags) + + Like :c:func:`uv_udp_try_send`, but can send multiple datagrams. + Lightweight abstraction around :man:`sendmmsg(2)`, with a :man:`sendmsg(2)` + fallback loop for platforms that do not support the former. The handle must + be fully initialized; call c:func:`uv_udp_bind` first. + + :returns: >= 0: number of datagrams sent. Zero only if `count` was zero. + < 0: negative error code. Only if sending the first datagram fails, + otherwise returns a positive send count. ``UV_EAGAIN`` when datagrams + cannot be sent right now; fall back to :c:func:`uv_udp_send`. + + .. versionadded:: 1.50.0 + .. c:function:: int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb) Prepare for receiving data. If the socket has not previously been bound diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 9e450c5110fe57..938e998fdc54d1 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -58,6 +58,7 @@ extern "C" { #include #include #include +#include /* Internal type, do not use. */ struct uv__queue { @@ -157,6 +158,7 @@ struct uv__queue { XX(ESOCKTNOSUPPORT, "socket type not supported") \ XX(ENODATA, "no data available") \ XX(EUNATCH, "protocol driver not attached") \ + XX(ENOEXEC, "exec format error") \ #define UV_HANDLE_TYPE_MAP(XX) \ XX(ASYNC, async) \ @@ -775,6 +777,12 @@ UV_EXTERN int uv_udp_try_send(uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr); +UV_EXTERN int uv_udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/], + unsigned int flags); UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb); @@ -798,10 +806,15 @@ struct uv_tty_s { typedef enum { /* Initial/normal terminal mode */ UV_TTY_MODE_NORMAL, - /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + /* + * Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled). + * May become equivalent to UV_TTY_MODE_RAW_VT in future libuv versions. + */ UV_TTY_MODE_RAW, /* Binary-safe I/O mode for IPC (Unix-only) */ - UV_TTY_MODE_IO + UV_TTY_MODE_IO, + /* Raw input mode. On Windows ENABLE_VIRTUAL_TERMINAL_INPUT is also set. */ + UV_TTY_MODE_RAW_VT } uv_tty_mode_t; typedef enum { @@ -1288,6 +1301,7 @@ typedef struct { } uv_rusage_t; UV_EXTERN int uv_getrusage(uv_rusage_t* rusage); +UV_EXTERN int uv_getrusage_thread(uv_rusage_t* rusage); UV_EXTERN int uv_os_homedir(char* buffer, size_t* size); UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size); @@ -1577,6 +1591,8 @@ UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, const char* path, int mode, uv_fs_cb cb); +#define UV_FS_UTIME_NOW (INFINITY) +#define UV_FS_UTIME_OMIT (NAN) UV_EXTERN int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, @@ -1869,6 +1885,7 @@ UV_EXTERN int uv_gettimeofday(uv_timeval64_t* tv); typedef void (*uv_thread_cb)(void* arg); UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg); +UV_EXTERN int uv_thread_detach(uv_thread_t* tid); typedef enum { UV_THREAD_NO_FLAGS = 0x00, @@ -1898,6 +1915,9 @@ UV_EXTERN int uv_thread_getcpu(void); UV_EXTERN uv_thread_t uv_thread_self(void); UV_EXTERN int uv_thread_join(uv_thread_t *tid); UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2); +UV_EXTERN int uv_thread_setname(const char* name); +UV_EXTERN int uv_thread_getname(uv_thread_t* tid, char* name, size_t size); + /* The presence of these unions force similar struct layout. */ #define XX(_, name) uv_ ## name ## _t name; diff --git a/deps/uv/include/uv/errno.h b/deps/uv/include/uv/errno.h index 127278ef916161..ac00778cfc59fb 100644 --- a/deps/uv/include/uv/errno.h +++ b/deps/uv/include/uv/errno.h @@ -474,4 +474,10 @@ # define UV__EUNATCH (-4023) #endif +#if defined(ENOEXEC) && !defined(_WIN32) +# define UV__ENOEXEC UV__ERR(ENOEXEC) +#else +# define UV__ENOEXEC (-4022) +#endif + #endif /* UV_ERRNO_H_ */ diff --git a/deps/uv/include/uv/unix.h b/deps/uv/include/uv/unix.h index 538f98b6c5d657..7c972026f688e8 100644 --- a/deps/uv/include/uv/unix.h +++ b/deps/uv/include/uv/unix.h @@ -271,7 +271,10 @@ typedef struct { #define UV_UDP_SEND_PRIVATE_FIELDS \ struct uv__queue queue; \ - struct sockaddr_storage addr; \ + union { \ + struct sockaddr addr; \ + struct sockaddr_storage storage; \ + } u; \ unsigned int nbufs; \ uv_buf_t* bufs; \ ssize_t status; \ diff --git a/deps/uv/include/uv/version.h b/deps/uv/include/uv/version.h index cfa7871322e690..77432f259588eb 100644 --- a/deps/uv/include/uv/version.h +++ b/deps/uv/include/uv/version.h @@ -31,8 +31,8 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 49 -#define UV_VERSION_PATCH 2 +#define UV_VERSION_MINOR 51 +#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 12ac53b4f217d2..a88bf29e9ff504 100644 --- a/deps/uv/include/uv/win.h +++ b/deps/uv/include/uv/win.h @@ -20,7 +20,7 @@ */ #ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x0600 +# define _WIN32_WINNT 0x0A00 #endif #if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) @@ -32,14 +32,6 @@ typedef intptr_t ssize_t; #include -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -typedef struct pollfd { - SOCKET fd; - short events; - short revents; -} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD; -#endif - #ifndef LOCALE_INVARIANT # define LOCALE_INVARIANT 0x007f #endif @@ -507,8 +499,11 @@ typedef struct { union { \ struct { \ /* Used for readable TTY handles */ \ - /* TODO: remove me in v2.x. */ \ - HANDLE unused_; \ + union { \ + /* TODO: remove me in v2.x. */ \ + HANDLE unused_; \ + int mode; \ + } mode; \ uv_buf_t read_line_buffer; \ HANDLE read_raw_wait; \ /* Fields used for translating win keystrokes into vt100 characters */ \ diff --git a/deps/uv/src/fs-poll.c b/deps/uv/src/fs-poll.c index 1bac1c568e36ca..1fadafdea1746a 100644 --- a/deps/uv/src/fs-poll.c +++ b/deps/uv/src/fs-poll.c @@ -51,7 +51,7 @@ struct poll_ctx { static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b); static void poll_cb(uv_fs_t* req); static void timer_cb(uv_timer_t* timer); -static void timer_close_cb(uv_handle_t* handle); +static void timer_close_cb(uv_handle_t* timer); static uv_stat_t zero_statbuf; @@ -139,6 +139,9 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) { struct poll_ctx* ctx; size_t required_len; + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + if (!uv_is_active((uv_handle_t*)handle)) { *size = 0; return UV_EINVAL; diff --git a/deps/uv/src/idna.c b/deps/uv/src/idna.c index efc5f283ce2ef9..5fcaf64c974a8a 100644 --- a/deps/uv/src/idna.c +++ b/deps/uv/src/idna.c @@ -393,7 +393,7 @@ void uv_wtf8_to_utf16(const char* source_ptr, code_point = uv__wtf8_decode1(&source_ptr); /* uv_wtf8_length_as_utf16 should have been called and checked first. */ assert(code_point >= 0); - if (code_point > 0x10000) { + if (code_point > 0xFFFF) { assert(code_point < 0x10FFFF); *w_target++ = (((code_point - 0x10000) >> 10) + 0xD800); *w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00; diff --git a/deps/uv/src/threadpool.c b/deps/uv/src/threadpool.c index 45af50dcd04ea6..98d81cc7b6a4ed 100644 --- a/deps/uv/src/threadpool.c +++ b/deps/uv/src/threadpool.c @@ -59,6 +59,7 @@ static void worker(void* arg) { struct uv__queue* q; int is_slow_work; + uv_thread_setname("libuv-worker"); uv_sem_post((uv_sem_t*) arg); arg = NULL; diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index 3af3009a2167d6..48da0c9c40c842 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -1120,6 +1120,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifreq *ifr, *p, flg; struct in6_ifreq if6; struct sockaddr_dl* sa_addr; + size_t namelen; + char* name; ifc.ifc_req = NULL; sock6fd = -1; @@ -1156,6 +1158,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) /* Count all up and running ipv4/ipv6 addresses */ + namelen = 0; ifr = ifc.ifc_req; while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { p = ifr; @@ -1175,6 +1178,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) continue; + namelen += strlen(p->ifr_name) + 1; (*count)++; } @@ -1182,11 +1186,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { goto cleanup; /* Alloc the return interface structs */ - *addresses = uv__calloc(*count, sizeof(**addresses)); - if (!(*addresses)) { + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); + if (*addresses == NULL) { r = UV_ENOMEM; goto cleanup; } + name = (char*) &(*addresses)[*count]; address = *addresses; ifr = ifc.ifc_req; @@ -1210,7 +1215,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* All conditions above must match count loop */ - address->name = uv__strdup(p->ifr_name); + namelen = strlen(p->ifr_name) + 1; + address->name = memcpy(name, p->ifr_name, namelen); + name += namelen; if (inet6) address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); @@ -1282,13 +1289,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - int i; - - for (i = 0; i < count; ++i) { - uv__free(addresses[i].name); - } - + int count) { uv__free(addresses); } diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c index 0ff2669e30a628..538ae7876f2b24 100644 --- a/deps/uv/src/unix/async.c +++ b/deps/uv/src/unix/async.c @@ -38,6 +38,34 @@ #include #endif +#if UV__KQUEUE_EVFILT_USER +static uv_once_t kqueue_runtime_detection_guard = UV_ONCE_INIT; +static int kqueue_evfilt_user_support = 1; + + +static void uv__kqueue_runtime_detection(void) { + int kq; + struct kevent ev[2]; + struct timespec timeout = {0, 0}; + + /* Perform the runtime detection to ensure that kqueue with + * EVFILT_USER actually works. */ + kq = kqueue(); + EV_SET(ev, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER, + EV_ADD | EV_CLEAR, 0, 0, 0); + EV_SET(ev + 1, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER, + 0, NOTE_TRIGGER, 0, 0); + if (kevent(kq, ev, 2, ev, 1, &timeout) < 1 || + ev[0].filter != EVFILT_USER || + ev[0].ident != UV__KQUEUE_EVFILT_USER_IDENT || + ev[0].flags & EV_ERROR) + /* If we wind up here, we can assume that EVFILT_USER is defined but + * broken on the current system. */ + kqueue_evfilt_user_support = 0; + uv__close(kq); +} +#endif + static void uv__async_send(uv_loop_t* loop); static int uv__async_start(uv_loop_t* loop); static void uv__cpu_relax(void); @@ -139,7 +167,11 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(w == &loop->async_io_watcher); +#if UV__KQUEUE_EVFILT_USER + for (;!kqueue_evfilt_user_support;) { +#else for (;;) { +#endif r = read(w->fd, buf, sizeof(buf)); if (r == sizeof(buf)) @@ -195,6 +227,17 @@ static void uv__async_send(uv_loop_t* loop) { len = sizeof(val); fd = loop->async_io_watcher.fd; /* eventfd */ } +#elif UV__KQUEUE_EVFILT_USER + struct kevent ev; + + if (kqueue_evfilt_user_support) { + fd = loop->async_io_watcher.fd; /* magic number for EVFILT_USER */ + EV_SET(&ev, fd, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0); + r = kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL); + if (r == 0) + return; + abort(); + } #endif do @@ -215,6 +258,9 @@ static void uv__async_send(uv_loop_t* loop) { static int uv__async_start(uv_loop_t* loop) { int pipefd[2]; int err; +#if UV__KQUEUE_EVFILT_USER + struct kevent ev; +#endif if (loop->async_io_watcher.fd != -1) return 0; @@ -226,16 +272,59 @@ static int uv__async_start(uv_loop_t* loop) { pipefd[0] = err; pipefd[1] = -1; +#elif UV__KQUEUE_EVFILT_USER + uv_once(&kqueue_runtime_detection_guard, uv__kqueue_runtime_detection); + if (kqueue_evfilt_user_support) { + /* In order not to break the generic pattern of I/O polling, a valid + * file descriptor is required to take up a room in loop->watchers, + * thus we create one for that, but this fd will not be actually used, + * it's just a placeholder and magic number which is going to be closed + * during the cleanup, as other FDs. */ + err = uv__open_cloexec("/", O_RDONLY); + if (err < 0) + return err; + + pipefd[0] = err; + pipefd[1] = -1; + + /* When using EVFILT_USER event to wake up the kqueue, this event must be + * registered beforehand. Otherwise, calling kevent() to issue an + * unregistered EVFILT_USER event will get an ENOENT. + * Since uv__async_send() may happen before uv__io_poll() with multi-threads, + * we can't defer this registration of EVFILT_USER event as we did for other + * events, but must perform it right away. */ + EV_SET(&ev, err, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, 0); + err = kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL); + if (err < 0) + return UV__ERR(errno); + } else { + err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE); + if (err < 0) + return err; + } #else err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE); if (err < 0) return err; #endif - uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]); - uv__io_start(loop, &loop->async_io_watcher, POLLIN); + err = uv__io_init_start(loop, &loop->async_io_watcher, uv__async_io, + pipefd[0], POLLIN); + if (err < 0) { + uv__close(pipefd[0]); + if (pipefd[1] != -1) + uv__close(pipefd[1]); + return err; + } loop->async_wfd = pipefd[1]; +#if UV__KQUEUE_EVFILT_USER + /* Prevent the EVFILT_USER event from being added to kqueue redundantly + * and mistakenly later in uv__io_poll(). */ + if (kqueue_evfilt_user_support) + loop->async_io_watcher.events = loop->async_io_watcher.pevents; +#endif + return 0; } diff --git a/deps/uv/src/unix/bsd-ifaddrs.c b/deps/uv/src/unix/bsd-ifaddrs.c index 11ca95591fc382..8d9ebd25d4306b 100644 --- a/deps/uv/src/unix/bsd-ifaddrs.c +++ b/deps/uv/src/unix/bsd-ifaddrs.c @@ -65,13 +65,13 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return 0; } +/* TODO(bnoordhuis) share with linux.c */ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + uv_interface_address_t* address; struct ifaddrs* addrs; struct ifaddrs* ent; - uv_interface_address_t* address; -#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__) - int i; -#endif + size_t namelen; + char* name; *count = 0; *addresses = NULL; @@ -80,9 +80,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV__ERR(errno); /* Count the number of interfaces */ + namelen = 0; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -92,20 +94,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } /* Make sure the memory is initiallized to zero using calloc() */ - *addresses = uv__calloc(*count, sizeof(**addresses)); - + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); if (*addresses == NULL) { freeifaddrs(addrs); return UV_ENOMEM; } + name = (char*) &(*addresses)[*count]; address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; - address->name = uv__strdup(ent->ifa_name); + namelen = strlen(ent->ifa_name) + 1; + address->name = memcpy(name, ent->ifa_name, namelen); + name += namelen; if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); @@ -129,6 +133,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__) /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + int i; + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) continue; @@ -151,13 +157,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } +/* TODO(bnoordhuis) share with linux.c */ void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(addresses[i].name); - } - uv__free(addresses); } diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 0c52ccf2ad7b2d..bd51b69b8120e8 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -52,6 +52,8 @@ #endif #if defined(__APPLE__) +# include +# include # include # include #endif /* defined(__APPLE__) */ @@ -751,7 +753,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { int uv_cwd(char* buffer, size_t* size) { char scratch[1 + UV__PATH_MAX]; - if (buffer == NULL || size == NULL) + if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; /* Try to read directly into the user's buffer first... */ @@ -865,7 +867,7 @@ static unsigned int next_power_of_two(unsigned int val) { return val; } -static void maybe_resize(uv_loop_t* loop, unsigned int len) { +static int maybe_resize(uv_loop_t* loop, unsigned int len) { uv__io_t** watchers; void* fake_watcher_list; void* fake_watcher_count; @@ -873,7 +875,7 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { unsigned int i; if (len <= loop->nwatchers) - return; + return 0; /* Preserve fake watcher list and count at the end of the watchers */ if (loop->watchers != NULL) { @@ -889,7 +891,7 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { (nwatchers + 2) * sizeof(loop->watchers[0])); if (watchers == NULL) - abort(); + return UV_ENOMEM; for (i = loop->nwatchers; i < nwatchers; i++) watchers[i] = NULL; watchers[nwatchers] = fake_watcher_list; @@ -897,11 +899,11 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { loop->watchers = watchers; loop->nwatchers = nwatchers; + return 0; } void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { - assert(cb != NULL); assert(fd >= -1); uv__queue_init(&w->pending_queue); uv__queue_init(&w->watcher_queue); @@ -912,14 +914,18 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { } -void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { +int uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + int err; + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); w->pevents |= events; - maybe_resize(loop, w->fd + 1); + err = maybe_resize(loop, w->fd + 1); + if (err) + return err; #if !defined(__sun) /* The event ports backend needs to rearm all file descriptors on each and @@ -927,7 +933,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { * short-circuit here if the event mask is unchanged. */ if (w->events == w->pevents) - return; + return 0; #endif if (uv__queue_empty(&w->watcher_queue)) @@ -937,6 +943,25 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { loop->watchers[w->fd] = w; loop->nfds++; } + + return 0; +} + + +int uv__io_init_start(uv_loop_t* loop, + uv__io_t* w, + uv__io_cb 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); + return err; } @@ -999,10 +1024,10 @@ int uv__fd_exists(uv_loop_t* loop, int fd) { } -int uv_getrusage(uv_rusage_t* rusage) { +static int uv__getrusage(int who, uv_rusage_t* rusage) { struct rusage usage; - if (getrusage(RUSAGE_SELF, &usage)) + if (getrusage(who, &usage)) return UV__ERR(errno); rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec; @@ -1041,6 +1066,50 @@ int uv_getrusage(uv_rusage_t* rusage) { } +int uv_getrusage(uv_rusage_t* rusage) { + return uv__getrusage(RUSAGE_SELF, rusage); +} + + +int uv_getrusage_thread(uv_rusage_t* rusage) { +#if defined(__APPLE__) + mach_msg_type_number_t count; + thread_basic_info_data_t info; + kern_return_t kr; + thread_t thread; + + thread = mach_thread_self(); + count = THREAD_BASIC_INFO_COUNT; + kr = thread_info(thread, + THREAD_BASIC_INFO, + (thread_info_t)&info, + &count); + + if (kr != KERN_SUCCESS) { + mach_port_deallocate(mach_task_self(), thread); + return UV_EINVAL; + } + + memset(rusage, 0, sizeof(*rusage)); + + rusage->ru_utime.tv_sec = info.user_time.seconds; + rusage->ru_utime.tv_usec = info.user_time.microseconds; + rusage->ru_stime.tv_sec = info.system_time.seconds; + rusage->ru_stime.tv_usec = info.system_time.microseconds; + + mach_port_deallocate(mach_task_self(), thread); + + return 0; + +#elif defined(RUSAGE_LWP) + return uv__getrusage(RUSAGE_LWP, rusage); +#elif defined(RUSAGE_THREAD) + return uv__getrusage(RUSAGE_THREAD, rusage); +#endif /* defined(__APPLE__) */ + return UV_ENOTSUP; +} + + int uv__open_cloexec(const char* path, int flags) { #if defined(O_CLOEXEC) int fd; @@ -1977,14 +2046,11 @@ unsigned int uv_available_parallelism(void) { #ifdef __linux__ { - double rc_with_cgroup; - uv__cpu_constraint c = {0, 0, 0.0}; + long long quota = 0; - if (uv__get_constrained_cpu(&c) == 0 && c.period_length > 0) { - rc_with_cgroup = (double)c.quota_per_period / c.period_length * c.proportions; - if (rc_with_cgroup < rc) - rc = (long)rc_with_cgroup; /* Casting is safe since rc_with_cgroup < rc < LONG_MAX */ - } + if (uv__get_constrained_cpu("a) == 0) + if (quota > 0 && quota < rc) + rc = quota; } #endif /* __linux__ */ diff --git a/deps/uv/src/unix/darwin-proctitle.c b/deps/uv/src/unix/darwin-proctitle.c index 5288083ef04fd7..5e5642972a4df6 100644 --- a/deps/uv/src/unix/darwin-proctitle.c +++ b/deps/uv/src/unix/darwin-proctitle.c @@ -33,25 +33,9 @@ #include "darwin-stub.h" #endif - -static int uv__pthread_setname_np(const char* name) { - char namebuf[64]; /* MAXTHREADNAMESIZE */ - int err; - - strncpy(namebuf, name, sizeof(namebuf) - 1); - namebuf[sizeof(namebuf) - 1] = '\0'; - - err = pthread_setname_np(namebuf); - if (err) - return UV__ERR(err); - - return 0; -} - - int uv__set_process_title(const char* title) { #if TARGET_OS_IPHONE - return uv__pthread_setname_np(title); + return uv__thread_setname(title); #else CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, const char*, @@ -177,7 +161,7 @@ int uv__set_process_title(const char* title) { goto out; } - uv__pthread_setname_np(title); /* Don't care if it fails. */ + uv__thread_setname(title); /* Don't care if it fails. */ err = 0; out: diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 239ecda16a7eb9..717f3fab36939e 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -203,8 +203,23 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { } -UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) { +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) +static struct timespec uv__fs_to_timespec(double time) { struct timespec ts; + + if (uv__isinf(time)) + return (struct timespec){UTIME_NOW, UTIME_NOW}; + if (uv__isnan(time)) + return (struct timespec){UTIME_OMIT, UTIME_OMIT}; + ts.tv_sec = time; ts.tv_nsec = (time - ts.tv_sec) * 1e9; @@ -221,41 +236,23 @@ UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) { } return ts; } +#endif -UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) { - struct timeval tv; - tv.tv_sec = time; - tv.tv_usec = (time - tv.tv_sec) * 1e6; - if (tv.tv_usec < 0) { - tv.tv_usec += 1e6; - tv.tv_sec -= 1; - } - return tv; -} static ssize_t uv__fs_futime(uv_fs_t* req) { -#if defined(__linux__) \ +#if defined(__APPLE__) \ || defined(_AIX71) \ - || defined(__HAIKU__) \ - || defined(__GNU__) - struct timespec ts[2]; - ts[0] = uv__fs_to_timespec(req->atime); - ts[1] = uv__fs_to_timespec(req->mtime); - return futimens(req->file, ts); -#elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ || defined(__NetBSD__) \ || defined(__OpenBSD__) \ + || defined(__linux__) \ || defined(__sun) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); -# if defined(__sun) - return futimesat(req->file, NULL, tv); -# else - return futimes(req->file, tv); -# endif + struct timespec ts[2]; + ts[0] = uv__fs_to_timespec(req->atime); + ts[1] = uv__fs_to_timespec(req->mtime); + return futimens(req->file, ts); #elif defined(__MVS__) attrib_t atr; memset(&atr, 0, sizeof(atr)); @@ -461,12 +458,7 @@ static ssize_t uv__pwritev_emul(int fd, /* The function pointer cache is an uintptr_t because _Atomic void* * doesn't work on macos/ios/etc... - * Disable optimization on armv7 to work around the bug described in - * https://github.com/libuv/libuv/issues/4532 */ -#if defined(__arm__) && (__ARM_ARCH == 7) -__attribute__((optimize("O0"))) -#endif static ssize_t uv__preadv_or_pwritev(int fd, const struct iovec* bufs, size_t nbufs, @@ -479,7 +471,12 @@ static ssize_t uv__preadv_or_pwritev(int fd, p = (void*) atomic_load_explicit(cache, memory_order_relaxed); if (p == NULL) { #ifdef RTLD_DEFAULT - p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev"); + /* Try _LARGEFILE_SOURCE version of preadv/pwritev first, + * then fall back to the plain version, for libcs like musl. + */ + p = dlsym(RTLD_DEFAULT, is_pread ? "preadv64" : "pwritev64"); + if (p == NULL) + p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev"); dlerror(); /* Clear errors. */ #endif /* RTLD_DEFAULT */ if (p == NULL) @@ -487,10 +484,7 @@ static ssize_t uv__preadv_or_pwritev(int fd, atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed); } - /* Use memcpy instead of `f = p` to work around a compiler bug, - * see https://github.com/libuv/libuv/issues/4532 - */ - memcpy(&f, &p, sizeof(p)); + f = p; return f(fd, bufs, nbufs, off); } @@ -1145,25 +1139,20 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { static ssize_t uv__fs_utime(uv_fs_t* req) { -#if defined(__linux__) \ - || defined(_AIX71) \ - || defined(__sun) \ - || defined(__HAIKU__) +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); return utimensat(AT_FDCWD, req->path, ts, 0); -#elif defined(__APPLE__) \ - || defined(__DragonFly__) \ - || defined(__FreeBSD__) \ - || defined(__NetBSD__) \ - || defined(__OpenBSD__) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); - return utimes(req->path, tv); -#elif defined(_AIX) \ - && !defined(_AIX71) +#elif defined(_AIX) && !defined(_AIX71) struct utimbuf buf; buf.actime = req->atime; buf.modtime = req->mtime; @@ -1184,24 +1173,19 @@ static ssize_t uv__fs_utime(uv_fs_t* req) { static ssize_t uv__fs_lutime(uv_fs_t* req) { -#if defined(__linux__) || \ - defined(_AIX71) || \ - defined(__sun) || \ - defined(__HAIKU__) || \ - defined(__GNU__) || \ - defined(__OpenBSD__) +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW); -#elif defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__NetBSD__) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); - return lutimes(req->path, tv); #else errno = ENOSYS; return -1; diff --git a/deps/uv/src/unix/haiku.c b/deps/uv/src/unix/haiku.c index 31284b66dc3e96..0d3645f014b4eb 100644 --- a/deps/uv/src/unix/haiku.c +++ b/deps/uv/src/unix/haiku.c @@ -120,7 +120,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { int i; status_t status; system_info system; - uint32_t topology_count; + uint32 topology_count; /* Haiku expects address of uint32, not uint32_t */ uint64_t cpuspeed; uv_cpu_info_t* cpu_info; diff --git a/deps/uv/src/unix/ibmi.c b/deps/uv/src/unix/ibmi.c index 837bba6e2fef7b..9d94d2af54468a 100644 --- a/deps/uv/src/unix/ibmi.c +++ b/deps/uv/src/unix/ibmi.c @@ -394,6 +394,8 @@ static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) { int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; struct ifaddrs_pase *ifap = NULL, *cur; + size_t namelen; + char* name; int inet6, r = 0; *count = 0; @@ -403,6 +405,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV_ENOSYS; /* The first loop to get the size of the array to be allocated */ + namelen = 0; for (cur = ifap; cur; cur = cur->ifa_next) { if (!(cur->ifa_addr->sa_family == AF_INET6 || cur->ifa_addr->sa_family == AF_INET)) @@ -411,6 +414,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING)) continue; + namelen += strlen(cur->ifa_name) + 1; (*count)++; } @@ -420,11 +424,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } /* Alloc the return interface structs */ - *addresses = uv__calloc(*count, sizeof(**addresses)); + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); if (*addresses == NULL) { Qp2freeifaddrs(ifap); return UV_ENOMEM; } + + name = (char*) &(*addresses)[*count]; address = *addresses; /* The second loop to fill in the array */ @@ -436,7 +442,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING)) continue; - address->name = uv__strdup(cur->ifa_name); + namelen = strlen(cur->ifa_name) + 1; + address->name = memcpy(name, cur->ifa_name, namelen); + name += namelen; inet6 = (cur->ifa_addr->sa_family == AF_INET6); @@ -497,13 +505,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } -void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { - int i; - - for (i = 0; i < count; ++i) { - uv__free(addresses[i].name); - } - +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { uv__free(addresses); } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 8d586b0b64a96c..a1d7d4366308ac 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -35,6 +35,10 @@ #include #include #include +#if defined(__APPLE__) || defined(__DragonFly__) || \ + defined(__FreeBSD__) || defined(__NetBSD__) +#include +#endif #define uv__msan_unpoison(p, n) \ do { \ @@ -253,7 +257,12 @@ 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); -void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events); +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, + int fd, + unsigned int events); void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events); void uv__io_close(uv_loop_t* loop, uv__io_t* w); void uv__io_feed(uv_loop_t* loop, uv__io_t* w); @@ -323,6 +332,8 @@ void uv__prepare_close(uv_prepare_t* handle); void uv__process_close(uv_process_t* handle); void uv__stream_close(uv_stream_t* handle); void uv__tcp_close(uv_tcp_t* handle); +int uv__thread_setname(const char* name); +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size); size_t uv__thread_stack_size(void); void uv__udp_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle); @@ -483,13 +494,7 @@ uv__fs_copy_file_range(int fd_in, #endif #ifdef __linux__ -typedef struct { - long long quota_per_period; - long long period_length; - double proportions; -} uv__cpu_constraint; - -int uv__get_constrained_cpu(uv__cpu_constraint* constraint); +int uv__get_constrained_cpu(long long* quota); #endif #if defined(__sun) && !defined(__illumos__) @@ -504,4 +509,22 @@ int uv__get_constrained_cpu(uv__cpu_constraint* constraint); #endif #endif +#if defined(EVFILT_USER) && defined(NOTE_TRIGGER) +/* EVFILT_USER is available since OS X 10.6, DragonFlyBSD 4.0, + * FreeBSD 8.1, and NetBSD 10.0. + * + * Note that even though EVFILT_USER is defined on the current system, + * it may still fail to work at runtime somehow. In that case, we fall + * back to pipe-based signaling. + */ +#define UV__KQUEUE_EVFILT_USER 1 +/* Magic number of identifier used for EVFILT_USER during runtime detection. + * There are no Google hits for this number when I create it. That way, + * people will be directed here if this number gets printed due to some + * kqueue error and they google for help. */ +#define UV__KQUEUE_EVFILT_USER_IDENT 0x1e7e7711 +#else +#define UV__KQUEUE_EVFILT_USER 0 +#endif + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 66aa166f053f52..39b72012c26955 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -97,8 +97,7 @@ int uv__io_fork(uv_loop_t* loop) { int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct kevent ev; - int rc; + struct kevent ev[2]; struct stat sb; #ifdef __APPLE__ char path[MAXPATHLEN]; @@ -133,17 +132,12 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { } #endif - rc = 0; - EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); - if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) - rc = UV__ERR(errno); - - EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); - if (rc == 0) - if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) - abort(); + EV_SET(ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); + EV_SET(ev + 1, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, ev, 2, NULL, 0, NULL)) + return UV__ERR(errno); - return rc; + return 0; } @@ -367,6 +361,17 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { continue; } +#if UV__KQUEUE_EVFILT_USER + if (ev->filter == EVFILT_USER) { + w = &loop->async_io_watcher; + assert(fd == w->fd); + uv__metrics_update_idle_time(loop); + w->cb(loop, w, w->events); + nevents++; + continue; + } +#endif + if (ev->filter == EVFILT_VNODE) { assert(w->events == POLLIN); assert(w->pevents == POLLIN); @@ -564,6 +569,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, const char* path, unsigned int flags) { int fd; + int r; #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 struct stat statbuf; #endif @@ -599,7 +605,6 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop, memory_order_relaxed)) { - int r; /* The fallback fd is no longer needed */ uv__close_nocheckstdio(fd); handle->event_watcher.fd = -1; @@ -615,11 +620,16 @@ int uv_fs_event_start(uv_fs_event_t* handle, fallback: #endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */ - uv__handle_start(handle); - uv__io_init(&handle->event_watcher, uv__fs_event, fd); - uv__io_start(handle->loop, &handle->event_watcher, POLLIN); + r = uv__io_init_start(handle->loop, + &handle->event_watcher, + uv__fs_event, + fd, + POLLIN); - return 0; + if (!r) + uv__handle_start(handle); + + return r; } diff --git a/deps/uv/src/unix/linux.c b/deps/uv/src/unix/linux.c index 857a4ef8a6686f..ea3e2de0384b2c 100644 --- a/deps/uv/src/unix/linux.c +++ b/deps/uv/src/unix/linux.c @@ -455,7 +455,7 @@ int uv__io_uring_register(int fd, unsigned opcode, void* arg, unsigned nargs) { } -static int uv__use_io_uring(void) { +static int uv__use_io_uring(uint32_t flags) { #if defined(__ANDROID_API__) return 0; /* Possibly available but blocked by seccomp. */ #elif defined(__arm__) && __SIZEOF_POINTER__ == 4 @@ -470,25 +470,27 @@ static int uv__use_io_uring(void) { char* val; int use; - use = atomic_load_explicit(&use_io_uring, memory_order_relaxed); - - if (use == 0) { - use = uv__kernel_version() >= #if defined(__hppa__) - /* io_uring first supported on parisc in 6.1, functional in .51 */ - /* https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/ */ - /* 6.1.51 */ 0x060133 -#else - /* Older kernels have a bug where the sqpoll thread uses 100% CPU. */ - /* 5.10.186 */ 0x050ABA + /* io_uring first supported on parisc in 6.1, functional in .51 + * https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/ + */ + if (uv__kernel_version() < /*6.1.51*/0x060133) + return 0; #endif - ? 1 : -1; - /* But users can still enable it if they so desire. */ - val = getenv("UV_USE_IO_URING"); - if (val != NULL) - use = atoi(val) ? 1 : -1; + /* SQPOLL is all kinds of buggy but epoll batching should work fine. */ + if (0 == (flags & UV__IORING_SETUP_SQPOLL)) + return 1; + /* Older kernels have a bug where the sqpoll thread uses 100% CPU. */ + if (uv__kernel_version() < /*5.10.186*/0x050ABA) + return 0; + + use = atomic_load_explicit(&use_io_uring, memory_order_relaxed); + + if (use == 0) { + val = getenv("UV_USE_IO_URING"); + use = val != NULL && atoi(val) > 0 ? 1 : -1; atomic_store_explicit(&use_io_uring, use, memory_order_relaxed); } @@ -518,7 +520,7 @@ static void uv__iou_init(int epollfd, sq = MAP_FAILED; sqe = MAP_FAILED; - if (!uv__use_io_uring()) + if (!uv__use_io_uring(flags)) return; kernel_version = uv__kernel_version(); @@ -766,14 +768,13 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, */ if (iou->ringfd == -2) { /* By default, the SQPOLL is not created. Enable only if the loop is - * configured with UV_LOOP_USE_IO_URING_SQPOLL. + * configured with UV_LOOP_USE_IO_URING_SQPOLL and the UV_USE_IO_URING + * environment variable is unset or a positive number. */ - if ((loop->flags & UV_LOOP_ENABLE_IO_URING_SQPOLL) == 0) { - iou->ringfd = -1; - return NULL; - } + if (loop->flags & UV_LOOP_ENABLE_IO_URING_SQPOLL) + if (uv__use_io_uring(UV__IORING_SETUP_SQPOLL)) + uv__iou_init(loop->backend_fd, iou, 64, UV__IORING_SETUP_SQPOLL); - uv__iou_init(loop->backend_fd, iou, 64, UV__IORING_SETUP_SQPOLL); if (iou->ringfd == -2) iou->ringfd = -1; /* "failed" */ } @@ -1713,16 +1714,22 @@ int uv_uptime(double* uptime) { int uv_cpu_info(uv_cpu_info_t** ci, int* count) { #if defined(__PPC__) static const char model_marker[] = "cpu\t\t: "; + static const char model_marker2[] = ""; #elif defined(__arm__) - static const char model_marker[] = "Processor\t: "; + static const char model_marker[] = "model name\t: "; + static const char model_marker2[] = "Processor\t: "; #elif defined(__aarch64__) static const char model_marker[] = "CPU part\t: "; + static const char model_marker2[] = ""; #elif defined(__mips__) static const char model_marker[] = "cpu model\t\t: "; + static const char model_marker2[] = ""; #elif defined(__loongarch__) static const char model_marker[] = "cpu family\t\t: "; + static const char model_marker2[] = ""; #else static const char model_marker[] = "model name\t: "; + static const char model_marker2[] = ""; #endif static const char parts[] = #ifdef __aarch64__ @@ -1821,14 +1828,22 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) { if (1 != fscanf(fp, "processor\t: %u\n", &cpu)) break; /* Parse error. */ - found = 0; - while (!found && fgets(buf, sizeof(buf), fp)) - found = !strncmp(buf, model_marker, sizeof(model_marker) - 1); + while (fgets(buf, sizeof(buf), fp)) { + if (!strncmp(buf, model_marker, sizeof(model_marker) - 1)) { + p = buf + sizeof(model_marker) - 1; + goto parts; + } + if (!*model_marker2) + continue; + if (!strncmp(buf, model_marker2, sizeof(model_marker2) - 1)) { + p = buf + sizeof(model_marker2) - 1; + goto parts; + } + } - if (!found) - goto next; + goto next; /* Not found. */ - p = buf + sizeof(model_marker) - 1; +parts: n = (int) strcspn(p, "\n"); /* arm64: translate CPU part code to model name. */ @@ -1939,11 +1954,15 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return !exclude_type; } +/* TODO(bnoordhuis) share with bsd-ifaddrs.c */ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - struct ifaddrs *addrs, *ent; uv_interface_address_t* address; + struct sockaddr_ll* sll; + struct ifaddrs* addrs; + struct ifaddrs* ent; + size_t namelen; + char* name; int i; - struct sockaddr_ll *sll; *count = 0; *addresses = NULL; @@ -1952,10 +1971,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV__ERR(errno); /* Count the number of interfaces */ + namelen = 0; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -1965,19 +1986,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } /* Make sure the memory is initiallized to zero using calloc() */ - *addresses = uv__calloc(*count, sizeof(**addresses)); - if (!(*addresses)) { + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); + if (*addresses == NULL) { freeifaddrs(addrs); return UV_ENOMEM; } + name = (char*) &(*addresses)[*count]; address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; - address->name = uv__strdup(ent->ifa_name); + namelen = strlen(ent->ifa_name) + 1; + address->name = memcpy(name, ent->ifa_name, namelen); + name += namelen; if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); @@ -2021,14 +2045,9 @@ 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) { - int i; - - for (i = 0; i < count; i++) { - uv__free(addresses[i].name); - } - + int count) { uv__free(addresses); } @@ -2286,49 +2305,83 @@ uint64_t uv_get_available_memory(void) { static int uv__get_cgroupv2_constrained_cpu(const char* cgroup, - uv__cpu_constraint* constraint) { - char path[256]; - char buf[1024]; - unsigned int weight; - int cgroup_size; + long long* quota) { + static const char cgroup_mount[] = "/sys/fs/cgroup"; const char* cgroup_trimmed; + char buf[1024]; + char full_path[256]; + char path[256]; char quota_buf[16]; + char* last_slash; + int cgroup_size; + long long limit; + long long min_quota; + long long period; if (strncmp(cgroup, "0::/", 4) != 0) return UV_EINVAL; /* Trim ending \n by replacing it with a 0 */ cgroup_trimmed = cgroup + sizeof("0::/") - 1; /* Skip the prefix "0::/" */ - cgroup_size = (int)strcspn(cgroup_trimmed, "\n"); /* Find the first slash */ + cgroup_size = (int)strcspn(cgroup_trimmed, "\n"); /* Find the first \n */ + min_quota = LLONG_MAX; - /* Construct the path to the cpu.max file */ - snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.max", cgroup_size, - cgroup_trimmed); + /* Construct the path to the cpu.max files */ + snprintf(path, sizeof(path), "%s/%.*s/cgroup.controllers", cgroup_mount, + cgroup_size, cgroup_trimmed); - /* Read cpu.max */ + /* Read controllers, if not exists, not really a cgroup */ if (uv__slurp(path, buf, sizeof(buf)) < 0) return UV_EIO; - if (sscanf(buf, "%15s %llu", quota_buf, &constraint->period_length) != 2) - return UV_EINVAL; + snprintf(path, sizeof(path), "%s/%.*s", cgroup_mount, cgroup_size, + cgroup_trimmed); - if (strncmp(quota_buf, "max", 3) == 0) - constraint->quota_per_period = LLONG_MAX; - else if (sscanf(quota_buf, "%lld", &constraint->quota_per_period) != 1) - return UV_EINVAL; // conversion failed + /* + * Traverse up the cgroup v2 hierarchy, starting from the current cgroup path. + * At each level, attempt to read the "cpu.max" file, which defines the CPU + * quota and period. + * + * This reflects how Linux applies cgroup limits hierarchically. + * + * e.g: given a path like /sys/fs/cgroup/foo/bar/baz, we check: + * - /sys/fs/cgroup/foo/bar/baz/cpu.max + * - /sys/fs/cgroup/foo/bar/cpu.max + * - /sys/fs/cgroup/foo/cpu.max + * - /sys/fs/cgroup/cpu.max + */ + while (strncmp(path, cgroup_mount, strlen(cgroup_mount)) == 0) { + snprintf(full_path, sizeof(full_path), "%s/cpu.max", path); - /* Construct the path to the cpu.weight file */ - snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.weight", cgroup_size, - cgroup_trimmed); + /* Silently ignore and continue if the file does not exist */ + if (uv__slurp(full_path, quota_buf, sizeof(quota_buf)) < 0) + goto next; - /* Read cpu.weight */ - if (uv__slurp(path, buf, sizeof(buf)) < 0) - return UV_EIO; + /* No limit, move on */ + if (strncmp(quota_buf, "max", 3) == 0) + goto next; - if (sscanf(buf, "%u", &weight) != 1) - return UV_EINVAL; + /* Read cpu.max */ + if (sscanf(quota_buf, "%lld %lld", &limit, &period) != 2) + goto next; - constraint->proportions = (double)weight / 100.0; + /* Can't divide by 0 */ + if (period == 0) + goto next; + + *quota = limit / period; + if (*quota < min_quota) + min_quota = *quota; + +next: + /* Move up one level in the cgroup hierarchy by trimming the last path. + * The loop ends once we reach the cgroup root mount point. + */ + last_slash = strrchr(path, '/'); + if (last_slash == NULL || strcmp(path, cgroup_mount) == 0) + break; + *last_slash = '\0'; + } return 0; } @@ -2349,12 +2402,13 @@ static char* uv__cgroup1_find_cpu_controller(const char* cgroup, } static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, - uv__cpu_constraint* constraint) { + long long* quota) { char path[256]; char buf[1024]; - unsigned int shares; int cgroup_size; char* cgroup_cpu; + long long period_length; + long long quota_per_period; cgroup_cpu = uv__cgroup1_find_cpu_controller(cgroup, &cgroup_size); @@ -2365,10 +2419,11 @@ static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.cfs_quota_us", cgroup_size, cgroup_cpu); + /* Read cpu.cfs_quota_us */ if (uv__slurp(path, buf, sizeof(buf)) < 0) return UV_EIO; - if (sscanf(buf, "%lld", &constraint->quota_per_period) != 1) + if (sscanf(buf, "%lld", "a_per_period) != 1) return UV_EINVAL; /* Construct the path to the cpu.cfs_period_us file */ @@ -2379,26 +2434,19 @@ static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, if (uv__slurp(path, buf, sizeof(buf)) < 0) return UV_EIO; - if (sscanf(buf, "%lld", &constraint->period_length) != 1) + if (sscanf(buf, "%lld", &period_length) != 1) return UV_EINVAL; - /* Construct the path to the cpu.shares file */ - snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.shares", cgroup_size, - cgroup_cpu); - - /* Read cpu.shares */ - if (uv__slurp(path, buf, sizeof(buf)) < 0) - return UV_EIO; - - if (sscanf(buf, "%u", &shares) != 1) + /* Can't divide by 0 */ + if (period_length == 0) return UV_EINVAL; - constraint->proportions = (double)shares / 1024.0; + *quota = quota_per_period / period_length; return 0; } -int uv__get_constrained_cpu(uv__cpu_constraint* constraint) { +int uv__get_constrained_cpu(long long* quota) { char cgroup[1024]; /* Read the cgroup from /proc/self/cgroup */ @@ -2409,9 +2457,9 @@ int uv__get_constrained_cpu(uv__cpu_constraint* constraint) { * The entry for cgroup v2 is always in the format "0::$PATH" * see https://docs.kernel.org/admin-guide/cgroup-v2.html */ if (strncmp(cgroup, "0::/", 4) == 0) - return uv__get_cgroupv2_constrained_cpu(cgroup, constraint); + return uv__get_cgroupv2_constrained_cpu(cgroup, quota); else - return uv__get_cgroupv1_constrained_cpu(cgroup, constraint); + return uv__get_cgroupv1_constrained_cpu(cgroup, quota); } @@ -2441,6 +2489,7 @@ static int compare_watchers(const struct watcher_list* a, static int init_inotify(uv_loop_t* loop) { + int err; int fd; if (loop->inotify_fd != -1) @@ -2450,10 +2499,14 @@ static int init_inotify(uv_loop_t* loop) { if (fd < 0) return UV__ERR(errno); - loop->inotify_fd = fd; - uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); - uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); + err = uv__io_init_start(loop, &loop->inotify_read_watcher, uv__inotify_read, + fd, POLLIN); + if (err) { + uv__close(fd); + return err; + } + loop->inotify_fd = fd; return 0; } diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index 179ee999d8052e..5d3f0c7a348b33 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -32,12 +32,11 @@ int uv_loop_init(uv_loop_t* loop) { void* saved_data; int err; - saved_data = loop->data; memset(loop, 0, sizeof(*loop)); loop->data = saved_data; - lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields)); + lfields = uv__calloc(1, sizeof(*lfields)); if (lfields == NULL) return UV_ENOMEM; loop->internal_fields = lfields; @@ -116,6 +115,11 @@ int uv_loop_init(uv_loop_t* loop) { fail_signal_init: uv__platform_loop_delete(loop); + if (loop->backend_fd != -1) { + uv__close(loop->backend_fd); + loop->backend_fd = -1; + } + fail_platform_init: uv_mutex_destroy(&lfields->loop_metrics.lock); diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index 9c863b6c90dad9..cf20fa6658209d 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -211,8 +211,16 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { which[1] = HW_CPUSPEED; size = sizeof(cpuspeed); - if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0)) + cpuspeed = 0; + /* + * HW_CPUSPEED can return EOPNOTSUPP if cpuspeed is 0, + * so ignore that and continue the flow, because we + * still care about the rest of the CPU info. + */ + if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0) && + (errno != EOPNOTSUPP)) { goto error; + } size = sizeof(info); for (i = 0; i < numcpus; i++) { diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index 1f9acfac41e9c5..68e225e2e17fbb 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -31,13 +31,15 @@ /* Does the file path contain embedded nul bytes? */ -static int includes_nul(const char *s, size_t n) { +static int includes_invalid_nul(const char *s, size_t n) { if (n == 0) return 0; #ifdef __linux__ - /* Accept abstract socket namespace path ("\0/virtual/path"). */ - s++; - n--; + /* Accept abstract socket namespace paths, throughout which nul bytes have + * no special significance ("\0foo\0bar"). + */ + if (s[0] == '\0') + return 0; #endif return NULL != memchr(s, '\0', n); } @@ -84,7 +86,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; #endif - if (includes_nul(name, namelen)) + if (includes_invalid_nul(name, namelen)) return UV_EINVAL; if (flags & UV_PIPE_NO_TRUNCATE) @@ -271,7 +273,7 @@ int uv_pipe_connect2(uv_connect_t* req, if (namelen == 0) return UV_EINVAL; - if (includes_nul(name, namelen)) + if (includes_invalid_nul(name, namelen)) return UV_EINVAL; if (flags & UV_PIPE_NO_TRUNCATE) @@ -360,6 +362,9 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, char* p; int err; + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + addrlen = sizeof(sa); memset(&sa, 0, addrlen); err = uv__getsockpeername((const uv_handle_t*) handle, @@ -442,13 +447,18 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { int uv_pipe_chmod(uv_pipe_t* handle, int mode) { - unsigned desired_mode; - struct stat pipe_stat; - char* name_buffer; + char name_buffer[1 + UV__PATH_MAX]; + int desired_mode; size_t name_len; + const char* name; + int fd; int r; - if (handle == NULL || uv__stream_fd(handle) == -1) + if (handle == NULL) + return UV_EBADF; + + fd = uv__stream_fd(handle); + if (fd == -1) return UV_EBADF; if (mode != UV_READABLE && @@ -456,46 +466,32 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { mode != (UV_WRITABLE | UV_READABLE)) return UV_EINVAL; - /* Unfortunately fchmod does not work on all platforms, we will use chmod. */ - name_len = 0; - r = uv_pipe_getsockname(handle, NULL, &name_len); - if (r != UV_ENOBUFS) - return r; - - name_buffer = uv__malloc(name_len); - if (name_buffer == NULL) - return UV_ENOMEM; - - r = uv_pipe_getsockname(handle, name_buffer, &name_len); - if (r != 0) { - uv__free(name_buffer); - return r; - } - - /* stat must be used as fstat has a bug on Darwin */ - if (uv__stat(name_buffer, &pipe_stat) == -1) { - uv__free(name_buffer); - return -errno; - } - desired_mode = 0; if (mode & UV_READABLE) desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; if (mode & UV_WRITABLE) desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; - /* Exit early if pipe already has desired mode. */ - if ((pipe_stat.st_mode & desired_mode) == desired_mode) { - uv__free(name_buffer); - return 0; - } + /* fchmod on macOS and (Free|Net|Open)BSD does not support UNIX sockets. */ + if (fchmod(fd, desired_mode)) + if (errno != EINVAL && errno != EOPNOTSUPP) + return UV__ERR(errno); - pipe_stat.st_mode |= desired_mode; + /* Fall back to chmod. */ + name_len = sizeof(name_buffer); + r = uv_pipe_getsockname(handle, name_buffer, &name_len); + if (r != 0) + return r; + name = name_buffer; - r = chmod(name_buffer, pipe_stat.st_mode); - uv__free(name_buffer); + /* On some platforms, getsockname returns an empty string, and we try with pipe_fname. */ + if (name_len == 0 && handle->pipe_fname != NULL) + name = handle->pipe_fname; - return r != -1 ? 0 : UV__ERR(errno); + if (chmod(name, desired_mode)) + return UV__ERR(errno); + + return 0; } @@ -506,7 +502,9 @@ int uv_pipe(uv_os_fd_t fds[2], int read_flags, int write_flags) { defined(__FreeBSD__) || \ defined(__OpenBSD__) || \ defined(__DragonFly__) || \ - defined(__NetBSD__) + defined(__NetBSD__) || \ + defined(__illumos__) || \ + (defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4) int flags = O_CLOEXEC; if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE)) diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c index 7a12e2d1488a9d..535ac6baafc6e0 100644 --- a/deps/uv/src/unix/poll.c +++ b/deps/uv/src/unix/poll.c @@ -24,7 +24,6 @@ #include #include -#include static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index f2038f2c0e823e..43e6b798458fc1 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -188,8 +188,12 @@ void uv__wait_children(uv_loop_t* loop) { static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { int mask; int fd; + int ret; + int size; + int i; mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM; + size = 64 * 1024; switch (container->flags & mask) { case UV_IGNORE: @@ -199,8 +203,17 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { assert(container->data.stream != NULL); if (container->data.stream->type != UV_NAMED_PIPE) return UV_EINVAL; - else - return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0); + else { + ret = uv_socketpair(SOCK_STREAM, 0, fds, 0, 0); + + if (ret == 0) + for (i = 0; i < 2; i++) { + setsockopt(fds[i], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); + setsockopt(fds[i], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); + } + } + + return ret; case UV_INHERIT_FD: case UV_INHERIT_STREAM: diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c index f23c887d0d6788..ccaa72db457c59 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/src/unix/signal.c @@ -259,22 +259,28 @@ static void uv__signal_unregister_handler(int signum) { static int uv__signal_loop_once_init(uv_loop_t* loop) { + int* pipefd; int err; /* Return if already initialized. */ - if (loop->signal_pipefd[0] != -1) + pipefd = loop->signal_pipefd; + if (pipefd[0] != -1) return 0; - err = uv__make_pipe(loop->signal_pipefd, UV_NONBLOCK_PIPE); + err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE); if (err) return err; - uv__io_init(&loop->signal_io_watcher, - uv__signal_event, - loop->signal_pipefd[0]); - uv__io_start(loop, &loop->signal_io_watcher, POLLIN); + err = uv__io_init_start(loop, &loop->signal_io_watcher, uv__signal_event, + pipefd[0], POLLIN); + if (err) { + uv__close(pipefd[0]); + uv__close(pipefd[1]); + pipefd[0] = -1; + pipefd[1] = -1; + } - return 0; + return err; } diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index 2d6bae79604e09..6c38c31aa00efa 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -546,8 +546,15 @@ int uv_fs_event_start(uv_fs_event_t* handle, } if (first_run) { - uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd); - uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN); + err = uv__io_init_start(handle->loop, + &handle->loop->fs_event_watcher, + uv__fs_event_read, + portfd, + POLLIN); + if (err) + uv__handle_stop(handle); + + return err; } return 0; @@ -826,6 +833,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; struct ifaddrs* addrs; struct ifaddrs* ent; + size_t namelen; + char* name; *count = 0; *addresses = NULL; @@ -834,9 +843,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV__ERR(errno); /* Count the number of interfaces */ + namelen = 0; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -845,19 +856,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return 0; } - *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) { + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); + if (*addresses == NULL) { freeifaddrs(addrs); return UV_ENOMEM; } + name = (char*) &(*addresses)[*count]; address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent)) continue; - address->name = uv__strdup(ent->ifa_name); + namelen = strlen(ent->ifa_name) + 1; + address->name = memcpy(name, ent->ifa_name, namelen); + name += namelen; if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); @@ -885,13 +899,7 @@ 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) { - int i; - - for (i = 0; i < count; i++) { - uv__free(addresses[i].name); - } - + int count) { uv__free(addresses); } diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index f05e6fe0f7dd5a..34fea364aebe6d 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -23,6 +23,9 @@ #include "internal.h" #include +#ifdef __OpenBSD__ +#include +#endif #include #include @@ -126,6 +129,12 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { return uv_thread_create_ex(tid, ¶ms, entry, arg); } + +int uv_thread_detach(uv_thread_t *tid) { + return UV__ERR(pthread_detach(*tid)); +} + + int uv_thread_create_ex(uv_thread_t* tid, const uv_thread_options_t* params, void (*entry)(void *arg), @@ -205,7 +214,7 @@ int uv_thread_setaffinity(uv_thread_t* tid, if (cpumask[i]) CPU_SET(i, &cpuset); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__OHOS__) if (sched_setaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset)) r = errno; else @@ -233,7 +242,7 @@ int uv_thread_getaffinity(uv_thread_t* tid, return UV_EINVAL; CPU_ZERO(&cpuset); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__OHOS__) if (sched_getaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset)) r = errno; else @@ -291,6 +300,18 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { return pthread_equal(*t1, *t2); } +int uv_thread_setname(const char* name) { + if (name == NULL) + return UV_EINVAL; + return uv__thread_setname(name); +} + +int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) { + if (name == NULL || size == 0) + return UV_EINVAL; + + return uv__thread_getname(tid, name, size); +} int uv_mutex_init(uv_mutex_t* mutex) { #if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK) @@ -875,3 +896,80 @@ void uv_key_set(uv_key_t* key, void* value) { if (pthread_setspecific(*key, value)) abort(); } + +#if defined(_AIX) || defined(__MVS__) || defined(__PASE__) +int uv__thread_setname(const char* name) { + return UV_ENOSYS; +} +#elif defined(__APPLE__) +int uv__thread_setname(const char* name) { + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + int err = pthread_setname_np(namebuf); + if (err) + return UV__ERR(errno); + return 0; +} +#elif defined(__NetBSD__) +int uv__thread_setname(const char* name) { + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + return UV__ERR(pthread_setname_np(pthread_self(), "%s", namebuf)); +} +#elif defined(__OpenBSD__) +int uv__thread_setname(const char* name) { + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + pthread_set_name_np(pthread_self(), namebuf); + return 0; +} +#else +int uv__thread_setname(const char* name) { + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + return UV__ERR(pthread_setname_np(pthread_self(), namebuf)); +} +#endif + +#if (defined(__ANDROID_API__) && __ANDROID_API__ < 26) || \ + defined(_AIX) || \ + defined(__MVS__) || \ + defined(__PASE__) +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) { + return UV_ENOSYS; +} +#elif defined(__OpenBSD__) +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) { + char thread_name[UV_PTHREAD_MAX_NAMELEN_NP]; + pthread_get_name_np(*tid, thread_name, sizeof(thread_name)); + strncpy(name, thread_name, size - 1); + name[size - 1] = '\0'; + return 0; +} +#elif defined(__APPLE__) +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) { + char thread_name[UV_PTHREAD_MAX_NAMELEN_NP]; + if (pthread_getname_np(*tid, thread_name, sizeof(thread_name)) != 0) + return UV__ERR(errno); + + strncpy(name, thread_name, size - 1); + name[size - 1] = '\0'; + return 0; +} +#else +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) { + int r; + char thread_name[UV_PTHREAD_MAX_NAMELEN_NP]; + r = pthread_getname_np(*tid, thread_name, sizeof(thread_name)); + if (r != 0) + return UV__ERR(r); + + strncpy(name, thread_name, size - 1); + name[size - 1] = '\0'; + return 0; +} +#endif diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index 793054ba5a9bff..b8610720267962 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -284,6 +284,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { int fd; int rc; + if (uv__is_raw_tty_mode(mode)) { + /* There is only a single raw TTY mode on UNIX. */ + mode = UV_TTY_MODE_RAW; + } + if (tty->mode == (int) mode) return 0; @@ -324,6 +329,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { case UV_TTY_MODE_IO: uv__tty_make_raw(&tmp); break; + default: + UNREACHABLE(); } /* Apply changes after draining */ diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index f6640fc7231863..c4a3559d61e350 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -47,6 +47,10 @@ static void uv__udp_sendmsg(uv_udp_t* handle); static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain, unsigned int flags); +static int uv__udp_sendmsg1(int fd, + const uv_buf_t* bufs, + unsigned int nbufs, + const struct sockaddr* addr); void uv__udp_close(uv_udp_t* handle) { @@ -282,169 +286,6 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { && handle->recv_cb != NULL); } -static void uv__udp_sendmsg_one(uv_udp_t* handle, uv_udp_send_t* req) { - struct uv__queue* q; - struct msghdr h; - ssize_t size; - - for (;;) { - memset(&h, 0, sizeof h); - if (req->addr.ss_family == AF_UNSPEC) { - h.msg_name = NULL; - h.msg_namelen = 0; - } else { - h.msg_name = &req->addr; - if (req->addr.ss_family == AF_INET6) - h.msg_namelen = sizeof(struct sockaddr_in6); - else if (req->addr.ss_family == AF_INET) - h.msg_namelen = sizeof(struct sockaddr_in); - else if (req->addr.ss_family == AF_UNIX) - h.msg_namelen = sizeof(struct sockaddr_un); - else { - assert(0 && "unsupported address family"); - abort(); - } - } - h.msg_iov = (struct iovec*) req->bufs; - h.msg_iovlen = req->nbufs; - - do - size = sendmsg(handle->io_watcher.fd, &h, 0); - while (size == -1 && errno == EINTR); - - if (size == -1) - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) - return; - - req->status = (size == -1 ? UV__ERR(errno) : size); - - /* Sending a datagram is an atomic operation: either all data - * is written or nothing is (and EMSGSIZE is raised). That is - * why we don't handle partial writes. Just pop the request - * off the write queue and onto the completed queue, done. - */ - uv__queue_remove(&req->queue); - uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); - uv__io_feed(handle->loop, &handle->io_watcher); - - if (uv__queue_empty(&handle->write_queue)) - return; - - q = uv__queue_head(&handle->write_queue); - req = uv__queue_data(q, uv_udp_send_t, queue); - } -} - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) -static void uv__udp_sendmsg_many(uv_udp_t* handle) { - uv_udp_send_t* req; - struct mmsghdr h[20]; - struct mmsghdr* p; - struct uv__queue* q; - ssize_t npkts; - size_t pkts; - size_t i; - -write_queue_drain: - for (pkts = 0, q = uv__queue_head(&handle->write_queue); - pkts < ARRAY_SIZE(h) && q != &handle->write_queue; - ++pkts, q = uv__queue_head(q)) { - req = uv__queue_data(q, uv_udp_send_t, queue); - - p = &h[pkts]; - memset(p, 0, sizeof(*p)); - if (req->addr.ss_family == AF_UNSPEC) { - p->msg_hdr.msg_name = NULL; - p->msg_hdr.msg_namelen = 0; - } else { - p->msg_hdr.msg_name = &req->addr; - if (req->addr.ss_family == AF_INET6) - p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in6); - else if (req->addr.ss_family == AF_INET) - p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in); - else if (req->addr.ss_family == AF_UNIX) - p->msg_hdr.msg_namelen = sizeof(struct sockaddr_un); - else { - assert(0 && "unsupported address family"); - abort(); - } - } - h[pkts].msg_hdr.msg_iov = (struct iovec*) req->bufs; - h[pkts].msg_hdr.msg_iovlen = req->nbufs; - } - -#if defined(__APPLE__) - do - npkts = sendmsg_x(handle->io_watcher.fd, h, pkts, MSG_DONTWAIT); - while (npkts == -1 && errno == EINTR); -#else - do - npkts = sendmmsg(handle->io_watcher.fd, h, pkts, 0); - while (npkts == -1 && errno == EINTR); -#endif - - if (npkts < 1) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) - return; - for (i = 0, q = uv__queue_head(&handle->write_queue); - i < pkts && q != &handle->write_queue; - ++i, q = uv__queue_head(&handle->write_queue)) { - req = uv__queue_data(q, uv_udp_send_t, queue); - req->status = UV__ERR(errno); - uv__queue_remove(&req->queue); - uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); - } - uv__io_feed(handle->loop, &handle->io_watcher); - return; - } - - /* Safety: npkts known to be >0 below. Hence cast from ssize_t - * to size_t safe. - */ - for (i = 0, q = uv__queue_head(&handle->write_queue); - i < (size_t)npkts && q != &handle->write_queue; - ++i, q = uv__queue_head(&handle->write_queue)) { - req = uv__queue_data(q, uv_udp_send_t, queue); - req->status = req->bufs[0].len; - - /* Sending a datagram is an atomic operation: either all data - * is written or nothing is (and EMSGSIZE is raised). That is - * why we don't handle partial writes. Just pop the request - * off the write queue and onto the completed queue, done. - */ - uv__queue_remove(&req->queue); - uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); - } - - /* couldn't batch everything, continue sending (jump to avoid stack growth) */ - if (!uv__queue_empty(&handle->write_queue)) - goto write_queue_drain; - - uv__io_feed(handle->loop, &handle->io_watcher); -} -#endif /* __linux__ || ____FreeBSD__ || __APPLE__ */ - -static void uv__udp_sendmsg(uv_udp_t* handle) { - struct uv__queue* q; - uv_udp_send_t* req; - - if (uv__queue_empty(&handle->write_queue)) - return; - - q = uv__queue_head(&handle->write_queue); - req = uv__queue_data(q, uv_udp_send_t, queue); - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) - /* Use sendmmsg() if this send request contains more than one datagram OR - * there is more than one send request (because that automatically implies - * there is more than one datagram.) - */ - if (req->nbufs != 1 || &handle->write_queue != uv__queue_next(&req->queue)) - return uv__udp_sendmsg_many(handle); -#endif - - return uv__udp_sendmsg_one(handle, req); -} /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional * refinements for programs that use multicast. Therefore we preferentially @@ -459,6 +300,9 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { * * zOS does not support getsockname with SO_REUSEPORT option when using * AF_UNIX. + * + * Solaris 11.4: SO_REUSEPORT will not load balance when SO_REUSEADDR + * is also set, but it's not valid for every socket type. */ static int uv__sock_reuseaddr(int fd) { int yes; @@ -476,8 +320,18 @@ static int uv__sock_reuseaddr(int fd) { if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); } -#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) && \ - !defined(__sun__) && !defined(__DragonFly__) && !defined(_AIX73) +#elif defined(SO_REUSEPORT) && defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4 + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) { + if (errno != ENOPROTOOPT) + return UV__ERR(errno); + /* Not all socket types accept SO_REUSEPORT. */ + errno = 0; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) + return UV__ERR(errno); + } +#elif defined(SO_REUSEPORT) && \ + !defined(__linux__) && !defined(__GNU__) && \ + !defined(__illumos__) && !defined(__DragonFly__) && !defined(_AIX73) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); #else @@ -743,11 +597,11 @@ int uv__udp_send(uv_udp_send_t* req, empty_queue = (handle->send_queue_count == 0); uv__req_init(handle->loop, req, UV_UDP_SEND); - assert(addrlen <= sizeof(req->addr)); + assert(addrlen <= sizeof(req->u.storage)); if (addr == NULL) - req->addr.ss_family = AF_UNSPEC; + req->u.storage.ss_family = AF_UNSPEC; else - memcpy(&req->addr, addr, addrlen); + memcpy(&req->u.storage, addr, addrlen); req->send_cb = send_cb; req->handle = handle; req->nbufs = nbufs; @@ -790,10 +644,9 @@ int uv__udp_try_send(uv_udp_t* handle, const struct sockaddr* addr, unsigned int addrlen) { int err; - struct msghdr h; - ssize_t size; - assert(nbufs > 0); + if (nbufs < 1) + return UV_EINVAL; /* already sending a message */ if (handle->send_queue_count != 0) @@ -807,24 +660,11 @@ int uv__udp_try_send(uv_udp_t* handle, assert(handle->flags & UV_HANDLE_UDP_CONNECTED); } - memset(&h, 0, sizeof h); - h.msg_name = (struct sockaddr*) addr; - h.msg_namelen = addrlen; - h.msg_iov = (struct iovec*) bufs; - h.msg_iovlen = nbufs; - - do { - size = sendmsg(handle->io_watcher.fd, &h, 0); - } while (size == -1 && errno == EINTR); - - if (size == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) - return UV_EAGAIN; - else - return UV__ERR(errno); - } + err = uv__udp_sendmsg1(handle->io_watcher.fd, bufs, nbufs, addr); + if (err > 0) + return uv__count_bufs(bufs, nbufs); - return size; + return err; } @@ -1401,3 +1241,194 @@ int uv__udp_recv_stop(uv_udp_t* handle) { return 0; } + + +static int uv__udp_prep_pkt(struct msghdr* h, + const uv_buf_t* bufs, + const unsigned int nbufs, + const struct sockaddr* addr) { + memset(h, 0, sizeof(*h)); + h->msg_name = (void*) addr; + h->msg_iov = (void*) bufs; + h->msg_iovlen = nbufs; + if (addr == NULL) + return 0; + switch (addr->sa_family) { + case AF_INET: + h->msg_namelen = sizeof(struct sockaddr_in); + return 0; + case AF_INET6: + h->msg_namelen = sizeof(struct sockaddr_in6); + return 0; + case AF_UNIX: + h->msg_namelen = sizeof(struct sockaddr_un); + return 0; + case AF_UNSPEC: + h->msg_name = NULL; + return 0; + } + return UV_EINVAL; +} + + +static int uv__udp_sendmsg1(int fd, + const uv_buf_t* bufs, + unsigned int nbufs, + const struct sockaddr* addr) { + struct msghdr h; + int r; + + if ((r = uv__udp_prep_pkt(&h, bufs, nbufs, addr))) + return r; + + do + r = sendmsg(fd, &h, 0); + while (r == -1 && errno == EINTR); + + if (r < 0) { + r = UV__ERR(errno); + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) + r = UV_EAGAIN; + return r; + } + + /* 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; +} + + +static int uv__udp_sendmsgv(int fd, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/]) { + unsigned int i; + int nsent; + int r; + + r = 0; + nsent = 0; + +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ + (defined(__sun__) && defined(MSG_WAITFORONE)) + if (count > 1) { + for (i = 0; i < count; /*empty*/) { + struct mmsghdr m[20]; + unsigned int n; + + for (n = 0; i < count && n < ARRAY_SIZE(m); i++, n++) + if ((r = uv__udp_prep_pkt(&m[n].msg_hdr, bufs[i], nbufs[i], addrs[i]))) + goto exit; + + do +#if defined(__APPLE__) + r = sendmsg_x(fd, m, n, MSG_DONTWAIT); +#else + r = sendmmsg(fd, m, n, 0); +#endif + while (r == -1 && errno == EINTR); + + if (r < 1) + goto exit; + + nsent += r; + i += r; + } + + goto exit; + } +#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || + * (defined(__sun__) && defined(MSG_WAITFORONE)) + */ + + for (i = 0; i < count; i++, nsent++) + if ((r = uv__udp_sendmsg1(fd, bufs[i], nbufs[i], addrs[i]))) + goto exit; /* goto to avoid unused label warning. */ + +exit: + + if (nsent > 0) + return nsent; + + if (r < 0) { + r = UV__ERR(errno); + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) + r = UV_EAGAIN; + } + + return r; +} + + +static void uv__udp_sendmsg(uv_udp_t* handle) { + static const int N = 20; + struct sockaddr* addrs[N]; + unsigned int nbufs[N]; + uv_buf_t* bufs[N]; + struct uv__queue* q; + uv_udp_send_t* req; + int n; + + if (uv__queue_empty(&handle->write_queue)) + return; + +again: + n = 0; + q = uv__queue_head(&handle->write_queue); + do { + req = uv__queue_data(q, uv_udp_send_t, queue); + addrs[n] = &req->u.addr; + nbufs[n] = req->nbufs; + bufs[n] = req->bufs; + q = uv__queue_next(q); + n++; + } while (n < N && q != &handle->write_queue); + + n = uv__udp_sendmsgv(handle->io_watcher.fd, n, bufs, nbufs, addrs); + while (n > 0) { + q = uv__queue_head(&handle->write_queue); + req = uv__queue_data(q, uv_udp_send_t, queue); + req->status = uv__count_bufs(req->bufs, req->nbufs); + uv__queue_remove(&req->queue); + uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); + n--; + } + + if (n == 0) { + if (uv__queue_empty(&handle->write_queue)) + goto feed; + goto again; + } + + if (n == UV_EAGAIN) + return; + + /* Register the error against first request in queue because that + * is the request that uv__udp_sendmsgv tried but failed to send, + * because if it did send any requests, it won't return an error. + */ + q = uv__queue_head(&handle->write_queue); + req = uv__queue_data(q, uv_udp_send_t, queue); + req->status = n; + uv__queue_remove(&req->queue); + uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); +feed: + uv__io_feed(handle->loop, &handle->io_watcher); +} + + +int uv__udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/]) { + int fd; + + fd = handle->io_watcher.fd; + if (fd == -1) + return UV_EINVAL; + + return uv__udp_sendmsgv(fd, count, bufs, nbufs, addrs); +} diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 2200fe3f0a41e2..60ff56b9dd7391 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -514,6 +514,25 @@ int uv_udp_try_send(uv_udp_t* handle, } +int uv_udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/], + unsigned int flags) { + if (count < 1) + return UV_EINVAL; + + if (flags != 0) + return UV_EINVAL; + + if (handle->send_queue_count > 0) + return UV_EAGAIN; + + return uv__udp_try_send2(handle, count, bufs, nbufs, addrs); +} + + int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb) { @@ -644,6 +663,9 @@ int uv_send_buffer_size(uv_handle_t* handle, int *value) { int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) { size_t required_len; + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + if (!uv__is_active(handle)) { *size = 0; return UV_EINVAL; diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index 4baede2e506ee1..b9a8e976eefdd6 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "uv.h" #include "uv/tree.h" @@ -125,7 +126,7 @@ enum { /* Only used by uv_tty_t handles. */ UV_HANDLE_TTY_READABLE = 0x01000000, - UV_HANDLE_TTY_RAW = 0x02000000, + UV_HANDLE_UNUSED0 = 0x02000000, UV_HANDLE_TTY_SAVED_POSITION = 0x04000000, UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000, @@ -140,6 +141,10 @@ enum { UV_HANDLE_REAP = 0x10000000 }; +static inline int uv__is_raw_tty_mode(uv_tty_mode_t m) { + return m == UV_TTY_MODE_RAW || m == UV_TTY_MODE_RAW_VT; +} + int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); void uv__loop_close(uv_loop_t* loop); @@ -191,6 +196,12 @@ int uv__udp_try_send(uv_udp_t* handle, const struct sockaddr* addr, unsigned int addrlen); +int uv__udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/]); + int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb, uv_udp_recv_cb recv_cb); @@ -428,4 +439,36 @@ struct uv__loop_internal_fields_s { #endif /* __linux__ */ }; +#if defined(_WIN32) +# define UV_PTHREAD_MAX_NAMELEN_NP 32767 +#elif defined(__APPLE__) +# define UV_PTHREAD_MAX_NAMELEN_NP 64 +#elif defined(__NetBSD__) || defined(__illumos__) +# define UV_PTHREAD_MAX_NAMELEN_NP PTHREAD_MAX_NAMELEN_NP +#elif defined (__linux__) +# define UV_PTHREAD_MAX_NAMELEN_NP 16 +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +# define UV_PTHREAD_MAX_NAMELEN_NP (MAXCOMLEN + 1) +#else +# define UV_PTHREAD_MAX_NAMELEN_NP 16 +#endif + +/* Open-coded so downstream users don't have to link libm. */ +static inline int uv__isinf(double d) { + uint64_t v; + + STATIC_ASSERT(sizeof(v) == sizeof(d)); + memcpy(&v, &d, sizeof(v)); + return (v << 1 >> 53) == 2047 && !(v << 12); +} + +/* Open-coded so downstream users don't have to link libm. */ +static inline int uv__isnan(double d) { + uint64_t v; + + STATIC_ASSERT(sizeof(v) == sizeof(d)); + memcpy(&v, &d, sizeof(v)); + return (v << 1 >> 53) == 2047 && !!(v << 12); +} + #endif /* UV_COMMON_H_ */ diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index e9885a0f1ff389..5f41c87ad5ed13 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -114,7 +114,7 @@ static int uv__loops_add(uv_loop_t* loop) { failed_loops_realloc: uv_mutex_unlock(&uv__loops_lock); - return ERROR_OUTOFMEMORY; + return UV_ENOMEM; } @@ -423,97 +423,6 @@ int uv_backend_timeout(const uv_loop_t* loop) { } -static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { - uv__loop_internal_fields_t* lfields; - DWORD bytes; - ULONG_PTR key; - OVERLAPPED* overlapped; - uv_req_t* req; - int repeat; - uint64_t timeout_time; - uint64_t user_timeout; - int reset_timeout; - - lfields = uv__get_internal_fields(loop); - timeout_time = loop->time + timeout; - - if (lfields->flags & UV_METRICS_IDLE_TIME) { - reset_timeout = 1; - user_timeout = timeout; - timeout = 0; - } else { - reset_timeout = 0; - } - - for (repeat = 0; ; repeat++) { - /* 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; - - GetQueuedCompletionStatus(loop->iocp, - &bytes, - &key, - &overlapped, - timeout); - - if (reset_timeout != 0) { - if (overlapped && timeout == 0) - uv__metrics_inc_events_waiting(loop, 1); - timeout = user_timeout; - reset_timeout = 0; - } - - /* Placed here because on success the loop will break whether there is an - * empty package or not, or if GetQueuedCompletionStatus returned early then - * the timeout will be updated and the loop will run again. In either case - * the idle time will need to be updated. - */ - uv__metrics_update_idle_time(loop); - - if (overlapped) { - uv__metrics_inc_events(loop, 1); - - /* Package was dequeued */ - req = uv__overlapped_to_req(overlapped); - uv__insert_pending_req(loop, req); - - /* Some time might have passed waiting for I/O, - * so update the loop time here. - */ - uv_update_time(loop); - } else if (GetLastError() != WAIT_TIMEOUT) { - /* Serious error */ - uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); - } else if (timeout > 0) { - /* GetQueuedCompletionStatus can occasionally return a little early. - * Make sure that the desired timeout target time is reached. - */ - uv_update_time(loop); - if (timeout_time > loop->time) { - timeout = (DWORD)(timeout_time - loop->time); - /* The first call to GetQueuedCompletionStatus should return very - * close to the target time and the second should reach it, but - * this is not stated in the documentation. To make sure a busy - * loop cannot happen, the timeout is increased exponentially - * starting on the third round. - */ - timeout += repeat ? (1 << (repeat - 1)) : 0; - continue; - } - } - break; - } -} - - static void uv__poll(uv_loop_t* loop, DWORD timeout) { uv__loop_internal_fields_t* lfields; BOOL success; @@ -553,12 +462,12 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { */ lfields->current_timeout = timeout; - success = pGetQueuedCompletionStatusEx(loop->iocp, - overlappeds, - ARRAY_SIZE(overlappeds), - &count, - timeout, - FALSE); + success = GetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); if (reset_timeout != 0) { timeout = user_timeout; @@ -566,7 +475,7 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { } /* Placed here because on success the loop will break whether there is an - * empty package or not, or if pGetQueuedCompletionStatusEx returned early + * empty package or not, or if GetQueuedCompletionStatusEx returned early * then the timeout will be updated and the loop will run again. In either * case the idle time will need to be updated. */ @@ -647,10 +556,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { uv__metrics_inc_loop_count(loop); - if (pGetQueuedCompletionStatusEx) - uv__poll(loop, timeout); - else - uv__poll_wine(loop, timeout); + uv__poll(loop, timeout); /* Process immediate callbacks (e.g. write_cb) a small fixed number of * times to avoid loop starvation.*/ diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 7ab407e05345f9..1bbb8c52be2d82 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -253,6 +253,8 @@ int uv_fs_event_start(uv_fs_event_t* handle, } dir_to_watch = dir; + uv__free(short_path); + short_path = NULL; uv__free(pathw); pathw = NULL; } @@ -577,6 +579,8 @@ void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req, info.DeletePending) { uv__convert_utf16_to_utf8(handle->dirw, -1, &filename); handle->cb(handle, filename, UV_RENAME, 0); + uv__free(filename); + filename = NULL; } else { handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); } diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index f2215bb3082178..27248f644f381b 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -58,6 +58,19 @@ #define FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE 0x0010 #endif /* FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE */ +NTSTATUS uv__RtlUnicodeStringInit( + PUNICODE_STRING DestinationString, + PWSTR SourceString, + size_t SourceStringLen +) { + if (SourceStringLen > 0x7FFF) + return STATUS_INVALID_PARAMETER; + DestinationString->MaximumLength = DestinationString->Length = + SourceStringLen * sizeof(SourceString[0]); + DestinationString->Buffer = SourceString; + return STATUS_SUCCESS; +} + #define INIT(subtype) \ do { \ if (req == NULL) \ @@ -1689,12 +1702,12 @@ INLINE 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. + /* Check if the new fast API is available. */ if (!pGetFileInformationByName) { return FS__STAT_PATH_TRY_SLOW; } - // Check if the API call fails. + /* Check if the API call fails. */ if (!pGetFileInformationByName(path, FileStatBasicByNameInfo, &stat_info, sizeof(stat_info))) { switch(GetLastError()) { @@ -1708,7 +1721,7 @@ INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path, return FS__STAT_PATH_TRY_SLOW; } - // A file handle is needed to get st_size for links. + /* A file handle is needed to get st_size for links. */ if ((stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { return FS__STAT_PATH_TRY_SLOW; } @@ -1775,7 +1788,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, SetLastError(pRtlNtStatusToDosError(nt_status)); return -1; } else { - stat_info.VolumeSerialNumber.QuadPart = volume_info.VolumeSerialNumber; + stat_info.VolumeSerialNumber.LowPart = volume_info.VolumeSerialNumber; } stat_info.DeviceType = device_info.DeviceType; @@ -1802,7 +1815,6 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, * detect this failure and retry without do_lstat if appropriate. */ if (fs__readlink_handle(handle, NULL, &target_length) != 0) { - fs__stat_assign_statbuf(statbuf, stat_info, do_lstat); return -1; } stat_info.EndOfFile.QuadPart = target_length; @@ -1827,7 +1839,7 @@ 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) { - statbuf->st_dev = stat_info.VolumeSerialNumber.QuadPart; + statbuf->st_dev = stat_info.VolumeSerialNumber.LowPart; /* Todo: st_mode should probably always be 0666 for everyone. We might also * want to report 0777 if the file is a .exe or a directory. @@ -1941,6 +1953,179 @@ INLINE static void fs__stat_prepare_path(WCHAR* pathw) { } } +INLINE 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; + FILE_FS_VOLUME_INFORMATION volume_info; + FILE_FS_DEVICE_INFORMATION device_info; + IO_STATUS_BLOCK io_status; + NTSTATUS nt_status; + WCHAR* path_dirpath = NULL; + WCHAR* path_filename = NULL; + UNICODE_STRING FileMask; + size_t len; + size_t split; + WCHAR splitchar; + int includes_name; + + /* AKA strtok or wcscspn, in reverse. */ + len = wcslen(path); + split = len; + + includes_name = 0; + while (split > 0 && path[split - 1] != L'\\' && path[split - 1] != L'/' && + path[split - 1] != L':') { + /* check if the path contains a character other than /,\,:,. */ + if (path[split-1] != '.') { + includes_name = 1; + } + split--; + } + /* If the path is a relative path with a file name or a folder name */ + if (split == 0 && includes_name) { + path_dirpath = L"."; + /* If there is a slash or a backslash */ + } else if (path[split - 1] == L'\\' || path[split - 1] == L'/') { + path_dirpath = path; + /* If there is no filename, consider it as a relative folder path */ + if (!includes_name) { + split = len; + /* Else, split it */ + } else { + splitchar = path[split - 1]; + path[split - 1] = L'\0'; + } + /* e.g. "..", "c:" */ + } else { + path_dirpath = path; + split = len; + } + path_filename = &path[split]; + + len = 0; + while (1) { + if (path_filename[len] == L'\0') + break; + if (path_filename[len] == L'*' || path_filename[len] == L'?' || + path_filename[len] == L'>' || path_filename[len] == L'<' || + path_filename[len] == L'"') { + ret_error = ERROR_INVALID_NAME; + goto cleanup; + } + len++; + } + + /* Get directory handle */ + handle = CreateFileW(path_dirpath, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + ret_error = GetLastError(); + goto cleanup; + } + + /* Get files in the directory */ + nt_status = uv__RtlUnicodeStringInit(&FileMask, path_filename, len); + if (!NT_SUCCESS(nt_status)) { + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; + } + nt_status = pNtQueryDirectoryFile(handle, + NULL, + NULL, + NULL, + &io_status, + &dir_info, + sizeof(dir_info), + FileIdFullDirectoryInformation, + TRUE, + &FileMask, + TRUE); + + /* Buffer overflow (a warning status code) is expected here since there isn't + * enough space to store the FileName, and actually indicates success. */ + if (!NT_SUCCESS(nt_status) && nt_status != STATUS_BUFFER_OVERFLOW) { + if (nt_status == STATUS_NO_MORE_FILES) + ret_error = ERROR_PATH_NOT_FOUND; + else + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; + } + + /* Assign values to stat_info */ + memset(&stat_info, 0, sizeof(FILE_STAT_BASIC_INFORMATION)); + stat_info.FileAttributes = dir_info.FileAttributes; + stat_info.CreationTime.QuadPart = dir_info.CreationTime.QuadPart; + stat_info.LastAccessTime.QuadPart = dir_info.LastAccessTime.QuadPart; + stat_info.LastWriteTime.QuadPart = dir_info.LastWriteTime.QuadPart; + if (stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + /* A file handle is needed to get st_size for the link (from + * FSCTL_GET_REPARSE_POINT), which is required by posix, but we are here + * because getting the file handle failed. We could get just the + * ReparsePointTag by querying FILE_ID_EXTD_DIR_INFORMATION instead to make + * sure this really is a link before giving up here on the uv_fs_stat call, + * but that doesn't seem essential. */ + if (!do_lstat) + goto cleanup; + stat_info.EndOfFile.QuadPart = 0; + stat_info.AllocationSize.QuadPart = 0; + } else { + stat_info.EndOfFile.QuadPart = dir_info.EndOfFile.QuadPart; + stat_info.AllocationSize.QuadPart = dir_info.AllocationSize.QuadPart; + } + stat_info.ChangeTime.QuadPart = dir_info.ChangeTime.QuadPart; + stat_info.FileId.QuadPart = dir_info.FileId.QuadPart; + + /* Finish up by getting device info from the directory handle, + * since files presumably must live on their device. */ + nt_status = pNtQueryVolumeInformationFile(handle, + &io_status, + &volume_info, + sizeof volume_info, + FileFsVolumeInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (io_status.Status == STATUS_NOT_IMPLEMENTED) { + stat_info.VolumeSerialNumber.QuadPart = 0; + } else if (NT_ERROR(nt_status)) { + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; + } else { + stat_info.VolumeSerialNumber.QuadPart = volume_info.VolumeSerialNumber; + } + + nt_status = pNtQueryVolumeInformationFile(handle, + &io_status, + &device_info, + sizeof device_info, + FileFsDeviceInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (NT_ERROR(nt_status)) { + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; + } + + stat_info.DeviceType = device_info.DeviceType; + stat_info.NumberOfLinks = 1; /* No way to recover this info. */ + + fs__stat_assign_statbuf(statbuf, stat_info, do_lstat); + ret_error = 0; + +cleanup: + if (split != 0) + path[split - 1] = splitchar; + if (handle != INVALID_HANDLE_VALUE) + CloseHandle(handle); + return ret_error; +} INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, int do_lstat, @@ -1949,7 +2134,7 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, DWORD flags; DWORD ret; - // If new API exists, try to use it. + /* If new API exists, try to use it. */ switch (fs__stat_path(path, statbuf, do_lstat)) { case FS__STAT_PATH_SUCCESS: return 0; @@ -1959,7 +2144,7 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, break; } - // If the new API does not exist, use the old API. + /* If the new API does not exist, use the old API. */ flags = FILE_FLAG_BACKUP_SEMANTICS; if (do_lstat) flags |= FILE_FLAG_OPEN_REPARSE_POINT; @@ -1972,8 +2157,12 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, flags, NULL); - if (handle == INVALID_HANDLE_VALUE) - return GetLastError(); + if (handle == INVALID_HANDLE_VALUE) { + ret = GetLastError(); + if (ret != ERROR_ACCESS_DENIED && ret != ERROR_SHARING_VIOLATION) + return ret; + return fs__stat_directory(path, statbuf, do_lstat, ret); + } if (fs__stat_handle(handle, statbuf, do_lstat) != 0) ret = GetLastError(); @@ -2391,14 +2580,29 @@ static void fs__fchmod(uv_fs_t* req) { INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { - FILETIME filetime_a, filetime_m; + FILETIME filetime_as, *filetime_a = &filetime_as; + FILETIME filetime_ms, *filetime_m = &filetime_ms; + FILETIME now; - TIME_T_TO_FILETIME(atime, &filetime_a); - TIME_T_TO_FILETIME(mtime, &filetime_m); + if (uv__isinf(atime) || uv__isinf(mtime)) + GetSystemTimeAsFileTime(&now); - if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) { + if (uv__isinf(atime)) + filetime_a = &now; + else if (uv__isnan(atime)) + filetime_a = NULL; + else + TIME_T_TO_FILETIME(atime, filetime_a); + + if (uv__isinf(mtime)) + filetime_m = &now; + else if (uv__isnan(mtime)) + filetime_m = NULL; + else + TIME_T_TO_FILETIME(mtime, filetime_m); + + if (!SetFileTime(handle, NULL, filetime_a, filetime_m)) return -1; - } return 0; } diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index d46ecb9fc702e6..d05bfd28aec8b9 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -1161,9 +1161,9 @@ int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) { err = uv__tcp_xfer_import( (uv_tcp_t*) client, item->xfer_type, &item->xfer_info); - + uv__free(item); - + if (err != 0) return err; @@ -1738,7 +1738,7 @@ static DWORD uv__pipe_get_ipc_remote_pid(uv_pipe_t* handle) { GetNamedPipeServerProcessId(handle->handle, pid); } } - + return *pid; } @@ -2602,6 +2602,9 @@ int uv_pipe_pending_count(uv_pipe_t* handle) { int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) { + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + if (handle->flags & UV_HANDLE_BOUND) return uv__pipe_getname(handle, buffer, size); @@ -2616,6 +2619,9 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) { int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) { + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + /* emulate unix behaviour */ if (handle->flags & UV_HANDLE_BOUND) return UV_ENOTCONN; diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index 9d48ddc6f84d6f..27605ca36f4434 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -898,7 +898,7 @@ int uv_spawn(uv_loop_t* loop, *env = NULL, *cwd = NULL; STARTUPINFOW startup; PROCESS_INFORMATION info; - DWORD process_flags; + DWORD process_flags, cwd_len; BYTE* child_stdio_buffer; uv__process_init(loop, process); @@ -947,9 +947,10 @@ int uv_spawn(uv_loop_t* loop, if (err) goto done_uv; + cwd_len = wcslen(cwd); } else { /* Inherit cwd */ - DWORD cwd_len, r; + DWORD r; cwd_len = GetCurrentDirectoryW(0, NULL); if (!cwd_len) { @@ -970,6 +971,15 @@ int uv_spawn(uv_loop_t* loop, } } + /* If cwd is too long, shorten it */ + if (cwd_len >= MAX_PATH) { + cwd_len = GetShortPathNameW(cwd, cwd, cwd_len); + if (cwd_len == 0) { + err = GetLastError(); + goto done; + } + } + /* Get PATH environment variable. */ path = find_path(env); if (path == NULL) { diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c index bf39b88633b0d8..753cb6a34a5b9a 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -57,6 +57,9 @@ STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*)); static uv_key_t uv__current_thread_key; static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT; +static uv_once_t uv__thread_name_once = UV_ONCE_INIT; +HRESULT (WINAPI *pGetThreadDescription)(HANDLE, PWSTR*); +HRESULT (WINAPI *pSetThreadDescription)(HANDLE, PCWSTR); static void uv__init_current_thread_key(void) { @@ -95,6 +98,15 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { return uv_thread_create_ex(tid, ¶ms, entry, arg); } + +int uv_thread_detach(uv_thread_t *tid) { + if (CloseHandle(*tid) == 0) + return uv_translate_sys_error(GetLastError()); + + return 0; +} + + int uv_thread_create_ex(uv_thread_t* tid, const uv_thread_options_t* params, void (*entry)(void *arg), @@ -269,6 +281,92 @@ 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"); + if (m != NULL) { + pGetThreadDescription = (void*) GetProcAddress(m, "GetThreadDescription"); + pSetThreadDescription = (void*) GetProcAddress(m, "SetThreadDescription"); + } +} + + +int uv_thread_setname(const char* name) { + HRESULT hr; + WCHAR* namew; + int err; + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + + uv_once(&uv__thread_name_once, uv__thread_name_init_once); + + if (pSetThreadDescription == NULL) + return UV_ENOSYS; + + if (name == NULL) + return UV_EINVAL; + + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + + namew = NULL; + err = uv__convert_utf8_to_utf16(namebuf, &namew); + if (err) + return err; + + hr = pSetThreadDescription(GetCurrentThread(), namew); + uv__free(namew); + if (FAILED(hr)) + return uv_translate_sys_error(HRESULT_CODE(hr)); + + return 0; +} + + +int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) { + HRESULT hr; + WCHAR* namew; + char* thread_name; + size_t buf_size; + int r; + DWORD exit_code; + + uv_once(&uv__thread_name_once, uv__thread_name_init_once); + + if (pGetThreadDescription == NULL) + return UV_ENOSYS; + + if (name == NULL || size == 0) + return UV_EINVAL; + + if (tid == NULL || *tid == NULL) + return UV_EINVAL; + + /* Check if the thread handle is valid */ + if (!GetExitCodeThread(*tid, &exit_code) || exit_code != STILL_ACTIVE) + return UV_ENOENT; + + namew = NULL; + thread_name = NULL; + hr = pGetThreadDescription(*tid, &namew); + if (FAILED(hr)) + return uv_translate_sys_error(HRESULT_CODE(hr)); + + buf_size = size; + r = uv__copy_utf16_to_utf8(namew, -1, name, &buf_size); + if (r == UV_ENOBUFS) { + r = uv__convert_utf16_to_utf8(namew, wcslen(namew), &thread_name); + if (r == 0) { + uv__strscpy(name, thread_name, size); + uv__free(thread_name); + } + } + + LocalFree(namew); + return r; +} + + int uv_mutex_init(uv_mutex_t* mutex) { InitializeCriticalSection(mutex); return 0; diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index c0339ded2e4b76..66ca99cda83ab1 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -58,6 +58,9 @@ #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endif +#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT +#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 +#endif #define CURSOR_SIZE_SMALL 25 #define CURSOR_SIZE_LARGE 100 @@ -119,7 +122,10 @@ static int uv_tty_virtual_width = -1; * handle signalling SIGWINCH */ -static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE; +static HANDLE uv__tty_console_handle_out = INVALID_HANDLE_VALUE; +static HANDLE uv__tty_console_handle_in = INVALID_HANDLE_VALUE; +static DWORD uv__tty_console_in_original_mode = (DWORD)-1; +static volatile LONG uv__tty_console_in_need_mode_reset = 0; static int uv__tty_console_height = -1; static int uv__tty_console_width = -1; static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE; @@ -159,19 +165,21 @@ static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED; static void uv__determine_vterm_state(HANDLE handle); void uv__console_init(void) { + DWORD dwMode; + if (uv_sem_init(&uv_tty_output_lock, 1)) abort(); - uv__tty_console_handle = CreateFileW(L"CONOUT$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - 0, - 0); - if (uv__tty_console_handle != INVALID_HANDLE_VALUE) { + uv__tty_console_handle_out = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + 0, + 0); + if (uv__tty_console_handle_out != INVALID_HANDLE_VALUE) { CONSOLE_SCREEN_BUFFER_INFO sb_info; uv_mutex_init(&uv__tty_console_resize_mutex); - if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) { + if (GetConsoleScreenBufferInfo(uv__tty_console_handle_out, &sb_info)) { uv__tty_console_width = sb_info.dwSize.X; uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; } @@ -179,6 +187,18 @@ void uv__console_init(void) { NULL, WT_EXECUTELONGFUNCTION); } + uv__tty_console_handle_in = CreateFileW(L"CONIN$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + 0, + OPEN_EXISTING, + 0, + 0); + if (uv__tty_console_handle_in != INVALID_HANDLE_VALUE) { + if (GetConsoleMode(uv__tty_console_handle_in, &dwMode)) { + uv__tty_console_in_original_mode = dwMode; + } + } } @@ -253,7 +273,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { /* Initialize TTY input specific fields. */ tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE; /* TODO: remove me in v2.x. */ - tty->tty.rd.unused_ = NULL; + tty->tty.rd.mode.unused_ = NULL; + /* Partially overwrites unused_ again. */ + tty->tty.rd.mode.mode = 0; tty->tty.rd.read_line_buffer = uv_null_buf_; tty->tty.rd.read_raw_wait = NULL; @@ -344,6 +366,7 @@ static void uv__tty_capture_initial_style( int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { DWORD flags; + DWORD try_set_flags; unsigned char was_reading; uv_alloc_cb alloc_cb; uv_read_cb read_cb; @@ -353,14 +376,19 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { return UV_EINVAL; } - if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) { + if ((int)mode == tty->tty.rd.mode.mode) { return 0; } + try_set_flags = 0; switch (mode) { case UV_TTY_MODE_NORMAL: flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; break; + case UV_TTY_MODE_RAW_VT: + try_set_flags = ENABLE_VIRTUAL_TERMINAL_INPUT; + InterlockedExchange(&uv__tty_console_in_need_mode_reset, 1); + /* fallthrough */ case UV_TTY_MODE_RAW: flags = ENABLE_WINDOW_INPUT; break; @@ -386,16 +414,16 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { } uv_sem_wait(&uv_tty_output_lock); - if (!SetConsoleMode(tty->handle, flags)) { + if (!SetConsoleMode(tty->handle, flags | try_set_flags) && + !SetConsoleMode(tty->handle, flags)) { err = uv_translate_sys_error(GetLastError()); uv_sem_post(&uv_tty_output_lock); return err; } uv_sem_post(&uv_tty_output_lock); - /* Update flag. */ - tty->flags &= ~UV_HANDLE_TTY_RAW; - tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0; + /* Update mode. */ + tty->tty.rd.mode.mode = mode; /* If we just stopped reading, restart. */ if (was_reading) { @@ -614,7 +642,7 @@ static void uv__tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { static void uv__tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) { - if (handle->flags & UV_HANDLE_TTY_RAW) { + if (uv__is_raw_tty_mode(handle->tty.rd.mode.mode)) { uv__tty_queue_read_raw(loop, handle); } else { uv__tty_queue_read_line(loop, handle); @@ -702,7 +730,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, handle->flags &= ~UV_HANDLE_READ_PENDING; if (!(handle->flags & UV_HANDLE_READING) || - !(handle->flags & UV_HANDLE_TTY_RAW)) { + !(uv__is_raw_tty_mode(handle->tty.rd.mode.mode))) { goto out; } @@ -1050,7 +1078,7 @@ int uv__tty_read_stop(uv_tty_t* handle) { if (!(handle->flags & UV_HANDLE_READ_PENDING)) return 0; - if (handle->flags & UV_HANDLE_TTY_RAW) { + if (uv__is_raw_tty_mode(handle->tty.rd.mode.mode)) { /* Cancel raw read. Write some bullshit event to force the console wait to * return. */ memset(&record, 0, sizeof record); @@ -2293,7 +2321,17 @@ void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { int uv_tty_reset_mode(void) { - /* Not necessary to do anything. */ + /** + * Shells on Windows do know to reset output flags after a program exits, + * but not necessarily input flags, so we do that for them. + */ + if ( + uv__tty_console_handle_in != INVALID_HANDLE_VALUE && + uv__tty_console_in_original_mode != (DWORD)-1 && + InterlockedExchange(&uv__tty_console_in_need_mode_reset, 0) != 0 + ) { + SetConsoleMode(uv__tty_console_handle_in, uv__tty_console_in_original_mode); + } return 0; } @@ -2390,7 +2428,7 @@ static void uv__tty_console_signal_resize(void) { CONSOLE_SCREEN_BUFFER_INFO sb_info; int width, height; - if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) + if (!GetConsoleScreenBufferInfo(uv__tty_console_handle_out, &sb_info)) return; width = sb_info.dwSize.X; diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 5c8f6e1dd0b449..e0873c2a899c24 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -1101,7 +1101,8 @@ int uv__udp_try_send(uv_udp_t* handle, struct sockaddr_storage converted; int err; - assert(nbufs > 0); + if (nbufs < 1) + return UV_EINVAL; if (addr != NULL) { err = uv__convert_to_localhost_if_unspecified(addr, &converted); @@ -1141,3 +1142,21 @@ int uv__udp_try_send(uv_udp_t* handle, return bytes; } + + +int uv__udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/]) { + unsigned int i; + int r; + + for (i = 0; i < 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; +} diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index e0dba1aaa94e28..57061bf8d703fe 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -191,7 +191,7 @@ int uv_cwd(char* buffer, size_t* size) { WCHAR *utf16_buffer; int r; - if (buffer == NULL || size == NULL) { + if (buffer == NULL || size == NULL || *size == 0) { return UV_EINVAL; } @@ -874,56 +874,100 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses, int uv_getrusage(uv_rusage_t *uv_rusage) { - FILETIME createTime, exitTime, kernelTime, userTime; - SYSTEMTIME kernelSystemTime, userSystemTime; - PROCESS_MEMORY_COUNTERS memCounters; - IO_COUNTERS ioCounters; + FILETIME create_time, exit_time, kernel_time, user_time; + SYSTEMTIME kernel_system_time, user_system_time; + PROCESS_MEMORY_COUNTERS mem_counters; + IO_COUNTERS io_counters; int ret; - ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime); + ret = GetProcessTimes(GetCurrentProcess(), + &create_time, + &exit_time, + &kernel_time, + &user_time); if (ret == 0) { return uv_translate_sys_error(GetLastError()); } - ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime); + ret = FileTimeToSystemTime(&kernel_time, &kernel_system_time); if (ret == 0) { return uv_translate_sys_error(GetLastError()); } - ret = FileTimeToSystemTime(&userTime, &userSystemTime); + ret = FileTimeToSystemTime(&user_time, &user_system_time); if (ret == 0) { return uv_translate_sys_error(GetLastError()); } ret = GetProcessMemoryInfo(GetCurrentProcess(), - &memCounters, - sizeof(memCounters)); + &mem_counters, + sizeof(mem_counters)); if (ret == 0) { return uv_translate_sys_error(GetLastError()); } - ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); + ret = GetProcessIoCounters(GetCurrentProcess(), &io_counters); if (ret == 0) { return uv_translate_sys_error(GetLastError()); } memset(uv_rusage, 0, sizeof(*uv_rusage)); - uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 + - userSystemTime.wMinute * 60 + - userSystemTime.wSecond; - uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000; + uv_rusage->ru_utime.tv_sec = user_system_time.wHour * 3600 + + user_system_time.wMinute * 60 + + user_system_time.wSecond; + uv_rusage->ru_utime.tv_usec = user_system_time.wMilliseconds * 1000; - uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 + - kernelSystemTime.wMinute * 60 + - kernelSystemTime.wSecond; - uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000; + uv_rusage->ru_stime.tv_sec = kernel_system_time.wHour * 3600 + + kernel_system_time.wMinute * 60 + + kernel_system_time.wSecond; + uv_rusage->ru_stime.tv_usec = kernel_system_time.wMilliseconds * 1000; - uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; - uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; + uv_rusage->ru_majflt = (uint64_t) mem_counters.PageFaultCount; + uv_rusage->ru_maxrss = (uint64_t) mem_counters.PeakWorkingSetSize / 1024; - uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount; - uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount; + uv_rusage->ru_oublock = (uint64_t) io_counters.WriteOperationCount; + uv_rusage->ru_inblock = (uint64_t) io_counters.ReadOperationCount; + + return 0; +} + + +int uv_getrusage_thread(uv_rusage_t* uv_rusage) { + FILETIME create_time, exit_time, kernel_time, user_time; + SYSTEMTIME kernel_system_time, user_system_time; + int ret; + + ret = GetThreadTimes(GetCurrentThread(), + &create_time, + &exit_time, + &kernel_time, + &user_time); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = FileTimeToSystemTime(&kernel_time, &kernel_system_time); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + ret = FileTimeToSystemTime(&user_time, &user_system_time); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + + memset(uv_rusage, 0, sizeof(*uv_rusage)); + + uv_rusage->ru_utime.tv_sec = user_system_time.wHour * 3600 + + user_system_time.wMinute * 60 + + user_system_time.wSecond; + uv_rusage->ru_utime.tv_usec = user_system_time.wMilliseconds * 1000; + + uv_rusage->ru_stime.tv_sec = kernel_system_time.wHour * 3600 + + kernel_system_time.wMinute * 60 + + kernel_system_time.wSecond; + uv_rusage->ru_stime.tv_usec = kernel_system_time.wMilliseconds * 1000; return 0; } @@ -972,6 +1016,7 @@ int uv_os_homedir(char* buffer, size_t* size) { int uv_os_tmpdir(char* buffer, size_t* size) { + int r; wchar_t *path; size_t len; @@ -1010,7 +1055,9 @@ int uv_os_tmpdir(char* buffer, size_t* size) { path[len] = L'\0'; } - return uv__copy_utf16_to_utf8(path, len, buffer, size); + r = uv__copy_utf16_to_utf8(path, len, buffer, size); + uv__free(path); + return r; } @@ -1589,7 +1636,7 @@ int uv_os_uname(uv_utsname_t* buffer) { version_size = sizeof(buffer->version) - version_size; r = uv__copy_utf16_to_utf8(os_info.szCSDVersion, -1, - buffer->version + + buffer->version + sizeof(buffer->version) - version_size, &version_size); if (r) diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index a74108db03e701..315a0d49aff50b 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -36,9 +36,6 @@ sNtQueryDirectoryFile pNtQueryDirectoryFile; sNtQuerySystemInformation pNtQuerySystemInformation; sNtQueryInformationProcess pNtQueryInformationProcess; -/* Kernel32 function pointers */ -sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; - /* Powrprof.dll function pointer */ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; @@ -55,7 +52,6 @@ void uv__winapi_init(void) { HMODULE ntdll_module; HMODULE powrprof_module; HMODULE user32_module; - HMODULE kernel32_module; HMODULE ws2_32_module; HMODULE api_win_core_file_module; @@ -121,15 +117,6 @@ void uv__winapi_init(void) { uv_fatal_error(GetLastError(), "GetProcAddress"); } - kernel32_module = GetModuleHandleA("kernel32.dll"); - if (kernel32_module == NULL) { - uv_fatal_error(GetLastError(), "GetModuleHandleA"); - } - - pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress( - kernel32_module, - "GetQueuedCompletionStatusEx"); - powrprof_module = LoadLibraryExA("powrprof.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (powrprof_module != NULL) { pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 5800e70dfd7d11..b9c9f1abc8899e 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4145,45 +4145,40 @@ typedef struct _FILE_STAT_BASIC_INFORMATION { ULONG DeviceType; ULONG DeviceCharacteristics; ULONG Reserved; - FILE_ID_128 FileId128; LARGE_INTEGER VolumeSerialNumber; + FILE_ID_128 FileId128; } FILE_STAT_BASIC_INFORMATION; #endif -/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does - * not. - */ -#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) - typedef struct _REPARSE_DATA_BUFFER { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union { - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - struct { - ULONG StringCount; - WCHAR StringList[1]; - } AppExecLinkReparseBuffer; - }; - } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; -#endif +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + struct { + ULONG StringCount; + WCHAR StringList[1]; + } AppExecLinkReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; typedef struct _IO_STATUS_BLOCK { union { @@ -4292,6 +4287,22 @@ typedef struct _FILE_BOTH_DIR_INFORMATION { WCHAR FileName[1]; } FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; +typedef struct _FILE_ID_FULL_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION; + typedef struct _FILE_BASIC_INFORMATION { LARGE_INTEGER CreationTime; LARGE_INTEGER LastAccessTime; @@ -4661,15 +4672,6 @@ typedef NTSTATUS (NTAPI *sNtQueryInformationProcess) # define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 #endif -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) - typedef struct _OVERLAPPED_ENTRY { - ULONG_PTR lpCompletionKey; - LPOVERLAPPED lpOverlapped; - ULONG_PTR Internal; - DWORD dwNumberOfBytesTransferred; - } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY; -#endif - /* from wincon.h */ #ifndef ENABLE_INSERT_MODE # define ENABLE_INSERT_MODE 0x20 @@ -4716,14 +4718,6 @@ typedef NTSTATUS (NTAPI *sNtQueryInformationProcess) # define ERROR_MUI_FILE_NOT_LOADED 15105 #endif -typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx) - (HANDLE CompletionPort, - LPOVERLAPPED_ENTRY lpCompletionPortEntries, - ULONG ulCount, - PULONG ulNumEntriesRemoved, - DWORD dwMilliseconds, - BOOL fAlertable); - /* from powerbase.h */ #ifndef DEVICE_NOTIFY_CALLBACK # define DEVICE_NOTIFY_CALLBACK 2 @@ -4818,9 +4812,6 @@ extern sNtQueryDirectoryFile pNtQueryDirectoryFile; extern sNtQuerySystemInformation pNtQuerySystemInformation; extern sNtQueryInformationProcess pNtQueryInformationProcess; -/* Kernel32 function pointers */ -extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; - /* Powrprof.dll function pointer */ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; diff --git a/deps/uv/src/win/winsock.h b/deps/uv/src/win/winsock.h index 2af958870a7de6..bb3808a35c27e6 100644 --- a/deps/uv/src/win/winsock.h +++ b/deps/uv/src/win/winsock.h @@ -154,47 +154,6 @@ typedef struct _AFD_RECV_INFO { #define IOCTL_AFD_POLL \ _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED) -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP { - /* FIXME: __C89_NAMELESS was removed */ - /* __C89_NAMELESS */ union { - ULONGLONG Alignment; - /* __C89_NAMELESS */ struct { - ULONG Length; - DWORD Flags; - }; - }; - struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next; - SOCKET_ADDRESS Address; - IP_PREFIX_ORIGIN PrefixOrigin; - IP_SUFFIX_ORIGIN SuffixOrigin; - IP_DAD_STATE DadState; - ULONG ValidLifetime; - ULONG PreferredLifetime; - ULONG LeaseLifetime; -} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP; - -typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH { - union { - ULONGLONG Alignment; - struct { - ULONG Length; - DWORD Flags; - }; - }; - struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next; - SOCKET_ADDRESS Address; - IP_PREFIX_ORIGIN PrefixOrigin; - IP_SUFFIX_ORIGIN SuffixOrigin; - IP_DAD_STATE DadState; - ULONG ValidLifetime; - ULONG PreferredLifetime; - ULONG LeaseLifetime; - UINT8 OnLinkPrefixLength; -} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH; - -#endif - int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr, struct sockaddr_storage* storage); diff --git a/deps/uv/test/runner-unix.c b/deps/uv/test/runner-unix.c index 81560add82043e..3d14cb69b29ee1 100644 --- a/deps/uv/test/runner-unix.c +++ b/deps/uv/test/runner-unix.c @@ -367,6 +367,7 @@ long int process_output_size(process_info_t *p) { /* Copy the contents of the stdio output buffer to `fd`. */ int process_copy_output(process_info_t* p, FILE* stream) { char buf[1024]; + int partial; int r; r = fseek(p->stdout_file, 0, SEEK_SET); @@ -375,9 +376,9 @@ int process_copy_output(process_info_t* p, FILE* stream) { return -1; } - /* TODO: what if the line is longer than buf */ + partial = 0; while ((r = fread(buf, 1, sizeof(buf), p->stdout_file)) != 0) - print_lines(buf, r, stream); + partial = print_lines(buf, r, stream, partial); if (ferror(p->stdout_file)) { perror("read"); diff --git a/deps/uv/test/runner-win.c b/deps/uv/test/runner-win.c index 6c6e35f7731327..8035ca62f8ec9f 100644 --- a/deps/uv/test/runner-win.c +++ b/deps/uv/test/runner-win.c @@ -219,6 +219,7 @@ long int process_output_size(process_info_t *p) { int process_copy_output(process_info_t* p, FILE* stream) { char buf[1024]; + int partial; int fd, r; fd = _open_osfhandle((intptr_t)p->stdio_out, _O_RDONLY | _O_TEXT); @@ -229,8 +230,9 @@ int process_copy_output(process_info_t* p, FILE* stream) { if (r < 0) return -1; + partial = 0; while ((r = _read(fd, buf, sizeof(buf))) != 0) - print_lines(buf, r, stream); + partial = print_lines(buf, r, stream, partial); _close(fd); return 0; diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c index d1dd02f5ce0806..87e7db0b05c5ea 100644 --- a/deps/uv/test/runner.c +++ b/deps/uv/test/runner.c @@ -27,6 +27,11 @@ #include "task.h" #include "uv.h" +/* Refs: https://github.com/libuv/libuv/issues/4369 */ +#if defined(__ANDROID__) +#include +#endif + char executable_path[sizeof(executable_path)]; @@ -142,6 +147,13 @@ void log_tap_result(int test_count, fflush(stdout); } +void enable_fdsan(void) { +/* Refs: https://github.com/libuv/libuv/issues/4369 */ +#if defined(__ANDROID__) + android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS); +#endif +} + int run_test(const char* test, int benchmark_output, @@ -160,6 +172,8 @@ int run_test(const char* test, main_proc = NULL; process_count = 0; + enable_fdsan(); + #ifndef _WIN32 /* Clean up stale socket from previous run. */ remove(TEST_PIPENAME); @@ -412,13 +426,17 @@ void print_tests(FILE* stream) { } -void print_lines(const char* buffer, size_t size, FILE* stream) { +int print_lines(const char* buffer, size_t size, FILE* stream, int partial) { const char* start; const char* end; start = buffer; while ((end = memchr(start, '\n', &buffer[size] - start))) { - fputs("# ", stream); + if (partial == 0) + fputs("# ", stream); + else + partial = 0; + fwrite(start, 1, (int)(end - start), stream); fputs("\n", stream); fflush(stream); @@ -427,9 +445,13 @@ void print_lines(const char* buffer, size_t size, FILE* stream) { end = &buffer[size]; if (start < end) { - fputs("# ", stream); + if (partial == 0) + fputs("# ", stream); + fwrite(start, 1, (int)(end - start), stream); - fputs("\n", stream); fflush(stream); + return 1; } + + return 0; } diff --git a/deps/uv/test/runner.h b/deps/uv/test/runner.h index 6801564f961c31..ff7d4eec9b6870 100644 --- a/deps/uv/test/runner.h +++ b/deps/uv/test/runner.h @@ -123,7 +123,7 @@ int run_test_part(const char* test, const char* part); void print_tests(FILE* stream); /* Print lines in |buffer| as TAP diagnostics to |stream|. */ -void print_lines(const char* buffer, size_t size, FILE* stream); +int print_lines(const char* buffer, size_t size, FILE* stream, int partial); /* * Stuff that should be implemented by test-runner-.h diff --git a/deps/uv/test/test-connect-unspecified.c b/deps/uv/test/test-connect-unspecified.c index 73e59a9972b670..ebed8c3c20b809 100644 --- a/deps/uv/test/test-connect-unspecified.c +++ b/deps/uv/test/test-connect-unspecified.c @@ -22,11 +22,7 @@ #include "uv.h" #include "task.h" -static void connect_4(uv_connect_t* req, int status) { - ASSERT_NE(status, UV_EADDRNOTAVAIL); -} - -static void connect_6(uv_connect_t* req, int status) { +static void connect_cb(uv_connect_t* req, int status) { ASSERT_NE(status, UV_EADDRNOTAVAIL); } @@ -46,7 +42,7 @@ TEST_IMPL(connect_unspecified) { ASSERT_OK(uv_tcp_connect(&connect4, &socket4, (const struct sockaddr*) &addr4, - connect_4)); + connect_cb)); if (can_ipv6()) { ASSERT_OK(uv_tcp_init(loop, &socket6)); @@ -54,7 +50,7 @@ TEST_IMPL(connect_unspecified) { ASSERT_OK(uv_tcp_connect(&connect6, &socket6, (const struct sockaddr*) &addr6, - connect_6)); + connect_cb)); } ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index bb223a5f654c03..f224181fc36855 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -32,7 +32,7 @@ static uv_fs_event_t fs_event; static const char file_prefix[] = "fsevent-"; static const int fs_event_file_count = 16; -#if defined(__APPLE__) || defined(_WIN32) +#if (defined(__APPLE__) && !defined(__TSAN__)) || defined(_WIN32) static const char file_prefix_in_subdir[] = "subdir"; static int fs_multievent_cb_called; #endif @@ -153,7 +153,14 @@ static void fs_event_cb_del_dir(uv_fs_event_t* handle, ASSERT_PTR_EQ(handle, &fs_event); ASSERT_OK(status); ASSERT(events == UV_CHANGE || events == UV_RENAME); + /* There is a bug in the FreeBSD kernel where the filename is sometimes NULL. + * Refs: https://github.com/libuv/libuv/issues/4606 + */ + #if defined(__FreeBSD__) + ASSERT(filename == NULL || strcmp(filename, "watch_del_dir") == 0); + #else ASSERT_OK(strcmp(filename, "watch_del_dir")); + #endif ASSERT_OK(uv_fs_event_stop(handle)); uv_close((uv_handle_t*)handle, close_cb); } @@ -243,7 +250,7 @@ static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle, } } -#if defined(__APPLE__) || defined(_WIN32) +#if (defined(__APPLE__) && !defined(__TSAN__)) || defined(_WIN32) static const char* fs_event_get_filename_in_subdir(int i) { snprintf(fs_event_filename, sizeof(fs_event_filename), @@ -1121,7 +1128,7 @@ TEST_IMPL(fs_event_getpath) { ASSERT_EQ(r, UV_EINVAL); r = uv_fs_event_start(&fs_event, fail_cb, watch_dir[i], 0); ASSERT_OK(r); - len = 0; + len = 1; r = uv_fs_event_getpath(&fs_event, buf, &len); ASSERT_EQ(r, UV_ENOBUFS); ASSERT_LT(len, sizeof buf); /* sanity check */ diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 33cbd428707c36..4761b15bad188b 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -59,6 +59,18 @@ #define TOO_LONG_NAME_LENGTH 65536 #define PATHMAX 4096 +#ifdef _WIN32 +static const int is_win32 = 1; +#else +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; @@ -827,43 +839,70 @@ static void check_utime(const char* path, ASSERT_OK(req.result); s = &req.statbuf; - if (s->st_atim.tv_nsec == 0 && s->st_mtim.tv_nsec == 0) { - /* - * Test sub-second timestamps only when supported (such as Windows with + if (isfinite(atime)) { + /* Test sub-second timestamps only when supported (such as Windows with * NTFS). Some other platforms support sub-second timestamps, but that * support is filesystem-dependent. Notably OS X (HFS Plus) does NOT * support sub-second timestamps. But kernels may round or truncate in * either direction, so we may accept either possible answer. */ -#ifdef _WIN32 - ASSERT_DOUBLE_EQ(atime, (long) atime); - ASSERT_DOUBLE_EQ(mtime, (long) atime); -#endif - if (atime > 0 || (long) atime == atime) - ASSERT_EQ(s->st_atim.tv_sec, (long) atime); - if (mtime > 0 || (long) mtime == mtime) - ASSERT_EQ(s->st_mtim.tv_sec, (long) mtime); - ASSERT_GE(s->st_atim.tv_sec, (long) atime - 1); - ASSERT_GE(s->st_mtim.tv_sec, (long) mtime - 1); - ASSERT_LE(s->st_atim.tv_sec, (long) atime); - ASSERT_LE(s->st_mtim.tv_sec, (long) mtime); + if (s->st_atim.tv_nsec == 0) { + if (is_win32) + ASSERT_DOUBLE_EQ(atime, (long) atime); + if (atime > 0 || (long) atime == atime) + ASSERT_EQ(s->st_atim.tv_sec, (long) atime); + ASSERT_GE(s->st_atim.tv_sec, (long) atime - 1); + ASSERT_LE(s->st_atim.tv_sec, (long) atime); + } else { + double st_atim; + /* TODO(vtjnash): would it be better to normalize this? */ + if (!is_apple_or_sunpro_c) + ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); + 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 + */ + if (!test_lutime) + ASSERT_DOUBLE_EQ(st_atim, atime); + } + } else if (isinf(atime)) { + /* We test with timestamps that are in the distant past + * (if you're a Gen Z-er) so check it's more recent than that. + */ + ASSERT_GT(s->st_atim.tv_sec, 1739710000); } else { - double st_atim; - double st_mtim; -#if !defined(__APPLE__) && !defined(__SUNPRO_C) - /* TODO(vtjnash): would it be better to normalize this? */ - ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); - ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); -#endif - st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; - st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; - /* - * Linux does not allow reading reliably the atime of a symlink - * since readlink() can update it + ASSERT_OK(0); + } + + if (isfinite(mtime)) { + /* Test sub-second timestamps only when supported (such as Windows with + * NTFS). Some other platforms support sub-second timestamps, but that + * support is filesystem-dependent. Notably OS X (HFS Plus) does NOT + * support sub-second timestamps. But kernels may round or truncate in + * either direction, so we may accept either possible answer. */ - if (!test_lutime) - ASSERT_DOUBLE_EQ(st_atim, atime); - ASSERT_DOUBLE_EQ(st_mtim, mtime); + if (s->st_mtim.tv_nsec == 0) { + if (is_win32) + ASSERT_DOUBLE_EQ(mtime, (long) atime); + if (mtime > 0 || (long) mtime == mtime) + ASSERT_EQ(s->st_mtim.tv_sec, (long) mtime); + ASSERT_GE(s->st_mtim.tv_sec, (long) mtime - 1); + ASSERT_LE(s->st_mtim.tv_sec, (long) mtime); + } else { + double st_mtim; + /* TODO(vtjnash): would it be better to normalize this? */ + if (!is_apple_or_sunpro_c) + ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); + st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; + ASSERT_DOUBLE_EQ(st_mtim, mtime); + } + } else if (isinf(mtime)) { + /* We test with timestamps that are in the distant past + * (if you're a Gen Z-er) so check it's more recent than that. + */ + ASSERT_GT(s->st_mtim.tv_sec, 1739710000); + } else { + ASSERT_OK(0); } uv_fs_req_cleanup(&req); @@ -1607,6 +1646,50 @@ TEST_IMPL(fs_fstat) { } +TEST_IMPL(fs_fstat_st_dev) { + uv_fs_t req; + uv_fs_t req_link; + uv_loop_t* loop = uv_default_loop(); + char* test_file = "tmp_st_dev"; + char* symlink_file = "tmp_st_dev_link"; + + unlink(test_file); + unlink(symlink_file); + + // Create file + int r = uv_fs_open(NULL, &req, test_file, UV_FS_O_RDWR | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); + uv_fs_req_cleanup(&req); + + // Create a symlink + r = uv_fs_symlink(loop, &req, test_file, symlink_file, 0, NULL); + ASSERT_EQ(r, 0); + uv_fs_req_cleanup(&req); + + // Call uv_fs_fstat for file + r = uv_fs_stat(loop, &req, test_file, NULL); + ASSERT_EQ(r, 0); + + // Call uv_fs_fstat for symlink + r = uv_fs_stat(loop, &req_link, symlink_file, NULL); + ASSERT_EQ(r, 0); + + // Compare st_dev + ASSERT_EQ(((uv_stat_t*)req.ptr)->st_dev, ((uv_stat_t*)req_link.ptr)->st_dev); + + // Cleanup + uv_fs_req_cleanup(&req); + uv_fs_req_cleanup(&req_link); + unlink(test_file); + unlink(symlink_file); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + + TEST_IMPL(fs_fstat_stdio) { int fd; int res; @@ -2684,13 +2767,46 @@ TEST_IMPL(fs_utime) { atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */ - r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL); - ASSERT_OK(r); + ASSERT_OK(uv_fs_utime(NULL, &req, path, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_utime(NULL, + &req, + path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_utime(NULL, + &req, + path, + UV_FS_UTIME_NOW, + UV_FS_UTIME_OMIT, + NULL)); ASSERT_OK(req.result); uv_fs_req_cleanup(&req); + check_utime(path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_utime(NULL, &req, path, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); check_utime(path, atime, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_utime(NULL, + &req, + path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_NOW, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 0); + atime = mtime = 1291404900.25; /* 2010-12-03 20:35:00.25 - mees <3 */ checkme.path = path; checkme.atime = atime; @@ -2824,9 +2940,43 @@ TEST_IMPL(fs_futime) { ASSERT_OK(req.result); #endif uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_futime(NULL, + &req, + file, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); check_utime(path, atime, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_futime(NULL, + &req, + file, + UV_FS_UTIME_NOW, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_futime(NULL, &req, file, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_futime(NULL, + &req, + file, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_NOW, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 0); + atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */ checkme.atime = atime; @@ -2888,20 +3038,50 @@ TEST_IMPL(fs_lutime) { /* Test the synchronous version. */ atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */ - checkme.atime = atime; - checkme.mtime = mtime; - checkme.path = symlink_path; - req.data = &checkme; - r = uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL); -#if (defined(_AIX) && !defined(_AIX71)) || \ - defined(__MVS__) +#if (defined(_AIX) && !defined(_AIX71)) || defined(__MVS__) ASSERT_EQ(r, UV_ENOSYS); RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1"); #endif ASSERT_OK(r); - lutime_cb(&req); - ASSERT_EQ(1, lutime_cb_count); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, + &req, + symlink_path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, + &req, + symlink_path, + UV_FS_UTIME_NOW, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, + &req, + symlink_path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_NOW, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 1); /* Test the asynchronous version. */ atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */ @@ -2909,11 +3089,12 @@ TEST_IMPL(fs_lutime) { checkme.atime = atime; checkme.mtime = mtime; checkme.path = symlink_path; + req.data = &checkme; r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb); ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT_EQ(2, lutime_cb_count); + ASSERT_EQ(1, lutime_cb_count); /* Cleanup. */ unlink(path); @@ -4507,6 +4688,60 @@ TEST_IMPL(fs_open_readonly_acl) { MAKE_VALGRIND_HAPPY(loop); return 0; } + +TEST_IMPL(fs_stat_no_permission) { + uv_passwd_t pwd; + uv_fs_t req; + int r; + char* filename = "test_file_no_permission.txt"; + + /* Setup - clear the ACL and remove the file */ + loop = uv_default_loop(); + r = uv_os_get_passwd(&pwd); + ASSERT_OK(r); + call_icacls("icacls %s /remove *S-1-1-0:(F)", filename); + unlink(filename); + + /* Create the file */ + r = uv_fs_open(loop, + &open_req1, + filename, + UV_FS_O_RDONLY | UV_FS_O_CREAT, + S_IRUSR, + NULL); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); + uv_fs_req_cleanup(&open_req1); + r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); + ASSERT_OK(r); + ASSERT_OK(close_req.result); + uv_fs_req_cleanup(&close_req); + + /* Set up ACL */ + r = call_icacls("icacls %s /deny *S-1-1-0:(F)", filename); + if (r != 0) { + goto acl_cleanup; + } + + /* Read file stats */ + r = uv_fs_stat(NULL, &req, filename, NULL); + if (r != 0) { + goto acl_cleanup; + } + + uv_fs_req_cleanup(&req); + + acl_cleanup: + /* Cleanup */ + call_icacls("icacls %s /reset", filename); + uv_fs_unlink(NULL, &unlink_req, filename, NULL); + uv_fs_req_cleanup(&unlink_req); + unlink(filename); + uv_os_free_passwd(&pwd); + ASSERT_OK(r); + MAKE_VALGRIND_HAPPY(loop); + return 0; +} #endif #ifdef _WIN32 diff --git a/deps/uv/test/test-idna.c b/deps/uv/test/test-idna.c index 28f9eaaae9e77a..46df9f3c581015 100644 --- a/deps/uv/test/test-idna.c +++ b/deps/uv/test/test-idna.c @@ -39,7 +39,7 @@ TEST_IMPL(utf8_decode1) { /* Two-byte sequences. */ p = b; - snprintf(b, sizeof(b), "\xC2\x80\xDF\xBF"); + snprintf(b, sizeof(b), "%s", "\xC2\x80\xDF\xBF"); ASSERT_EQ(128, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 2); ASSERT_EQ(0x7FF, uv__utf8_decode1(&p, b + sizeof(b))); @@ -47,7 +47,7 @@ TEST_IMPL(utf8_decode1) { /* Three-byte sequences. */ p = b; - snprintf(b, sizeof(b), "\xE0\xA0\x80\xEF\xBF\xBF"); + snprintf(b, sizeof(b), "%s", "\xE0\xA0\x80\xEF\xBF\xBF"); ASSERT_EQ(0x800, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 3); ASSERT_EQ(0xFFFF, uv__utf8_decode1(&p, b + sizeof(b))); @@ -55,7 +55,7 @@ TEST_IMPL(utf8_decode1) { /* Four-byte sequences. */ p = b; - snprintf(b, sizeof(b), "\xF0\x90\x80\x80\xF4\x8F\xBF\xBF"); + snprintf(b, sizeof(b), "%s", "\xF0\x90\x80\x80\xF4\x8F\xBF\xBF"); ASSERT_EQ(0x10000, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 4); ASSERT_EQ(0x10FFFF, uv__utf8_decode1(&p, b + sizeof(b))); @@ -63,7 +63,7 @@ TEST_IMPL(utf8_decode1) { /* Four-byte sequences > U+10FFFF; disallowed. */ p = b; - snprintf(b, sizeof(b), "\xF4\x90\xC0\xC0\xF7\xBF\xBF\xBF"); + snprintf(b, sizeof(b), "%s", "\xF4\x90\xC0\xC0\xF7\xBF\xBF\xBF"); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 4); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); @@ -71,7 +71,7 @@ TEST_IMPL(utf8_decode1) { /* Overlong; disallowed. */ p = b; - snprintf(b, sizeof(b), "\xC0\x80\xC1\x80"); + snprintf(b, sizeof(b), "%s", "\xC0\x80\xC1\x80"); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 2); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); @@ -79,7 +79,7 @@ TEST_IMPL(utf8_decode1) { /* Surrogate pairs; disallowed. */ p = b; - snprintf(b, sizeof(b), "\xED\xA0\x80\xED\xA3\xBF"); + snprintf(b, sizeof(b), "%s", "\xED\xA0\x80\xED\xA3\xBF"); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 3); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); @@ -87,7 +87,7 @@ TEST_IMPL(utf8_decode1) { /* Simply illegal. */ p = b; - snprintf(b, sizeof(b), "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"); + snprintf(b, sizeof(b), "%s", "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"); for (i = 1; i <= 8; i++) { ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); @@ -218,3 +218,15 @@ TEST_IMPL(idna_toascii) { #undef T #endif /* __MVS__ */ + +TEST_IMPL(wtf8) { + static const char input[] = "ᜄȺy𐞲:𞢢𘴇𐀀'¥3̞[ +#include + +static int limit; +static int alloc; + +static void* t_realloc(void* p, size_t n) { + alloc += n; + if (alloc > limit) + return NULL; + p = realloc(p, n); + ASSERT_NOT_NULL(p); + return p; +} + +static void* t_calloc(size_t m, size_t n) { + return t_realloc(NULL, m * n); +} + +static void* t_malloc(size_t n) { + return t_realloc(NULL, n); +} + +TEST_IMPL(loop_init_oom) { + uv_loop_t loop; + int err; + + ASSERT_OK(uv_replace_allocator(t_malloc, t_realloc, t_calloc, free)); + for (;;) { + err = uv_loop_init(&loop); + if (err == 0) + break; + ASSERT_EQ(err, UV_ENOMEM); + limit += 8; + alloc = 0; + } + ASSERT_OK(uv_loop_close(&loop)); + return 0; +} diff --git a/deps/uv/test/test-pipe-getsockname.c b/deps/uv/test/test-pipe-getsockname.c index 34b572343c698a..3be30e674182f2 100644 --- a/deps/uv/test/test-pipe-getsockname.c +++ b/deps/uv/test/test-pipe-getsockname.c @@ -59,7 +59,7 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) { ASSERT_OK(r); if (*buf == '\0') { /* Linux abstract socket. */ - const char expected[] = "\0" TEST_PIPENAME; + const char expected[] = "\0" TEST_PIPENAME "\0"; ASSERT_EQ(len, sizeof(expected) - 1); ASSERT_MEM_EQ(buf, expected, len); } else { @@ -154,6 +154,15 @@ TEST_IMPL(pipe_getsockname) { ASSERT_STR_EQ(pipe_server.pipe_fname, TEST_PIPENAME); #endif + r = uv_pipe_getsockname(&pipe_server, NULL, &len); + ASSERT_EQ(r, UV_EINVAL); + + r = uv_pipe_getsockname(&pipe_server, buf, NULL); + ASSERT_EQ(r, UV_EINVAL); + + r = uv_pipe_getsockname(&pipe_server, NULL, NULL); + ASSERT_EQ(r, UV_EINVAL); + len = sizeof(TEST_PIPENAME) - 1; ASSERT_EQ(UV_ENOBUFS, uv_pipe_getsockname(&pipe_server, buf, &len)); @@ -214,7 +223,7 @@ TEST_IMPL(pipe_getsockname) { TEST_IMPL(pipe_getsockname_abstract) { /* TODO(bnoordhuis) Use unique name, susceptible to concurrent test runs. */ - static const char name[] = "\0" TEST_PIPENAME; + static const char name[] = "\0" TEST_PIPENAME "\0"; #if defined(__linux__) char buf[256]; size_t buflen; diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c index 4e5300da037399..06a8e484dd78ec 100644 --- a/deps/uv/test/test-platform-output.c +++ b/deps/uv/test/test-platform-output.c @@ -236,5 +236,24 @@ TEST_IMPL(platform_output) { printf(" version: %s\n", uname.version); printf(" machine: %s\n", uname.machine); + err = uv_getrusage_thread(&rusage); + if (err != UV_ENOTSUP) { + ASSERT_OK(err); + ASSERT_UINT64_GE(rusage.ru_utime.tv_sec, 0); + ASSERT_UINT64_GE(rusage.ru_utime.tv_usec, 0); + ASSERT_UINT64_GE(rusage.ru_stime.tv_sec, 0); + ASSERT_UINT64_GE(rusage.ru_stime.tv_usec, 0); + printf("uv_getrusage_thread:\n"); + printf(" user: %llu sec %llu microsec\n", + (unsigned long long) rusage.ru_utime.tv_sec, + (unsigned long long) rusage.ru_utime.tv_usec); + printf(" system: %llu sec %llu microsec\n", + (unsigned long long) rusage.ru_stime.tv_sec, + (unsigned long long) rusage.ru_stime.tv_usec); + printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt); + printf(" maximum resident set size: %llu\n", + (unsigned long long) rusage.ru_maxrss); + } + return 0; } diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index efbb2395ff8b2b..964c8a86c76eb6 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -1329,9 +1329,7 @@ TEST_IMPL(environment_creation) { } } if (prev) { /* verify sort order */ -#if !defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR) ASSERT_EQ(1, CompareStringOrdinal(prev, -1, str, -1, TRUE)); -#endif } ASSERT(found); /* verify that we expected this variable */ } @@ -1524,7 +1522,7 @@ TEST_IMPL(spawn_setuid_fails) { init_process_options("spawn_helper1", fail_cb); options.flags |= UV_PROCESS_SETUID; - /* On IBMi PASE, there is no root user. User may grant + /* On IBMi PASE, there is no root user. User may grant * root-like privileges, including setting uid to 0. */ #if defined(__PASE__) @@ -1575,7 +1573,7 @@ TEST_IMPL(spawn_setgid_fails) { init_process_options("spawn_helper1", fail_cb); options.flags |= UV_PROCESS_SETGID; - /* On IBMi PASE, there is no root user. User may grant + /* On IBMi PASE, there is no root user. User may grant * root-like privileges, including setting gid to 0. */ #if defined(__MVS__) || defined(__PASE__) diff --git a/deps/uv/test/test-thread-name.c b/deps/uv/test/test-thread-name.c new file mode 100644 index 00000000000000..39340744290a0e --- /dev/null +++ b/deps/uv/test/test-thread-name.c @@ -0,0 +1,193 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include "../src/uv-common.h" + +#include + +struct semaphores { + uv_sem_t main; + uv_sem_t worker; +}; + +static void thread_run(void* arg) { + int r; + char thread_name[16]; + struct semaphores* sem; + uv_thread_t thread; + + sem = arg; + +#ifdef _WIN32 + /* uv_thread_self isn't defined for the main thread on Windows. */ + thread = GetCurrentThread(); +#else + thread = uv_thread_self(); +#endif + + r = uv_thread_setname("worker-thread"); + ASSERT_OK(r); + + uv_sem_post(&sem->worker); + + r = uv_thread_getname(&thread, thread_name, sizeof(thread_name)); + ASSERT_OK(r); + + ASSERT_STR_EQ(thread_name, "worker-thread"); + + uv_sem_wait(&sem->main); +} + +TEST_IMPL(thread_name) { + int r; + uv_thread_t threads[2]; + char tn[UV_PTHREAD_MAX_NAMELEN_NP]; + char thread_name[UV_PTHREAD_MAX_NAMELEN_NP]; + char long_thread_name[UV_PTHREAD_MAX_NAMELEN_NP + 1]; + struct semaphores sem; + +#if defined(__ANDROID_API__) && __ANDROID_API__ < 26 || \ + defined(_AIX) || \ + defined(__MVS__) || \ + defined(__PASE__) + RETURN_SKIP("API not available on this platform"); +#endif + + ASSERT_OK(uv_sem_init(&sem.main, 0)); + ASSERT_OK(uv_sem_init(&sem.worker, 0)); + + memset(thread_name, 'a', sizeof(thread_name) - 1); + thread_name[sizeof(thread_name) - 1] = '\0'; + + memset(long_thread_name, 'a', sizeof(long_thread_name) - 1); + long_thread_name[sizeof(long_thread_name) - 1] = '\0'; + +#ifdef _WIN32 + /* uv_thread_self isn't defined for the main thread on Windows. */ + threads[0] = GetCurrentThread(); +#else + threads[0] = uv_thread_self(); +#endif + + r = uv_thread_getname(&threads[0], tn, sizeof(tn)); + ASSERT_OK(r); + + r = uv_thread_setname(long_thread_name); + ASSERT_OK(r); + + r = uv_thread_getname(&threads[0], tn, sizeof(tn)); + ASSERT_OK(r); + ASSERT_STR_EQ(tn, thread_name); + + r = uv_thread_setname(thread_name); + ASSERT_OK(r); + + r = uv_thread_getname(&threads[0], tn, sizeof(tn)); + ASSERT_OK(r); + ASSERT_STR_EQ(tn, thread_name); + + r = uv_thread_getname(&threads[0], tn, 3); + ASSERT_OK(r); + ASSERT_EQ(strlen(tn), 2); + ASSERT_OK(memcmp(thread_name, tn, 2)); + + /* Illumos doesn't support non-ASCII thread names. */ +#ifndef __illumos__ + r = uv_thread_setname("~½¬{½"); + ASSERT_OK(r); + + r = uv_thread_getname(&threads[0], tn, sizeof(tn)); + ASSERT_OK(r); + ASSERT_STR_EQ(tn, "~½¬{½"); +#endif + + ASSERT_OK(uv_thread_create(threads + 1, thread_run, &sem)); + + uv_sem_wait(&sem.worker); + + r = uv_thread_getname(threads + 1, tn, sizeof(tn)); + ASSERT_OK(r); + + ASSERT_STR_EQ(tn, "worker-thread"); + + uv_sem_post(&sem.main); + + ASSERT_OK(uv_thread_join(threads + 1)); + + uv_sem_destroy(&sem.main); + uv_sem_destroy(&sem.worker); + + return 0; +} + +#define MAX_THREADS 4 + +static void* executedThreads[MAX_THREADS] = { NULL }; +static int size; +static uv_loop_t* loop; + +static unsigned short int key_exists(void* key) { + size_t i; + for (i = 0; i < MAX_THREADS; i++) { + if (executedThreads[i] == key) { + return 1; + } + } + return 0; +} + +static void work_cb(uv_work_t* req) { + uv_thread_t thread = uv_thread_self(); + req->data = &thread; + char tn[UV_PTHREAD_MAX_NAMELEN_NP]; + ASSERT_OK(uv_thread_getname(&thread, tn, sizeof(tn))); + ASSERT_STR_EQ(tn, "libuv-worker"); +} + +static void after_work_cb(uv_work_t* req, int status) { + ASSERT_OK(status); + if (!key_exists(req->data)) { + executedThreads[size++] = req->data; + } + + if (size == MAX_THREADS) { + return; + } + + uv_queue_work(loop, req, work_cb, after_work_cb); +} + +TEST_IMPL(thread_name_threadpool) { + +#if defined(_AIX) || defined(__PASE__) + RETURN_SKIP("API not available on this platform"); +#endif + uv_work_t req; + loop = uv_default_loop(); + // Just to make sure all workers will be executed + // with the correct thread name + ASSERT_OK(uv_queue_work(loop, &req, work_cb, after_work_cb)); + uv_run(loop, UV_RUN_DEFAULT); + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} diff --git a/deps/uv/test/test-thread.c b/deps/uv/test/test-thread.c index d0094e304435bb..819bbd5c92399d 100644 --- a/deps/uv/test/test-thread.c +++ b/deps/uv/test/test-thread.c @@ -294,3 +294,13 @@ TEST_IMPL(thread_stack_size_explicit) { return 0; } + +static void thread_detach_cb(void* arg) {} + +TEST_IMPL(thread_detach) { + uv_thread_t thread; + ASSERT_OK(uv_thread_create(&thread, thread_detach_cb, NULL)); + ASSERT_OK(uv_thread_detach(&thread)); + + return 0; +} diff --git a/deps/uv/test/test-tty-duplicate-key.c b/deps/uv/test/test-tty-duplicate-key.c index 871d580266ad8d..e3e813e69b3536 100644 --- a/deps/uv/test/test-tty-duplicate-key.c +++ b/deps/uv/test/test-tty-duplicate-key.c @@ -131,7 +131,7 @@ static void make_key_event_records(WORD virt_key, DWORD ctr_key_state, # undef KEV } -TEST_IMPL(tty_duplicate_vt100_fn_key) { +TEST_IMPL(tty_duplicate_vt100_fn_key_libuv) { int r; int ttyin_fd; uv_tty_t tty_in; @@ -163,6 +163,10 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) { r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read); ASSERT_OK(r); + /* + * libuv has chosen to emit ESC[[A, but other terminals, and even + * Windows itself use a different escape sequence, see the test below. + */ expect_str = ESC"[[A"; expect_nread = strlen(expect_str); @@ -184,6 +188,62 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) { return 0; } +TEST_IMPL(tty_duplicate_vt100_fn_key_winvt) { + int r; + int ttyin_fd; + uv_tty_t tty_in; + uv_loop_t* loop; + HANDLE handle; + INPUT_RECORD records[2]; + DWORD written; + + loop = uv_default_loop(); + + /* Make sure we have an FD that refers to a tty */ + handle = CreateFileA("conin$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); + ttyin_fd = _open_osfhandle((intptr_t) handle, 0); + ASSERT_GE(ttyin_fd, 0); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ + ASSERT_OK(r); + ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); + ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); + + r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read); + ASSERT_OK(r); + + /* + * Some keys, like F1, get are assigned a different value by Windows + * in ENABLE_VIRTUAL_TERMINAL_INPUT mode vs. libuv in the test above. + */ + expect_str = ESC"OP"; + expect_nread = strlen(expect_str); + + /* Turn on raw mode. */ + r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW_VT); + ASSERT_OK(r); + + /* + * Send F1 keystroke. + */ + make_key_event_records(VK_F1, 0, TRUE, records); + WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written); + ASSERT_EQ(written, ARRAY_SIZE(records)); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + TEST_IMPL(tty_duplicate_alt_modifier_key) { int r; int ttyin_fd; diff --git a/deps/uv/test/test-udp-mmsg.c b/deps/uv/test/test-udp-mmsg.c index c0e000b9d92bbf..73213c43d97aa2 100644 --- a/deps/uv/test/test-udp-mmsg.c +++ b/deps/uv/test/test-udp-mmsg.c @@ -32,12 +32,12 @@ #define BUFFER_MULTIPLIER 20 #define MAX_DGRAM_SIZE (64 * 1024) #define NUM_SENDS 40 -#define EXPECTED_MMSG_ALLOCS (NUM_SENDS / BUFFER_MULTIPLIER) static uv_udp_t recver; static uv_udp_t sender; static int recv_cb_called; static int received_datagrams; +static int read_bytes; static int close_cb_called; static int alloc_cb_called; @@ -74,6 +74,7 @@ static void recv_cb(uv_udp_t* handle, const struct sockaddr* addr, unsigned flags) { ASSERT_GE(nread, 0); + read_bytes += nread; /* free and return if this is a mmsg free-only callback invocation */ if (flags & UV_UDP_MMSG_FREE) { @@ -140,7 +141,7 @@ TEST_IMPL(udp_mmsg) { /* On platforms that don't support mmsg, each recv gets its own alloc */ if (uv_udp_using_recvmmsg(&recver)) - ASSERT_EQ(alloc_cb_called, EXPECTED_MMSG_ALLOCS); + ASSERT_EQ(read_bytes, NUM_SENDS * 4); /* we're sending 4 bytes per datagram */ else ASSERT_EQ(alloc_cb_called, recv_cb_called); diff --git a/deps/uv/test/test-udp-multicast-join.c b/deps/uv/test/test-udp-multicast-join.c index 9e322dc579fc33..58b055561c6ded 100644 --- a/deps/uv/test/test-udp-multicast-join.c +++ b/deps/uv/test/test-udp-multicast-join.c @@ -36,10 +36,9 @@ static uv_udp_t client; static uv_udp_send_t req; static uv_udp_send_t req_ss; +static int darwin_ebusy_errors; static int cl_recv_cb_called; - static int sv_send_cb_called; - static int close_cb_called; static void alloc_cb(uv_handle_t* handle, @@ -128,6 +127,13 @@ static void cl_recv_cb(uv_udp_t* handle, #if !defined(__NetBSD__) r = uv_udp_set_source_membership(&server, MULTICAST_ADDR, NULL, source_addr, UV_JOIN_GROUP); +#if defined(__APPLE__) + if (r == UV_EBUSY) { + uv_close((uv_handle_t*) &server, close_cb); + darwin_ebusy_errors++; + return; + } +#endif ASSERT_OK(r); #endif @@ -160,7 +166,13 @@ TEST_IMPL(udp_multicast_join) { r = uv_udp_set_membership(&server, MULTICAST_ADDR, NULL, UV_JOIN_GROUP); if (r == UV_ENODEV) RETURN_SKIP("No multicast support."); + if (r == UV_ENOEXEC) + RETURN_SKIP("No multicast support (likely a firewall issue)."); ASSERT_OK(r); +#if defined(__ANDROID__) + /* It returns an ENOSYS error */ + RETURN_SKIP("Test does not currently work in ANDROID"); +#endif r = uv_udp_recv_start(&server, alloc_cb, cl_recv_cb); ASSERT_OK(r); @@ -175,6 +187,9 @@ TEST_IMPL(udp_multicast_join) { /* run the loop till all events are processed */ uv_run(uv_default_loop(), UV_RUN_DEFAULT); + if (darwin_ebusy_errors > 0) + RETURN_SKIP("Unexplained macOS IP_ADD_SOURCE_MEMBERSHIP EBUSY bug"); + ASSERT_EQ(2, cl_recv_cb_called); ASSERT_EQ(2, sv_send_cb_called); ASSERT_EQ(2, close_cb_called); diff --git a/deps/uv/test/test-udp-multicast-join6.c b/deps/uv/test/test-udp-multicast-join6.c index c6872e4283247d..430e4e3321e859 100644 --- a/deps/uv/test/test-udp-multicast-join6.c +++ b/deps/uv/test/test-udp-multicast-join6.c @@ -33,6 +33,7 @@ #if defined(__APPLE__) || \ defined(_AIX) || \ defined(__MVS__) || \ + defined(__FreeBSD__) || \ defined(__NetBSD__) || \ defined(__OpenBSD__) #define MULTICAST_ADDR "ff02::1%lo0" diff --git a/deps/uv/test/test-udp-try-send.c b/deps/uv/test/test-udp-try-send.c index 0c76fb1c84df68..6181fbbbffca3b 100644 --- a/deps/uv/test/test-udp-try-send.c +++ b/deps/uv/test/test-udp-try-send.c @@ -60,8 +60,6 @@ static void sv_recv_cb(uv_udp_t* handle, const uv_buf_t* rcvbuf, const struct sockaddr* addr, unsigned flags) { - ASSERT_GT(nread, 0); - if (nread == 0) { ASSERT_NULL(addr); return; @@ -70,11 +68,17 @@ static void sv_recv_cb(uv_udp_t* handle, ASSERT_EQ(4, nread); ASSERT_NOT_NULL(addr); - ASSERT_OK(memcmp("EXIT", rcvbuf->base, nread)); - uv_close((uv_handle_t*) handle, close_cb); - uv_close((uv_handle_t*) &client, close_cb); + if (!memcmp("EXIT", rcvbuf->base, nread)) { + uv_close((uv_handle_t*) handle, close_cb); + uv_close((uv_handle_t*) &client, close_cb); + } else { + ASSERT_MEM_EQ(rcvbuf->base, "HELO", 4); + } sv_recv_cb_called++; + + if (sv_recv_cb_called == 2) + uv_udp_recv_stop(handle); } @@ -101,9 +105,33 @@ TEST_IMPL(udp_try_send) { ASSERT_OK(r); buf = uv_buf_init(buffer, sizeof(buffer)); + + r = uv_udp_try_send(&client, &buf, 0, (const struct sockaddr*) &addr); + ASSERT_EQ(r, UV_EINVAL); + r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr); ASSERT_EQ(r, UV_EMSGSIZE); + uv_buf_t* bufs[] = {&buf, &buf}; + unsigned int nbufs[] = {1, 1}; + struct sockaddr* addrs[] = { + (struct sockaddr*) &addr, + (struct sockaddr*) &addr, + }; + + ASSERT_EQ(0, sv_recv_cb_called); + + buf = uv_buf_init("HELO", 4); + r = uv_udp_try_send2(&client, 2, bufs, nbufs, addrs, /*flags*/0); + ASSERT_EQ(r, 2); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT_EQ(2, sv_recv_cb_called); + + r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); + ASSERT_OK(r); + buf = uv_buf_init("EXIT", 4); r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr); ASSERT_EQ(4, r); @@ -111,7 +139,7 @@ TEST_IMPL(udp_try_send) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT_EQ(2, close_cb_called); - ASSERT_EQ(1, sv_recv_cb_called); + ASSERT_EQ(3, sv_recv_cb_called); ASSERT_OK(client.send_queue_size); ASSERT_OK(server.send_queue_size); diff --git a/test/parallel/test-child-process-stdout-flush-exit.js b/test/parallel/test-child-process-stdout-flush-exit.js index 3c5f00d9bb2b13..90f746c39ef6d3 100644 --- a/test/parallel/test-child-process-stdout-flush-exit.js +++ b/test/parallel/test-child-process-stdout-flush-exit.js @@ -25,9 +25,14 @@ const assert = require('assert'); // If child process output to console and exit // The console.log statements here are part of the test. +// Note: This test verifies specific behavior that is *not* guaranteed +// by Node.js's API contract. See https://nodejs.org/api/process.html#processexitcode. +// We are still generally interested in knowing when this test breaks, +// since applications may rely on the implicit behavior of stdout having +// a buffer size up to which they can write data synchronously. if (process.argv[2] === 'child') { console.log('hello'); - for (let i = 0; i < 200; i++) { + for (let i = 0; i < 100; i++) { console.log('filler'); } console.log('goodbye');