deps: update libuv to 1.50.0

PR-URL: https://github.com/nodejs/node/pull/56616
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Ulises Gascón <ulisesgascongonzalez@gmail.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
This commit is contained in:
Node.js GitHub Bot 2025-01-17 13:54:52 -05:00 committed by GitHub
parent 2e45656eb2
commit a500382d18
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
58 changed files with 1582 additions and 567 deletions

1
deps/uv/.mailmap vendored
View File

@ -52,6 +52,7 @@ San-Tai Hsu <vanilla@fatpipi.com>
Santiago Gimeno <santiago.gimeno@quantion.es> <santiago.gimeno@gmail.com>
Saúl Ibarra Corretgé <s@saghul.net>
Saúl Ibarra Corretgé <s@saghul.net> <saghul@gmail.com>
Saúl Ibarra Corretgé <saghul@gmail.com> <s@saghul.net>
Shigeki Ohtsu <ohtsu@iij.ad.jp> <ohtsu@ohtsu.org>
Shuowang (Wayne) Zhang <shuowang.zhang@ibm.com>
TK-one <tk5641@naver.com>

4
deps/uv/AUTHORS vendored
View File

@ -588,5 +588,7 @@ Raihaan Shouhell <raihaanhimself@gmail.com>
Rialbat <miha-wead@mail.ru>
Adam <adam@NetBSD.org>
Poul T Lomholt <ptlomholt@users.noreply.github.com>
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Thad House <ThadHouse@users.noreply.github.com>
Julian A Avar C <28635807+julian-a-avar-c@users.noreply.github.com>
amcgoogan <105525867+amcgoogan@users.noreply.github.com>
Rafael Gonzaga <rafael.nunu@hotmail.com>

View File

@ -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

83
deps/uv/ChangeLog vendored
View File

@ -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:

1
deps/uv/LINKS.md vendored
View File

@ -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

View File

@ -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))

3
deps/uv/Makefile.am vendored
View File

@ -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 \

View File

@ -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 | |

View File

@ -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])

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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,

View File

@ -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

12
deps/uv/include/uv.h vendored
View File

@ -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;

View File

@ -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_ */

View File

@ -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; \

View File

@ -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 ""

View File

@ -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 <winsock2.h>
#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

View File

@ -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;

2
deps/uv/src/idna.c vendored
View File

@ -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;

View File

@ -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;

View File

@ -38,6 +38,34 @@
#include <sys/eventfd.h>
#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;
}

View File

@ -52,6 +52,8 @@
#endif
#if defined(__APPLE__)
# include <mach/mach.h>
# include <mach/thread_info.h>
# include <sys/filio.h>
# include <sys/sysctl.h>
#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;

View File

@ -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:

View File

@ -35,6 +35,10 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#if defined(__APPLE__) || defined(__DragonFly__) || \
defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/event.h>
#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_ */

View File

@ -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_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);
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();
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);

View File

@ -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;
#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/
*/
if (uv__kernel_version() < /*6.1.51*/0x060133)
return 0;
#endif
/* 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) {
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
#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;
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. */

View File

@ -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);
}

View File

@ -23,6 +23,9 @@
#include "internal.h"
#include <pthread.h>
#ifdef __OpenBSD__
#include <pthread_np.h>
#endif
#include <assert.h>
#include <errno.h>
@ -126,6 +129,12 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
return uv_thread_create_ex(tid, &params, 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

387
deps/uv/src/unix/udp.c vendored
View File

@ -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);
}

View File

@ -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;

View File

@ -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_ */

110
deps/uv/src/win/core.c vendored
View File

@ -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.*/

View File

@ -253,6 +253,8 @@ short_path_done:
}
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));
}

205
deps/uv/src/win/fs.c vendored
View File

@ -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();

View File

@ -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;

View File

@ -95,6 +95,15 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
return uv_thread_create_ex(tid, &params, 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;

21
deps/uv/src/win/udp.c vendored
View File

@ -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;
}

View File

@ -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)

View File

@ -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)

View File

@ -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_ */

View File

@ -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);

14
deps/uv/test/runner.c vendored
View File

@ -27,6 +27,11 @@
#include "task.h"
#include "uv.h"
/* Refs: https://github.com/libuv/libuv/issues/4369 */
#if defined(__ANDROID__)
#include <android/fdsan.h>
#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);

View File

@ -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 */

View File

@ -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

View File

@ -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̞[<i$";
uint16_t buf[32];
ssize_t len;
len = uv_wtf8_length_as_utf16(input);
ASSERT_GT(len, 0);
ASSERT_LT(len, ARRAY_SIZE(buf));
uv_wtf8_to_utf16(input, buf, len);
return 0;
}

View File

