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/AUTHORS b/deps/uv/AUTHORS index 041b7aff610f57..39550bbc535eb2 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -588,5 +588,7 @@ 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 diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt index 28c6df25666967..af89db2dfc2762 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 @@ -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 @@ -667,6 +667,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..006a9e1b415de9 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,4 +1,85 @@ -2024.10.18, Version 1.49.2 (Stable) +2025.01.15, Version 1.50.0 (Stable) + +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..743935cebb8532 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 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..9b9e6be7178b22 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 \ @@ -294,6 +294,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/SUPPORTED_PLATFORMS.md b/deps/uv/SUPPORTED_PLATFORMS.md index 8a435d2592e47f..9597801b919687 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 2015 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..fc8316b8e8fa75 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.50.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]) 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/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..f40cf0a33c8121 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,6 +140,23 @@ 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. + + .. 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. + + .. 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. diff --git a/deps/uv/docs/src/threadpool.rst b/deps/uv/docs/src/threadpool.rst index 7cfa797314ca48..05f31d2ccf30b8 100644 --- a/deps/uv/docs/src/threadpool.rst +++ b/deps/uv/docs/src/threadpool.rst @@ -17,6 +17,8 @@ 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`) libuv preallocates and initializes the maximum number of threads allowed by 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/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..f0ec376b607c05 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -157,6 +157,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 +776,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); @@ -1288,6 +1295,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); @@ -1869,6 +1877,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 +1907,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..76eb7d125fe468 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 50 +#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..58d10b8d07fa0b 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 diff --git a/deps/uv/src/fs-poll.c b/deps/uv/src/fs-poll.c index 1bac1c568e36ca..44f6263a5832ec 100644 --- a/deps/uv/src/fs-poll.c +++ b/deps/uv/src/fs-poll.c @@ -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/async.c b/deps/uv/src/unix/async.c index 0ff2669e30a628..8265a43ab47046 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,6 +272,36 @@ 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("/dev/null", 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) @@ -236,6 +312,13 @@ static int uv__async_start(uv_loop_t* loop) { uv__io_start(loop, &loop->async_io_watcher, POLLIN); 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/core.c b/deps/uv/src/unix/core.c index 0c52ccf2ad7b2d..61cbc0d027f04a 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... */ @@ -999,10 +1001,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 +1043,48 @@ 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_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; 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/internal.h b/deps/uv/src/unix/internal.h index 8d586b0b64a96c..b1d2b21756da36 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 { \ @@ -323,6 +327,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); @@ -504,4 +510,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..e0166c344b05c4 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); diff --git a/deps/uv/src/unix/linux.c b/deps/uv/src/unix/linux.c index 857a4ef8a6686f..763f5dd5917b44 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. */ diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index 1f9acfac41e9c5..bd57b17fb0367a 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -360,6 +360,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, @@ -444,7 +447,7 @@ 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]; size_t name_len; int r; @@ -457,26 +460,14 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { 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; - + name_len = sizeof(name_buffer); r = uv_pipe_getsockname(handle, name_buffer, &name_len); - if (r != 0) { - uv__free(name_buffer); + if (r != 0) 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; - } + if (uv__stat(name_buffer, &pipe_stat) == -1) + return UV__ERR(errno); desired_mode = 0; if (mode & UV_READABLE) @@ -485,15 +476,12 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { 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); + if ((pipe_stat.st_mode & desired_mode) == desired_mode) return 0; - } pipe_stat.st_mode |= desired_mode; r = chmod(name_buffer, pipe_stat.st_mode); - uv__free(name_buffer); return r != -1 ? 0 : UV__ERR(errno); } diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index f05e6fe0f7dd5a..e51c290466d08b 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), @@ -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/udp.c b/deps/uv/src/unix/udp.c index f6640fc7231863..67c01f7dce8e18 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 @@ -743,11 +584,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 +631,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 +647,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; + err = uv__udp_sendmsg1(handle->io_watcher.fd, bufs, nbufs, addr); + if (err > 0) + return uv__count_bufs(bufs, 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); - } - - return size; + return err; } @@ -1401,3 +1228,191 @@ 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__) + 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__) */ + + 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..372f0c4b3ac39e 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -191,6 +191,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 +434,18 @@ 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 + #endif /* UV_COMMON_H_ */ diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index e9885a0f1ff389..bc63b06673ac1a 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -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..a4742aa2ec13fd 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; } @@ -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; @@ -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(); 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/thread.c b/deps/uv/src/win/thread.c index bf39b88633b0d8..436846a716807e 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -95,6 +95,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 +278,71 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { } +int uv_thread_setname(const char* name) { + HRESULT hr; + WCHAR* namew; + int err; + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + + 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 = SetThreadDescription(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; + + 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 = GetThreadDescription(*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/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..1d1b2837e1a190 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; } @@ -1589,7 +1633,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..4e0ccc61baf225 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4150,40 +4150,35 @@ typedef struct _FILE_STAT_BASIC_INFORMATION { } 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; @@ -4837,4 +4828,13 @@ typedef int (WINAPI *uv_sGetHostNameW) int); extern uv_sGetHostNameW pGetHostNameW; +/* processthreadsapi.h */ +#if defined(__MINGW32__) +WINBASEAPI +HRESULT WINAPI GetThreadDescription(HANDLE hThread, + PWSTR *ppszThreadDescription); +WINBASEAPI +HRESULT WINAPI SetThreadDescription(HANDLE hThread, PCWSTR lpThreadDescription); +#endif + #endif /* UV_WIN_WINAPI_H_ */ 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.c b/deps/uv/test/runner.c index d1dd02f5ce0806..54abb39dd22886 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); diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index bb223a5f654c03..b53057dc25bb22 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -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); } @@ -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..423d72dd2f7b84 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -4507,6 +4507,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̞[ + +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) { + 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-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);