@ -466,6 +466,7 @@ TEST_DECLARE (threadpool_cancel_work)
TEST_DECLARE (threadpool_cancel_fs)
TEST_DECLARE (threadpool_cancel_single)
TEST_DECLARE (threadpool_cancel_when_busy)
TEST_DECLARE (thread_detach)
TEST_DECLARE (thread_local_storage)
TEST_DECLARE (thread_stack_size)
TEST_DECLARE (thread_stack_size_explicit)
@ -477,6 +478,8 @@ TEST_DECLARE (thread_create)
TEST_DECLARE (thread_equal)
TEST_DECLARE (thread_affinity)
TEST_DECLARE (thread_priority)
TEST_DECLARE (thread_name)
TEST_DECLARE (thread_name_threadpool)
TEST_DECLARE (dlerror)
#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \
!defined(__sun)
@ -512,6 +515,7 @@ TEST_DECLARE (environment_creation)
TEST_DECLARE (listen_with_simultaneous_accepts)
TEST_DECLARE (listen_no_simultaneous_accepts)
TEST_DECLARE (fs_stat_root)
TEST_DECLARE (fs_stat_no_permission)
TEST_DECLARE (spawn_with_an_odd_path)
TEST_DECLARE (spawn_no_path)
TEST_DECLARE (spawn_no_ext)
@ -572,6 +576,7 @@ TEST_DECLARE (fork_threadpool_queue_work_simple)
TEST_DECLARE (iouring_pollhup)
TEST_DECLARE (wtf8)
TEST_DECLARE (idna_toascii)
TEST_DECLARE (utf8_decode1)
TEST_DECLARE (utf8_decode1_overrun)
@ -1040,6 +1045,7 @@ TASK_LIST_START
TEST_ENTRY (listen_with_simultaneous_accepts)
TEST_ENTRY (listen_no_simultaneous_accepts)
TEST_ENTRY (fs_stat_root)
TEST_ENTRY (fs_stat_no_permission)
TEST_ENTRY (spawn_with_an_odd_path)
TEST_ENTRY (spawn_no_path)
TEST_ENTRY (spawn_no_ext)
@ -1179,6 +1185,7 @@ TASK_LIST_START
TEST_ENTRY (threadpool_cancel_fs)
TEST_ENTRY (threadpool_cancel_single)
TEST_ENTRY (threadpool_cancel_when_busy)
TEST_ENTRY (thread_detach)
TEST_ENTRY (thread_local_storage)
TEST_ENTRY (thread_stack_size)
TEST_ENTRY (thread_stack_size_explicit)
@ -1190,6 +1197,8 @@ TASK_LIST_START
TEST_ENTRY (thread_equal)
TEST_ENTRY (thread_affinity)
TEST_ENTRY (thread_priority)
TEST_ENTRY (thread_name)
TEST_ENTRY (thread_name_threadpool)
TEST_ENTRY (dlerror)
TEST_ENTRY (ip4_addr)
TEST_ENTRY (ip6_addr_link_local)
@ -1223,6 +1232,7 @@ TASK_LIST_START
TEST_ENTRY (iouring_pollhup)
TEST_ENTRY (wtf8)
TEST_ENTRY (utf8_decode1)
TEST_ENTRY (utf8_decode1_overrun)
TEST_ENTRY (uname)

View File

@ -154,6 +154,15 @@ TEST_IMPL(pipe_getsockname) {
ASSERT_STR_EQ(pipe_server.pipe_fname, TEST_PIPENAME);
#endif
r = uv_pipe_getsockname(&pipe_server, NULL, &len);
ASSERT_EQ(r, UV_EINVAL);
r = uv_pipe_getsockname(&pipe_server, buf, NULL);
ASSERT_EQ(r, UV_EINVAL);
r = uv_pipe_getsockname(&pipe_server, NULL, NULL);
ASSERT_EQ(r, UV_EINVAL);
len = sizeof(TEST_PIPENAME) - 1;
ASSERT_EQ(UV_ENOBUFS, uv_pipe_getsockname(&pipe_server, buf, &len));

View File

@ -236,5 +236,21 @@ TEST_IMPL(platform_output) {
printf(" version: %s\n", uname.version);
printf(" machine: %s\n", uname.machine);
ASSERT_OK(uv_getrusage_thread(&rusage));
ASSERT_UINT64_GE(rusage.ru_utime.tv_sec, 0);
ASSERT_UINT64_GE(rusage.ru_utime.tv_usec, 0);
ASSERT_UINT64_GE(rusage.ru_stime.tv_sec, 0);
ASSERT_UINT64_GE(rusage.ru_stime.tv_usec, 0);
printf("uv_getrusage_thread:\n");
printf(" user: %llu sec %llu microsec\n",
(unsigned long long) rusage.ru_utime.tv_sec,
(unsigned long long) rusage.ru_utime.tv_usec);
printf(" system: %llu sec %llu microsec\n",
(unsigned long long) rusage.ru_stime.tv_sec,
(unsigned long long) rusage.ru_stime.tv_usec);
printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt);
printf(" maximum resident set size: %llu\n",
(unsigned long long) rusage.ru_maxrss);
return 0;
}

View File

@ -1329,9 +1329,7 @@ TEST_IMPL(environment_creation) {
}
}
if (prev) { /* verify sort order */
#if !defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR)
ASSERT_EQ(1, CompareStringOrdinal(prev, -1, str, -1, TRUE));
#endif
}
ASSERT(found); /* verify that we expected this variable */
}
@ -1524,7 +1522,7 @@ TEST_IMPL(spawn_setuid_fails) {
init_process_options("spawn_helper1", fail_cb);
options.flags |= UV_PROCESS_SETUID;
/* On IBMi PASE, there is no root user. User may grant
/* On IBMi PASE, there is no root user. User may grant
* root-like privileges, including setting uid to 0.
*/
#if defined(__PASE__)
@ -1575,7 +1573,7 @@ TEST_IMPL(spawn_setgid_fails) {
init_process_options("spawn_helper1", fail_cb);
options.flags |= UV_PROCESS_SETGID;
/* On IBMi PASE, there is no root user. User may grant
/* On IBMi PASE, there is no root user. User may grant
* root-like privileges, including setting gid to 0.
*/
#if defined(__MVS__) || defined(__PASE__)

189
deps/uv/test/test-thread-name.c vendored Normal file
View File

@ -0,0 +1,189 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "task.h"
#include "../src/uv-common.h"
#include <string.h>
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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -33,6 +33,7 @@
#if defined(__APPLE__) || \
defined(_AIX) || \
defined(__MVS__) || \
defined(__FreeBSD__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__)
#define MULTICAST_ADDR "ff02::1%lo0"

View File

@ -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);