From af1a79cf490dc805be8b91d719a6aef4dc8fcf0d Mon Sep 17 00:00:00 2001 From: Kevin Adler Date: Thu, 8 Apr 2021 11:00:55 -0500 Subject: [PATCH 001/713] ibmi: Handle interface names longer than 10 chars IBM i interface names are based off the associated line description. Since line descriptions are objects, they have 10 character limit on their names. However, since IBM i 7.2 interface names may be up to 16 characters long if the interface is for a a VLAN (eg. MYETHLINE1.4094). To handle this, we must strip off a VLAN ID to get the actual line description name, since that's what the QDCRLIND API wants. One issue exists because line descriptions can contain periods and numbers; so for interface names less than 10 characters long ETH2.4 could be a line description name or it could be ETH2 with VLAN 4. We follow the method that the XPF ioctls use: try the interface name directly first and if an error occurs, try to strip off the VLAN ID. https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/ioctl.htm#unotes Fixes: https://github.com/libuv/libuv/issues/3062 PR-URL: https://github.com/libuv/libuv/pull/3144 Reviewed-By: Richard Lau --- src/unix/ibmi.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/unix/ibmi.c b/src/unix/ibmi.c index 96efc02bad6..8c6ae636329 100644 --- a/src/unix/ibmi.c +++ b/src/unix/ibmi.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -166,7 +165,7 @@ static void iconv_a2e(const char* src, unsigned char dst[], size_t length) { srclen = strlen(src); if (srclen > length) - abort(); + srclen = length; for (i = 0; i < srclen; i++) dst[i] = a2e[src[i]]; /* padding the remaining part with spaces */ @@ -360,6 +359,10 @@ static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) { if (rc != 0) return rc; + if (err.bytes_available > 0) { + return -1; + } + /* convert ebcdic loca_adapter_address to ascii first */ iconv_e2a(rcvr.loca_adapter_address, mac_addr, sizeof(rcvr.loca_adapter_address)); @@ -443,9 +446,42 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } address->is_internal = cur->ifa_flags & IFF_LOOPBACK ? 1 : 0; if (!address->is_internal) { - int rc = get_ibmi_physical_address(address->name, &address->phys_addr); - if (rc != 0) - r = rc; + int rc = -1; + size_t name_len = strlen(address->name); + /* To get the associated MAC address, we must convert the address to a + * line description. Normally, the name field contains the line + * description name, but for VLANs it has the VLAN appended with a + * period. Since object names can also contain periods and numbers, there + * is no way to know if a returned name is for a VLAN or not. eg. + * *LIND ETH1.1 and *LIND ETH1, VLAN 1 both have the same name: ETH1.1 + * + * Instead, we apply the same heuristic used by some of the XPF ioctls: + * - names > 10 *must* contain a VLAN + * - assume names <= 10 do not contain a VLAN and try directly + * - if >10 or QDCRLIND returned an error, try to strip off a VLAN + * and try again + * - if we still get an error or couldn't find a period, leave the MAC as + * 00:00:00:00:00:00 + */ + if (name_len <= 10) { + /* Assume name does not contain a VLAN ID */ + rc = get_ibmi_physical_address(address->name, &address->phys_addr); + } + + if (name_len > 10 || rc != 0) { + /* The interface name must contain a VLAN ID suffix. Attempt to strip + * it off so we can get the line description to pass to QDCRLIND. + */ + char* temp_name = uv__strdup(address->name); + char* dot = strrchr(temp_name, '.'); + if (dot != NULL) { + *dot = '\0'; + if (strlen(temp_name) <= 10) { + rc = get_ibmi_physical_address(temp_name, &address->phys_addr); + } + } + uv__free(temp_name); + } } address++; @@ -498,4 +534,4 @@ int uv_get_process_title(char* buffer, size_t size) { } void uv__process_title_cleanup(void) { -} \ No newline at end of file +} From 614bdbc56f4df422ae75d09c9ee760b7a7c8b472 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 10 May 2021 19:29:25 -0400 Subject: [PATCH 002/713] docs: update read-the-docs version of sphinx This is specified both as best-practice to specify the defaults explicitly, and as required for updating sphinx from v1.8.5 Refs: https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html PR-URL: https://github.com/libuv/libuv/pull/3154 Reviewed-By: Colin Ihrig --- .readthedocs.yaml | 11 +++++++++++ docs/requirements.txt | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 .readthedocs.yaml create mode 100644 docs/requirements.txt diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000000..e53b9f3e84b --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,11 @@ +version: 2 + +sphinx: + builder: html + configuration: null + fail_on_warning: false + +python: + version: 3.8 + install: + - requirements: docs/requirements.txt diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000000..8386e0178fa --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,42 @@ +# primary +Sphinx==3.5.4 + +# dependencies +alabaster==0.7.12 +appdirs==1.4.3 +Babel==2.9.0 +CacheControl==0.12.6 +certifi==2019.11.28 +chardet==3.0.4 +colorama==0.4.3 +contextlib2==0.6.0 +distlib==0.3.0 +distro==1.4.0 +docutils==0.16 +html5lib==1.0.1 +idna==2.8 +imagesize==1.2.0 +ipaddr==2.2.0 +Jinja2==2.11.3 +lockfile==0.12.2 +MarkupSafe==1.1.1 +msgpack==0.6.2 +packaging==20.3 +pep517==0.8.2 +progress==1.5 +Pygments==2.8.1 +pyparsing==2.4.6 +pytoml==0.1.21 +pytz==2021.1 +requests==2.22.0 +retrying==1.3.3 +six==1.14.0 +snowballstemmer==2.1.0 +sphinxcontrib-applehelp==1.0.2 +sphinxcontrib-devhelp==1.0.2 +sphinxcontrib-htmlhelp==1.0.3 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==1.0.3 +sphinxcontrib-serializinghtml==1.1.4 +urllib3==1.25.8 +webencodings==0.5.1 From 23bebf015b7720991d6422046d34b4888ddb0e75 Mon Sep 17 00:00:00 2001 From: twosee Date: Tue, 11 May 2021 07:44:31 +0800 Subject: [PATCH 003/713] unix: refactor uv_try_write This simplifies the code, for better clarify (and performance)! PR-URL: https://github.com/libuv/libuv/pull/2874 Reviewed-By: Jameson Nash --- src/unix/stream.c | 180 +++++++++++++++++++++------------------------- 1 file changed, 82 insertions(+), 98 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index c0cb20949b6..03a9669cb7b 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -799,33 +799,21 @@ static int uv__handle_fd(uv_handle_t* handle) { } } -static void uv__write(uv_stream_t* stream) { +static int uv__try_write(uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle) { struct iovec* iov; - QUEUE* q; - uv_write_t* req; int iovmax; int iovcnt; ssize_t n; - int err; - -start: - - assert(uv__stream_fd(stream) >= 0); - - if (QUEUE_EMPTY(&stream->write_queue)) - return; - - q = QUEUE_HEAD(&stream->write_queue); - req = QUEUE_DATA(q, uv_write_t, queue); - assert(req->handle == stream); /* * Cast to iovec. We had to have our own uv_buf_t instead of iovec * because Windows's WSABUF is not an iovec. */ - assert(sizeof(uv_buf_t) == sizeof(struct iovec)); - iov = (struct iovec*) &(req->bufs[req->write_index]); - iovcnt = req->nbufs - req->write_index; + iov = (struct iovec*) bufs; + iovcnt = nbufs; iovmax = uv__getiovmax(); @@ -837,8 +825,7 @@ static void uv__write(uv_stream_t* stream) { * Now do the actual writev. Note that we've been updating the pointers * inside the iov each time we write. So there is no need to offset it. */ - - if (req->send_handle) { + if (send_handle != NULL) { int fd_to_send; struct msghdr msg; struct cmsghdr *cmsg; @@ -847,12 +834,10 @@ static void uv__write(uv_stream_t* stream) { struct cmsghdr alias; } scratch; - if (uv__is_closing(req->send_handle)) { - err = UV_EBADF; - goto error; - } + if (uv__is_closing(send_handle)) + return UV_EBADF; - fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); + fd_to_send = uv__handle_fd((uv_handle_t*) send_handle); memset(&scratch, 0, sizeof(scratch)); @@ -882,40 +867,65 @@ static void uv__write(uv_stream_t* stream) { do n = sendmsg(uv__stream_fd(stream), &msg, 0); while (n == -1 && RETRY_ON_WRITE_ERROR(errno)); - - /* Ensure the handle isn't sent again in case this is a partial write. */ - if (n >= 0) - req->send_handle = NULL; } else { do n = uv__writev(uv__stream_fd(stream), iov, iovcnt); while (n == -1 && RETRY_ON_WRITE_ERROR(errno)); } - if (n == -1 && !IS_TRANSIENT_WRITE_ERROR(errno, req->send_handle)) { - err = UV__ERR(errno); - goto error; - } + if (n >= 0) + return n; - if (n >= 0 && uv__write_req_update(stream, req, n)) { - uv__write_req_finish(req); - return; /* TODO(bnoordhuis) Start trying to write the next request. */ - } + if (IS_TRANSIENT_WRITE_ERROR(errno, send_handle)) + return UV_EAGAIN; - /* If this is a blocking stream, try again. */ - if (stream->flags & UV_HANDLE_BLOCKING_WRITES) - goto start; + return UV__ERR(errno); +} - /* We're not done. */ - uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); +static void uv__write(uv_stream_t* stream) { + QUEUE* q; + uv_write_t* req; + ssize_t n; - /* Notify select() thread about state change */ - uv__stream_osx_interrupt_select(stream); + assert(uv__stream_fd(stream) >= 0); + + for (;;) { + if (QUEUE_EMPTY(&stream->write_queue)) + return; + + q = QUEUE_HEAD(&stream->write_queue); + req = QUEUE_DATA(q, uv_write_t, queue); + assert(req->handle == stream); + + n = uv__try_write(stream, + &(req->bufs[req->write_index]), + req->nbufs - req->write_index, + req->send_handle); + + /* Ensure the handle isn't sent again in case this is a partial write. */ + if (n >= 0) { + req->send_handle = NULL; + if (uv__write_req_update(stream, req, n)) { + uv__write_req_finish(req); + return; /* TODO(bnoordhuis) Start trying to write the next request. */ + } + } else if (n != UV_EAGAIN) + break; - return; + /* If this is a blocking stream, try again. */ + if (stream->flags & UV_HANDLE_BLOCKING_WRITES) + continue; + + /* We're not done. */ + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); -error: - req->error = err; + /* Notify select() thread about state change */ + uv__stream_osx_interrupt_select(stream); + + return; + } + + req->error = n; uv__write_req_finish(req); uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); if (!uv__io_active(&stream->io_watcher, POLLIN)) @@ -1390,14 +1400,9 @@ static void uv__stream_connect(uv_stream_t* stream) { } -int uv_write2(uv_write_t* req, - uv_stream_t* stream, - const uv_buf_t bufs[], - unsigned int nbufs, - uv_stream_t* send_handle, - uv_write_cb cb) { - int empty_queue; - +static int uv__check_before_write(uv_stream_t* stream, + unsigned int nbufs, + uv_stream_t* send_handle) { assert(nbufs > 0); assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || @@ -1410,7 +1415,7 @@ int uv_write2(uv_write_t* req, if (!(stream->flags & UV_HANDLE_WRITABLE)) return UV_EPIPE; - if (send_handle) { + if (send_handle != NULL) { if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) return UV_EINVAL; @@ -1430,6 +1435,22 @@ int uv_write2(uv_write_t* req, #endif } + return 0; +} + +int uv_write2(uv_write_t* req, + uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle, + uv_write_cb cb) { + int empty_queue; + int err; + + err = uv__check_before_write(stream, nbufs, send_handle); + if (err < 0) + return err; + /* It's legal for write_queue_size > 0 even when the write_queue is empty; * it means there are error-state requests in the write_completed_queue that * will touch up write_queue_size later, see also uv__write_req_finish(). @@ -1498,57 +1519,20 @@ int uv_write(uv_write_t* req, } -void uv_try_write_cb(uv_write_t* req, int status) { - /* Should not be called */ - abort(); -} - - int uv_try_write(uv_stream_t* stream, const uv_buf_t bufs[], unsigned int nbufs) { - int r; - int has_pollout; - size_t written; - size_t req_size; - uv_write_t req; + int err; /* Connecting or already writing some data */ if (stream->connect_req != NULL || stream->write_queue_size != 0) return UV_EAGAIN; - has_pollout = uv__io_active(&stream->io_watcher, POLLOUT); - - r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb); - if (r != 0) - return r; - - /* Remove not written bytes from write queue size */ - written = uv__count_bufs(bufs, nbufs); - if (req.bufs != NULL) - req_size = uv__write_req_size(&req); - else - req_size = 0; - written -= req_size; - stream->write_queue_size -= req_size; - - /* Unqueue request, regardless of immediateness */ - QUEUE_REMOVE(&req.queue); - uv__req_unregister(stream->loop, &req); - if (req.bufs != req.bufsml) - uv__free(req.bufs); - req.bufs = NULL; - - /* Do not poll for writable, if we wasn't before calling this */ - if (!has_pollout) { - uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); - uv__stream_osx_interrupt_select(stream); - } + err = uv__check_before_write(stream, nbufs, NULL); + if (err < 0) + return err; - if (written == 0 && req_size != 0) - return req.error < 0 ? req.error : UV_EAGAIN; - else - return written; + return uv__try_write(stream, bufs, nbufs, NULL); } From 8635170d8fa512fbaf0e8810b2b9854718c57246 Mon Sep 17 00:00:00 2001 From: yiyuaner Date: Thu, 13 May 2021 06:41:30 +0800 Subject: [PATCH 004/713] linux-core: add proper divide by zero assert PR-URL: https://github.com/libuv/libuv/pull/3166 Reviewed-By: Jameson Nash Reviewed-By: Colin Ihrig Reviewed-By: Richard Lau --- src/unix/linux-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index c356e96d2de..8746744d563 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -855,9 +855,9 @@ static int read_times(FILE* statfile_fp, char buf[1024]; ticks = (unsigned int)sysconf(_SC_CLK_TCK); - multiplier = ((uint64_t)1000L / ticks); assert(ticks != (unsigned int) -1); assert(ticks != 0); + multiplier = ((uint64_t)1000L / ticks); rewind(statfile_fp); From 5c19f73aa206fcd2be55e2f20aaa8939b3cc5ff9 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Thu, 13 May 2021 04:12:29 +0530 Subject: [PATCH 005/713] misc: remove unnecessary _GNU_SOURCE macros Since we are building with the `-D_GNU_SOURCE` option turned on, the macro definitions are not needed anymore. Refs: https://github.com/libuv/libuv/pull/3165#issuecomment-835747442 PR-URL: https://github.com/libuv/libuv/pull/3168 Reviewed-By: Jameson Nash Reviewed-By: Ben Noordhuis --- src/unix/getaddrinfo.c | 3 --- src/unix/linux-syscalls.h | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/unix/getaddrinfo.c b/src/unix/getaddrinfo.c index d7ca7d1a446..77337ace945 100644 --- a/src/unix/getaddrinfo.c +++ b/src/unix/getaddrinfo.c @@ -21,9 +21,6 @@ /* Expose glibc-specific EAI_* error codes. Needs to be defined before we * include any headers. */ -#ifndef _GNU_SOURCE -# define _GNU_SOURCE -#endif #include "uv.h" #include "internal.h" diff --git a/src/unix/linux-syscalls.h b/src/unix/linux-syscalls.h index c85231f6bf4..b4d9082d46f 100644 --- a/src/unix/linux-syscalls.h +++ b/src/unix/linux-syscalls.h @@ -22,9 +22,6 @@ #ifndef UV_LINUX_SYSCALL_H_ #define UV_LINUX_SYSCALL_H_ -#undef _GNU_SOURCE -#define _GNU_SOURCE - #include #include #include From 0714eded1947eaf47bc4e7efabe40e8440ca1a00 Mon Sep 17 00:00:00 2001 From: bbara Date: Thu, 13 May 2021 00:45:47 +0200 Subject: [PATCH 006/713] test: log to stdout to conform TAP spec The TAP specification [1] explicitely states: A harness must only read TAP output from standard output and not from standard error. [1] https://testanything.org/tap-specification.html PR-URL: https://github.com/libuv/libuv/pull/3153 Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Jameson Nash Reviewed-By: Ben Noordhuis --- test/runner.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/test/runner.c b/test/runner.c index bb50b43b304..789108275cd 100644 --- a/test/runner.c +++ b/test/runner.c @@ -98,8 +98,8 @@ int run_tests(int benchmark_output) { skip = (actual > 0 && 0 == strcmp(TASKS[0].task_name, "platform_output")); qsort(TASKS + skip, actual - skip, sizeof(TASKS[0]), compare_task); - fprintf(stderr, "1..%d\n", total); - fflush(stderr); + fprintf(stdout, "1..%d\n", total); + fflush(stdout); /* Run all tests. */ passed = 0; @@ -156,8 +156,8 @@ void log_tap_result(int test_count, reason[0] = '\0'; } - fprintf(stderr, "%s %d - %s%s%s\n", result, test_count, test, directive, reason); - fflush(stderr); + fprintf(stdout, "%s %d - %s%s%s\n", result, test_count, test, directive, reason); + fflush(stdout); } @@ -307,28 +307,28 @@ int run_test(const char* test, /* Show error and output from processes if the test failed. */ if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) { if (strlen(errmsg) > 0) - fprintf(stderr, "# %s\n", errmsg); - fprintf(stderr, "# "); - fflush(stderr); + fprintf(stdout, "# %s\n", errmsg); + fprintf(stdout, "# "); + fflush(stdout); for (i = 0; i < process_count; i++) { switch (process_output_size(&processes[i])) { case -1: - fprintf(stderr, "Output from process `%s`: (unavailable)\n", + fprintf(stdout, "Output from process `%s`: (unavailable)\n", process_get_name(&processes[i])); - fflush(stderr); + fflush(stdout); break; case 0: - fprintf(stderr, "Output from process `%s`: (no output)\n", + fprintf(stdout, "Output from process `%s`: (no output)\n", process_get_name(&processes[i])); - fflush(stderr); + fflush(stdout); break; default: - fprintf(stderr, "Output from process `%s`:\n", process_get_name(&processes[i])); - fflush(stderr); - process_copy_output(&processes[i], stderr); + fprintf(stdout, "Output from process `%s`:\n", process_get_name(&processes[i])); + fflush(stdout); + process_copy_output(&processes[i], stdout); break; } } @@ -337,18 +337,18 @@ int run_test(const char* test, } else if (benchmark_output) { switch (process_output_size(main_proc)) { case -1: - fprintf(stderr, "%s: (unavailable)\n", test); - fflush(stderr); + fprintf(stdout, "%s: (unavailable)\n", test); + fflush(stdout); break; case 0: - fprintf(stderr, "%s: (no output)\n", test); - fflush(stderr); + fprintf(stdout, "%s: (no output)\n", test); + fflush(stdout); break; default: for (i = 0; i < process_count; i++) { - process_copy_output(&processes[i], stderr); + process_copy_output(&processes[i], stdout); } break; } @@ -378,8 +378,8 @@ int run_test_part(const char* test, const char* part) { } } - fprintf(stderr, "No test part with that name: %s:%s\n", test, part); - fflush(stderr); + fprintf(stdout, "No test part with that name: %s:%s\n", test, part); + fflush(stdout); return 255; } From 882ee25346d7e0cf021f67c22475fcb0995b2c06 Mon Sep 17 00:00:00 2001 From: SeverinLeonhardt Date: Thu, 13 May 2021 00:48:29 +0200 Subject: [PATCH 007/713] win,fs: fix C4090 warning with MSVC When compiling the current code MSVC prints this warning: warning C4090: '=': different 'const' qualifiers This warning was introduced with dc6fdcd where the `(char*)` cast for the call to `wcstombs` was removed. Re-adding this cast to silence the warning. PR-URL: https://github.com/libuv/libuv/pull/3146 Refs: https://github.com/libuv/libuv/pull/2938 Reviewed-By: Richard Lau Reviewed-By: Jameson Nash --- src/win/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/fs.c b/src/win/fs.c index a083b5e82c8..674070400be 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1238,7 +1238,7 @@ void fs__mktemp(uv_fs_t* req, uv__fs_mktemp_func func) { uint64_t v; char* path; - path = req->path; + path = (char*)req->path; len = wcslen(req->file.pathw); ep = req->file.pathw + len; if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) { From defed5008011d5b187934d42629c850b5147f5ea Mon Sep 17 00:00:00 2001 From: Andy Fiddaman Date: Wed, 12 May 2021 22:51:36 +0000 Subject: [PATCH 008/713] build: some systems provide dlopen() in libc libuv is packaged for OmniOS, an illumos distribution (OpenSolaris fork), and on that platform `libdl.so` is just a legacy stub library that does not need to be linked. `dlopen()` and friends are present in libc. Changing to using `AC_SEARCH_LIBS()` instead of `AC_CHECK_LIB()` stops the unnecessary linking of libdl. PR-URL: https://github.com/libuv/libuv/pull/3113 Reviewed-By: Ben Noordhuis Reviewed-By: Jameson Nash --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4bdc7fd3f53..3c13d4015b1 100644 --- a/configure.ac +++ b/configure.ac @@ -43,7 +43,7 @@ AX_PTHREAD([ LIBS="$LIBS $PTHREAD_LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" ]) -AC_CHECK_LIB([dl], [dlopen]) +AC_SEARCH_LIBS([dlopen], [dl]) AC_SEARCH_LIBS([kstat_lookup], [kstat]) AC_SEARCH_LIBS([gethostbyname], [nsl]) AC_SEARCH_LIBS([perfstat_cpu], [perfstat]) From 9739400d41f3f325713b1ae737e5de056a35fe29 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Thu, 13 May 2021 20:31:14 +0530 Subject: [PATCH 009/713] include: add EOVERFLOW status code mapping Refs: https://github.com/nodejs/node/pull/38159#discussion_r610288214 PR-URL: https://github.com/libuv/libuv/pull/3145 Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Jameson Nash --- docs/src/errors.rst | 4 ++++ include/uv.h | 1 + include/uv/errno.h | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/docs/src/errors.rst b/docs/src/errors.rst index c2daa8584eb..25d0efaf031 100644 --- a/docs/src/errors.rst +++ b/docs/src/errors.rst @@ -251,6 +251,10 @@ Error constants operation not supported on socket +.. c:macro:: UV_EOVERFLOW + + value too large for defined data type + .. c:macro:: UV_EPERM operation not permitted diff --git a/include/uv.h b/include/uv.h index deda6ca715d..d2bdcc9cf04 100644 --- a/include/uv.h +++ b/include/uv.h @@ -126,6 +126,7 @@ extern "C" { XX(ENOTEMPTY, "directory not empty") \ XX(ENOTSOCK, "socket operation on non-socket") \ XX(ENOTSUP, "operation not supported on socket") \ + XX(EOVERFLOW, "value too large for defined data type") \ XX(EPERM, "operation not permitted") \ XX(EPIPE, "broken pipe") \ XX(EPROTO, "protocol error") \ diff --git a/include/uv/errno.h b/include/uv/errno.h index aadce9c14c9..a0ca571b0d1 100644 --- a/include/uv/errno.h +++ b/include/uv/errno.h @@ -445,4 +445,10 @@ # define UV__EILSEQ (-4027) #endif +#if defined(EOVERFLOW) && !defined(_WIN32) +# define UV__EOVERFLOW UV__ERR(EOVERFLOW) +#else +# define UV__EOVERFLOW (-4026) +#endif + #endif /* UV_ERRNO_H_ */ From b94934f01257d19814baddd175fae7477dfebb1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Romain=20Roff=C3=A9?= Date: Thu, 13 May 2021 17:06:22 +0200 Subject: [PATCH 010/713] win,build: Add cmake -DSTATIC_VCRT=ON option PR-URL: https://github.com/libuv/libuv/pull/3085 Reviewed-By: Jameson Nash --- CMakeLists.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f81aa959d62..daa236f4320 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,10 @@ cmake_minimum_required(VERSION 3.4) -project(libuv LANGUAGES C) cmake_policy(SET CMP0057 NEW) # Enable IN_LIST operator cmake_policy(SET CMP0064 NEW) # Support if (TEST) operator +cmake_policy(SET CMP0091 NEW) # Enable CMAKE_MSVC_RUNTIME_LIBRARY + +project(libuv LANGUAGES C) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") @@ -38,6 +40,14 @@ if(ASAN AND CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address") endif() +# MSVC options +if(MSVC) + option(STATIC_VCRT "Force /MT for static VC runtimes" OFF) + if(STATIC_VCRT) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif() +endif() + # Compiler check string(CONCAT is-msvc $, From 9864053c9c969ef6b725504de192b29aed8a28a9 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Thu, 13 May 2021 20:48:43 +0530 Subject: [PATCH 011/713] unix,fs: use uv__load_relaxed and uv__store_relaxed This is more clear about the intended semantics with multiple threads. PR-URL: https://github.com/libuv/libuv/pull/3124 Reviewed-By: Ben Noordhuis Reviewed-By: Jameson Nash --- src/unix/fs.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 8ff5fd24d0d..eb17fb4a23e 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -965,18 +965,20 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { #ifdef __linux__ { - static int copy_file_range_support = 1; + static int no_copy_file_range_support; - if (copy_file_range_support) { + if (uv__load_relaxed(&no_copy_file_range_support) == 0) { r = uv__fs_copy_file_range(in_fd, &off, out_fd, NULL, req->bufsml[0].len, 0); if (r == -1 && errno == ENOSYS) { /* ENOSYS - it will never work */ errno = 0; - copy_file_range_support = 0; + uv__store_relaxed(&no_copy_file_range_support, 1); } else if (r == -1 && errno == EACCES && uv__is_buggy_cephfs(in_fd)) { + /* EACCES - pre-4.20 kernels have a bug where CephFS uses the RADOS + copy-from command when it shouldn't */ errno = 0; - copy_file_range_support = 0; + uv__store_relaxed(&no_copy_file_range_support, 1); } else if (r == -1 && (errno == ENOTSUP || errno == EXDEV)) { /* ENOTSUP - it could work on another file system type */ /* EXDEV - it will not work when in_fd and out_fd are not on the same From 95f88f47f28b4686a6959377c8d2c31daa40bd64 Mon Sep 17 00:00:00 2001 From: Eagle Liang Date: Thu, 13 May 2021 23:42:55 +0800 Subject: [PATCH 012/713] win: fix string encoding issue of uv_os_gethostname Windows API gethostname(buffer, size) return unicode string in char array. It will cause garbled code if the host name contains non ascii characters without cast into multi byte char. This change keep the same encoding with the implementation on Unix/macOS platform, which is utf-8. Requires Windows 8 / Server 2012. Fixes: https://github.com/libuv/libuv/issues/3148 PR-URL: https://github.com/libuv/libuv/pull/3149 Reviewed-By: Jameson Nash --- src/win/util.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/win/util.c b/src/win/util.c index aad8f1a15e9..88602c7ee86 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1664,26 +1664,33 @@ int uv_os_unsetenv(const char* name) { int uv_os_gethostname(char* buffer, size_t* size) { - char buf[UV_MAXHOSTNAMESIZE]; + WCHAR buf[UV_MAXHOSTNAMESIZE]; size_t len; + char* utf8_str; + int convert_result; if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; uv__once_init(); /* Initialize winsock */ - if (gethostname(buf, sizeof(buf)) != 0) + if (GetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0) return uv_translate_sys_error(WSAGetLastError()); - buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ - len = strlen(buf); + convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str); + if (convert_result != 0) + return convert_result; + + len = strlen(utf8_str); if (len >= *size) { *size = len + 1; + uv__free(utf8_str); return UV_ENOBUFS; } - memcpy(buffer, buf, len + 1); + memcpy(buffer, utf8_str, len + 1); + uv__free(utf8_str); *size = len; return 0; } From ac5b21a2c900a3fa33cb49acf637039d7c8af28e Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 13 May 2021 23:07:14 -0400 Subject: [PATCH 013/713] Revert "win,build: Add cmake -DSTATIC_VCRT=ON option" This reverts commit b94934f01257d19814baddd175fae7477dfebb1a. The required version of cmake (3.15) is newer than we are currently using in Android CI (3.10). PR-URL: https://github.com/libuv/libuv/pull/3172 Refs: https://github.com/libuv/libuv/pull/3085 --- CMakeLists.txt | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index daa236f4320..f81aa959d62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,8 @@ cmake_minimum_required(VERSION 3.4) +project(libuv LANGUAGES C) cmake_policy(SET CMP0057 NEW) # Enable IN_LIST operator cmake_policy(SET CMP0064 NEW) # Support if (TEST) operator -cmake_policy(SET CMP0091 NEW) # Enable CMAKE_MSVC_RUNTIME_LIBRARY - -project(libuv LANGUAGES C) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") @@ -40,14 +38,6 @@ if(ASAN AND CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address") endif() -# MSVC options -if(MSVC) - option(STATIC_VCRT "Force /MT for static VC runtimes" OFF) - if(STATIC_VCRT) - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - endif() -endif() - # Compiler check string(CONCAT is-msvc $, From 6dbb1e2e1d467b93456fc9b0981d13354b0a9be7 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Thu, 20 May 2021 22:53:12 +0800 Subject: [PATCH 014/713] unix,process: add uv__write_errno helper function No functional changes, but slightly more compact code. PR-URL: https://github.com/libuv/libuv/pull/3059 Reviewed-By: Jameson Nash --- src/unix/process.c | 55 +++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index 418bd530dda..f4aebb0490e 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -201,6 +201,12 @@ static void uv__write_int(int fd, int val) { } +static void uv__write_errno(int error_fd) { + uv__write_int(error_fd, UV__ERR(errno)); + _exit(127); +} + + #if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) /* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be * avoided. Since this isn't called on those targets, the function @@ -229,10 +235,8 @@ static void uv__process_child_init(const uv_process_options_t* options, if (use_fd < 0 || use_fd >= fd) continue; pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); - if (pipes[fd][1] == -1) { - uv__write_int(error_fd, UV__ERR(errno)); - _exit(127); - } + if (pipes[fd][1] == -1) + uv__write_errno(error_fd); } for (fd = 0; fd < stdio_count; fd++) { @@ -249,10 +253,8 @@ static void uv__process_child_init(const uv_process_options_t* options, use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); close_fd = use_fd; - if (use_fd < 0) { - uv__write_int(error_fd, UV__ERR(errno)); - _exit(127); - } + if (use_fd < 0) + uv__write_errno(error_fd); } } @@ -261,10 +263,8 @@ static void uv__process_child_init(const uv_process_options_t* options, else fd = dup2(use_fd, fd); - if (fd == -1) { - uv__write_int(error_fd, UV__ERR(errno)); - _exit(127); - } + if (fd == -1) + uv__write_errno(error_fd); if (fd <= 2) uv__nonblock_fcntl(fd, 0); @@ -280,10 +280,8 @@ static void uv__process_child_init(const uv_process_options_t* options, uv__close(use_fd); } - if (options->cwd != NULL && chdir(options->cwd)) { - uv__write_int(error_fd, UV__ERR(errno)); - _exit(127); - } + if (options->cwd != NULL && chdir(options->cwd)) + uv__write_errno(error_fd); if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { /* When dropping privileges from root, the `setgroups` call will @@ -296,15 +294,11 @@ static void uv__process_child_init(const uv_process_options_t* options, SAVE_ERRNO(setgroups(0, NULL)); } - if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) { - uv__write_int(error_fd, UV__ERR(errno)); - _exit(127); - } + if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) + uv__write_errno(error_fd); - if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { - uv__write_int(error_fd, UV__ERR(errno)); - _exit(127); - } + if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) + uv__write_errno(error_fd); if (options->env != NULL) { environ = options->env; @@ -327,26 +321,23 @@ static void uv__process_child_init(const uv_process_options_t* options, if (SIG_ERR != signal(n, SIG_DFL)) continue; - uv__write_int(error_fd, UV__ERR(errno)); - _exit(127); + uv__write_errno(error_fd); } /* Reset signal mask. */ sigemptyset(&set); err = pthread_sigmask(SIG_SETMASK, &set, NULL); - if (err != 0) { - uv__write_int(error_fd, UV__ERR(err)); - _exit(127); - } + if (err != 0) + uv__write_errno(error_fd); #ifdef __MVS__ execvpe(options->file, options->args, environ); #else execvp(options->file, options->args); #endif - uv__write_int(error_fd, UV__ERR(errno)); - _exit(127); + + uv__write_errno(error_fd); } #endif From ce15b8405e9d01e221f8390475deab4a40d26e38 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 21 May 2021 16:20:07 -0400 Subject: [PATCH 015/713] Re-merge "unix,stream: clear read/write states on close/eof" This reverts commit 46f36e3df1a666620f6749427f15651cbc4b7001. PR-URL: https://github.com/libuv/libuv/pull/3006 Refs: https://github.com/libuv/libuv/pull/2967 Refs: https://github.com/libuv/libuv/pull/2409 Refs: https://github.com/libuv/libuv/issues/2943 Refs: https://github.com/libuv/libuv/pull/2968 Refs: https://github.com/nodejs/node/pull/36111 Reviewed-By: Santiago Gimeno --- CMakeLists.txt | 3 + Makefile.am | 3 + src/unix/stream.c | 3 + src/win/tcp.c | 2 + test/echo-server.c | 10 +- test/test-list.h | 11 ++ ...-not-readable-nor-writable-on-read-error.c | 104 ++++++++++++++++++ test/test-not-readable-on-eof.c | 103 +++++++++++++++++ test/test-not-writable-after-shutdown.c | 69 ++++++++++++ 9 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 test/test-not-readable-nor-writable-on-read-error.c create mode 100644 test/test-not-readable-on-eof.c create mode 100644 test/test-not-writable-after-shutdown.c diff --git a/CMakeLists.txt b/CMakeLists.txt index f81aa959d62..0217c01b2c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -485,6 +485,9 @@ if(LIBUV_BUILD_TESTS) test/test-metrics.c test/test-multiple-listen.c test/test-mutexes.c + test/test-not-readable-nor-writable-on-read-error.c + test/test-not-readable-on-eof.c + test/test-not-writable-after-shutdown.c test/test-osx-select.c test/test-pass-always.c test/test-ping-pong.c diff --git a/Makefile.am b/Makefile.am index e8bab4963dd..6f2d018c4a7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -206,6 +206,9 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-metrics.c \ test/test-multiple-listen.c \ test/test-mutexes.c \ + test/test-not-readable-nor-writable-on-read-error.c \ + test/test-not-readable-on-eof.c \ + test/test-not-writable-after-shutdown.c \ test/test-osx-select.c \ test/test-pass-always.c \ test/test-ping-pong.c \ diff --git a/src/unix/stream.c b/src/unix/stream.c index 03a9669cb7b..dd1f5538c3d 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1011,6 +1011,7 @@ uv_handle_type uv__handle_type(int fd) { static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { stream->flags |= UV_HANDLE_READ_EOF; stream->flags &= ~UV_HANDLE_READING; + stream->flags &= ~UV_HANDLE_READABLE; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); @@ -1198,6 +1199,7 @@ static void uv__read(uv_stream_t* stream) { #endif } else { /* Error. User should call uv_close(). */ + stream->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); stream->read_cb(stream, UV__ERR(errno), &buf); if (stream->flags & UV_HANDLE_READING) { stream->flags &= ~UV_HANDLE_READING; @@ -1286,6 +1288,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { req->cb = cb; stream->shutdown_req = req; stream->flags |= UV_HANDLE_SHUTTING; + stream->flags &= ~UV_HANDLE_WRITABLE; uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); diff --git a/src/win/tcp.c b/src/win/tcp.c index 517700e66d8..890877baf2c 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -1024,6 +1024,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, */ err = WSAECONNRESET; } + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(err), @@ -1105,6 +1106,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, * Unix. */ err = WSAECONNRESET; } + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(err), diff --git a/test/echo-server.c b/test/echo-server.c index ef58d280ae1..e69c0e262b3 100644 --- a/test/echo-server.c +++ b/test/echo-server.c @@ -69,7 +69,6 @@ static void after_shutdown(uv_shutdown_t* req, int status) { free(req); } - static void after_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { @@ -96,13 +95,20 @@ static void after_read(uv_stream_t* handle, /* * Scan for the letter Q which signals that we should quit the server. * If we get QS it means close the stream. + * If we get QSH it means disable linger before close the socket. */ if (!server_closed) { for (i = 0; i < nread; i++) { if (buf->base[i] == 'Q') { if (i + 1 < nread && buf->base[i + 1] == 'S') { + int reset = 0; + if (i + 2 < nread && buf->base[i + 2] == 'H') + reset = 1; free(buf->base); - uv_close((uv_handle_t*)handle, on_close); + if (reset && handle->type == UV_TCP) + ASSERT(0 == uv_tcp_close_reset((uv_tcp_t*) handle, on_close)); + else + uv_close((uv_handle_t*) handle, on_close); return; } else { uv_close(server, on_server_close); diff --git a/test/test-list.h b/test/test-list.h index d7c7b086f03..c3c6002ea3d 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -504,6 +504,10 @@ TEST_DECLARE (handle_type_name) TEST_DECLARE (req_type_name) TEST_DECLARE (getters_setters) +TEST_DECLARE (not_writable_after_shutdown) +TEST_DECLARE (not_readable_nor_writable_on_read_error) +TEST_DECLARE (not_readable_on_eof) + #ifndef _WIN32 TEST_DECLARE (fork_timer) TEST_DECLARE (fork_socketpair) @@ -1127,6 +1131,13 @@ TASK_LIST_START TEST_ENTRY (idna_toascii) #endif + TEST_ENTRY (not_writable_after_shutdown) + TEST_HELPER (not_writable_after_shutdown, tcp4_echo_server) + TEST_ENTRY (not_readable_nor_writable_on_read_error) + TEST_HELPER (not_readable_nor_writable_on_read_error, tcp4_echo_server) + TEST_ENTRY (not_readable_on_eof) + TEST_HELPER (not_readable_on_eof, tcp4_echo_server) + TEST_ENTRY (metrics_idle_time) TEST_ENTRY (metrics_idle_time_thread) TEST_ENTRY (metrics_idle_time_zero) diff --git a/test/test-not-readable-nor-writable-on-read-error.c b/test/test-not-readable-nor-writable-on-read-error.c new file mode 100644 index 00000000000..ae951e39893 --- /dev/null +++ b/test/test-not-readable-nor-writable-on-read-error.c @@ -0,0 +1,104 @@ +/* Copyright the 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" + +static uv_loop_t loop; +static uv_tcp_t tcp_client; +static uv_connect_t connect_req; +static uv_write_t write_req; +static char reset_me_cmd[] = {'Q', 'S', 'H'}; + +static int connect_cb_called; +static int read_cb_called; +static int write_cb_called; +static int close_cb_called; + +static void write_cb(uv_write_t* req, int status) { + write_cb_called++; + ASSERT(status == 0); +} + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[64]; + buf->base = slab; + buf->len = sizeof(slab); +} + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + +static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { + read_cb_called++; + + ASSERT((nread < 0) && (nread != UV_EOF)); + ASSERT(0 == uv_is_writable(handle)); + ASSERT(0 == uv_is_readable(handle)); + + uv_close((uv_handle_t*) handle, close_cb); +} + +static void connect_cb(uv_connect_t* req, int status) { + int r; + uv_buf_t reset_me; + + connect_cb_called++; + ASSERT(status == 0); + + r = uv_read_start((uv_stream_t*) &tcp_client, alloc_cb, read_cb); + ASSERT(r == 0); + + reset_me = uv_buf_init(reset_me_cmd, sizeof(reset_me_cmd)); + + r = uv_write(&write_req, + (uv_stream_t*) &tcp_client, + &reset_me, + 1, + write_cb); + + ASSERT(r == 0); +} + +TEST_IMPL(not_readable_nor_writable_on_read_error) { + struct sockaddr_in sa; + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &sa)); + ASSERT(0 == uv_loop_init(&loop)); + ASSERT(0 == uv_tcp_init(&loop, &tcp_client)); + + ASSERT(0 == uv_tcp_connect(&connect_req, + &tcp_client, + (const struct sockaddr*) &sa, + connect_cb)); + + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + + ASSERT(connect_cb_called == 1); + ASSERT(read_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-not-readable-on-eof.c b/test/test-not-readable-on-eof.c new file mode 100644 index 00000000000..2bb5f4eeccc --- /dev/null +++ b/test/test-not-readable-on-eof.c @@ -0,0 +1,103 @@ +/* Copyright the 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" + +static uv_loop_t loop; +static uv_tcp_t tcp_client; +static uv_connect_t connect_req; +static uv_write_t write_req; +static char close_me_cmd[] = {'Q', 'S'}; + +static int connect_cb_called; +static int read_cb_called; +static int write_cb_called; +static int close_cb_called; + +static void write_cb(uv_write_t* req, int status) { + write_cb_called++; + ASSERT(status == 0); +} + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[64]; + buf->base = slab; + buf->len = sizeof(slab); +} + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + +static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { + read_cb_called++; + + ASSERT(nread == UV_EOF); + ASSERT(0 == uv_is_readable(handle)); + + uv_close((uv_handle_t*) handle, close_cb); +} + +static void connect_cb(uv_connect_t* req, int status) { + int r; + uv_buf_t close_me; + + connect_cb_called++; + ASSERT(status == 0); + + r = uv_read_start((uv_stream_t*) &tcp_client, alloc_cb, read_cb); + ASSERT(r == 0); + + close_me = uv_buf_init(close_me_cmd, sizeof(close_me_cmd)); + + r = uv_write(&write_req, + (uv_stream_t*) &tcp_client, + &close_me, + 1, + write_cb); + + ASSERT(r == 0); +} + +TEST_IMPL(not_readable_on_eof) { + struct sockaddr_in sa; + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &sa)); + ASSERT(0 == uv_loop_init(&loop)); + ASSERT(0 == uv_tcp_init(&loop, &tcp_client)); + + ASSERT(0 == uv_tcp_connect(&connect_req, + &tcp_client, + (const struct sockaddr*) &sa, + connect_cb)); + + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + + ASSERT(connect_cb_called == 1); + ASSERT(read_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-not-writable-after-shutdown.c b/test/test-not-writable-after-shutdown.c new file mode 100644 index 00000000000..9cd93703cea --- /dev/null +++ b/test/test-not-writable-after-shutdown.c @@ -0,0 +1,69 @@ +/* Copyright the 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" + +static uv_shutdown_t shutdown_req; + +static void close_cb(uv_handle_t* handle) { + +} + +static void shutdown_cb(uv_shutdown_t* req, int status) { + uv_close((uv_handle_t*) req->handle, close_cb); +} + +static void connect_cb(uv_connect_t* req, int status) { + int r; + ASSERT(status == 0); + + r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb); + ASSERT(r == 0); + + ASSERT(0 == uv_is_writable(req->handle)); +} + +TEST_IMPL(not_writable_after_shutdown) { + int r; + struct sockaddr_in addr; + uv_loop_t* loop; + uv_tcp_t socket; + uv_connect_t connect_req; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + loop = uv_default_loop(); + + r = uv_tcp_init(loop, &socket); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, + &socket, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From a064166bd2dfca37de7b317328781424bcfc200e Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Sat, 22 May 2021 01:57:22 +0530 Subject: [PATCH 016/713] unix,core: fix errno handling in uv__getpwuid_r Fixes: https://github.com/libuv/libuv/issues/3174 PR-URL: https://github.com/libuv/libuv/pull/3177 Reviewed-By: Jameson Nash --- src/unix/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 15aa57d96dd..e0246a2e7e7 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1184,7 +1184,9 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { if (buf == NULL) return UV_ENOMEM; - r = getpwuid_r(uid, &pw, buf, bufsize, &result); + do + r = getpwuid_r(uid, &pw, buf, bufsize, &result); + while (r == EINTR); if (r != ERANGE) break; @@ -1194,7 +1196,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { if (r != 0) { uv__free(buf); - return -r; + return UV__ERR(r); } if (result == NULL) { From 46451737e6174281317cabdf05c9ba1434c359d6 Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Fri, 21 May 2021 13:34:31 -0700 Subject: [PATCH 017/713] errors: map ESOCKTNOSUPPORT errno PR-URL: https://github.com/libuv/libuv/pull/3151 Reviewed-By: Jameson Nash Reviewed-By: Colin Ihrig --- docs/src/errors.rst | 4 ++++ include/uv.h | 1 + include/uv/errno.h | 6 ++++++ src/win/error.c | 2 +- 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/src/errors.rst b/docs/src/errors.rst index 25d0efaf031..c7240f3546f 100644 --- a/docs/src/errors.rst +++ b/docs/src/errors.rst @@ -335,6 +335,10 @@ Error constants illegal byte sequence +.. c:macro:: UV_ESOCKTNOSUPPORT + + socket type not supported + API --- diff --git a/include/uv.h b/include/uv.h index d2bdcc9cf04..7524ff95af7 100644 --- a/include/uv.h +++ b/include/uv.h @@ -149,6 +149,7 @@ extern "C" { XX(ENOTTY, "inappropriate ioctl for device") \ XX(EFTYPE, "inappropriate file type or format") \ XX(EILSEQ, "illegal byte sequence") \ + XX(ESOCKTNOSUPPORT, "socket type not supported") \ #define UV_HANDLE_TYPE_MAP(XX) \ XX(ASYNC, async) \ diff --git a/include/uv/errno.h b/include/uv/errno.h index a0ca571b0d1..71906b3f5e6 100644 --- a/include/uv/errno.h +++ b/include/uv/errno.h @@ -451,4 +451,10 @@ # define UV__EOVERFLOW (-4026) #endif +#if defined(ESOCKTNOSUPPORT) && !defined(_WIN32) +# define UV__ESOCKTNOSUPPORT UV__ERR(ESOCKTNOSUPPORT) +#else +# define UV__ESOCKTNOSUPPORT (-4025) +#endif + #endif /* UV_ERRNO_H_ */ diff --git a/src/win/error.c b/src/win/error.c index 3ec984c83eb..3a269da87a9 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -105,7 +105,6 @@ int uv_translate_sys_error(int sys_errno) { case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL; case WSAEINVAL: return UV_EINVAL; case WSAEPFNOSUPPORT: return UV_EINVAL; - case WSAESOCKTNOSUPPORT: return UV_EINVAL; case ERROR_BEGINNING_OF_MEDIA: return UV_EIO; case ERROR_BUS_RESET: return UV_EIO; case ERROR_CRC: return UV_EIO; @@ -168,6 +167,7 @@ int uv_translate_sys_error(int sys_errno) { case ERROR_NOT_SAME_DEVICE: return UV_EXDEV; case ERROR_INVALID_FUNCTION: return UV_EISDIR; case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG; + case WSAESOCKTNOSUPPORT: return UV_ESOCKTNOSUPPORT; default: return UV_UNKNOWN; } } From 4cf638de0505035506521a5988193b9b8d94a281 Mon Sep 17 00:00:00 2001 From: Simon Kissane Date: Tue, 25 May 2021 06:30:49 +1000 Subject: [PATCH 018/713] doc: uv_read_stop always succeeds Fixes: https://github.com/libuv/libuv/issues/3041 PR-URL: https://github.com/libuv/libuv/pull/3076 Reviewed-By: Jameson Nash --- docs/src/stream.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/src/stream.rst b/docs/src/stream.rst index 429ebdab28f..58ef7d98400 100644 --- a/docs/src/stream.rst +++ b/docs/src/stream.rst @@ -151,6 +151,11 @@ API This function is idempotent and may be safely called on a stopped stream. + This function will always succeed; hence, checking its return value is + unnecessary. A non-zero return indicates that finishing releasing resources + may be pending on the next input event on that TTY on Windows, and does not + indicate failure. + .. c:function:: int uv_write(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb) Write data to stream. Buffers are written in order. Example: From 385b7960a056686e6d7326b4ebe26b922619b36d Mon Sep 17 00:00:00 2001 From: twosee Date: Thu, 27 May 2021 22:54:33 +0800 Subject: [PATCH 019/713] inet: fix inconsistent return value of inet_ntop6 PR-URL: https://github.com/libuv/libuv/pull/3182 Reviewed-By: Jameson Nash --- src/inet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/inet.c b/src/inet.c index 698ab232e53..ddabf22fa52 100644 --- a/src/inet.c +++ b/src/inet.c @@ -141,8 +141,9 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) { if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words)) *tp++ = ':'; *tp++ = '\0'; - if (UV_E2BIG == uv__strscpy(dst, tmp, size)) + if ((size_t) (tp - tmp) > size) return UV_ENOSPC; + uv__strscpy(dst, tmp, size); return 0; } From 6085bcef8dea1eaa21a92e2b6e6f03a0476b6c54 Mon Sep 17 00:00:00 2001 From: twosee Date: Fri, 28 May 2021 22:52:58 +0800 Subject: [PATCH 020/713] darwin: fix -Wsometimes-uninitialized warning PR-URL: https://github.com/libuv/libuv/pull/3190 Reviewed-By: Jameson Nash --- src/unix/darwin.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unix/darwin.c b/src/unix/darwin.c index 40960e6f69d..a7be0dd2f3c 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -302,12 +302,13 @@ static int uv__get_cpu_speed(uint64_t* speed) { pIOObjectRelease(it); err = 0; -out: + if (device_type_str != NULL) pCFRelease(device_type_str); if (clock_frequency_str != NULL) pCFRelease(clock_frequency_str); +out: if (core_foundation_handle != NULL) dlclose(core_foundation_handle); From bcc4f8fdde45471f30e168fe27be347076ebdf2c Mon Sep 17 00:00:00 2001 From: twosee Date: Fri, 28 May 2021 22:57:59 +0800 Subject: [PATCH 021/713] stream: introduce uv_try_write2 function `uv_try_write2(stream, bufs, nbufs, send_handle)` acts like `uv_try_write()` and extended write function for sending handles over a pipe like `uv_write2`. It always returns `UV_EAGAIN` instead of `UV_ENOSYS` on Windows so we can easily write cross-platform code without special treatment. PR-URL: https://github.com/libuv/libuv/pull/3183 Reviewed-By: Jameson Nash --- docs/src/stream.rst | 10 ++++++++++ include/uv.h | 4 ++++ src/unix/stream.c | 10 +++++++++- src/win/stream.c | 10 ++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/docs/src/stream.rst b/docs/src/stream.rst index 58ef7d98400..ca7e83f7722 100644 --- a/docs/src/stream.rst +++ b/docs/src/stream.rst @@ -207,6 +207,16 @@ API * < 0: negative error code (``UV_EAGAIN`` is returned if no data can be sent immediately). +.. c:function:: int uv_try_write2(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle) + + Same as :c:func:`uv_try_write` and extended write function for sending + handles over a pipe like c:func:`uv_write2`. + + Try to send a handle is not supported on Windows, + where it returns ``UV_EAGAIN``. + + .. versionadded:: 1.42.0 + .. c:function:: int uv_is_readable(const uv_stream_t* handle) Returns 1 if the stream is readable, 0 otherwise. diff --git a/include/uv.h b/include/uv.h index 7524ff95af7..77503bde9f2 100644 --- a/include/uv.h +++ b/include/uv.h @@ -528,6 +528,10 @@ UV_EXTERN int uv_write2(uv_write_t* req, UV_EXTERN int uv_try_write(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs); +UV_EXTERN int uv_try_write2(uv_stream_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle); /* uv_write_t is a subclass of uv_req_t. */ struct uv_write_s { diff --git a/src/unix/stream.c b/src/unix/stream.c index dd1f5538c3d..f64c01cfcfb 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1525,6 +1525,14 @@ int uv_write(uv_write_t* req, int uv_try_write(uv_stream_t* stream, const uv_buf_t bufs[], unsigned int nbufs) { + return uv_try_write2(stream, bufs, nbufs, NULL); +} + + +int uv_try_write2(uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle) { int err; /* Connecting or already writing some data */ @@ -1535,7 +1543,7 @@ int uv_try_write(uv_stream_t* stream, if (err < 0) return err; - return uv__try_write(stream, bufs, nbufs, NULL); + return uv__try_write(stream, bufs, nbufs, send_handle); } diff --git a/src/win/stream.c b/src/win/stream.c index ebb5fe5cb79..abf477f6442 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -188,6 +188,16 @@ int uv_try_write(uv_stream_t* stream, } +int uv_try_write2(uv_stream_t* stream, + const uv_buf_t bufs[], + unsigned int nbufs, + uv_stream_t* send_handle) { + if (send_handle != NULL) + return UV_EAGAIN; + return uv_try_write(stream, bufs, nbufs); +} + + int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { uv_loop_t* loop = handle->loop; From 93942168281680bca60ddbd8d4c596fabcb8efd9 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Fri, 28 May 2021 20:37:51 +0530 Subject: [PATCH 022/713] win,fs: correct error code in uv_fs_read and uv_fs_write Just like the unix counterpart, uv_fs_read and uv_fs_write should throw an EBADF instead of manually throwing an EPERM when the passed fd has not been opened with the right access flags. PR-URL: https://github.com/libuv/libuv/pull/3180 Reviewed-By: Jameson Nash --- src/win/fs.c | 4 ++-- test/test-fs-open-flags.c | 38 +++++++++++++++++++------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 674070400be..4bb2dc16e10 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -758,7 +758,7 @@ void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) { void* view; if (rw_flags == UV_FS_O_WRONLY) { - SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED); + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FLAGS); return; } if (fd_info->is_directory) { @@ -936,7 +936,7 @@ void fs__write_filemap(uv_fs_t* req, HANDLE file, FILETIME ft; if (rw_flags == UV_FS_O_RDONLY) { - SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED); + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FLAGS); return; } if (fd_info->is_directory) { diff --git a/test/test-fs-open-flags.c b/test/test-fs-open-flags.c index 5f61007adde..372afe13975 100644 --- a/test/test-fs-open-flags.c +++ b/test/test-fs-open-flags.c @@ -276,21 +276,21 @@ static void fs_open_flags(int add_flags) { /* r */ flags = add_flags | UV_FS_O_RDONLY; openFail(absent_file, UV_ENOENT); - writeFail(empty_file, UV_EPERM); + writeFail(empty_file, UV_EBADF); readExpect(empty_file, "", 0); - writeFail(dummy_file, UV_EPERM); + writeFail(dummy_file, UV_EBADF); readExpect(dummy_file, "a", 1); - writeFail(empty_dir, UV_EPERM); + writeFail(empty_dir, UV_EBADF); readFail(empty_dir, UV_EISDIR); /* rs */ flags = add_flags | UV_FS_O_RDONLY | UV_FS_O_SYNC; openFail(absent_file, UV_ENOENT); - writeFail(empty_file, UV_EPERM); + writeFail(empty_file, UV_EBADF); readExpect(empty_file, "", 0); - writeFail(dummy_file, UV_EPERM); + writeFail(dummy_file, UV_EBADF); readExpect(dummy_file, "a", 1); - writeFail(empty_dir, UV_EPERM); + writeFail(empty_dir, UV_EBADF); readFail(empty_dir, UV_EISDIR); /* r+ */ @@ -316,18 +316,18 @@ static void fs_open_flags(int add_flags) { /* w */ flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EPERM); + readFail(absent_file, UV_EBADF); writeExpect(empty_file, "bc", 2); - readFail(empty_file, UV_EPERM); + readFail(empty_file, UV_EBADF); writeExpect(dummy_file, "bc", 2); - readFail(dummy_file, UV_EPERM); + readFail(dummy_file, UV_EBADF); openFail(empty_dir, UV_EISDIR); /* wx */ flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY | UV_FS_O_EXCL; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EPERM); + readFail(absent_file, UV_EBADF); openFail(empty_file, UV_EEXIST); openFail(dummy_file, UV_EEXIST); openFail(empty_dir, UV_EEXIST); @@ -354,19 +354,19 @@ static void fs_open_flags(int add_flags) { /* a */ flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EPERM); + readFail(absent_file, UV_EBADF); writeExpect(empty_file, "bc", 2); - readFail(empty_file, UV_EPERM); + readFail(empty_file, UV_EBADF); writeExpect(dummy_file, "abc", 3); - readFail(dummy_file, UV_EPERM); + readFail(dummy_file, UV_EBADF); writeFail(empty_dir, UV_EISDIR); - readFail(empty_dir, UV_EPERM); + readFail(empty_dir, UV_EBADF); /* ax */ flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY | UV_FS_O_EXCL; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EPERM); + readFail(absent_file, UV_EBADF); openFail(empty_file, UV_EEXIST); openFail(dummy_file, UV_EEXIST); openFail(empty_dir, UV_EEXIST); @@ -375,13 +375,13 @@ static void fs_open_flags(int add_flags) { flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY | UV_FS_O_SYNC; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EPERM); + readFail(absent_file, UV_EBADF); writeExpect(empty_file, "bc", 2); - readFail(empty_file, UV_EPERM); + readFail(empty_file, UV_EBADF); writeExpect(dummy_file, "abc", 3); - readFail(dummy_file, UV_EPERM); + readFail(dummy_file, UV_EBADF); writeFail(empty_dir, UV_EISDIR); - readFail(empty_dir, UV_EPERM); + readFail(empty_dir, UV_EBADF); /* a+ */ flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR; From 2ce720c6dba643cf486d19c7aa1b5678aa64eda1 Mon Sep 17 00:00:00 2001 From: twosee Date: Fri, 28 May 2021 23:11:23 +0800 Subject: [PATCH 023/713] poll,win: UV_PRIORITIZED option should not assert PR-URL: https://github.com/libuv/libuv/pull/3171 Reviewed-By: Jameson Nash --- src/win/poll.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/win/poll.c b/src/win/poll.c index 87858590c85..9d377596066 100644 --- a/src/win/poll.c +++ b/src/win/poll.c @@ -488,7 +488,8 @@ static int uv__poll_set(uv_poll_t* handle, int events, uv_poll_cb cb) { assert(handle->type == UV_POLL); assert(!(handle->flags & UV_HANDLE_CLOSING)); - assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); + assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT | + UV_PRIORITIZED)) == 0); handle->events = events; handle->poll_cb = cb; From 07b86b96c83b3fed0c3930d5f2db3d3a4848fd97 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Fri, 28 May 2021 16:18:22 +0100 Subject: [PATCH 024/713] src: DragonFlyBSD has mmsghdr struct too Still returns ENOSYS, until the send/recv functions are implemented. PR-URL: https://github.com/libuv/libuv/pull/3040 Reviewed-By: Santiago Gimeno Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis Reviewed-By: Jameson Nash --- src/unix/freebsd.c | 4 ++-- src/unix/internal.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index fe795a0e75e..1013fe4d0c8 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -265,7 +265,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { -#if __FreeBSD__ >= 11 +#if __FreeBSD__ >= 11 && !defined(__DragonFly__) return sendmmsg(fd, mmsg, vlen, /* flags */ 0); #else return errno = ENOSYS, -1; @@ -274,7 +274,7 @@ int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { -#if __FreeBSD__ >= 11 +#if __FreeBSD__ >= 11 && !defined(__DragonFly__) return recvmmsg(fd, mmsg, vlen, 0 /* flags */, NULL /* timeout */); #else return errno = ENOSYS, -1; diff --git a/src/unix/internal.h b/src/unix/internal.h index 5593e49485f..c2c42560ce2 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -333,7 +333,8 @@ int uv__getsockpeername(const uv_handle_t* handle, #if defined(__linux__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) + defined(__FreeBSD_kernel__) || \ + defined(__DragonFly__) #define HAVE_MMSG 1 struct uv__mmsghdr { struct msghdr msg_hdr; From a98839d7bfaef389804a146fbcbeab2ab767f0a0 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Fri, 28 May 2021 08:22:44 -0700 Subject: [PATCH 025/713] cleanup,win: Remove _WIN32 guards on threadpool Fixes: https://github.com/libuv/libuv/issues/2980 Refs: https://github.com/nodejs/node/pull/35021 Reviewed-By: Ben Noordhuis Reviewed-By: Anna Henningsen Reviewed-By: Jameson Nash --- src/threadpool.c | 2 -- src/uv-common.c | 6 +++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/threadpool.c b/src/threadpool.c index 0998938f3e0..869ae95f58c 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -161,7 +161,6 @@ static void post(QUEUE* q, enum uv__work_kind kind) { void uv__threadpool_cleanup(void) { -#ifndef _WIN32 unsigned int i; if (nthreads == 0) @@ -181,7 +180,6 @@ void uv__threadpool_cleanup(void) { threads = NULL; nthreads = 0; -#endif } diff --git a/src/uv-common.c b/src/uv-common.c index dd559a11d11..e81ed79b0c5 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -872,7 +872,11 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { } -#ifdef __GNUC__ /* Also covers __clang__ and __INTEL_COMPILER. */ +/* Also covers __clang__ and __INTEL_COMPILER. Disabled on Windows because + * threads have already been forcibly terminated by the operating system + * by the time destructors run, ergo, it's not safe to try to clean them up. + */ +#if defined(__GNUC__) && !defined(_WIN32) __attribute__((destructor)) #endif void uv_library_shutdown(void) { From b201c1a0f0b1ba2365dc285f466ff6fe5307decf Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Fri, 28 May 2021 21:12:09 +0530 Subject: [PATCH 026/713] freebsd: fix an incompatible pointer type warning Fixes: https://github.com/libuv/libuv/issues/3155 PR-URL: https://github.com/libuv/libuv/pull/3188 Reviewed-By: Jameson Nash --- src/unix/freebsd.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index 1013fe4d0c8..170b897e202 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -266,7 +266,10 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { #if __FreeBSD__ >= 11 && !defined(__DragonFly__) - return sendmmsg(fd, mmsg, vlen, /* flags */ 0); + return sendmmsg(fd, + (struct mmsghdr*) mmsg, + vlen, + 0 /* flags */); #else return errno = ENOSYS, -1; #endif @@ -275,7 +278,11 @@ int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { #if __FreeBSD__ >= 11 && !defined(__DragonFly__) - return recvmmsg(fd, mmsg, vlen, 0 /* flags */, NULL /* timeout */); + return recvmmsg(fd, + (struct mmsghdr*) mmsg, + vlen, + 0 /* flags */, + NULL /* timeout */); #else return errno = ENOSYS, -1; #endif From 6b0051d14decb22cab1ae7ee0adf0da99620cafe Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Tue, 8 Jun 2021 21:40:35 +0430 Subject: [PATCH 027/713] core: Correct the conditionals for {cloexec,nonblock}_ioctl These functions are declared with one set of conditionals in the header, and defined with another set of conditionals in the c file. This commit makes all decisions regarding `uv__{nonblock,cloexec}_ioctl` depend on a boolean macro instead. There's one function that expects `uv__nonblock_ioctl` to be defined, so that bit of the function is also conditionally compiled. PR-URL: https://github.com/libuv/libuv/pull/3163 Reviewed-By: Jameson Nash Reviewed-By: Santiago Gimeno --- src/unix/core.c | 3 +-- src/unix/internal.h | 2 ++ src/unix/poll.c | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index e0246a2e7e7..71e9c525c4a 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -584,7 +584,7 @@ int uv__close(int fd) { return uv__close_nocheckstdio(fd); } - +#if UV__NONBLOCK_IS_IOCTL int uv__nonblock_ioctl(int fd, int set) { int r; @@ -599,7 +599,6 @@ int uv__nonblock_ioctl(int fd, int set) { } -#if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__HAIKU__) int uv__cloexec_ioctl(int fd, int set) { int r; diff --git a/src/unix/internal.h b/src/unix/internal.h index c2c42560ce2..69084ed2706 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -176,9 +176,11 @@ struct uv__stream_queued_fds_s { defined(__NetBSD__) #define uv__cloexec uv__cloexec_ioctl #define uv__nonblock uv__nonblock_ioctl +#define UV__NONBLOCK_IS_IOCTL 1 #else #define uv__cloexec uv__cloexec_fcntl #define uv__nonblock uv__nonblock_fcntl +#define UV__NONBLOCK_IS_IOCTL 0 #endif /* On Linux, uv__nonblock_fcntl() and uv__nonblock_ioctl() do not commute diff --git a/src/unix/poll.c b/src/unix/poll.c index 7a1bc7b9dd5..7a12e2d1488 100644 --- a/src/unix/poll.c +++ b/src/unix/poll.c @@ -79,9 +79,10 @@ int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { * Workaround for e.g. kqueue fds not supporting ioctls. */ err = uv__nonblock(fd, 1); +#if UV__NONBLOCK_IS_IOCTL if (err == UV_ENOTTY) - if (uv__nonblock == uv__nonblock_ioctl) - err = uv__nonblock_fcntl(fd, 1); + err = uv__nonblock_fcntl(fd, 1); +#endif if (err) return err; From 99eb736b4c81c8a00aa52ebd75de7198fbbcddbe Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 10 Jun 2021 13:12:07 -0400 Subject: [PATCH 028/713] win,tcp: make uv_close work more like unix This is an attempt to fix some resource management issues on Windows. Win32 sockets have an issue where it sends an RST packet if there is an outstanding overlapped calls. We can avoid that by being certain to explicitly cancel our read and write requests first. This also removes some conditional cleanup code, since we might as well clean it up eagerly (like unix). Otherwise, it looks to me like these might cause the accept callbacks to be run after the endgame had freed the memory for them. The comment here seems mixed up between send and recv buffers. The default behavior on calling `closesocket` is already to do a graceful shutdown (see https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-closesocket with default l_onoff=zero) if it is the last open handle. The expected behavior if there are pending reads in flight is to send an RST packet, notifying the client that the server connection was destroyed before acknowledging the EOF. Additionally, we need to cancel writes explicitly: we need to notify Win32 that it is okay to cancel these writes (so it doesn't also generate an RST packet on the wire). Refs: https://github.com/libuv/libuv/pull/3035 Refs: https://github.com/nodejs/node/pull/35946 Refs: https://github.com/nodejs/node/issues/35904 Fixes: https://github.com/libuv/libuv/issues/3034 PR-URL: https://github.com/libuv/libuv/pull/3036 Reviewed-By: Santiago Gimeno --- src/uv-common.h | 3 +- src/win/tcp.c | 111 ++++++++++++++++++++++-------------------------- test/test-ipc.c | 2 +- 3 files changed, 53 insertions(+), 63 deletions(-) diff --git a/src/uv-common.h b/src/uv-common.h index a92912fdb1a..dbeb698cf59 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -106,8 +106,7 @@ enum { UV_HANDLE_TCP_KEEPALIVE = 0x02000000, UV_HANDLE_TCP_SINGLE_ACCEPT = 0x04000000, UV_HANDLE_TCP_ACCEPT_STATE_CHANGING = 0x08000000, - UV_HANDLE_TCP_SOCKET_CLOSED = 0x10000000, - UV_HANDLE_SHARED_TCP_SOCKET = 0x20000000, + UV_HANDLE_SHARED_TCP_SOCKET = 0x10000000, /* Only used by uv_udp_t handles. */ UV_HANDLE_UDP_PROCESSING = 0x01000000, diff --git a/src/win/tcp.c b/src/win/tcp.c index 890877baf2c..770123faca5 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -236,12 +236,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); - - if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) { - closesocket(handle->socket); - handle->socket = INVALID_SOCKET; - handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; - } + assert(handle->socket == INVALID_SOCKET); if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) { if (handle->flags & UV_HANDLE_EMULATE_IOCP) { @@ -599,6 +594,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { } } + /* If this flag is set, we already made this listen call in xfer. */ if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) && listen(handle->socket, backlog) == SOCKET_ERROR) { return WSAGetLastError(); @@ -769,7 +765,7 @@ static int uv__is_loopback(const struct sockaddr_storage* storage) { } // Check if Windows version is 10.0.16299 or later -static int uv__is_fast_loopback_fail_supported() { +static int uv__is_fast_loopback_fail_supported(void) { OSVERSIONINFOW os_info; if (!pRtlGetVersion) return 0; @@ -1160,9 +1156,14 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, } handle->stream.conn.write_reqs_pending--; - if (handle->stream.conn.shutdown_req != NULL && - handle->stream.conn.write_reqs_pending == 0) { - uv_want_endgame(loop, (uv_handle_t*)handle); + if (handle->stream.conn.write_reqs_pending == 0) { + if (handle->flags & UV_HANDLE_CLOSING) { + closesocket(handle->socket); + handle->socket = INVALID_SOCKET; + } + if (handle->stream.conn.shutdown_req != NULL) { + uv_want_endgame(loop, (uv_handle_t*)handle); + } } DECREASE_PENDING_REQ_COUNT(handle); @@ -1404,9 +1405,24 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { } -static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) { - SOCKET socket = tcp->socket; +static void uv_tcp_try_cancel_reqs(uv_tcp_t* tcp) { + SOCKET socket; int non_ifs_lsp; + int reading; + int writing; + + socket = tcp->socket; + reading = tcp->flags & UV_HANDLE_READING; + writing = tcp->stream.conn.write_reqs_pending > 0; + if (!reading && !writing) + return; + + /* TODO: in libuv v2, keep explicit track of write_reqs, so we can cancel + * them each explicitly with CancelIoEx (like unix). */ + if (reading) + CancelIoEx((HANDLE) socket, &tcp->read_req.u.io.overlapped); + if (writing) + CancelIo((HANDLE) socket); /* Check if we have any non-IFS LSPs stacked on top of TCP */ non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : @@ -1426,71 +1442,41 @@ static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) { NULL, NULL) != 0) { /* Failed. We can't do CancelIo. */ - return -1; + return; } } assert(socket != 0 && socket != INVALID_SOCKET); - if (!CancelIo((HANDLE) socket)) { - return GetLastError(); + if (socket != tcp->socket) { + if (reading) + CancelIoEx((HANDLE) socket, &tcp->read_req.u.io.overlapped); + if (writing) + CancelIo((HANDLE) socket); } - - /* It worked. */ - return 0; } void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { - int close_socket = 1; - - if (tcp->flags & UV_HANDLE_READ_PENDING) { - /* In order for winsock to do a graceful close there must not be any any - * pending reads, or the socket must be shut down for writing */ - if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) { - /* Just do shutdown on non-shared sockets, which ensures graceful close. */ - shutdown(tcp->socket, SD_SEND); - - } else if (uv_tcp_try_cancel_io(tcp) == 0) { - /* In case of a shared socket, we try to cancel all outstanding I/O,. If - * that works, don't close the socket yet - wait for the read req to - * return and close the socket in uv_tcp_endgame. */ - close_socket = 0; - - } else { - /* When cancelling isn't possible - which could happen when an LSP is - * present on an old Windows version, we will have to close the socket - * with a read pending. That is not nice because trailing sent bytes may - * not make it to the other side. */ + if (tcp->flags & UV_HANDLE_CONNECTION) { + uv_tcp_try_cancel_reqs(tcp); + if (tcp->flags & UV_HANDLE_READING) { + uv_read_stop((uv_stream_t*) tcp); } - - } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) && - tcp->tcp.serv.accept_reqs != NULL) { - /* Under normal circumstances closesocket() will ensure that all pending - * accept reqs are canceled. However, when the socket is shared the - * presence of another reference to the socket in another process will keep - * the accept reqs going, so we have to ensure that these are canceled. */ - if (uv_tcp_try_cancel_io(tcp) != 0) { - /* When cancellation is not possible, there is another option: we can - * close the incoming sockets, which will also cancel the accept - * operations. However this is not cool because we might inadvertently - * close a socket that just accepted a new connection, which will cause - * the connection to be aborted. */ + } else { + if (tcp->tcp.serv.accept_reqs != NULL) { + /* First close the incoming sockets to cancel the accept operations before + * we free their resources. */ unsigned int i; for (i = 0; i < uv_simultaneous_server_accepts; i++) { uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i]; - if (req->accept_socket != INVALID_SOCKET && - !HasOverlappedIoCompleted(&req->u.io.overlapped)) { + if (req->accept_socket != INVALID_SOCKET) { closesocket(req->accept_socket); req->accept_socket = INVALID_SOCKET; } } } - } - - if (tcp->flags & UV_HANDLE_READING) { - tcp->flags &= ~UV_HANDLE_READING; - DECREASE_ACTIVE_COUNT(loop, tcp); + assert(!(tcp->flags & UV_HANDLE_READING)); } if (tcp->flags & UV_HANDLE_LISTENING) { @@ -1498,10 +1484,15 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { DECREASE_ACTIVE_COUNT(loop, tcp); } - if (close_socket) { + /* If any overlapped req failed to cancel, calling `closesocket` now would + * cause Win32 to send an RST packet. Try to avoid that for writes, if + * possibly applicable, by waiting to process the completion notifications + * first (which typically should be cancellations). There's not much we can + * do about canceled reads, which also will generate an RST packet. */ + if (!(tcp->flags & UV_HANDLE_CONNECTION) || + tcp->stream.conn.write_reqs_pending == 0) { closesocket(tcp->socket); tcp->socket = INVALID_SOCKET; - tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; } tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); diff --git a/test/test-ipc.c b/test/test-ipc.c index ba3ba737481..68a0e1bb814 100644 --- a/test/test-ipc.c +++ b/test/test-ipc.c @@ -203,7 +203,7 @@ static void on_read(uv_stream_t* handle, /* Make sure that the expected data is correctly multiplexed. */ ASSERT_MEM_EQ("hello\n", buf->base, nread); - outbuf = uv_buf_init("world\n", 6); + outbuf = uv_buf_init("foobar\n", 7); r = uv_write(&write_req, (uv_stream_t*)pipe, &outbuf, 1, NULL); ASSERT_EQ(r, 0); From 79d836b996a926b43076c8b5267d10c731c3e210 Mon Sep 17 00:00:00 2001 From: twosee Date: Sat, 19 Jun 2021 11:38:03 +0800 Subject: [PATCH 029/713] doc: more accurate list of valid send_handle's PR-URL: https://github.com/libuv/libuv/pull/3201 Reviewed-By: Jameson Nash --- docs/src/stream.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/src/stream.rst b/docs/src/stream.rst index ca7e83f7722..0b42c4b3f8c 100644 --- a/docs/src/stream.rst +++ b/docs/src/stream.rst @@ -193,8 +193,9 @@ API initialized with `ipc` == 1. .. note:: - `send_handle` must be a TCP socket or pipe, which is a server or a connection (listening - or connected state). Bound sockets or pipes will be assumed to be servers. + `send_handle` must be a TCP, pipe and UDP handle on Unix, or a TCP + handle on Windows, which is a server or a connection (listening or + connected state). Bound sockets or pipes will be assumed to be servers. .. c:function:: int uv_try_write(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs) From 9918a1743816dc49d6c664e41641d78ffd4a0705 Mon Sep 17 00:00:00 2001 From: twosee Date: Sat, 19 Jun 2021 11:40:00 +0800 Subject: [PATCH 030/713] win,tcp: translate system errors correctly PR-URL: https://github.com/libuv/libuv/pull/3200 Reviewed-By: Jameson Nash Reviewed-By: Colin Ihrig --- src/win/tcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/win/tcp.c b/src/win/tcp.c index 770123faca5..cf2dbd85fdb 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -1339,7 +1339,7 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int enable) { if (handle->socket != INVALID_SOCKET) { err = uv__tcp_nodelay(handle, handle->socket, enable); if (err) - return err; + return uv_translate_sys_error(err); } if (enable) { @@ -1358,7 +1358,7 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { if (handle->socket != INVALID_SOCKET) { err = uv__tcp_keepalive(handle, handle->socket, enable, delay); if (err) - return err; + return uv_translate_sys_error(err); } if (enable) { From 963ecc82d0988f9bbaef07a6939d774dfd027b7c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 19 Jun 2021 05:47:24 +0200 Subject: [PATCH 031/713] unix: implement cpu_relax() on ppc64 We also tell the compiler it is not allowed to reorder the PAUSE instruction relative to other instructions. It is a mostly theoretical issue, but better safe than sorry. PR-URL: https://github.com/libuv/libuv/pull/2590 Reviewed-By: Richard Lau Reviewed-By: Jameson Nash --- src/unix/atomic-ops.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h index 347d19365f7..c48d058435a 100644 --- a/src/unix/atomic-ops.h +++ b/src/unix/atomic-ops.h @@ -52,9 +52,11 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { UV_UNUSED(static void cpu_relax(void)) { #if defined(__i386__) || defined(__x86_64__) - __asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */ + __asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */ #elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__) - __asm__ volatile("yield"); + __asm__ __volatile__ ("yield" ::: "memory"); +#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) + __asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory"); #endif } From 103dbaede33d5818b0795a05b319661c4d3b7d46 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Tue, 22 Jun 2021 01:33:22 +0530 Subject: [PATCH 032/713] Revert "win,fs: correct error code in uv_fs_read and uv_fs_write" This reverts commit 93942168281680bca60ddbd8d4c596fabcb8efd9. Refs: https://github.com/libuv/libuv/pull/3180 Refs: https://github.com/libuv/libuv/pull/3205 PR-URL: https://github.com/libuv/libuv/pull/3211 Reviewed-By: Jameson Nash --- src/win/fs.c | 4 ++-- test/test-fs-open-flags.c | 38 +++++++++++++++++++------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 4bb2dc16e10..674070400be 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -758,7 +758,7 @@ void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) { void* view; if (rw_flags == UV_FS_O_WRONLY) { - SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FLAGS); + SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED); return; } if (fd_info->is_directory) { @@ -936,7 +936,7 @@ void fs__write_filemap(uv_fs_t* req, HANDLE file, FILETIME ft; if (rw_flags == UV_FS_O_RDONLY) { - SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FLAGS); + SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED); return; } if (fd_info->is_directory) { diff --git a/test/test-fs-open-flags.c b/test/test-fs-open-flags.c index 372afe13975..5f61007adde 100644 --- a/test/test-fs-open-flags.c +++ b/test/test-fs-open-flags.c @@ -276,21 +276,21 @@ static void fs_open_flags(int add_flags) { /* r */ flags = add_flags | UV_FS_O_RDONLY; openFail(absent_file, UV_ENOENT); - writeFail(empty_file, UV_EBADF); + writeFail(empty_file, UV_EPERM); readExpect(empty_file, "", 0); - writeFail(dummy_file, UV_EBADF); + writeFail(dummy_file, UV_EPERM); readExpect(dummy_file, "a", 1); - writeFail(empty_dir, UV_EBADF); + writeFail(empty_dir, UV_EPERM); readFail(empty_dir, UV_EISDIR); /* rs */ flags = add_flags | UV_FS_O_RDONLY | UV_FS_O_SYNC; openFail(absent_file, UV_ENOENT); - writeFail(empty_file, UV_EBADF); + writeFail(empty_file, UV_EPERM); readExpect(empty_file, "", 0); - writeFail(dummy_file, UV_EBADF); + writeFail(dummy_file, UV_EPERM); readExpect(dummy_file, "a", 1); - writeFail(empty_dir, UV_EBADF); + writeFail(empty_dir, UV_EPERM); readFail(empty_dir, UV_EISDIR); /* r+ */ @@ -316,18 +316,18 @@ static void fs_open_flags(int add_flags) { /* w */ flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EBADF); + readFail(absent_file, UV_EPERM); writeExpect(empty_file, "bc", 2); - readFail(empty_file, UV_EBADF); + readFail(empty_file, UV_EPERM); writeExpect(dummy_file, "bc", 2); - readFail(dummy_file, UV_EBADF); + readFail(dummy_file, UV_EPERM); openFail(empty_dir, UV_EISDIR); /* wx */ flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY | UV_FS_O_EXCL; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EBADF); + readFail(absent_file, UV_EPERM); openFail(empty_file, UV_EEXIST); openFail(dummy_file, UV_EEXIST); openFail(empty_dir, UV_EEXIST); @@ -354,19 +354,19 @@ static void fs_open_flags(int add_flags) { /* a */ flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EBADF); + readFail(absent_file, UV_EPERM); writeExpect(empty_file, "bc", 2); - readFail(empty_file, UV_EBADF); + readFail(empty_file, UV_EPERM); writeExpect(dummy_file, "abc", 3); - readFail(dummy_file, UV_EBADF); + readFail(dummy_file, UV_EPERM); writeFail(empty_dir, UV_EISDIR); - readFail(empty_dir, UV_EBADF); + readFail(empty_dir, UV_EPERM); /* ax */ flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY | UV_FS_O_EXCL; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EBADF); + readFail(absent_file, UV_EPERM); openFail(empty_file, UV_EEXIST); openFail(dummy_file, UV_EEXIST); openFail(empty_dir, UV_EEXIST); @@ -375,13 +375,13 @@ static void fs_open_flags(int add_flags) { flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY | UV_FS_O_SYNC; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EBADF); + readFail(absent_file, UV_EPERM); writeExpect(empty_file, "bc", 2); - readFail(empty_file, UV_EBADF); + readFail(empty_file, UV_EPERM); writeExpect(dummy_file, "abc", 3); - readFail(dummy_file, UV_EBADF); + readFail(dummy_file, UV_EPERM); writeFail(empty_dir, UV_EISDIR); - readFail(empty_dir, UV_EBADF); + readFail(empty_dir, UV_EPERM); /* a+ */ flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR; From 9ec6bb914febbd392b10bb9e774e25a7a15737c3 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 22 Jun 2021 13:23:59 -0400 Subject: [PATCH 033/713] docs: move list of project links under PR control Copied from https://github.com/libuv/libuv/wiki/Projects-that-use-libuv, since the wiki was vulnerable to spam content. PR-URL: https://github.com/libuv/libuv/pull/3204 Reviewed-By: Richard Lau --- LINKS.md | 101 ++++++++++++++++++++++++++++++++ README.md | 2 +- docs/src/guide/introduction.rst | 2 +- docs/src/index.rst | 2 +- 4 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 LINKS.md diff --git a/LINKS.md b/LINKS.md new file mode 100644 index 00000000000..b8204e56e16 --- /dev/null +++ b/LINKS.md @@ -0,0 +1,101 @@ +### Apps / VM +* [BIND 9](https://bind.isc.org/): DNS software system including an authoritative server, a recursive resolver and related utilities. +* [cjdns](https://github.com/cjdelisle/cjdns): Encrypted self-configuring network/VPN routing engine +* [clearskies_core](https://github.com/larroy/clearskies_core): Clearskies file synchronization program. (C++11) +* [CMake](https://cmake.org) open-source, cross-platform family of tools designed to build, test and package software +* [Coherence](https://github.com/liesware/coherence/): Cryptographic server for modern web apps. +* [DPS-For-IoT](https://github.com/intel/dps-for-iot/wiki): Fully distributed publish/subscribe protocol. +* [HashLink](https://github.com/HaxeFoundation/hashlink): Haxe run-time with libuv support included. +* [Haywire](https://github.com/kellabyte/Haywire): Asynchronous HTTP server. +* [H2O](https://github.com/h2o/h2o): An optimized HTTP server with support for HTTP/1.x and HTTP/2. +* [Igropyr](https://github.com/guenchi/Igropyr): a async Scheme http server base on libuv. +* [Julia](http://julialang.org/): Scientific computing programming language +* [Kestrel](https://github.com/aspnet/AspNetCore/tree/master/src/Servers/Kestrel): web server (C# + libuv + [ASP.NET Core](http://github.com/aspnet)) +* [Knot DNS Resolver](https://www.knot-resolver.cz/): A minimalistic DNS caching resolver +* [Lever](http://leverlanguage.com): runtime, libuv at the 0.9.0 release +* [libnode](https://github.com/plenluno/libnode): C++ implementation of Node.js +* [libstorj](https://github.com/Storj/libstorj): Library for interacting with Storj network +* [libuv_message_framing](https://github.com/litesync/libuv_message_framing) Message-based communication for libuv +* [luaw](https://github.com/raksoras/luaw): Lua web server backed by libuv +* [Luvit](http://luvit.io): Node.JS for the Lua Inventor +* [mo](https://github.com/wehu/mo): Scheme (guile) + libuv runtime +* [MoarVM](https://github.com/MoarVM/MoarVM): a VM for [Rakudo](http://rakudo.org/) [Raku](http://raku.org) +* [Mysocks](https://github.com/zhou0/mysocks): a cross-platform [Shadowsocks](https://shadowsocks.org) client +* [mediasoup](http://mediasoup.org): Powerful WebRTC SFU for Node.js +* [Neovim](https://neovim.io/): A major refactor of Vim. +* [node9](https://github.com/jvburnes/node9): A portable, hybrid, distributed OS based on Inferno, LuaJIT and Libuv +* [node.js](http://www.nodejs.org/): Javascript (using Google's V8) + libuv +* [node.native](https://github.com/d5/node.native): node.js-like API for C++11 +* [nodeuv](https://github.com/nodeuv): An organization with several c++ wrappers for libs which are used in node.js. +* [phastlight](https://github.com/phastlight/phastlight): Command line tool and web server written in PHP 5.3+ inspired by Node.js +* [pilight](https://www.pilight.org/): home automation ("domotica") +* [pixie](https://github.com/pixie-lang/pixie): clojure-inspired lisp with a tracing JIT +* [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 +* [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 +* [Swish](https://github.com/becls/swish/): Concurrency engine with Erlang-like concepts. Includes a web server. +* [Trevi](https://github.com/Yoseob/Trevi): A powerful Swift Web Application Server Framework Project +* [Urbit](http://urbit.org): runtime +* [uv_callback](https://github.com/litesync/uv_callback) libuv thread communication +* [uvloop](https://github.com/MagicStack/uvloop): Ultra fast implementation of python's asyncio event loop on top of libuv +* [Wren CLI](https://github.com/wren-lang/wren-cli): For io, process, scheduler and timer modules + +### Other +* [libtuv](https://github.com/Samsung/libtuv): libuv fork for IoT and embedded systems + +### Bindings +* [Ring](http://ring-lang.net) + * [RingLibuv](http://ring-lang.sourceforge.net/doc1.7/libuv.html) +* Ruby + * [libuv](https://github.com/cotag/libuv) + * [uvrb](https://github.com/avalanche123/uvrb) + * [ruv](https://github.com/aq1018/ruv) + * [rbuv](https://github.com/rbuv/rbuv) + * [mruby-uv](https://github.com/mattn/mruby-uv): mruby binding +* Lua + * [luv](https://github.com/creationix/luv) + * [lev](https://github.com/connectFree/lev) + * [lluv](https://github.com/moteus/lua-lluv) +* C++11 + * [uvpp](https://github.com/larroy/uvpp) - Not complete, exposes very few aspects of `libuv` +* C++17 + * [uvw](https://github.com/skypjack/uvw) - Header-only, event based, tiny and easy to use *libuv* wrapper in modern C++. +* Python + * [Pyuv](https://github.com/saghul/pyuv) + * [uvloop](https://github.com/MagicStack/uvloop) - Ultra fast asyncio event loop. + * [gevent](http://www.gevent.org) - Coroutine-based concurrency library for Python +* C# + * [NetUV](http://github.com/StormHub/NetUV) + * [LibuvSharp](http://github.com/txdv/LibuvSharp) +* Perl 5 + * [UV](https://metacpan.org/pod/UV) +* [Raku](https://raku.org/) + * [MoarVM](https://github.com/MoarVM/MoarVM) [uses](http://6guts.wordpress.com/2013/05/31/moarvm-a-virtual-machine-for-nqp-and-rakudo/) libuv +* PHP + * [php-uv](https://github.com/bwoebi/php-uv) +* Go + * [go-uv](https://github.com/mattn/go-uv) +* OCaml + * [luv](https://github.com/aantron/luv) + * [uwt](https://github.com/fdopen/uwt) +* ooc + * [ooc-uv](https://github.com/nddrylliog/ooc-uv) +* dylan + * [uv-dylan](https://github.com/waywardmonkeys/uv-dylan) +* R + * [httpuv](https://github.com/rstudio/httpuv): HTTP and WebSocket server library for R + * [fs](https://fs.r-lib.org/): Cross-platform file system operations +* Java + * [libuv-java](https://java.net/projects/avatar-js/sources/libuv-java/show): Java bindings +* Nim + * [nimuv](https://github.com/2vg/nimuv): Nim bindings +* Lisp + * [cl-libuv](https://github.com/orthecreedence/cl-libuv) Common Lisp bindings + * [cl-async](https://github.com/orthecreedence/cl-async) Common Lisp async abstraction on top of cl-libuv +* [Céu](http://www.ceu-lang.org) + * [Céu-libuv](https://github.com/fsantanna/ceu-libuv) +* Delphi + * [node.pas](https://github.com/vovach777/node.pas) NodeJS-like ecosystem +* Haskell + * [Z.Haskell](https://z.haskell.world) diff --git a/README.md b/README.md index f643a270826..23b82439d47 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ libuv is a multi-platform support library with a focus on asynchronous I/O. It was primarily developed for use by [Node.js][], but it's also used by [Luvit](http://luvit.io/), [Julia](http://julialang.org/), -[pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/libuv/libuv/wiki/Projects-that-use-libuv). +[pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/libuv/libuv/blob/v1.x/LINKS.md). ## Feature highlights diff --git a/docs/src/guide/introduction.rst b/docs/src/guide/introduction.rst index 0a3af43486d..0656e4d852f 100644 --- a/docs/src/guide/introduction.rst +++ b/docs/src/guide/introduction.rst @@ -72,4 +72,4 @@ There is no need to ``make install``. To build the examples run ``make`` in the .. _node.js: https://www.nodejs.org .. _libev was removed: https://github.com/joyent/libuv/issues/485 .. _Rust: https://www.rust-lang.org -.. _variety: https://github.com/libuv/libuv/wiki/Projects-that-use-libuv +.. _variety: https://github.com/libuv/libuv/blob/v1.x/LINKS.md diff --git a/docs/src/index.rst b/docs/src/index.rst index f696dc16279..4b5d4d2c511 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -17,7 +17,7 @@ was primarily developed for use by `Node.js`_, but it's also used by `Luvit`_, .. _Luvit: https://luvit.io .. _Julia: https://julialang.org .. _pyuv: https://github.com/saghul/pyuv -.. _others: https://github.com/libuv/libuv/wiki/Projects-that-use-libuv +.. _others: https://github.com/libuv/libuv/blob/v1.x/LINKS.md Features From 592cd40af8d4ae3a33654aa5e1106287ecb591bc Mon Sep 17 00:00:00 2001 From: Erkhes N <71805796+rexes-ND@users.noreply.github.com> Date: Thu, 1 Jul 2021 12:24:35 +0900 Subject: [PATCH 034/713] test: wrong pointer arithmetic multiplier PR-URL: https://github.com/libuv/libuv/pull/3216 Reviewed-By: Ben Noordhuis Reviewed-By: Jameson Nash --- test/runner-unix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runner-unix.c b/test/runner-unix.c index b7ca1f857ec..a13648bc883 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -197,7 +197,7 @@ static void* dowait(void* data) { process_info_t* p; for (i = 0; i < args->n; i++) { - p = (process_info_t*)(args->vec + i * sizeof(process_info_t)); + p = &args->vec[i]; if (p->terminated) continue; r = waitpid(p->pid, &p->status, 0); if (r < 0) { @@ -323,7 +323,7 @@ int process_wait(process_info_t* vec, int n, int timeout) { } else { /* Timeout. Kill all the children. */ for (i = 0; i < n; i++) { - p = (process_info_t*)(vec + i * sizeof(process_info_t)); + p = &vec[i]; kill(p->pid, SIGTERM); } retval = -2; From 4a27d87a6966d053f67e267fdbd9474433143c2b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 30 Jun 2021 23:25:20 -0400 Subject: [PATCH 035/713] doc: switch discussion forum to github Freenode is gone (replaced by Libera.chat), but IRC was unused anyways. Fixes: https://github.com/libuv/libuv/issues/3157 Fixes: https://github.com/libuv/libuv/issues/3208 PR-URL: https://github.com/libuv/libuv/pull/3214 Reviewed-By: Ben Noordhuis --- .github/ISSUE_TEMPLATE.md | 2 +- CONTRIBUTING.md | 10 +++++----- README.md | 3 +-- docs/code/dns/main.c | 4 ++-- docs/src/guide/networking.rst | 2 +- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 42538796096..43934de7064 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -2,7 +2,7 @@ If you want to report a bug, you are in the right place! If you need help or have a question, go here: -https://github.com/libuv/help/issues/new +https://github.com/libuv/libuv/discussions If you are reporting a libuv test failure, please ensure that you are not running the test as root. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b0abe3b40ea..d37c51d6363 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,11 +23,11 @@ The stable branch is effectively frozen; patches that change the libuv API/ABI or affect the run-time behavior of applications get rejected. In case of doubt, open an issue in the [issue tracker][], post your question -to the [libuv mailing list], or contact one of [project maintainers][] on [IRC][]. +to the [libuv discussions forum], or message the [libuv mailing list]. -Especially do so if you plan to work on something big. Nothing is more -frustrating than seeing your hard work go to waste because your vision -does not align with that of a project maintainers. +Especially do so if you plan to work on something big. Nothing is more +frustrating than seeing your hard work go to waste because your vision does not +align with that of the [project maintainers]. ### BRANCH @@ -166,6 +166,6 @@ not send out notifications when you add commits. [issue tracker]: https://github.com/libuv/libuv/issues [libuv mailing list]: http://groups.google.com/group/libuv -[IRC]: http://webchat.freenode.net/?channels=libuv +[libuv discussions forum]: https://github.com/libuv/libuv/discussions [Google C/C++ style guide]: https://google.github.io/styleguide/cppguide.html [project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md diff --git a/README.md b/README.md index 23b82439d47..a9a8a9d1179 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,8 @@ The documentation is licensed under the CC BY 4.0 license. Check the [LICENSE-do ## Community - * [Support](https://github.com/libuv/help) + * [Support](https://github.com/libuv/libuv/discussions) * [Mailing list](http://groups.google.com/group/libuv) - * [IRC chatroom (#libuv@irc.freenode.org)](http://webchat.freenode.net?channels=libuv&uio=d4) ## Documentation diff --git a/docs/code/dns/main.c b/docs/code/dns/main.c index 77a7005f4a6..2d63f1aa198 100644 --- a/docs/code/dns/main.c +++ b/docs/code/dns/main.c @@ -69,8 +69,8 @@ int main() { hints.ai_flags = 0; uv_getaddrinfo_t resolver; - fprintf(stderr, "irc.freenode.net is... "); - int r = uv_getaddrinfo(loop, &resolver, on_resolved, "irc.freenode.net", "6667", &hints); + fprintf(stderr, "irc.libera.chat is... "); + int r = uv_getaddrinfo(loop, &resolver, on_resolved, "irc.libera.chat", "6667", &hints); if (r) { fprintf(stderr, "getaddrinfo call error %s\n", uv_err_name(r)); diff --git a/docs/src/guide/networking.rst b/docs/src/guide/networking.rst index 50a191dd802..dcb5643137c 100644 --- a/docs/src/guide/networking.rst +++ b/docs/src/guide/networking.rst @@ -193,7 +193,7 @@ Querying DNS libuv provides asynchronous DNS resolution. For this it provides its own ``getaddrinfo`` replacement [#]_. In the callback you can perform normal socket operations on the retrieved addresses. Let's connect to -Freenode to see an example of DNS resolution. +Libera.chat to see an example of DNS resolution. .. rubric:: dns/main.c .. literalinclude:: ../../code/dns/main.c From b7466e31e4bee160d82a68fca11b1f61d46debae Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 21 May 2021 11:23:36 +0200 Subject: [PATCH 036/713] idna: fix OOB read in punycode decoder libuv was vulnerable to out-of-bounds reads in the uv__idna_toascii() function which is used to convert strings to ASCII. This is called by the DNS resolution function and can lead to information disclosures or crashes. Reported by Eric Sesterhenn in collaboration with Cure53 and ExpressVPN. Reported-By: Eric Sesterhenn Fixes: https://github.com/libuv/libuv/issues/3147 PR-URL: https://github.com/libuv/libuv-private/pull/1 Refs: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22918 Reviewed-By: Colin Ihrig Reviewed-By: Richard Lau --- src/idna.c | 49 +++++++++++++++++++++++++++++++++++------------- test/test-idna.c | 19 +++++++++++++++++++ test/test-list.h | 2 ++ 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/idna.c b/src/idna.c index 13ffac6be81..b44cb16a1ee 100644 --- a/src/idna.c +++ b/src/idna.c @@ -19,6 +19,7 @@ #include "uv.h" #include "idna.h" +#include #include static unsigned uv__utf8_decode1_slow(const char** p, @@ -32,7 +33,7 @@ static unsigned uv__utf8_decode1_slow(const char** p, if (a > 0xF7) return -1; - switch (*p - pe) { + switch (pe - *p) { default: if (a > 0xEF) { min = 0x10000; @@ -62,6 +63,8 @@ static unsigned uv__utf8_decode1_slow(const char** p, a = 0; break; } + /* Fall through. */ + case 0: return -1; /* Invalid continuation byte. */ } @@ -88,6 +91,8 @@ static unsigned uv__utf8_decode1_slow(const char** p, unsigned uv__utf8_decode1(const char** p, const char* pe) { unsigned a; + assert(*p < pe); + a = (unsigned char) *(*p)++; if (a < 128) @@ -96,9 +101,6 @@ unsigned uv__utf8_decode1(const char** p, const char* pe) { return uv__utf8_decode1_slow(p, pe, a); } -#define foreach_codepoint(c, p, pe) \ - for (; (void) (*p <= pe && (c = uv__utf8_decode1(p, pe))), *p <= pe;) - static int uv__idna_toascii_label(const char* s, const char* se, char** d, char* de) { static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789"; @@ -121,15 +123,22 @@ static int uv__idna_toascii_label(const char* s, const char* se, ss = s; todo = 0; - foreach_codepoint(c, &s, se) { + /* Note: after this loop we've visited all UTF-8 characters and know + * they're legal so we no longer need to check for decode errors. + */ + while (s < se) { + c = uv__utf8_decode1(&s, se); + + if (c == -1u) + return UV_EINVAL; + if (c < 128) h++; - else if (c == (unsigned) -1) - return UV_EINVAL; else todo++; } + /* Only write "xn--" when there are non-ASCII characters. */ if (todo > 0) { if (*d < de) *(*d)++ = 'x'; if (*d < de) *(*d)++ = 'n'; @@ -137,9 +146,13 @@ static int uv__idna_toascii_label(const char* s, const char* se, if (*d < de) *(*d)++ = '-'; } + /* Write ASCII characters. */ x = 0; s = ss; - foreach_codepoint(c, &s, se) { + while (s < se) { + c = uv__utf8_decode1(&s, se); + assert(c != -1u); + if (c > 127) continue; @@ -166,10 +179,15 @@ static int uv__idna_toascii_label(const char* s, const char* se, while (todo > 0) { m = -1; s = ss; - foreach_codepoint(c, &s, se) + + while (s < se) { + c = uv__utf8_decode1(&s, se); + assert(c != -1u); + if (c >= n) if (c < m) m = c; + } x = m - n; y = h + 1; @@ -181,7 +199,10 @@ static int uv__idna_toascii_label(const char* s, const char* se, n = m; s = ss; - foreach_codepoint(c, &s, se) { + while (s < se) { + c = uv__utf8_decode1(&s, se); + assert(c != -1u); + if (c < n) if (++delta == 0) return UV_E2BIG; /* Overflow. */ @@ -245,8 +266,6 @@ static int uv__idna_toascii_label(const char* s, const char* se, return 0; } -#undef foreach_codepoint - long uv__idna_toascii(const char* s, const char* se, char* d, char* de) { const char* si; const char* st; @@ -256,10 +275,14 @@ long uv__idna_toascii(const char* s, const char* se, char* d, char* de) { ds = d; - for (si = s; si < se; /* empty */) { + si = s; + while (si < se) { st = si; c = uv__utf8_decode1(&si, se); + if (c == -1u) + return UV_EINVAL; + if (c != '.') if (c != 0x3002) /* 。 */ if (c != 0xFF0E) /* . */ diff --git a/test/test-idna.c b/test/test-idna.c index b76853cb996..f4fad9653df 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -96,6 +96,25 @@ TEST_IMPL(utf8_decode1) { return 0; } +TEST_IMPL(utf8_decode1_overrun) { + const char* p; + char b[1]; + + /* Single byte. */ + p = b; + b[0] = 0x7F; + ASSERT_EQ(0x7F, uv__utf8_decode1(&p, b + 1)); + ASSERT_EQ(p, b + 1); + + /* Multi-byte. */ + p = b; + b[0] = 0xC0; + ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + 1)); + ASSERT_EQ(p, b + 1); + + return 0; +} + /* Doesn't work on z/OS because that platform uses EBCDIC, not ASCII. */ #ifndef __MVS__ diff --git a/test/test-list.h b/test/test-list.h index c3c6002ea3d..424eea07fa6 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -528,6 +528,7 @@ TEST_DECLARE (fork_threadpool_queue_work_simple) TEST_DECLARE (idna_toascii) TEST_DECLARE (utf8_decode1) +TEST_DECLARE (utf8_decode1_overrun) TEST_DECLARE (uname) TEST_DECLARE (metrics_idle_time) @@ -1124,6 +1125,7 @@ TASK_LIST_START #endif TEST_ENTRY (utf8_decode1) + TEST_ENTRY (utf8_decode1_overrun) TEST_ENTRY (uname) /* Doesn't work on z/OS because that platform uses EBCDIC, not ASCII. */ From 03d12d1a375b51b67b70c7fb0e7887f21a259c48 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 2 Jul 2021 20:50:18 +0200 Subject: [PATCH 037/713] build: make sure -fvisibility=hidden is set PR-URL: https://github.com/libuv/libuv/pull/3005 Reviewed-By: Jameson Nash --- configure.ac | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 3c13d4015b1..8ac49276e50 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,10 @@ AC_ENABLE_SHARED AC_ENABLE_STATIC AC_PROG_CC AM_PROG_CC_C_O -CC_FLAG_VISIBILITY #[-fvisibility=hidden] + +CC_ATTRIBUTE_VISIBILITY([default], [ + CC_FLAG_VISIBILITY([CFLAGS="${CFLAGS} -fvisibility=hidden"]) +]) CC_CHECK_CFLAGS_APPEND([-fno-strict-aliasing]) CC_CHECK_CFLAGS_APPEND([-g]) CC_CHECK_CFLAGS_APPEND([-std=gnu89]) From caf22ddbf5b1b8d06006b24f3b50c5e698fe2d8c Mon Sep 17 00:00:00 2001 From: tjarlama Date: Sat, 3 Jul 2021 00:30:37 +0530 Subject: [PATCH 038/713] illumos: event ports to epoll Sunos has added epoll wrappers to offer compatability for binaries build specifically for linux (https://illumos.org/man/5/epoll). With this, it's now possible to develop epoll as a generic interface and share between Linux and SUNOS, similar to kqueue. Fixes: https://github.com/libuv/libuv/issues/3008 PR-URL: https://github.com/libuv/libuv/pull/3046 Reviewed-By: Ben Noordhuis --- CMakeLists.txt | 11 +- Makefile.am | 7 +- src/unix/epoll.c | 422 ++++++++++++++++++++++++++++++++++++++++++ src/unix/internal.h | 1 + src/unix/linux-core.c | 395 +-------------------------------------- src/unix/sunos.c | 275 +-------------------------- 6 files changed, 439 insertions(+), 672 deletions(-) create mode 100644 src/unix/epoll.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0217c01b2c7..de1272a6de8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,7 +210,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android") src/unix/pthread-fixes.c src/unix/random-getentropy.c src/unix/random-getrandom.c - src/unix/random-sysctl-linux.c) + src/unix/random-sysctl-linux.c + src/unix/epoll.c) endif() if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "Android|Linux") @@ -254,7 +255,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") src/unix/linux-syscalls.c src/unix/procfs-exepath.c src/unix/random-getrandom.c - src/unix/random-sysctl-linux.c) + src/unix/random-sysctl-linux.c + src/unix/epoll.c) endif() if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") @@ -325,7 +327,10 @@ endif() if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") list(APPEND uv_defines __EXTENSIONS__ _XOPEN_SOURCE=500) list(APPEND uv_libraries kstat nsl sendfile socket) - list(APPEND uv_sources src/unix/no-proctitle.c src/unix/sunos.c) + list(APPEND uv_sources + src/unix/no-proctitle.c + src/unix/sunos.c + src/unix/epoll.c) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Haiku") diff --git a/Makefile.am b/Makefile.am index 6f2d018c4a7..4d8fb40da92 100644 --- a/Makefile.am +++ b/Makefile.am @@ -391,7 +391,8 @@ libuv_la_CFLAGS += -D_GNU_SOURCE libuv_la_SOURCES += src/unix/android-ifaddrs.c \ src/unix/pthread-fixes.c \ src/unix/random-getrandom.c \ - src/unix/random-sysctl-linux.c + src/unix/random-sysctl-linux.c \ + src/unix/epoll.c endif if CYGWIN @@ -472,7 +473,8 @@ libuv_la_SOURCES += src/unix/linux-core.c \ src/unix/procfs-exepath.c \ src/unix/proctitle.c \ src/unix/random-getrandom.c \ - src/unix/random-sysctl-linux.c + src/unix/random-sysctl-linux.c \ + src/unix/epoll.c test_run_tests_LDFLAGS += -lutil endif @@ -516,6 +518,7 @@ libuv_la_CFLAGS += -D__EXTENSIONS__ \ -D_XOPEN_SOURCE=500 \ -D_REENTRANT libuv_la_SOURCES += src/unix/no-proctitle.c \ + src/unix/epoll.c \ src/unix/sunos.c endif diff --git a/src/unix/epoll.c b/src/unix/epoll.c new file mode 100644 index 00000000000..97348e254b4 --- /dev/null +++ b/src/unix/epoll.c @@ -0,0 +1,422 @@ +/* Copyright libuv contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" +#include +#include + +int uv__epoll_init(uv_loop_t* loop) { + int fd; + fd = epoll_create1(O_CLOEXEC); + + /* epoll_create1() can fail either because it's not implemented (old kernel) + * or because it doesn't understand the O_CLOEXEC flag. + */ + if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) { + fd = epoll_create(256); + + if (fd != -1) + uv__cloexec(fd, 1); + } + + loop->backend_fd = fd; + if (fd == -1) + return UV__ERR(errno); + + return 0; +} + + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct epoll_event* events; + struct epoll_event dummy; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + assert(fd >= 0); + + events = (struct epoll_event*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events != NULL) + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if (events[i].data.fd == fd) + events[i].data.fd = -1; + + /* Remove the file descriptor from the epoll. + * This avoids a problem where the same file description remains open + * in another process, causing repeated junk epoll events. + * + * We pass in a dummy epoll_event, to work around a bug in old kernels. + */ + if (loop->backend_fd >= 0) { + /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that + * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. + */ + memset(&dummy, 0, sizeof(dummy)); + epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy); + } +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct epoll_event e; + int rc; + + memset(&e, 0, sizeof(e)); + e.events = POLLIN; + e.data.fd = -1; + + rc = 0; + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e)) + if (errno != EEXIST) + rc = UV__ERR(errno); + + if (rc == 0) + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e)) + abort(); + + return rc; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes + * effectively infinite on 32 bits architectures. To avoid blocking + * indefinitely, we cap the timeout and poll again if necessary. + * + * Note that "30 minutes" is a simplification because it depends on + * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200, + * that being the largest value I have seen in the wild (and only once.) + */ + static const int max_safe_timeout = 1789569; + static int no_epoll_pwait_cached; + static int no_epoll_wait_cached; + int no_epoll_pwait; + int no_epoll_wait; + struct epoll_event events[1024]; + struct epoll_event* pe; + struct epoll_event e; + int real_timeout; + QUEUE* q; + uv__io_t* w; + sigset_t sigset; + uint64_t sigmask; + uint64_t base; + int have_signals; + int nevents; + int count; + int nfds; + int fd; + int op; + int i; + int user_timeout; + int reset_timeout; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + memset(&e, 0, sizeof(e)); + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + e.events = w->pevents; + e.data.fd = w->fd; + + if (w->events == 0) + op = EPOLL_CTL_ADD; + else + op = EPOLL_CTL_MOD; + + /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching + * events, skip the syscall and squelch the events after epoll_wait(). + */ + if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) { + if (errno != EEXIST) + abort(); + + assert(op == EPOLL_CTL_ADD); + + /* We've reactivated a file descriptor that's been watched before. */ + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e)) + abort(); + } + + w->events = w->pevents; + } + + sigmask = 0; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + sigemptyset(&sigset); + sigaddset(&sigset, SIGPROF); + sigmask |= 1 << (SIGPROF - 1); + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + real_timeout = timeout; + + if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + reset_timeout = 1; + user_timeout = timeout; + timeout = 0; + } else { + reset_timeout = 0; + user_timeout = 0; + } + + /* You could argue there is a dependency between these two but + * ultimately we don't care about their ordering with respect + * to one another. Worst case, we make a few system calls that + * could have been avoided because another thread already knows + * they fail with ENOSYS. Hardly the end of the world. + */ + no_epoll_pwait = uv__load_relaxed(&no_epoll_pwait_cached); + no_epoll_wait = uv__load_relaxed(&no_epoll_wait_cached); + + for (;;) { + /* Only need to set the provider_entry_time if timeout != 0. The function + * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. + */ + if (timeout != 0) + uv__metrics_set_provider_entry_time(loop); + + /* See the comment for max_safe_timeout for an explanation of why + * this is necessary. Executive summary: kernel bug workaround. + */ + if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) + timeout = max_safe_timeout; + + if (sigmask != 0 && no_epoll_pwait != 0) + if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) + abort(); + + if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) { + nfds = epoll_pwait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout, + &sigset); + if (nfds == -1 && errno == ENOSYS) { + uv__store_relaxed(&no_epoll_pwait_cached, 1); + no_epoll_pwait = 1; + } + } else { + nfds = epoll_wait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout); + if (nfds == -1 && errno == ENOSYS) { + uv__store_relaxed(&no_epoll_wait_cached, 1); + no_epoll_wait = 1; + } + } + + if (sigmask != 0 && no_epoll_pwait != 0) + if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)) + abort(); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* We may have been inside the system call for longer than |timeout| + * milliseconds so we need to update the timestamp to avoid drift. + */ + goto update_timeout; + } + + if (nfds == -1) { + if (errno == ENOSYS) { + /* epoll_wait() or epoll_pwait() failed, try the other system call. */ + assert(no_epoll_wait == 0 || no_epoll_pwait == 0); + continue; + } + + if (errno != EINTR) + abort(); + + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + have_signals = 0; + nevents = 0; + + { + /* Squelch a -Waddress-of-packed-member warning with gcc >= 9. */ + union { + struct epoll_event* events; + uv__io_t* watchers; + } x; + + x.events = events; + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = x.watchers; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + } + + for (i = 0; i < nfds; i++) { + pe = events + i; + fd = pe->data.fd; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + + assert(fd >= 0); + assert((unsigned) fd < loop->nwatchers); + + w = loop->watchers[fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. + * + * Ignore all errors because we may be racing with another thread + * when the file descriptor is closed. + */ + epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe); + continue; + } + + /* Give users only events they're interested in. Prevents spurious + * callbacks when previous callback invocation in this loop has stopped + * the current watcher. Also, filters out events that users has not + * requested us to watch. + */ + pe->events &= w->pevents | POLLERR | POLLHUP; + + /* Work around an epoll quirk where it sometimes reports just the + * EPOLLERR or EPOLLHUP event. In order to force the event loop to + * move forward, we merge in the read/write events that the watcher + * is interested in; uv__read() and uv__write() will then deal with + * the error or hangup in the usual fashion. + * + * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user + * reads the available data, calls uv_read_stop(), then sometime later + * calls uv_read_start() again. By then, libuv has forgotten about the + * hangup and the kernel won't report EPOLLIN again because there's + * nothing left to read. If anything, libuv is to blame here. The + * current hack is just a quick bandaid; to properly fix it, libuv + * needs to remember the error/hangup event. We should get that for + * free when we switch over to edge-triggered I/O. + */ + if (pe->events == POLLERR || pe->events == POLLHUP) + pe->events |= + w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); + + if (pe->events != 0) { + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) { + have_signals = 1; + } else { + uv__metrics_update_idle_time(loop); + w->cb(loop, w, pe->events); + } + + nevents++; + } + } + + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (have_signals != 0) { + uv__metrics_update_idle_time(loop); + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + } + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + real_timeout -= (loop->time - base); + if (real_timeout <= 0) + return; + + timeout = real_timeout; + } +} + diff --git a/src/unix/internal.h b/src/unix/internal.h index 69084ed2706..5365cc71bca 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -259,6 +259,7 @@ int uv__signal_loop_fork(uv_loop_t* loop); /* platform specific */ uint64_t uv__hrtime(uv_clocktype_t type); int uv__kqueue_init(uv_loop_t* loop); +int uv__epoll_init(uv_loop_t* loop); int uv__platform_loop_init(uv_loop_t* loop); void uv__platform_loop_delete(uv_loop_t* loop); void uv__platform_invalidate_fd(uv_loop_t* loop, int fd); diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 8746744d563..eaf97599ca6 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -82,29 +82,12 @@ static int read_times(FILE* statfile_fp, static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); static uint64_t read_cpufreq(unsigned int cpunum); - int uv__platform_loop_init(uv_loop_t* loop) { - int fd; - fd = epoll_create1(O_CLOEXEC); - - /* epoll_create1() can fail either because it's not implemented (old kernel) - * or because it doesn't understand the O_CLOEXEC flag. - */ - if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) { - fd = epoll_create(256); - - if (fd != -1) - uv__cloexec(fd, 1); - } - - loop->backend_fd = fd; + loop->inotify_fd = -1; loop->inotify_watchers = NULL; - if (fd == -1) - return UV__ERR(errno); - - return 0; + return uv__epoll_init(loop); } @@ -134,380 +117,6 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } -void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { - struct epoll_event* events; - struct epoll_event dummy; - uintptr_t i; - uintptr_t nfds; - - assert(loop->watchers != NULL); - assert(fd >= 0); - - events = (struct epoll_event*) loop->watchers[loop->nwatchers]; - nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; - if (events != NULL) - /* Invalidate events with same file descriptor */ - for (i = 0; i < nfds; i++) - if (events[i].data.fd == fd) - events[i].data.fd = -1; - - /* Remove the file descriptor from the epoll. - * This avoids a problem where the same file description remains open - * in another process, causing repeated junk epoll events. - * - * We pass in a dummy epoll_event, to work around a bug in old kernels. - */ - if (loop->backend_fd >= 0) { - /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that - * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. - */ - memset(&dummy, 0, sizeof(dummy)); - epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy); - } -} - - -int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct epoll_event e; - int rc; - - memset(&e, 0, sizeof(e)); - e.events = POLLIN; - e.data.fd = -1; - - rc = 0; - if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e)) - if (errno != EEXIST) - rc = UV__ERR(errno); - - if (rc == 0) - if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e)) - abort(); - - return rc; -} - - -void uv__io_poll(uv_loop_t* loop, int timeout) { - /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes - * effectively infinite on 32 bits architectures. To avoid blocking - * indefinitely, we cap the timeout and poll again if necessary. - * - * Note that "30 minutes" is a simplification because it depends on - * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200, - * that being the largest value I have seen in the wild (and only once.) - */ - static const int max_safe_timeout = 1789569; - static int no_epoll_pwait_cached; - static int no_epoll_wait_cached; - int no_epoll_pwait; - int no_epoll_wait; - struct epoll_event events[1024]; - struct epoll_event* pe; - struct epoll_event e; - int real_timeout; - QUEUE* q; - uv__io_t* w; - sigset_t sigset; - uint64_t sigmask; - uint64_t base; - int have_signals; - int nevents; - int count; - int nfds; - int fd; - int op; - int i; - int user_timeout; - int reset_timeout; - - if (loop->nfds == 0) { - assert(QUEUE_EMPTY(&loop->watcher_queue)); - return; - } - - memset(&e, 0, sizeof(e)); - - while (!QUEUE_EMPTY(&loop->watcher_queue)) { - q = QUEUE_HEAD(&loop->watcher_queue); - QUEUE_REMOVE(q); - QUEUE_INIT(q); - - w = QUEUE_DATA(q, uv__io_t, watcher_queue); - assert(w->pevents != 0); - assert(w->fd >= 0); - assert(w->fd < (int) loop->nwatchers); - - e.events = w->pevents; - e.data.fd = w->fd; - - if (w->events == 0) - op = EPOLL_CTL_ADD; - else - op = EPOLL_CTL_MOD; - - /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching - * events, skip the syscall and squelch the events after epoll_wait(). - */ - if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) { - if (errno != EEXIST) - abort(); - - assert(op == EPOLL_CTL_ADD); - - /* We've reactivated a file descriptor that's been watched before. */ - if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e)) - abort(); - } - - w->events = w->pevents; - } - - sigmask = 0; - if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { - sigemptyset(&sigset); - sigaddset(&sigset, SIGPROF); - sigmask |= 1 << (SIGPROF - 1); - } - - assert(timeout >= -1); - base = loop->time; - count = 48; /* Benchmarks suggest this gives the best throughput. */ - real_timeout = timeout; - - if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { - reset_timeout = 1; - user_timeout = timeout; - timeout = 0; - } else { - reset_timeout = 0; - user_timeout = 0; - } - - /* You could argue there is a dependency between these two but - * ultimately we don't care about their ordering with respect - * to one another. Worst case, we make a few system calls that - * could have been avoided because another thread already knows - * they fail with ENOSYS. Hardly the end of the world. - */ - no_epoll_pwait = uv__load_relaxed(&no_epoll_pwait_cached); - no_epoll_wait = uv__load_relaxed(&no_epoll_wait_cached); - - for (;;) { - /* Only need to set the provider_entry_time if timeout != 0. The function - * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. - */ - if (timeout != 0) - uv__metrics_set_provider_entry_time(loop); - - /* See the comment for max_safe_timeout for an explanation of why - * this is necessary. Executive summary: kernel bug workaround. - */ - if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) - timeout = max_safe_timeout; - - if (sigmask != 0 && no_epoll_pwait != 0) - if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) - abort(); - - if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) { - nfds = epoll_pwait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout, - &sigset); - if (nfds == -1 && errno == ENOSYS) { - uv__store_relaxed(&no_epoll_pwait_cached, 1); - no_epoll_pwait = 1; - } - } else { - nfds = epoll_wait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout); - if (nfds == -1 && errno == ENOSYS) { - uv__store_relaxed(&no_epoll_wait_cached, 1); - no_epoll_wait = 1; - } - } - - if (sigmask != 0 && no_epoll_pwait != 0) - if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)) - abort(); - - /* Update loop->time unconditionally. It's tempting to skip the update when - * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the - * operating system didn't reschedule our process while in the syscall. - */ - SAVE_ERRNO(uv__update_time(loop)); - - if (nfds == 0) { - assert(timeout != -1); - - if (reset_timeout != 0) { - timeout = user_timeout; - reset_timeout = 0; - } - - if (timeout == -1) - continue; - - if (timeout == 0) - return; - - /* We may have been inside the system call for longer than |timeout| - * milliseconds so we need to update the timestamp to avoid drift. - */ - goto update_timeout; - } - - if (nfds == -1) { - if (errno == ENOSYS) { - /* epoll_wait() or epoll_pwait() failed, try the other system call. */ - assert(no_epoll_wait == 0 || no_epoll_pwait == 0); - continue; - } - - if (errno != EINTR) - abort(); - - if (reset_timeout != 0) { - timeout = user_timeout; - reset_timeout = 0; - } - - if (timeout == -1) - continue; - - if (timeout == 0) - return; - - /* Interrupted by a signal. Update timeout and poll again. */ - goto update_timeout; - } - - have_signals = 0; - nevents = 0; - - { - /* Squelch a -Waddress-of-packed-member warning with gcc >= 9. */ - union { - struct epoll_event* events; - uv__io_t* watchers; - } x; - - x.events = events; - assert(loop->watchers != NULL); - loop->watchers[loop->nwatchers] = x.watchers; - loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; - } - - for (i = 0; i < nfds; i++) { - pe = events + i; - fd = pe->data.fd; - - /* Skip invalidated events, see uv__platform_invalidate_fd */ - if (fd == -1) - continue; - - assert(fd >= 0); - assert((unsigned) fd < loop->nwatchers); - - w = loop->watchers[fd]; - - if (w == NULL) { - /* File descriptor that we've stopped watching, disarm it. - * - * Ignore all errors because we may be racing with another thread - * when the file descriptor is closed. - */ - epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe); - continue; - } - - /* Give users only events they're interested in. Prevents spurious - * callbacks when previous callback invocation in this loop has stopped - * the current watcher. Also, filters out events that users has not - * requested us to watch. - */ - pe->events &= w->pevents | POLLERR | POLLHUP; - - /* Work around an epoll quirk where it sometimes reports just the - * EPOLLERR or EPOLLHUP event. In order to force the event loop to - * move forward, we merge in the read/write events that the watcher - * is interested in; uv__read() and uv__write() will then deal with - * the error or hangup in the usual fashion. - * - * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user - * reads the available data, calls uv_read_stop(), then sometime later - * calls uv_read_start() again. By then, libuv has forgotten about the - * hangup and the kernel won't report EPOLLIN again because there's - * nothing left to read. If anything, libuv is to blame here. The - * current hack is just a quick bandaid; to properly fix it, libuv - * needs to remember the error/hangup event. We should get that for - * free when we switch over to edge-triggered I/O. - */ - if (pe->events == POLLERR || pe->events == POLLHUP) - pe->events |= - w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); - - if (pe->events != 0) { - /* Run signal watchers last. This also affects child process watchers - * because those are implemented in terms of signal watchers. - */ - if (w == &loop->signal_io_watcher) { - have_signals = 1; - } else { - uv__metrics_update_idle_time(loop); - w->cb(loop, w, pe->events); - } - - nevents++; - } - } - - if (reset_timeout != 0) { - timeout = user_timeout; - reset_timeout = 0; - } - - if (have_signals != 0) { - uv__metrics_update_idle_time(loop); - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); - } - - loop->watchers[loop->nwatchers] = NULL; - loop->watchers[loop->nwatchers + 1] = NULL; - - if (have_signals != 0) - return; /* Event loop should cycle now so don't poll again. */ - - if (nevents != 0) { - if (nfds == ARRAY_SIZE(events) && --count != 0) { - /* Poll for more events but don't block this time. */ - timeout = 0; - continue; - } - return; - } - - if (timeout == 0) - return; - - if (timeout == -1) - continue; - -update_timeout: - assert(timeout > 0); - - real_timeout -= (loop->time - base); - if (real_timeout <= 0) - return; - - timeout = real_timeout; - } -} - uint64_t uv__hrtime(uv_clocktype_t type) { static clock_t fast_clock_id = -1; diff --git a/src/unix/sunos.c b/src/unix/sunos.c index d511c18b85e..5e2ec688430 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -65,24 +65,9 @@ int uv__platform_loop_init(uv_loop_t* loop) { - int err; - int fd; - loop->fs_fd = -1; - loop->backend_fd = -1; - - fd = port_create(); - if (fd == -1) - return UV__ERR(errno); - err = uv__cloexec(fd, 1); - if (err) { - uv__close(fd); - return err; - } - loop->backend_fd = fd; - - return 0; + return uv__epoll_init(loop); } @@ -111,264 +96,6 @@ int uv__io_fork(uv_loop_t* loop) { } -void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { - struct port_event* events; - uintptr_t i; - uintptr_t nfds; - - assert(loop->watchers != NULL); - assert(fd >= 0); - - events = (struct port_event*) loop->watchers[loop->nwatchers]; - nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; - if (events == NULL) - return; - - /* Invalidate events with same file descriptor */ - for (i = 0; i < nfds; i++) - if ((int) events[i].portev_object == fd) - events[i].portev_object = -1; -} - - -int uv__io_check_fd(uv_loop_t* loop, int fd) { - if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) - return UV__ERR(errno); - - if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) { - perror("(libuv) port_dissociate()"); - abort(); - } - - return 0; -} - - -void uv__io_poll(uv_loop_t* loop, int timeout) { - struct port_event events[1024]; - struct port_event* pe; - struct timespec spec; - QUEUE* q; - uv__io_t* w; - sigset_t* pset; - sigset_t set; - uint64_t base; - uint64_t diff; - uint64_t idle_poll; - unsigned int nfds; - unsigned int i; - int saved_errno; - int have_signals; - int nevents; - int count; - int err; - int fd; - int user_timeout; - int reset_timeout; - - if (loop->nfds == 0) { - assert(QUEUE_EMPTY(&loop->watcher_queue)); - return; - } - - while (!QUEUE_EMPTY(&loop->watcher_queue)) { - q = QUEUE_HEAD(&loop->watcher_queue); - QUEUE_REMOVE(q); - QUEUE_INIT(q); - - w = QUEUE_DATA(q, uv__io_t, watcher_queue); - assert(w->pevents != 0); - - if (port_associate(loop->backend_fd, - PORT_SOURCE_FD, - w->fd, - w->pevents, - 0)) { - perror("(libuv) port_associate()"); - abort(); - } - - w->events = w->pevents; - } - - pset = NULL; - if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { - pset = &set; - sigemptyset(pset); - sigaddset(pset, SIGPROF); - } - - assert(timeout >= -1); - base = loop->time; - count = 48; /* Benchmarks suggest this gives the best throughput. */ - - if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { - reset_timeout = 1; - user_timeout = timeout; - timeout = 0; - } else { - reset_timeout = 0; - } - - for (;;) { - /* Only need to set the provider_entry_time if timeout != 0. The function - * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. - */ - if (timeout != 0) - uv__metrics_set_provider_entry_time(loop); - - if (timeout != -1) { - spec.tv_sec = timeout / 1000; - spec.tv_nsec = (timeout % 1000) * 1000000; - } - - /* Work around a kernel bug where nfds is not updated. */ - events[0].portev_source = 0; - - nfds = 1; - saved_errno = 0; - - if (pset != NULL) - pthread_sigmask(SIG_BLOCK, pset, NULL); - - err = port_getn(loop->backend_fd, - events, - ARRAY_SIZE(events), - &nfds, - timeout == -1 ? NULL : &spec); - - if (pset != NULL) - pthread_sigmask(SIG_UNBLOCK, pset, NULL); - - if (err) { - /* Work around another kernel bug: port_getn() may return events even - * on error. - */ - if (errno == EINTR || errno == ETIME) { - saved_errno = errno; - } else { - perror("(libuv) port_getn()"); - abort(); - } - } - - /* Update loop->time unconditionally. It's tempting to skip the update when - * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the - * operating system didn't reschedule our process while in the syscall. - */ - SAVE_ERRNO(uv__update_time(loop)); - - if (events[0].portev_source == 0) { - if (reset_timeout != 0) { - timeout = user_timeout; - reset_timeout = 0; - } - - if (timeout == 0) - return; - - if (timeout == -1) - continue; - - goto update_timeout; - } - - if (nfds == 0) { - assert(timeout != -1); - return; - } - - have_signals = 0; - nevents = 0; - - assert(loop->watchers != NULL); - loop->watchers[loop->nwatchers] = (void*) events; - loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; - for (i = 0; i < nfds; i++) { - pe = events + i; - fd = pe->portev_object; - - /* Skip invalidated events, see uv__platform_invalidate_fd */ - if (fd == -1) - continue; - - assert(fd >= 0); - assert((unsigned) fd < loop->nwatchers); - - w = loop->watchers[fd]; - - /* File descriptor that we've stopped watching, ignore. */ - if (w == NULL) - continue; - - /* Run signal watchers last. This also affects child process watchers - * because those are implemented in terms of signal watchers. - */ - if (w == &loop->signal_io_watcher) { - have_signals = 1; - } else { - uv__metrics_update_idle_time(loop); - w->cb(loop, w, pe->portev_events); - } - - nevents++; - - if (w != loop->watchers[fd]) - continue; /* Disabled by callback. */ - - /* Events Ports operates in oneshot mode, rearm timer on next run. */ - if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) - QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); - } - - if (reset_timeout != 0) { - timeout = user_timeout; - reset_timeout = 0; - } - - if (have_signals != 0) { - uv__metrics_update_idle_time(loop); - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); - } - - loop->watchers[loop->nwatchers] = NULL; - loop->watchers[loop->nwatchers + 1] = NULL; - - if (have_signals != 0) - return; /* Event loop should cycle now so don't poll again. */ - - if (nevents != 0) { - if (nfds == ARRAY_SIZE(events) && --count != 0) { - /* Poll for more events but don't block this time. */ - timeout = 0; - continue; - } - return; - } - - if (saved_errno == ETIME) { - assert(timeout != -1); - return; - } - - if (timeout == 0) - return; - - if (timeout == -1) - continue; - -update_timeout: - assert(timeout > 0); - - diff = loop->time - base; - if (diff >= (uint64_t) timeout) - return; - - timeout -= diff; - } -} - - uint64_t uv__hrtime(uv_clocktype_t type) { return gethrtime(); } From b6d51dc40eb420d81a28c3b3c7b6de4ee9319dfc Mon Sep 17 00:00:00 2001 From: "Joshua M. Clulow" Date: Fri, 2 Jul 2021 12:06:18 -0700 Subject: [PATCH 039/713] illumos,tty: UV_TTY_MODE_IO waits for 4 bytes uv_tty_set_mode() allows a tty device to be set to raw mode with UV_TTY_MODE_RAW, which correctly sets MIN and TIME to appropriate values for character input. When UV_TTY_MODE_IO is passed, on illumos systems a compatibility implementation of cfmakeraw() is used that does _not_ set MIN or TIME. As a result, consumers of IO mode will block until a minimum of 4 bytes is available on the tty instead of just 1 as is expected. PR-URL: https://github.com/libuv/libuv/pull/3219 Reviewed-By: Jameson Nash --- src/unix/tty.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/unix/tty.c b/src/unix/tty.c index 6f60abaadb0..9442cf16360 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -242,6 +242,24 @@ static void uv__tty_make_raw(struct termios* tio) { tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); tio->c_cflag &= ~(CSIZE | PARENB); tio->c_cflag |= CS8; + + /* + * By default, most software expects a pending read to block until at + * least one byte becomes available. As per termio(7I), this requires + * setting the MIN and TIME parameters appropriately. + * + * As a somewhat unfortunate artifact of history, the MIN and TIME slots + * in the control character array overlap with the EOF and EOL slots used + * for canonical mode processing. Because the EOF character needs to be + * the ASCII EOT value (aka Control-D), it has the byte value 4. When + * switching to raw mode, this is interpreted as a MIN value of 4; i.e., + * reads will block until at least four bytes have been input. + * + * Other platforms with a distinct MIN slot like Linux and FreeBSD appear + * to default to a MIN value of 1, so we'll force that value here: + */ + tio->c_cc[VMIN] = 1; + tio->c_cc[VTIME] = 0; #else cfmakeraw(tio); #endif /* #ifdef __sun */ From 337dbfd968d211b7f2fe0a90e019dc90fb61153f Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 7 Jul 2021 15:59:20 -0400 Subject: [PATCH 040/713] doc: add vtjnash GPG ID PR-URL: https://github.com/libuv/libuv/pull/3235 Reviewed-By: Richard Lau --- MAINTAINERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 268251e615a..fb7e5ef3417 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -16,6 +16,7 @@ libuv is currently managed by the following individuals: * **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq)) - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) * **Jameson Nash** ([@vtjnash](https://github.com/vtjnash)) + - GPG key: AEAD 0A4B 6867 6775 1A0E 4AEF 34A2 5FB1 2824 6514 (pubkey-vtjnash) * **John Barboza** ([@jbarz](https://github.com/jbarz)) * **Kaoru Takanashi** ([@erw7](https://github.com/erw7)) - GPG Key: 5804 F999 8A92 2AFB A398 47A0 7183 5090 6134 887F (pubkey-erw7) From b12699b1efabfd241324f4ab6cfd6ce576db491e Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Wed, 7 Jul 2021 21:19:47 +0100 Subject: [PATCH 041/713] linux: read CPU model information on ppc Fixes: https://github.com/libuv/libuv/issues/3217 PR-URL: https://github.com/libuv/libuv/pull/3232 Reviewed-By: Jameson Nash --- src/unix/linux-core.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index eaf97599ca6..2716e2be65d 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -349,14 +349,19 @@ static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) { } -/* Also reads the CPU frequency on x86. The other architectures only have - * a BogoMIPS field, which may not be very accurate. +/* Also reads the CPU frequency on ppc and x86. The other architectures only + * have a BogoMIPS field, which may not be very accurate. * * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup. */ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { +#if defined(__PPC__) + static const char model_marker[] = "cpu\t\t: "; + static const char speed_marker[] = "clock\t\t: "; +#else static const char model_marker[] = "model name\t: "; static const char speed_marker[] = "cpu MHz\t\t: "; +#endif const char* inferred_model; unsigned int model_idx; unsigned int speed_idx; @@ -378,6 +383,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { #if defined(__arm__) || \ defined(__i386__) || \ defined(__mips__) || \ + defined(__PPC__) || \ defined(__x86_64__) fp = uv__open_file("/proc/cpuinfo"); if (fp == NULL) @@ -426,7 +432,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { } fclose(fp); -#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */ +#endif /* __arm__ || __i386__ || __mips__ || __PPC__ || __x86_64__ */ /* Now we want to make sure that all the models contain *something* because * it's not safe to leave them as null. Copy the last entry unless there From e49ef4f309e631e2ecbeb7ff4397b0b073da681c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20=C3=8Dscaro?= Date: Fri, 9 Jul 2021 17:07:18 -0300 Subject: [PATCH 042/713] darwin: fix uv_barrier race condition Prior to this patch a race condition may occur in case a thread tries to destroy the barrier while other awaiting threads were not notified. Since the internal mutex and condition variables are destroyed this may cause an undefined behavior as described by the man pages. So in order to prevent such scenarios the detroy function will not wait until all awaiting threads are finished before proceeding. Fixes: https://github.com/libuv/libuv/issues/3102 PR-URL: https://github.com/libuv/libuv/pull/3162 Reviewed-By: Jameson Nash --- src/unix/thread.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/unix/thread.c b/src/unix/thread.c index 98fc2e1b331..c46450cc661 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -107,8 +107,7 @@ int uv_barrier_wait(uv_barrier_t* barrier) { } last = (--b->out == 0); - if (!last) - uv_cond_signal(&b->cond); /* Not needed for last thread. */ + uv_cond_signal(&b->cond); uv_mutex_unlock(&b->mutex); return last; @@ -122,9 +121,10 @@ void uv_barrier_destroy(uv_barrier_t* barrier) { uv_mutex_lock(&b->mutex); assert(b->in == 0); - assert(b->out == 0); + while (b->out != 0) + uv_cond_wait(&b->cond, &b->mutex); - if (b->in != 0 || b->out != 0) + if (b->in != 0) abort(); uv_mutex_unlock(&b->mutex); From 03f1a6979caff380bfcfcd1293390474eaad6164 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 13 Jul 2021 10:54:02 -0400 Subject: [PATCH 043/713] unix,stream: fix loop hang after uv_shutdown While most users will likely typically call uv_close in their uv_shutdown callback, some callers (notable nodejs) do not always do so. This can result in libuv keeping the loop active, even though there are no outstanding reqs left to handle. This bug was added in 80f2f826bf90b84e659321c0b7fd8af419acb85e, where the premise of that commit appears to have simply been incorrect, as demonstrated by the added test. Refs: https://github.com/libuv/libuv/issues/3202 PR-URL: https://github.com/libuv/libuv/pull/3233 Reviewed-By: Santiago Gimeno --- CMakeLists.txt | 1 + Makefile.am | 1 + src/unix/stream.c | 12 +-- test/echo-server.c | 55 +++++++----- test/test-list.h | 4 + test/test-shutdown-simultaneous.c | 135 ++++++++++++++++++++++++++++++ 6 files changed, 181 insertions(+), 27 deletions(-) create mode 100644 test/test-shutdown-simultaneous.c diff --git a/CMakeLists.txt b/CMakeLists.txt index de1272a6de8..624bf2b13ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -525,6 +525,7 @@ if(LIBUV_BUILD_TESTS) test/test-semaphore.c test/test-shutdown-close.c test/test-shutdown-eof.c + test/test-shutdown-simultaneous.c test/test-shutdown-twice.c test/test-signal-multiple-loops.c test/test-signal-pending-on-close.c diff --git a/Makefile.am b/Makefile.am index 4d8fb40da92..02ba5468d7e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -241,6 +241,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-semaphore.c \ test/test-shutdown-close.c \ test/test-shutdown-eof.c \ + test/test-shutdown-simultaneous.c \ test/test-shutdown-twice.c \ test/test-signal-multiple-loops.c \ test/test-signal-pending-on-close.c \ diff --git a/src/unix/stream.c b/src/unix/stream.c index f64c01cfcfb..bc64fe8f44b 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -926,10 +926,9 @@ static void uv__write(uv_stream_t* stream) { } req->error = n; + // XXX(jwn): this must call uv__stream_flush_write_queue(stream, n) here, since we won't generate any more events uv__write_req_finish(req); uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); - if (!uv__io_active(&stream->io_watcher, POLLIN)) - uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); } @@ -1013,8 +1012,7 @@ static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { stream->flags &= ~UV_HANDLE_READING; stream->flags &= ~UV_HANDLE_READABLE; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); - if (!uv__io_active(&stream->io_watcher, POLLOUT)) - uv__handle_stop(stream); + uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); stream->read_cb(stream, UV_EOF, buf); } @@ -1204,8 +1202,7 @@ static void uv__read(uv_stream_t* stream) { if (stream->flags & UV_HANDLE_READING) { stream->flags &= ~UV_HANDLE_READING; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); - if (!uv__io_active(&stream->io_watcher, POLLOUT)) - uv__handle_stop(stream); + uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); } } @@ -1582,8 +1579,7 @@ int uv_read_stop(uv_stream_t* stream) { stream->flags &= ~UV_HANDLE_READING; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); - if (!uv__io_active(&stream->io_watcher, POLLOUT)) - uv__handle_stop(stream); + uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); stream->read_cb = NULL; diff --git a/test/echo-server.c b/test/echo-server.c index e69c0e262b3..058c9925475 100644 --- a/test/echo-server.c +++ b/test/echo-server.c @@ -65,24 +65,35 @@ static void after_write(uv_write_t* req, int status) { static void after_shutdown(uv_shutdown_t* req, int status) { + ASSERT_EQ(status, 0); uv_close((uv_handle_t*) req->handle, on_close); free(req); } + +static void on_shutdown(uv_shutdown_t* req, int status) { + ASSERT_EQ(status, 0); + free(req); +} + + static void after_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { int i; write_req_t *wr; uv_shutdown_t* sreq; + int shutdown = 0; if (nread < 0) { /* Error or EOF */ - ASSERT(nread == UV_EOF); + ASSERT_EQ(nread, UV_EOF); free(buf->base); sreq = malloc(sizeof* sreq); - ASSERT(0 == uv_shutdown(sreq, handle, after_shutdown)); + if (uv_is_writable(handle)) { + ASSERT_EQ(0, uv_shutdown(sreq, handle, after_shutdown)); + } return; } @@ -95,25 +106,28 @@ static void after_read(uv_stream_t* handle, /* * Scan for the letter Q which signals that we should quit the server. * If we get QS it means close the stream. + * If we get QSS it means shutdown the stream. * If we get QSH it means disable linger before close the socket. */ - if (!server_closed) { - for (i = 0; i < nread; i++) { - if (buf->base[i] == 'Q') { - if (i + 1 < nread && buf->base[i + 1] == 'S') { - int reset = 0; - if (i + 2 < nread && buf->base[i + 2] == 'H') - reset = 1; - free(buf->base); - if (reset && handle->type == UV_TCP) - ASSERT(0 == uv_tcp_close_reset((uv_tcp_t*) handle, on_close)); - else - uv_close((uv_handle_t*) handle, on_close); - return; - } else { - uv_close(server, on_server_close); - server_closed = 1; - } + for (i = 0; i < nread; i++) { + if (buf->base[i] == 'Q') { + if (i + 1 < nread && buf->base[i + 1] == 'S') { + int reset = 0; + if (i + 2 < nread && buf->base[i + 2] == 'S') + shutdown = 1; + if (i + 2 < nread && buf->base[i + 2] == 'H') + reset = 1; + if (reset && handle->type == UV_TCP) + ASSERT_EQ(0, uv_tcp_close_reset((uv_tcp_t*) handle, on_close)); + else if (shutdown) + break; + else + uv_close((uv_handle_t*) handle, on_close); + free(buf->base); + return; + } else if (!server_closed) { + uv_close(server, on_server_close); + server_closed = 1; } } } @@ -125,6 +139,9 @@ static void after_read(uv_stream_t* handle, if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) { FATAL("uv_write failed"); } + + if (shutdown) + ASSERT_EQ(0, uv_shutdown(malloc(sizeof* sreq), handle, on_shutdown)); } diff --git a/test/test-list.h b/test/test-list.h index 424eea07fa6..59b95da9ebe 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -206,6 +206,7 @@ TEST_DECLARE (connection_fail_doesnt_auto_close) TEST_DECLARE (shutdown_close_tcp) TEST_DECLARE (shutdown_close_pipe) TEST_DECLARE (shutdown_eof) +TEST_DECLARE (shutdown_simultaneous) TEST_DECLARE (shutdown_twice) TEST_DECLARE (callback_stack) TEST_DECLARE (env_vars) @@ -784,6 +785,9 @@ TASK_LIST_START TEST_ENTRY (shutdown_eof) TEST_HELPER (shutdown_eof, tcp4_echo_server) + TEST_ENTRY (shutdown_simultaneous) + TEST_HELPER (shutdown_simultaneous, tcp4_echo_server) + TEST_ENTRY (shutdown_twice) TEST_HELPER (shutdown_twice, tcp4_echo_server) diff --git a/test/test-shutdown-simultaneous.c b/test/test-shutdown-simultaneous.c new file mode 100644 index 00000000000..7de3bd42252 --- /dev/null +++ b/test/test-shutdown-simultaneous.c @@ -0,0 +1,135 @@ +/* Copyright libuv project and contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + +static uv_tcp_t tcp; +static uv_connect_t connect_req; +static uv_shutdown_t shutdown_req; +static uv_buf_t qbuf; +static int got_q; +static int got_eof; +static int called_connect_cb; +static int called_shutdown_cb; +static int called_tcp_close_cb; + + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = malloc(size); + buf->len = size; +} + + +static void shutdown_cb(uv_shutdown_t *req, int status) { + ASSERT_PTR_EQ(req, &shutdown_req); + + ASSERT_EQ(called_connect_cb, 1); + ASSERT_EQ(called_tcp_close_cb, 0); +} + + +static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) { + ASSERT_PTR_EQ((uv_tcp_t*)t, &tcp); + + if (nread == 0) { + free(buf->base); + return; + } + + if (!got_q) { + ASSERT_EQ(nread, 4); + ASSERT_EQ(got_eof, 0); + ASSERT_MEM_EQ(buf->base, "QQSS", 4); + free(buf->base); + got_q = 1; + puts("got QQSS"); + /* Shutdown our end of the connection simultaneously */ + uv_shutdown(&shutdown_req, (uv_stream_t*) &tcp, shutdown_cb); + called_shutdown_cb++; + } else { + ASSERT_EQ(nread, UV_EOF); + if (buf->base) { + free(buf->base); + } + got_eof = 1; + puts("got EOF"); + } +} + + +static void connect_cb(uv_connect_t *req, int status) { + ASSERT_EQ(status, 0); + ASSERT_PTR_EQ(req, &connect_req); + + /* Start reading from our connection so we can receive the EOF. */ + ASSERT_EQ(0, uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb)); + + /* Check error handling. */ + ASSERT_EQ(UV_EALREADY, uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb)); + ASSERT_EQ(UV_EINVAL, uv_read_start(NULL, alloc_cb, read_cb)); + ASSERT_EQ(UV_EINVAL, uv_read_start((uv_stream_t*)&tcp, NULL, read_cb)); + ASSERT_EQ(UV_EINVAL, uv_read_start((uv_stream_t*)&tcp, alloc_cb, NULL)); + + /* + * Write the letter 'Q' and 'QSS` to gracefully kill the echo-server. This + * will not effect our connection. + */ + ASSERT_EQ(qbuf.len, uv_try_write((uv_stream_t*) &tcp, &qbuf, 1)); + + called_connect_cb++; + ASSERT_EQ(called_shutdown_cb, 0); +} + + +/* + * This test has a client which connects to the echo_server and immediately + * issues a shutdown. We check that this does not cause libuv to hang. + */ +TEST_IMPL(shutdown_simultaneous) { + struct sockaddr_in server_addr; + int r; + + qbuf.base = "QQSS"; + qbuf.len = 4; + + ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + r = uv_tcp_init(uv_default_loop(), &tcp); + ASSERT_EQ(r, 0); + + r = uv_tcp_connect(&connect_req, + &tcp, + (const struct sockaddr*) &server_addr, + connect_cb); + ASSERT_EQ(r, 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT_EQ(called_connect_cb, 1); + ASSERT_EQ(called_shutdown_cb, 1); + ASSERT_EQ(got_eof, 1); + ASSERT_EQ(got_q, 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From 5c85d67bc781430f2db8f446795494aa8d399de8 Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Tue, 13 Jul 2021 08:20:53 -0700 Subject: [PATCH 044/713] doc,udp: note that suggested_size is 1 max-sized dgram The intention here is to make working with recvmmsg more straight-forward, since internally libuv expects buffers that are multiples of UV__UDP_DGRAM_MAXSIZE, but previously the availability of that value wasn't readily apparent to the caller. Closes: https://github.com/libuv/libuv/issues/2822 Closes: https://github.com/libuv/libuv/issues/1025 Closes: https://github.com/libuv/libuv/pull/1114 PR-URL: https://github.com/libuv/libuv/pull/2986 Reviewed-By: Jameson Nash --- docs/src/udp.rst | 5 +++++ src/unix/udp.c | 2 -- src/uv-common.h | 2 ++ src/win/udp.c | 4 ++-- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/src/udp.rst b/docs/src/udp.rst index 3a7c6db4f00..009767d55dc 100644 --- a/docs/src/udp.rst +++ b/docs/src/udp.rst @@ -404,6 +404,11 @@ API :returns: 0 on success, or an error code < 0 on failure. + .. note:: + When using :man:`recvmmsg(2)`, the number of messages received at a time is limited + by the number of max size dgrams that will fit into the buffer allocated in `alloc_cb`, and + `suggested_size` in `alloc_cb` for udp_recv is always set to the size of 1 max size dgram. + .. versionchanged:: 1.35.0 added support for :man:`recvmmsg(2)` on supported platforms). The use of this feature requires a buffer larger than 2 * 64KB to be passed to `alloc_cb`. diff --git a/src/unix/udp.c b/src/unix/udp.c index 5d0ec8d30e3..49051c07c15 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -32,8 +32,6 @@ #endif #include -#define UV__UDP_DGRAM_MAXSIZE (64 * 1024) - #if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP) # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP #endif diff --git a/src/uv-common.h b/src/uv-common.h index dbeb698cf59..8a190bf8fa8 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -68,6 +68,8 @@ extern int snprintf(char*, size_t, const char*, ...); #define uv__store_relaxed(p, v) do *p = v; while (0) #endif +#define UV__UDP_DGRAM_MAXSIZE (64 * 1024) + /* Handle flags. Some flags are specific to Windows or UNIX. */ enum { /* Used by all handles. */ diff --git a/src/win/udp.c b/src/win/udp.c index 68ca728aa5c..3043f2da88e 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -284,7 +284,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { handle->flags &= ~UV_HANDLE_ZERO_READ; handle->recv_buffer = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer); + handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &handle->recv_buffer); if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) { handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0); return; @@ -501,7 +501,7 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, /* Do a nonblocking receive. * TODO: try to read multiple datagrams at once. FIONREAD maybe? */ buf = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); + handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf); if (buf.base == NULL || buf.len == 0) { handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); goto done; From f9ad802fa5dd5afe6730f8e00cfdbf98f1d7a969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 14 Jul 2021 19:36:30 +0300 Subject: [PATCH 045/713] mingw: fix building for ARM/AArch64 Don't use x86 inline assembly in these cases, but fall back to __sync_fetch_and_or, similar to _InterlockedOr8 in the MSVC case. This corresponds to what is done in src/unix/atomic-ops.h, where ARM/AArch64 cases end up implementing cmpxchgi with __sync_val_compare_and_swap. PR-URL: https://github.com/libuv/libuv/pull/3236 Reviewed-By: Jameson Nash --- src/win/atomicops-inl.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/win/atomicops-inl.h b/src/win/atomicops-inl.h index 52713cf305f..2f984c6db0b 100644 --- a/src/win/atomicops-inl.h +++ b/src/win/atomicops-inl.h @@ -39,10 +39,11 @@ static char INLINE uv__atomic_exchange_set(char volatile* target) { return _InterlockedOr8(target, 1); } -#else /* GCC */ +#else /* GCC, Clang in mingw mode */ -/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */ static inline char uv__atomic_exchange_set(char volatile* target) { +#if defined(__i386__) || defined(__x86_64__) + /* Mingw-32 version, hopefully this works for 64-bit gcc as well. */ const char one = 1; char old_value; __asm__ __volatile__ ("lock xchgb %0, %1\n\t" @@ -50,6 +51,9 @@ static inline char uv__atomic_exchange_set(char volatile* target) { : "0"(one), "m"(*target) : "memory"); return old_value; +#else + return __sync_fetch_and_or(target, 1); +#endif } #endif From 8ea8f124386486af2380127c6885848f9d502a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claes=20N=C3=A4st=C3=A9n?= Date: Mon, 19 Jul 2021 19:06:51 +0200 Subject: [PATCH 046/713] unix: strnlen is not available on Solaris 10 `strnlen` was not available on Solaris 10, so provide a fallback implementation for it. PR-URL: https://github.com/libuv/libuv/pull/3152 Reviewed-By: Ben Noordhuis Reviewed-By: Jameson Nash --- src/unix/internal.h | 6 ++++++ src/unix/sunos.c | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/unix/internal.h b/src/unix/internal.h index 5365cc71bca..12d4da93686 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -350,5 +350,11 @@ int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen); #define HAVE_MMSG 0 #endif +#if defined(__sun) +#if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L +size_t strnlen(const char* s, size_t maxlen); +#endif +#endif + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 5e2ec688430..c47d17a30cb 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -592,3 +592,14 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses, uv__free(addresses); } + + +#if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L +size_t strnlen(const char* s, size_t maxlen) { + const char* end; + end = memchr(s, '\0', maxlen); + if (end == NULL) + return maxlen; + return end - s; +} +#endif From 5fe597268e4e78dc84e481f57317a573356f63c2 Mon Sep 17 00:00:00 2001 From: Andy Fiddaman Date: Tue, 20 Jul 2021 02:19:24 +0000 Subject: [PATCH 047/713] sunos: restore use of event ports The sunos platform currently covers at least the Solaris and illumos operating systems. Although these diverged 11 years ago they still share some common features such as support for event ports. illumos also has a compatibility wrapper for epoll but this is not recommended for use over event ports. From the NOTES section of https://illumos.org/man/5/epoll: The epoll facility is implemented for purposes of offering compatibility to and portability of Linux-borne applications; native applications should continue to prefer using event ports... In particular, use of epoll in a multithreaded environment is fraught with peril... Restore the event ports code so that libuv can continue to be used on Solaris, and to avoid the problems that come with using epoll() on illumos. The separation of epoll into src/unix/epoll.c has been retained. Fixes: https://github.com/libuv/libuv/issues/3241 PR-URL: https://github.com/libuv/libuv/pull/3242 Reviewed-By: Jameson Nash --- CMakeLists.txt | 3 +- Makefile.am | 1 - src/unix/sunos.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 275 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 624bf2b13ad..a7ba9e91861 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -329,8 +329,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") list(APPEND uv_libraries kstat nsl sendfile socket) list(APPEND uv_sources src/unix/no-proctitle.c - src/unix/sunos.c - src/unix/epoll.c) + src/unix/sunos.c) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Haiku") diff --git a/Makefile.am b/Makefile.am index 02ba5468d7e..5830003c1e0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -519,7 +519,6 @@ libuv_la_CFLAGS += -D__EXTENSIONS__ \ -D_XOPEN_SOURCE=500 \ -D_REENTRANT libuv_la_SOURCES += src/unix/no-proctitle.c \ - src/unix/epoll.c \ src/unix/sunos.c endif diff --git a/src/unix/sunos.c b/src/unix/sunos.c index c47d17a30cb..2bf297e5d96 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -65,9 +65,24 @@ int uv__platform_loop_init(uv_loop_t* loop) { + int err; + int fd; + loop->fs_fd = -1; + loop->backend_fd = -1; + + fd = port_create(); + if (fd == -1) + return UV__ERR(errno); - return uv__epoll_init(loop); + err = uv__cloexec(fd, 1); + if (err) { + uv__close(fd); + return err; + } + loop->backend_fd = fd; + + return 0; } @@ -96,6 +111,264 @@ int uv__io_fork(uv_loop_t* loop) { } +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct port_event* events; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + assert(fd >= 0); + + events = (struct port_event*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events == NULL) + return; + + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].portev_object == fd) + events[i].portev_object = -1; +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) + return UV__ERR(errno); + + if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) { + perror("(libuv) port_dissociate()"); + abort(); + } + + return 0; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + struct port_event events[1024]; + struct port_event* pe; + struct timespec spec; + QUEUE* q; + uv__io_t* w; + sigset_t* pset; + sigset_t set; + uint64_t base; + uint64_t diff; + uint64_t idle_poll; + unsigned int nfds; + unsigned int i; + int saved_errno; + int have_signals; + int nevents; + int count; + int err; + int fd; + int user_timeout; + int reset_timeout; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + + if (port_associate(loop->backend_fd, + PORT_SOURCE_FD, + w->fd, + w->pevents, + 0)) { + perror("(libuv) port_associate()"); + abort(); + } + + w->events = w->pevents; + } + + pset = NULL; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + pset = &set; + sigemptyset(pset); + sigaddset(pset, SIGPROF); + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + + if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + reset_timeout = 1; + user_timeout = timeout; + timeout = 0; + } else { + reset_timeout = 0; + } + + for (;;) { + /* Only need to set the provider_entry_time if timeout != 0. The function + * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. + */ + if (timeout != 0) + uv__metrics_set_provider_entry_time(loop); + + if (timeout != -1) { + spec.tv_sec = timeout / 1000; + spec.tv_nsec = (timeout % 1000) * 1000000; + } + + /* Work around a kernel bug where nfds is not updated. */ + events[0].portev_source = 0; + + nfds = 1; + saved_errno = 0; + + if (pset != NULL) + pthread_sigmask(SIG_BLOCK, pset, NULL); + + err = port_getn(loop->backend_fd, + events, + ARRAY_SIZE(events), + &nfds, + timeout == -1 ? NULL : &spec); + + if (pset != NULL) + pthread_sigmask(SIG_UNBLOCK, pset, NULL); + + if (err) { + /* Work around another kernel bug: port_getn() may return events even + * on error. + */ + if (errno == EINTR || errno == ETIME) { + saved_errno = errno; + } else { + perror("(libuv) port_getn()"); + abort(); + } + } + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (events[0].portev_source == 0) { + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + + goto update_timeout; + } + + if (nfds == 0) { + assert(timeout != -1); + return; + } + + have_signals = 0; + nevents = 0; + + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + for (i = 0; i < nfds; i++) { + pe = events + i; + fd = pe->portev_object; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + + assert(fd >= 0); + assert((unsigned) fd < loop->nwatchers); + + w = loop->watchers[fd]; + + /* File descriptor that we've stopped watching, ignore. */ + if (w == NULL) + continue; + + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) { + have_signals = 1; + } else { + uv__metrics_update_idle_time(loop); + w->cb(loop, w, pe->portev_events); + } + + nevents++; + + if (w != loop->watchers[fd]) + continue; /* Disabled by callback. */ + + /* Events Ports operates in oneshot mode, rearm timer on next run. */ + if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + } + + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (have_signals != 0) { + uv__metrics_update_idle_time(loop); + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + } + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (saved_errno == ETIME) { + assert(timeout != -1); + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + diff = loop->time - base; + if (diff >= (uint64_t) timeout) + return; + + timeout -= diff; + } +} + + uint64_t uv__hrtime(uv_clocktype_t type) { return gethrtime(); } From 7b18d0aa15b7d7e7afe85e34386ee89cffc82b74 Mon Sep 17 00:00:00 2001 From: Andy Fiddaman Date: Tue, 20 Jul 2021 02:27:40 +0000 Subject: [PATCH 048/713] sunos,cmake: use thread-safe errno On illumos, the global errno variable is not thread-safe by default, requiring that the application be built with gcc's -pthread option, or that it defines -D_REENTRANT. This was done already for the autotools build, but not for CMake. PR-URL: https://github.com/libuv/libuv/pull/3243 Reviewed-By: Jameson Nash --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a7ba9e91861..148d0e68992 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -325,7 +325,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OS400") endif() if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") - list(APPEND uv_defines __EXTENSIONS__ _XOPEN_SOURCE=500) + list(APPEND uv_defines __EXTENSIONS__ _XOPEN_SOURCE=500 _REENTRANT) list(APPEND uv_libraries kstat nsl sendfile socket) list(APPEND uv_sources src/unix/no-proctitle.c From 6ce14710da7079eb248868171f6343bc409ea3a4 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 19 Jul 2021 22:44:04 -0400 Subject: [PATCH 049/713] 2021.07.21, Version 1.42.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.41.0: * doc: fix code highlighting (Darshan Sen) * test: move to ASSERT_NULL and ASSERT_NOT_NULL test macros (tjarlama) * zos: build in ascii code page (Shuowang (Wayne) Zhang) * zos: don't use nanosecond timestamp fields (Shuowang (Wayne) Zhang) * zos: introduce zoslib (Shuowang (Wayne) Zhang) * zos: use strnlen() from zoslib (Shuowang (Wayne) Zhang) * zos: use nanosleep() from zoslib (Shuowang (Wayne) Zhang) * zos: use __getargv() from zoslib to get exe path (Shuowang (Wayne) Zhang) * zos: treat __rfim_utok as binary (Shuowang (Wayne) Zhang) * zos: use execvpe() to set environ explictly (Shuowang (Wayne) Zhang) * zos: use custom proctitle implementation (Shuowang (Wayne) Zhang) * doc: add instructions for building on z/OS (Shuowang (Wayne) Zhang) * linux,udp: enable full ICMP error reporting (Ondřej Surý) * test: fix test-udp-send-unreachable (Ondřej Surý) * include: fix typo in documentation (Tobias Nießen) * chore: use for(;;) instead of while (Yash Ladha) * test: remove string + int warning on udp-pummel (Juan José Arboleda) * cmake: fix linker flags (Zhao Zhili) * test: fix stack-use-after-scope (Zhao Zhili) * unix: expose thread_stack_size() internally (Brandon Cheng) * darwin: use RLIMIT_STACK for fsevents pthread (Brandon Cheng) * darwin: abort on pthread_attr_init fail (Brandon Cheng) * benchmark: remove unreachable code (Matvii Hodovaniuk) * macos: fix memleaks in uv__get_cpu_speed (George Zhao) * Make Thread Sanitizer aware of file descriptor close in uv__close() (Ondřej Surý) * darwin: fix iOS compilation and functionality (Hayden) * linux: work around copy_file_range() cephfs bug (Ben Noordhuis) * zos: implement uv_get_constrained_memory() (Shuowang (Wayne) Zhang) * zos: fix uv_get_free_memory() (Shuowang (Wayne) Zhang) * zos: use CVTRLSTG to get total memory accurately (Shuowang (Wayne) Zhang) * ibmi: Handle interface names longer than 10 chars (Kevin Adler) * docs: update read-the-docs version of sphinx (Jameson Nash) * unix: refactor uv_try_write (twosee) * linux-core: add proper divide by zero assert (yiyuaner) * misc: remove unnecessary _GNU_SOURCE macros (Darshan Sen) * test: log to stdout to conform TAP spec (bbara) * win,fs: fix C4090 warning with MSVC (SeverinLeonhardt) * build: some systems provide dlopen() in libc (Andy Fiddaman) * include: add EOVERFLOW status code mapping (Darshan Sen) * unix,fs: use uv__load_relaxed and uv__store_relaxed (Darshan Sen) * win: fix string encoding issue of uv_os_gethostname (Eagle Liang) * unix,process: add uv__write_errno helper function (Ricky Zhou) * Re-merge "unix,stream: clear read/write states on close/eof" (Jameson Nash) * unix,core: fix errno handling in uv__getpwuid_r (Darshan Sen) * errors: map ESOCKTNOSUPPORT errno (Ryan Liptak) * doc: uv_read_stop always succeeds (Simon Kissane) * inet: fix inconsistent return value of inet_ntop6 (twosee) * darwin: fix -Wsometimes-uninitialized warning (twosee) * stream: introduce uv_try_write2 function (twosee) * poll,win: UV_PRIORITIZED option should not assert (twosee) * src: DragonFlyBSD has mmsghdr struct too (David Carlier) * cleanup,win: Remove _WIN32 guards on threadpool (James M Snell) * freebsd: fix an incompatible pointer type warning (Darshan Sen) * core: Correct the conditionals for {cloexec,nonblock}_ioctl (Ali Mohammad Pur) * win,tcp: make uv_close work more like unix (Jameson Nash) * doc: more accurate list of valid send_handle's (twosee) * win,tcp: translate system errors correctly (twosee) * unix: implement cpu_relax() on ppc64 (Ben Noordhuis) * docs: move list of project links under PR control (Jameson Nash) * test: wrong pointer arithmetic multiplier (Erkhes N) * doc: switch discussion forum to github (Jameson Nash) * idna: fix OOB read in punycode decoder (Ben Noordhuis) * build: make sure -fvisibility=hidden is set (Santiago Gimeno) * illumos: event ports to epoll (tjarlama) * illumos,tty: UV_TTY_MODE_IO waits for 4 bytes (Joshua M. Clulow) * doc: add vtjnash GPG ID (Jameson Nash) * linux: read CPU model information on ppc (Richard Lau) * darwin: fix uv_barrier race condition (Guilherme Íscaro) * unix,stream: fix loop hang after uv_shutdown (Jameson Nash) * doc,udp: note that suggested_size is 1 max-sized dgram (Ryan Liptak) * mingw: fix building for ARM/AArch64 (Martin Storsjö) * unix: strnlen is not available on Solaris 10 (Claes Nästén) * sunos: restore use of event ports (Andy Fiddaman) * sunos,cmake: use thread-safe errno (Andy Fiddaman) --- .mailmap | 4 ++ AUTHORS | 24 ++++++- ChangeLog | 155 +++++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 8 +-- 5 files changed, 186 insertions(+), 7 deletions(-) diff --git a/.mailmap b/.mailmap index 045b7702d95..7be85aba980 100644 --- a/.mailmap +++ b/.mailmap @@ -2,6 +2,7 @@ A. Hauptmann Aaron Bieber Alan Gutierrez Andrius Bentkus +Andy Fiddaman Bert Belder Bert Belder Bert Belder @@ -10,6 +11,8 @@ Brian White Brian White Caleb James DeLisle Christoph Iserlohn +Darshan Sen +David Carlier Devchandra Meetei Leishangthem Fedor Indutny Frank Denis @@ -53,4 +56,5 @@ gengjiawen jBarz jBarz ptlomholt +tjarlama <59913901+tjarlama@users.noreply.github.com> zlargon diff --git a/AUTHORS b/AUTHORS index 9f327af9f83..741bcc708cb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -114,7 +114,6 @@ Dylan Cali Austin Foxley Benjamin Saunders Geoffry Song -Rasmus Christian Pedersen William Light Oleg Efimov Lars Gierth @@ -123,7 +122,6 @@ Justin Venus Kristian Evensen Linus Mårtensson Navaneeth Kedaram Nambiathan -Yorkie StarWing thierry-FreeBSD Isaiah Norton @@ -459,3 +457,25 @@ schamberg97 <50446906+schamberg97@users.noreply.github.com> Bob Weinand Issam E. Maghni Juan Pablo Canepa +Shuowang (Wayne) Zhang +Ondřej Surý +Juan José Arboleda +Zhao Zhili +Brandon Cheng +Matvii Hodovaniuk +Hayden +yiyuaner +bbara +SeverinLeonhardt +Andy Fiddaman +Romain Roffé +Eagle Liang +Ricky Zhou +Simon Kissane +James M Snell +Ali Mohammad Pur +Erkhes N <71805796+rexes-ND@users.noreply.github.com> +Joshua M. Clulow +Guilherme Íscaro +Martin Storsjö +Claes Nästén diff --git a/ChangeLog b/ChangeLog index d0eaf9fe34a..4f2a4bc91dd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,158 @@ +2021.07.21, Version 1.42.0 (Stable) + +Changes since version 1.41.0: + +* doc: fix code highlighting (Darshan Sen) + +* test: move to ASSERT_NULL and ASSERT_NOT_NULL test macros (tjarlama) + +* zos: build in ascii code page (Shuowang (Wayne) Zhang) + +* zos: don't use nanosecond timestamp fields (Shuowang (Wayne) Zhang) + +* zos: introduce zoslib (Shuowang (Wayne) Zhang) + +* zos: use strnlen() from zoslib (Shuowang (Wayne) Zhang) + +* zos: use nanosleep() from zoslib (Shuowang (Wayne) Zhang) + +* zos: use __getargv() from zoslib to get exe path (Shuowang (Wayne) Zhang) + +* zos: treat __rfim_utok as binary (Shuowang (Wayne) Zhang) + +* zos: use execvpe() to set environ explictly (Shuowang (Wayne) Zhang) + +* zos: use custom proctitle implementation (Shuowang (Wayne) Zhang) + +* doc: add instructions for building on z/OS (Shuowang (Wayne) Zhang) + +* linux,udp: enable full ICMP error reporting (Ondřej Surý) + +* test: fix test-udp-send-unreachable (Ondřej Surý) + +* include: fix typo in documentation (Tobias Nießen) + +* chore: use for(;;) instead of while (Yash Ladha) + +* test: remove string + int warning on udp-pummel (Juan José Arboleda) + +* cmake: fix linker flags (Zhao Zhili) + +* test: fix stack-use-after-scope (Zhao Zhili) + +* unix: expose thread_stack_size() internally (Brandon Cheng) + +* darwin: use RLIMIT_STACK for fsevents pthread (Brandon Cheng) + +* darwin: abort on pthread_attr_init fail (Brandon Cheng) + +* benchmark: remove unreachable code (Matvii Hodovaniuk) + +* macos: fix memleaks in uv__get_cpu_speed (George Zhao) + +* Make Thread Sanitizer aware of file descriptor close in uv__close() (Ondřej + Surý) + +* darwin: fix iOS compilation and functionality (Hayden) + +* linux: work around copy_file_range() cephfs bug (Ben Noordhuis) + +* zos: implement uv_get_constrained_memory() (Shuowang (Wayne) Zhang) + +* zos: fix uv_get_free_memory() (Shuowang (Wayne) Zhang) + +* zos: use CVTRLSTG to get total memory accurately (Shuowang (Wayne) Zhang) + +* ibmi: Handle interface names longer than 10 chars (Kevin Adler) + +* docs: update read-the-docs version of sphinx (Jameson Nash) + +* unix: refactor uv_try_write (twosee) + +* linux-core: add proper divide by zero assert (yiyuaner) + +* misc: remove unnecessary _GNU_SOURCE macros (Darshan Sen) + +* test: log to stdout to conform TAP spec (bbara) + +* win,fs: fix C4090 warning with MSVC (SeverinLeonhardt) + +* build: some systems provide dlopen() in libc (Andy Fiddaman) + +* include: add EOVERFLOW status code mapping (Darshan Sen) + +* unix,fs: use uv__load_relaxed and uv__store_relaxed (Darshan Sen) + +* win: fix string encoding issue of uv_os_gethostname (Eagle Liang) + +* unix,process: add uv__write_errno helper function (Ricky Zhou) + +* Re-merge "unix,stream: clear read/write states on close/eof" (Jameson Nash) + +* unix,core: fix errno handling in uv__getpwuid_r (Darshan Sen) + +* errors: map ESOCKTNOSUPPORT errno (Ryan Liptak) + +* doc: uv_read_stop always succeeds (Simon Kissane) + +* inet: fix inconsistent return value of inet_ntop6 (twosee) + +* darwin: fix -Wsometimes-uninitialized warning (twosee) + +* stream: introduce uv_try_write2 function (twosee) + +* poll,win: UV_PRIORITIZED option should not assert (twosee) + +* src: DragonFlyBSD has mmsghdr struct too (David Carlier) + +* cleanup,win: Remove _WIN32 guards on threadpool (James M Snell) + +* freebsd: fix an incompatible pointer type warning (Darshan Sen) + +* core: Correct the conditionals for {cloexec,nonblock}_ioctl (Ali Mohammad + Pur) + +* win,tcp: make uv_close work more like unix (Jameson Nash) + +* doc: more accurate list of valid send_handle's (twosee) + +* win,tcp: translate system errors correctly (twosee) + +* unix: implement cpu_relax() on ppc64 (Ben Noordhuis) + +* docs: move list of project links under PR control (Jameson Nash) + +* test: wrong pointer arithmetic multiplier (Erkhes N) + +* doc: switch discussion forum to github (Jameson Nash) + +* idna: fix OOB read in punycode decoder (Ben Noordhuis) + +* build: make sure -fvisibility=hidden is set (Santiago Gimeno) + +* illumos: event ports to epoll (tjarlama) + +* illumos,tty: UV_TTY_MODE_IO waits for 4 bytes (Joshua M. Clulow) + +* doc: add vtjnash GPG ID (Jameson Nash) + +* linux: read CPU model information on ppc (Richard Lau) + +* darwin: fix uv_barrier race condition (Guilherme Íscaro) + +* unix,stream: fix loop hang after uv_shutdown (Jameson Nash) + +* doc,udp: note that suggested_size is 1 max-sized dgram (Ryan Liptak) + +* mingw: fix building for ARM/AArch64 (Martin Storsjö) + +* unix: strnlen is not available on Solaris 10 (Claes Nästén) + +* sunos: restore use of event ports (Andy Fiddaman) + +* sunos,cmake: use thread-safe errno (Andy Fiddaman) + + 2021.02.14, Version 1.41.0 (Stable), 1dff88e5161cba5c59276d2070d2e304e4dcb242 Changes since version 1.40.0: diff --git a/configure.ac b/configure.ac index 8ac49276e50..1fbb5c8c822 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.41.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.42.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 858ff5dc2bb..d5ba36c3ba9 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 41 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 42 +#define UV_VERSION_PATCH 0 +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 8763476155c4a2a496e9134af25b2b8b87a07ccb Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 19 Jul 2021 22:44:31 -0400 Subject: [PATCH 050/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 4f2a4bc91dd..11492c55323 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2021.07.21, Version 1.42.0 (Stable) +2021.07.21, Version 1.42.0 (Stable), 6ce14710da7079eb248868171f6343bc409ea3a4 Changes since version 1.41.0: From 574c49f07fd4142aadf7657affbf73ad322da752 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 20 Jul 2021 00:48:38 -0400 Subject: [PATCH 051/713] Now working on version 1.42.1 Fixes: https://github.com/libuv/libuv/issues/3202 --- include/uv/version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/uv/version.h b/include/uv/version.h index d5ba36c3ba9..ab5ed00954d 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 42 -#define UV_VERSION_PATCH 0 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 1 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From bd7fcf1bfc411c4a57141002f97a163d6a00a925 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 21 Jul 2021 12:39:13 -0400 Subject: [PATCH 052/713] run test named ip6_sin6_len This appears to have been missed in the original PR. Refs: https://github.com/libuv/libuv/pull/2492 Refs: https://github.com/libuv/libuv/issues/2655 (fixes one issue listed) PR-URL: https://github.com/libuv/libuv/pull/3246 Reviewed-By: Santiago Gimeno --- test/test-ip6-addr.c | 6 +++--- test/test-list.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/test/test-ip6-addr.c b/test/test-ip6-addr.c index 39d570659da..8036c4b1712 100644 --- a/test/test-ip6-addr.c +++ b/test/test-ip6-addr.c @@ -161,11 +161,11 @@ TEST_IMPL(ip6_pton) { #undef GOOD_ADDR_LIST #undef BAD_ADDR_LIST -#ifdef SIN6_LEN TEST_IMPL(ip6_sin6_len) { struct sockaddr_in6 s; - ASSERT(uv_ip6_addr("::", 0, &s) < 0); + ASSERT_EQ(0, uv_ip6_addr("::", 0, &s)); +#ifdef SIN6_LEN ASSERT(s.sin6_len == sizeof(s)); +#endif return 0; } -#endif diff --git a/test/test-list.h b/test/test-list.h index 59b95da9ebe..f8ed94bce21 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -78,6 +78,7 @@ TEST_DECLARE (tty_pty) TEST_DECLARE (stdio_over_pipes) TEST_DECLARE (stdio_emulate_iocp) TEST_DECLARE (ip6_pton) +TEST_DECLARE (ip6_sin6_len) TEST_DECLARE (connect_unspecified) TEST_DECLARE (ipc_heavy_traffic_deadlock_bug) TEST_DECLARE (ipc_listen_before_write) @@ -610,6 +611,7 @@ TASK_LIST_START TEST_ENTRY (stdio_over_pipes) TEST_ENTRY (stdio_emulate_iocp) TEST_ENTRY (ip6_pton) + TEST_ENTRY (ip6_sin6_len) TEST_ENTRY (connect_unspecified) TEST_ENTRY (ipc_heavy_traffic_deadlock_bug) TEST_ENTRY (ipc_listen_before_write) From 84c057a357bcf5f67ba3fdfde3e8e22e1693074f Mon Sep 17 00:00:00 2001 From: Mohamed Edrah <43171151+MSE99@users.noreply.github.com> Date: Thu, 29 Jul 2021 18:08:53 +0200 Subject: [PATCH 053/713] docs: fix wrong information about scheduling Fixes: https://github.com/libuv/libuv/issues/3252 PR-URL: https://github.com/libuv/libuv/pull/3253 Reviewed-By: Ben Noordhuis Reviewed-By: Jameson Nash --- docs/src/guide/basics.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/guide/basics.rst b/docs/src/guide/basics.rst index e55a20cfd7c..457fb15cbe8 100644 --- a/docs/src/guide/basics.rst +++ b/docs/src/guide/basics.rst @@ -42,7 +42,7 @@ as other activities and other I/O operations are kept waiting. One of the standard solutions is to use threads. Each blocking I/O operation is started in a separate thread (or in a thread pool). When the blocking function -gets invoked in the thread, the processor can schedule another thread to run, +gets invoked in the thread, the operating system can schedule another thread to run, which actually needs the CPU. The approach followed by libuv uses another style, which is the **asynchronous, From 04289fa326b790c1a4abb236d1f9d913bacfc8c6 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 29 Jul 2021 12:09:51 -0400 Subject: [PATCH 054/713] unix: protect fork in uv_spawn from signals Years ago, we found that various kernels (linux, macOS) were known to fail if they try to deliver a signal during this syscall, so we prevent that from happening. They may have fixed those issues, but it is generally just a bad time for signals to arrive (glibc blocks them here, for example, including some more internal ones that it won't let us touch here). We try to be a bit conservative, and leave many signals unblocked which could happen during normal execution and should terminate the process if they do. There is a small race window after the child starts before we clear the old handlers, if the user was to send an fake signal from elsewhere, but that should be quite unlikely. PR-URL: https://github.com/libuv/libuv/pull/3251 Reviewed-By: Ben Noordhuis --- src/unix/process.c | 91 +++++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index f4aebb0490e..91bf3c50702 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -216,13 +217,32 @@ static void uv__process_child_init(const uv_process_options_t* options, int stdio_count, int (*pipes)[2], int error_fd) { - sigset_t set; + sigset_t signewset; int close_fd; int use_fd; - int err; int fd; int n; + /* Reset signal disposition first. Use a hard-coded limit because NSIG is not + * fixed on Linux: it's either 32, 34 or 64, depending on whether RT signals + * are enabled. We are not allowed to touch RT signal handlers, glibc uses + * them internally. + */ + for (n = 1; n < 32; n += 1) { + if (n == SIGKILL || n == SIGSTOP) + continue; /* Can't be changed. */ + +#if defined(__HAIKU__) + if (n == SIGKILLTHR) + continue; /* Can't be changed. */ +#endif + + if (SIG_ERR != signal(n, SIG_DFL)) + continue; + + uv__write_errno(error_fd); + } + if (options->flags & UV_PROCESS_DETACHED) setsid(); @@ -304,32 +324,10 @@ static void uv__process_child_init(const uv_process_options_t* options, environ = options->env; } - /* Reset signal disposition. Use a hard-coded limit because NSIG - * is not fixed on Linux: it's either 32, 34 or 64, depending on - * whether RT signals are enabled. We are not allowed to touch - * RT signal handlers, glibc uses them internally. - */ - for (n = 1; n < 32; n += 1) { - if (n == SIGKILL || n == SIGSTOP) - continue; /* Can't be changed. */ - -#if defined(__HAIKU__) - if (n == SIGKILLTHR) - continue; /* Can't be changed. */ -#endif - - if (SIG_ERR != signal(n, SIG_DFL)) - continue; - - uv__write_errno(error_fd); - } - - /* Reset signal mask. */ - sigemptyset(&set); - err = pthread_sigmask(SIG_SETMASK, &set, NULL); - - if (err != 0) - uv__write_errno(error_fd); + /* Reset signal mask just before exec. */ + sigemptyset(&signewset); + if (sigprocmask(SIG_SETMASK, &signewset, NULL) != 0) + abort(); #ifdef __MVS__ execvpe(options->file, options->args, environ); @@ -338,6 +336,7 @@ static void uv__process_child_init(const uv_process_options_t* options, #endif uv__write_errno(error_fd); + abort(); } #endif @@ -349,6 +348,8 @@ int uv_spawn(uv_loop_t* loop, /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ return UV_ENOSYS; #else + sigset_t signewset; + sigset_t sigoldset; int signal_pipe[2] = { -1, -1 }; int pipes_storage[8][2]; int (*pipes)[2]; @@ -423,25 +424,41 @@ int uv_spawn(uv_loop_t* loop, /* Acquire write lock to prevent opening new fds in worker threads */ uv_rwlock_wrlock(&loop->cloexec_lock); - pid = fork(); - if (pid == -1) { + /* Start the child with most signals blocked, to avoid any issues before we + * can reset them, but allow program failures to exit (and not hang). */ + sigfillset(&signewset); + sigdelset(&signewset, SIGKILL); + sigdelset(&signewset, SIGSTOP); + sigdelset(&signewset, SIGTRAP); + sigdelset(&signewset, SIGSEGV); + sigdelset(&signewset, SIGBUS); + sigdelset(&signewset, SIGILL); + sigdelset(&signewset, SIGSYS); + sigdelset(&signewset, SIGABRT); + if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0) + abort(); + + pid = fork(); + if (pid == -1) err = UV__ERR(errno); - uv_rwlock_wrunlock(&loop->cloexec_lock); - uv__close(signal_pipe[0]); - uv__close(signal_pipe[1]); - goto error; - } - if (pid == 0) { + if (pid == 0) uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]); + + if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0) abort(); - } /* Release lock in parent process */ uv_rwlock_wrunlock(&loop->cloexec_lock); + uv__close(signal_pipe[1]); + if (pid == -1) { + uv__close(signal_pipe[0]); + goto error; + } + process->status = 0; exec_errorno = 0; do From 6530ea2ff243161b4208aed9549fe2e4c6acc563 Mon Sep 17 00:00:00 2001 From: Supragya Raj Date: Thu, 5 Aug 2021 15:27:26 +0530 Subject: [PATCH 055/713] drop only successfully sent packets post sendmmsg sendmmsg returns with number of packets sent which can be less than number of packets requested to be sent. Do not flush entire write queue and use the returned info to partially clear the write queue. Refs: https://github.com/libuv/libuv/issues/3129 (fixes one issue listed) PR-URL: https://github.com/libuv/libuv/pull/3265 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- src/unix/udp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index 49051c07c15..8e718ced0ac 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -375,8 +375,11 @@ static void uv__udp_sendmmsg(uv_udp_t* handle) { return; } + /* Safety: npkts known to be >0 below. Hence cast from ssize_t + * to size_t safe. + */ for (i = 0, q = QUEUE_HEAD(&handle->write_queue); - i < pkts && q != &handle->write_queue; + i < (size_t)npkts && q != &handle->write_queue; ++i, q = QUEUE_HEAD(&handle->write_queue)) { assert(q != NULL); req = QUEUE_DATA(q, uv_udp_send_t, queue); From 50c337a0b177669410efef83541e6f17c63ff5b0 Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Wed, 8 Sep 2021 23:02:11 +0900 Subject: [PATCH 056/713] test: fix typo in test-tty-escape-sequence-processing.c postion -> position in several comments PR-URL: https://github.com/libuv/libuv/pull/3284 Reviewed-By: Ben Noordhuis Reviewed-By: Jameson Nash --- test/test-tty-escape-sequence-processing.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test-tty-escape-sequence-processing.c b/test/test-tty-escape-sequence-processing.c index ef34e5927c5..c19ccb5cb1c 100644 --- a/test/test-tty-escape-sequence-processing.c +++ b/test/test-tty-escape-sequence-processing.c @@ -271,7 +271,7 @@ static void make_expect_screen_erase(struct captured_screen* cs, static void make_expect_screen_write(struct captured_screen* cs, COORD cursor_position, const char* text) { - /* postion of cursor */ + /* position of cursor */ char* start; start = cs->text + cs->si.width * (cursor_position.Y - 1) + cursor_position.X - 1; @@ -1261,7 +1261,7 @@ TEST_IMPL(tty_save_restore_cursor_position) { cursor_pos.Y = si.height / 4; set_cursor_position(&tty_out, cursor_pos); - /* restore the cursor postion */ + /* restore the cursor position */ snprintf(buffer, sizeof(buffer), "%su", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); @@ -1280,7 +1280,7 @@ TEST_IMPL(tty_save_restore_cursor_position) { cursor_pos.Y = si.height / 4; set_cursor_position(&tty_out, cursor_pos); - /* restore the cursor postion */ + /* restore the cursor position */ snprintf(buffer, sizeof(buffer), "%s8", ESC); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); From 66a3053e70496f2bad851aa0643032e5e98147bb Mon Sep 17 00:00:00 2001 From: Sylvain Corlay Date: Wed, 8 Sep 2021 16:37:12 +0200 Subject: [PATCH 057/713] cmake: use standard installation layout always Fixes: https://github.com/libuv/libuv/issues/3074 PR-URL: https://github.com/libuv/libuv/pull/3084 Reviewed-By: Jameson Nash --- CMakeLists.txt | 58 ++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 148d0e68992..f7e87994a19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -625,40 +625,34 @@ if(LIBUV_BUILD_TESTS) endif() endif() -if(UNIX OR MINGW) - # Now for some gibbering horrors from beyond the stars... - foreach(lib IN LISTS uv_libraries) - list(APPEND LIBS "-l${lib}") - endforeach() - string(REPLACE ";" " " LIBS "${LIBS}") - # Consider setting project version via project() call? - file(STRINGS configure.ac configure_ac REGEX ^AC_INIT) - string(REGEX MATCH "([0-9]+)[.][0-9]+[.][0-9]+" PACKAGE_VERSION "${configure_ac}") - set(UV_VERSION_MAJOR "${CMAKE_MATCH_1}") - # The version in the filename is mirroring the behaviour of autotools. - set_target_properties(uv PROPERTIES - VERSION ${UV_VERSION_MAJOR}.0.0 - SOVERSION ${UV_VERSION_MAJOR}) - set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}) - set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) - set(prefix ${CMAKE_INSTALL_PREFIX}) - configure_file(libuv.pc.in libuv.pc @ONLY) - configure_file(libuv-static.pc.in libuv-static.pc @ONLY) - - install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) - install(FILES ${PROJECT_BINARY_DIR}/libuv.pc ${PROJECT_BINARY_DIR}/libuv-static.pc - DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - install(TARGETS uv LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) - install(TARGETS uv_a ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -endif() +# Now for some gibbering horrors from beyond the stars... +foreach(lib IN LISTS uv_libraries) + list(APPEND LIBS "-l${lib}") +endforeach() +string(REPLACE ";" " " LIBS "${LIBS}") +# Consider setting project version via project() call? +file(STRINGS configure.ac configure_ac REGEX ^AC_INIT) +string(REGEX MATCH "([0-9]+)[.][0-9]+[.][0-9]+" PACKAGE_VERSION "${configure_ac}") +set(UV_VERSION_MAJOR "${CMAKE_MATCH_1}") +# The version in the filename is mirroring the behaviour of autotools. +set_target_properties(uv PROPERTIES + VERSION ${UV_VERSION_MAJOR}.0.0 + SOVERSION ${UV_VERSION_MAJOR}) +set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}) +set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) +set(prefix ${CMAKE_INSTALL_PREFIX}) +configure_file(libuv.pc.in libuv.pc @ONLY) +configure_file(libuv-static.pc.in libuv-static.pc @ONLY) + +install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) +install(FILES ${PROJECT_BINARY_DIR}/libuv.pc ${PROJECT_BINARY_DIR}/libuv-static.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +install(TARGETS uv LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(TARGETS uv_a ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) if(MSVC) - install(DIRECTORY include/ DESTINATION include) - install(FILES LICENSE DESTINATION .) - install(TARGETS uv uv_a - RUNTIME DESTINATION lib/$ - ARCHIVE DESTINATION lib/$) + set(CMAKE_DEBUG_POSTFIX d) endif() message(STATUS "summary of build options: From 7024f8b2422880568150b2605d9035fa2a597346 Mon Sep 17 00:00:00 2001 From: earnal Date: Wed, 8 Sep 2021 17:27:08 +0200 Subject: [PATCH 058/713] win,spawn: allow UNC path with forward slash Fixes: https://github.com/libuv/libuv/issues/3159 PR-URL: https://github.com/libuv/libuv/pull/3167 Reviewed-By: Jameson Nash --- src/win/process.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/win/process.c b/src/win/process.c index 4038fbfd290..68d70c76b2a 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -169,7 +169,9 @@ static WCHAR* search_path_join_test(const WCHAR* dir, size_t cwd_len) { WCHAR *result, *result_pos; DWORD attrs; - if (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') { + if (dir_len > 2 && + ((dir[0] == L'\\' || dir[0] == L'/') && + (dir[1] == L'\\' || dir[1] == L'/'))) { /* It's a UNC path so ignore cwd */ cwd_len = 0; } else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) { From a39009a5a9252a566ca0704d02df8dabc4ce328f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 8 Sep 2021 17:30:02 +0200 Subject: [PATCH 059/713] win,fsevent: fix uv_fs_event_stop() assert Fix a logic error where calling uv_fs_event_stop() from the event callback tripped on a `handle->dir_handle != INVALID_HANDLE_VALUE` assert in uv_fs_event_queue_readdirchanges(). Fixes: https://github.com/libuv/libuv/issues/3258 PR-URL: https://github.com/libuv/libuv/pull/3259 Reviewed-By: Jameson Nash Reviewed-By: Santiago Gimeno --- src/win/fs-event.c | 6 +++--- test/test-fs-event.c | 49 +++++++++++++++++++++++++++++++++++++++++++- test/test-list.h | 2 ++ 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 0126c5ededf..76da077551d 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -574,10 +574,10 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); } - if (!(handle->flags & UV_HANDLE_CLOSING)) { - uv_fs_event_queue_readdirchanges(loop, handle); - } else { + if (handle->flags & UV_HANDLE_CLOSING) { uv_want_endgame(loop, (uv_handle_t*)handle); + } else if (uv__is_active(handle)) { + uv_fs_event_queue_readdirchanges(loop, handle); } } diff --git a/test/test-fs-event.c b/test/test-fs-event.c index ec163868f49..b04809db333 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -380,7 +380,7 @@ static void timer_cb_file(uv_timer_t* handle) { static void timer_cb_touch(uv_timer_t* timer) { uv_close((uv_handle_t*)timer, NULL); - touch_file("watch_file"); + touch_file((char*) timer->data); timer_cb_touch_called++; } @@ -730,6 +730,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) { r = uv_timer_init(loop, &timer); ASSERT(r == 0); + timer.data = "watch_file"; r = uv_timer_start(&timer, timer_cb_touch, 1100, 0); ASSERT(r == 0); @@ -1174,3 +1175,49 @@ TEST_IMPL(fs_event_watch_invalid_path) { MAKE_VALGRIND_HAPPY(); return 0; } + +static int fs_event_cb_stop_calls; + +static void fs_event_cb_stop(uv_fs_event_t* handle, const char* path, + int events, int status) { + uv_fs_event_stop(handle); + fs_event_cb_stop_calls++; +} + +TEST_IMPL(fs_event_stop_in_cb) { + uv_fs_event_t fs; + uv_timer_t timer; + char path[] = "fs_event_stop_in_cb.txt"; + +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + + remove(path); + create_file(path); + + ASSERT_EQ(0, uv_fs_event_init(uv_default_loop(), &fs)); + ASSERT_EQ(0, uv_fs_event_start(&fs, fs_event_cb_stop, path, 0)); + + /* Note: timer_cb_touch() closes the handle. */ + timer.data = path; + ASSERT_EQ(0, uv_timer_init(uv_default_loop(), &timer)); + ASSERT_EQ(0, uv_timer_start(&timer, timer_cb_touch, 100, 0)); + + ASSERT_EQ(0, fs_event_cb_stop_calls); + ASSERT_EQ(0, timer_cb_touch_called); + + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT_EQ(1, fs_event_cb_stop_calls); + ASSERT_EQ(1, timer_cb_touch_called); + + uv_close((uv_handle_t*) &fs, NULL); + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, fs_event_cb_stop_calls); + + remove(path); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index f8ed94bce21..69a63ac5bdb 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -391,6 +391,7 @@ TEST_DECLARE (fs_event_close_in_callback) TEST_DECLARE (fs_event_start_and_close) TEST_DECLARE (fs_event_error_reporting) TEST_DECLARE (fs_event_getpath) +TEST_DECLARE (fs_event_stop_in_cb) TEST_DECLARE (fs_scandir_empty_dir) TEST_DECLARE (fs_scandir_non_existent_dir) TEST_DECLARE (fs_scandir_file) @@ -1052,6 +1053,7 @@ TASK_LIST_START TEST_ENTRY (fs_event_start_and_close) TEST_ENTRY_CUSTOM (fs_event_error_reporting, 0, 0, 60000) TEST_ENTRY (fs_event_getpath) + TEST_ENTRY (fs_event_stop_in_cb) TEST_ENTRY (fs_scandir_empty_dir) TEST_ENTRY (fs_scandir_non_existent_dir) TEST_ENTRY (fs_scandir_file) From f6dfbcec76f423dfac16e6842f0c8dfd3e91bb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Tue, 5 Oct 2021 06:01:25 -0500 Subject: [PATCH 060/713] unix: remove redundant include in unix.h (#3319) --- include/uv/unix.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/uv/unix.h b/include/uv/unix.h index e3cf7bdd4ef..ea37d787686 100644 --- a/include/uv/unix.h +++ b/include/uv/unix.h @@ -65,12 +65,10 @@ # include "uv/bsd.h" #elif defined(__CYGWIN__) || \ defined(__MSYS__) || \ + defined(__HAIKU__) || \ + defined(__QNX__) || \ defined(__GNU__) # include "uv/posix.h" -#elif defined(__HAIKU__) -# include "uv/posix.h" -#elif defined(__QNX__) -# include "uv/posix.h" #endif #ifndef NI_MAXHOST From 7af7318b21677e5106da8a27a69cd0befca82458 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 5 Oct 2021 21:46:38 +0200 Subject: [PATCH 061/713] doc: mark SmartOS as Tier 3 support (#3320) There haven't been active maintainers for this platform for a long time so back to tier 3 it goes. --- SUPPORTED_PLATFORMS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 30e0ea617a6..87e23823ad6 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -10,7 +10,7 @@ | 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 | | -| SmartOS | Tier 2 | >= 14.4 | Maintainers: @libuv/smartos | +| SmartOS | Tier 3 | >= 14.4 | | | Android | Tier 3 | NDK >= r15b | | | MinGW | Tier 3 | MinGW32 and MinGW-w64 | | | SunOS | Tier 3 | Solaris 121 and later | | From 68355e7d15adb7fb4807e854ecbaa228ae70e7f1 Mon Sep 17 00:00:00 2001 From: YAKSH BARIYA Date: Wed, 6 Oct 2021 01:28:20 +0530 Subject: [PATCH 062/713] doc: fix broken links for netbsd's sysctl manpage (#3312) --- docs/src/misc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 9a8595e577c..2fe6c1ce85d 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -732,7 +732,7 @@ API :man:`sysctl(2)`. - FreeBSD: `getrandom(2) _`, or `/dev/urandom` after reading from `/dev/random` once. - - NetBSD: `KERN_ARND` `sysctl(3) _` + - NetBSD: `KERN_ARND` `sysctl(7) _` - macOS, OpenBSD: `getentropy(2) _` if available, or `/dev/urandom` after reading from `/dev/random` once. - AIX: `/dev/random`. From 80373e8eb1411d72a6c2bfc9896f36c2feab26e7 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 6 Oct 2021 23:56:47 +0200 Subject: [PATCH 063/713] misc: adjust stalebot deadline (#3316) Three weeks is arguably a little too aggressive and auto-closing is not a crowd favorite. Bump to four weeks and disable auto-closing. --- .github/stale.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/stale.yml b/.github/stale.yml index d0ba3a4a99d..6f2fb663c62 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,9 +1,9 @@ # Number of days of inactivity before an issue becomes stale -daysUntilStale: 21 +daysUntilStale: 28 # Number of days of inactivity before a stale issue is closed # Set to false to disable. If disabled, issues still need to be closed # manually, but will remain marked as stale. -daysUntilClose: 120 +daysUntilClose: false # Issues with these labels will never be considered stale exemptLabels: - v2 @@ -18,7 +18,6 @@ staleLabel: stale # Comment to post when marking an issue as stale. Set to `false` to disable markComment: > This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. + recent activity. Thank you for your contributions. # Comment to post when closing a stale issue. Set to `false` to disable closeComment: false From c852be467e863c54b16c73bd7fa6d9bc2c59fd2a Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Sat, 9 Oct 2021 12:32:31 +0000 Subject: [PATCH 064/713] test: remove `dns-server.c` as it is not used anywhere (#3313) Signed-off-by: Darshan Sen --- CMakeLists.txt | 1 - Makefile.am | 1 - test/benchmark-list.h | 1 - test/dns-server.c | 340 ------------------------------------------ 4 files changed, 343 deletions(-) delete mode 100644 test/dns-server.c diff --git a/CMakeLists.txt b/CMakeLists.txt index f7e87994a19..086e0dd58e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -418,7 +418,6 @@ if(LIBUV_BUILD_TESTS) test/benchmark-thread.c test/benchmark-udp-pummel.c test/blackhole-server.c - test/dns-server.c test/echo-server.c test/run-benchmarks.c test/runner.c) diff --git a/Makefile.am b/Makefile.am index 5830003c1e0..97c257037a6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -141,7 +141,6 @@ endif test_run_tests_LDFLAGS = test_run_tests_SOURCES = test/blackhole-server.c \ - test/dns-server.c \ test/echo-server.c \ test/run-tests.c \ test/runner.c \ diff --git a/test/benchmark-list.h b/test/benchmark-list.h index 29e44c30f02..71e4eab9a57 100644 --- a/test/benchmark-list.h +++ b/test/benchmark-list.h @@ -81,7 +81,6 @@ HELPER_DECLARE (tcp_pump_server) HELPER_DECLARE (pipe_pump_server) HELPER_DECLARE (tcp4_echo_server) HELPER_DECLARE (pipe_echo_server) -HELPER_DECLARE (dns_server) TASK_LIST_START BENCHMARK_ENTRY (sizes) diff --git a/test/dns-server.c b/test/dns-server.c deleted file mode 100644 index f8ca87f227e..00000000000 --- a/test/dns-server.c +++ /dev/null @@ -1,340 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "uv.h" -#include "task.h" -#include -#include -#include - - -typedef struct { - uv_write_t req; - uv_buf_t buf; -} write_req_t; - - -/* used to track multiple DNS requests received */ -typedef struct { - char* prevbuf_ptr; - int prevbuf_pos; - int prevbuf_rem; -} dnsstate; - - -/* modify handle to append dnsstate */ -typedef struct { - uv_tcp_t handle; - dnsstate state; -} dnshandle; - - -static uv_loop_t* loop; - - -static uv_tcp_t server; - - -static void after_write(uv_write_t* req, int status); -static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf); -static void on_close(uv_handle_t* peer); -static void on_connection(uv_stream_t*, int status); - -#define WRITE_BUF_LEN (64*1024) -#define DNSREC_LEN (4) - -#define LEN_OFFSET 0 -#define QUERYID_OFFSET 2 - -static unsigned char DNSRsp[] = { - 0, 43, 0, 0, 0x81, 0x80, 0, 1, 0, 1, 0, 0, 0, 0 -}; - -static unsigned char qrecord[] = { - 5, 'e', 'c', 'h', 'o', 's', 3, 's', 'r', 'v', 0, 0, 1, 0, 1 -}; - -static unsigned char arecord[] = { - 0xc0, 0x0c, 0, 1, 0, 1, 0, 0, 5, 0xbd, 0, 4, 10, 0, 1, 1 -}; - - -static void after_write(uv_write_t* req, int status) { - write_req_t* wr; - - if (status) { - fprintf(stderr, "uv_write error: %s\n", uv_strerror(status)); - ASSERT(0); - } - - wr = (write_req_t*) req; - - /* Free the read/write buffer and the request */ - free(wr->buf.base); - free(wr); -} - - -static void after_shutdown(uv_shutdown_t* req, int status) { - uv_close((uv_handle_t*) req->handle, on_close); - free(req); -} - - -static void addrsp(write_req_t* wr, char* hdr) { - char * dnsrsp; - short int rsplen; - short int* reclen; - - rsplen = sizeof(DNSRsp) + sizeof(qrecord) + sizeof(arecord); - - ASSERT (rsplen + wr->buf.len < WRITE_BUF_LEN); - - dnsrsp = wr->buf.base + wr->buf.len; - - /* copy stock response */ - memcpy(dnsrsp, DNSRsp, sizeof(DNSRsp)); - memcpy(dnsrsp + sizeof(DNSRsp), qrecord, sizeof(qrecord)); - memcpy(dnsrsp + sizeof(DNSRsp) + sizeof(qrecord), arecord, sizeof(arecord)); - - /* overwrite with network order length and id from request header */ - reclen = (short int*)dnsrsp; - *reclen = htons(rsplen-2); - dnsrsp[QUERYID_OFFSET] = hdr[QUERYID_OFFSET]; - dnsrsp[QUERYID_OFFSET+1] = hdr[QUERYID_OFFSET+1]; - - wr->buf.len += rsplen; -} - -static void process_req(uv_stream_t* handle, - ssize_t nread, - const uv_buf_t* buf) { - write_req_t* wr; - dnshandle* dns = (dnshandle*)handle; - char hdrbuf[DNSREC_LEN]; - int hdrbuf_remaining = DNSREC_LEN; - int rec_remaining = 0; - int readbuf_remaining; - char* dnsreq; - char* hdrstart; - int usingprev = 0; - - wr = (write_req_t*) malloc(sizeof *wr); - wr->buf.base = (char*)malloc(WRITE_BUF_LEN); - wr->buf.len = 0; - - if (dns->state.prevbuf_ptr != NULL) { - dnsreq = dns->state.prevbuf_ptr + dns->state.prevbuf_pos; - readbuf_remaining = dns->state.prevbuf_rem; - usingprev = 1; - } else { - dnsreq = buf->base; - readbuf_remaining = nread; - } - hdrstart = dnsreq; - - while (dnsreq != NULL) { - /* something to process */ - while (readbuf_remaining > 0) { - /* something to process in current buffer */ - if (hdrbuf_remaining > 0) { - /* process len and id */ - if (readbuf_remaining < hdrbuf_remaining) { - /* too little to get request header. save for next buffer */ - memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining], - dnsreq, - readbuf_remaining); - hdrbuf_remaining = DNSREC_LEN - readbuf_remaining; - break; - } else { - /* save header */ - memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining], - dnsreq, - hdrbuf_remaining); - dnsreq += hdrbuf_remaining; - readbuf_remaining -= hdrbuf_remaining; - hdrbuf_remaining = 0; - - /* get record length */ - rec_remaining = (unsigned) hdrbuf[0] * 256 + (unsigned) hdrbuf[1]; - rec_remaining -= (DNSREC_LEN - 2); - } - } - - if (rec_remaining <= readbuf_remaining) { - /* prepare reply */ - addrsp(wr, hdrbuf); - - /* move to next record */ - dnsreq += rec_remaining; - hdrstart = dnsreq; - readbuf_remaining -= rec_remaining; - rec_remaining = 0; - hdrbuf_remaining = DNSREC_LEN; - } else { - /* otherwise this buffer is done. */ - rec_remaining -= readbuf_remaining; - break; - } - } - - /* If we had to use bytes from prev buffer, start processing the current - * one. - */ - if (usingprev == 1) { - /* free previous buffer */ - free(dns->state.prevbuf_ptr); - dnsreq = buf->base; - readbuf_remaining = nread; - usingprev = 0; - } else { - dnsreq = NULL; - } - } - - /* send write buffer */ - if (wr->buf.len > 0) { - if (uv_write((uv_write_t*) &wr->req, handle, &wr->buf, 1, after_write)) { - FATAL("uv_write failed"); - } - } - - if (readbuf_remaining > 0) { - /* save start of record position, so we can continue on next read */ - dns->state.prevbuf_ptr = buf->base; - dns->state.prevbuf_pos = hdrstart - buf->base; - dns->state.prevbuf_rem = nread - dns->state.prevbuf_pos; - } else { - /* nothing left in this buffer */ - dns->state.prevbuf_ptr = NULL; - dns->state.prevbuf_pos = 0; - dns->state.prevbuf_rem = 0; - free(buf->base); - } -} - -static void after_read(uv_stream_t* handle, - ssize_t nread, - const uv_buf_t* buf) { - uv_shutdown_t* req; - - if (nread < 0) { - /* Error or EOF */ - ASSERT(nread == UV_EOF); - - if (buf->base) { - free(buf->base); - } - - req = malloc(sizeof *req); - uv_shutdown(req, handle, after_shutdown); - - return; - } - - if (nread == 0) { - /* Everything OK, but nothing read. */ - free(buf->base); - return; - } - /* process requests and send responses */ - process_req(handle, nread, buf); -} - - -static void on_close(uv_handle_t* peer) { - free(peer); -} - - -static void buf_alloc(uv_handle_t* handle, - size_t suggested_size, - uv_buf_t* buf) { - buf->base = malloc(suggested_size); - buf->len = suggested_size; -} - - -static void on_connection(uv_stream_t* server, int status) { - dnshandle* handle; - int r; - - ASSERT(status == 0); - - handle = (dnshandle*) malloc(sizeof *handle); - ASSERT_NOT_NULL(handle); - - /* initialize read buffer state */ - handle->state.prevbuf_ptr = 0; - handle->state.prevbuf_pos = 0; - handle->state.prevbuf_rem = 0; - - r = uv_tcp_init(loop, (uv_tcp_t*)handle); - ASSERT(r == 0); - - r = uv_accept(server, (uv_stream_t*)handle); - ASSERT(r == 0); - - r = uv_read_start((uv_stream_t*)handle, buf_alloc, after_read); - ASSERT(r == 0); -} - - -static int dns_start(int port) { - struct sockaddr_in addr; - int r; - - ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr)); - - r = uv_tcp_init(loop, &server); - if (r) { - /* TODO: Error codes */ - fprintf(stderr, "Socket creation error\n"); - return 1; - } - - r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); - if (r) { - /* TODO: Error codes */ - fprintf(stderr, "Bind error\n"); - return 1; - } - - r = uv_listen((uv_stream_t*)&server, 128, on_connection); - if (r) { - /* TODO: Error codes */ - fprintf(stderr, "Listen error\n"); - return 1; - } - - return 0; -} - - -HELPER_IMPL(dns_server) { - loop = uv_default_loop(); - - if (dns_start(TEST_PORT_2)) - return 1; - - uv_run(loop, UV_RUN_DEFAULT); - return 0; -} From f716265b51fe887f2d219d2cbfa67010c89a48d1 Mon Sep 17 00:00:00 2001 From: YAKSH BARIYA Date: Sat, 9 Oct 2021 18:33:21 +0530 Subject: [PATCH 065/713] build: fix non-cmake android builds (#3311) See https://github.com/libuv/libuv/issues/2768#issuecomment-731375392 Patch based upon https://github.com/termux/termux-packages/pull/7529 --- Makefile.am | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index 97c257037a6..cb3b42c27b7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -389,10 +389,7 @@ if ANDROID uvinclude_HEADERS += include/uv/android-ifaddrs.h libuv_la_CFLAGS += -D_GNU_SOURCE libuv_la_SOURCES += src/unix/android-ifaddrs.c \ - src/unix/pthread-fixes.c \ - src/unix/random-getrandom.c \ - src/unix/random-sysctl-linux.c \ - src/unix/epoll.c + src/unix/pthread-fixes.c endif if CYGWIN From c273d8b9cf4b3cbd4c896dc484c30c3e18a02d6e Mon Sep 17 00:00:00 2001 From: Ofek Lev Date: Sat, 9 Oct 2021 18:56:50 -0400 Subject: [PATCH 066/713] doc: replace pyuv with uvloop (#3324) - pyuv is not actively maintained - uvloop is downloaded 11M/mo, pyuv only 25k/mo Refs: https://github.com/saghul/pyuv/issues/270#issuecomment-925106097 --- README.md | 2 +- docs/src/index.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a9a8a9d1179..06486febc28 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ libuv is a multi-platform support library with a focus on asynchronous I/O. It was primarily developed for use by [Node.js][], but it's also used by [Luvit](http://luvit.io/), [Julia](http://julialang.org/), -[pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/libuv/libuv/blob/v1.x/LINKS.md). +[uvloop](https://github.com/MagicStack/uvloop), and [others](https://github.com/libuv/libuv/blob/v1.x/LINKS.md). ## Feature highlights diff --git a/docs/src/index.rst b/docs/src/index.rst index 4b5d4d2c511..5bdb4be84b6 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -7,7 +7,7 @@ Overview libuv is a multi-platform support library with a focus on asynchronous I/O. It was primarily developed for use by `Node.js`_, but it's also used by `Luvit`_, -`Julia`_, `pyuv`_, and `others`_. +`Julia`_, `uvloop`_, and `others`_. .. note:: In case you find errors in this documentation you can help by sending @@ -16,7 +16,7 @@ was primarily developed for use by `Node.js`_, but it's also used by `Luvit`_, .. _Node.js: https://nodejs.org .. _Luvit: https://luvit.io .. _Julia: https://julialang.org -.. _pyuv: https://github.com/saghul/pyuv +.. _uvloop: https://github.com/MagicStack/uvloop .. _others: https://github.com/libuv/libuv/blob/v1.x/LINKS.md From 6564ccc90073296769ac17319bba3f3357005603 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 9 Oct 2021 18:57:43 -0400 Subject: [PATCH 067/713] asan: fix some tests (#3323) Previously they were just being run incorrectly, but nothing wrong with the test itself. We were also interpreting an ASAN failure as TEST_SKIP, so test failures would not actually be reported as CI failures. --- .github/workflows/sanitizer.yml | 11 +++++++---- CMakeLists.txt | 6 +++--- test/task.h | 2 +- test/test-fs-copyfile.c | 3 --- test/test-fs-event.c | 3 --- test/test-fs-readdir.c | 3 --- test/test-fs.c | 6 ------ test/test-ping-pong.c | 3 +++ test/test-pipe-connect-error.c | 3 --- 9 files changed, 14 insertions(+), 26 deletions(-) diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 51e14794ffd..ede60117fec 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -7,11 +7,14 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + - name: Setup + run: | + sudo apt-get install ninja-build - name: Envinfo run: npx envinfo - name: ASAN run: | - mkdir build - cd build && cmake .. -DBUILD_TESTING=ON -DASAN=ON -DCMAKE_BUILD_TYPE=Debug - cmake --build . && ./uv_run_tests_a - + mkdir build-asan + (cd build-asan && cmake .. -G Ninja -DBUILD_TESTING=ON -DASAN=ON -DCMAKE_BUILD_TYPE=Debug) + cmake --build build-asan + ./build-asan/uv_run_tests_a diff --git a/CMakeLists.txt b/CMakeLists.txt index 086e0dd58e7..191cd2a7f58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,8 +33,8 @@ endif() option(ASAN "Enable AddressSanitizer (ASan)" OFF) if(ASAN AND CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang") add_definitions(-D__ASAN__=1) - set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") - set (CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=address") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=address") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address") endif() @@ -658,6 +658,6 @@ message(STATUS "summary of build options: Install prefix: ${CMAKE_INSTALL_PREFIX} Target system: ${CMAKE_SYSTEM_NAME} Compiler: - C compiler: ${CMAKE_C_COMPILER} + C compiler: ${CMAKE_C_COMPILER} (${CMAKE_C_COMPILER_ID}) CFLAGS: ${CMAKE_C_FLAGS_${_build_type}} ${CMAKE_C_FLAGS} ") diff --git a/test/task.h b/test/task.h index a02c8931b50..925f1b1c0ae 100644 --- a/test/task.h +++ b/test/task.h @@ -277,7 +277,7 @@ const char* fmt(double d); /* Reserved test exit codes. */ enum test_status { TEST_OK = 0, - TEST_SKIP + TEST_SKIP = 7 }; #define RETURN_OK() \ diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index fa00fe4ee89..c785a4b51fb 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -96,9 +96,6 @@ static void touch_file(const char* name, unsigned int size) { TEST_IMPL(fs_copyfile) { -#if defined(__ASAN__) - RETURN_SKIP("Test does not currently work in ASAN"); -#endif const char src[] = "test_file_src"; uv_loop_t* loop; uv_fs_t req; diff --git a/test/test-fs-event.c b/test/test-fs-event.c index b04809db333..cbe63190780 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -673,9 +673,6 @@ TEST_IMPL(fs_event_watch_file_exact_path) { TEST_IMPL(fs_event_watch_file_twice) { #if defined(NO_FS_EVENTS) RETURN_SKIP(NO_FS_EVENTS); -#endif -#if defined(__ASAN__) - RETURN_SKIP("Test does not currently work in ASAN"); #endif const char path[] = "test/fixtures/empty_file"; uv_fs_event_t watchers[2]; diff --git a/test/test-fs-readdir.c b/test/test-fs-readdir.c index 41e1d373ca8..6bb69178415 100644 --- a/test/test-fs-readdir.c +++ b/test/test-fs-readdir.c @@ -230,9 +230,6 @@ static void file_opendir_cb(uv_fs_t* req) { } TEST_IMPL(fs_readdir_file) { -#if defined(__ASAN__) - RETURN_SKIP("Test does not currently work in ASAN"); -#endif const char* path; int r; diff --git a/test/test-fs.c b/test/test-fs.c index 034c971d362..f2336e1eb19 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2897,9 +2897,6 @@ TEST_IMPL(fs_scandir_non_existent_dir) { } TEST_IMPL(fs_scandir_file) { -#if defined(__ASAN__) - RETURN_SKIP("Test does not currently work in ASAN"); -#endif const char* path; int r; @@ -3146,9 +3143,6 @@ static void fs_read_bufs(int add_flags) { uv_fs_req_cleanup(&close_req); } TEST_IMPL(fs_read_bufs) { -#if defined(__ASAN__) - RETURN_SKIP("Test does not currently work in ASAN"); -#endif fs_read_bufs(0); fs_read_bufs(UV_FS_O_FILEMAP); diff --git a/test/test-ping-pong.c b/test/test-ping-pong.c index 4a26e4dee1b..c598587d112 100644 --- a/test/test-ping-pong.c +++ b/test/test-ping-pong.c @@ -84,6 +84,7 @@ static void pinger_on_close(uv_handle_t* handle) { static void pinger_after_write(uv_write_t* req, int status) { ASSERT_EQ(status, 0); + free(req->data); free(req); } @@ -110,6 +111,7 @@ static void pinger_write_ping(pinger_t* pinger) { req = malloc(sizeof(*req)); ASSERT_NOT_NULL(req); + req->data = NULL; ASSERT_EQ(0, uv_write(req, stream, bufs, nbufs, pinger_after_write)); puts("PING"); @@ -185,6 +187,7 @@ static void ponger_read_cb(uv_stream_t* stream, writebuf = uv_buf_init(buf->base, nread); req = malloc(sizeof(*req)); ASSERT_NOT_NULL(req); + req->data = buf->base; ASSERT_EQ(0, uv_write(req, stream, &writebuf, 1, pinger_after_write)); } diff --git a/test/test-pipe-connect-error.c b/test/test-pipe-connect-error.c index 30c270d9fce..0f1e2b1c1ed 100644 --- a/test/test-pipe-connect-error.c +++ b/test/test-pipe-connect-error.c @@ -76,9 +76,6 @@ TEST_IMPL(pipe_connect_bad_name) { TEST_IMPL(pipe_connect_to_file) { -#if defined(__ASAN__) - RETURN_SKIP("Test does not currently work in ASAN"); -#endif const char* path = "test/fixtures/empty_file"; uv_pipe_t client; uv_connect_t req; From 22d62239289c7c6e50e6cc4a93642b3b46bf2dad Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 16 Oct 2021 06:13:29 -0400 Subject: [PATCH 068/713] build: add experimental TSAN configuration (#3328) --- .github/workflows/sanitizer.yml | 8 +++++++- CMakeLists.txt | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index ede60117fec..c0a54b28235 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -3,7 +3,7 @@ name: Sanitizer checks on: [push, pull_request] jobs: - asan: + sanitizers: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -12,6 +12,12 @@ jobs: sudo apt-get install ninja-build - name: Envinfo run: npx envinfo + - name: TSAN + run: | + mkdir build-tsan + (cd build-tsan && cmake .. -G Ninja -DBUILD_TESTING=ON -DTSAN=ON -DCMAKE_BUILD_TYPE=Release) + cmake --build build-tsan + ./build-tsan/uv_run_tests_a || true # currently permit failures - name: ASAN run: | mkdir build-asan diff --git a/CMakeLists.txt b/CMakeLists.txt index 191cd2a7f58..2d916f41111 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,13 +31,26 @@ if(QEMU) endif() option(ASAN "Enable AddressSanitizer (ASan)" OFF) -if(ASAN AND CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang") +option(TSAN "Enable ThreadSanitizer (TSan)" OFF) + +if((ASAN OR TSAN) AND NOT (CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang")) + message(SEND_ERROR "Sanitizer support requires clang or gcc. Try again with -DCMAKE_C_COMPILER.") +endif() + +if(ASAN) add_definitions(-D__ASAN__=1) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=address") set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address") endif() +if(TSAN) + add_definitions(-D__TSAN__=1) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=thread") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=thread") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=thread") +endif() + # Compiler check string(CONCAT is-msvc $, From 5b00797205918a594ee2559d5e87a010fe1f0bb5 Mon Sep 17 00:00:00 2001 From: ~locpyl-tidnyd <81016946+locpyl-tidnyd@users.noreply.github.com> Date: Sat, 16 Oct 2021 13:17:38 +0300 Subject: [PATCH 069/713] pipe: remove useless assertion (#3302) This assertion was added when req->write_buffer was a pointer. It was then checking that write_buffer itself was not NULL. Checking that .base is not NULL is superfluous because WriteFile will return error 998 (ERROR_NO_ACCESS) if the input buffer is invalid. This assertion fires on zero-length writes when base==NULL&&len==0. --- src/win/pipe.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index 88ba99bbc0a..912aed9b620 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1252,7 +1252,6 @@ static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) { assert(req != NULL); assert(req->type == UV_WRITE); assert(handle->type == UV_NAMED_PIPE); - assert(req->write_buffer.base); result = WriteFile(handle->handle, req->write_buffer.base, From 6cce781b06ae14befce206a940d02db2aed3d8ad Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Sat, 16 Oct 2021 10:20:50 +0000 Subject: [PATCH 070/713] bsd: destroy mutex in uv__process_title_cleanup() (#3286) Signed-off-by: Darshan Sen --- src/unix/bsd-proctitle.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/unix/bsd-proctitle.c b/src/unix/bsd-proctitle.c index 723b81c01c2..4f4e9e5183f 100644 --- a/src/unix/bsd-proctitle.c +++ b/src/unix/bsd-proctitle.c @@ -38,9 +38,7 @@ static void init_process_title_mutex_once(void) { void uv__process_title_cleanup(void) { - /* TODO(bnoordhuis) uv_mutex_destroy(&process_title_mutex) - * and reset process_title_mutex_once? - */ + uv_mutex_destroy(&process_title_mutex); } From 1cefd94d560cb1d6e5c9817a471fada2f6c5b2a5 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Sat, 16 Oct 2021 10:25:48 +0000 Subject: [PATCH 071/713] build: add windows build to CI (#3212) Refs: https://github.com/libuv/libuv/issues/3325 Signed-off-by: Darshan Sen --- .github/workflows/CI.yml | 30 ++++++++++++++++++++++ test/test-tty-escape-sequence-processing.c | 10 ++++++++ 2 files changed, 40 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c38412344a0..9b4afa99eda 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -3,6 +3,36 @@ name: CI on: [push, pull_request] jobs: + build-windows: + runs-on: windows-${{ matrix.config.server }} + name: build-${{ matrix.config.toolchain}}-${{ matrix.config.arch}} + strategy: + fail-fast: false + matrix: + config: + - {toolchain: Visual Studio 15 2017, arch: Win32, server: 2016} + - {toolchain: Visual Studio 15 2017, arch: x64, server: 2016} + - {toolchain: Visual Studio 16 2019, arch: Win32, server: 2019} + - {toolchain: Visual Studio 16 2019, arch: x64, server: 2019} + - {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022} + - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022} + steps: + - uses: actions/checkout@v2 + - name: Envinfo + run: npx envinfo + - name: Build + shell: cmd + run: | + mkdir -p build + cd build + cmake .. -DBUILD_TESTING=ON -G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }} + cmake --build . + - name: Test + shell: cmd + run: | + cd build + ctest -C Debug --output-on-failure + build-android: runs-on: ubuntu-latest container: reactnativecommunity/react-native-android:2020-5-20 diff --git a/test/test-tty-escape-sequence-processing.c b/test/test-tty-escape-sequence-processing.c index c19ccb5cb1c..5f04291d244 100644 --- a/test/test-tty-escape-sequence-processing.c +++ b/test/test-tty-escape-sequence-processing.c @@ -1070,6 +1070,11 @@ TEST_IMPL(tty_set_style) { WORD attr; int i, length; +#if _MSC_VER >= 1920 && _MSC_VER <= 1929 + RETURN_SKIP("Broken on Microsoft Visual Studio 2019, to be investigated. " + "See: https://github.com/libuv/libuv/issues/3304"); +#endif + loop = uv_default_loop(); initialize_tty(&tty_out); @@ -1348,6 +1353,11 @@ TEST_IMPL(tty_escape_sequence_processing) { struct captured_screen actual = {0}, expect = {0}; int dir; +#if _MSC_VER >= 1920 && _MSC_VER <= 1929 + RETURN_SKIP("Broken on Microsoft Visual Studio 2019, to be investigated. " + "See: https://github.com/libuv/libuv/issues/3304"); +#endif + loop = uv_default_loop(); initialize_tty(&tty_out); From 9604b61db679be2697132891f22509f88ebcc416 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Sat, 16 Oct 2021 13:11:52 +0000 Subject: [PATCH 072/713] win,fs: fix error code in uv_fs_read() and uv_fs_write() (#3303) Just like the Unix counterpart, uv_fs_read() and uv_fs_write() should throw an EBADF instead of throwing an EPERM when the passed fd has not been opened with the right flags. Signed-off-by: Darshan Sen --- src/win/fs.c | 18 +++++++++++++++--- test/test-fs-open-flags.c | 38 +++++++++++++++++++------------------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 674070400be..903764144f4 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -758,7 +758,7 @@ void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) { void* view; if (rw_flags == UV_FS_O_WRONLY) { - SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED); + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FLAGS); return; } if (fd_info->is_directory) { @@ -912,6 +912,11 @@ void fs__read(uv_fs_t* req) { SET_REQ_RESULT(req, bytes); } else { error = GetLastError(); + + if (error == ERROR_ACCESS_DENIED) { + error = ERROR_INVALID_FLAGS; + } + if (error == ERROR_HANDLE_EOF) { SET_REQ_RESULT(req, bytes); } else { @@ -936,7 +941,7 @@ void fs__write_filemap(uv_fs_t* req, HANDLE file, FILETIME ft; if (rw_flags == UV_FS_O_RDONLY) { - SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED); + SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FLAGS); return; } if (fd_info->is_directory) { @@ -1052,6 +1057,7 @@ void fs__write(uv_fs_t* req) { OVERLAPPED overlapped, *overlapped_ptr; LARGE_INTEGER offset_; DWORD bytes; + DWORD error; int result; unsigned int index; LARGE_INTEGER original_position; @@ -1111,7 +1117,13 @@ void fs__write(uv_fs_t* req) { if (result || bytes > 0) { SET_REQ_RESULT(req, bytes); } else { - SET_REQ_WIN32_ERROR(req, GetLastError()); + error = GetLastError(); + + if (error == ERROR_ACCESS_DENIED) { + error = ERROR_INVALID_FLAGS; + } + + SET_REQ_WIN32_ERROR(req, error); } } diff --git a/test/test-fs-open-flags.c b/test/test-fs-open-flags.c index 5f61007adde..372afe13975 100644 --- a/test/test-fs-open-flags.c +++ b/test/test-fs-open-flags.c @@ -276,21 +276,21 @@ static void fs_open_flags(int add_flags) { /* r */ flags = add_flags | UV_FS_O_RDONLY; openFail(absent_file, UV_ENOENT); - writeFail(empty_file, UV_EPERM); + writeFail(empty_file, UV_EBADF); readExpect(empty_file, "", 0); - writeFail(dummy_file, UV_EPERM); + writeFail(dummy_file, UV_EBADF); readExpect(dummy_file, "a", 1); - writeFail(empty_dir, UV_EPERM); + writeFail(empty_dir, UV_EBADF); readFail(empty_dir, UV_EISDIR); /* rs */ flags = add_flags | UV_FS_O_RDONLY | UV_FS_O_SYNC; openFail(absent_file, UV_ENOENT); - writeFail(empty_file, UV_EPERM); + writeFail(empty_file, UV_EBADF); readExpect(empty_file, "", 0); - writeFail(dummy_file, UV_EPERM); + writeFail(dummy_file, UV_EBADF); readExpect(dummy_file, "a", 1); - writeFail(empty_dir, UV_EPERM); + writeFail(empty_dir, UV_EBADF); readFail(empty_dir, UV_EISDIR); /* r+ */ @@ -316,18 +316,18 @@ static void fs_open_flags(int add_flags) { /* w */ flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EPERM); + readFail(absent_file, UV_EBADF); writeExpect(empty_file, "bc", 2); - readFail(empty_file, UV_EPERM); + readFail(empty_file, UV_EBADF); writeExpect(dummy_file, "bc", 2); - readFail(dummy_file, UV_EPERM); + readFail(dummy_file, UV_EBADF); openFail(empty_dir, UV_EISDIR); /* wx */ flags = add_flags | UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY | UV_FS_O_EXCL; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EPERM); + readFail(absent_file, UV_EBADF); openFail(empty_file, UV_EEXIST); openFail(dummy_file, UV_EEXIST); openFail(empty_dir, UV_EEXIST); @@ -354,19 +354,19 @@ static void fs_open_flags(int add_flags) { /* a */ flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EPERM); + readFail(absent_file, UV_EBADF); writeExpect(empty_file, "bc", 2); - readFail(empty_file, UV_EPERM); + readFail(empty_file, UV_EBADF); writeExpect(dummy_file, "abc", 3); - readFail(dummy_file, UV_EPERM); + readFail(dummy_file, UV_EBADF); writeFail(empty_dir, UV_EISDIR); - readFail(empty_dir, UV_EPERM); + readFail(empty_dir, UV_EBADF); /* ax */ flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY | UV_FS_O_EXCL; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EPERM); + readFail(absent_file, UV_EBADF); openFail(empty_file, UV_EEXIST); openFail(dummy_file, UV_EEXIST); openFail(empty_dir, UV_EEXIST); @@ -375,13 +375,13 @@ static void fs_open_flags(int add_flags) { flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_WRONLY | UV_FS_O_SYNC; writeExpect(absent_file, "bc", 2); - readFail(absent_file, UV_EPERM); + readFail(absent_file, UV_EBADF); writeExpect(empty_file, "bc", 2); - readFail(empty_file, UV_EPERM); + readFail(empty_file, UV_EBADF); writeExpect(dummy_file, "abc", 3); - readFail(dummy_file, UV_EPERM); + readFail(dummy_file, UV_EBADF); writeFail(empty_dir, UV_EISDIR); - readFail(empty_dir, UV_EPERM); + readFail(empty_dir, UV_EBADF); /* a+ */ flags = add_flags | UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR; From 1e73814fd0c6843daa064f79e0c0bb6f83fa44ae Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 16 Oct 2021 15:12:28 +0200 Subject: [PATCH 073/713] build: add macos-latest to ci matrix (#3331) Co-authored-by: Jameson Nash Fixes: https://github.com/libuv/libuv/issues/3325 --- .github/workflows/CI.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 9b4afa99eda..c8af0199c7d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -47,6 +47,25 @@ jobs: $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/20.0.5594570/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-21 .. $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake --build . + build-macos: + runs-on: macos-10.15 + steps: + - uses: actions/checkout@v2 + - name: Envinfo + run: npx envinfo + - name: Setup + run: | + brew install ninja + - name: Build + run: | + mkdir build + cd build && cmake .. -DBUILD_TESTING=ON -G Ninja + cmake --build . + ls -lh + - name: Test + run: | + cd build && ctest -V + build-cross-qemu: runs-on: ubuntu-latest name: build-cross-qemu-${{ matrix.config.target }} From 5246ce458af0a8ab90e896470789da1bb16e9106 Mon Sep 17 00:00:00 2001 From: Evan Miller Date: Wed, 20 Oct 2021 12:20:23 -0400 Subject: [PATCH 074/713] udp: fix &/&& typo in macro condition (#3334) --- src/unix/udp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index 8e718ced0ac..71bfbf7f795 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -883,7 +883,7 @@ static int uv__udp_set_membership6(uv_udp_t* handle, #if !defined(__OpenBSD__) && \ !defined(__NetBSD__) && \ !defined(__ANDROID__) && \ - !defined(__DragonFly__) & \ + !defined(__DragonFly__) && \ !defined(__QNX__) static int uv__udp_set_source_membership4(uv_udp_t* handle, const struct sockaddr_in* multicast_addr, From 172d64bc671076091bb9b617ff360a8cd3dc8c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= Date: Mon, 1 Nov 2021 18:51:06 +0100 Subject: [PATCH 075/713] build: install cmake package module If installed into correct location, libuv can be reused in CMakeLists.txt by: find_package(libuv) PR-URL: https://github.com/libuv/libuv/pull/3293 --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d916f41111..16a8cc5d6f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -660,8 +660,9 @@ install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) install(FILES ${PROJECT_BINARY_DIR}/libuv.pc ${PROJECT_BINARY_DIR}/libuv-static.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) -install(TARGETS uv LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(TARGETS uv EXPORT libuvConfig LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(TARGETS uv_a ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(EXPORT libuvConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libuv) if(MSVC) set(CMAKE_DEBUG_POSTFIX d) From 26b2e5dbb6301756644d6e4cf6ca9c49c00513d3 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Mon, 1 Nov 2021 12:09:59 -0700 Subject: [PATCH 076/713] win: fix build for mingw32 (#3340) Commit e9c524aa from pull request https://github.com/libuv/libuv/pull/3149 introduced a hard dependency on `GetHostnameW`, which isn't declared yet in mingw distributions (see https://github.com/msys2/MINGW-packages/issues/9667). This prevents the current version of libuv from building on many mingw distributions, until such time the next version of mingw is released with the correct definition for `GetHostnameW`, preventing a lot of projects depending on libuv from building on mingw properly, as not all distributions will update to head immediately anyway. Instead of waiting, let's find the definition ourselves using `GetProcAddress` and use the pointer instead. PR-URL: https://github.com/libuv/libuv/pull/3340 --- src/win/util.c | 5 ++++- src/win/winapi.c | 10 ++++++++++ src/win/winapi.h | 7 +++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/win/util.c b/src/win/util.c index 88602c7ee86..33e874ac442 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1674,7 +1674,10 @@ int uv_os_gethostname(char* buffer, size_t* size) { uv__once_init(); /* Initialize winsock */ - if (GetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0) + if (pGetHostNameW == NULL) + return UV_ENOSYS; + + if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0) return uv_translate_sys_error(WSAGetLastError()); convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str); diff --git a/src/win/winapi.c b/src/win/winapi.c index bb86ec8ceac..bf306cd83bd 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -45,12 +45,15 @@ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; /* User32.dll function pointer */ sSetWinEventHook pSetWinEventHook; +/* ws2_32.dll function pointer */ +uv_sGetHostNameW pGetHostNameW; void uv_winapi_init(void) { HMODULE ntdll_module; HMODULE powrprof_module; HMODULE user32_module; HMODULE kernel32_module; + HMODULE ws2_32_module; ntdll_module = GetModuleHandleA("ntdll.dll"); if (ntdll_module == NULL) { @@ -134,4 +137,11 @@ void uv_winapi_init(void) { pSetWinEventHook = (sSetWinEventHook) GetProcAddress(user32_module, "SetWinEventHook"); } + + ws2_32_module = LoadLibraryA("ws2_32.dll"); + if (ws2_32_module != NULL) { + pGetHostNameW = (uv_sGetHostNameW) GetProcAddress( + ws2_32_module, + "GetHostNameW"); + } } diff --git a/src/win/winapi.h b/src/win/winapi.h index 0b66b5634bc..d380bda42a3 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4759,4 +4759,11 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi /* User32.dll function pointer */ extern sSetWinEventHook pSetWinEventHook; +/* ws2_32.dll function pointer */ +/* mingw doesn't have this definition, so let's declare it here locally */ +typedef int (WINAPI *uv_sGetHostNameW) + (PWSTR, + int); +extern uv_sGetHostNameW pGetHostNameW; + #endif /* UV_WIN_WINAPI_H_ */ From 3e90bc76b036124c2a94f9bf006af527755271cf Mon Sep 17 00:00:00 2001 From: erw7 Date: Wed, 3 Nov 2021 00:28:42 +0900 Subject: [PATCH 077/713] build: fix build failures with MinGW new headers A structure definition was added to mstcpip.h in mingw-w64-x86_64-headers-git 9.0.0.6327.f29c1101f, which causes a conflict and the build fails. Fix this by changing the name in the definition in mstcpip.h. PR-URL: https://github.com/libuv/libuv/pull/3345 --- include/uv/win.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/uv/win.h b/include/uv/win.h index f5f1d3a3cc2..5fecf4bf6e5 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -45,7 +45,14 @@ typedef struct pollfd { #endif #include +// Disable the typedef in mstcpip.h of MinGW. +#define _TCP_INITIAL_RTO_PARAMETERS _TCP_INITIAL_RTO_PARAMETERS__AVOID +#define TCP_INITIAL_RTO_PARAMETERS TCP_INITIAL_RTO_PARAMETERS__AVOID +#define PTCP_INITIAL_RTO_PARAMETERS PTCP_INITIAL_RTO_PARAMETERS__AVOID #include +#undef _TCP_INITIAL_RTO_PARAMETERS +#undef TCP_INITIAL_RTO_PARAMETERS +#undef PTCP_INITIAL_RTO_PARAMETERS #include #include From 77e6bd4874de73c772f5a3fa50b4727ed4ffaa13 Mon Sep 17 00:00:00 2001 From: AJ Heller Date: Tue, 2 Nov 2021 10:58:25 -0700 Subject: [PATCH 078/713] build: fix win build with cmake versions before v3.14 (#3343) Before v3.14, cmake throws the following error: ``` CMake Error at third_party/libuv/CMakeLists.txt:663 (install): install Library TARGETS given no DESTINATION! ``` I confirmed on Windows 7 and Windows Server 2016, with about a dozen cmake versions between 3.7 and 3.22. I also confirmed that the DESTINATION `${CMAKE_INSTALL_LIBDIR}` is populated with a valid path. PR-URL: https://github.com/libuv/libuv/pull/3343 --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16a8cc5d6f3..337b09c2694 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -660,7 +660,9 @@ install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) install(FILES ${PROJECT_BINARY_DIR}/libuv.pc ${PROJECT_BINARY_DIR}/libuv-static.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) -install(TARGETS uv EXPORT libuvConfig LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(TARGETS uv EXPORT libuvConfig + RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(TARGETS uv_a ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(EXPORT libuvConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libuv) From 48e04275332f5753427d21a52f17ec6206451f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Wed, 3 Nov 2021 05:13:22 -0500 Subject: [PATCH 079/713] unix: support aarch64 in uv_cpu_info() (#3327) --- src/unix/linux-core.c | 99 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 4 deletions(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 2716e2be65d..8c9bbb75f70 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -365,24 +365,30 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { const char* inferred_model; unsigned int model_idx; unsigned int speed_idx; + unsigned int part_idx; char buf[1024]; char* model; FILE* fp; + int model_id; /* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */ (void) &model_marker; (void) &speed_marker; (void) &speed_idx; + (void) &part_idx; (void) &model; (void) &buf; (void) &fp; + (void) &model_id; model_idx = 0; speed_idx = 0; + part_idx = 0; #if defined(__arm__) || \ defined(__i386__) || \ defined(__mips__) || \ + defined(__aarch64__) || \ defined(__PPC__) || \ defined(__x86_64__) fp = uv__open_file("/proc/cpuinfo"); @@ -402,11 +408,96 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { continue; } } -#if defined(__arm__) || defined(__mips__) +#if defined(__arm__) || defined(__mips__) || defined(__aarch64__) if (model_idx < numcpus) { #if defined(__arm__) /* Fallback for pre-3.8 kernels. */ static const char model_marker[] = "Processor\t: "; +#elif defined(__aarch64__) + static const char part_marker[] = "CPU part\t: "; + + /* Adapted from: https://github.com/karelzak/util-linux */ + struct vendor_part { + const int id; + const char* name; + }; + + static const struct vendor_part arm_chips[] = { + { 0x811, "ARM810" }, + { 0x920, "ARM920" }, + { 0x922, "ARM922" }, + { 0x926, "ARM926" }, + { 0x940, "ARM940" }, + { 0x946, "ARM946" }, + { 0x966, "ARM966" }, + { 0xa20, "ARM1020" }, + { 0xa22, "ARM1022" }, + { 0xa26, "ARM1026" }, + { 0xb02, "ARM11 MPCore" }, + { 0xb36, "ARM1136" }, + { 0xb56, "ARM1156" }, + { 0xb76, "ARM1176" }, + { 0xc05, "Cortex-A5" }, + { 0xc07, "Cortex-A7" }, + { 0xc08, "Cortex-A8" }, + { 0xc09, "Cortex-A9" }, + { 0xc0d, "Cortex-A17" }, /* Originally A12 */ + { 0xc0f, "Cortex-A15" }, + { 0xc0e, "Cortex-A17" }, + { 0xc14, "Cortex-R4" }, + { 0xc15, "Cortex-R5" }, + { 0xc17, "Cortex-R7" }, + { 0xc18, "Cortex-R8" }, + { 0xc20, "Cortex-M0" }, + { 0xc21, "Cortex-M1" }, + { 0xc23, "Cortex-M3" }, + { 0xc24, "Cortex-M4" }, + { 0xc27, "Cortex-M7" }, + { 0xc60, "Cortex-M0+" }, + { 0xd01, "Cortex-A32" }, + { 0xd03, "Cortex-A53" }, + { 0xd04, "Cortex-A35" }, + { 0xd05, "Cortex-A55" }, + { 0xd06, "Cortex-A65" }, + { 0xd07, "Cortex-A57" }, + { 0xd08, "Cortex-A72" }, + { 0xd09, "Cortex-A73" }, + { 0xd0a, "Cortex-A75" }, + { 0xd0b, "Cortex-A76" }, + { 0xd0c, "Neoverse-N1" }, + { 0xd0d, "Cortex-A77" }, + { 0xd0e, "Cortex-A76AE" }, + { 0xd13, "Cortex-R52" }, + { 0xd20, "Cortex-M23" }, + { 0xd21, "Cortex-M33" }, + { 0xd41, "Cortex-A78" }, + { 0xd42, "Cortex-A78AE" }, + { 0xd4a, "Neoverse-E1" }, + { 0xd4b, "Cortex-A78C" }, + }; + + if (strncmp(buf, part_marker, sizeof(part_marker) - 1) == 0) { + model = buf + sizeof(part_marker) - 1; + + errno = 0; + model_id = strtol(model, NULL, 16); + if ((errno != 0) || model_id < 0) { + fclose(fp); + return UV_EINVAL; + } + + for (part_idx = 0; part_idx < ARRAY_SIZE(arm_chips); part_idx++) { + if (model_id == arm_chips[part_idx].id) { + model = uv__strdup(arm_chips[part_idx].name); + if (model == NULL) { + fclose(fp); + return UV_ENOMEM; + } + ci[model_idx++].model = model; + break; + } + } + } #else /* defined(__mips__) */ static const char model_marker[] = "cpu model\t\t: "; #endif @@ -421,18 +512,18 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { continue; } } -#else /* !__arm__ && !__mips__ */ +#else /* !__arm__ && !__mips__ && !__aarch64__ */ if (speed_idx < numcpus) { if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) { ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1); continue; } } -#endif /* __arm__ || __mips__ */ +#endif /* __arm__ || __mips__ || __aarch64__ */ } fclose(fp); -#endif /* __arm__ || __i386__ || __mips__ || __PPC__ || __x86_64__ */ +#endif /* __arm__ || __i386__ || __mips__ || __PPC__ || __x86_64__ || __aarch__ */ /* Now we want to make sure that all the models contain *something* because * it's not safe to leave them as null. Copy the last entry unless there From 0f696da5f0328dde1f9cc0372692ce22f0d17100 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 9 Nov 2021 22:17:50 +0100 Subject: [PATCH 080/713] linux: work around CIFS EPERM bug (#3354) It's been reported that copy_file_range() on a CIFS mount fails with an EPERM error, even though the source and target files have the appropriate permissions. This is probably a variation on the EPERM error that libuv handles when it tries to fchmod() a file on a CIFS mount that hasn't been mounted with the "noperm" option, so let's handle it here too. This commit applies minor refactoring because the "work around file system bugs" section got quite unwieldy. I also snuck in a bug fix where the workaround for buggy CephFS mounts disabled copy_file_range() permanently. Fixes: https://github.com/libuv/libuv/issues/3322 --- src/unix/fs.c | 119 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 40 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index eb17fb4a23e..362c36c6a0c 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -946,6 +946,71 @@ static int uv__is_buggy_cephfs(int fd) { return uv__kernel_version() < /* 4.20.0 */ 0x041400; } + + +static int uv__is_cifs_or_smb(int fd) { + struct statfs s; + + if (-1 == fstatfs(fd, &s)) + return 0; + + switch ((unsigned) s.f_type) { + case 0x0000517Bu: /* SMB */ + case 0xFE534D42u: /* SMB2 */ + case 0xFF534D42u: /* CIFS */ + return 1; + } + + return 0; +} + + +static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off, + int out_fd, size_t len) { + static int no_copy_file_range_support; + ssize_t r; + + if (uv__load_relaxed(&no_copy_file_range_support)) { + errno = ENOSYS; + return -1; + } + + r = uv__fs_copy_file_range(in_fd, off, out_fd, NULL, len, 0); + + if (r != -1) + return r; + + switch (errno) { + case EACCES: + /* Pre-4.20 kernels have a bug where CephFS uses the RADOS + * copy-from command when it shouldn't. + */ + if (uv__is_buggy_cephfs(in_fd)) + errno = ENOSYS; /* Use fallback. */ + break; + case ENOSYS: + uv__store_relaxed(&no_copy_file_range_support, 1); + break; + case EPERM: + /* It's been reported that CIFS spuriously fails. + * Consider it a transient error. + */ + if (uv__is_cifs_or_smb(out_fd)) + errno = ENOSYS; /* Use fallback. */ + break; + case ENOTSUP: + case EXDEV: + /* ENOTSUP - it could work on another file system type. + * EXDEV - it will not work when in_fd and out_fd are not on the same + * mounted filesystem (pre Linux 5.3) + */ + errno = ENOSYS; /* Use fallback. */ + break; + } + + return -1; +} + #endif /* __linux__ */ @@ -960,40 +1025,21 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { { off_t off; ssize_t r; + size_t len; + int try_sendfile; off = req->off; + len = req->bufsml[0].len; + try_sendfile = 1; #ifdef __linux__ - { - static int no_copy_file_range_support; - - if (uv__load_relaxed(&no_copy_file_range_support) == 0) { - r = uv__fs_copy_file_range(in_fd, &off, out_fd, NULL, req->bufsml[0].len, 0); - - if (r == -1 && errno == ENOSYS) { - /* ENOSYS - it will never work */ - errno = 0; - uv__store_relaxed(&no_copy_file_range_support, 1); - } else if (r == -1 && errno == EACCES && uv__is_buggy_cephfs(in_fd)) { - /* EACCES - pre-4.20 kernels have a bug where CephFS uses the RADOS - copy-from command when it shouldn't */ - errno = 0; - uv__store_relaxed(&no_copy_file_range_support, 1); - } else if (r == -1 && (errno == ENOTSUP || errno == EXDEV)) { - /* ENOTSUP - it could work on another file system type */ - /* EXDEV - it will not work when in_fd and out_fd are not on the same - mounted filesystem (pre Linux 5.3) */ - errno = 0; - } else { - goto ok; - } - } - } + r = uv__fs_try_copy_file_range(in_fd, &off, out_fd, len); + try_sendfile = (r == -1 && errno == ENOSYS); #endif - r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len); + if (try_sendfile) + r = sendfile(out_fd, in_fd, &off, len); -ok: /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but * it still writes out data. Fortunately, we can detect it by checking if * the offset has been updated. @@ -1277,22 +1323,15 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { if (fchmod(dstfd, src_statsbuf.st_mode) == -1) { err = UV__ERR(errno); #ifdef __linux__ + /* fchmod() on CIFS shares always fails with EPERM unless the share is + * mounted with "noperm". As fchmod() is a meaningless operation on such + * shares anyway, detect that condition and squelch the error. + */ if (err != UV_EPERM) goto out; - { - struct statfs s; - - /* fchmod() on CIFS shares always fails with EPERM unless the share is - * mounted with "noperm". As fchmod() is a meaningless operation on such - * shares anyway, detect that condition and squelch the error. - */ - if (fstatfs(dstfd, &s) == -1) - goto out; - - if ((unsigned) s.f_type != /* CIFS */ 0xFF534D42u) - goto out; - } + if (!uv__is_cifs_or_smb(dstfd)) + goto out; err = 0; #else /* !__linux__ */ From 96b26b1ee291f96d6d5540966118b3599f8375b4 Mon Sep 17 00:00:00 2001 From: Stacey Marshall Date: Thu, 18 Nov 2021 10:01:47 +0000 Subject: [PATCH 081/713] sunos: Oracle Developer Studio support (#3364) Oracle Solaris linker visibility support. Option "-fvisibility=hidden" requires public functions to be defined as "__global". fs_utime_round test failed as timespec.tv_nsec conversion to double resulted in negative number. Skipped this test. Note that it was necessary to compile with C99 language features. --- include/uv.h | 2 ++ test/test-fs.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/uv.h b/include/uv.h index 77503bde9f2..61a2c546ece 100644 --- a/include/uv.h +++ b/include/uv.h @@ -43,6 +43,8 @@ extern "C" { /* Building static library. */ # define UV_EXTERN /* nothing */ # endif +#elif defined(__sun) +# define UV_EXTERN __global #elif __GNUC__ >= 4 # define UV_EXTERN __attribute__((visibility("default"))) #else diff --git a/test/test-fs.c b/test/test-fs.c index f2336e1eb19..5478a290e34 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -844,7 +844,7 @@ static void check_utime(const char* path, } else { double st_atim; double st_mtim; -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(__sun) /* TODO(vtjnash): would it be better to normalize this? */ ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); From 69b811f340f43ba5343eddbe167dd4882e136fe6 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Fri, 19 Nov 2021 17:12:04 -0500 Subject: [PATCH 082/713] Revert "sunos: Oracle Developer Studio support (#3364)" This reverts commit 96b26b1ee291f96d6d5540966118b3599f8375b4. The commit was reported to break libuv on Illumos systems. --- include/uv.h | 2 -- test/test-fs.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/uv.h b/include/uv.h index 61a2c546ece..77503bde9f2 100644 --- a/include/uv.h +++ b/include/uv.h @@ -43,8 +43,6 @@ extern "C" { /* Building static library. */ # define UV_EXTERN /* nothing */ # endif -#elif defined(__sun) -# define UV_EXTERN __global #elif __GNUC__ >= 4 # define UV_EXTERN __attribute__((visibility("default"))) #else diff --git a/test/test-fs.c b/test/test-fs.c index 5478a290e34..f2336e1eb19 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -844,7 +844,7 @@ static void check_utime(const char* path, } else { double st_atim; double st_mtim; -#if !defined(__APPLE__) && !defined(__sun) +#ifndef __APPLE__ /* TODO(vtjnash): would it be better to normalize this? */ ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); From e592ebe9d31088add987025df1271d2bf7daa957 Mon Sep 17 00:00:00 2001 From: Stacey Marshall Date: Wed, 24 Nov 2021 15:10:13 +0000 Subject: [PATCH 083/713] sunos: Oracle Developer Studio support (#3374) Oracle Developer Studio requires public functions to be defined as "__global" when "-fvisibility=hidden" used as added by [#3005](https://github.com/libuv/libuv/pull/3005). For documentation on `__global` see Reducing Symbol Scope in Oracle Developer Studio C/C++ guide https://www.oracle.com/solaris/technologies/symbol-scope.html. fs_utime_round test failed as timespec.tv_nsec conversion to double resulted in negative number. Skip this test for __SPRO_C builds. Note that it was necessary to have C99 language features enabled with Studio compiler (-xc99=all) as version v1.41.0 has other commits that have used C99 features. Tested with: - cc: Studio 12.6 Sun C 5.15 SunOS_sparc 152881-05 2019/10/30 - gcc (GCC) 11.2.0 Refs: https://github.com/libuv/libuv/pull/3364 --- include/uv.h | 2 ++ test/test-fs.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/uv.h b/include/uv.h index 77503bde9f2..79acd834cb3 100644 --- a/include/uv.h +++ b/include/uv.h @@ -45,6 +45,8 @@ extern "C" { # endif #elif __GNUC__ >= 4 # define UV_EXTERN __attribute__((visibility("default"))) +#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) /* Sun Studio >= 8 */ +# define UV_EXTERN __global #else # define UV_EXTERN /* nothing */ #endif diff --git a/test/test-fs.c b/test/test-fs.c index f2336e1eb19..aecf10f9e28 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -844,7 +844,7 @@ static void check_utime(const char* path, } else { double st_atim; double st_mtim; -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(__SUNPRO_C) /* TODO(vtjnash): would it be better to normalize this? */ ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); From b2614a10a579ae6e9936eb483fe5ce14aa65a212 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 24 Nov 2021 19:25:47 -0500 Subject: [PATCH 084/713] stream: permit read after seeing EOF (#3361) On some streams (notably TTYs), it is permitted to continue reading after getting EOF. So still stop reading on EOF, but allow the user to reset the stream and try to read again (which may just get EOF). This relaxes the constraint added in ce15b8405e9d01e221f8390475deab4a40d26e38. Refs: https://github.com/libuv/libuv/pull/3006 --- CMakeLists.txt | 2 +- Makefile.am | 2 +- src/unix/stream.c | 10 +--- src/win/pipe.c | 1 - src/win/tcp.c | 3 +- test/test-list.h | 6 +- ...adable-on-eof.c => test-readable-on-eof.c} | 60 +++++++++++-------- 7 files changed, 43 insertions(+), 41 deletions(-) rename test/{test-not-readable-on-eof.c => test-readable-on-eof.c} (68%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 337b09c2694..1d033f8297e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -502,7 +502,6 @@ if(LIBUV_BUILD_TESTS) test/test-multiple-listen.c test/test-mutexes.c test/test-not-readable-nor-writable-on-read-error.c - test/test-not-readable-on-eof.c test/test-not-writable-after-shutdown.c test/test-osx-select.c test/test-pass-always.c @@ -530,6 +529,7 @@ if(LIBUV_BUILD_TESTS) test/test-process-title.c test/test-queue-foreach-delete.c test/test-random.c + test/test-readable-on-eof.c test/test-ref.c test/test-run-nowait.c test/test-run-once.c diff --git a/Makefile.am b/Makefile.am index cb3b42c27b7..3a2fba6df86 100644 --- a/Makefile.am +++ b/Makefile.am @@ -206,7 +206,6 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-multiple-listen.c \ test/test-mutexes.c \ test/test-not-readable-nor-writable-on-read-error.c \ - test/test-not-readable-on-eof.c \ test/test-not-writable-after-shutdown.c \ test/test-osx-select.c \ test/test-pass-always.c \ @@ -234,6 +233,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-process-title-threadsafe.c \ test/test-queue-foreach-delete.c \ test/test-random.c \ + test/test-readable-on-eof.c \ test/test-ref.c \ test/test-run-nowait.c \ test/test-run-once.c \ diff --git a/src/unix/stream.c b/src/unix/stream.c index bc64fe8f44b..5858258d286 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1010,7 +1010,6 @@ uv_handle_type uv__handle_type(int fd) { static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { stream->flags |= UV_HANDLE_READ_EOF; stream->flags &= ~UV_HANDLE_READING; - stream->flags &= ~UV_HANDLE_READABLE; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); @@ -1550,15 +1549,12 @@ int uv__read_start(uv_stream_t* stream, assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY); - /* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just - * expresses the desired state of the user. - */ + /* The UV_HANDLE_READING flag is irrelevant of the state of the stream - it + * just expresses the desired state of the user. */ stream->flags |= UV_HANDLE_READING; + stream->flags &= ~UV_HANDLE_READ_EOF; /* TODO: try to do the read inline? */ - /* TODO: keep track of tcp state. If we've gotten a EOF then we should - * not start the IO watcher. - */ assert(uv__stream_fd(stream) >= 0); assert(alloc_cb); diff --git a/src/win/pipe.c b/src/win/pipe.c index 912aed9b620..984b766bb43 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1796,7 +1796,6 @@ static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, * it. */ eof_timer_destroy(handle); - handle->flags &= ~UV_HANDLE_READABLE; uv_read_stop((uv_stream_t*) handle); handle->read_cb((uv_stream_t*) handle, UV_EOF, &buf); diff --git a/src/win/tcp.c b/src/win/tcp.c index cf2dbd85fdb..be4133a8478 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -1044,7 +1044,6 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(loop, handle); } - handle->flags &= ~UV_HANDLE_READABLE; buf.base = 0; buf.len = 0; @@ -1081,7 +1080,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, } } else { /* Connection closed */ - handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE); + handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(loop, handle); handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf); diff --git a/test/test-list.h b/test/test-list.h index 69a63ac5bdb..3141a7cbfe8 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -509,7 +509,7 @@ TEST_DECLARE (getters_setters) TEST_DECLARE (not_writable_after_shutdown) TEST_DECLARE (not_readable_nor_writable_on_read_error) -TEST_DECLARE (not_readable_on_eof) +TEST_DECLARE (readable_on_eof) #ifndef _WIN32 TEST_DECLARE (fork_timer) @@ -1145,8 +1145,8 @@ TASK_LIST_START TEST_HELPER (not_writable_after_shutdown, tcp4_echo_server) TEST_ENTRY (not_readable_nor_writable_on_read_error) TEST_HELPER (not_readable_nor_writable_on_read_error, tcp4_echo_server) - TEST_ENTRY (not_readable_on_eof) - TEST_HELPER (not_readable_on_eof, tcp4_echo_server) + TEST_ENTRY (readable_on_eof) + TEST_HELPER (readable_on_eof, tcp4_echo_server) TEST_ENTRY (metrics_idle_time) TEST_ENTRY (metrics_idle_time_thread) diff --git a/test/test-not-readable-on-eof.c b/test/test-readable-on-eof.c similarity index 68% rename from test/test-not-readable-on-eof.c rename to test/test-readable-on-eof.c index 2bb5f4eeccc..68e84542477 100644 --- a/test/test-not-readable-on-eof.c +++ b/test/test-readable-on-eof.c @@ -35,7 +35,7 @@ static int close_cb_called; static void write_cb(uv_write_t* req, int status) { write_cb_called++; - ASSERT(status == 0); + ASSERT_EQ(status, 0); } static void alloc_cb(uv_handle_t* handle, @@ -51,12 +51,20 @@ static void close_cb(uv_handle_t* handle) { } static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { - read_cb_called++; - - ASSERT(nread == UV_EOF); - ASSERT(0 == uv_is_readable(handle)); + int r; - uv_close((uv_handle_t*) handle, close_cb); + ASSERT_EQ(nread, UV_EOF); + ASSERT_EQ(uv_is_readable(handle), 1); + ASSERT_EQ(uv_is_writable(handle), 1); + + if (++read_cb_called == 3) { + uv_close((uv_handle_t*) handle, close_cb); + ASSERT_EQ(uv_is_readable(handle), 0); + ASSERT_EQ(uv_is_writable(handle), 0); + } else { + r = uv_read_start((uv_stream_t*) &tcp_client, alloc_cb, read_cb); + ASSERT_EQ(r, 0); + } } static void connect_cb(uv_connect_t* req, int status) { @@ -64,10 +72,9 @@ static void connect_cb(uv_connect_t* req, int status) { uv_buf_t close_me; connect_cb_called++; - ASSERT(status == 0); + ASSERT_EQ(status, 0); - r = uv_read_start((uv_stream_t*) &tcp_client, alloc_cb, read_cb); - ASSERT(r == 0); + read_cb((uv_stream_t*) &tcp_client, UV_EOF, NULL); close_me = uv_buf_init(close_me_cmd, sizeof(close_me_cmd)); @@ -77,26 +84,27 @@ static void connect_cb(uv_connect_t* req, int status) { 1, write_cb); - ASSERT(r == 0); + ASSERT_EQ(r, 0); } -TEST_IMPL(not_readable_on_eof) { +TEST_IMPL(readable_on_eof) { struct sockaddr_in sa; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &sa)); - ASSERT(0 == uv_loop_init(&loop)); - ASSERT(0 == uv_tcp_init(&loop, &tcp_client)); - - ASSERT(0 == uv_tcp_connect(&connect_req, - &tcp_client, - (const struct sockaddr*) &sa, - connect_cb)); - - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); - - ASSERT(connect_cb_called == 1); - ASSERT(read_cb_called == 1); - ASSERT(write_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(uv_ip4_addr("127.0.0.1", TEST_PORT, &sa), 0); + ASSERT_EQ(uv_loop_init(&loop), 0); + ASSERT_EQ(uv_tcp_init(&loop, &tcp_client), 0); + + ASSERT_EQ(uv_tcp_connect(&connect_req, + &tcp_client, + (const struct sockaddr*) &sa, + connect_cb), + 0); + + ASSERT_EQ(uv_run(&loop, UV_RUN_DEFAULT), 0); + + ASSERT_EQ(connect_cb_called, 1); + ASSERT_EQ(read_cb_called, 3); + ASSERT_EQ(write_cb_called, 1); + ASSERT_EQ(close_cb_called, 1); MAKE_VALGRIND_HAPPY(); return 0; From 40bf9a89eb1a66dfa4ab9f97ec418e2e6878dc67 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 24 Nov 2021 19:34:57 -0500 Subject: [PATCH 085/713] thread: initialize uv_thread_self for all threads (#3357) In particular, previously the main thread would have an id of NULL, which was then not valid to use with any other API that expected a uv_thread_t handle. --- src/win/thread.c | 15 +++++++++++++-- test/test-thread-equal.c | 6 ++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/win/thread.c b/src/win/thread.c index 89c53ada755..3615101b44d 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -103,7 +103,7 @@ static UINT __stdcall uv__thread_start(void* arg) { uv__free(ctx_p); uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key); - uv_key_set(&uv__current_thread_key, (void*) ctx.self); + uv_key_set(&uv__current_thread_key, ctx.self); ctx.entry(ctx.arg); @@ -183,7 +183,18 @@ int uv_thread_create_ex(uv_thread_t* tid, uv_thread_t uv_thread_self(void) { uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key); - return (uv_thread_t) uv_key_get(&uv__current_thread_key); + uv_thread_t key = uv_key_get(&uv__current_thread_key); + if (key == NULL) { + /* If the thread wasn't started by uv_thread_create (such as the main + * thread), we assign an id to it now. */ + if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &key, 0, + FALSE, DUPLICATE_SAME_ACCESS)) { + uv_fatal_error(GetLastError(), "DuplicateHandle"); + } + uv_key_set(&uv__current_thread_key, key); + } + return key; } diff --git a/test/test-thread-equal.c b/test/test-thread-equal.c index 27c07ee2c7d..f7bde71b3d9 100644 --- a/test/test-thread-equal.c +++ b/test/test-thread-equal.c @@ -28,6 +28,9 @@ uv_thread_t subthreads[2]; static void check_thread(void* arg) { uv_thread_t *thread_id = arg; uv_thread_t self_id = uv_thread_self(); +#ifdef _WIN32 + ASSERT_NOT_NULL(self_id); +#endif ASSERT(uv_thread_equal(&main_thread_id, &self_id) == 0); *thread_id = uv_thread_self(); } @@ -35,6 +38,9 @@ static void check_thread(void* arg) { TEST_IMPL(thread_equal) { uv_thread_t threads[2]; main_thread_id = uv_thread_self(); +#ifdef _WIN32 + ASSERT_NOT_NULL(main_thread_id); +#endif ASSERT(0 != uv_thread_equal(&main_thread_id, &main_thread_id)); ASSERT(0 == uv_thread_create(threads + 0, check_thread, subthreads + 0)); ASSERT(0 == uv_thread_create(threads + 1, check_thread, subthreads + 1)); From abfc4f0b15e3543425106a4b0bccd00a46ba5446 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 24 Nov 2021 19:37:02 -0500 Subject: [PATCH 086/713] kqueue: ignore write-end closed notifications (#3277) The combination EVFILT_WRITE+EV_EOF is valid and indicates that the reader has disconnected (called `shutdown(SHUT_RD)`). Probably very rare in practice, but this seems more correct. Issue noticed (for UV_DISCONNECT clients of uv_poll), while doing research for https://github.com/libuv/libuv/pull/3250. --- src/unix/kqueue.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index bf183d5fdc0..75e9110709d 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -326,6 +326,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (errno != ENOENT) abort(); } + if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) + revents |= UV__POLLRDHUP; } if (ev->filter == EV_OOBAND) { @@ -359,9 +361,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (ev->flags & EV_ERROR) revents |= POLLERR; - if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) - revents |= UV__POLLRDHUP; - if (revents == 0) continue; From 1e7074913e1d2a1be72b62ba807325c14b0b317a Mon Sep 17 00:00:00 2001 From: Jesper Storm Bache Date: Wed, 24 Nov 2021 16:50:52 -0800 Subject: [PATCH 087/713] macos: fix the cfdata length in uv__get_cpu_speed (#3356) We observed crashes inside CFRelease in uv__get_cpu_speed on the new Mac Book Pro (arm) hardware. The problem is that the stack got clobbered. On the new mac hardware the returned length is 8. For the 4 byte case, a temp variable is used to avoid having to add endian-sensitive offsets. Fixes: https://github.com/libuv/libuv/issues/3355 --- src/unix/darwin.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/unix/darwin.c b/src/unix/darwin.c index a7be0dd2f3c..62f04d31542 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -280,14 +280,18 @@ static int uv__get_cpu_speed(uint64_t* speed) { NULL, 0); if (freq_ref) { - uint32_t freq; + const UInt8* freq_ref_ptr = pCFDataGetBytePtr(freq_ref); CFIndex len = pCFDataGetLength(freq_ref); - CFRange range; - range.location = 0; - range.length = len; + if (len == 8) + memcpy(speed, freq_ref_ptr, 8); + else if (len == 4) { + uint32_t v; + memcpy(&v, freq_ref_ptr, 4); + *speed = v; + } else { + *speed = 0; + } - pCFDataGetBytes(freq_ref, range, (UInt8*)&freq); - *speed = freq; pCFRelease(freq_ref); pCFRelease(data); break; From c7843ecfbc935823ed8c46af77d64e9c1f285c54 Mon Sep 17 00:00:00 2001 From: Campbell He Date: Thu, 25 Nov 2021 17:05:15 +0800 Subject: [PATCH 088/713] unix,win: add uv_ip_name to get name from sockaddr (#3368) uv_ip_name is a kind of wrapper of uv_ip4_name and uv_ip6_name which can be used after getaddrinfo to get the IP name directly from addrinfo.ai_addr. --- CMakeLists.txt | 1 + Makefile.am | 1 + docs/src/misc.rst | 4 +++ include/uv.h | 1 + src/uv-common.c | 14 ++++++++++ test/test-ip-name.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 7 files changed, 88 insertions(+) create mode 100644 test/test-ip-name.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d033f8297e..96900b2a7ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -489,6 +489,7 @@ if(LIBUV_BUILD_TESTS) test/test-idna.c test/test-ip4-addr.c test/test-ip6-addr.c + test/test-ip-name.c test/test-ipc-heavy-traffic-deadlock-bug.c test/test-ipc-send-recv.c test/test-ipc.c diff --git a/Makefile.am b/Makefile.am index 3a2fba6df86..4184a0a372f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -192,6 +192,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-idna.c \ test/test-ip4-addr.c \ test/test-ip6-addr.c \ + test/test-ip-name.c \ test/test-ipc-heavy-traffic-deadlock-bug.c \ test/test-ipc-send-recv.c \ test/test-ipc.c \ diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 2fe6c1ce85d..8017e8e1596 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -377,6 +377,10 @@ API Convert a binary structure containing an IPv6 address to a string. +.. c:function:: int uv_ip_name(const struct sockaddr *src, char *dst, size_t size) + + Convert a binary structure containing an IPv4 address or an IPv6 address to a string. + .. c:function:: int uv_inet_ntop(int af, const void* src, char* dst, size_t size) .. c:function:: int uv_inet_pton(int af, const char* src, void* dst) diff --git a/include/uv.h b/include/uv.h index 79acd834cb3..606083c87de 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1660,6 +1660,7 @@ UV_EXTERN int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr); UV_EXTERN int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size); UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size); +UV_EXTERN int uv_ip_name(const struct sockaddr* src, char* dst, size_t size); UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size); UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst); diff --git a/src/uv-common.c b/src/uv-common.c index e81ed79b0c5..b0d5822ebb7 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -274,6 +274,20 @@ int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) { } +int uv_ip_name(const struct sockaddr *src, char *dst, size_t size) { + switch (src->sa_family) { + case AF_INET: + return uv_inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr, + dst, size); + case AF_INET6: + return uv_inet_ntop(AF_INET6, &((struct sockaddr_in6 *)src)->sin6_addr, + dst, size); + default: + return UV_EAFNOSUPPORT; + } +} + + int uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr, unsigned int flags) { diff --git a/test/test-ip-name.c b/test/test-ip-name.c new file mode 100644 index 00000000000..1cb1b605834 --- /dev/null +++ b/test/test-ip-name.c @@ -0,0 +1,65 @@ +/* Copyright The libuv project and contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +union TestAddr { + struct sockaddr addr; + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; +}; + + +TEST_IMPL(ip_name) { + char dst[INET6_ADDRSTRLEN]; + union TestAddr test_addr; + struct sockaddr* addr = &test_addr.addr; + struct sockaddr_in* addr4 = &test_addr.addr4; + struct sockaddr_in6* addr6 = &test_addr.addr6; + + /* test ip4_name */ + ASSERT_EQ(0, uv_ip4_addr("192.168.0.1", TEST_PORT, addr4)); + ASSERT_EQ(0, uv_ip4_name(addr4, dst, INET_ADDRSTRLEN)); + ASSERT_EQ(0, strcmp("192.168.0.1", dst)); + + ASSERT_EQ(0, uv_ip_name(addr, dst, INET_ADDRSTRLEN)); + ASSERT_EQ(0, strcmp("192.168.0.1", dst)); + + /* test ip6_name */ + ASSERT_EQ(0, uv_ip6_addr("fe80::2acf:daff:fedd:342a", TEST_PORT, addr6)); + ASSERT_EQ(0, uv_ip6_name(addr6, dst, INET6_ADDRSTRLEN)); + ASSERT_EQ(0, strcmp("fe80::2acf:daff:fedd:342a", dst)); + + ASSERT_EQ(0, uv_ip_name(addr, dst, INET6_ADDRSTRLEN)); + ASSERT_EQ(0, strcmp("fe80::2acf:daff:fedd:342a", dst)); + + /* test other sa_family */ + addr->sa_family = AF_UNIX; + /* size is not a concern here */ + ASSERT_EQ(UV_EAFNOSUPPORT, uv_ip_name(addr, dst, INET6_ADDRSTRLEN)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 3141a7cbfe8..e0b247f4863 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -460,6 +460,7 @@ TEST_DECLARE (poll_multiple_handles) TEST_DECLARE (ip4_addr) TEST_DECLARE (ip6_addr_link_local) +TEST_DECLARE (ip_name) TEST_DECLARE (poll_close_doesnt_corrupt_stack) TEST_DECLARE (poll_closesocket) @@ -1106,6 +1107,7 @@ TASK_LIST_START TEST_ENTRY (dlerror) TEST_ENTRY (ip4_addr) TEST_ENTRY (ip6_addr_link_local) + TEST_ENTRY (ip_name) TEST_ENTRY (queue_foreach_delete) From 4075298df20de81f0ee0541b9386904c412fa05f Mon Sep 17 00:00:00 2001 From: AJ Heller Date: Tue, 30 Nov 2021 20:22:31 -0800 Subject: [PATCH 089/713] win,test: fix a few typos PR-URL: https://github.com/libuv/libuv/pull/3375 --- src/win/tcp.c | 2 +- test/test-tcp-connect-timeout.c | 2 +- test/test-udp-connect.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/win/tcp.c b/src/win/tcp.c index be4133a8478..6ca11e070bf 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -1650,7 +1650,7 @@ int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int f err = WSAGetLastError(); if (err == ERROR_IO_PENDING) { /* Result should complete immediately, since we already called connect, - * but emperically, we sometimes have to poll the kernel a couple times + * but empirically, we sometimes have to poll the kernel a couple times * until it notices that. */ while (!WSAGetOverlappedResult(client1, &overlap, &bytes, FALSE, &flags)) { err = WSAGetLastError(); diff --git a/test/test-tcp-connect-timeout.c b/test/test-tcp-connect-timeout.c index 3c34e54ae7f..0f968157127 100644 --- a/test/test-tcp-connect-timeout.c +++ b/test/test-tcp-connect-timeout.c @@ -111,7 +111,7 @@ static int is_supported_system(void) { if (cnt != 3) { return 0; } - /* relase >= 10.0.16299 */ + /* release >= 10.0.16299 */ for (cnt = 0; cnt < 3; ++cnt) { if (semver[cnt] > min_semver[cnt]) return 1; diff --git a/test/test-udp-connect.c b/test/test-udp-connect.c index 89ca1a84fcd..cd159b68da4 100644 --- a/test/test-udp-connect.c +++ b/test/test-udp-connect.c @@ -124,7 +124,7 @@ TEST_IMPL(udp_connect) { buf = uv_buf_init("EXIT", 4); - /* connect() to INADDR_ANY fails on Windows wih WSAEADDRNOTAVAIL */ + /* connect() to INADDR_ANY fails on Windows with WSAEADDRNOTAVAIL */ ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &tmp_addr)); r = uv_udp_connect(&client, (const struct sockaddr*) &tmp_addr); #ifdef _WIN32 From 0a47e4c7714c9d1cf62efef3efafd3fc3ad354c2 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Fri, 3 Dec 2021 04:04:44 -0500 Subject: [PATCH 090/713] zos: use destructor for uv__threadpool_cleanup() (#3376) On z/OS, instead of calling the uv__threadpool_cleanup() function from inside uv_library_shutdown(), the destructor attribute must be used; otherwise, tests will fail with exit code 1 and no output. Additionally, post() does not need to be called when the destructor attribute is used. Also adds uv__os390_cleanup() function to clean System V message queue on z/OS. Co-authored-by: Igor Todorovski Co-authored-by: Gaby Baghdadi --- src/threadpool.c | 7 +++++++ src/unix/os390-syscalls.c | 5 +++++ src/unix/os390-syscalls.h | 1 + src/uv-common.c | 5 +++++ 4 files changed, 18 insertions(+) diff --git a/src/threadpool.c b/src/threadpool.c index 869ae95f58c..e804c7c4b6f 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -160,13 +160,20 @@ static void post(QUEUE* q, enum uv__work_kind kind) { } +#ifdef __MVS__ +/* TODO(itodorov) - zos: revisit when Woz compiler is available. */ +__attribute__((destructor)) +#endif void uv__threadpool_cleanup(void) { unsigned int i; if (nthreads == 0) return; +#ifndef __MVS__ + /* TODO(gabylb) - zos: revisit when Woz compiler is available. */ post(&exit_message, UV__WORK_CPU); +#endif for (i = 0; i < nthreads; i++) if (uv_thread_join(threads + i)) diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c index c19155339c3..a74112701a4 100644 --- a/src/unix/os390-syscalls.c +++ b/src/unix/os390-syscalls.c @@ -136,6 +136,11 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) { } +void uv__os390_cleanup(void) { + msgctl(uv_backend_fd(uv_default_loop()), IPC_RMID, NULL); +} + + static void init_message_queue(uv__os390_epoll* lst) { struct { long int header; diff --git a/src/unix/os390-syscalls.h b/src/unix/os390-syscalls.h index 7d59b75e470..9f504171d85 100644 --- a/src/unix/os390-syscalls.h +++ b/src/unix/os390-syscalls.h @@ -70,5 +70,6 @@ int sem_destroy(UV_PLATFORM_SEM_T* semid); int sem_post(UV_PLATFORM_SEM_T* semid); int sem_trywait(UV_PLATFORM_SEM_T* semid); int sem_wait(UV_PLATFORM_SEM_T* semid); +void uv__os390_cleanup(void); #endif /* UV_OS390_SYSCALL_H_ */ diff --git a/src/uv-common.c b/src/uv-common.c index b0d5822ebb7..f43dd3dee7e 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -901,7 +901,12 @@ void uv_library_shutdown(void) { uv__process_title_cleanup(); uv__signal_cleanup(); +#ifdef __MVS__ + /* TODO(itodorov) - zos: revisit when Woz compiler is available. */ + uv__os390_cleanup(); +#else uv__threadpool_cleanup(); +#endif uv__store_relaxed(&was_shutdown, 1); } From beb64b0a88f92b51f877ee11da660a7a8c7a0b00 Mon Sep 17 00:00:00 2001 From: Andrey Hohutkin Date: Mon, 3 Jan 2022 12:24:19 +0200 Subject: [PATCH 091/713] linux: use MemAvailable instead of MemFree (#3351) Fixes: https://github.com/nodejs/node/issues/23892 --- src/unix/linux-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 8c9bbb75f70..413d0dd3f09 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -788,7 +788,7 @@ uint64_t uv_get_free_memory(void) { struct sysinfo info; uint64_t rc; - rc = uv__read_proc_meminfo("MemFree:"); + rc = uv__read_proc_meminfo("MemAvailable:"); if (rc != 0) return rc; From 64742416e0de05fe3ba4588c2b395da97d13c0ef Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 3 Jan 2022 05:25:45 -0500 Subject: [PATCH 092/713] freebsd: call dlerror() only if necessary (#3388) Similar to the dlopen() codepath. Refs: https://github.com/JuliaLang/julia/pull/40392 Refs: https://github.com/JuliaLang/julia/issues/39582 --- src/unix/dl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/dl.c b/src/unix/dl.c index fc1c052bb81..80b3333ae28 100644 --- a/src/unix/dl.c +++ b/src/unix/dl.c @@ -53,7 +53,7 @@ void uv_dlclose(uv_lib_t* lib) { int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { dlerror(); /* Reset error status. */ *ptr = dlsym(lib->handle, name); - return uv__dlerror(lib); + return *ptr ? 0 : uv__dlerror(lib); } From a865f781249de7f2769f1a190b4fc9493c5fc74f Mon Sep 17 00:00:00 2001 From: deal Date: Mon, 3 Jan 2022 18:31:29 +0800 Subject: [PATCH 093/713] bsd,windows,zos: fix udp disconnect EINVAL (#3350) Fixes: https://github.com/libuv/libuv/issues/3344 --- CMakeLists.txt | 1 + Makefile.am | 1 + src/unix/udp.c | 55 +++++++++-- src/win/udp.c | 2 +- test/test-list.h | 2 + test/test-udp-connect6.c | 200 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 254 insertions(+), 7 deletions(-) create mode 100644 test/test-udp-connect6.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 96900b2a7ec..b41e5462dd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -587,6 +587,7 @@ if(LIBUV_BUILD_TESTS) test/test-udp-alloc-cb-fail.c test/test-udp-bind.c test/test-udp-connect.c + test/test-udp-connect6.c test/test-udp-create-socket-early.c test/test-udp-dgram-too-big.c test/test-udp-ipv6.c diff --git a/Makefile.am b/Makefile.am index 4184a0a372f..e91cfb8f03e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -291,6 +291,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-udp-alloc-cb-fail.c \ test/test-udp-bind.c \ test/test-udp-connect.c \ + test/test-udp-connect6.c \ test/test-udp-create-socket-early.c \ test/test-udp-dgram-too-big.c \ test/test-udp-ipv6.c \ diff --git a/src/unix/udp.c b/src/unix/udp.c index 71bfbf7f795..aee8d639344 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -654,28 +654,71 @@ int uv__udp_connect(uv_udp_t* handle, return 0; } - +/* From https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html + * Any of uv supported UNIXs kernel should be standardized, but the kernel + * implementation logic not same, let's use pseudocode to explain the udp + * disconnect behaviors: + * + * Predefined stubs for pseudocode: + * 1. sodisconnect: The function to perform the real udp disconnect + * 2. pru_connect: The function to perform the real udp connect + * 3. so: The kernel object match with socket fd + * 4. addr: The sockaddr parameter from user space + * + * BSDs: + * if(sodisconnect(so) == 0) { // udp disconnect succeed + * if (addr->sa_len != so->addr->sa_len) return EINVAL; + * if (addr->sa_family != so->addr->sa_family) return EAFNOSUPPORT; + * pru_connect(so); + * } + * else return EISCONN; + * + * z/OS (same with Windows): + * if(addr->sa_len < so->addr->sa_len) return EINVAL; + * if (addr->sa_family == AF_UNSPEC) sodisconnect(so); + * + * AIX: + * if(addr->sa_len != sizeof(struct sockaddr)) return EINVAL; // ignore ip proto version + * if (addr->sa_family == AF_UNSPEC) sodisconnect(so); + * + * Linux,Others: + * if(addr->sa_len < sizeof(struct sockaddr)) return EINVAL; + * if (addr->sa_family == AF_UNSPEC) sodisconnect(so); + */ int uv__udp_disconnect(uv_udp_t* handle) { int r; +#if defined(__MVS__) + struct sockaddr_storage addr; +#else struct sockaddr addr; +#endif memset(&addr, 0, sizeof(addr)); - + +#if defined(__MVS__) + addr.ss_family = AF_UNSPEC; +#else addr.sa_family = AF_UNSPEC; - +#endif + do { errno = 0; - r = connect(handle->io_watcher.fd, &addr, sizeof(addr)); + r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr)); } while (r == -1 && errno == EINTR); - if (r == -1 && errno != EAFNOSUPPORT) + if (r == -1) { +#if defined(BSD) /* The macro BSD is from sys/param.h */ + if (errno != EAFNOSUPPORT && errno != EINVAL) + return UV__ERR(errno); +#else return UV__ERR(errno); +#endif + } handle->flags &= ~UV_HANDLE_UDP_CONNECTED; return 0; } - int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[], diff --git a/src/win/udp.c b/src/win/udp.c index 3043f2da88e..3a86e0ea8c3 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -1083,7 +1083,7 @@ int uv__udp_connect(uv_udp_t* handle, int uv__udp_disconnect(uv_udp_t* handle) { int err; - struct sockaddr addr; + struct sockaddr_storage addr; memset(&addr, 0, sizeof(addr)); diff --git a/test/test-list.h b/test/test-list.h index e0b247f4863..1f566861a0e 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -160,6 +160,7 @@ TEST_DECLARE (udp_alloc_cb_fail) TEST_DECLARE (udp_bind) TEST_DECLARE (udp_bind_reuseaddr) TEST_DECLARE (udp_connect) +TEST_DECLARE (udp_connect6) TEST_DECLARE (udp_create_early) TEST_DECLARE (udp_create_early_bad_bind) TEST_DECLARE (udp_create_early_bad_domain) @@ -737,6 +738,7 @@ TASK_LIST_START TEST_ENTRY (udp_bind) TEST_ENTRY (udp_bind_reuseaddr) TEST_ENTRY (udp_connect) + TEST_ENTRY (udp_connect6) TEST_ENTRY (udp_create_early) TEST_ENTRY (udp_create_early_bad_bind) TEST_ENTRY (udp_create_early_bad_domain) diff --git a/test/test-udp-connect6.c b/test/test-udp-connect6.c new file mode 100644 index 00000000000..8e385af99b2 --- /dev/null +++ b/test/test-udp-connect6.c @@ -0,0 +1,200 @@ +/* Copyright libuv project and contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + +static uv_udp_t server; +static uv_udp_t client; +static uv_buf_t buf; +static struct sockaddr_in6 lo_addr; + +static int cl_send_cb_called; +static int sv_recv_cb_called; + +static int close_cb_called; + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + CHECK_HANDLE(handle); + ASSERT_LE(suggested_size, sizeof(slab)); + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + ASSERT(uv_is_closing(handle)); + close_cb_called++; +} + + +static void cl_send_cb(uv_udp_send_t* req, int status) { + int r; + + ASSERT_NOT_NULL(req); + ASSERT_EQ(status, 0); + CHECK_HANDLE(req->handle); + if (++cl_send_cb_called == 1) { + uv_udp_connect(&client, NULL); + r = uv_udp_send(req, &client, &buf, 1, NULL, cl_send_cb); + ASSERT_EQ(r, UV_EDESTADDRREQ); + r = uv_udp_send(req, + &client, + &buf, + 1, + (const struct sockaddr*) &lo_addr, + cl_send_cb); + ASSERT_EQ(r, 0); + } + +} + + +static void sv_recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* rcvbuf, + const struct sockaddr* addr, + unsigned flags) { + if (nread > 0) { + ASSERT_EQ(nread, 4); + ASSERT_NOT_NULL(addr); + ASSERT_EQ(memcmp("EXIT", rcvbuf->base, nread), 0); + if (++sv_recv_cb_called == 4) { + uv_close((uv_handle_t*) &server, close_cb); + uv_close((uv_handle_t*) &client, close_cb); + } + } +} + + +TEST_IMPL(udp_connect6) { +#if defined(__PASE__) + RETURN_SKIP( + "IBMi PASE's UDP connection can not be disconnected with AF_UNSPEC."); +#endif + uv_udp_send_t req; + struct sockaddr_in6 ext_addr; + struct sockaddr_in6 tmp_addr; + int r; + int addrlen; + + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + + ASSERT_EQ(0, uv_ip6_addr("::", TEST_PORT, &lo_addr)); + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT_EQ(r, 0); + + r = uv_udp_bind(&server, (const struct sockaddr*) &lo_addr, 0); + ASSERT_EQ(r, 0); + + r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); + ASSERT_EQ(r, 0); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT_EQ(r, 0); + + buf = uv_buf_init("EXIT", 4); + + /* connect() to INADDR_ANY fails on Windows wih WSAEADDRNOTAVAIL */ + ASSERT_EQ(0, uv_ip6_addr("::", TEST_PORT, &tmp_addr)); + r = uv_udp_connect(&client, (const struct sockaddr*) &tmp_addr); +#ifdef _WIN32 + ASSERT_EQ(r, UV_EADDRNOTAVAIL); +#else + ASSERT_EQ(r, 0); + r = uv_udp_connect(&client, NULL); + ASSERT_EQ(r, 0); +#endif + + ASSERT_EQ(0, uv_ip6_addr("2001:4860:4860::8888", TEST_PORT, &ext_addr)); + ASSERT_EQ(0, uv_ip6_addr("::1", TEST_PORT, &lo_addr)); + + r = uv_udp_connect(&client, (const struct sockaddr*) &lo_addr); + ASSERT_EQ(r, 0); + r = uv_udp_connect(&client, (const struct sockaddr*) &ext_addr); + ASSERT_EQ(r, UV_EISCONN); + + addrlen = sizeof(tmp_addr); + r = uv_udp_getpeername(&client, (struct sockaddr*) &tmp_addr, &addrlen); + ASSERT_EQ(r, 0); + + /* To send messages in connected UDP sockets addr must be NULL */ + r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &lo_addr); + ASSERT_EQ(r, UV_EISCONN); + r = uv_udp_try_send(&client, &buf, 1, NULL); + ASSERT_EQ(r, 4); + r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &ext_addr); + ASSERT_EQ(r, UV_EISCONN); + + r = uv_udp_connect(&client, NULL); + ASSERT_EQ(r, 0); + r = uv_udp_connect(&client, NULL); + ASSERT_EQ(r, UV_ENOTCONN); + + addrlen = sizeof(tmp_addr); + r = uv_udp_getpeername(&client, (struct sockaddr*) &tmp_addr, &addrlen); + ASSERT_EQ(r, UV_ENOTCONN); + + /* To send messages in disconnected UDP sockets addr must be set */ + r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &lo_addr); + ASSERT_EQ(r, 4); + r = uv_udp_try_send(&client, &buf, 1, NULL); + ASSERT_EQ(r, UV_EDESTADDRREQ); + + + r = uv_udp_connect(&client, (const struct sockaddr*) &lo_addr); + ASSERT_EQ(r, 0); + r = uv_udp_send(&req, + &client, + &buf, + 1, + (const struct sockaddr*) &lo_addr, + cl_send_cb); + ASSERT_EQ(r, UV_EISCONN); + r = uv_udp_send(&req, &client, &buf, 1, NULL, cl_send_cb); + ASSERT_EQ(r, 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT_EQ(close_cb_called, 2); + ASSERT_EQ(sv_recv_cb_called, 4); + ASSERT_EQ(cl_send_cb_called, 2); + + ASSERT_EQ(client.send_queue_size, 0); + ASSERT_EQ(server.send_queue_size, 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From 988f2bfc4defb9a85a536a3e645834c161143ee0 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 4 Jan 2022 09:18:00 -0500 Subject: [PATCH 094/713] 2022.01.05, Version 1.43.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.42.0: * run test named ip6_sin6_len (Jameson Nash) * docs: fix wrong information about scheduling (Mohamed Edrah) * unix: protect fork in uv_spawn from signals (Jameson Nash) * drop only successfully sent packets post sendmmsg (Supragya Raj) * test: fix typo in test-tty-escape-sequence-processing.c (Ikko Ashimine) * cmake: use standard installation layout always (Sylvain Corlay) * win,spawn: allow UNC path with forward slash (earnal) * win,fsevent: fix uv_fs_event_stop() assert (Ben Noordhuis) * unix: remove redundant include in unix.h ( * doc: mark SmartOS as Tier 3 support ( * doc: fix broken links for netbsd's sysctl manpage ( * misc: adjust stalebot deadline ( * test: remove `dns-server.c` as it is not used anywhere ( * build: fix non-cmake android builds ( * doc: replace pyuv with uvloop ( * asan: fix some tests ( * build: add experimental TSAN configuration ( * pipe: remove useless assertion ( * bsd: destroy mutex in uv__process_title_cleanup() ( * build: add windows build to CI ( * win,fs: fix error code in uv_fs_read() and uv_fs_write() ( Sen) * build: add macos-latest to ci matrix ( * udp: fix &/&& typo in macro condition ( * build: install cmake package module (Petr Menšík) * win: fix build for mingw32 ( * build: fix build failures with MinGW new headers (erw7) * build: fix win build with cmake versions before v3.14 ( * unix: support aarch64 in uv_cpu_info() ( * linux: work around CIFS EPERM bug ( * sunos: Oracle Developer Studio support ( * Revert "sunos: Oracle Developer Studio support ( * sunos: Oracle Developer Studio support ( * stream: permit read after seeing EOF ( * thread: initialize uv_thread_self for all threads ( * kqueue: ignore write-end closed notifications ( * macos: fix the cfdata length in uv__get_cpu_speed ( Bache) * unix,win: add uv_ip_name to get name from sockaddr ( * win,test: fix a few typos (AJ Heller) * zos: use destructor for uv__threadpool_cleanup() ( Zhang) * linux: use MemAvailable instead of MemFree ( * freebsd: call dlerror() only if necessary ( * bsd,windows,zos: fix udp disconnect EINVAL ( --- .mailmap | 4 ++ AUTHORS | 17 +++++++++ ChangeLog | 89 ++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 8 ++-- 5 files changed, 115 insertions(+), 5 deletions(-) diff --git a/.mailmap b/.mailmap index 7be85aba980..b23377c6151 100644 --- a/.mailmap +++ b/.mailmap @@ -1,4 +1,5 @@ A. Hauptmann +AJ Heller Aaron Bieber Alan Gutierrez Andrius Bentkus @@ -12,6 +13,7 @@ Brian White Caleb James DeLisle Christoph Iserlohn Darshan Sen +Darshan Sen David Carlier Devchandra Meetei Leishangthem Fedor Indutny @@ -21,6 +23,7 @@ Isaac Z. Schlueter Jason Williams Jesse Gorzinski Jesse Gorzinski +Juan José Arboleda Justin Venus Keno Fischer Keno Fischer @@ -46,6 +49,7 @@ Santiago Gimeno Saúl Ibarra Corretgé Saúl Ibarra Corretgé Shigeki Ohtsu +Shuowang (Wayne) Zhang TK-one Timothy J. Fontaine Yasuhiro Matsumoto diff --git a/AUTHORS b/AUTHORS index 741bcc708cb..a18d09668b9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -479,3 +479,20 @@ Joshua M. Clulow Guilherme Íscaro Martin Storsjö Claes Nästén +Mohamed Edrah <43171151+MSE99@users.noreply.github.com> +Supragya Raj +Ikko Ashimine +Sylvain Corlay +earnal +YAKSH BARIYA +Ofek Lev +~locpyl-tidnyd <81016946+locpyl-tidnyd@users.noreply.github.com> +Evan Miller +Petr Menšík +Nicolas Noble +AJ Heller +Stacey Marshall +Jesper Storm Bache +Campbell He +Andrey Hohutkin +deal diff --git a/ChangeLog b/ChangeLog index 11492c55323..ad661769a54 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,92 @@ +2022.01.05, Version 1.43.0 (Stable) + +Changes since version 1.42.0: + +* run test named ip6_sin6_len (Jameson Nash) + +* docs: fix wrong information about scheduling (Mohamed Edrah) + +* unix: protect fork in uv_spawn from signals (Jameson Nash) + +* drop only successfully sent packets post sendmmsg (Supragya Raj) + +* test: fix typo in test-tty-escape-sequence-processing.c (Ikko Ashimine) + +* cmake: use standard installation layout always (Sylvain Corlay) + +* win,spawn: allow UNC path with forward slash (earnal) + +* win,fsevent: fix uv_fs_event_stop() assert (Ben Noordhuis) + +* unix: remove redundant include in unix.h ( + +* doc: mark SmartOS as Tier 3 support ( + +* doc: fix broken links for netbsd's sysctl manpage ( + +* misc: adjust stalebot deadline ( + +* test: remove `dns-server.c` as it is not used anywhere ( + +* build: fix non-cmake android builds ( + +* doc: replace pyuv with uvloop ( + +* asan: fix some tests ( + +* build: add experimental TSAN configuration ( + +* pipe: remove useless assertion ( + +* bsd: destroy mutex in uv__process_title_cleanup() ( + +* build: add windows build to CI ( + +* win,fs: fix error code in uv_fs_read() and uv_fs_write() ( Sen) + +* build: add macos-latest to ci matrix ( + +* udp: fix &/&& typo in macro condition ( + +* build: install cmake package module (Petr Menšík) + +* win: fix build for mingw32 ( + +* build: fix build failures with MinGW new headers (erw7) + +* build: fix win build with cmake versions before v3.14 ( + +* unix: support aarch64 in uv_cpu_info() ( + +* linux: work around CIFS EPERM bug ( + +* sunos: Oracle Developer Studio support ( + +* Revert "sunos: Oracle Developer Studio support ( + +* sunos: Oracle Developer Studio support ( + +* stream: permit read after seeing EOF ( + +* thread: initialize uv_thread_self for all threads ( + +* kqueue: ignore write-end closed notifications ( + +* macos: fix the cfdata length in uv__get_cpu_speed ( Bache) + +* unix,win: add uv_ip_name to get name from sockaddr ( + +* win,test: fix a few typos (AJ Heller) + +* zos: use destructor for uv__threadpool_cleanup() ( Zhang) + +* linux: use MemAvailable instead of MemFree ( + +* freebsd: call dlerror() only if necessary ( + +* bsd,windows,zos: fix udp disconnect EINVAL ( + + 2021.07.21, Version 1.42.0 (Stable), 6ce14710da7079eb248868171f6343bc409ea3a4 Changes since version 1.41.0: diff --git a/configure.ac b/configure.ac index 1fbb5c8c822..bdb0c75ea50 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.42.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.43.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index ab5ed00954d..46f469296e4 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 42 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 43 +#define UV_VERSION_PATCH 0 +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 2c31ecb8faafcb9081fc4ccce47035761a1b24c0 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 4 Jan 2022 09:18:00 -0500 Subject: [PATCH 095/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ad661769a54..3c94ef2f1ae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2022.01.05, Version 1.43.0 (Stable) +2022.01.05, Version 1.43.0 (Stable), 988f2bfc4defb9a85a536a3e645834c161143ee0 Changes since version 1.42.0: From bb6248bca4ccc4cb50b3e859be23afd9be52ebcb Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 4 Jan 2022 09:27:20 -0500 Subject: [PATCH 096/713] Now working on version 1.43.1 Fixes: https://github.com/libuv/libuv/issues/3397 --- include/uv/version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/uv/version.h b/include/uv/version.h index 46f469296e4..1934f390dc5 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 43 -#define UV_VERSION_PATCH 0 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 1 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From abb109f30f7c0b3615b75156376d2e886c365df8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 9 Jan 2022 12:20:15 +0100 Subject: [PATCH 097/713] darwin: remove EPROTOTYPE error workaround (#3405) It's been reported in the past that OS X 10.10, because of a race condition in the XNU kernel, sometimes returns a transient EPROTOTYPE error when trying to write to a socket. Libuv handles that by retrying the operation until it succeeds or fails with a different error. Recently it's been reported that current versions of the operating system formerly known as OS X fail permanently with EPROTOTYPE under certain conditions, resulting in an infinite loop. Because Apple isn't exactly forthcoming with bug fixes or even details, I'm opting to simply remove the workaround and have the error bubble up. Refs: https://github.com/libuv/libuv/pull/482 --- src/unix/stream.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 5858258d286..c5cd6ddc0b6 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -58,20 +58,6 @@ struct uv__stream_select_s { fd_set* swrite; size_t swrite_sz; }; - -/* Due to a possible kernel bug at least in OS X 10.10 "Yosemite", - * EPROTOTYPE can be returned while trying to write to a socket that is - * shutting down. If we retry the write, we should get the expected EPIPE - * instead. - */ -# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR || errno == EPROTOTYPE) -# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \ - (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \ - (errno == EMSGSIZE && send_handle != NULL)) -#else -# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR) -# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \ - (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) #endif /* defined(__APPLE__) */ static void uv__stream_connect(uv_stream_t*); @@ -866,17 +852,17 @@ static int uv__try_write(uv_stream_t* stream, do n = sendmsg(uv__stream_fd(stream), &msg, 0); - while (n == -1 && RETRY_ON_WRITE_ERROR(errno)); + while (n == -1 && errno == EINTR); } else { do n = uv__writev(uv__stream_fd(stream), iov, iovcnt); - while (n == -1 && RETRY_ON_WRITE_ERROR(errno)); + while (n == -1 && errno == EINTR); } if (n >= 0) return n; - if (IS_TRANSIENT_WRITE_ERROR(errno, send_handle)) + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) return UV_EAGAIN; return UV__ERR(errno); From 2e42847f4efa77ff5e5b217a33536f341b0a3f1a Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Sun, 9 Jan 2022 19:51:43 -0500 Subject: [PATCH 098/713] doc: fix v1.43.0 changelog entries PR-URL: https://github.com/libuv/libuv/pull/3407 --- ChangeLog | 62 +++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3c94ef2f1ae..0a41c5760bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,73 +18,73 @@ Changes since version 1.42.0: * win,fsevent: fix uv_fs_event_stop() assert (Ben Noordhuis) -* unix: remove redundant include in unix.h ( +* unix: remove redundant include in unix.h (Juan José Arboleda) -* doc: mark SmartOS as Tier 3 support ( +* doc: mark SmartOS as Tier 3 support (Ben Noordhuis) -* doc: fix broken links for netbsd's sysctl manpage ( +* doc: fix broken links for netbsd's sysctl manpage (YAKSH BARIYA) -* misc: adjust stalebot deadline ( +* misc: adjust stalebot deadline (Ben Noordhuis) -* test: remove `dns-server.c` as it is not used anywhere ( +* test: remove `dns-server.c` as it is not used anywhere (Darshan Sen) -* build: fix non-cmake android builds ( +* build: fix non-cmake android builds (YAKSH BARIYA) -* doc: replace pyuv with uvloop ( +* doc: replace pyuv with uvloop (Ofek Lev) -* asan: fix some tests ( +* asan: fix some tests (Jameson Nash) -* build: add experimental TSAN configuration ( +* build: add experimental TSAN configuration (Jameson Nash) -* pipe: remove useless assertion ( +* pipe: remove useless assertion (~locpyl-tidnyd) -* bsd: destroy mutex in uv__process_title_cleanup() ( +* bsd: destroy mutex in uv__process_title_cleanup() (Darshan Sen) -* build: add windows build to CI ( +* build: add windows build to CI (Darshan Sen) -* win,fs: fix error code in uv_fs_read() and uv_fs_write() ( Sen) +* win,fs: fix error code in uv_fs_read() and uv_fs_write() (Darshan Sen) -* build: add macos-latest to ci matrix ( +* build: add macos-latest to ci matrix (Ben Noordhuis) -* udp: fix &/&& typo in macro condition ( +* udp: fix &/&& typo in macro condition (Evan Miller) * build: install cmake package module (Petr Menšík) -* win: fix build for mingw32 ( +* win: fix build for mingw32 (Nicolas Noble) * build: fix build failures with MinGW new headers (erw7) -* build: fix win build with cmake versions before v3.14 ( +* build: fix win build with cmake versions before v3.14 (AJ Heller) -* unix: support aarch64 in uv_cpu_info() ( +* unix: support aarch64 in uv_cpu_info() (Juan José Arboleda) -* linux: work around CIFS EPERM bug ( +* linux: work around CIFS EPERM bug (Ben Noordhuis) -* sunos: Oracle Developer Studio support ( +* sunos: Oracle Developer Studio support (Stacey Marshall) -* Revert "sunos: Oracle Developer Studio support ( +* Revert "sunos: Oracle Developer Studio support (cjihrig) -* sunos: Oracle Developer Studio support ( +* sunos: Oracle Developer Studio support (Stacey Marshall) -* stream: permit read after seeing EOF ( +* stream: permit read after seeing EOF (Jameson Nash) -* thread: initialize uv_thread_self for all threads ( +* thread: initialize uv_thread_self for all threads (Jameson Nash) -* kqueue: ignore write-end closed notifications ( +* kqueue: ignore write-end closed notifications (Jameson Nash) -* macos: fix the cfdata length in uv__get_cpu_speed ( Bache) +* macos: fix the cfdata length in uv__get_cpu_speed (Jesper Storm Bache) -* unix,win: add uv_ip_name to get name from sockaddr ( +* unix,win: add uv_ip_name to get name from sockaddr (Campbell He) * win,test: fix a few typos (AJ Heller) -* zos: use destructor for uv__threadpool_cleanup() ( Zhang) +* zos: use destructor for uv__threadpool_cleanup() (Wayne Zhang) -* linux: use MemAvailable instead of MemFree ( +* linux: use MemAvailable instead of MemFree (Andrey Hohutkin) -* freebsd: call dlerror() only if necessary ( +* freebsd: call dlerror() only if necessary (Jameson Nash) -* bsd,windows,zos: fix udp disconnect EINVAL ( +* bsd,windows,zos: fix udp disconnect EINVAL (deal) 2021.07.21, Version 1.42.0 (Stable), 6ce14710da7079eb248868171f6343bc409ea3a4 From a3e02e5e4abd5343f0e09e08b179ee03ebd78eff Mon Sep 17 00:00:00 2001 From: David Machaj <46852402+dmachaj@users.noreply.github.com> Date: Wed, 12 Jan 2022 07:07:17 -0800 Subject: [PATCH 099/713] win: replace CRITICAL_SECTION+Semaphore with SRWLock (#3383) Fixes: https://github.com/libuv/libuv/issues/3382 --- include/uv/win.h | 23 +++++------- src/win/thread.c | 91 ++++++++++-------------------------------------- 2 files changed, 27 insertions(+), 87 deletions(-) diff --git a/include/uv/win.h b/include/uv/win.h index 5fecf4bf6e5..59a5d86e736 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -263,21 +263,14 @@ typedef union { } unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */ } uv_cond_t; -typedef union { - struct { - unsigned int num_readers_; - CRITICAL_SECTION num_readers_lock_; - HANDLE write_semaphore_; - } state_; - /* TODO: remove me in v2.x. */ - struct { - SRWLOCK unused_; - } unused1_; - /* TODO: remove me in v2.x. */ - struct { - uv_mutex_t unused1_; - uv_mutex_t unused2_; - } unused2_; +typedef struct { + SRWLOCK read_write_lock_; + /* TODO: retained for ABI compatibility; remove me in v2.x */ +#ifdef _WIN64 + unsigned char padding_[72]; +#else + unsigned char padding_[44]; +#endif } uv_rwlock_t; typedef struct { diff --git a/src/win/thread.c b/src/win/thread.c index 3615101b44d..ea5dc04e9e5 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -248,113 +248,60 @@ void uv_mutex_unlock(uv_mutex_t* mutex) { LeaveCriticalSection(mutex); } +/* Ensure that the ABI for this type remains stable in v1.x */ +#ifdef _WIN64 +STATIC_ASSERT(sizeof(uv_rwlock_t) == 80); +#else +STATIC_ASSERT(sizeof(uv_rwlock_t) == 48); +#endif int uv_rwlock_init(uv_rwlock_t* rwlock) { - /* Initialize the semaphore that acts as the write lock. */ - HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL); - if (handle == NULL) - return uv_translate_sys_error(GetLastError()); - rwlock->state_.write_semaphore_ = handle; - - /* Initialize the critical section protecting the reader count. */ - InitializeCriticalSection(&rwlock->state_.num_readers_lock_); - - /* Initialize the reader count. */ - rwlock->state_.num_readers_ = 0; + memset(rwlock, 0, sizeof(*rwlock)); + InitializeSRWLock(&rwlock->read_write_lock_); return 0; } void uv_rwlock_destroy(uv_rwlock_t* rwlock) { - DeleteCriticalSection(&rwlock->state_.num_readers_lock_); - CloseHandle(rwlock->state_.write_semaphore_); + /* SRWLock does not need explicit destruction so long as there are no waiting threads + See: https://docs.microsoft.com/windows/win32/api/synchapi/nf-synchapi-initializesrwlock#remarks */ } void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { - /* Acquire the lock that protects the reader count. */ - EnterCriticalSection(&rwlock->state_.num_readers_lock_); - - /* Increase the reader count, and lock for write if this is the first - * reader. - */ - if (++rwlock->state_.num_readers_ == 1) { - DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE); - if (r != WAIT_OBJECT_0) - uv_fatal_error(GetLastError(), "WaitForSingleObject"); - } - - /* Release the lock that protects the reader count. */ - LeaveCriticalSection(&rwlock->state_.num_readers_lock_); + AcquireSRWLockShared(&rwlock->read_write_lock_); } int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { - int err; - - if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_)) + if (!TryAcquireSRWLockShared(&rwlock->read_write_lock_)) return UV_EBUSY; - err = 0; - - if (rwlock->state_.num_readers_ == 0) { - /* Currently there are no other readers, which means that the write lock - * needs to be acquired. - */ - DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0); - if (r == WAIT_OBJECT_0) - rwlock->state_.num_readers_++; - else if (r == WAIT_TIMEOUT) - err = UV_EBUSY; - else if (r == WAIT_FAILED) - uv_fatal_error(GetLastError(), "WaitForSingleObject"); - - } else { - /* The write lock has already been acquired because there are other - * active readers. - */ - rwlock->state_.num_readers_++; - } - - LeaveCriticalSection(&rwlock->state_.num_readers_lock_); - return err; + return 0; } void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { - EnterCriticalSection(&rwlock->state_.num_readers_lock_); - - if (--rwlock->state_.num_readers_ == 0) { - if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL)) - uv_fatal_error(GetLastError(), "ReleaseSemaphore"); - } - - LeaveCriticalSection(&rwlock->state_.num_readers_lock_); + ReleaseSRWLockShared(&rwlock->read_write_lock_); } void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { - DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE); - if (r != WAIT_OBJECT_0) - uv_fatal_error(GetLastError(), "WaitForSingleObject"); + AcquireSRWLockExclusive(&rwlock->read_write_lock_); } int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { - DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0); - if (r == WAIT_OBJECT_0) - return 0; - else if (r == WAIT_TIMEOUT) + if (!TryAcquireSRWLockExclusive(&rwlock->read_write_lock_)) return UV_EBUSY; - else - uv_fatal_error(GetLastError(), "WaitForSingleObject"); + + return 0; } void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { - if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL)) - uv_fatal_error(GetLastError(), "ReleaseSemaphore"); + ReleaseSRWLockExclusive(&rwlock->read_write_lock_); } From 3a7b95593acaab9739404bd120baa62c2007a18a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 12 Jan 2022 16:11:43 +0100 Subject: [PATCH 100/713] darwin: translate EPROTOTYPE to ECONNRESET (#3413) macOS versions 10.10 and 10.15 - and presumbaly 10.11 to 10.14, too - have a bug where a race condition causes the kernel to return EPROTOTYPE because the socket isn't fully constructed. It's probably the result of the peer closing the connection and that is why libuv translates it to ECONNRESET. Previously, libuv retried until the EPROTOTYPE error went away but some VPN software causes the same behavior except the error is permanent, not transient, turning the retry mechanism into an infinite loop. Refs: https://github.com/libuv/libuv/pull/482 Refs: https://github.com/libuv/libuv/pull/3405 --- src/unix/stream.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/unix/stream.c b/src/unix/stream.c index c5cd6ddc0b6..b5b05a6a4a7 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -865,6 +865,20 @@ static int uv__try_write(uv_stream_t* stream, if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) return UV_EAGAIN; +#ifdef __APPLE__ + /* macOS versions 10.10 and 10.15 - and presumbaly 10.11 to 10.14, too - + * have a bug where a race condition causes the kernel to return EPROTOTYPE + * because the socket isn't fully constructed. It's probably the result of + * the peer closing the connection and that is why libuv translates it to + * ECONNRESET. Previously, libuv retried until the EPROTOTYPE error went + * away but some VPN software causes the same behavior except the error is + * permanent, not transient, turning the retry mechanism into an infinite + * loop. See https://github.com/libuv/libuv/pull/482. + */ + if (errno == EPROTOTYPE) + return UV_ECONNRESET; +#endif /* __APPLE__ */ + return UV__ERR(errno); } From c8cbdbd2c47863fcb081415b5cade536bd4f7250 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 13 Jan 2022 05:55:25 +0100 Subject: [PATCH 101/713] android: use libc getifaddrs() (#3412) Fixes: https://github.com/libuv/libuv/issues/3411 --- .github/workflows/CI.yml | 2 +- CMakeLists.txt | 1 - LICENSE | 4 - Makefile.am | 4 +- SUPPORTED_PLATFORMS.md | 2 +- include/uv/android-ifaddrs.h | 54 --- src/unix/android-ifaddrs.c | 713 ----------------------------------- src/unix/linux-core.c | 10 +- 8 files changed, 8 insertions(+), 782 deletions(-) delete mode 100644 include/uv/android-ifaddrs.h delete mode 100644 src/unix/android-ifaddrs.c diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c8af0199c7d..19fc0cf036b 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -44,7 +44,7 @@ jobs: # see build options you can use in https://developer.android.com/ndk/guides/cmake run: | mkdir build && cd build - $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/20.0.5594570/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-21 .. + $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/20.0.5594570/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-24 .. $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake --build . build-macos: diff --git a/CMakeLists.txt b/CMakeLists.txt index b41e5462dd6..5d4dc3b8c56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -215,7 +215,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android") list(APPEND uv_defines _GNU_SOURCE) list(APPEND uv_libraries dl) list(APPEND uv_sources - src/unix/android-ifaddrs.c src/unix/linux-core.c src/unix/linux-inotify.c src/unix/linux-syscalls.c diff --git a/LICENSE b/LICENSE index 28f17339e29..eb126dab3aa 100644 --- a/LICENSE +++ b/LICENSE @@ -64,7 +64,3 @@ The externally maintained libraries used by libuv are: - pthread-fixes.c, copyright Google Inc. and Sony Mobile Communications AB. Three clause BSD license. - - - android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design - Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement - n° 289016). Three clause BSD license. diff --git a/Makefile.am b/Makefile.am index e91cfb8f03e..359d8a5c5b2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -388,10 +388,8 @@ libuv_la_SOURCES += src/unix/aix-common.c \ endif if ANDROID -uvinclude_HEADERS += include/uv/android-ifaddrs.h libuv_la_CFLAGS += -D_GNU_SOURCE -libuv_la_SOURCES += src/unix/android-ifaddrs.c \ - src/unix/pthread-fixes.c +libuv_la_SOURCES += src/unix/pthread-fixes.c endif if CYGWIN diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 87e23823ad6..4d8ea07ce88 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -11,7 +11,7 @@ | z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | | Linux with musl | Tier 2 | musl >= 1.0 | | | SmartOS | Tier 3 | >= 14.4 | | -| Android | Tier 3 | NDK >= r15b | | +| Android | Tier 3 | NDK >= r15b | Android 7.0 and up | | MinGW | Tier 3 | MinGW32 and MinGW-w64 | | | SunOS | Tier 3 | Solaris 121 and later | | | Other | Tier 3 | N/A | | diff --git a/include/uv/android-ifaddrs.h b/include/uv/android-ifaddrs.h deleted file mode 100644 index 9cd19fec129..00000000000 --- a/include/uv/android-ifaddrs.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 1995, 1999 - * Berkeley Software Design, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp - */ - -#ifndef _IFADDRS_H_ -#define _IFADDRS_H_ - -struct ifaddrs { - struct ifaddrs *ifa_next; - char *ifa_name; - unsigned int ifa_flags; - struct sockaddr *ifa_addr; - struct sockaddr *ifa_netmask; - struct sockaddr *ifa_dstaddr; - void *ifa_data; -}; - -/* - * This may have been defined in . Note that if is - * to be included it must be included before this header file. - */ -#ifndef ifa_broadaddr -#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ -#endif - -#include - -__BEGIN_DECLS -extern int getifaddrs(struct ifaddrs **ifap); -extern void freeifaddrs(struct ifaddrs *ifa); -__END_DECLS - -#endif diff --git a/src/unix/android-ifaddrs.c b/src/unix/android-ifaddrs.c deleted file mode 100644 index 4765cc06b57..00000000000 --- a/src/unix/android-ifaddrs.c +++ /dev/null @@ -1,713 +0,0 @@ -/* -Copyright (c) 2013, Kenneth MacKay -Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016) -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "uv/android-ifaddrs.h" -#include "uv-common.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef struct NetlinkList -{ - struct NetlinkList *m_next; - struct nlmsghdr *m_data; - unsigned int m_size; -} NetlinkList; - -static int netlink_socket(pid_t *p_pid) -{ - struct sockaddr_nl l_addr; - socklen_t l_len; - - int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if(l_socket < 0) - { - return -1; - } - - memset(&l_addr, 0, sizeof(l_addr)); - l_addr.nl_family = AF_NETLINK; - if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) - { - close(l_socket); - return -1; - } - - l_len = sizeof(l_addr); - if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0) - { - close(l_socket); - return -1; - } - *p_pid = l_addr.nl_pid; - - return l_socket; -} - -static int netlink_send(int p_socket, int p_request) -{ - char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))]; - - struct nlmsghdr *l_hdr; - struct rtgenmsg *l_msg; - struct sockaddr_nl l_addr; - - memset(l_buffer, 0, sizeof(l_buffer)); - - l_hdr = (struct nlmsghdr *)l_buffer; - l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr); - - l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg)); - l_hdr->nlmsg_type = p_request; - l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; - l_hdr->nlmsg_pid = 0; - l_hdr->nlmsg_seq = p_socket; - l_msg->rtgen_family = AF_UNSPEC; - - memset(&l_addr, 0, sizeof(l_addr)); - l_addr.nl_family = AF_NETLINK; - return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr))); -} - -static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) -{ - struct sockaddr_nl l_addr; - struct msghdr l_msg; - - struct iovec l_iov; - l_iov.iov_base = p_buffer; - l_iov.iov_len = p_len; - - for(;;) - { - int l_result; - l_msg.msg_name = (void *)&l_addr; - l_msg.msg_namelen = sizeof(l_addr); - l_msg.msg_iov = &l_iov; - l_msg.msg_iovlen = 1; - l_msg.msg_control = NULL; - l_msg.msg_controllen = 0; - l_msg.msg_flags = 0; - l_result = recvmsg(p_socket, &l_msg, 0); - - if(l_result < 0) - { - if(errno == EINTR) - { - continue; - } - return -2; - } - - /* Buffer was too small */ - if(l_msg.msg_flags & MSG_TRUNC) - { - return -1; - } - return l_result; - } -} - -static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done) -{ - size_t l_size = 4096; - void *l_buffer = NULL; - - for(;;) - { - int l_read; - - uv__free(l_buffer); - l_buffer = uv__malloc(l_size); - if (l_buffer == NULL) - { - return NULL; - } - - l_read = netlink_recv(p_socket, l_buffer, l_size); - *p_size = l_read; - if(l_read == -2) - { - uv__free(l_buffer); - return NULL; - } - if(l_read >= 0) - { - struct nlmsghdr *l_hdr; - for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) - { - if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket) - { - continue; - } - - if(l_hdr->nlmsg_type == NLMSG_DONE) - { - *p_done = 1; - break; - } - - if(l_hdr->nlmsg_type == NLMSG_ERROR) - { - uv__free(l_buffer); - return NULL; - } - } - return l_buffer; - } - - l_size *= 2; - } -} - -static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size) -{ - NetlinkList *l_item = uv__malloc(sizeof(NetlinkList)); - if (l_item == NULL) - { - return NULL; - } - - l_item->m_next = NULL; - l_item->m_data = p_data; - l_item->m_size = p_size; - return l_item; -} - -static void freeResultList(NetlinkList *p_list) -{ - NetlinkList *l_cur; - while(p_list) - { - l_cur = p_list; - p_list = p_list->m_next; - uv__free(l_cur->m_data); - uv__free(l_cur); - } -} - -static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid) -{ - int l_size; - int l_done; - NetlinkList *l_list; - NetlinkList *l_end; - - if(netlink_send(p_socket, p_request) < 0) - { - return NULL; - } - - l_list = NULL; - l_end = NULL; - - l_done = 0; - while(!l_done) - { - NetlinkList *l_item; - - struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done); - /* Error */ - if(!l_hdr) - { - freeResultList(l_list); - return NULL; - } - - l_item = newListItem(l_hdr, l_size); - if (!l_item) - { - freeResultList(l_list); - return NULL; - } - if(!l_list) - { - l_list = l_item; - } - else - { - l_end->m_next = l_item; - } - l_end = l_item; - } - return l_list; -} - -static size_t maxSize(size_t a, size_t b) -{ - return (a > b ? a : b); -} - -static size_t calcAddrLen(sa_family_t p_family, int p_dataSize) -{ - switch(p_family) - { - case AF_INET: - return sizeof(struct sockaddr_in); - case AF_INET6: - return sizeof(struct sockaddr_in6); - case AF_PACKET: - return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize); - default: - return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize); - } -} - -static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size) -{ - switch(p_family) - { - case AF_INET: - memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size); - break; - case AF_INET6: - memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size); - break; - case AF_PACKET: - memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size); - ((struct sockaddr_ll*)p_dest)->sll_halen = p_size; - break; - default: - memcpy(p_dest->sa_data, p_data, p_size); - break; - } - p_dest->sa_family = p_family; -} - -static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry) -{ - if(!*p_resultList) - { - *p_resultList = p_entry; - } - else - { - struct ifaddrs *l_cur = *p_resultList; - while(l_cur->ifa_next) - { - l_cur = l_cur->ifa_next; - } - l_cur->ifa_next = p_entry; - } -} - -static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList) -{ - struct ifaddrs *l_entry; - - char *l_index; - char *l_name; - char *l_addr; - char *l_data; - - struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); - - size_t l_nameSize = 0; - size_t l_addrSize = 0; - size_t l_dataSize = 0; - - size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); - struct rtattr *l_rta; - for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) - { - size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); - switch(l_rta->rta_type) - { - case IFLA_ADDRESS: - case IFLA_BROADCAST: - l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); - break; - case IFLA_IFNAME: - l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); - break; - case IFLA_STATS: - l_dataSize += NLMSG_ALIGN(l_rtaSize); - break; - default: - break; - } - } - - l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize); - if (l_entry == NULL) - { - return -1; - } - memset(l_entry, 0, sizeof(struct ifaddrs)); - l_entry->ifa_name = ""; - - l_index = ((char *)l_entry) + sizeof(struct ifaddrs); - l_name = l_index + sizeof(int); - l_addr = l_name + l_nameSize; - l_data = l_addr + l_addrSize; - - /* Save the interface index so we can look it up when handling the - * addresses. - */ - memcpy(l_index, &l_info->ifi_index, sizeof(int)); - - l_entry->ifa_flags = l_info->ifi_flags; - - l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); - for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) - { - void *l_rtaData = RTA_DATA(l_rta); - size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); - switch(l_rta->rta_type) - { - case IFLA_ADDRESS: - case IFLA_BROADCAST: - { - size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); - makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); - ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; - ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; - if(l_rta->rta_type == IFLA_ADDRESS) - { - l_entry->ifa_addr = (struct sockaddr *)l_addr; - } - else - { - l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; - } - l_addr += NLMSG_ALIGN(l_addrLen); - break; - } - case IFLA_IFNAME: - strncpy(l_name, l_rtaData, l_rtaDataSize); - l_name[l_rtaDataSize] = '\0'; - l_entry->ifa_name = l_name; - break; - case IFLA_STATS: - memcpy(l_data, l_rtaData, l_rtaDataSize); - l_entry->ifa_data = l_data; - break; - default: - break; - } - } - - addToEnd(p_resultList, l_entry); - return 0; -} - -static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks) -{ - int l_num = 0; - struct ifaddrs *l_cur = *p_links; - while(l_cur && l_num < p_numLinks) - { - char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs); - int l_index; - memcpy(&l_index, l_indexPtr, sizeof(int)); - if(l_index == p_index) - { - return l_cur; - } - - l_cur = l_cur->ifa_next; - ++l_num; - } - return NULL; -} - -static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks) -{ - struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); - struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks); - - size_t l_nameSize = 0; - size_t l_addrSize = 0; - - int l_addedNetmask = 0; - - size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); - struct rtattr *l_rta; - struct ifaddrs *l_entry; - - char *l_name; - char *l_addr; - - for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) - { - size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); - if(l_info->ifa_family == AF_PACKET) - { - continue; - } - - switch(l_rta->rta_type) - { - case IFA_ADDRESS: - case IFA_LOCAL: - l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); - if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) - { - /* Make room for netmask */ - l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); - l_addedNetmask = 1; - } - break; - case IFA_BROADCAST: - l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); - break; - case IFA_LABEL: - l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1); - break; - default: - break; - } - } - - l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); - if (l_entry == NULL) - { - return -1; - } - memset(l_entry, 0, sizeof(struct ifaddrs)); - l_entry->ifa_name = (l_interface ? l_interface->ifa_name : ""); - - l_name = ((char *)l_entry) + sizeof(struct ifaddrs); - l_addr = l_name + l_nameSize; - - l_entry->ifa_flags = l_info->ifa_flags; - if(l_interface) - { - l_entry->ifa_flags |= l_interface->ifa_flags; - } - - l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); - for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) - { - void *l_rtaData = RTA_DATA(l_rta); - size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); - switch(l_rta->rta_type) - { - case IFA_ADDRESS: - case IFA_BROADCAST: - case IFA_LOCAL: - { - size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); - makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); - if(l_info->ifa_family == AF_INET6) - { - if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) - { - ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; - } - } - - /* Apparently in a point-to-point network IFA_ADDRESS contains - * the dest address and IFA_LOCAL contains the local address - */ - if(l_rta->rta_type == IFA_ADDRESS) - { - if(l_entry->ifa_addr) - { - l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; - } - else - { - l_entry->ifa_addr = (struct sockaddr *)l_addr; - } - } - else if(l_rta->rta_type == IFA_LOCAL) - { - if(l_entry->ifa_addr) - { - l_entry->ifa_dstaddr = l_entry->ifa_addr; - } - l_entry->ifa_addr = (struct sockaddr *)l_addr; - } - else - { - l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; - } - l_addr += NLMSG_ALIGN(l_addrLen); - break; - } - case IFA_LABEL: - strncpy(l_name, l_rtaData, l_rtaDataSize); - l_name[l_rtaDataSize] = '\0'; - l_entry->ifa_name = l_name; - break; - default: - break; - } - } - - if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) - { - unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); - unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); - unsigned char l_mask[16] = {0}; - unsigned i; - for(i=0; i<(l_prefix/8); ++i) - { - l_mask[i] = 0xff; - } - if(l_prefix % 8) - { - l_mask[i] = 0xff << (8 - (l_prefix % 8)); - } - - makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); - l_entry->ifa_netmask = (struct sockaddr *)l_addr; - } - - addToEnd(p_resultList, l_entry); - return 0; -} - -static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) -{ - - int l_numLinks = 0; - for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) - { - unsigned int l_nlsize = p_netlinkList->m_size; - struct nlmsghdr *l_hdr; - for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) - { - if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket) - { - continue; - } - - if(l_hdr->nlmsg_type == NLMSG_DONE) - { - break; - } - - if(l_hdr->nlmsg_type == RTM_NEWLINK) - { - if(interpretLink(l_hdr, p_resultList) == -1) - { - return -1; - } - ++l_numLinks; - } - } - } - return l_numLinks; -} - -static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) -{ - for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) - { - unsigned int l_nlsize = p_netlinkList->m_size; - struct nlmsghdr *l_hdr; - for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) - { - if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket) - { - continue; - } - - if(l_hdr->nlmsg_type == NLMSG_DONE) - { - break; - } - - if(l_hdr->nlmsg_type == RTM_NEWADDR) - { - if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1) - { - return -1; - } - } - } - } - return 0; -} - -int getifaddrs(struct ifaddrs **ifap) -{ - int l_socket; - int l_result; - int l_numLinks; - pid_t l_pid; - NetlinkList *l_linkResults; - NetlinkList *l_addrResults; - - if(!ifap) - { - return -1; - } - *ifap = NULL; - - l_socket = netlink_socket(&l_pid); - if(l_socket < 0) - { - return -1; - } - - l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid); - if(!l_linkResults) - { - close(l_socket); - return -1; - } - - l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid); - if(!l_addrResults) - { - close(l_socket); - freeResultList(l_linkResults); - return -1; - } - - l_result = 0; - l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap); - if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1) - { - l_result = -1; - } - - freeResultList(l_linkResults); - freeResultList(l_addrResults); - close(l_socket); - return l_result; -} - -void freeifaddrs(struct ifaddrs *ifa) -{ - struct ifaddrs *l_cur; - while(ifa) - { - l_cur = ifa; - ifa = ifa->ifa_next; - uv__free(l_cur); - } -} diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 413d0dd3f09..7b041e68567 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -45,6 +45,10 @@ #define HAVE_IFADDRS_H 1 +# if defined(__ANDROID_API__) && __ANDROID_API__ < 24 +# undef HAVE_IFADDRS_H +#endif + #ifdef __UCLIBC__ # if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32 # undef HAVE_IFADDRS_H @@ -52,11 +56,7 @@ #endif #ifdef HAVE_IFADDRS_H -# if defined(__ANDROID__) -# include "uv/android-ifaddrs.h" -# else -# include -# endif +# include # include # include # include From 2fbfa0358b3bb920ddd1c2747d4887b35b9ac161 Mon Sep 17 00:00:00 2001 From: Jessica Clarke Date: Thu, 13 Jan 2022 05:20:14 +0000 Subject: [PATCH 102/713] unix: fix STATIC_ASSERT to check what it means to check (#3417) Currently it's checking pointers to the uv_buf_t fields match the size of the iovec fields. This is true on traditional architectures where pointers are just machine word-sized integers, but not on CHERI, and thus Arm's Morello prototype, where pointers contain additional metadata (including bounds and permissions). Drop the & to fix this. --- src/unix/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 71e9c525c4a..3dd3fd90a8e 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -96,9 +96,9 @@ static int uv__run_pending(uv_loop_t* loop); /* Verify that uv_buf_t is ABI-compatible with struct iovec. */ STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec)); -STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) == +STATIC_ASSERT(sizeof(((uv_buf_t*) 0)->base) == sizeof(((struct iovec*) 0)->iov_base)); -STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->len) == +STATIC_ASSERT(sizeof(((uv_buf_t*) 0)->len) == sizeof(((struct iovec*) 0)->iov_len)); STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base)); STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len)); From e9cb18484ecdc10e005d306db53d099e06ade9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Sat, 15 Jan 2022 06:24:37 +0100 Subject: [PATCH 103/713] unix: ensure struct msghdr is zeroed in recvmmsg (#3419) With MUSL libc, the struct msghdr is padded to align with the types used in the Linux kernel headers (int vs size_t). When the padding was not zeroed, the syscall would return EMSGSIZE because the random bytes in the padding would be read by kernel as part of the size_t type. Fixes: https://github.com/libuv/libuv/issues/3416 --- src/unix/udp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index aee8d639344..74ef398a065 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -201,6 +201,7 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { for (k = 0; k < chunks; ++k) { iov[k].iov_base = buf->base + k * UV__UDP_DGRAM_MAXSIZE; iov[k].iov_len = UV__UDP_DGRAM_MAXSIZE; + memset(&msgs[k].msg_hdr, 0, sizeof(msgs[k].msg_hdr)); msgs[k].msg_hdr.msg_iov = iov + k; msgs[k].msg_hdr.msg_iovlen = 1; msgs[k].msg_hdr.msg_name = peers + k; @@ -655,16 +656,16 @@ int uv__udp_connect(uv_udp_t* handle, } /* From https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html - * Any of uv supported UNIXs kernel should be standardized, but the kernel + * Any of uv supported UNIXs kernel should be standardized, but the kernel * implementation logic not same, let's use pseudocode to explain the udp * disconnect behaviors: - * + * * Predefined stubs for pseudocode: * 1. sodisconnect: The function to perform the real udp disconnect * 2. pru_connect: The function to perform the real udp connect * 3. so: The kernel object match with socket fd * 4. addr: The sockaddr parameter from user space - * + * * BSDs: * if(sodisconnect(so) == 0) { // udp disconnect succeed * if (addr->sa_len != so->addr->sa_len) return EINVAL; @@ -694,13 +695,13 @@ int uv__udp_disconnect(uv_udp_t* handle) { #endif memset(&addr, 0, sizeof(addr)); - + #if defined(__MVS__) addr.ss_family = AF_UNSPEC; #else addr.sa_family = AF_UNSPEC; #endif - + do { errno = 0; r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr)); From d5ed7f125642b412a7a91baa585dc934ccd185e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Sat, 15 Jan 2022 06:24:37 +0100 Subject: [PATCH 104/713] test: test with maximum recvmmsg buffer (#3419) The maximum numbers receivable by the recvmmsg call is defined in src/unix/udp.c as UV__MMSG_MAXWIDTH with the current value being 20. Align the size of the receive buffer in the mmsg test to receive the maximum number of UDP packets in the test. --- test/test-udp-mmsg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-udp-mmsg.c b/test/test-udp-mmsg.c index fb241151072..401c4f33e7c 100644 --- a/test/test-udp-mmsg.c +++ b/test/test-udp-mmsg.c @@ -29,9 +29,9 @@ #define CHECK_HANDLE(handle) \ ASSERT((uv_udp_t*)(handle) == &recver || (uv_udp_t*)(handle) == &sender) -#define BUFFER_MULTIPLIER 4 +#define BUFFER_MULTIPLIER 20 #define MAX_DGRAM_SIZE (64 * 1024) -#define NUM_SENDS 8 +#define NUM_SENDS 40 #define EXPECTED_MMSG_ALLOCS (NUM_SENDS / BUFFER_MULTIPLIER) static uv_udp_t recver; From b5fa965bcb169f36ae58ebc35a48d85835f9756e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 17 Jan 2022 09:36:26 +0100 Subject: [PATCH 105/713] unix: don't allow too small thread stack size (#3423) uv_thread_create_ex() lets you set a stack size that is smaller than is safe. It enforces a lower bound of PTHREAD_STACK_MIN (when that constant is defined) but with musl libc that's still too small to receive signals on. Put the lower bound at 8192 or PTHREAD_STACK_MIN, whichever is greater. The same restriction was already in place for the _default_ stack size. --- src/unix/thread.c | 86 ++++++++++++++++++++++++++++------------------ test/test-thread.c | 5 +++ 2 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/unix/thread.c b/src/unix/thread.c index c46450cc661..d89e5cd13ba 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -162,12 +162,46 @@ void uv_barrier_destroy(uv_barrier_t* barrier) { #endif -/* On MacOS, threads other than the main thread are created with a reduced - * stack size by default. Adjust to RLIMIT_STACK aligned to the page size. +/* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is + * too small to safely receive signals on. + * + * Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has + * the largest MINSIGSTKSZ of the architectures that musl supports) so + * let's use that as a lower bound. * - * On Linux, threads created by musl have a much smaller stack than threads + * We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ + * is between 28 and 133 KB when compiling against glibc, depending + * on the architecture. + */ +static size_t uv__min_stack_size(void) { + static const size_t min = 8192; + +#ifdef PTHREAD_STACK_MIN /* Not defined on NetBSD. */ + if (min < (size_t) PTHREAD_STACK_MIN) + return PTHREAD_STACK_MIN; +#endif /* PTHREAD_STACK_MIN */ + + return min; +} + + +/* On Linux, threads created by musl have a much smaller stack than threads * created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency. */ +static size_t uv__default_stack_size(void) { +#if !defined(__linux__) + return 0; +#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__) + return 4 << 20; /* glibc default. */ +#else + return 2 << 20; /* glibc default. */ +#endif +} + + +/* On MacOS, threads other than the main thread are created with a reduced + * stack size by default. Adjust to RLIMIT_STACK aligned to the page size. + */ size_t uv__thread_stack_size(void) { #if defined(__APPLE__) || defined(__linux__) struct rlimit lim; @@ -176,34 +210,20 @@ size_t uv__thread_stack_size(void) { * the system call wrapper invokes the wrong system call. Don't treat * that as fatal, just use the default stack size instead. */ - if (0 == getrlimit(RLIMIT_STACK, &lim) && lim.rlim_cur != RLIM_INFINITY) { - /* pthread_attr_setstacksize() expects page-aligned values. */ - lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); - - /* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is - * too small to safely receive signals on. - * - * Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has - * the largest MINSIGSTKSZ of the architectures that musl supports) so - * let's use that as a lower bound. - * - * We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ - * is between 28 and 133 KB when compiling against glibc, depending - * on the architecture. - */ - if (lim.rlim_cur >= 8192) - if (lim.rlim_cur >= PTHREAD_STACK_MIN) - return lim.rlim_cur; - } -#endif + if (getrlimit(RLIMIT_STACK, &lim)) + return uv__default_stack_size(); -#if !defined(__linux__) - return 0; -#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__) - return 4 << 20; /* glibc default. */ -#else - return 2 << 20; /* glibc default. */ + if (lim.rlim_cur == RLIM_INFINITY) + return uv__default_stack_size(); + + /* pthread_attr_setstacksize() expects page-aligned values. */ + lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); + + if (lim.rlim_cur >= (rlim_t) uv__min_stack_size()) + return lim.rlim_cur; #endif + + return uv__default_stack_size(); } @@ -222,6 +242,7 @@ int uv_thread_create_ex(uv_thread_t* tid, pthread_attr_t attr_storage; size_t pagesize; size_t stack_size; + size_t min_stack_size; /* Used to squelch a -Wcast-function-type warning. */ union { @@ -239,10 +260,9 @@ int uv_thread_create_ex(uv_thread_t* tid, pagesize = (size_t)getpagesize(); /* Round up to the nearest page boundary. */ stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1); -#ifdef PTHREAD_STACK_MIN - if (stack_size < PTHREAD_STACK_MIN) - stack_size = PTHREAD_STACK_MIN; -#endif + min_stack_size = uv__min_stack_size(); + if (stack_size < min_stack_size) + stack_size = min_stack_size; } if (stack_size > 0) { diff --git a/test/test-thread.c b/test/test-thread.c index 8de5a6f03a3..c01991b4723 100644 --- a/test/test-thread.c +++ b/test/test-thread.c @@ -273,6 +273,11 @@ TEST_IMPL(thread_stack_size_explicit) { thread_check_stack, &options)); ASSERT(0 == uv_thread_join(&thread)); + options.stack_size = 42; + ASSERT(0 == uv_thread_create_ex(&thread, &options, + thread_check_stack, &options)); + ASSERT(0 == uv_thread_join(&thread)); + #ifdef PTHREAD_STACK_MIN options.stack_size = PTHREAD_STACK_MIN - 42; /* unaligned size */ ASSERT(0 == uv_thread_create_ex(&thread, &options, From e43eb667b5e0cace1eef4b6f5898de83cde262c6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 17 Jan 2022 12:55:41 +0100 Subject: [PATCH 106/713] bsd: ensure mutex is initialized (#3428) The process title mutex was destroyed on library unload without ensuring it was initialized - and it may not be because it's initialized lazily. On most platforms it worked by accident because an "all zeroes" mutex is synonymous with an initialized and unlocked mutex, but not on NetBSD. Refs: https://github.com/libuv/libuv/pull/3286#issuecomment-1014058782 --- src/unix/bsd-proctitle.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/unix/bsd-proctitle.c b/src/unix/bsd-proctitle.c index 4f4e9e5183f..b0c01e2cb85 100644 --- a/src/unix/bsd-proctitle.c +++ b/src/unix/bsd-proctitle.c @@ -38,6 +38,7 @@ static void init_process_title_mutex_once(void) { void uv__process_title_cleanup(void) { + uv_once(&process_title_mutex_once, init_process_title_mutex_once); uv_mutex_destroy(&process_title_mutex); } From bb0b4bb783da45ca995d8fb3d5dec0ed84133446 Mon Sep 17 00:00:00 2001 From: Jiawen Geng Date: Thu, 20 Jan 2022 22:08:14 +0800 Subject: [PATCH 107/713] doc: add gengjiawen as maintainer (#3430) --- MAINTAINERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index fb7e5ef3417..9420dbbfecb 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -17,6 +17,7 @@ libuv is currently managed by the following individuals: - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) * **Jameson Nash** ([@vtjnash](https://github.com/vtjnash)) - GPG key: AEAD 0A4B 6867 6775 1A0E 4AEF 34A2 5FB1 2824 6514 (pubkey-vtjnash) +* **Jiawen Geng** ([@gengjiawen](https://github.com/gengjiawen)) * **John Barboza** ([@jbarz](https://github.com/jbarz)) * **Kaoru Takanashi** ([@erw7](https://github.com/erw7)) - GPG Key: 5804 F999 8A92 2AFB A398 47A0 7183 5090 6134 887F (pubkey-erw7) From d9e90857f0e756684f3ab3286217a68e1a0ff716 Mon Sep 17 00:00:00 2001 From: Jeremy Rose Date: Mon, 31 Jan 2022 11:49:22 -0800 Subject: [PATCH 108/713] process: monitor for exit with kqueue on BSDs (#3441) This adds a workaround for an xnu kernel bug that sometimes results in SIGCHLD not being delivered. The workaround is to use kevent to listen for EVFILT_PROC/NOTE_EXIT events instead of relying on SIGCHLD on *BSD. Apple rdar: FB9529664 Refs: https://github.com/libuv/libuv/pull/3257 --- src/unix/internal.h | 1 + src/unix/kqueue.c | 5 +++++ src/unix/process.c | 24 ++++++++++++++++++++---- test/test-list.h | 2 ++ test/test-spawn.c | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/unix/internal.h b/src/unix/internal.h index 12d4da93686..16be13b99f5 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -282,6 +282,7 @@ uv_handle_type uv__handle_type(int fd); FILE* uv__open_file(const char* path); int uv__getpwuid_r(uv_passwd_t* pwd); int uv__search_path(const char* prog, char* buf, size_t* buflen); +void uv__wait_children(uv_loop_t* loop); /* random */ int uv__random_devurandom(void* buf, size_t buflen); diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 75e9110709d..efbc561dee2 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -284,6 +284,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; for (i = 0; i < nfds; i++) { ev = events + i; + if (ev->filter == EVFILT_PROC) { + uv__wait_children(loop); + nevents++; + continue; + } fd = ev->ident; /* Skip invalidated events, see uv__platform_invalidate_fd */ if (fd == -1) diff --git a/src/unix/process.c b/src/unix/process.c index 91bf3c50702..c1f6bd4b007 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -49,10 +49,20 @@ extern char **environ; # include "zos-base.h" #endif +#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#include +#endif + +#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) static void uv__chld(uv_signal_t* handle, int signum) { + assert(signum == SIGCHLD); + uv__wait_children(handle->loop); +} +#endif + +void uv__wait_children(uv_loop_t* loop) { uv_process_t* process; - uv_loop_t* loop; int exit_status; int term_signal; int status; @@ -61,10 +71,7 @@ static void uv__chld(uv_signal_t* handle, int signum) { QUEUE* q; QUEUE* h; - assert(signum == SIGCHLD); - QUEUE_INIT(&pending); - loop = handle->loop; h = &loop->process_handles; q = QUEUE_HEAD(h); @@ -420,7 +427,9 @@ int uv_spawn(uv_loop_t* loop, if (err) goto error; +#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); +#endif /* Acquire write lock to prevent opening new fds in worker threads */ uv_rwlock_wrlock(&loop->cloexec_lock); @@ -495,6 +504,13 @@ int uv_spawn(uv_loop_t* loop, /* Only activate this handle if exec() happened successfully */ if (exec_errorno == 0) { +#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + struct kevent event; + EV_SET(&event, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, 0); + if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) + abort(); +#endif + QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); uv__handle_start(process); } diff --git a/test/test-list.h b/test/test-list.h index 1f566861a0e..a43edf1a4a9 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -320,6 +320,7 @@ TEST_DECLARE (spawn_reads_child_path) TEST_DECLARE (spawn_inherit_streams) TEST_DECLARE (spawn_quoted_path) TEST_DECLARE (spawn_tcp_server) +TEST_DECLARE (spawn_exercise_sigchld_issue) TEST_DECLARE (fs_poll) TEST_DECLARE (fs_poll_getpath) TEST_DECLARE (fs_poll_close_request) @@ -950,6 +951,7 @@ TASK_LIST_START TEST_ENTRY (spawn_inherit_streams) TEST_ENTRY (spawn_quoted_path) TEST_ENTRY (spawn_tcp_server) + TEST_ENTRY (spawn_exercise_sigchld_issue) TEST_ENTRY (fs_poll) TEST_ENTRY (fs_poll_getpath) TEST_ENTRY (fs_poll_close_request) diff --git a/test/test-spawn.c b/test/test-spawn.c index 9f2eb24b2d6..dfd5458ef37 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1891,6 +1891,44 @@ TEST_IMPL(spawn_quoted_path) { #endif } +TEST_IMPL(spawn_exercise_sigchld_issue) { + int r; + int i; + uv_process_options_t dummy_options = {0}; + uv_process_t dummy_processes[100]; + char* args[2]; + + init_process_options("spawn_helper1", exit_cb); + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT_EQ(r, 0); + + // This test exercises a bug in the darwin kernel that causes SIGCHLD not to + // be delivered sometimes. Calling posix_spawn many times increases the + // likelihood of encountering this issue, so spin a few times to make this + // test more reliable. + dummy_options.file = args[0] = "program-that-had-better-not-exist"; + args[1] = NULL; + dummy_options.args = args; + dummy_options.exit_cb = fail_cb; + dummy_options.flags = 0; + for (i = 0; i < 100; i++) { + r = uv_spawn(uv_default_loop(), &dummy_processes[i], &dummy_options); + if (r != UV_ENOENT) + ASSERT_EQ(r, UV_EACCES); + uv_close((uv_handle_t*) &dummy_processes[i], close_cb); + } + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT_EQ(r, 0); + + ASSERT_EQ(exit_cb_called, 1); + ASSERT_EQ(close_cb_called, 101); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + /* Helper for child process of spawn_inherit_streams */ #ifndef _WIN32 void spawn_stdin_stdout(void) { From e89abc80ea43065a726ade191b810af53ec6158a Mon Sep 17 00:00:00 2001 From: Momtchil Momtchev Date: Mon, 31 Jan 2022 22:25:05 +0100 Subject: [PATCH 109/713] test: fix flaky uv_fs_lutime test (#3424) Disable `atime` testing for symlink as this test is dependant on a race condition on some OSes (Linux is one) as `lstat` updates the `atime`. As both `mtime` and `atime` are set by the same syscall, barring an eventual kernel bug, this test does not omit any error case. --- test/test-fs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/test-fs.c b/test/test-fs.c index aecf10f9e28..c879f629848 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -851,7 +851,12 @@ static void check_utime(const char* path, #endif st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; - ASSERT_DOUBLE_EQ(st_atim, atime); + /* + * Linux does not allow reading reliably the atime of a symlink + * since readlink() can update it + */ + if (!test_lutime) + ASSERT_DOUBLE_EQ(st_atim, atime); ASSERT_DOUBLE_EQ(st_mtim, mtime); } From 125da33f8246ad6454edb5d2dced1cff4363e411 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 31 Jan 2022 16:25:20 -0500 Subject: [PATCH 110/713] build: fix cmake install locations (#3415) Adds static libraries and DLL import libraries, as well as making sure the DLLs go to the correct folder. Closes #3414 --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d4dc3b8c56..1b124e76086 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -662,8 +662,9 @@ install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) install(FILES ${PROJECT_BINARY_DIR}/libuv.pc ${PROJECT_BINARY_DIR}/libuv-static.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(TARGETS uv EXPORT libuvConfig - RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(TARGETS uv_a ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(EXPORT libuvConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libuv) From cdced3a3ad1b3e4287f92c9d434b543a9e509938 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 1 Feb 2022 05:49:01 +0800 Subject: [PATCH 111/713] thread,win: fix C90 style nit (#3393) --- src/win/thread.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/win/thread.c b/src/win/thread.c index ea5dc04e9e5..d3b1c96b619 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -182,8 +182,9 @@ int uv_thread_create_ex(uv_thread_t* tid, uv_thread_t uv_thread_self(void) { + uv_thread_t key; uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key); - uv_thread_t key = uv_key_get(&uv__current_thread_key); + key = uv_key_get(&uv__current_thread_key); if (key == NULL) { /* If the thread wasn't started by uv_thread_create (such as the main * thread), we assign an id to it now. */ From 930af43437e6dddca715ebb4f2ff4b5e3602f19e Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 31 Jan 2022 16:50:32 -0500 Subject: [PATCH 112/713] build: rename CFLAGS to AM_CFLAGS (#3431) The CFLAGS variable is reserved and should never be set: https://www.gnu.org/software/automake/manual/html_node/User-Variables.html --- Makefile.am | 8 ++++---- m4/libuv-check-flags.m4 | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Makefile.am b/Makefile.am index 359d8a5c5b2..49faf82fb0c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,8 +27,8 @@ uvinclude_HEADERS = include/uv/errno.h \ CLEANFILES = lib_LTLIBRARIES = libuv.la -libuv_la_CFLAGS = @CFLAGS@ -libuv_la_LDFLAGS = -no-undefined -version-info 1:0:0 +libuv_la_CFLAGS = $(AM_CFLAGS) +libuv_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 1:0:0 libuv_la_SOURCES = src/fs-poll.c \ src/heap-inl.h \ src/idna.c \ @@ -131,7 +131,7 @@ EXTRA_DIST = test/fixtures/empty_file \ TESTS = test/run-tests check_PROGRAMS = test/run-tests -test_run_tests_CFLAGS = +test_run_tests_CFLAGS = $(AM_CFLAGS) if SUNOS # Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers @@ -139,7 +139,7 @@ if SUNOS test_run_tests_CFLAGS += -pthreads endif -test_run_tests_LDFLAGS = +test_run_tests_LDFLAGS = $(AM_LDFLAGS) test_run_tests_SOURCES = test/blackhole-server.c \ test/echo-server.c \ test/run-tests.c \ diff --git a/m4/libuv-check-flags.m4 b/m4/libuv-check-flags.m4 index e347056ae2e..46b9dd86a7d 100644 --- a/m4/libuv-check-flags.m4 +++ b/m4/libuv-check-flags.m4 @@ -1,6 +1,7 @@ dnl Macros to check the presence of generic (non-typed) symbols. dnl Copyright (c) 2006-2008 Diego Pettenò dnl Copyright (c) 2006-2008 xine project +dnl Copyright (c) 2021 libuv project dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by @@ -63,7 +64,7 @@ AC_DEFUN([CC_CHECK_CFLAGS], [ ]) dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found]) -dnl Check for CFLAG and appends them to CFLAGS if supported +dnl Check for CFLAG and appends them to AM_CFLAGS if supported AC_DEFUN([CC_CHECK_CFLAG_APPEND], [ AC_CACHE_CHECK([if $CC supports $1 flag], AS_TR_SH([cc_cv_cflags_$1]), @@ -71,7 +72,7 @@ AC_DEFUN([CC_CHECK_CFLAG_APPEND], [ ) AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], - [CFLAGS="$CFLAGS $1"; DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; $2], [$3]) + [AM_CFLAGS="$AM_CFLAGS $1"; DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; $2], [$3]) ]) dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not]) From 870828c8af077562c4394e243a399017552434ed Mon Sep 17 00:00:00 2001 From: woclass Date: Tue, 1 Feb 2022 05:52:42 +0800 Subject: [PATCH 113/713] doc/guide: update content and sample code (#3408) - Add `Makefile` for example codes. (cherry-pick from old uvbook repo) - Add a new example "Default loop" to "Basics of libuv"/"Default loop" - Document review and update: `Introduction`, `Basics of libuv`, `Filesystem` + Update the referenced libuv code snippet + Link update: http->https **Content Updates**: - `filesystem.rst`#L291-L297: Add note for `uv_fs_event_start` - `filesystem.rst`#L334: Add description of the callback function parameter `status` The following examples have been tested manually in WSL2 (Ubuntu 20.04) with libuv 1.42.0: - helloworld - default-loop - idle-basic - uvcat - uvtee - onchange (test on macOS) Co-authored-by: Nikhil Marathe --- docs/code/.gitignore | 3 ++ docs/code/Makefile | 82 +++++++++++++++++++++++++++++++++ docs/code/default-loop/main.c | 12 +++++ docs/src/guide/basics.rst | 23 +++++++-- docs/src/guide/filesystem.rst | 30 ++++++++---- docs/src/guide/introduction.rst | 18 ++++---- 6 files changed, 144 insertions(+), 24 deletions(-) create mode 100644 docs/code/.gitignore create mode 100644 docs/code/Makefile create mode 100644 docs/code/default-loop/main.c diff --git a/docs/code/.gitignore b/docs/code/.gitignore new file mode 100644 index 00000000000..c46ecde4c6f --- /dev/null +++ b/docs/code/.gitignore @@ -0,0 +1,3 @@ +*/* +!*.c +!*.h diff --git a/docs/code/Makefile b/docs/code/Makefile new file mode 100644 index 00000000000..0526e8c2eea --- /dev/null +++ b/docs/code/Makefile @@ -0,0 +1,82 @@ +examples=\ + helloworld\ + default-loop\ + idle-basic\ + uvcat\ + uvtee\ + onchange\ + thread-create\ + queue-work\ + progress\ + tcp-echo-server\ + dns\ + udp-dhcp\ + idle-compute\ + ref-timer\ + spawn\ + detach\ + proc-streams\ + cgi\ + pipe-echo-server\ + multi-echo-server\ + tty\ + tty-gravity\ + interfaces\ + locks \ + signal \ + uvstop \ + queue-cancel + +UV_PATH=$(shell pwd)/../.. +UV_LIB=$(UV_PATH)/.libs/libuv.a +CFLAGS=-g -Wall -I$(UV_PATH)/include +LIBS= + +uname_S=$(shell uname -s) + +ifeq (Darwin, $(uname_S)) +CFLAGS+=-framework CoreServices +SHARED_LIB_FLAGS=-bundle -undefined dynamic_lookup -o plugin/libhello.dylib +endif + +ifeq (Linux, $(uname_S)) +LIBS=-lrt -ldl -lm -pthread -lcurl +SHARED_LIB_FLAGS=-shared -Wl,-soname,libhello.so -o plugin/libhello.so +PLUGIN_EXE_FLAGS=-Wl,-export-dynamic +endif + + +all: $(examples) plugin/plugin proc-streams/test cgi/tick multi-echo-server/worker uvwget/uvwget + +$(examples): % : %/main.c + gcc $(CFLAGS) -o $@/$@ $< $(UV_LIB) $(LIBS) + +plugin: plugin/plugin +plugin/plugin: plugin/*.c + gcc $(CFLAGS) $(PLUGIN_EXE_FLAGS) -o plugin/plugin plugin/main.c $(UV_LIB) $(LIBS) + gcc -g -Wall -c -fPIC -o plugin/hello.o plugin/hello.c + gcc $(SHARED_LIB_FLAGS) plugin/hello.o + +proc-streams/test: proc-streams/test.c + gcc -g -Wall -o proc-streams/test proc-streams/test.c + +cgi/tick: cgi/tick.c + gcc -g -Wall -o cgi/tick cgi/tick.c + +multi-echo-server/worker: multi-echo-server/worker.c + gcc $(CFLAGS) -o multi-echo-server/worker multi-echo-server/worker.c $(UV_LIB) $(LIBS) + +uvwget: uvwget/uvwget +uvwget/uvwget: uvwget/main.c + gcc $(CFLAGS) `curl-config --cflags --libs` -o uvwget/uvwget uvwget/main.c $(UV_LIB) $(LIBS) + +clean: + for dir in $(examples); do cd $$dir; rm -f $$dir; rm -rf $$dir.dSYM; cd ..; done + rm -rf plugin/*.o plugin/libhello.* + rm -rf plugin/plugin plugin/plugin.dSYM + rm -rf proc-streams/test proc-streams/test.dSYM + rm -rf cgi/tick cgi/tick.dSYM + rm -rf multi-echo-server/worker multi-echo-server/worker.dSYM + rm -rf uvwget/uvwget uvwget/uvwget.dSYM + +.PHONY: clean all $(examples) plugin uvwget diff --git a/docs/code/default-loop/main.c b/docs/code/default-loop/main.c new file mode 100644 index 00000000000..e00a4d2bbe0 --- /dev/null +++ b/docs/code/default-loop/main.c @@ -0,0 +1,12 @@ +#include +#include + +int main() { + uv_loop_t *loop = uv_default_loop(); + + printf("Default loop.\n"); + uv_run(loop, UV_RUN_DEFAULT); + + uv_loop_close(loop); + return 0; +} diff --git a/docs/src/guide/basics.rst b/docs/src/guide/basics.rst index 457fb15cbe8..2b21d730c30 100644 --- a/docs/src/guide/basics.rst +++ b/docs/src/guide/basics.rst @@ -71,7 +71,7 @@ architecture of libuv and its background. If you have no prior experience with either libuv or libev, it is a quick, useful watch. libuv's event loop is explained in more detail in the `documentation -`_. +`_. .. raw:: html @@ -109,6 +109,11 @@ A default loop is provided by libuv and can be accessed using ``uv_default_loop()``. You should use this loop if you only want a single loop. +.. rubric:: default-loop/main.c +.. literalinclude:: ../../code/default-loop/main.c + :language: c + :linenos: + .. note:: node.js uses the default loop as its main loop. If you are writing bindings @@ -119,9 +124,9 @@ loop. Error handling -------------- -Initialization functions or synchronous functions which may fail return a negative number on error. Async functions that may fail will pass a status parameter to their callbacks. The error messages are defined as ``UV_E*`` `constants`_. +Initialization functions or synchronous functions which may fail return a negative number on error. Async functions that may fail will pass a status parameter to their callbacks. The error messages are defined as ``UV_E*`` `constants`_. -.. _constants: http://docs.libuv.org/en/v1.x/errors.html#error-constants +.. _constants: https://docs.libuv.org/en/v1.x/errors.html#error-constants You can use the ``uv_strerror(int)`` and ``uv_err_name(int)`` functions to get a ``const char *`` describing the error or the error name respectively. @@ -134,7 +139,7 @@ Handles and Requests libuv works by the user expressing interest in particular events. This is usually done by creating a **handle** to an I/O device, timer or process. Handles are opaque structs named as ``uv_TYPE_t`` where type signifies what the -handle is used for. +handle is used for. .. rubric:: libuv watchers .. code-block:: c @@ -169,6 +174,16 @@ handle is used for. typedef struct uv_udp_send_s uv_udp_send_t; typedef struct uv_fs_s uv_fs_t; typedef struct uv_work_s uv_work_t; + typedef struct uv_random_s uv_random_t; + + /* None of the above. */ + typedef struct uv_env_item_s uv_env_item_t; + typedef struct uv_cpu_info_s uv_cpu_info_t; + typedef struct uv_interface_address_s uv_interface_address_t; + typedef struct uv_dirent_s uv_dirent_t; + typedef struct uv_passwd_s uv_passwd_t; + typedef struct uv_utsname_s uv_utsname_t; + typedef struct uv_statfs_s uv_statfs_t; Handles represent long-lived objects. Async operations on such handles are diff --git a/docs/src/guide/filesystem.rst b/docs/src/guide/filesystem.rst index 2d5f6cb9250..c0bfbf5b54e 100644 --- a/docs/src/guide/filesystem.rst +++ b/docs/src/guide/filesystem.rst @@ -13,7 +13,7 @@ Simple filesystem read/write is achieved using the ``uv_fs_*`` functions and the watchers registered with the event loop when application interaction is required. -.. _thread pool: http://docs.libuv.org/en/v1.x/threadpool.html#thread-pool-work-scheduling +.. _thread pool: https://docs.libuv.org/en/v1.x/threadpool.html#thread-pool-work-scheduling All filesystem functions have two forms - *synchronous* and *asynchronous*. @@ -66,7 +66,7 @@ The ``result`` field of a ``uv_fs_t`` is the file descriptor in case of the .. literalinclude:: ../../code/uvcat/main.c :language: c :linenos: - :lines: 26-40 + :lines: 26-39 :emphasize-lines: 2,8,12 In the case of a read call, you should pass an *initialized* buffer which will @@ -91,7 +91,7 @@ callbacks. .. literalinclude:: ../../code/uvcat/main.c :language: c :linenos: - :lines: 16-24 + :lines: 17-24 :emphasize-lines: 6 .. warning:: @@ -132,6 +132,7 @@ same patterns as the read/write/open calls, returning the result in the int uv_fs_copyfile(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb); int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb); int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, uv_fs_cb cb); + int uv_fs_mkstemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, uv_fs_cb cb); int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb); int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb); int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent); @@ -149,6 +150,7 @@ same patterns as the read/write/open calls, returning the result in the int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb); int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb); int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, double mtime, uv_fs_cb cb); + int uv_fs_lutime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb); int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb); int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb); int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb); @@ -158,6 +160,7 @@ same patterns as the read/write/open calls, returning the result in the int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb); int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb); int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb); + int uv_fs_statfs(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb); .. _buffers-and-streams: @@ -190,7 +193,7 @@ and freed by the application. .. ERROR:: - THIS PROGRAM DOES NOT ALWAYS WORK, NEED SOMETHING BETTER** + **THIS PROGRAM DOES NOT ALWAYS WORK, NEED SOMETHING BETTER** To demonstrate streams we will need to use ``uv_pipe_t``. This allows streaming local files [#]_. Here is a simple tee utility using libuv. Doing all operations @@ -209,7 +212,7 @@ opened as bidirectional by default. .. literalinclude:: ../../code/uvtee/main.c :language: c :linenos: - :lines: 61-80 + :lines: 62-80 :emphasize-lines: 4,5,15 The third argument of ``uv_pipe_init()`` should be set to 1 for IPC using named @@ -285,6 +288,13 @@ a command whenever any of the watched files change:: ./onchange [file2] ... +.. note:: + + Currently this example only works on OSX and Windows. + Refer to the `notes of uv_fs_event_start`_ function. + +.. _notes of uv_fs_event_start: https://docs.libuv.org/en/v1.x/fs_event.html#c.uv_fs_event_start + The file change notification is started using ``uv_fs_event_init()``: .. rubric:: onchange/main.c - The setup @@ -300,8 +310,8 @@ argument, ``flags``, can be: .. code-block:: c /* - * Flags to be passed to uv_fs_event_start(). - */ + * Flags to be passed to uv_fs_event_start(). + */ enum uv_fs_event_flags { UV_FS_EVENT_WATCH_ENTRY = 1, UV_FS_EVENT_STAT = 2, @@ -319,9 +329,9 @@ The callback will receive the following arguments: #. ``const char *filename`` - If a directory is being monitored, this is the file which was changed. Only non-``null`` on Linux and Windows. May be ``null`` even on those platforms. - #. ``int flags`` - one of ``UV_RENAME`` or ``UV_CHANGE``, or a bitwise OR of - both. - #. ``int status`` - Currently 0. + #. ``int events`` - one of ``UV_RENAME`` or ``UV_CHANGE``, or a bitwise OR of + both. + #. ``int status`` - If ``status < 0``, there is an :ref:`libuv error`. In our example we simply print the arguments and run the command using ``system()``. diff --git a/docs/src/guide/introduction.rst b/docs/src/guide/introduction.rst index 0656e4d852f..819e9f759f3 100644 --- a/docs/src/guide/introduction.rst +++ b/docs/src/guide/introduction.rst @@ -8,7 +8,7 @@ It is meant to cover the main areas of libuv, but is not a comprehensive reference discussing every function and data structure. The `official libuv documentation`_ may be consulted for full details. -.. _official libuv documentation: http://docs.libuv.org/en/v1.x/ +.. _official libuv documentation: https://docs.libuv.org/en/v1.x/ This book is still a work in progress, so sections may be incomplete, but I hope you will enjoy it as it grows. @@ -47,25 +47,23 @@ Since then libuv has continued to mature and become a high quality standalone library for system programming. Users outside of node.js include Mozilla's Rust_ programming language, and a variety_ of language bindings. -This book and the code is based on libuv version `v1.3.0`_. +This book and the code is based on libuv version `v1.42.0`_. Code ---- -All the code from this book is included as part of the source of the book on -Github. `Clone`_/`Download`_ the book, then build libuv:: +All the example code and the source of the book is included as part of +the libuv_ project on Github. +Clone or Download libuv_, then build it:: - cd libuv - ./autogen.sh + sh autogen.sh ./configure make There is no need to ``make install``. To build the examples run ``make`` in the -``code/`` directory. +``docs/code/`` directory. -.. _Clone: https://github.com/nikhilm/uvbook -.. _Download: https://github.com/nikhilm/uvbook/downloads -.. _v1.3.0: https://github.com/libuv/libuv/tags +.. _v1.42.0: https://github.com/libuv/libuv/releases/tag/v1.42.0 .. _V8: https://v8.dev .. _libev: http://software.schmorp.de/pkg/libev.html .. _libuv: https://github.com/libuv/libuv From 953f901dd2330a9979838cd43ff04eacde71b25a Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 1 Feb 2022 15:27:12 -0500 Subject: [PATCH 114/713] process,bsd: handle kevent NOTE_EXIT failure (#3451) The kernel may return ESRCH if the child has already exited here. This is rather annoying, and means we must indirectly handle notification to our event loop of the process exit. Refs: https://github.com/libuv/libuv/pull/3441 Refs: https://github.com/libuv/libuv/pull/3257 --- src/unix/internal.h | 3 ++- src/unix/kqueue.c | 7 ++++++- src/unix/process.c | 8 ++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/unix/internal.h b/src/unix/internal.h index 16be13b99f5..2dcc8b32f51 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -145,7 +145,8 @@ typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t; /* loop flags */ enum { - UV_LOOP_BLOCK_SIGPROF = 1 + UV_LOOP_BLOCK_SIGPROF = 0x1, + UV_LOOP_REAP_CHILDREN = 0x2 }; /* flags of excluding ifaddr */ diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index efbc561dee2..857eb1d54bf 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -285,7 +285,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { for (i = 0; i < nfds; i++) { ev = events + i; if (ev->filter == EVFILT_PROC) { - uv__wait_children(loop); + loop->flags |= UV_LOOP_REAP_CHILDREN; nevents++; continue; } @@ -382,6 +382,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { nevents++; } + if (loop->flags & UV_LOOP_REAP_CHILDREN) { + loop->flags &= ~UV_LOOP_REAP_CHILDREN; + uv__wait_children(loop); + } + if (reset_timeout != 0) { timeout = user_timeout; reset_timeout = 0; diff --git a/src/unix/process.c b/src/unix/process.c index c1f6bd4b007..2920b942962 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -507,8 +507,12 @@ int uv_spawn(uv_loop_t* loop, #if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) struct kevent event; EV_SET(&event, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, 0); - if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) - abort(); + if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) { + if (errno != ESRCH) + abort(); + /* Process already exited. Call waitpid on the next loop iteration. */ + loop->flags |= UV_LOOP_REAP_CHILDREN; + } #endif QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); From 038086dc0867a9f37fe1a27f5c1ae6348e1457d6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 8 Feb 2022 14:18:10 +0100 Subject: [PATCH 115/713] test: remove flaky test ipc_closed_handle (#3464) The test is very flaky, both on the CI and on people's local machines. I spent some time trying to fix it but its design is fairly questionable and it fails to test what it should more often than not because on fast machines no queueing of data takes place. Fixes #2307. --- test/run-tests.c | 5 -- test/test-ipc.c | 127 ----------------------------------------------- test/test-list.h | 6 --- 3 files changed, 138 deletions(-) diff --git a/test/run-tests.c b/test/run-tests.c index 5e53aaa80b1..86b0359949b 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -49,7 +49,6 @@ __attribute__((constructor)) void init() { int ipc_helper(int listen_after_write); int ipc_helper_heavy_traffic_deadlock_bug(void); int ipc_helper_tcp_connection(void); -int ipc_helper_closed_handle(void); int ipc_send_recv_helper(void); int ipc_helper_bind_twice(void); int ipc_helper_send_zero(void); @@ -119,10 +118,6 @@ static int maybe_run_test(int argc, char **argv) { return ipc_helper_tcp_connection(); } - if (strcmp(argv[1], "ipc_helper_closed_handle") == 0) { - return ipc_helper_closed_handle(); - } - if (strcmp(argv[1], "ipc_helper_bind_twice") == 0) { return ipc_helper_bind_twice(); } diff --git a/test/test-ipc.c b/test/test-ipc.c index 68a0e1bb814..cf131ffd193 100644 --- a/test/test-ipc.c +++ b/test/test-ipc.c @@ -45,8 +45,6 @@ static int close_cb_called; static int connection_accepted; static int tcp_conn_read_cb_called; static int tcp_conn_write_cb_called; -static int closed_handle_data_read; -static int closed_handle_write; static int send_zero_write; typedef struct { @@ -57,15 +55,6 @@ typedef struct { #define CONN_COUNT 100 #define BACKLOG 128 -#define LARGE_SIZE 100000 - -static uv_buf_t large_buf; -static char buffer[LARGE_SIZE]; -static uv_write_t write_reqs[300]; -static int write_reqs_completed; - -static unsigned int write_until_data_queued(void); -static void send_handle_and_close(void); static void close_server_conn_cb(uv_handle_t* handle) { @@ -417,26 +406,6 @@ static void on_read_connection(uv_stream_t* handle, } -#ifndef _WIN32 -static void on_read_closed_handle(uv_stream_t* handle, - ssize_t nread, - const uv_buf_t* buf) { - if (nread == 0 || nread == UV_EOF) { - free(buf->base); - return; - } - - if (nread < 0) { - printf("error recving on channel: %s\n", uv_strerror(nread)); - abort(); - } - - closed_handle_data_read += nread; - free(buf->base); -} -#endif - - static void on_read_send_zero(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { @@ -498,15 +467,6 @@ TEST_IMPL(ipc_tcp_connection) { return r; } -#ifndef _WIN32 -TEST_IMPL(ipc_closed_handle) { - int r; - r = run_ipc_test("ipc_helper_closed_handle", on_read_closed_handle); - ASSERT_EQ(r, 0); - return 0; -} -#endif - #ifdef _WIN32 TEST_IMPL(listen_with_simultaneous_accepts) { @@ -602,23 +562,6 @@ static void tcp_connection_write_cb(uv_write_t* req, int status) { } -static void closed_handle_large_write_cb(uv_write_t* req, int status) { - ASSERT_EQ(status, 0); - ASSERT(closed_handle_data_read = LARGE_SIZE); - if (++write_reqs_completed == ARRAY_SIZE(write_reqs)) { - write_reqs_completed = 0; - if (write_until_data_queued() > 0) - send_handle_and_close(); - } -} - - -static void closed_handle_write_cb(uv_write_t* req, int status) { - ASSERT_EQ(status, UV_EBADF); - closed_handle_write = 1; -} - - static void send_zero_write_cb(uv_write_t* req, int status) { ASSERT_EQ(status, 0); send_zero_write++; @@ -835,76 +778,6 @@ int ipc_helper_tcp_connection(void) { return 0; } -static unsigned int write_until_data_queued() { - unsigned int i; - int r; - - i = 0; - do { - r = uv_write(&write_reqs[i], - (uv_stream_t*)&channel, - &large_buf, - 1, - closed_handle_large_write_cb); - ASSERT_EQ(r, 0); - i++; - } while (channel.write_queue_size == 0 && - i < ARRAY_SIZE(write_reqs)); - - return channel.write_queue_size; -} - -static void send_handle_and_close() { - int r; - struct sockaddr_in addr; - - r = uv_tcp_init(uv_default_loop(), &tcp_server); - ASSERT_EQ(r, 0); - - ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); - - r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); - ASSERT_EQ(r, 0); - - r = uv_write2(&write_req, - (uv_stream_t*)&channel, - &large_buf, - 1, - (uv_stream_t*)&tcp_server, - closed_handle_write_cb); - ASSERT_EQ(r, 0); - - uv_close((uv_handle_t*)&tcp_server, NULL); -} - -int ipc_helper_closed_handle(void) { - int r; - - memset(buffer, '.', LARGE_SIZE); - large_buf = uv_buf_init(buffer, LARGE_SIZE); - - r = uv_pipe_init(uv_default_loop(), &channel, 1); - ASSERT_EQ(r, 0); - - uv_pipe_open(&channel, 0); - - ASSERT_EQ(1, uv_is_readable((uv_stream_t*) &channel)); - ASSERT_EQ(1, uv_is_writable((uv_stream_t*) &channel)); - ASSERT_EQ(0, uv_is_closing((uv_handle_t*) &channel)); - - if (write_until_data_queued() > 0) - send_handle_and_close(); - - r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(r, 0); - - ASSERT_EQ(closed_handle_write, 1); - - MAKE_VALGRIND_HAPPY(); - return 0; -} - - int ipc_helper_bind_twice(void) { /* * This is launched from test-ipc.c. stdin is a duplex channel diff --git a/test/test-list.h b/test/test-list.h index a43edf1a4a9..15a3bad05a6 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -91,9 +91,6 @@ TEST_DECLARE (ipc_send_recv_tcp) TEST_DECLARE (ipc_send_recv_tcp_inprocess) TEST_DECLARE (ipc_tcp_connection) TEST_DECLARE (ipc_send_zero) -#ifndef _WIN32 -TEST_DECLARE (ipc_closed_handle) -#endif TEST_DECLARE (tcp_alloc_cb_fail) TEST_DECLARE (tcp_ping_pong) TEST_DECLARE (tcp_ping_pong_vec) @@ -628,9 +625,6 @@ TASK_LIST_START TEST_ENTRY (ipc_send_recv_tcp_inprocess) TEST_ENTRY (ipc_tcp_connection) TEST_ENTRY (ipc_send_zero) -#ifndef _WIN32 - TEST_ENTRY (ipc_closed_handle) -#endif TEST_ENTRY (tcp_alloc_cb_fail) From de24da8c111687a2871d528052f5442e9b371ca1 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 8 Feb 2022 14:18:29 +0100 Subject: [PATCH 116/713] darwin: bump minimum supported version to 10.15 (#3406) We can't realistically claim to support 10.7 or any version that Apple no longer supports so let's bump the baseline to something more realistic. Refs: https://github.com/libuv/libuv/pull/482 Refs: https://github.com/libuv/libuv/pull/3405 --- SUPPORTED_PLATFORMS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 4d8ea07ce88..7b33cbbed94 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -3,7 +3,7 @@ | System | Support type | Supported versions | Notes | |---|---|---|---| | GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | | -| macOS | Tier 1 | macOS >= 10.7 | | +| macOS | Tier 1 | macOS >= 10.15 | Current and previous macOS release | | Windows | Tier 1 | >= Windows 8 | VS 2015 and later are supported | | FreeBSD | Tier 1 | >= 10 | | | AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | From 50c1d00839d050cc3071cdba27083ceca3593a33 Mon Sep 17 00:00:00 2001 From: Luca Adrian L Date: Tue, 8 Feb 2022 14:23:39 +0100 Subject: [PATCH 117/713] win: return fractional seconds in uv_uptime() (#3455) Some systems return fractional seconds, some return full seconds. On Windows uptime was artificially rounded down. Fixes #3447. --- docs/src/misc.rst | 2 +- src/win/util.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 8017e8e1596..38fbb56081e 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -312,7 +312,7 @@ API .. c:function:: int uv_uptime(double* uptime) - Gets the current system uptime. + Gets the current system uptime. Depending on the system full or fractional seconds are returned. .. c:function:: int uv_getrusage(uv_rusage_t* rusage) diff --git a/src/win/util.c b/src/win/util.c index 33e874ac442..5283602f210 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -608,8 +608,8 @@ int uv_uptime(double* uptime) { BYTE* address = (BYTE*) object_type + object_type->DefinitionLength + counter_definition->CounterOffset; uint64_t value = *((uint64_t*) address); - *uptime = floor((double) (object_type->PerfTime.QuadPart - value) / - (double) object_type->PerfFreq.QuadPart); + *uptime = (double) (object_type->PerfTime.QuadPart - value) / + (double) object_type->PerfFreq.QuadPart; uv__free(malloced_buffer); return 0; } From 7a68f5ab4b3b7a4aada44ffa0f7addc295174c7b Mon Sep 17 00:00:00 2001 From: WenTao Ou Date: Wed, 9 Feb 2022 00:43:19 +0800 Subject: [PATCH 118/713] build: export uv_a for cmake (#3373) --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b124e76086..9c3f997190c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -665,7 +665,8 @@ install(TARGETS uv EXPORT libuvConfig RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(TARGETS uv_a ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(TARGETS uv_a EXPORT libuvConfig + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(EXPORT libuvConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libuv) if(MSVC) From 939a05633f99eeba8f4fb5dfff0e7bab940f361b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 13 Feb 2022 00:12:11 -0500 Subject: [PATCH 119/713] loop: add pending work to loop-alive check (#3466) Pending work may be either (on any platform) pending_queue callbacks or (on unix) watcher_queue handles to add to the io poll object. Previously, we might have gotten somewhat stuck if the user caused an event to be added to one of these in the idle or prepare callbacks, or was embedding libuv. Refs: https://github.com/libuv/libuv/pull/3234 Refs: https://github.com/libuv/libuv/issues/3101 Refs: https://github.com/libuv/libuv/pull/3308 --- src/unix/core.c | 41 +++++++++++++++++++++-------------------- src/win/core.c | 43 ++++++++++++++++++------------------------- test/test-loop-time.c | 24 +++++++++++++++--------- 3 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 3dd3fd90a8e..e14c327ea50 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -334,35 +334,36 @@ int uv_backend_fd(const uv_loop_t* loop) { } -int uv_backend_timeout(const uv_loop_t* loop) { - if (loop->stop_flag != 0) - return 0; - - if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) - return 0; - - if (!QUEUE_EMPTY(&loop->idle_handles)) - return 0; - - if (!QUEUE_EMPTY(&loop->pending_queue)) - return 0; +static int uv__loop_alive(const uv_loop_t* loop) { + return uv__has_active_handles(loop) || + uv__has_active_reqs(loop) || + !QUEUE_EMPTY(&loop->pending_queue) || + loop->closing_handles != NULL; +} - if (loop->closing_handles) - return 0; - return uv__next_timeout(loop); +static int uv__backend_timeout(const uv_loop_t* loop) { + if (loop->stop_flag == 0 && + /* uv__loop_alive(loop) && */ + (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) && + QUEUE_EMPTY(&loop->pending_queue) && + QUEUE_EMPTY(&loop->idle_handles) && + loop->closing_handles == NULL) + return uv__next_timeout(loop); + return 0; } -static int uv__loop_alive(const uv_loop_t* loop) { - return uv__has_active_handles(loop) || - uv__has_active_reqs(loop) || - loop->closing_handles != NULL; +int uv_backend_timeout(const uv_loop_t* loop) { + if (QUEUE_EMPTY(&loop->watcher_queue)) + return uv__backend_timeout(loop); + /* Need to call uv_run to update the backend fd state. */ + return 0; } int uv_loop_alive(const uv_loop_t* loop) { - return uv__loop_alive(loop); + return uv__loop_alive(loop); } diff --git a/src/win/core.c b/src/win/core.c index e53a0f8e286..68409e37085 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -395,23 +395,28 @@ int uv_loop_fork(uv_loop_t* loop) { } -int uv_backend_timeout(const uv_loop_t* loop) { - if (loop->stop_flag != 0) - return 0; - - if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) - return 0; +static int uv__loop_alive(const uv_loop_t* loop) { + return uv__has_active_handles(loop) || + uv__has_active_reqs(loop) || + loop->pending_reqs_tail != NULL || + loop->endgame_handles != NULL; +} - if (loop->pending_reqs_tail) - return 0; - if (loop->endgame_handles) - return 0; +int uv_loop_alive(const uv_loop_t* loop) { + return uv__loop_alive(loop); +} - if (loop->idle_handles) - return 0; - return uv__next_timeout(loop); +int uv_backend_timeout(const uv_loop_t* loop) { + if (loop->stop_flag == 0 && + /* uv__loop_alive(loop) && */ + (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) && + loop->pending_reqs_tail == NULL && + loop->idle_handles == NULL && + loop->endgame_handles == NULL) + return uv__next_timeout(loop); + return 0; } @@ -581,18 +586,6 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { } -static int uv__loop_alive(const uv_loop_t* loop) { - return uv__has_active_handles(loop) || - uv__has_active_reqs(loop) || - loop->endgame_handles != NULL; -} - - -int uv_loop_alive(const uv_loop_t* loop) { - return uv__loop_alive(loop); -} - - int uv_run(uv_loop_t *loop, uv_run_mode mode) { DWORD timeout; int r; diff --git a/test/test-loop-time.c b/test/test-loop-time.c index a2db42cceec..087720b9e9e 100644 --- a/test/test-loop-time.c +++ b/test/test-loop-time.c @@ -28,7 +28,7 @@ TEST_IMPL(loop_update_time) { start = uv_now(uv_default_loop()); while (uv_now(uv_default_loop()) - start < 1000) - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_NOWAIT)); MAKE_VALGRIND_HAPPY(); return 0; @@ -43,20 +43,26 @@ TEST_IMPL(loop_backend_timeout) { uv_timer_t timer; int r; + /* The default loop has some internal watchers to initialize. */ + loop->active_handles++; + r = uv_run(loop, UV_RUN_NOWAIT); + ASSERT_EQ(r, 1); + loop->active_handles--; + ASSERT_EQ(uv_loop_alive(loop), 0); + r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_EQ(r, 0); - ASSERT(!uv_loop_alive(loop)); - ASSERT(uv_backend_timeout(loop) == 0); + ASSERT_EQ(uv_loop_alive(loop), 0); + ASSERT_EQ(uv_backend_timeout(loop), 0); r = uv_timer_start(&timer, cb, 1000, 0); /* 1 sec */ - ASSERT(r == 0); - ASSERT(uv_backend_timeout(loop) > 100); /* 0.1 sec */ - ASSERT(uv_backend_timeout(loop) <= 1000); /* 1 sec */ + ASSERT_EQ(r, 0); + ASSERT_EQ(uv_backend_timeout(loop), 1000); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); - ASSERT(uv_backend_timeout(loop) == 0); + ASSERT_EQ(r, 0); + ASSERT_EQ(uv_backend_timeout(loop), 0); MAKE_VALGRIND_HAPPY(); return 0; From d0e500c8769dbc08725f1bfedd562a0c1d5a0cae Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 13 Feb 2022 00:24:34 -0500 Subject: [PATCH 120/713] win: use GetTickCount64 for uptime again (#3470) Reverts 442aa1f4696d24a605790b8ad4317696758ee8de, since this is an improved API in Windows Vista that is now usable as a replacement. It simplifies the code substantially, while returning nearly the same result (on my system, the performance counters were 6 seconds behind). The old code also did not work on Wine-5.0 (where I observed that `data_size == data_block->HeaderLength`, and so no data was present). --- src/win/util.c | 99 +------------------------------------------------- 1 file changed, 2 insertions(+), 97 deletions(-) diff --git a/src/win/util.c b/src/win/util.c index 5283602f210..ee70ebc2083 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -531,103 +531,8 @@ int uv_resident_set_memory(size_t* rss) { int uv_uptime(double* uptime) { - BYTE stack_buffer[4096]; - BYTE* malloced_buffer = NULL; - BYTE* buffer = (BYTE*) stack_buffer; - size_t buffer_size = sizeof(stack_buffer); - DWORD data_size; - - PERF_DATA_BLOCK* data_block; - PERF_OBJECT_TYPE* object_type; - PERF_COUNTER_DEFINITION* counter_definition; - - DWORD i; - - for (;;) { - LONG result; - - data_size = (DWORD) buffer_size; - result = RegQueryValueExW(HKEY_PERFORMANCE_DATA, - L"2", - NULL, - NULL, - buffer, - &data_size); - if (result == ERROR_SUCCESS) { - break; - } else if (result != ERROR_MORE_DATA) { - *uptime = 0; - return uv_translate_sys_error(result); - } - - buffer_size *= 2; - /* Don't let the buffer grow infinitely. */ - if (buffer_size > 1 << 20) { - goto internalError; - } - - uv__free(malloced_buffer); - - buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size); - if (malloced_buffer == NULL) { - *uptime = 0; - return UV_ENOMEM; - } - } - - if (data_size < sizeof(*data_block)) - goto internalError; - - data_block = (PERF_DATA_BLOCK*) buffer; - - if (wmemcmp(data_block->Signature, L"PERF", 4) != 0) - goto internalError; - - if (data_size < data_block->HeaderLength + sizeof(*object_type)) - goto internalError; - - object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength); - - if (object_type->NumInstances != PERF_NO_INSTANCES) - goto internalError; - - counter_definition = (PERF_COUNTER_DEFINITION*) (buffer + - data_block->HeaderLength + object_type->HeaderLength); - for (i = 0; i < object_type->NumCounters; i++) { - if ((BYTE*) counter_definition + sizeof(*counter_definition) > - buffer + data_size) { - break; - } - - if (counter_definition->CounterNameTitleIndex == 674 && - counter_definition->CounterSize == sizeof(uint64_t)) { - if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size || - !(counter_definition->CounterType & PERF_OBJECT_TIMER)) { - goto internalError; - } else { - BYTE* address = (BYTE*) object_type + object_type->DefinitionLength + - counter_definition->CounterOffset; - uint64_t value = *((uint64_t*) address); - *uptime = (double) (object_type->PerfTime.QuadPart - value) / - (double) object_type->PerfFreq.QuadPart; - uv__free(malloced_buffer); - return 0; - } - } - - counter_definition = (PERF_COUNTER_DEFINITION*) - ((BYTE*) counter_definition + counter_definition->ByteLength); - } - - /* If we get here, the uptime value was not found. */ - uv__free(malloced_buffer); - *uptime = 0; - return UV_ENOSYS; - - internalError: - uv__free(malloced_buffer); - *uptime = 0; - return UV_EIO; + *uptime = GetTickCount64() / 1000.0; + return 0; } From cf7f70c25d399ea3d194bcc7d8c797b609b53959 Mon Sep 17 00:00:00 2001 From: jonilaitinen Date: Sun, 13 Feb 2022 13:26:55 +0800 Subject: [PATCH 121/713] win: restrict system DLL load paths (#3395) Currently `LoadLibraryA` call first attempts to load the given DLL from the application working directory before loading it from the system DLL path. This may pose a security risk if an attacker is able to place a malicious DLL into the application working directory as that DLL will be loaded instead of the system DLL. This is especially dangerous if the application is running with elevated privileges. This changes the DLL loading to use `LoadLibraryExA` method with `LOAD_LIBRARY_SEARCH_SYSTEM32` flag which restricts the DLL load path to system DLL path, ignoring any DLLs in the application working directory. --- src/win/winapi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/win/winapi.c b/src/win/winapi.c index bf306cd83bd..c04af61ba42 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -126,19 +126,19 @@ void uv_winapi_init(void) { kernel32_module, "GetQueuedCompletionStatusEx"); - powrprof_module = LoadLibraryA("powrprof.dll"); + powrprof_module = LoadLibraryExA("powrprof.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (powrprof_module != NULL) { pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification"); } - user32_module = LoadLibraryA("user32.dll"); + user32_module = GetModuleHandleA("user32.dll"); if (user32_module != NULL) { pSetWinEventHook = (sSetWinEventHook) GetProcAddress(user32_module, "SetWinEventHook"); } - ws2_32_module = LoadLibraryA("ws2_32.dll"); + ws2_32_module = GetModuleHandleA("ws2_32.dll"); if (ws2_32_module != NULL) { pGetHostNameW = (uv_sGetHostNameW) GetProcAddress( ws2_32_module, From 04a35efe69001a27e177aebde6c8db6f4cca7e4b Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Sun, 13 Feb 2022 11:01:59 +0530 Subject: [PATCH 122/713] win,errors: remap ERROR_ACCESS_DENIED to UV_EACCES (#3193) If we try to use uv_fs_rmdir on a read-only directory on Windows, it internally calls _wrmdir, which sets _doserrno to ERROR_ACCESS_DENIED and errno to EACCES. However, ERROR_ACCESS_DENIED is mapped to UV_EPERM, so I believe it should be remapped to UV_EACCES. --- src/win/error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/error.c b/src/win/error.c index 3a269da87a9..20ac19ef6e0 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -73,6 +73,7 @@ int uv_translate_sys_error(int sys_errno) { case WSAEACCES: return UV_EACCES; case ERROR_ELEVATION_REQUIRED: return UV_EACCES; case ERROR_CANT_ACCESS_FILE: return UV_EACCES; + case ERROR_ACCESS_DENIED: return UV_EACCES; case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; case WSAEADDRINUSE: return UV_EADDRINUSE; case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; @@ -154,7 +155,6 @@ int uv_translate_sys_error(int sys_errno) { case WSAENOTSOCK: return UV_ENOTSOCK; case ERROR_NOT_SUPPORTED: return UV_ENOTSUP; case ERROR_BROKEN_PIPE: return UV_EOF; - case ERROR_ACCESS_DENIED: return UV_EPERM; case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM; case ERROR_BAD_PIPE: return UV_EPIPE; case ERROR_NO_DATA: return UV_EPIPE; From 636cb8633b6c23cd7c5a72b916af84fb171c4a1e Mon Sep 17 00:00:00 2001 From: Momtchil Momtchev Date: Sun, 13 Feb 2022 06:40:35 +0100 Subject: [PATCH 123/713] bench: add `uv_queue_work` ping-pong measurement (#3425) --- CMakeLists.txt | 1 + test/benchmark-list.h | 2 ++ test/benchmark-queue-work.c | 68 +++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 test/benchmark-queue-work.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c3f997190c..881df67ce97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,6 +417,7 @@ if(LIBUV_BUILD_TESTS) test/benchmark-fs-stat.c test/benchmark-getaddrinfo.c test/benchmark-loop-count.c + test/benchmark-queue-work.c test/benchmark-million-async.c test/benchmark-million-timers.c test/benchmark-multi-accept.c diff --git a/test/benchmark-list.h b/test/benchmark-list.h index 71e4eab9a57..4e6dc33c542 100644 --- a/test/benchmark-list.h +++ b/test/benchmark-list.h @@ -72,6 +72,7 @@ BENCHMARK_DECLARE (async_pummel_1) BENCHMARK_DECLARE (async_pummel_2) BENCHMARK_DECLARE (async_pummel_4) BENCHMARK_DECLARE (async_pummel_8) +BENCHMARK_DECLARE (queue_work) BENCHMARK_DECLARE (spawn) BENCHMARK_DECLARE (thread_create) BENCHMARK_DECLARE (million_async) @@ -155,6 +156,7 @@ TASK_LIST_START BENCHMARK_ENTRY (async_pummel_2) BENCHMARK_ENTRY (async_pummel_4) BENCHMARK_ENTRY (async_pummel_8) + BENCHMARK_ENTRY (queue_work) BENCHMARK_ENTRY (spawn) BENCHMARK_ENTRY (thread_create) diff --git a/test/benchmark-queue-work.c b/test/benchmark-queue-work.c new file mode 100644 index 00000000000..2dd5cb66561 --- /dev/null +++ b/test/benchmark-queue-work.c @@ -0,0 +1,68 @@ +/* Copyright libuv contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "task.h" +#include "uv.h" + +static int done = 0; +static unsigned events = 0; +static unsigned result; + +static unsigned fastrand(void) { + static unsigned g = 0; + g = g * 214013 + 2531011; + return g; +} + +static void work_cb(uv_work_t* req) { + req->data = &result; + *(unsigned*)req->data = fastrand(); +} + +static void after_work_cb(uv_work_t* req, int status) { + events++; + if (!done) + ASSERT_EQ(0, uv_queue_work(req->loop, req, work_cb, after_work_cb)); +} + +static void timer_cb(uv_timer_t* handle) { done = 1; } + +BENCHMARK_IMPL(queue_work) { + uv_timer_t timer_handle; + uv_work_t work; + uv_loop_t* loop; + int timeout; + + loop = uv_default_loop(); + timeout = 5000; + + ASSERT_EQ(0, uv_timer_init(loop, &timer_handle)); + ASSERT_EQ(0, uv_timer_start(&timer_handle, timer_cb, timeout, 0)); + + ASSERT_EQ(0, uv_queue_work(loop, &work, work_cb, after_work_cb)); + ASSERT_EQ(0, uv_run(loop, UV_RUN_DEFAULT)); + + printf("%s async jobs in %.1f seconds (%s/s)\n", fmt(events), timeout / 1000., + fmt(events / (timeout / 1000.))); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From 8ec1732af08424163ac78e11ca8aa4a03328db54 Mon Sep 17 00:00:00 2001 From: UMU Date: Sun, 13 Feb 2022 13:57:43 +0800 Subject: [PATCH 124/713] build: fix error C4146 on MSVC (#3271) > error C4146: unary minus operator applied to unsigned type, result still unsigned --- src/idna.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/idna.c b/src/idna.c index b44cb16a1ee..93d982ca018 100644 --- a/src/idna.c +++ b/src/idna.c @@ -21,6 +21,7 @@ #include "idna.h" #include #include +#include /* UINT_MAX */ static unsigned uv__utf8_decode1_slow(const char** p, const char* pe, @@ -129,7 +130,7 @@ static int uv__idna_toascii_label(const char* s, const char* se, while (s < se) { c = uv__utf8_decode1(&s, se); - if (c == -1u) + if (c == UINT_MAX) return UV_EINVAL; if (c < 128) @@ -151,7 +152,7 @@ static int uv__idna_toascii_label(const char* s, const char* se, s = ss; while (s < se) { c = uv__utf8_decode1(&s, se); - assert(c != -1u); + assert(c != UINT_MAX); if (c > 127) continue; @@ -182,7 +183,7 @@ static int uv__idna_toascii_label(const char* s, const char* se, while (s < se) { c = uv__utf8_decode1(&s, se); - assert(c != -1u); + assert(c != UINT_MAX); if (c >= n) if (c < m) @@ -201,7 +202,7 @@ static int uv__idna_toascii_label(const char* s, const char* se, s = ss; while (s < se) { c = uv__utf8_decode1(&s, se); - assert(c != -1u); + assert(c != UINT_MAX); if (c < n) if (++delta == 0) @@ -280,7 +281,7 @@ long uv__idna_toascii(const char* s, const char* se, char* d, char* de) { st = si; c = uv__utf8_decode1(&si, se); - if (c == -1u) + if (c == UINT_MAX) return UV_EINVAL; if (c != '.') From 912bb8c5778f466adfb4935210d6b4439fdbdd7f Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Sat, 12 Feb 2022 22:04:41 -0800 Subject: [PATCH 125/713] test: fix benchmark-ping-udp (#2817) - Fixes the declaration of the benchmark in benchmark-list.h (it was not previously runnable at all) - Fixes the benchmark itself hanging infinitely because the data was being dropped via ICMP Destination Unreachable errors (meaning nread was always zero in pinger_read_cb) + The data getting lost was fixed by binding the udp socket - Properly checks for UV_UDP_MMSG_CHUNK, just as an example of what should generally be done (buf_free is actually a no-op as the buf is allocated on the stack) --- test/benchmark-list.h | 8 +++++++- test/benchmark-ping-udp.c | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/test/benchmark-list.h b/test/benchmark-list.h index 4e6dc33c542..1ab8f25813f 100644 --- a/test/benchmark-list.h +++ b/test/benchmark-list.h @@ -23,7 +23,9 @@ BENCHMARK_DECLARE (sizes) BENCHMARK_DECLARE (loop_count) BENCHMARK_DECLARE (loop_count_timed) BENCHMARK_DECLARE (ping_pongs) -BENCHMARK_DECLARE (ping_udp) +BENCHMARK_DECLARE (ping_udp1) +BENCHMARK_DECLARE (ping_udp10) +BENCHMARK_DECLARE (ping_udp100) BENCHMARK_DECLARE (tcp_write_batch) BENCHMARK_DECLARE (tcp4_pound_100) BENCHMARK_DECLARE (tcp4_pound_1000) @@ -91,6 +93,10 @@ TASK_LIST_START BENCHMARK_ENTRY (ping_pongs) BENCHMARK_HELPER (ping_pongs, tcp4_echo_server) + BENCHMARK_ENTRY (ping_udp1) + BENCHMARK_ENTRY (ping_udp10) + BENCHMARK_ENTRY (ping_udp100) + BENCHMARK_ENTRY (tcp_write_batch) BENCHMARK_HELPER (tcp_write_batch, tcp4_blackhole_server) diff --git a/test/benchmark-ping-udp.c b/test/benchmark-ping-udp.c index a29502a786f..cf9ca9811f7 100644 --- a/test/benchmark-ping-udp.c +++ b/test/benchmark-ping-udp.c @@ -94,6 +94,9 @@ static void pinger_read_cb(uv_udp_t* udp, pinger_t* pinger; pinger = (pinger_t*)udp->data; + /* No data here means something went wrong */ + ASSERT(nread > 0); + /* Now we count the pings */ for (i = 0; i < nread; i++) { ASSERT(buf->base[i] == PING[pinger->state]); @@ -108,7 +111,8 @@ static void pinger_read_cb(uv_udp_t* udp, } } - buf_free(buf); + if (buf && !(flags & UV_UDP_MMSG_CHUNK)) + buf_free(buf); } static void udp_pinger_new(void) { @@ -122,6 +126,8 @@ static void udp_pinger_new(void) { /* Try to do NUM_PINGS ping-pongs (connection-less). */ r = uv_udp_init(loop, &pinger->udp); ASSERT(r == 0); + r = uv_udp_bind(&pinger->udp, (const struct sockaddr*) &pinger->server_addr, 0); + ASSERT(r == 0); pinger->udp.data = pinger; From df78de04e46a8dbe341f418052238da0141a69af Mon Sep 17 00:00:00 2001 From: Momtchil Momtchev Date: Sun, 13 Feb 2022 07:40:10 +0100 Subject: [PATCH 126/713] win,fs: consider broken pipe error a normal EOF (#3053) This would later get translated in src/win/error.c this way, which previously could lead to rather confusing and inaccurate error messages. --- src/win/fs.c | 3 +-- test/test-pipe-set-non-blocking.c | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 903764144f4..41aeffddcf5 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -912,12 +912,11 @@ void fs__read(uv_fs_t* req) { SET_REQ_RESULT(req, bytes); } else { error = GetLastError(); - if (error == ERROR_ACCESS_DENIED) { error = ERROR_INVALID_FLAGS; } - if (error == ERROR_HANDLE_EOF) { + if (error == ERROR_HANDLE_EOF || error == ERROR_BROKEN_PIPE) { SET_REQ_RESULT(req, bytes); } else { SET_REQ_WIN32_ERROR(req, error); diff --git a/test/test-pipe-set-non-blocking.c b/test/test-pipe-set-non-blocking.c index 8246afaf827..827e7264108 100644 --- a/test/test-pipe-set-non-blocking.c +++ b/test/test-pipe-set-non-blocking.c @@ -46,11 +46,7 @@ static void thread_main(void* arg) { uv_fs_req_cleanup(&req); } while (n > 0 || (n == -1 && uv_errno == UV_EINTR)); -#ifdef _WIN32 - ASSERT(n == UV_EOF); -#else ASSERT(n == 0); -#endif } From 722d003076c5a4b985c4d52db1eb3fd073c8b1cc Mon Sep 17 00:00:00 2001 From: Paul Evans Date: Mon, 14 Feb 2022 16:37:19 +0000 Subject: [PATCH 127/713] document the values of enum uv_stdio_flags (#3039) Co-authored-by: Jameson Nash --- docs/src/process.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/src/process.rst b/docs/src/process.rst index ea6c4b9ad28..8acf7db3df3 100644 --- a/docs/src/process.rst +++ b/docs/src/process.rst @@ -109,10 +109,39 @@ Data types :: typedef enum { + /* + * The following four options are mutually-exclusive, and define + * the operation to perform for the corresponding file descriptor + * in the child process: + */ + + /* + * No file descriptor will be provided (or redirected to + * `/dev/null` if it is fd 0, 1 or 2). + */ UV_IGNORE = 0x00, + + /* + * Open a new pipe into `data.stream`, per the flags below. The + * `data.stream` field must point to a uv_pipe_t object that has + * been initialized with `uv_pipe_init(loop, data.stream, ipc);`, + * but not yet opened or connected. + /* UV_CREATE_PIPE = 0x01, + + /* + * The child process will be given a duplicate of the parent's + * file descriptor given by `data.fd`. + */ UV_INHERIT_FD = 0x02, + + /* + * The child process will be given a duplicate of the parent's + * file descriptor being used by the stream handle given by + * `data.stream`. + */ UV_INHERIT_STREAM = 0x04, + /* * When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE * determine the direction of flow, from the child process' perspective. Both @@ -120,6 +149,7 @@ Data types */ UV_READABLE_PIPE = 0x10, UV_WRITABLE_PIPE = 0x20, + /* * When UV_CREATE_PIPE is specified, specifying UV_NONBLOCK_PIPE opens the * handle in non-blocking mode in the child. This may cause loss of data, From 0209466496cfb62593717088a1af0cef45b2fc65 Mon Sep 17 00:00:00 2001 From: twosee Date: Tue, 15 Feb 2022 00:40:42 +0800 Subject: [PATCH 128/713] win,loop: add missing uv_update_time (#3175) Time of loop should be updated after the IOCP wait. --- src/win/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win/core.c b/src/win/core.c index 68409e37085..10b39da507a 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -631,6 +631,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from * the check. */ + uv_update_time(loop); uv__run_timers(loop); } From 3b2c25d22367dffc019903d6f58567886b99b0c6 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 14 Feb 2022 12:29:47 -0500 Subject: [PATCH 129/713] win,fs: avoid closing an invalid handle (#3473) While usually functional, calling CloseHandle(INVALID_HANDLE_VALUE) can result in debug builds (and/or wine) being unhappy and aborting there. --- src/win/fs.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 41aeffddcf5..a177a73ed46 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1880,8 +1880,9 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, NULL); if (handle == INVALID_HANDLE_VALUE) - ret = GetLastError(); - else if (fs__stat_handle(handle, statbuf, do_lstat) != 0) + return GetLastError(); + + if (fs__stat_handle(handle, statbuf, do_lstat) != 0) ret = GetLastError(); else ret = 0; @@ -2299,13 +2300,13 @@ INLINE static DWORD fs__utime_impl_from_path(WCHAR* path, flags, NULL); - if (handle == INVALID_HANDLE_VALUE) { - ret = GetLastError(); - } else if (fs__utime_handle(handle, atime, mtime) != 0) { + if (handle == INVALID_HANDLE_VALUE) + return GetLastError(); + + if (fs__utime_handle(handle, atime, mtime) != 0) ret = GetLastError(); - } else { + else ret = 0; - } CloseHandle(handle); return ret; From cc7dbaa3a18d54ef4735efa4c54c32a24cdf7e5b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 14 Feb 2022 13:37:05 -0500 Subject: [PATCH 130/713] fix oopsie from #3466 (#3475) I created `uv__backend_timeout` to be used internally for this reason, then forgot to use it, resulting in flaky tests and excessive trips around the uv_run loop. Fix #3472 --- src/unix/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/core.c b/src/unix/core.c index e14c327ea50..9a289edfa34 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -385,7 +385,7 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { timeout = 0; if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) - timeout = uv_backend_timeout(loop); + timeout = uv__backend_timeout(loop); uv__io_poll(loop, timeout); From d41a9a07e4806e9c07485a6d807ceec2df57e867 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 15 Feb 2022 16:10:22 +0100 Subject: [PATCH 131/713] doc: clarify android api level (#3480) Google goes to great lengths to obscure the relationship between the two so explicitly call out the API version matching Android 7.0. --- SUPPORTED_PLATFORMS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 7b33cbbed94..3a58f186399 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -11,7 +11,7 @@ | z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | | Linux with musl | Tier 2 | musl >= 1.0 | | | SmartOS | Tier 3 | >= 14.4 | | -| Android | Tier 3 | NDK >= r15b | Android 7.0 and up | +| Android | Tier 3 | NDK >= r15b | Android 7.0, `-DANDROID_PLATFORM=android-24` | | MinGW | Tier 3 | MinGW32 and MinGW-w64 | | | SunOS | Tier 3 | Solaris 121 and later | | | Other | Tier 3 | N/A | | From d54c92e3e68f0b8152617d8e97f704dd1e586bd6 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 15 Feb 2022 10:13:24 -0500 Subject: [PATCH 132/713] win: fix style nits [NFC] (#3474) Internal functions usually have a uv__ prefix. --- src/fs-poll.c | 2 +- src/unix/internal.h | 4 +- src/unix/pipe.c | 2 +- src/unix/stream.c | 4 +- src/unix/tcp.c | 2 +- src/win/async.c | 10 +-- src/win/core.c | 35 +++++---- src/win/fs-event.c | 36 ++++----- src/win/fs.c | 6 +- src/win/handle-inl.h | 26 +++---- src/win/handle.c | 26 +++---- src/win/internal.h | 138 +++++++++++++++++------------------ src/win/loop-watcher.c | 4 +- src/win/pipe.c | 152 +++++++++++++++++++------------------- src/win/poll.c | 32 ++++---- src/win/process.c | 20 ++--- src/win/req-inl.h | 34 ++++----- src/win/signal.c | 12 +-- src/win/stream-inl.h | 8 +- src/win/stream.c | 22 +++--- src/win/tcp.c | 132 ++++++++++++++++----------------- src/win/tty.c | 161 +++++++++++++++++++++-------------------- src/win/udp.c | 100 ++++++++++++------------- src/win/winapi.c | 2 +- src/win/winsock.c | 28 +++---- 25 files changed, 498 insertions(+), 500 deletions(-) diff --git a/src/fs-poll.c b/src/fs-poll.c index 89864e23fbc..1bac1c568e3 100644 --- a/src/fs-poll.c +++ b/src/fs-poll.c @@ -25,7 +25,7 @@ #ifdef _WIN32 #include "win/internal.h" #include "win/handle-inl.h" -#define uv__make_close_pending(h) uv_want_endgame((h)->loop, (h)) +#define uv__make_close_pending(h) uv__want_endgame((h)->loop, (h)) #else #include "unix/internal.h" #endif diff --git a/src/unix/internal.h b/src/unix/internal.h index 2dcc8b32f51..b0913d31cbe 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -244,12 +244,12 @@ int uv__dup2_cloexec(int oldfd, int newfd); int uv__open_cloexec(const char* path, int flags); /* tcp */ -int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb); +int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb); int uv__tcp_nodelay(int fd, int on); int uv__tcp_keepalive(int fd, int on, unsigned int delay); /* pipe */ -int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); +int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); /* signal */ void uv__signal_close(uv_signal_t* handle); diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 788e038e8aa..fcc2cba1a5d 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -91,7 +91,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { } -int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { +int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { if (uv__stream_fd(handle) == -1) return UV_EINVAL; diff --git a/src/unix/stream.c b/src/unix/stream.c index b5b05a6a4a7..619b6250129 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -644,11 +644,11 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { switch (stream->type) { case UV_TCP: - err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); + err = uv__tcp_listen((uv_tcp_t*)stream, backlog, cb); break; case UV_NAMED_PIPE: - err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); + err = uv__pipe_listen((uv_pipe_t*)stream, backlog, cb); break; default: diff --git a/src/unix/tcp.c b/src/unix/tcp.c index bc0fb661f1c..789807f05d2 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -328,7 +328,7 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) { } -int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { +int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { static int single_accept_cached = -1; unsigned long flags; int single_accept; diff --git a/src/win/async.c b/src/win/async.c index d787f6604ea..b904676e3a7 100644 --- a/src/win/async.c +++ b/src/win/async.c @@ -28,7 +28,7 @@ #include "req-inl.h" -void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { +void uv__async_endgame(uv_loop_t* loop, uv_async_t* handle) { if (handle->flags & UV_HANDLE_CLOSING && !handle->async_sent) { assert(!(handle->flags & UV_HANDLE_CLOSED)); @@ -54,9 +54,9 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { } -void uv_async_close(uv_loop_t* loop, uv_async_t* handle) { +void uv__async_close(uv_loop_t* loop, uv_async_t* handle) { if (!((uv_async_t*)handle)->async_sent) { - uv_want_endgame(loop, (uv_handle_t*) handle); + uv__want_endgame(loop, (uv_handle_t*) handle); } uv__handle_closing(handle); @@ -83,7 +83,7 @@ int uv_async_send(uv_async_t* handle) { } -void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, +void uv__process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, uv_req_t* req) { assert(handle->type == UV_ASYNC); assert(req->type == UV_WAKEUP); @@ -91,7 +91,7 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, handle->async_sent = 0; if (handle->flags & UV_HANDLE_CLOSING) { - uv_want_endgame(loop, (uv_handle_t*)handle); + uv__want_endgame(loop, (uv_handle_t*)handle); } else if (handle->async_cb != NULL) { handle->async_cb(handle); } diff --git a/src/win/core.c b/src/win/core.c index 10b39da507a..c08dedc47c2 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -84,10 +84,12 @@ static int uv__loops_capacity; #define UV__LOOPS_CHUNK_SIZE 8 static uv_mutex_t uv__loops_lock; + static void uv__loops_init(void) { uv_mutex_init(&uv__loops_lock); } + static int uv__loops_add(uv_loop_t* loop) { uv_loop_t** new_loops; int new_capacity, i; @@ -115,6 +117,7 @@ static int uv__loops_add(uv_loop_t* loop) { return ERROR_OUTOFMEMORY; } + static void uv__loops_remove(uv_loop_t* loop) { int loop_index; int smaller_capacity; @@ -173,7 +176,7 @@ void uv__wake_all_loops(void) { uv_mutex_unlock(&uv__loops_lock); } -static void uv_init(void) { +static void uv__init(void) { /* Tell Windows that we will handle critical errors. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); @@ -199,19 +202,19 @@ static void uv_init(void) { /* Fetch winapi function pointers. This must be done first because other * initialization code might need these function pointers to be loaded. */ - uv_winapi_init(); + uv__winapi_init(); /* Initialize winsock */ - uv_winsock_init(); + uv__winsock_init(); /* Initialize FS */ - uv_fs_init(); + uv__fs_init(); /* Initialize signal stuff */ - uv_signals_init(); + uv__signals_init(); /* Initialize console */ - uv_console_init(); + uv__console_init(); /* Initialize utilities */ uv__util_init(); @@ -327,7 +330,7 @@ void uv_update_time(uv_loop_t* loop) { void uv__once_init(void) { - uv_once(&uv_init_guard_, uv_init); + uv_once(&uv_init_guard_, uv__init); } @@ -467,8 +470,8 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { if (overlapped) { /* Package was dequeued */ - req = uv_overlapped_to_req(overlapped); - uv_insert_pending_req(loop, req); + 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. @@ -552,8 +555,8 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { * meant only to wake us up. */ if (overlappeds[i].lpOverlapped) { - req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); - uv_insert_pending_req(loop, req); + req = uv__overlapped_to_req(overlappeds[i].lpOverlapped); + uv__insert_pending_req(loop, req); } } @@ -599,9 +602,9 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { uv_update_time(loop); uv__run_timers(loop); - ran_pending = uv_process_reqs(loop); - uv_idle_invoke(loop); - uv_prepare_invoke(loop); + ran_pending = uv__process_reqs(loop); + uv__idle_invoke(loop); + uv__prepare_invoke(loop); timeout = 0; if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) @@ -619,8 +622,8 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { */ uv__metrics_update_idle_time(loop); - uv_check_invoke(loop); - uv_process_endgames(loop); + uv__check_invoke(loop); + uv__process_endgames(loop); if (mode == UV_RUN_ONCE) { /* UV_RUN_ONCE implies forward progress: at least one callback must have diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 76da077551d..6758c7c78bc 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -33,7 +33,7 @@ const unsigned int uv_directory_watcher_buffer_size = 4096; -static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, +static void uv__fs_event_queue_readdirchanges(uv_loop_t* loop, uv_fs_event_t* handle) { assert(handle->dir_handle != INVALID_HANDLE_VALUE); assert(!handle->req_pending); @@ -57,15 +57,15 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, NULL)) { /* Make this req pending reporting an error. */ SET_REQ_ERROR(&handle->req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)&handle->req); + uv__insert_pending_req(loop, (uv_req_t*)&handle->req); } handle->req_pending = 1; } -static void uv_relative_path(const WCHAR* filename, - const WCHAR* dir, - WCHAR** relpath) { +static void uv__relative_path(const WCHAR* filename, + const WCHAR* dir, + WCHAR** relpath) { size_t relpathlen; size_t filenamelen = wcslen(filename); size_t dirlen = wcslen(dir); @@ -80,7 +80,7 @@ static void uv_relative_path(const WCHAR* filename, (*relpath)[relpathlen] = L'\0'; } -static int uv_split_path(const WCHAR* filename, WCHAR** dir, +static int uv__split_path(const WCHAR* filename, WCHAR** dir, WCHAR** file) { size_t len, i; DWORD dir_len; @@ -255,12 +255,12 @@ int uv_fs_event_start(uv_fs_event_t* handle, short_path_done: short_path = short_path_buffer; - if (uv_split_path(pathw, &dir, &handle->filew) != 0) { + if (uv__split_path(pathw, &dir, &handle->filew) != 0) { last_error = GetLastError(); goto error; } - if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) { + if (uv__split_path(short_path, NULL, &handle->short_filew) != 0) { last_error = GetLastError(); goto error; } @@ -423,7 +423,7 @@ static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) { } -void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, +void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv_fs_event_t* handle) { FILE_NOTIFY_INFORMATION* file_info; int err, sizew, size; @@ -442,7 +442,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, */ if (!uv__is_active(handle)) { if (handle->flags & UV_HANDLE_CLOSING) { - uv_want_endgame(loop, (uv_handle_t*) handle); + uv__want_endgame(loop, (uv_handle_t*) handle); } return; } @@ -515,9 +515,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, if (long_filenamew) { /* Get the file name out of the long path. */ - uv_relative_path(long_filenamew, - handle->dirw, - &filenamew); + uv__relative_path(long_filenamew, + handle->dirw, + &filenamew); uv__free(long_filenamew); long_filenamew = filenamew; sizew = -1; @@ -575,26 +575,26 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } if (handle->flags & UV_HANDLE_CLOSING) { - uv_want_endgame(loop, (uv_handle_t*)handle); + uv__want_endgame(loop, (uv_handle_t*)handle); } else if (uv__is_active(handle)) { - uv_fs_event_queue_readdirchanges(loop, handle); + uv__fs_event_queue_readdirchanges(loop, handle); } } -void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) { +void uv__fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) { uv_fs_event_stop(handle); uv__handle_closing(handle); if (!handle->req_pending) { - uv_want_endgame(loop, (uv_handle_t*)handle); + uv__want_endgame(loop, (uv_handle_t*)handle); } } -void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { +void uv__fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) { assert(!(handle->flags & UV_HANDLE_CLOSED)); diff --git a/src/win/fs.c b/src/win/fs.c index a177a73ed46..792307995f6 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -46,7 +46,7 @@ do { \ if (req == NULL) \ return UV_EINVAL; \ - uv_fs_req_init(loop, req, subtype, cb); \ + uv__fs_req_init(loop, req, subtype, cb); \ } \ while (0) @@ -132,7 +132,7 @@ static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGE static DWORD uv__allocation_granularity; -void uv_fs_init(void) { +void uv__fs_init(void) { SYSTEM_INFO system_info; GetSystemInfo(&system_info); @@ -241,7 +241,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path, -INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, +INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req, uv_fs_type fs_type, const uv_fs_cb cb) { uv__once_init(); UV_REQ_INIT(req, UV_FS); diff --git a/src/win/handle-inl.h b/src/win/handle-inl.h index 82c657d579f..5c843c241ef 100644 --- a/src/win/handle-inl.h +++ b/src/win/handle-inl.h @@ -55,7 +55,7 @@ \ if (handle->flags & UV_HANDLE_CLOSING && \ handle->reqs_pending == 0) { \ - uv_want_endgame(loop, (uv_handle_t*)handle); \ + uv__want_endgame(loop, (uv_handle_t*)handle); \ } \ } while (0) @@ -85,7 +85,7 @@ } while (0) -INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) { +INLINE static void uv__want_endgame(uv_loop_t* loop, uv_handle_t* handle) { if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) { handle->flags |= UV_HANDLE_ENDGAME_QUEUED; @@ -95,7 +95,7 @@ INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) { } -INLINE static void uv_process_endgames(uv_loop_t* loop) { +INLINE static void uv__process_endgames(uv_loop_t* loop) { uv_handle_t* handle; while (loop->endgame_handles) { @@ -106,23 +106,23 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) { switch (handle->type) { case UV_TCP: - uv_tcp_endgame(loop, (uv_tcp_t*) handle); + uv__tcp_endgame(loop, (uv_tcp_t*) handle); break; case UV_NAMED_PIPE: - uv_pipe_endgame(loop, (uv_pipe_t*) handle); + uv__pipe_endgame(loop, (uv_pipe_t*) handle); break; case UV_TTY: - uv_tty_endgame(loop, (uv_tty_t*) handle); + uv__tty_endgame(loop, (uv_tty_t*) handle); break; case UV_UDP: - uv_udp_endgame(loop, (uv_udp_t*) handle); + uv__udp_endgame(loop, (uv_udp_t*) handle); break; case UV_POLL: - uv_poll_endgame(loop, (uv_poll_t*) handle); + uv__poll_endgame(loop, (uv_poll_t*) handle); break; case UV_TIMER: @@ -133,23 +133,23 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) { case UV_PREPARE: case UV_CHECK: case UV_IDLE: - uv_loop_watcher_endgame(loop, handle); + uv__loop_watcher_endgame(loop, handle); break; case UV_ASYNC: - uv_async_endgame(loop, (uv_async_t*) handle); + uv__async_endgame(loop, (uv_async_t*) handle); break; case UV_SIGNAL: - uv_signal_endgame(loop, (uv_signal_t*) handle); + uv__signal_endgame(loop, (uv_signal_t*) handle); break; case UV_PROCESS: - uv_process_endgame(loop, (uv_process_t*) handle); + uv__process_endgame(loop, (uv_process_t*) handle); break; case UV_FS_EVENT: - uv_fs_event_endgame(loop, (uv_fs_event_t*) handle); + uv__fs_event_endgame(loop, (uv_fs_event_t*) handle); break; case UV_FS_POLL: diff --git a/src/win/handle.c b/src/win/handle.c index 61e4df61b32..53a81fdbc21 100644 --- a/src/win/handle.c +++ b/src/win/handle.c @@ -77,63 +77,63 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { /* Handle-specific close actions */ switch (handle->type) { case UV_TCP: - uv_tcp_close(loop, (uv_tcp_t*)handle); + uv__tcp_close(loop, (uv_tcp_t*)handle); return; case UV_NAMED_PIPE: - uv_pipe_close(loop, (uv_pipe_t*) handle); + uv__pipe_close(loop, (uv_pipe_t*) handle); return; case UV_TTY: - uv_tty_close((uv_tty_t*) handle); + uv__tty_close((uv_tty_t*) handle); return; case UV_UDP: - uv_udp_close(loop, (uv_udp_t*) handle); + uv__udp_close(loop, (uv_udp_t*) handle); return; case UV_POLL: - uv_poll_close(loop, (uv_poll_t*) handle); + uv__poll_close(loop, (uv_poll_t*) handle); return; case UV_TIMER: uv_timer_stop((uv_timer_t*)handle); uv__handle_closing(handle); - uv_want_endgame(loop, handle); + uv__want_endgame(loop, handle); return; case UV_PREPARE: uv_prepare_stop((uv_prepare_t*)handle); uv__handle_closing(handle); - uv_want_endgame(loop, handle); + uv__want_endgame(loop, handle); return; case UV_CHECK: uv_check_stop((uv_check_t*)handle); uv__handle_closing(handle); - uv_want_endgame(loop, handle); + uv__want_endgame(loop, handle); return; case UV_IDLE: uv_idle_stop((uv_idle_t*)handle); uv__handle_closing(handle); - uv_want_endgame(loop, handle); + uv__want_endgame(loop, handle); return; case UV_ASYNC: - uv_async_close(loop, (uv_async_t*) handle); + uv__async_close(loop, (uv_async_t*) handle); return; case UV_SIGNAL: - uv_signal_close(loop, (uv_signal_t*) handle); + uv__signal_close(loop, (uv_signal_t*) handle); return; case UV_PROCESS: - uv_process_close(loop, (uv_process_t*) handle); + uv__process_close(loop, (uv_process_t*) handle); return; case UV_FS_EVENT: - uv_fs_event_close(loop, (uv_fs_event_t*) handle); + uv__fs_event_close(loop, (uv_fs_event_t*) handle); return; case UV_FS_POLL: diff --git a/src/win/internal.h b/src/win/internal.h index b1b25b4c786..17e399be5c7 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -72,25 +72,25 @@ typedef struct { uint32_t delayed_error; } uv__ipc_socket_xfer_info_t; -int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb); -int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client); -int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, +int uv__tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb); +int uv__tcp_accept(uv_tcp_t* server, uv_tcp_t* client); +int uv__tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb); -int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, +int uv__tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[], unsigned int nbufs); -void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req); -void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, +void uv__process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req); +void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, uv_write_t* req); -void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, +void uv__process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req); -void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, +void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, uv_connect_t* req); -void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp); -void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); +void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp); +void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); int uv__tcp_xfer_export(uv_tcp_t* handle, int pid, @@ -104,12 +104,12 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp, /* * UDP */ -void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req); -void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, +void uv__process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req); +void uv__process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, uv_udp_send_t* req); -void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle); -void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); +void uv__udp_close(uv_loop_t* loop, uv_udp_t* handle); +void uv__udp_endgame(uv_loop_t* loop, uv_udp_t* handle); /* @@ -118,9 +118,9 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); int uv__create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags); -int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); -int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client); -int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, +int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); +int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client); +int uv__pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb); void uv__pipe_read_stop(uv_pipe_t* handle); int uv__pipe_write(uv_loop_t* loop, @@ -131,74 +131,74 @@ int uv__pipe_write(uv_loop_t* loop, uv_stream_t* send_handle, uv_write_cb cb); -void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, +void uv__process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, uv_req_t* req); -void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, +void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, uv_write_t* req); -void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, +void uv__process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, uv_req_t* raw_req); -void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, +void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, uv_connect_t* req); -void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, +void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req); -void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle); -void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle); -void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); +void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle); +void uv__pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle); +void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); /* * TTY */ -void uv_console_init(void); +void uv__console_init(void); -int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, +int uv__tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb); -int uv_tty_read_stop(uv_tty_t* handle); -int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle, +int uv__tty_read_stop(uv_tty_t* handle); +int uv__tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[], unsigned int nbufs); -void uv_tty_close(uv_tty_t* handle); +void uv__tty_close(uv_tty_t* handle); -void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, +void uv__process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, uv_req_t* req); -void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, +void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, uv_write_t* req); /* - * uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working + * uv__process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working * TODO: find a way to remove it */ -void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, +void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, uv_req_t* raw_req); /* - * uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working + * uv__process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working * TODO: find a way to remove it */ -void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, +void uv__process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, uv_connect_t* req); -void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle); +void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle); /* * Poll watchers */ -void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, +void uv__process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req); -int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle); -void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); +int uv__poll_close(uv_loop_t* loop, uv_poll_t* handle); +void uv__poll_endgame(uv_loop_t* loop, uv_poll_t* handle); /* * Loop watchers */ -void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle); +void uv__loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle); -void uv_prepare_invoke(uv_loop_t* loop); -void uv_check_invoke(uv_loop_t* loop); -void uv_idle_invoke(uv_loop_t* loop); +void uv__prepare_invoke(uv_loop_t* loop); +void uv__check_invoke(uv_loop_t* loop); +void uv__idle_invoke(uv_loop_t* loop); void uv__once_init(void); @@ -206,53 +206,47 @@ void uv__once_init(void); /* * Async watcher */ -void uv_async_close(uv_loop_t* loop, uv_async_t* handle); -void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle); +void uv__async_close(uv_loop_t* loop, uv_async_t* handle); +void uv__async_endgame(uv_loop_t* loop, uv_async_t* handle); -void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, +void uv__process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, uv_req_t* req); /* * Signal watcher */ -void uv_signals_init(void); +void uv__signals_init(void); int uv__signal_dispatch(int signum); -void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle); -void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle); +void uv__signal_close(uv_loop_t* loop, uv_signal_t* handle); +void uv__signal_endgame(uv_loop_t* loop, uv_signal_t* handle); -void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, +void uv__process_signal_req(uv_loop_t* loop, uv_signal_t* handle, uv_req_t* req); /* * Spawn */ -void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle); -void uv_process_close(uv_loop_t* loop, uv_process_t* handle); -void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle); - - -/* - * Error - */ -int uv_translate_sys_error(int sys_errno); +void uv__process_proc_exit(uv_loop_t* loop, uv_process_t* handle); +void uv__process_close(uv_loop_t* loop, uv_process_t* handle); +void uv__process_endgame(uv_loop_t* loop, uv_process_t* handle); /* * FS */ -void uv_fs_init(void); +void uv__fs_init(void); /* * FS Event */ -void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, +void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv_fs_event_t* handle); -void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle); -void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle); +void uv__fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle); +void uv__fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle); /* @@ -299,28 +293,28 @@ HANDLE uv__stdio_handle(BYTE* buffer, int fd); /* * Winapi and ntapi utility functions */ -void uv_winapi_init(void); +void uv__winapi_init(void); /* * Winsock utility functions */ -void uv_winsock_init(void); +void uv__winsock_init(void); -int uv_ntstatus_to_winsock_error(NTSTATUS status); +int uv__ntstatus_to_winsock_error(NTSTATUS status); -BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target); -BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target); +BOOL uv__get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target); +BOOL uv__get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target); -int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers, +int WSAAPI uv__wsarecv_workaround(SOCKET socket, WSABUF* buffers, DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); -int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, +int WSAAPI uv__wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr, int* addr_len, WSAOVERLAPPED *overlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); -int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, +int WSAAPI uv__msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, AFD_POLL_INFO* info_out, OVERLAPPED* overlapped); /* Whether there are any non-IFS LSPs stacked on TCP */ diff --git a/src/win/loop-watcher.c b/src/win/loop-watcher.c index ad7fbea1697..fad9e8a8e4c 100644 --- a/src/win/loop-watcher.c +++ b/src/win/loop-watcher.c @@ -26,7 +26,7 @@ #include "handle-inl.h" -void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { +void uv__loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { if (handle->flags & UV_HANDLE_CLOSING) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; @@ -104,7 +104,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { } \ \ \ - void uv_##name##_invoke(uv_loop_t* loop) { \ + void uv__##name##_invoke(uv_loop_t* loop) { \ uv_##name##_t* handle; \ \ (loop)->next_##name##_handle = (loop)->name##_handles; \ diff --git a/src/win/pipe.c b/src/win/pipe.c index 984b766bb43..a4bab2c4838 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -98,13 +98,13 @@ static void eof_timer_destroy(uv_pipe_t* pipe); static void eof_timer_close_cb(uv_handle_t* handle); -static void uv_unique_pipe_name(char* ptr, char* name, size_t size) { +static void uv__unique_pipe_name(char* ptr, char* name, size_t size) { snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId()); } int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { - uv_stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); + uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); handle->reqs_pending = 0; handle->handle = INVALID_HANDLE_VALUE; @@ -120,8 +120,8 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { } -static void uv_pipe_connection_init(uv_pipe_t* handle) { - uv_connection_init((uv_stream_t*) handle); +static void uv__pipe_connection_init(uv_pipe_t* handle) { + uv__connection_init((uv_stream_t*) handle); handle->read_req.data = handle; handle->pipe.conn.eof_timer = NULL; assert(!(handle->flags & UV_HANDLE_PIPESERVER)); @@ -209,7 +209,7 @@ static int uv__pipe_server( int err; for (;;) { - uv_unique_pipe_name(random, name, nameSize); + uv__unique_pipe_name(random, name, nameSize); pipeHandle = CreateNamedPipeA(name, access | FILE_FLAG_FIRST_PIPE_INSTANCE, @@ -427,7 +427,7 @@ int uv__create_stdio_pipe_pair(uv_loop_t* loop, goto error; } - uv_pipe_connection_init(parent_pipe); + uv__pipe_connection_init(parent_pipe); parent_pipe->handle = server_pipe; *child_pipe_ptr = client_pipe; @@ -450,11 +450,11 @@ int uv__create_stdio_pipe_pair(uv_loop_t* loop, } -static int uv_set_pipe_handle(uv_loop_t* loop, - uv_pipe_t* handle, - HANDLE pipeHandle, - int fd, - DWORD duplex_flags) { +static int uv__set_pipe_handle(uv_loop_t* loop, + uv_pipe_t* handle, + HANDLE pipeHandle, + int fd, + DWORD duplex_flags) { NTSTATUS nt_status; IO_STATUS_BLOCK io_status; FILE_MODE_INFORMATION mode_info; @@ -578,7 +578,7 @@ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) { } -void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { +void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { int err; DWORD result; uv_shutdown_t* req; @@ -630,7 +630,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) { /* Short-circuit, no need to call FlushFileBuffers. */ - uv_insert_pending_req(loop, (uv_req_t*) req); + uv__insert_pending_req(loop, (uv_req_t*) req); return; } @@ -826,7 +826,7 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { } if (pipeHandle != INVALID_HANDLE_VALUE && - !uv_set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) { + !uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) { SET_REQ_SUCCESS(req); } else { SET_REQ_ERROR(req, GetLastError()); @@ -890,17 +890,17 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, assert(pipeHandle != INVALID_HANDLE_VALUE); - if (uv_set_pipe_handle(loop, - (uv_pipe_t*) req->handle, - pipeHandle, - -1, - duplex_flags)) { + if (uv__set_pipe_handle(loop, + (uv_pipe_t*) req->handle, + pipeHandle, + -1, + duplex_flags)) { err = GetLastError(); goto error; } SET_REQ_SUCCESS(req); - uv_insert_pending_req(loop, (uv_req_t*) req); + uv__insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); return; @@ -916,7 +916,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, err); - uv_insert_pending_req(loop, (uv_req_t*) req); + uv__insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); return; @@ -980,7 +980,7 @@ void uv__pipe_read_stop(uv_pipe_t* handle) { /* Cleans up uv_pipe_t (server or connection) and all resources associated with * it. */ -void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { +void uv__pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { int i; HANDLE pipeHandle; @@ -1013,7 +1013,7 @@ void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { } -void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { +void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { if (handle->flags & UV_HANDLE_READING) { handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(loop, handle); @@ -1024,10 +1024,10 @@ void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { DECREASE_ACTIVE_COUNT(loop, handle); } - uv_pipe_cleanup(loop, handle); + uv__pipe_cleanup(loop, handle); if (handle->reqs_pending == 0) { - uv_want_endgame(loop, (uv_handle_t*) handle); + uv__want_endgame(loop, (uv_handle_t*) handle); } handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); @@ -1035,13 +1035,13 @@ void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { } -static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, +static void uv__pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, uv_pipe_accept_t* req, BOOL firstInstance) { assert(handle->flags & UV_HANDLE_LISTENING); if (!firstInstance && !pipe_alloc_accept(loop, handle, req, FALSE)) { SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*) req); + uv__insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; return; } @@ -1061,7 +1061,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, GetLastError()); } - uv_insert_pending_req(loop, (uv_req_t*) req); + uv__insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; return; } @@ -1071,7 +1071,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, } -int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { +int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) { uv_loop_t* loop = server->loop; uv_pipe_t* pipe_client; uv_pipe_accept_t* req; @@ -1110,7 +1110,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { } /* Initialize the client handle and copy the pipeHandle to the client */ - uv_pipe_connection_init(pipe_client); + uv__pipe_connection_init(pipe_client); pipe_client->handle = req->pipeHandle; pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; @@ -1121,7 +1121,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { server->handle = INVALID_HANDLE_VALUE; if (!(server->flags & UV_HANDLE_CLOSING)) { - uv_pipe_queue_accept(loop, server, req, FALSE); + uv__pipe_queue_accept(loop, server, req, FALSE); } } @@ -1130,7 +1130,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { /* Starts listening for connections for the given pipe. */ -int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { +int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { uv_loop_t* loop = handle->loop; int i; @@ -1162,7 +1162,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { assert(handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE); for (i = 0; i < handle->pipe.serv.pending_instances; i++) { - uv_pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0); + uv__pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0); } return 0; @@ -1306,7 +1306,7 @@ static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out } -static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { +static void uv__pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { uv_read_t* req; int result; @@ -1365,15 +1365,15 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { return; error: - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; } -int uv_pipe_read_start(uv_pipe_t* handle, - uv_alloc_cb alloc_cb, - uv_read_cb read_cb) { +int uv__pipe_read_start(uv_pipe_t* handle, + uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { uv_loop_t* loop = handle->loop; handle->flags |= UV_HANDLE_READING; @@ -1391,14 +1391,14 @@ int uv_pipe_read_start(uv_pipe_t* handle, uv_fatal_error(GetLastError(), "CreateEvent"); } } - uv_pipe_queue_read(loop, handle); + uv__pipe_queue_read(loop, handle); } return 0; } -static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle, +static void uv__insert_non_overlapped_write_req(uv_pipe_t* handle, uv_write_t* req) { req->next_req = NULL; if (handle->pipe.conn.non_overlapped_writes_tail) { @@ -1434,7 +1434,7 @@ static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) { } -static void uv_queue_non_overlapped_write(uv_pipe_t* handle) { +static void uv__queue_non_overlapped_write(uv_pipe_t* handle) { uv_write_t* req = uv_remove_non_overlapped_write_req(handle); if (req) { if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc, @@ -1575,9 +1575,9 @@ static int uv__pipe_write_data(uv_loop_t* loop, return 0; } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { req->write_buffer = write_buf; - uv_insert_non_overlapped_write_req(handle, req); + uv__insert_non_overlapped_write_req(handle, req); if (handle->stream.conn.write_reqs_pending == 0) { - uv_queue_non_overlapped_write(handle); + uv__queue_non_overlapped_write(handle); } /* Request queued by the kernel. */ @@ -1790,7 +1790,7 @@ int uv__pipe_write(uv_loop_t* loop, } -static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, +static void uv__pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, uv_buf_t buf) { /* If there is an eof timer running, we don't need it any more, so discard * it. */ @@ -1802,7 +1802,7 @@ static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, } -static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error, +static void uv__pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error, uv_buf_t buf) { /* If there is an eof timer running, we don't need it any more, so discard * it. */ @@ -1814,12 +1814,12 @@ static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error, } -static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle, +static void uv__pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle, int error, uv_buf_t buf) { if (error == ERROR_BROKEN_PIPE) { - uv_pipe_read_eof(loop, handle, buf); + uv__pipe_read_eof(loop, handle, buf); } else { - uv_pipe_read_error(loop, handle, error, buf); + uv__pipe_read_error(loop, handle, error, buf); } } @@ -1890,7 +1890,7 @@ static DWORD uv__pipe_read_data(uv_loop_t* loop, /* Read into the user buffer. */ if (!ReadFile(handle->handle, buf.base, max_bytes, &bytes_read, NULL)) { - uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf); + uv__pipe_read_error_or_eof(loop, handle, GetLastError(), buf); return 0; /* Break out of read loop. */ } @@ -1977,14 +1977,14 @@ static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) { err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */ error: - uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_); + uv__pipe_read_error_or_eof(loop, handle, err, uv_null_buf_); return 0; /* Break out of read loop. */ } -void uv_process_pipe_read_req(uv_loop_t* loop, - uv_pipe_t* handle, - uv_req_t* req) { +void uv__process_pipe_read_req(uv_loop_t* loop, + uv_pipe_t* handle, + uv_req_t* req) { assert(handle->type == UV_NAMED_PIPE); handle->flags &= ~(UV_HANDLE_READ_PENDING | UV_HANDLE_CANCELLATION_PENDING); @@ -2005,7 +2005,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, * indicate an ERROR_OPERATION_ABORTED error. This error isn't relevant to * the user; we'll start a new zero-read at the end of this function. */ if (err != ERROR_OPERATION_ABORTED) - uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_); + uv__pipe_read_error_or_eof(loop, handle, err, uv_null_buf_); } else { /* The zero-read completed without error, indicating there is data @@ -2015,7 +2015,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, /* Get the number of bytes available. */ avail = 0; if (!PeekNamedPipe(handle->handle, NULL, 0, NULL, &avail, NULL)) - uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_); + uv__pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_); /* Read until we've either read all the bytes available, or the 'reading' * flag is cleared. */ @@ -2044,12 +2044,12 @@ void uv_process_pipe_read_req(uv_loop_t* loop, /* Start another zero-read request if necessary. */ if ((handle->flags & UV_HANDLE_READING) && !(handle->flags & UV_HANDLE_READ_PENDING)) { - uv_pipe_queue_read(loop, handle); + uv__pipe_queue_read(loop, handle); } } -void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, +void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, uv_write_t* req) { int err; @@ -2091,26 +2091,26 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE && handle->pipe.conn.non_overlapped_writes_tail) { assert(handle->stream.conn.write_reqs_pending > 0); - uv_queue_non_overlapped_write(handle); + uv__queue_non_overlapped_write(handle); } if (handle->stream.conn.shutdown_req != NULL && handle->stream.conn.write_reqs_pending == 0) { - uv_want_endgame(loop, (uv_handle_t*)handle); + uv__want_endgame(loop, (uv_handle_t*)handle); } DECREASE_PENDING_REQ_COUNT(handle); } -void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, +void uv__process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, uv_req_t* raw_req) { uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req; assert(handle->type == UV_NAMED_PIPE); if (handle->flags & UV_HANDLE_CLOSING) { - /* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */ + /* The req->pipeHandle should be freed already in uv__pipe_cleanup(). */ assert(req->pipeHandle == INVALID_HANDLE_VALUE); DECREASE_PENDING_REQ_COUNT(handle); return; @@ -2130,7 +2130,7 @@ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, req->pipeHandle = INVALID_HANDLE_VALUE; } if (!(handle->flags & UV_HANDLE_CLOSING)) { - uv_pipe_queue_accept(loop, handle, req, FALSE); + uv__pipe_queue_accept(loop, handle, req, FALSE); } } @@ -2138,7 +2138,7 @@ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, } -void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, +void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, uv_connect_t* req) { int err; @@ -2149,7 +2149,7 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, if (req->cb) { err = 0; if (REQ_SUCCESS(req)) { - uv_pipe_connection_init(handle); + uv__pipe_connection_init(handle); } else { err = GET_REQ_ERROR(req); } @@ -2160,7 +2160,7 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, } -void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, +void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req) { assert(handle->type == UV_NAMED_PIPE); @@ -2171,7 +2171,7 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, * is readable and we haven't seen EOF come in ourselves. */ eof_timer_init(handle); - /* If reading start the timer right now. Otherwise uv_pipe_queue_read will + /* If reading start the timer right now. Otherwise uv__pipe_queue_read will * start it. */ if (handle->flags & UV_HANDLE_READ_PENDING) { eof_timer_start(handle); @@ -2231,9 +2231,9 @@ static void eof_timer_cb(uv_timer_t* timer) { assert(pipe->type == UV_NAMED_PIPE); /* This should always be true, since we start the timer only in - * uv_pipe_queue_read after successfully calling ReadFile, or in - * uv_process_pipe_shutdown_req if a read is pending, and we always - * immediately stop the timer in uv_process_pipe_read_req. */ + * uv__pipe_queue_read after successfully calling ReadFile, or in + * uv__process_pipe_shutdown_req if a read is pending, and we always + * immediately stop the timer in uv__process_pipe_read_req. */ assert(pipe->flags & UV_HANDLE_READ_PENDING); /* If there are many packets coming off the iocp then the timer callback may @@ -2254,7 +2254,7 @@ static void eof_timer_cb(uv_timer_t* timer) { /* Report the eof and update flags. This will get reported even if the user * stopped reading in the meantime. TODO: is that okay? */ - uv_pipe_read_eof(loop, pipe, uv_null_buf_); + uv__pipe_read_eof(loop, pipe, uv_null_buf_); } @@ -2328,15 +2328,15 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { duplex_flags |= UV_HANDLE_READABLE; if (os_handle == INVALID_HANDLE_VALUE || - uv_set_pipe_handle(pipe->loop, - pipe, - os_handle, - file, - duplex_flags) == -1) { + uv__set_pipe_handle(pipe->loop, + pipe, + os_handle, + file, + duplex_flags) == -1) { return UV_EINVAL; } - uv_pipe_connection_init(pipe); + uv__pipe_connection_init(pipe); if (pipe->ipc) { assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); diff --git a/src/win/poll.c b/src/win/poll.c index 9d377596066..53a4fd97612 100644 --- a/src/win/poll.c +++ b/src/win/poll.c @@ -122,14 +122,14 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped); - result = uv_msafd_poll((SOCKET) handle->peer_socket, - afd_poll_info, - afd_poll_info, - &req->u.io.overlapped); + result = uv__msafd_poll((SOCKET) handle->peer_socket, + afd_poll_info, + afd_poll_info, + &req->u.io.overlapped); if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) { /* Queue this req, reporting an error. */ SET_REQ_ERROR(req, WSAGetLastError()); - uv_insert_pending_req(loop, req); + uv__insert_pending_req(loop, req); } } @@ -195,7 +195,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, } else if ((handle->flags & UV_HANDLE_CLOSING) && handle->submitted_events_1 == 0 && handle->submitted_events_2 == 0) { - uv_want_endgame(loop, (uv_handle_t*) handle); + uv__want_endgame(loop, (uv_handle_t*) handle); } } @@ -357,7 +357,7 @@ static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { WT_EXECUTELONGFUNCTION)) { /* Make this req pending, reporting an error. */ SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, req); + uv__insert_pending_req(loop, req); } } @@ -400,7 +400,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, } else if ((handle->flags & UV_HANDLE_CLOSING) && handle->submitted_events_1 == 0 && handle->submitted_events_2 == 0) { - uv_want_endgame(loop, (uv_handle_t*) handle); + uv__want_endgame(loop, (uv_handle_t*) handle); } } @@ -524,7 +524,7 @@ int uv_poll_stop(uv_poll_t* handle) { } -void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) { +void uv__process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) { if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { uv__fast_poll_process_poll_req(loop, handle, req); } else { @@ -533,7 +533,7 @@ void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) { } -int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) { +int uv__poll_close(uv_loop_t* loop, uv_poll_t* handle) { AFD_POLL_INFO afd_poll_info; DWORD error; int result; @@ -543,7 +543,7 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) { if (handle->submitted_events_1 == 0 && handle->submitted_events_2 == 0) { - uv_want_endgame(loop, (uv_handle_t*) handle); + uv__want_endgame(loop, (uv_handle_t*) handle); return 0; } @@ -559,10 +559,10 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) { afd_poll_info.Handles[0].Status = 0; afd_poll_info.Handles[0].Events = AFD_POLL_ALL; - result = uv_msafd_poll(handle->socket, - &afd_poll_info, - uv__get_afd_poll_info_dummy(), - uv__get_overlapped_dummy()); + result = uv__msafd_poll(handle->socket, + &afd_poll_info, + uv__get_afd_poll_info_dummy(), + uv__get_overlapped_dummy()); if (result == SOCKET_ERROR) { error = WSAGetLastError(); @@ -574,7 +574,7 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) { } -void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) { +void uv__poll_endgame(uv_loop_t* loop, uv_poll_t* handle) { assert(handle->flags & UV_HANDLE_CLOSING); assert(!(handle->flags & UV_HANDLE_CLOSED)); diff --git a/src/win/process.c b/src/win/process.c index 68d70c76b2a..24c633393fd 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -105,7 +105,7 @@ static void uv__init_global_job_handle(void) { } -static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) { +static int uv__utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) { int ws_len, r; WCHAR* ws; @@ -137,7 +137,7 @@ static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) { } -static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { +static void uv__process_init(uv_loop_t* loop, uv_process_t* handle) { uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS); handle->exit_cb = NULL; handle->pid = 0; @@ -864,7 +864,7 @@ static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) { /* Called on main thread after a child process has exited. */ -void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { +void uv__process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { int64_t exit_code; DWORD status; @@ -874,7 +874,7 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { /* If we're closing, don't call the exit callback. Just schedule a close * callback now. */ if (handle->flags & UV_HANDLE_CLOSING) { - uv_want_endgame(loop, (uv_handle_t*) handle); + uv__want_endgame(loop, (uv_handle_t*) handle); return; } @@ -902,7 +902,7 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { } -void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { +void uv__process_close(uv_loop_t* loop, uv_process_t* handle) { uv__handle_closing(handle); if (handle->wait_handle != INVALID_HANDLE_VALUE) { @@ -918,12 +918,12 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { } if (!handle->exit_cb_pending) { - uv_want_endgame(loop, (uv_handle_t*)handle); + uv__want_endgame(loop, (uv_handle_t*)handle); } } -void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) { +void uv__process_endgame(uv_loop_t* loop, uv_process_t* handle) { assert(!handle->exit_cb_pending); assert(handle->flags & UV_HANDLE_CLOSING); assert(!(handle->flags & UV_HANDLE_CLOSED)); @@ -948,7 +948,7 @@ int uv_spawn(uv_loop_t* loop, PROCESS_INFORMATION info; DWORD process_flags; - uv_process_init(loop, process); + uv__process_init(loop, process); process->exit_cb = options->exit_cb; if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { @@ -969,7 +969,7 @@ int uv_spawn(uv_loop_t* loop, UV_PROCESS_WINDOWS_HIDE_GUI | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); - err = uv_utf8_to_utf16_alloc(options->file, &application); + err = uv__utf8_to_utf16_alloc(options->file, &application); if (err) goto done; @@ -988,7 +988,7 @@ int uv_spawn(uv_loop_t* loop, if (options->cwd) { /* Explicit cwd */ - err = uv_utf8_to_utf16_alloc(options->cwd, &cwd); + err = uv__utf8_to_utf16_alloc(options->cwd, &cwd); if (err) goto done; diff --git a/src/win/req-inl.h b/src/win/req-inl.h index f2513b7d3e7..b7a345640a7 100644 --- a/src/win/req-inl.h +++ b/src/win/req-inl.h @@ -50,7 +50,7 @@ (pRtlNtStatusToDosError(GET_REQ_STATUS((req)))) #define GET_REQ_SOCK_ERROR(req) \ - (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req)))) + (uv__ntstatus_to_winsock_error(GET_REQ_STATUS((req)))) #define REGISTER_HANDLE_REQ(loop, handle, req) \ @@ -82,12 +82,12 @@ } -INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) { +INLINE static uv_req_t* uv__overlapped_to_req(OVERLAPPED* overlapped) { return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped); } -INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) { +INLINE static void uv__insert_pending_req(uv_loop_t* loop, uv_req_t* req) { req->next_req = NULL; if (loop->pending_reqs_tail) { #ifdef _DEBUG @@ -115,19 +115,19 @@ INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) { do { \ switch (((uv_handle_t*) (req)->handle_at)->type) { \ case UV_TCP: \ - uv_process_tcp_##method##_req(loop, \ + uv__process_tcp_##method##_req(loop, \ (uv_tcp_t*) ((req)->handle_at), \ req); \ break; \ \ case UV_NAMED_PIPE: \ - uv_process_pipe_##method##_req(loop, \ + uv__process_pipe_##method##_req(loop, \ (uv_pipe_t*) ((req)->handle_at), \ req); \ break; \ \ case UV_TTY: \ - uv_process_tty_##method##_req(loop, \ + uv__process_tty_##method##_req(loop, \ (uv_tty_t*) ((req)->handle_at), \ req); \ break; \ @@ -138,7 +138,7 @@ INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) { } while (0) -INLINE static int uv_process_reqs(uv_loop_t* loop) { +INLINE static int uv__process_reqs(uv_loop_t* loop) { uv_req_t* req; uv_req_t* first; uv_req_t* next; @@ -174,40 +174,40 @@ INLINE static int uv_process_reqs(uv_loop_t* loop) { case UV_SHUTDOWN: /* Tcp shutdown requests don't come here. */ assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE); - uv_process_pipe_shutdown_req( + uv__process_pipe_shutdown_req( loop, (uv_pipe_t*) ((uv_shutdown_t*) req)->handle, (uv_shutdown_t*) req); break; case UV_UDP_RECV: - uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req); + uv__process_udp_recv_req(loop, (uv_udp_t*) req->data, req); break; case UV_UDP_SEND: - uv_process_udp_send_req(loop, - ((uv_udp_send_t*) req)->handle, - (uv_udp_send_t*) req); + uv__process_udp_send_req(loop, + ((uv_udp_send_t*) req)->handle, + (uv_udp_send_t*) req); break; case UV_WAKEUP: - uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req); + uv__process_async_wakeup_req(loop, (uv_async_t*) req->data, req); break; case UV_SIGNAL_REQ: - uv_process_signal_req(loop, (uv_signal_t*) req->data, req); + uv__process_signal_req(loop, (uv_signal_t*) req->data, req); break; case UV_POLL_REQ: - uv_process_poll_req(loop, (uv_poll_t*) req->data, req); + uv__process_poll_req(loop, (uv_poll_t*) req->data, req); break; case UV_PROCESS_EXIT: - uv_process_proc_exit(loop, (uv_process_t*) req->data); + uv__process_proc_exit(loop, (uv_process_t*) req->data); break; case UV_FS_EVENT_REQ: - uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); + uv__process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); break; default: diff --git a/src/win/signal.c b/src/win/signal.c index 3d9f92cfb17..8c79871b9bb 100644 --- a/src/win/signal.c +++ b/src/win/signal.c @@ -39,7 +39,7 @@ int uv__signal_start(uv_signal_t* handle, int signum, int oneshot); -void uv_signals_init(void) { +void uv__signals_init(void) { InitializeCriticalSection(&uv__signal_lock); if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) abort(); @@ -231,7 +231,7 @@ int uv__signal_start(uv_signal_t* handle, } -void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, +void uv__process_signal_req(uv_loop_t* loop, uv_signal_t* handle, uv_req_t* req) { long dispatched_signum; @@ -254,22 +254,22 @@ void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, if (handle->flags & UV_HANDLE_CLOSING) { /* When it is closing, it must be stopped at this point. */ assert(handle->signum == 0); - uv_want_endgame(loop, (uv_handle_t*) handle); + uv__want_endgame(loop, (uv_handle_t*) handle); } } -void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) { +void uv__signal_close(uv_loop_t* loop, uv_signal_t* handle) { uv_signal_stop(handle); uv__handle_closing(handle); if (handle->pending_signum == 0) { - uv_want_endgame(loop, (uv_handle_t*) handle); + uv__want_endgame(loop, (uv_handle_t*) handle); } } -void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) { +void uv__signal_endgame(uv_loop_t* loop, uv_signal_t* handle) { assert(handle->flags & UV_HANDLE_CLOSING); assert(!(handle->flags & UV_HANDLE_CLOSED)); diff --git a/src/win/stream-inl.h b/src/win/stream-inl.h index 40f5ddd51ea..91b1e785daf 100644 --- a/src/win/stream-inl.h +++ b/src/win/stream-inl.h @@ -30,9 +30,9 @@ #include "req-inl.h" -INLINE static void uv_stream_init(uv_loop_t* loop, - uv_stream_t* handle, - uv_handle_type type) { +INLINE static void uv__stream_init(uv_loop_t* loop, + uv_stream_t* handle, + uv_handle_type type) { uv__handle_init(loop, (uv_handle_t*) handle, type); handle->write_queue_size = 0; handle->activecnt = 0; @@ -46,7 +46,7 @@ INLINE static void uv_stream_init(uv_loop_t* loop, } -INLINE static void uv_connection_init(uv_stream_t* handle) { +INLINE static void uv__connection_init(uv_stream_t* handle) { handle->flags |= UV_HANDLE_CONNECTION; } diff --git a/src/win/stream.c b/src/win/stream.c index abf477f6442..b304d170cc7 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -33,10 +33,10 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { err = ERROR_INVALID_PARAMETER; switch (stream->type) { case UV_TCP: - err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); + err = uv__tcp_listen((uv_tcp_t*)stream, backlog, cb); break; case UV_NAMED_PIPE: - err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); + err = uv__pipe_listen((uv_pipe_t*)stream, backlog, cb); break; default: assert(0); @@ -52,10 +52,10 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { err = ERROR_INVALID_PARAMETER; switch (server->type) { case UV_TCP: - err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client); + err = uv__tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client); break; case UV_NAMED_PIPE: - err = uv_pipe_accept((uv_pipe_t*)server, client); + err = uv__pipe_accept((uv_pipe_t*)server, client); break; default: assert(0); @@ -73,13 +73,13 @@ int uv__read_start(uv_stream_t* handle, err = ERROR_INVALID_PARAMETER; switch (handle->type) { case UV_TCP: - err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb); + err = uv__tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb); break; case UV_NAMED_PIPE: - err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb); + err = uv__pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb); break; case UV_TTY: - err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb); + err = uv__tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb); break; default: assert(0); @@ -97,7 +97,7 @@ int uv_read_stop(uv_stream_t* handle) { err = 0; if (handle->type == UV_TTY) { - err = uv_tty_read_stop((uv_tty_t*) handle); + err = uv__tty_read_stop((uv_tty_t*) handle); } else if (handle->type == UV_NAMED_PIPE) { uv__pipe_read_stop((uv_pipe_t*) handle); } else { @@ -124,14 +124,14 @@ int uv_write(uv_write_t* req, err = ERROR_INVALID_PARAMETER; switch (handle->type) { case UV_TCP: - err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb); + err = uv__tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb); break; case UV_NAMED_PIPE: err = uv__pipe_write( loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb); break; case UV_TTY: - err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb); + err = uv__tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb); break; default: assert(0); @@ -217,7 +217,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); - uv_want_endgame(loop, (uv_handle_t*)handle); + uv__want_endgame(loop, (uv_handle_t*)handle); return 0; } diff --git a/src/win/tcp.c b/src/win/tcp.c index 6ca11e070bf..1d9085c9e42 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -78,11 +78,11 @@ static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsign } -static int uv_tcp_set_socket(uv_loop_t* loop, - uv_tcp_t* handle, - SOCKET socket, - int family, - int imported) { +static int uv__tcp_set_socket(uv_loop_t* loop, + uv_tcp_t* handle, + SOCKET socket, + int family, + int imported) { DWORD yes = 1; int non_ifs_lsp; int err; @@ -162,7 +162,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) { if (flags & ~0xFF) return UV_EINVAL; - uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP); + uv__stream_init(loop, (uv_stream_t*) handle, UV_TCP); handle->tcp.serv.accept_reqs = NULL; handle->tcp.serv.pending_accepts = NULL; handle->socket = INVALID_SOCKET; @@ -173,7 +173,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) { handle->delayed_error = 0; /* If anything fails beyond this point we need to remove the handle from - * the handle queue, since it was added by uv__handle_init in uv_stream_init. + * the handle queue, since it was added by uv__handle_init in uv__stream_init. */ if (domain != AF_UNSPEC) { @@ -187,7 +187,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) { return uv_translate_sys_error(err); } - err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0); + err = uv__tcp_set_socket(handle->loop, handle, sock, domain, 0); if (err) { closesocket(sock); QUEUE_REMOVE(&handle->handle_queue); @@ -205,7 +205,7 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) { } -void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { +void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { int err; unsigned int i; uv_tcp_accept_t* req; @@ -286,10 +286,10 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { * See issue #1360. * */ -static int uv_tcp_try_bind(uv_tcp_t* handle, - const struct sockaddr* addr, - unsigned int addrlen, - unsigned int flags) { +static int uv__tcp_try_bind(uv_tcp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { DWORD err; int r; @@ -305,7 +305,7 @@ static int uv_tcp_try_bind(uv_tcp_t* handle, return WSAGetLastError(); } - err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0); + err = uv__tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0); if (err) { closesocket(sock); return err; @@ -385,7 +385,7 @@ static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) { } -static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { +static void uv__tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { uv_loop_t* loop = handle->loop; BOOL success; DWORD bytes; @@ -406,7 +406,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { accept_socket = socket(family, SOCK_STREAM, 0); if (accept_socket == INVALID_SOCKET) { SET_REQ_ERROR(req, WSAGetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); handle->reqs_pending++; return; } @@ -414,7 +414,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { /* Make the socket non-inheritable */ if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) { SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); handle->reqs_pending++; closesocket(accept_socket); return; @@ -440,7 +440,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { /* Process the req without IOCP. */ req->accept_socket = accept_socket; handle->reqs_pending++; - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(success)) { /* The req will be processed with IOCP. */ req->accept_socket = accept_socket; @@ -451,12 +451,12 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { req->event_handle, post_completion, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD)) { SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); } } else { /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, WSAGetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); handle->reqs_pending++; /* Destroy the preallocated client socket. */ closesocket(accept_socket); @@ -469,7 +469,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { } -static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { +static void uv__tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { uv_read_t* req; uv_buf_t buf; int result; @@ -524,7 +524,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { /* Process the req without IOCP. */ req->u.io.overlapped.InternalHigh = bytes; - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* The req will be processed with IOCP. */ if (handle->flags & UV_HANDLE_EMULATE_IOCP && @@ -533,12 +533,12 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { req->event_handle, post_completion, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD)) { SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); } } else { /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, WSAGetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); } } @@ -558,7 +558,7 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) { } -int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { +int uv__tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { unsigned int i, simultaneous_accepts; uv_tcp_accept_t* req; int err; @@ -578,10 +578,10 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { } if (!(handle->flags & UV_HANDLE_BOUND)) { - err = uv_tcp_try_bind(handle, - (const struct sockaddr*) &uv_addr_ip4_any_, - sizeof(uv_addr_ip4_any_), - 0); + err = uv__tcp_try_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + 0); if (err) return err; if (handle->delayed_error) @@ -589,7 +589,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { } if (!handle->tcp.serv.func_acceptex) { - if (!uv_get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) { + if (!uv__get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) { return WSAEAFNOSUPPORT; } } @@ -630,7 +630,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { req->event_handle = NULL; } - uv_tcp_queue_accept(handle, req); + uv__tcp_queue_accept(handle, req); } /* Initialize other unused requests too, because uv_tcp_endgame doesn't @@ -650,7 +650,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { } -int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { +int uv__tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { uv_loop_t* loop = server->loop; int err = 0; int family; @@ -672,7 +672,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { family = AF_INET; } - err = uv_tcp_set_socket(client->loop, + err = uv__tcp_set_socket(client->loop, client, req->accept_socket, family, @@ -680,7 +680,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { if (err) { closesocket(req->accept_socket); } else { - uv_connection_init((uv_stream_t*) client); + uv__connection_init((uv_stream_t*) client); /* AcceptEx() implicitly binds the accepted socket. */ client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; } @@ -693,7 +693,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { if (!(server->flags & UV_HANDLE_CLOSING)) { /* Check if we're in a middle of changing the number of pending accepts. */ if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) { - uv_tcp_queue_accept(server, req); + uv__tcp_queue_accept(server, req); } else { /* We better be switching to a single pending accept. */ assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT); @@ -706,7 +706,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { * All previously queued accept requests are now processed. * We now switch to queueing just a single accept. */ - uv_tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]); + uv__tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]); server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; } @@ -719,7 +719,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { } -int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, +int uv__tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) { uv_loop_t* loop = handle->loop; @@ -738,7 +738,7 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, uv_fatal_error(GetLastError(), "CreateEvent"); } } - uv_tcp_queue_read(loop, handle); + uv__tcp_queue_read(loop, handle); } return 0; @@ -779,7 +779,7 @@ static int uv__is_fast_loopback_fail_supported(void) { return os_info.dwBuildNumber >= 16299; } -static int uv_tcp_try_connect(uv_connect_t* req, +static int uv__tcp_try_connect(uv_connect_t* req, uv_tcp_t* handle, const struct sockaddr* addr, unsigned int addrlen, @@ -807,7 +807,7 @@ static int uv_tcp_try_connect(uv_connect_t* req, } else { abort(); } - err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0); + err = uv__tcp_try_bind(handle, bind_addr, addrlen, 0); if (err) return err; if (handle->delayed_error != 0) @@ -815,7 +815,7 @@ static int uv_tcp_try_connect(uv_connect_t* req, } if (!handle->tcp.conn.func_connectex) { - if (!uv_get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) { + if (!uv__get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) { return WSAEAFNOSUPPORT; } } @@ -850,7 +850,7 @@ static int uv_tcp_try_connect(uv_connect_t* req, /* Process the req without IOCP. */ handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); return 0; } @@ -866,7 +866,7 @@ static int uv_tcp_try_connect(uv_connect_t* req, /* Process the req without IOCP. */ handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(success)) { /* The req will be processed with IOCP. */ handle->reqs_pending++; @@ -903,7 +903,7 @@ int uv_tcp_getpeername(const uv_tcp_t* handle, } -int uv_tcp_write(uv_loop_t* loop, +int uv__tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, const uv_buf_t bufs[], @@ -941,7 +941,7 @@ int uv_tcp_write(uv_loop_t* loop, handle->reqs_pending++; handle->stream.conn.write_reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); - uv_insert_pending_req(loop, (uv_req_t*) req); + uv__insert_pending_req(loop, (uv_req_t*) req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs); @@ -954,7 +954,7 @@ int uv_tcp_write(uv_loop_t* loop, req->event_handle, post_write_completion, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) { SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); } } else { /* Send failed due to an error, report it later */ @@ -963,7 +963,7 @@ int uv_tcp_write(uv_loop_t* loop, handle->stream.conn.write_reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); SET_REQ_ERROR(req, WSAGetLastError()); - uv_insert_pending_req(loop, (uv_req_t*) req); + uv__insert_pending_req(loop, (uv_req_t*) req); } return 0; @@ -994,7 +994,7 @@ int uv__tcp_try_write(uv_tcp_t* handle, } -void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, +void uv__process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req) { DWORD bytes, flags, err; uv_buf_t buf; @@ -1115,7 +1115,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, /* Post another read if still reading and not closing. */ if ((handle->flags & UV_HANDLE_READING) && !(handle->flags & UV_HANDLE_READ_PENDING)) { - uv_tcp_queue_read(loop, handle); + uv__tcp_queue_read(loop, handle); } } @@ -1123,7 +1123,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, } -void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, +void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, uv_write_t* req) { int err; @@ -1161,7 +1161,7 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, handle->socket = INVALID_SOCKET; } if (handle->stream.conn.shutdown_req != NULL) { - uv_want_endgame(loop, (uv_handle_t*)handle); + uv__want_endgame(loop, (uv_handle_t*)handle); } } @@ -1169,7 +1169,7 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, } -void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, +void uv__process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* raw_req) { uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req; int err; @@ -1209,7 +1209,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, closesocket(req->accept_socket); req->accept_socket = INVALID_SOCKET; if (handle->flags & UV_HANDLE_LISTENING) { - uv_tcp_queue_accept(handle, req); + uv__tcp_queue_accept(handle, req); } } @@ -1217,7 +1217,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, } -void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, +void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, uv_connect_t* req) { int err; @@ -1242,7 +1242,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == 0) { - uv_connection_init((uv_stream_t*)handle); + uv__connection_init((uv_stream_t*)handle); handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; loop->active_tcp_streams++; } else { @@ -1312,7 +1312,7 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp, return WSAGetLastError(); } - err = uv_tcp_set_socket( + err = uv__tcp_set_socket( tcp->loop, tcp, socket, xfer_info->socket_info.iAddressFamily, 1); if (err) { closesocket(socket); @@ -1323,7 +1323,7 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp, tcp->flags |= UV_HANDLE_BOUND | UV_HANDLE_SHARED_TCP_SOCKET; if (xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION) { - uv_connection_init((uv_stream_t*)tcp); + uv__connection_init((uv_stream_t*)tcp); tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; } @@ -1404,7 +1404,7 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { } -static void uv_tcp_try_cancel_reqs(uv_tcp_t* tcp) { +static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) { SOCKET socket; int non_ifs_lsp; int reading; @@ -1456,9 +1456,9 @@ static void uv_tcp_try_cancel_reqs(uv_tcp_t* tcp) { } -void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { +void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { if (tcp->flags & UV_HANDLE_CONNECTION) { - uv_tcp_try_cancel_reqs(tcp); + uv__tcp_try_cancel_reqs(tcp); if (tcp->flags & UV_HANDLE_READING) { uv_read_stop((uv_stream_t*) tcp); } @@ -1498,7 +1498,7 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { uv__handle_closing(tcp); if (tcp->reqs_pending == 0) { - uv_want_endgame(tcp->loop, (uv_handle_t*)tcp); + uv__want_endgame(tcp->loop, (uv_handle_t*)tcp); } } @@ -1520,7 +1520,7 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { return uv_translate_sys_error(GetLastError()); } - err = uv_tcp_set_socket(handle->loop, + err = uv__tcp_set_socket(handle->loop, handle, sock, protocol_info.iAddressFamily, @@ -1537,7 +1537,7 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { saddr_len = sizeof(saddr); if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) { /* Socket is already connected. */ - uv_connection_init((uv_stream_t*) handle); + uv__connection_init((uv_stream_t*) handle); handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; } } @@ -1555,7 +1555,7 @@ int uv__tcp_bind(uv_tcp_t* handle, unsigned int flags) { int err; - err = uv_tcp_try_bind(handle, addr, addrlen, flags); + err = uv__tcp_try_bind(handle, addr, addrlen, flags); if (err) return uv_translate_sys_error(err); @@ -1573,7 +1573,7 @@ int uv__tcp_connect(uv_connect_t* req, uv_connect_cb cb) { int err; - err = uv_tcp_try_connect(req, handle, addr, addrlen, cb); + err = uv__tcp_try_connect(req, handle, addr, addrlen, cb); if (err) return uv_translate_sys_error(err); @@ -1634,7 +1634,7 @@ int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int f goto wsaerror; if (!SetHandleInformation((HANDLE) client1, HANDLE_FLAG_INHERIT, 0)) goto error; - if (!uv_get_acceptex_function(server, &func_acceptex)) { + if (!uv__get_acceptex_function(server, &func_acceptex)) { err = WSAEAFNOSUPPORT; goto cleanup; } diff --git a/src/win/tty.c b/src/win/tty.c index 1b9d4f85326..98c58883dcc 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -67,10 +67,10 @@ #define CURSOR_SIZE_SMALL 25 #define CURSOR_SIZE_LARGE 100 -static void uv_tty_capture_initial_style( +static void uv__tty_capture_initial_style( CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info, CONSOLE_CURSOR_INFO* cursor_info); -static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); +static void uv__tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); static int uv__cancel_read_console(uv_tty_t* handle); @@ -163,7 +163,7 @@ static BOOL uv__need_check_vterm_state = TRUE; static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED; static void uv__determine_vterm_state(HANDLE handle); -void uv_console_init(void) { +void uv__console_init(void) { if (uv_sem_init(&uv_tty_output_lock, 1)) abort(); uv__tty_console_handle = CreateFileW(L"CONOUT$", @@ -238,16 +238,16 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { uv__determine_vterm_state(handle); /* Remember the original console text attributes and cursor info. */ - uv_tty_capture_initial_style(&screen_buffer_info, &cursor_info); + uv__tty_capture_initial_style(&screen_buffer_info, &cursor_info); - uv_tty_update_virtual_window(&screen_buffer_info); + uv__tty_update_virtual_window(&screen_buffer_info); uv_sem_post(&uv_tty_output_lock); } - uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY); - uv_connection_init((uv_stream_t*) tty); + uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); + uv__connection_init((uv_stream_t*) tty); tty->handle = handle; tty->u.fd = fd; @@ -289,7 +289,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { /* Set the default console text attributes based on how the console was * configured when libuv started. */ -static void uv_tty_capture_initial_style( +static void uv__tty_capture_initial_style( CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info, CONSOLE_CURSOR_INFO* cursor_info) { static int style_captured = 0; @@ -380,7 +380,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { was_reading = 1; alloc_cb = tty->alloc_cb; read_cb = tty->read_cb; - err = uv_tty_read_stop(tty); + err = uv__tty_read_stop(tty); if (err) { return uv_translate_sys_error(err); } @@ -404,7 +404,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { /* If we just stopped reading, restart. */ if (was_reading) { - err = uv_tty_read_start(tty, alloc_cb, read_cb); + err = uv__tty_read_start(tty, alloc_cb, read_cb); if (err) { return uv_translate_sys_error(err); } @@ -422,7 +422,7 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { } uv_sem_wait(&uv_tty_output_lock); - uv_tty_update_virtual_window(&info); + uv__tty_update_virtual_window(&info); uv_sem_post(&uv_tty_output_lock); *width = uv_tty_virtual_width; @@ -452,7 +452,7 @@ static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) { } -static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) { +static void uv__tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) { uv_read_t* req; BOOL r; @@ -475,7 +475,7 @@ static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) { if (!r) { handle->tty.rd.read_raw_wait = NULL; SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); } handle->flags |= UV_HANDLE_READ_PENDING; @@ -579,7 +579,7 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { } -static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { +static void uv__tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { uv_read_t* req; BOOL r; @@ -611,7 +611,7 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { WT_EXECUTELONGFUNCTION); if (!r) { SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); } handle->flags |= UV_HANDLE_READ_PENDING; @@ -619,11 +619,11 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { } -static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) { +static void uv__tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) { if (handle->flags & UV_HANDLE_TTY_RAW) { - uv_tty_queue_read_raw(loop, handle); + uv__tty_queue_read_raw(loop, handle); } else { - uv_tty_queue_read_line(loop, handle); + uv__tty_queue_read_line(loop, handle); } } @@ -947,7 +947,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, /* Wait for more input events. */ if ((handle->flags & UV_HANDLE_READING) && !(handle->flags & UV_HANDLE_READ_PENDING)) { - uv_tty_queue_read(loop, handle); + uv__tty_queue_read(loop, handle); } DECREASE_PENDING_REQ_COUNT(handle); @@ -992,14 +992,14 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, /* Wait for more input events. */ if ((handle->flags & UV_HANDLE_READING) && !(handle->flags & UV_HANDLE_READ_PENDING)) { - uv_tty_queue_read(loop, handle); + uv__tty_queue_read(loop, handle); } DECREASE_PENDING_REQ_COUNT(handle); } -void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, +void uv__process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, uv_req_t* req) { assert(handle->type == UV_TTY); assert(handle->flags & UV_HANDLE_TTY_READABLE); @@ -1015,7 +1015,7 @@ void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, } -int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, +int uv__tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) { uv_loop_t* loop = handle->loop; @@ -1038,20 +1038,20 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, * Short-circuit if this could be the case. */ if (handle->tty.rd.last_key_len > 0) { SET_REQ_SUCCESS(&handle->read_req); - uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req); + uv__insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req); /* Make sure no attempt is made to insert it again until it's handled. */ handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; return 0; } - uv_tty_queue_read(loop, handle); + uv__tty_queue_read(loop, handle); return 0; } -int uv_tty_read_stop(uv_tty_t* handle) { +int uv__tty_read_stop(uv_tty_t* handle) { INPUT_RECORD record; DWORD written, err; @@ -1137,7 +1137,7 @@ static int uv__cancel_read_console(uv_tty_t* handle) { } -static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { +static void uv__tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { uv_tty_virtual_width = info->dwSize.X; uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1; @@ -1160,12 +1160,12 @@ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { } -static COORD uv_tty_make_real_coord(uv_tty_t* handle, +static COORD uv__tty_make_real_coord(uv_tty_t* handle, CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y, unsigned char y_relative) { COORD result; - uv_tty_update_virtual_window(info); + uv__tty_update_virtual_window(info); /* Adjust y position */ if (y_relative) { @@ -1197,7 +1197,7 @@ static COORD uv_tty_make_real_coord(uv_tty_t* handle, } -static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length, +static int uv__tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length, DWORD* error) { DWORD written; @@ -1218,7 +1218,7 @@ static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length, } -static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative, +static int uv__tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative, int y, unsigned char y_relative, DWORD* error) { CONSOLE_SCREEN_BUFFER_INFO info; COORD pos; @@ -1232,7 +1232,7 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative, *error = GetLastError(); } - pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative); + pos = uv__tty_make_real_coord(handle, &info, x, x_relative, y, y_relative); if (!SetConsoleCursorPosition(handle->handle, pos)) { if (GetLastError() == ERROR_INVALID_PARAMETER) { @@ -1248,7 +1248,7 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative, } -static int uv_tty_reset(uv_tty_t* handle, DWORD* error) { +static int uv__tty_reset(uv_tty_t* handle, DWORD* error) { const COORD origin = {0, 0}; const WORD char_attrs = uv_tty_default_text_attributes; CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; @@ -1300,7 +1300,7 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) { /* Move the virtual window up to the top. */ uv_tty_virtual_offset = 0; - uv_tty_update_virtual_window(&screen_buffer_info); + uv__tty_update_virtual_window(&screen_buffer_info); /* Reset the cursor size and the cursor state. */ if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) { @@ -1312,7 +1312,7 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) { } -static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen, +static int uv__tty_clear(uv_tty_t* handle, int dir, char entire_screen, DWORD* error) { CONSOLE_SCREEN_BUFFER_INFO info; COORD start, end; @@ -1341,7 +1341,7 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen, x2r = 1; } else { /* Clear to end of row. We pretend the console is 65536 characters wide, - * uv_tty_make_real_coord will clip it to the actual console width. */ + * uv__tty_make_real_coord will clip it to the actual console width. */ x2 = 0xffff; x2r = 0; } @@ -1364,8 +1364,8 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen, return -1; } - start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r); - end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r); + start = uv__tty_make_real_coord(handle, &info, x1, x1r, y1, y1r); + end = uv__tty_make_real_coord(handle, &info, x2, x2r, y2, y2r); count = (end.Y * info.dwSize.X + end.X) - (start.Y * info.dwSize.X + start.X) + 1; @@ -1400,7 +1400,7 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen, info.wAttributes |= bg >> 4; \ } while (0) -static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) { +static int uv__tty_set_style(uv_tty_t* handle, DWORD* error) { unsigned short argc = handle->tty.wr.ansi_csi_argc; unsigned short* argv = handle->tty.wr.ansi_csi_argv; int i; @@ -1556,7 +1556,7 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) { } -static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes, +static int uv__tty_save_state(uv_tty_t* handle, unsigned char save_attributes, DWORD* error) { CONSOLE_SCREEN_BUFFER_INFO info; @@ -1569,10 +1569,11 @@ static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes, return -1; } - uv_tty_update_virtual_window(&info); + uv__tty_update_virtual_window(&info); handle->tty.wr.saved_position.X = info.dwCursorPosition.X; - handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset; + handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - + uv_tty_virtual_offset; handle->flags |= UV_HANDLE_TTY_SAVED_POSITION; if (save_attributes) { @@ -1585,7 +1586,7 @@ static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes, } -static int uv_tty_restore_state(uv_tty_t* handle, +static int uv__tty_restore_state(uv_tty_t* handle, unsigned char restore_attributes, DWORD* error) { CONSOLE_SCREEN_BUFFER_INFO info; WORD new_attributes; @@ -1595,7 +1596,7 @@ static int uv_tty_restore_state(uv_tty_t* handle, } if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) { - if (uv_tty_move_caret(handle, + if (uv__tty_move_caret(handle, handle->tty.wr.saved_position.X, 0, handle->tty.wr.saved_position.Y, @@ -1625,7 +1626,7 @@ static int uv_tty_restore_state(uv_tty_t* handle, return 0; } -static int uv_tty_set_cursor_visibility(uv_tty_t* handle, +static int uv__tty_set_cursor_visibility(uv_tty_t* handle, BOOL visible, DWORD* error) { CONSOLE_CURSOR_INFO cursor_info; @@ -1645,7 +1646,7 @@ static int uv_tty_set_cursor_visibility(uv_tty_t* handle, return 0; } -static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) { +static int uv__tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) { CONSOLE_CURSOR_INFO cursor_info; if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) { @@ -1670,7 +1671,7 @@ static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) { } -static int uv_tty_write_bufs(uv_tty_t* handle, +static int uv__tty_write_bufs(uv_tty_t* handle, const uv_buf_t bufs[], unsigned int nbufs, DWORD* error) { @@ -1683,7 +1684,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, #define FLUSH_TEXT() \ do { \ if (utf16_buf_used > 0) { \ - uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \ + uv__tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \ utf16_buf_used = 0; \ } \ } while (0) @@ -1802,21 +1803,21 @@ static int uv_tty_write_bufs(uv_tty_t* handle, case 'c': /* Full console reset. */ FLUSH_TEXT(); - uv_tty_reset(handle, error); + uv__tty_reset(handle, error); ansi_parser_state = ANSI_NORMAL; continue; case '7': /* Save the cursor position and text attributes. */ FLUSH_TEXT(); - uv_tty_save_state(handle, 1, error); + uv__tty_save_state(handle, 1, error); ansi_parser_state = ANSI_NORMAL; continue; case '8': /* Restore the cursor position and text attributes */ FLUSH_TEXT(); - uv_tty_restore_state(handle, 1, error); + uv__tty_restore_state(handle, 1, error); ansi_parser_state = ANSI_NORMAL; continue; @@ -1849,7 +1850,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, ? handle->tty.wr.ansi_csi_argv[0] : 1; if (style >= 0 && style <= 6) { FLUSH_TEXT(); - uv_tty_set_cursor_shape(handle, style, error); + uv__tty_set_cursor_shape(handle, style, error); } } @@ -1947,7 +1948,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, if (handle->tty.wr.ansi_csi_argc == 1 && handle->tty.wr.ansi_csi_argv[0] == 25) { FLUSH_TEXT(); - uv_tty_set_cursor_visibility(handle, 0, error); + uv__tty_set_cursor_visibility(handle, 0, error); } break; @@ -1956,7 +1957,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, if (handle->tty.wr.ansi_csi_argc == 1 && handle->tty.wr.ansi_csi_argv[0] == 25) { FLUSH_TEXT(); - uv_tty_set_cursor_visibility(handle, 1, error); + uv__tty_set_cursor_visibility(handle, 1, error); } break; } @@ -1970,7 +1971,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, FLUSH_TEXT(); y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1); - uv_tty_move_caret(handle, 0, 1, y, 1, error); + uv__tty_move_caret(handle, 0, 1, y, 1, error); break; case 'B': @@ -1978,7 +1979,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, FLUSH_TEXT(); y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1; - uv_tty_move_caret(handle, 0, 1, y, 1, error); + uv__tty_move_caret(handle, 0, 1, y, 1, error); break; case 'C': @@ -1986,7 +1987,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, FLUSH_TEXT(); x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1; - uv_tty_move_caret(handle, x, 1, 0, 1, error); + uv__tty_move_caret(handle, x, 1, 0, 1, error); break; case 'D': @@ -1994,7 +1995,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, FLUSH_TEXT(); x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1); - uv_tty_move_caret(handle, x, 1, 0, 1, error); + uv__tty_move_caret(handle, x, 1, 0, 1, error); break; case 'E': @@ -2002,7 +2003,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, FLUSH_TEXT(); y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1; - uv_tty_move_caret(handle, 0, 0, y, 1, error); + uv__tty_move_caret(handle, 0, 0, y, 1, error); break; case 'F': @@ -2010,7 +2011,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, FLUSH_TEXT(); y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1); - uv_tty_move_caret(handle, 0, 0, y, 1, error); + uv__tty_move_caret(handle, 0, 0, y, 1, error); break; case 'G': @@ -2019,7 +2020,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0]) ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0; - uv_tty_move_caret(handle, x, 0, 0, 1, error); + uv__tty_move_caret(handle, x, 0, 0, 1, error); break; case 'H': @@ -2032,7 +2033,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1]) ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0; - uv_tty_move_caret(handle, x, 0, y, 0, error); + uv__tty_move_caret(handle, x, 0, y, 0, error); break; case 'J': @@ -2041,7 +2042,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0; if (d >= 0 && d <= 2) { - uv_tty_clear(handle, d, 1, error); + uv__tty_clear(handle, d, 1, error); } break; @@ -2051,26 +2052,26 @@ static int uv_tty_write_bufs(uv_tty_t* handle, d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0; if (d >= 0 && d <= 2) { - uv_tty_clear(handle, d, 0, error); + uv__tty_clear(handle, d, 0, error); } break; case 'm': /* Set style */ FLUSH_TEXT(); - uv_tty_set_style(handle, error); + uv__tty_set_style(handle, error); break; case 's': /* Save the cursor position. */ FLUSH_TEXT(); - uv_tty_save_state(handle, 0, error); + uv__tty_save_state(handle, 0, error); break; case 'u': /* Restore the cursor position */ FLUSH_TEXT(); - uv_tty_restore_state(handle, 0, error); + uv__tty_restore_state(handle, 0, error); break; } } @@ -2179,7 +2180,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, } -int uv_tty_write(uv_loop_t* loop, +int uv__tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle, const uv_buf_t bufs[], @@ -2197,13 +2198,13 @@ int uv_tty_write(uv_loop_t* loop, req->u.io.queued_bytes = 0; - if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) { + if (!uv__tty_write_bufs(handle, bufs, nbufs, &error)) { SET_REQ_SUCCESS(req); } else { SET_REQ_ERROR(req, error); } - uv_insert_pending_req(loop, (uv_req_t*) req); + uv__insert_pending_req(loop, (uv_req_t*) req); return 0; } @@ -2217,14 +2218,14 @@ int uv__tty_try_write(uv_tty_t* handle, if (handle->stream.conn.write_reqs_pending > 0) return UV_EAGAIN; - if (uv_tty_write_bufs(handle, bufs, nbufs, &error)) + if (uv__tty_write_bufs(handle, bufs, nbufs, &error)) return uv_translate_sys_error(error); return uv__count_bufs(bufs, nbufs); } -void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, +void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, uv_write_t* req) { int err; @@ -2239,17 +2240,17 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, handle->stream.conn.write_reqs_pending--; if (handle->stream.conn.shutdown_req != NULL && handle->stream.conn.write_reqs_pending == 0) { - uv_want_endgame(loop, (uv_handle_t*)handle); + uv__want_endgame(loop, (uv_handle_t*)handle); } DECREASE_PENDING_REQ_COUNT(handle); } -void uv_tty_close(uv_tty_t* handle) { +void uv__tty_close(uv_tty_t* handle) { assert(handle->u.fd == -1 || handle->u.fd > 2); if (handle->flags & UV_HANDLE_READING) - uv_tty_read_stop(handle); + uv__tty_read_stop(handle); if (handle->u.fd == -1) CloseHandle(handle->handle); @@ -2262,12 +2263,12 @@ void uv_tty_close(uv_tty_t* handle) { uv__handle_closing(handle); if (handle->reqs_pending == 0) { - uv_want_endgame(handle->loop, (uv_handle_t*) handle); + uv__want_endgame(handle->loop, (uv_handle_t*) handle); } } -void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { +void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { if (!(handle->flags & UV_HANDLE_TTY_READABLE) && handle->stream.conn.shutdown_req != NULL && handle->stream.conn.write_reqs_pending == 0) { @@ -2302,20 +2303,20 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { /* - * uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working + * uv__process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working * TODO: find a way to remove it */ -void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, +void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, uv_req_t* raw_req) { abort(); } /* - * uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working + * uv__process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working * TODO: find a way to remove it */ -void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, +void uv__process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, uv_connect_t* req) { abort(); } diff --git a/src/win/udp.c b/src/win/udp.c index 3a86e0ea8c3..407aa6cbdb1 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -60,7 +60,7 @@ int uv_udp_getsockname(const uv_udp_t* handle, } -static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, +static int uv__udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, int family) { DWORD yes = 1; WSAPROTOCOL_INFOW info; @@ -106,8 +106,8 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; - handle->func_wsarecv = uv_wsarecv_workaround; - handle->func_wsarecvfrom = uv_wsarecvfrom_workaround; + handle->func_wsarecv = uv__wsarecv_workaround; + handle->func_wsarecvfrom = uv__wsarecvfrom_workaround; } else if (GetLastError() != ERROR_INVALID_FUNCTION) { return GetLastError(); } @@ -155,7 +155,7 @@ int uv__udp_init_ex(uv_loop_t* loop, return uv_translate_sys_error(err); } - err = uv_udp_set_socket(handle->loop, handle, sock, domain); + err = uv__udp_set_socket(handle->loop, handle, sock, domain); if (err) { closesocket(sock); QUEUE_REMOVE(&handle->handle_queue); @@ -167,7 +167,7 @@ int uv__udp_init_ex(uv_loop_t* loop, } -void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) { +void uv__udp_close(uv_loop_t* loop, uv_udp_t* handle) { uv_udp_recv_stop(handle); closesocket(handle->socket); handle->socket = INVALID_SOCKET; @@ -175,12 +175,12 @@ void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) { uv__handle_closing(handle); if (handle->reqs_pending == 0) { - uv_want_endgame(loop, (uv_handle_t*) handle); + uv__want_endgame(loop, (uv_handle_t*) handle); } } -void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) { +void uv__udp_endgame(uv_loop_t* loop, uv_udp_t* handle) { if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); @@ -194,10 +194,10 @@ int uv_udp_using_recvmmsg(const uv_udp_t* handle) { } -static int uv_udp_maybe_bind(uv_udp_t* handle, - const struct sockaddr* addr, - unsigned int addrlen, - unsigned int flags) { +static int uv__udp_maybe_bind(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen, + unsigned int flags) { int r; int err; DWORD no = 0; @@ -216,7 +216,7 @@ static int uv_udp_maybe_bind(uv_udp_t* handle, return WSAGetLastError(); } - err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family); + err = uv__udp_set_socket(handle->loop, handle, sock, addr->sa_family); if (err) { closesocket(sock); return err; @@ -264,7 +264,7 @@ static int uv_udp_maybe_bind(uv_udp_t* handle, } -static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { +static void uv__udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { uv_req_t* req; uv_buf_t buf; DWORD bytes, flags; @@ -311,7 +311,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { handle->flags |= UV_HANDLE_READ_PENDING; req->u.io.overlapped.InternalHigh = bytes; handle->reqs_pending++; - uv_insert_pending_req(loop, req); + uv__insert_pending_req(loop, req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* The req will be processed with IOCP. */ handle->flags |= UV_HANDLE_READ_PENDING; @@ -319,7 +319,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { } else { /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, WSAGetLastError()); - uv_insert_pending_req(loop, req); + uv__insert_pending_req(loop, req); handle->reqs_pending++; } @@ -343,7 +343,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { handle->flags |= UV_HANDLE_READ_PENDING; req->u.io.overlapped.InternalHigh = bytes; handle->reqs_pending++; - uv_insert_pending_req(loop, req); + uv__insert_pending_req(loop, req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* The req will be processed with IOCP. */ handle->flags |= UV_HANDLE_READ_PENDING; @@ -351,7 +351,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { } else { /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, WSAGetLastError()); - uv_insert_pending_req(loop, req); + uv__insert_pending_req(loop, req); handle->reqs_pending++; } } @@ -367,10 +367,10 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, return UV_EALREADY; } - err = uv_udp_maybe_bind(handle, - (const struct sockaddr*) &uv_addr_ip4_any_, - sizeof(uv_addr_ip4_any_), - 0); + err = uv__udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + 0); if (err) return uv_translate_sys_error(err); @@ -384,7 +384,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, /* If reading was stopped and then started again, there could still be a recv * request pending. */ if (!(handle->flags & UV_HANDLE_READ_PENDING)) - uv_udp_queue_recv(loop, handle); + uv__udp_queue_recv(loop, handle); return 0; } @@ -433,7 +433,7 @@ static int uv__send(uv_udp_send_t* req, handle->send_queue_size += req->u.io.queued_bytes; handle->send_queue_count++; REGISTER_HANDLE_REQ(loop, handle, req); - uv_insert_pending_req(loop, (uv_req_t*)req); + uv__insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs); @@ -450,7 +450,7 @@ static int uv__send(uv_udp_send_t* req, } -void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, +void uv__process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req) { uv_buf_t buf; int partial; @@ -554,14 +554,14 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, /* Post another read if still reading and not closing. */ if ((handle->flags & UV_HANDLE_READING) && !(handle->flags & UV_HANDLE_READ_PENDING)) { - uv_udp_queue_recv(loop, handle); + uv__udp_queue_recv(loop, handle); } DECREASE_PENDING_REQ_COUNT(handle); } -void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, +void uv__process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, uv_udp_send_t* req) { int err; @@ -598,10 +598,10 @@ static int uv__udp_set_membership4(uv_udp_t* handle, return UV_EINVAL; /* If the socket is unbound, bind to inaddr_any. */ - err = uv_udp_maybe_bind(handle, - (const struct sockaddr*) &uv_addr_ip4_any_, - sizeof(uv_addr_ip4_any_), - UV_UDP_REUSEADDR); + err = uv__udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + UV_UDP_REUSEADDR); if (err) return uv_translate_sys_error(err); @@ -652,10 +652,10 @@ int uv__udp_set_membership6(uv_udp_t* handle, if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6)) return UV_EINVAL; - err = uv_udp_maybe_bind(handle, - (const struct sockaddr*) &uv_addr_ip6_any_, - sizeof(uv_addr_ip6_any_), - UV_UDP_REUSEADDR); + err = uv__udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip6_any_, + sizeof(uv_addr_ip6_any_), + UV_UDP_REUSEADDR); if (err) return uv_translate_sys_error(err); @@ -708,10 +708,10 @@ static int uv__udp_set_source_membership4(uv_udp_t* handle, return UV_EINVAL; /* If the socket is unbound, bind to inaddr_any. */ - err = uv_udp_maybe_bind(handle, - (const struct sockaddr*) &uv_addr_ip4_any_, - sizeof(uv_addr_ip4_any_), - UV_UDP_REUSEADDR); + err = uv__udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + UV_UDP_REUSEADDR); if (err) return uv_translate_sys_error(err); @@ -763,10 +763,10 @@ int uv__udp_set_source_membership6(uv_udp_t* handle, if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6)) return UV_EINVAL; - err = uv_udp_maybe_bind(handle, - (const struct sockaddr*) &uv_addr_ip6_any_, - sizeof(uv_addr_ip6_any_), - UV_UDP_REUSEADDR); + err = uv__udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip6_any_, + sizeof(uv_addr_ip6_any_), + UV_UDP_REUSEADDR); if (err) return uv_translate_sys_error(err); @@ -962,10 +962,10 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { return uv_translate_sys_error(GetLastError()); } - err = uv_udp_set_socket(handle->loop, - handle, - sock, - protocol_info.iAddressFamily); + err = uv__udp_set_socket(handle->loop, + handle, + sock, + protocol_info.iAddressFamily); if (err) return uv_translate_sys_error(err); @@ -1044,7 +1044,7 @@ int uv__udp_bind(uv_udp_t* handle, unsigned int flags) { int err; - err = uv_udp_maybe_bind(handle, addr, addrlen, flags); + err = uv__udp_maybe_bind(handle, addr, addrlen, flags); if (err) return uv_translate_sys_error(err); @@ -1066,7 +1066,7 @@ int uv__udp_connect(uv_udp_t* handle, else return UV_EINVAL; - err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); + err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0); if (err) return uv_translate_sys_error(err); } @@ -1117,7 +1117,7 @@ int uv__udp_send(uv_udp_send_t* req, else return UV_EINVAL; - err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); + err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0); if (err) return uv_translate_sys_error(err); } @@ -1159,7 +1159,7 @@ int uv__udp_try_send(uv_udp_t* handle, bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; else return UV_EINVAL; - err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); + err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0); if (err) return uv_translate_sys_error(err); } diff --git a/src/win/winapi.c b/src/win/winapi.c index c04af61ba42..53147b8262e 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -48,7 +48,7 @@ sSetWinEventHook pSetWinEventHook; /* ws2_32.dll function pointer */ uv_sGetHostNameW pGetHostNameW; -void uv_winapi_init(void) { +void uv__winapi_init(void) { HMODULE ntdll_module; HMODULE powrprof_module; HMODULE user32_module; diff --git a/src/win/winsock.c b/src/win/winsock.c index 4cf6e6b042c..a68b095366a 100644 --- a/src/win/winsock.c +++ b/src/win/winsock.c @@ -38,7 +38,7 @@ struct sockaddr_in6 uv_addr_ip6_any_; /* * Retrieves the pointer to a winsock extension function. */ -static BOOL uv_get_extension_function(SOCKET socket, GUID guid, +static BOOL uv__get_extension_function(SOCKET socket, GUID guid, void **target) { int result; DWORD bytes; @@ -62,20 +62,20 @@ static BOOL uv_get_extension_function(SOCKET socket, GUID guid, } -BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) { +BOOL uv__get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) { const GUID wsaid_acceptex = WSAID_ACCEPTEX; - return uv_get_extension_function(socket, wsaid_acceptex, (void**)target); + return uv__get_extension_function(socket, wsaid_acceptex, (void**)target); } -BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) { +BOOL uv__get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) { const GUID wsaid_connectex = WSAID_CONNECTEX; - return uv_get_extension_function(socket, wsaid_connectex, (void**)target); + return uv__get_extension_function(socket, wsaid_connectex, (void**)target); } -void uv_winsock_init(void) { +void uv__winsock_init(void) { WSADATA wsa_data; int errorno; SOCKET dummy; @@ -134,7 +134,7 @@ void uv_winsock_init(void) { } -int uv_ntstatus_to_winsock_error(NTSTATUS status) { +int uv__ntstatus_to_winsock_error(NTSTATUS status) { switch (status) { case STATUS_SUCCESS: return ERROR_SUCCESS; @@ -267,7 +267,7 @@ int uv_ntstatus_to_winsock_error(NTSTATUS status) { * the user to use the default msafd driver, doesn't work when other LSPs are * stacked on top of it. */ -int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers, +int WSAAPI uv__wsarecv_workaround(SOCKET socket, WSABUF* buffers, DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) { NTSTATUS status; @@ -346,7 +346,7 @@ int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers, break; default: - error = uv_ntstatus_to_winsock_error(status); + error = uv__ntstatus_to_winsock_error(status); break; } @@ -360,8 +360,8 @@ int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers, } -/* See description of uv_wsarecv_workaround. */ -int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, +/* See description of uv__wsarecv_workaround. */ +int WSAAPI uv__wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr, int* addr_len, WSAOVERLAPPED *overlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) { @@ -444,7 +444,7 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, break; default: - error = uv_ntstatus_to_winsock_error(status); + error = uv__ntstatus_to_winsock_error(status); break; } @@ -458,7 +458,7 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, } -int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, +int WSAAPI uv__msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) { IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK* iosb_ptr; @@ -531,7 +531,7 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, break; default: - error = uv_ntstatus_to_winsock_error(status); + error = uv__ntstatus_to_winsock_error(status); break; } From 2bc22c40eb68f3b38d1ae3ea68ef2f180cbe9fef Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 16 Feb 2022 13:56:25 +0100 Subject: [PATCH 133/713] test: fix flaky udp_mmsg test Take into account that the data may not be already available in the socket causing the `recvmsg()` / `recvmmsg()` calls to return `EAGAIN` or `EWOULDBLOCK`. Fixes: https://github.com/libuv/libuv/issues/3479 --- test/test-udp-mmsg.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/test/test-udp-mmsg.c b/test/test-udp-mmsg.c index 401c4f33e7c..f722608a185 100644 --- a/test/test-udp-mmsg.c +++ b/test/test-udp-mmsg.c @@ -37,6 +37,7 @@ static uv_udp_t recver; static uv_udp_t sender; static int recv_cb_called; +static int received_datagrams; static int close_cb_called; static int alloc_cb_called; @@ -68,10 +69,10 @@ static void close_cb(uv_handle_t* handle) { static void recv_cb(uv_udp_t* handle, - ssize_t nread, - const uv_buf_t* rcvbuf, - const struct sockaddr* addr, - unsigned flags) { + ssize_t nread, + const uv_buf_t* rcvbuf, + const struct sockaddr* addr, + unsigned flags) { ASSERT_GE(nread, 0); /* free and return if this is a mmsg free-only callback invocation */ @@ -82,14 +83,20 @@ static void recv_cb(uv_udp_t* handle, return; } - ASSERT_EQ(nread, 4); - ASSERT_NOT_NULL(addr); - ASSERT_MEM_EQ("PING", rcvbuf->base, nread); + if (nread == 0) { + /* There can be no more available data for the time being. */ + ASSERT_NULL(addr); + } else { + ASSERT_EQ(nread, 4); + ASSERT_NOT_NULL(addr); + ASSERT_MEM_EQ("PING", rcvbuf->base, nread); + received_datagrams++; + } recv_cb_called++; - if (recv_cb_called == NUM_SENDS) { - uv_close((uv_handle_t*)handle, close_cb); - uv_close((uv_handle_t*)&sender, close_cb); + if (received_datagrams == NUM_SENDS) { + uv_close((uv_handle_t*) handle, close_cb); + uv_close((uv_handle_t*) &sender, close_cb); } /* Don't free if the buffer could be reused via mmsg */ @@ -124,7 +131,7 @@ TEST_IMPL(udp_mmsg) { ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT_EQ(close_cb_called, 2); - ASSERT_EQ(recv_cb_called, NUM_SENDS); + ASSERT_EQ(received_datagrams, NUM_SENDS); ASSERT_EQ(sender.send_queue_size, 0); ASSERT_EQ(recver.send_queue_size, 0); From e0a5f58d2cb698f5fa2a7a3bff4fb55c4e1f3449 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 20 Feb 2022 12:17:13 +0100 Subject: [PATCH 134/713] test: fix ipc_send_recv_pipe flakiness (#3478) The read callback failed to handle the `nread == 0` case, which is rare to non-existent on the systems we test on but apparently happens often enough on Solaris on SPARC to draw attention. Fixes #3469. --- test/test-ipc-send-recv.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/test-ipc-send-recv.c b/test/test-ipc-send-recv.c index 12d4e33221f..8a0e9708f02 100644 --- a/test/test-ipc-send-recv.c +++ b/test/test-ipc-send-recv.c @@ -308,8 +308,12 @@ static void read_cb(uv_stream_t* handle, return; } + ASSERT_GE(nread, 0); + pipe = (uv_pipe_t*) handle; - do { + ASSERT_EQ(pipe, &ctx2.channel); + + while (uv_pipe_pending_count(pipe) > 0) { if (++read_cb_count == 2) { recv = &ctx2.recv; write_req = &ctx2.write_req; @@ -318,10 +322,6 @@ static void read_cb(uv_stream_t* handle, write_req = &ctx2.write_req2; } - ASSERT(pipe == &ctx2.channel); - ASSERT(nread >= 0); - ASSERT(uv_pipe_pending_count(pipe) > 0); - pending = uv_pipe_pending_type(pipe); ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP); @@ -344,7 +344,7 @@ static void read_cb(uv_stream_t* handle, &recv->stream, write2_cb); ASSERT(r == 0); - } while (uv_pipe_pending_count(pipe) > 0); + } } static void send_recv_start(void) { From c2a345fa67ad8998a621cd0c77dbf2db82436959 Mon Sep 17 00:00:00 2001 From: wyckster Date: Tue, 22 Feb 2022 10:58:43 -0500 Subject: [PATCH 135/713] doc: checkout -> check out (#3489) "check out" is a verb phrase, but "checkout" is a noun. Since it is being used as a verb, the spelling "check out" is required. --- docs/src/design.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/design.rst b/docs/src/design.rst index a23e33a214a..0f5580c7e95 100644 --- a/docs/src/design.rst +++ b/docs/src/design.rst @@ -125,7 +125,7 @@ File I/O Unlike network I/O, there are no platform-specific file I/O primitives libuv could rely on, so the current approach is to run blocking file I/O operations in a thread pool. -For a thorough explanation of the cross-platform file I/O landscape, checkout +For a thorough explanation of the cross-platform file I/O landscape, check out `this post `_. libuv currently uses a global thread pool on which all loops can queue work. 3 types of From f3e0bffcb147fcda65c27007d276cc95ca084a18 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 22 Feb 2022 10:59:06 -0500 Subject: [PATCH 136/713] core: change uv_get_password uid/gid to unsigned (#3476) Added in https://github.com/libuv/libuv/pull/742, these values are typically defined as unsigned (since Linux 2.4). Only -1 is special, representing an invalid id (e.g. see setreuid). --- include/uv.h | 4 ++-- test/test-get-passwd.c | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/uv.h b/include/uv.h index 606083c87de..9a418b995cd 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1133,8 +1133,8 @@ struct uv_interface_address_s { struct uv_passwd_s { char* username; - long uid; - long gid; + unsigned long uid; + unsigned long gid; char* shell; char* homedir; }; diff --git a/test/test-get-passwd.c b/test/test-get-passwd.c index 865c07d6515..d2c7431fe7f 100644 --- a/test/test-get-passwd.c +++ b/test/test-get-passwd.c @@ -22,6 +22,10 @@ #include "uv.h" #include "task.h" #include +#ifndef _WIN32 +#include +#include +#endif TEST_IMPL(get_passwd) { /* TODO(gengjiawen): Fix test on QEMU. */ @@ -64,11 +68,15 @@ TEST_IMPL(get_passwd) { #endif #ifdef _WIN32 - ASSERT(pwd.uid == -1); - ASSERT(pwd.gid == -1); + ASSERT_EQ(pwd.uid, (unsigned)-1); + ASSERT_EQ(pwd.gid, (unsigned)-1); #else - ASSERT(pwd.uid >= 0); - ASSERT(pwd.gid >= 0); + ASSERT_NE(pwd.uid, (unsigned)-1); + ASSERT_NE(pwd.gid, (unsigned)-1); + ASSERT_EQ(pwd.uid, geteuid()); + if (pwd.uid != 0 && pwd.gid != getgid()) + /* This will be likely true, as only root could have changed it. */ + ASSERT_EQ(pwd.gid, getegid()); #endif /* Test uv_os_free_passwd() */ From 7ae0c9543d0080968766288c73874aee3798ae30 Mon Sep 17 00:00:00 2001 From: "Vittore F. Scolari" Date: Wed, 23 Feb 2022 18:04:18 +0100 Subject: [PATCH 137/713] hurd: unbreak build on GNU/Hurd (#3450) The GNU/Hurd platform does not define IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP, MCAST_JOIN_SOURCE_GROUP and MCAST_LEAVE_SOURCE_GROUP. Implement a few functions for the GNU/Hurd. Specifically: * uv_resident_set_memory (from Linux) * uv_get_free_memory (from Linux) * uv_get_total_memory (from Linux) * uv_cpu_info (from cygwin) * uv__process_title_cleanup (void) * uv_get_constrained_memory (stub) * Leave proctitle unimplemented on Hurd for now * Implement hurdish uv_exepath * Enable ifaddrs api * Unbreak udp basics * Unbreak futime and lutime on Hurd --- CMakeLists.txt | 11 +++ Makefile.am | 7 +- src/strscpy.h | 2 +- src/unix/bsd-ifaddrs.c | 8 +- src/unix/core.c | 26 +++++++ src/unix/fs.c | 6 +- src/unix/hurd.c | 167 +++++++++++++++++++++++++++++++++++++++++ src/unix/internal.h | 1 + src/unix/linux-core.c | 27 +------ src/unix/udp.c | 8 +- 10 files changed, 225 insertions(+), 38 deletions(-) create mode 100644 src/unix/hurd.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 881df67ce97..ac524127375 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -258,6 +258,17 @@ if(APPLE) src/unix/fsevents.c) endif() +if(CMAKE_SYSTEM_NAME STREQUAL "GNU") + list(APPEND uv_libraries dl) + list(APPEND uv_sources + src/unix/bsd-ifaddrs.c + src/unix/no-fsevents.c + src/unix/no-proctitle.c + src/unix/posix-hrtime.c + src/unix/posix-poll.c + src/unix/hurd.c) +endif() + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") list(APPEND uv_defines _GNU_SOURCE _POSIX_C_SOURCE=200112) list(APPEND uv_libraries dl rt) diff --git a/Makefile.am b/Makefile.am index 49faf82fb0c..d1ec1a5e2ab 100644 --- a/Makefile.am +++ b/Makefile.am @@ -455,9 +455,12 @@ endif if HURD uvinclude_HEADERS += include/uv/posix.h -libuv_la_SOURCES += src/unix/no-fsevents.c \ +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/no-fsevents.c \ + src/unix/no-proctitle.c \ src/unix/posix-hrtime.c \ - src/unix/posix-poll.c + src/unix/posix-poll.c \ + src/unix/hurd.c endif if LINUX diff --git a/src/strscpy.h b/src/strscpy.h index cc78149db5f..e8d47247f0d 100644 --- a/src/strscpy.h +++ b/src/strscpy.h @@ -28,7 +28,7 @@ */ #include "uv.h" -/* Copies up to |n-1| bytes from |d| to |s| and always zero-terminates +/* Copies up to |n-1| bytes from |s| to |d| and always zero-terminates * the result, except when |n==0|. Returns the number of bytes copied * or UV_E2BIG if |d| is too small. * diff --git a/src/unix/bsd-ifaddrs.c b/src/unix/bsd-ifaddrs.c index e48934bce2b..11ca95591fc 100644 --- a/src/unix/bsd-ifaddrs.c +++ b/src/unix/bsd-ifaddrs.c @@ -27,7 +27,7 @@ #include #include -#if !defined(__CYGWIN__) && !defined(__MSYS__) +#if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__GNU__) #include #endif @@ -40,7 +40,7 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return 1; if (ent->ifa_addr == NULL) return 1; -#if !defined(__CYGWIN__) && !defined(__MSYS__) +#if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__GNU__) /* * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, return whether `sa_family` * equals `AF_LINK`. Otherwise, the result depends on the operating @@ -69,7 +69,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifaddrs* addrs; struct ifaddrs* ent; uv_interface_address_t* address; -#if !(defined(__CYGWIN__) || defined(__MSYS__)) +#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__) int i; #endif @@ -126,7 +126,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address++; } -#if !(defined(__CYGWIN__) || defined(__MSYS__)) +#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__) /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) diff --git a/src/unix/core.c b/src/unix/core.c index 9a289edfa34..0bb334bd952 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1037,6 +1037,32 @@ int uv__open_cloexec(const char* path, int flags) { } +int uv__slurp(const char* filename, char* buf, size_t len) { + ssize_t n; + int fd; + + assert(len > 0); + + fd = uv__open_cloexec(filename, O_RDONLY); + if (fd < 0) + return fd; + + do + n = read(fd, buf, len - 1); + while (n == -1 && errno == EINTR); + + if (uv__close_nocheckstdio(fd)) + abort(); + + if (n < 0) + return UV__ERR(errno); + + buf[n] = '\0'; + + return 0; +} + + int uv__dup2_cloexec(int oldfd, int newfd) { #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__) int r; diff --git a/src/unix/fs.c b/src/unix/fs.c index 362c36c6a0c..99ea74650ca 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -247,7 +247,8 @@ UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) { static ssize_t uv__fs_futime(uv_fs_t* req) { #if defined(__linux__) \ || defined(_AIX71) \ - || defined(__HAIKU__) + || defined(__HAIKU__) \ + || defined(__GNU__) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); @@ -1168,7 +1169,8 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) { #if defined(__linux__) || \ defined(_AIX71) || \ defined(__sun) || \ - defined(__HAIKU__) + defined(__HAIKU__) || \ + defined(__GNU__) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); diff --git a/src/unix/hurd.c b/src/unix/hurd.c new file mode 100644 index 00000000000..d19ea634790 --- /dev/null +++ b/src/unix/hurd.c @@ -0,0 +1,167 @@ +/* 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. + */ + +#define _GNU_SOURCE 1 + +#include "uv.h" +#include "internal.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +int uv_exepath(char* buffer, size_t* size) { + kern_return_t err; + /* XXX in current Hurd, strings are char arrays of 1024 elements */ + string_t exepath; + ssize_t copied; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + if (*size - 1 > 0) { + /* XXX limited length of buffer in current Hurd, this API will probably + * evolve in the future */ + err = proc_get_exe(getproc(), getpid(), exepath); + + if (err) + return UV__ERR(err); + } + + copied = uv__strscpy(buffer, exepath, *size); + + /* do not return error on UV_E2BIG failure */ + *size = copied < 0 ? strlen(buffer) : (size_t) copied; + + return 0; +} + +int uv_resident_set_memory(size_t* rss) { + kern_return_t err; + struct task_basic_info bi; + mach_msg_type_number_t count; + + count = TASK_BASIC_INFO_COUNT; + err = task_info(mach_task_self(), TASK_BASIC_INFO, + (task_info_t) &bi, &count); + + if (err) + return UV__ERR(err); + + *rss = bi.resident_size; + + return 0; +} + +uint64_t uv_get_free_memory(void) { + kern_return_t err; + struct vm_statistics vmstats; + + err = vm_statistics(mach_task_self(), &vmstats); + + if (err) + return 0; + + return vmstats.free_count * vm_page_size; +} + + +uint64_t uv_get_total_memory(void) { + kern_return_t err; + host_basic_info_data_t hbi; + mach_msg_type_number_t cnt; + + cnt = HOST_BASIC_INFO_COUNT; + err = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t) &hbi, &cnt); + + if (err) + return 0; + + return hbi.memory_size; +} + + +int uv_uptime(double* uptime) { + char buf[128]; + + /* Try /proc/uptime first */ + if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf))) + if (1 == sscanf(buf, "%lf", uptime)) + return 0; + + /* Reimplement here code from procfs to calculate uptime if not mounted? */ + + return UV__ERR(EIO); +} + +void uv_loadavg(double avg[3]) { + char buf[128]; /* Large enough to hold all of /proc/loadavg. */ + + if (0 == uv__slurp("/proc/loadavg", buf, sizeof(buf))) + if (3 == sscanf(buf, "%lf %lf %lf", &avg[0], &avg[1], &avg[2])) + return; + + /* Reimplement here code from procfs to calculate loadavg if not mounted? */ +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + kern_return_t err; + host_basic_info_data_t hbi; + mach_msg_type_number_t cnt; + + /* Get count of cpus */ + cnt = HOST_BASIC_INFO_COUNT; + err = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t) &hbi, &cnt); + + if (err) { + err = UV__ERR(err); + goto abort; + } + + /* XXX not implemented on the Hurd */ + *cpu_infos = uv__calloc(hbi.avail_cpus, sizeof(**cpu_infos)); + if (*cpu_infos == NULL) { + err = UV_ENOMEM; + goto abort; + } + + *count = hbi.avail_cpus; + + return 0; + + abort: + *cpu_infos = NULL; + *count = 0; + return err; +} + +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} diff --git a/src/unix/internal.h b/src/unix/internal.h index b0913d31cbe..ec46f3855e5 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -242,6 +242,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); int uv__accept(int sockfd); int uv__dup2_cloexec(int oldfd, int newfd); int uv__open_cloexec(const char* path, int flags); +int uv__slurp(const char* filename, char* buf, size_t len); /* tcp */ int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb); diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 7b041e68567..425973789a8 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -211,31 +211,6 @@ int uv_resident_set_memory(size_t* rss) { return UV_EINVAL; } -static int uv__slurp(const char* filename, char* buf, size_t len) { - ssize_t n; - int fd; - - assert(len > 0); - - fd = uv__open_cloexec(filename, O_RDONLY); - if (fd < 0) - return fd; - - do - n = read(fd, buf, len - 1); - while (n == -1 && errno == EINTR); - - if (uv__close_nocheckstdio(fd)) - abort(); - - if (n < 0) - return UV__ERR(errno); - - buf[n] = '\0'; - - return 0; -} - int uv_uptime(double* uptime) { static volatile int no_clock_boottime; char buf[128]; @@ -243,7 +218,7 @@ int uv_uptime(double* uptime) { int r; /* Try /proc/uptime first, then fallback to clock_gettime(). */ - + if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf))) if (1 == sscanf(buf, "%lf", uptime)) return 0; diff --git a/src/unix/udp.c b/src/unix/udp.c index 74ef398a065..aad7a6dcf61 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -495,7 +495,7 @@ static int uv__set_reuse(int fd) { if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); } -#elif defined(SO_REUSEPORT) && !defined(__linux__) +#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); #else @@ -928,7 +928,8 @@ static int uv__udp_set_membership6(uv_udp_t* handle, !defined(__NetBSD__) && \ !defined(__ANDROID__) && \ !defined(__DragonFly__) && \ - !defined(__QNX__) + !defined(__QNX__) && \ + !defined(__GNU__) static int uv__udp_set_source_membership4(uv_udp_t* handle, const struct sockaddr_in* multicast_addr, const char* interface_addr, @@ -1120,7 +1121,8 @@ int uv_udp_set_source_membership(uv_udp_t* handle, !defined(__NetBSD__) && \ !defined(__ANDROID__) && \ !defined(__DragonFly__) && \ - !defined(__QNX__) + !defined(__QNX__) && \ + !defined(__GNU__) int err; union uv__sockaddr mcast_addr; union uv__sockaddr src_addr; From 993e9ebd07246b0f1a4201eed180c6f74c4d2f13 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 27 Feb 2022 10:49:29 +0000 Subject: [PATCH 138/713] freebsd: use copy_file_range() in uv_fs_sendfile() (#3496) Use copy_file_range() on FreeBSD 13 and above. --- src/unix/freebsd.c | 15 +++++++++++++++ src/unix/fs.c | 11 +++++++++++ src/unix/internal.h | 10 ++++++++++ 3 files changed, 36 insertions(+) diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index 170b897e202..658ff262d37 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -287,3 +287,18 @@ int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { return errno = ENOSYS, -1; #endif } + +ssize_t +uv__fs_copy_file_range(int fd_in, + off_t* off_in, + int fd_out, + off_t* off_out, + size_t len, + unsigned int flags) +{ +#if __FreeBSD__ >= 13 && !defined(__DragonFly__) + return copy_file_range(fd_in, off_in, fd_out, off_out, len, flags); +#else + return errno = ENOSYS, -1; +#endif +} diff --git a/src/unix/fs.c b/src/unix/fs.c index 99ea74650ca..b3211ec1066 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1075,6 +1075,17 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { */ #if defined(__FreeBSD__) || defined(__DragonFly__) +#if defined(__FreeBSD__) + off_t off; + + off = req->off; + r = uv__fs_copy_file_range(in_fd, &off, out_fd, NULL, req->bufsml[0].len, 0); + if (r >= 0) { + r = off - req->off; + req->off = off; + return r; + } +#endif len = 0; r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0); #elif defined(__FreeBSD_kernel__) diff --git a/src/unix/internal.h b/src/unix/internal.h index ec46f3855e5..2fa903e910e 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -359,5 +359,15 @@ size_t strnlen(const char* s, size_t maxlen); #endif #endif +#if defined(__FreeBSD__) +ssize_t +uv__fs_copy_file_range(int fd_in, + off_t* off_in, + int fd_out, + off_t* off_out, + size_t len, + unsigned int flags); +#endif + #endif /* UV_UNIX_INTERNAL_H_ */ From 56e279021f751699500e5f3c958e3fcdff3ec7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20=C3=8Dscaro?= Date: Sun, 27 Feb 2022 10:49:58 +0000 Subject: [PATCH 139/713] test: use closefd in runner-unix.c (#3497) This commit changes the plain close calls to the closefd function, which will properly check if close() returns an error. --- test/runner-unix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runner-unix.c b/test/runner-unix.c index a13648bc883..c165aab9305 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -333,8 +333,8 @@ int process_wait(process_info_t* vec, int n, int timeout) { abort(); terminate: - close(args.pipe[0]); - close(args.pipe[1]); + closefd(args.pipe[0]); + closefd(args.pipe[1]); return retval; } From 83efa3dd7140ef16e9d8fcde42011450f0c229e6 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 2 Mar 2022 15:15:39 -0500 Subject: [PATCH 140/713] Reland "macos: use posix_spawn instead of fork" (#3257) Fixes: https://github.com/libuv/libuv/issues/3050 Refs: https://github.com/libuv/libuv/issues/3086 Refs: https://github.com/libuv/libuv/pull/3064 Refs: https://github.com/libuv/libuv/pull/3107 Refs: https://github.com/libuv/libuv/pull/3064 This reverts commit 217fdf4265589889d00c7c0622fde2710971a020, then fixes several issues with it: * remove error fast-cleanup code that triggers a nodejs bug Refs: https://github.com/libuv/libuv/pull/3107#issuecomment-782482608 * protect posix_spawn from EINTR This is not a documented valid error, but seems to have been observed. * ignore setuid/setgid syscall This kernel function is not permitted unless the process is setuid root, so disable this syscall. Falling back to fork/exec should be okay for the rare cases that the user decides they need to do setuid(getuid()) or setuid(geteuid()) for the child. Refs: https://github.com/libuv/libuv/pull/3107#issuecomment-782482608 * improve posix_spawn path search Ports the improvements in musl back to this function * fix some additional problems and formatting issues We previously might fail to start a watcher, in rare failure cases, resulting in a zombie that we would fail to kill. Also avoid creating the signal-pipe unless required (addresses a review comment from Apple) * fix fd->fd mapping reuse There was a chance that when duplicating the fd's into stdio_count+fd we might be closing a currently opened fd with that value. --- src/unix/process.c | 727 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 608 insertions(+), 119 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index 2920b942962..b85aa3b94ed 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -35,8 +36,21 @@ #include #if defined(__APPLE__) && !TARGET_OS_IPHONE +# include +# include +# include +# include +# include +# include # include +# include # define environ (*_NSGetEnviron()) + +/* macOS 10.14 back does not define this constant */ +# ifndef POSIX_SPAWN_SETSID +# define POSIX_SPAWN_SETSID 1024 +# endif + #else extern char **environ; #endif @@ -261,22 +275,22 @@ static void uv__process_child_init(const uv_process_options_t* options, use_fd = pipes[fd][1]; if (use_fd < 0 || use_fd >= fd) continue; - pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); + pipes[fd][1] = fcntl(use_fd, F_DUPFD_CLOEXEC, stdio_count); if (pipes[fd][1] == -1) uv__write_errno(error_fd); } for (fd = 0; fd < stdio_count; fd++) { - close_fd = pipes[fd][0]; + close_fd = -1; use_fd = pipes[fd][1]; if (use_fd < 0) { if (fd >= 3) continue; else { - /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is - * set - */ + /* Redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is + * set. */ + uv__close_nocheckstdio(fd); /* Free up fd, if it happens to be open. */ use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); close_fd = use_fd; @@ -285,28 +299,24 @@ static void uv__process_child_init(const uv_process_options_t* options, } } - if (fd == use_fd) - uv__cloexec_fcntl(use_fd, 0); - else + if (fd == use_fd) { + if (close_fd == -1) + uv__cloexec_fcntl(use_fd, 0); + } + else { fd = dup2(use_fd, fd); + } if (fd == -1) uv__write_errno(error_fd); - if (fd <= 2) + if (fd <= 2 && close_fd == -1) uv__nonblock_fcntl(fd, 0); if (close_fd >= stdio_count) uv__close(close_fd); } - for (fd = 0; fd < stdio_count; fd++) { - use_fd = pipes[fd][1]; - - if (use_fd >= stdio_count) - uv__close(use_fd); - } - if (options->cwd != NULL && chdir(options->cwd)) uv__write_errno(error_fd); @@ -327,9 +337,8 @@ static void uv__process_child_init(const uv_process_options_t* options, if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) uv__write_errno(error_fd); - if (options->env != NULL) { + if (options->env != NULL) environ = options->env; - } /* Reset signal mask just before exec. */ sigemptyset(&signewset); @@ -348,6 +357,562 @@ static void uv__process_child_init(const uv_process_options_t* options, #endif +#if defined(__APPLE__) +typedef struct uv__posix_spawn_fncs_tag { + struct { + int (*addchdir_np)(const posix_spawn_file_actions_t *, const char *); + } file_actions; +} uv__posix_spawn_fncs_t; + + +static uv_once_t posix_spawn_init_once = UV_ONCE_INIT; +static uv__posix_spawn_fncs_t posix_spawn_fncs; +static int posix_spawn_can_use_setsid; + + +static void uv__spawn_init_posix_spawn_fncs(void) { + /* Try to locate all non-portable functions at runtime */ + posix_spawn_fncs.file_actions.addchdir_np = + dlsym(RTLD_DEFAULT, "posix_spawn_file_actions_addchdir_np"); +} + + +static void uv__spawn_init_can_use_setsid(void) { + static const int MACOS_CATALINA_VERSION_MAJOR = 19; + char version_str[256]; + char* version_major_str; + size_t version_str_size = 256; + int r; + int version_major; + + /* Get a version string */ + r = sysctlbyname("kern.osrelease", version_str, &version_str_size, NULL, 0); + if (r != 0) + return; + + /* Try to get the major version number. If not found + * fall back to the fork/exec flow */ + version_major_str = strtok(version_str, "."); + if (version_major_str == NULL) + return; + + /* Parse the version major as a number. If it is greater than + * the major version for macOS Catalina (aka macOS 10.15), then + * the POSIX_SPAWN_SETSID flag is available */ + version_major = atoi_l(version_major_str, NULL); /* Use LC_C_LOCALE */ + if (version_major >= MACOS_CATALINA_VERSION_MAJOR) + posix_spawn_can_use_setsid = 1; +} + + +static void uv__spawn_init_posix_spawn(void) { + /* Init handles to all potentially non-defined functions */ + uv__spawn_init_posix_spawn_fncs(); + + /* Init feature detection for POSIX_SPAWN_SETSID flag */ + uv__spawn_init_can_use_setsid(); +} + + +static int uv__spawn_set_posix_spawn_attrs( + posix_spawnattr_t* attrs, + const uv__posix_spawn_fncs_t* posix_spawn_fncs, + const uv_process_options_t* options) { + int err; + unsigned int flags; + sigset_t signal_set; + + err = posix_spawnattr_init(attrs); + if (err != 0) { + /* If initialization fails, no need to de-init, just return */ + return err; + } + + if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { + /* kauth_cred_issuser currently requires exactly uid == 0 for these + * posixspawn_attrs (set_groups_np, setuid_np, setgid_np), which deviates + * from the normal specification of setuid (which also uses euid), and they + * are also undocumented syscalls, so we do not use them. */ + err = ENOSYS; + goto error; + } + + /* Set flags for spawn behavior + * 1) POSIX_SPAWN_CLOEXEC_DEFAULT: (Apple Extension) All descriptors in the + * parent will be treated as if they had been created with O_CLOEXEC. The + * only fds that will be passed on to the child are those manipulated by + * the file actions + * 2) POSIX_SPAWN_SETSIGDEF: Signals mentioned in spawn-sigdefault in the + * spawn attributes will be reset to behave as their default + * 3) POSIX_SPAWN_SETSIGMASK: Signal mask will be set to the value of + * spawn-sigmask in attributes + * 4) POSIX_SPAWN_SETSID: Make the process a new session leader if a detached + * session was requested. */ + flags = POSIX_SPAWN_CLOEXEC_DEFAULT | + POSIX_SPAWN_SETSIGDEF | + POSIX_SPAWN_SETSIGMASK; + if (options->flags & UV_PROCESS_DETACHED) { + /* If running on a version of macOS where this flag is not supported, + * revert back to the fork/exec flow. Otherwise posix_spawn will + * silently ignore the flag. */ + if (!posix_spawn_can_use_setsid) { + err = ENOSYS; + goto error; + } + + flags |= POSIX_SPAWN_SETSID; + } + err = posix_spawnattr_setflags(attrs, flags); + if (err != 0) + goto error; + + /* Reset all signal the child to their default behavior */ + sigfillset(&signal_set); + err = posix_spawnattr_setsigdefault(attrs, &signal_set); + if (err != 0) + goto error; + + /* Reset the signal mask for all signals */ + sigemptyset(&signal_set); + err = posix_spawnattr_setsigmask(attrs, &signal_set); + if (err != 0) + goto error; + + return err; + +error: + (void) posix_spawnattr_destroy(attrs); + return err; +} + + +static int uv__spawn_set_posix_spawn_file_actions( + posix_spawn_file_actions_t* actions, + const uv__posix_spawn_fncs_t* posix_spawn_fncs, + const uv_process_options_t* options, + int stdio_count, + int (*pipes)[2]) { + int fd; + int fd2; + int use_fd; + int err; + + err = posix_spawn_file_actions_init(actions); + if (err != 0) { + /* If initialization fails, no need to de-init, just return */ + return err; + } + + /* Set the current working directory if requested */ + if (options->cwd != NULL) { + if (posix_spawn_fncs->file_actions.addchdir_np == NULL) { + err = ENOSYS; + goto error; + } + + err = posix_spawn_fncs->file_actions.addchdir_np(actions, options->cwd); + if (err != 0) + goto error; + } + + /* Do not return ENOSYS after this point, as we may mutate pipes. */ + + /* First duplicate low numbered fds, since it's not safe to duplicate them, + * they could get replaced. Example: swapping stdout and stderr; without + * this fd 2 (stderr) would be duplicated into fd 1, thus making both + * stdout and stderr go to the same fd, which was not the intention. */ + for (fd = 0; fd < stdio_count; fd++) { + use_fd = pipes[fd][1]; + if (use_fd < 0 || use_fd >= fd) + continue; + use_fd = stdio_count; + for (fd2 = 0; fd2 < stdio_count; fd2++) { + /* If we were not setting POSIX_SPAWN_CLOEXEC_DEFAULT, we would need to + * also consider whether fcntl(fd, F_GETFD) returned without the + * FD_CLOEXEC flag set. */ + if (pipes[fd2][1] == use_fd) { + use_fd++; + fd2 = 0; + } + } + err = posix_spawn_file_actions_adddup2( + actions, + pipes[fd][1], + use_fd); + assert(err != ENOSYS); + if (err != 0) + goto error; + pipes[fd][1] = use_fd; + } + + /* Second, move the descriptors into their respective places */ + for (fd = 0; fd < stdio_count; fd++) { + use_fd = pipes[fd][1]; + if (use_fd < 0) { + if (fd >= 3) + continue; + else { + /* If ignored, redirect to (or from) /dev/null, */ + err = posix_spawn_file_actions_addopen( + actions, + fd, + "/dev/null", + fd == 0 ? O_RDONLY : O_RDWR, + 0); + assert(err != ENOSYS); + if (err != 0) + goto error; + continue; + } + } + + if (fd == use_fd) + err = posix_spawn_file_actions_addinherit_np(actions, fd); + else + err = posix_spawn_file_actions_adddup2(actions, use_fd, fd); + assert(err != ENOSYS); + if (err != 0) + goto error; + + /* Make sure the fd is marked as non-blocking (state shared between child + * and parent). */ + uv__nonblock_fcntl(use_fd, 0); + } + + /* Finally, close all the superfluous descriptors */ + for (fd = 0; fd < stdio_count; fd++) { + use_fd = pipes[fd][1]; + if (use_fd < stdio_count) + continue; + + /* Check if we already closed this. */ + for (fd2 = 0; fd2 < fd; fd2++) { + if (pipes[fd2][1] == use_fd) + break; + } + if (fd2 < fd) + continue; + + err = posix_spawn_file_actions_addclose(actions, use_fd); + assert(err != ENOSYS); + if (err != 0) + goto error; + } + + return 0; + +error: + (void) posix_spawn_file_actions_destroy(actions); + return err; +} + +char* uv__spawn_find_path_in_env(char** env) { + char** env_iterator; + const char path_var[] = "PATH="; + + /* Look for an environment variable called PATH in the + * provided env array, and return its value if found */ + for (env_iterator = env; *env_iterator != NULL; env_iterator++) { + if (strncmp(*env_iterator, path_var, sizeof(path_var) - 1) == 0) { + /* Found "PATH=" at the beginning of the string */ + return *env_iterator + sizeof(path_var) - 1; + } + } + + return NULL; +} + + +static int uv__spawn_resolve_and_spawn(const uv_process_options_t* options, + posix_spawnattr_t* attrs, + posix_spawn_file_actions_t* actions, + pid_t* pid) { + const char *p; + const char *z; + const char *path; + size_t l; + size_t k; + int err; + int seen_eacces; + + path = NULL; + err = -1; + seen_eacces = 0; + + /* Short circuit for erroneous case */ + if (options->file == NULL) + return ENOENT; + + /* The environment for the child process is that of the parent unless overriden + * by options->env */ + char** env = environ; + if (options->env != NULL) + env = options->env; + + /* If options->file contains a slash, posix_spawn/posix_spawnp behave + * the same, and don't involve PATH resolution at all. Otherwise, if + * options->file does not include a slash, but no custom environment is + * to be used, the environment used for path resolution as well for the + * child process is that of the parent process, so posix_spawnp is the + * way to go. */ + if (strchr(options->file, '/') != NULL || options->env == NULL) { + do + err = posix_spawnp(pid, options->file, actions, attrs, options->args, env); + while (err == EINTR); + return err; + } + + /* Look for the definition of PATH in the provided env */ + path = uv__spawn_find_path_in_env(options->env); + + /* The following resolution logic (execvpe emulation) is copied from + * https://git.musl-libc.org/cgit/musl/tree/src/process/execvp.c + * and adapted to work for our specific usage */ + + /* If no path was provided in options->env, use the default value + * to look for the executable */ + if (path == NULL) + path = _PATH_DEFPATH; + + k = strnlen(options->file, NAME_MAX + 1); + if (k > NAME_MAX) + return ENAMETOOLONG; + + l = strnlen(path, PATH_MAX - 1) + 1; + + for (p = path;; p = z) { + /* Compose the new process file from the entry in the PATH + * environment variable and the actual file name */ + char b[PATH_MAX + NAME_MAX]; + z = strchr(p, ':'); + if (!z) + z = p + strlen(p); + if ((size_t)(z - p) >= l) { + if (!*z++) + break; + + continue; + } + memcpy(b, p, z - p); + b[z - p] = '/'; + memcpy(b + (z - p) + (z > p), options->file, k + 1); + + /* Try to spawn the new process file. If it fails with ENOENT, the + * new process file is not in this PATH entry, continue with the next + * PATH entry. */ + do + err = posix_spawn(pid, b, actions, attrs, options->args, env); + while (err == EINTR); + + switch (err) { + case EACCES: + seen_eacces = 1; + break; /* continue search */ + case ENOENT: + case ENOTDIR: + break; /* continue search */ + default: + return err; + } + + if (!*z++) + break; + } + + if (seen_eacces) + return EACCES; + return err; +} + + +static int uv__spawn_and_init_child_posix_spawn( + const uv_process_options_t* options, + int stdio_count, + int (*pipes)[2], + pid_t* pid, + const uv__posix_spawn_fncs_t* posix_spawn_fncs) { + int err; + posix_spawnattr_t attrs; + posix_spawn_file_actions_t actions; + + err = uv__spawn_set_posix_spawn_attrs(&attrs, posix_spawn_fncs, options); + if (err != 0) + goto error; + + /* This may mutate pipes. */ + err = uv__spawn_set_posix_spawn_file_actions(&actions, + posix_spawn_fncs, + options, + stdio_count, + pipes); + if (err != 0) { + (void) posix_spawnattr_destroy(&attrs); + goto error; + } + + /* Try to spawn options->file resolving in the provided environment + * if any */ + err = uv__spawn_resolve_and_spawn(options, &attrs, &actions, pid); + assert(err != ENOSYS); + + /* Destroy the actions/attributes */ + (void) posix_spawn_file_actions_destroy(&actions); + (void) posix_spawnattr_destroy(&attrs); + +error: + /* In an error situation, the attributes and file actions are + * already destroyed, only the happy path requires cleanup */ + return UV__ERR(err); +} +#endif + +static int uv__spawn_and_init_child_fork(const uv_process_options_t* options, + int stdio_count, + int (*pipes)[2], + int error_fd, + pid_t* pid) { + sigset_t signewset; + sigset_t sigoldset; + + /* Start the child with most signals blocked, to avoid any issues before we + * can reset them, but allow program failures to exit (and not hang). */ + sigfillset(&signewset); + sigdelset(&signewset, SIGKILL); + sigdelset(&signewset, SIGSTOP); + sigdelset(&signewset, SIGTRAP); + sigdelset(&signewset, SIGSEGV); + sigdelset(&signewset, SIGBUS); + sigdelset(&signewset, SIGILL); + sigdelset(&signewset, SIGSYS); + sigdelset(&signewset, SIGABRT); + if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0) + abort(); + + *pid = fork(); + + if (*pid == -1) { + /* Failed to fork */ + return UV__ERR(errno); + } + + if (*pid == 0) { + /* Fork succeeded, in the child process */ + uv__process_child_init(options, stdio_count, pipes, error_fd); + abort(); + } + + if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0) + abort(); + + /* Fork succeeded, in the parent process */ + return 0; +} + +static int uv__spawn_and_init_child( + uv_loop_t* loop, + const uv_process_options_t* options, + int stdio_count, + int (*pipes)[2], + pid_t* pid) { + int signal_pipe[2] = { -1, -1 }; + int status; + int err; + int exec_errorno; + ssize_t r; + +#if defined(__APPLE__) + uv_once(&posix_spawn_init_once, uv__spawn_init_posix_spawn); + + /* Special child process spawn case for macOS Big Sur (11.0) onwards + * + * Big Sur introduced a significant performance degradation on a call to + * fork/exec when the process has many pages mmaped in with MAP_JIT, like, say + * a javascript interpreter. Electron-based applications, for example, + * are impacted; though the magnitude of the impact depends on how much the + * app relies on subprocesses. + * + * On macOS, though, posix_spawn is implemented in a way that does not + * exhibit the problem. This block implements the forking and preparation + * logic with posix_spawn and its related primitives. It also takes advantage of + * the macOS extension POSIX_SPAWN_CLOEXEC_DEFAULT that makes impossible to + * leak descriptors to the child process. */ + err = uv__spawn_and_init_child_posix_spawn(options, + stdio_count, + pipes, + pid, + &posix_spawn_fncs); + + /* The posix_spawn flow will return UV_ENOSYS if any of the posix_spawn_x_np + * non-standard functions is both _needed_ and _undefined_. In those cases, + * default back to the fork/execve strategy. For all other errors, just fail. */ + if (err != UV_ENOSYS) + return err; + +#endif + + /* This pipe is used by the parent to wait until + * the child has called `execve()`. We need this + * to avoid the following race condition: + * + * if ((pid = fork()) > 0) { + * kill(pid, SIGTERM); + * } + * else if (pid == 0) { + * execve("/bin/cat", argp, envp); + * } + * + * The parent sends a signal immediately after forking. + * Since the child may not have called `execve()` yet, + * there is no telling what process receives the signal, + * our fork or /bin/cat. + * + * To avoid ambiguity, we create a pipe with both ends + * marked close-on-exec. Then, after the call to `fork()`, + * the parent polls the read end until it EOFs or errors with EPIPE. + */ + err = uv__make_pipe(signal_pipe, 0); + if (err) + return err; + + /* Acquire write lock to prevent opening new fds in worker threads */ + uv_rwlock_wrlock(&loop->cloexec_lock); + + err = uv__spawn_and_init_child_fork(options, stdio_count, pipes, signal_pipe[1], pid); + + /* Release lock in parent process */ + uv_rwlock_wrunlock(&loop->cloexec_lock); + + uv__close(signal_pipe[1]); + + if (err == 0) { + do + r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno)); + while (r == -1 && errno == EINTR); + + if (r == 0) + ; /* okay, EOF */ + else if (r == sizeof(exec_errorno)) { + do + err = waitpid(*pid, &status, 0); /* okay, read errorno */ + while (err == -1 && errno == EINTR); + assert(err == *pid); + err = exec_errorno; + } else if (r == -1 && errno == EPIPE) { + /* Something unknown happened to our child before spawn */ + do + err = waitpid(*pid, &status, 0); /* okay, got EPIPE */ + while (err == -1 && errno == EINTR); + assert(err == *pid); + err = UV_EPIPE; + } else + abort(); + } + + uv__close_nocheckstdio(signal_pipe[0]); + + return err; +} + int uv_spawn(uv_loop_t* loop, uv_process_t* process, const uv_process_options_t* options) { @@ -355,18 +920,13 @@ int uv_spawn(uv_loop_t* loop, /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ return UV_ENOSYS; #else - sigset_t signewset; - sigset_t sigoldset; - int signal_pipe[2] = { -1, -1 }; int pipes_storage[8][2]; int (*pipes)[2]; int stdio_count; - ssize_t r; pid_t pid; int err; int exec_errorno; int i; - int status; assert(options->file != NULL); assert(!(options->flags & ~(UV_PROCESS_DETACHED | @@ -379,6 +939,7 @@ int uv_spawn(uv_loop_t* loop, uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); QUEUE_INIT(&process->queue); + process->status = 0; stdio_count = options->stdio_count; if (stdio_count < 3) @@ -403,106 +964,24 @@ int uv_spawn(uv_loop_t* loop, goto error; } - /* This pipe is used by the parent to wait until - * the child has called `execve()`. We need this - * to avoid the following race condition: - * - * if ((pid = fork()) > 0) { - * kill(pid, SIGTERM); - * } - * else if (pid == 0) { - * execve("/bin/cat", argp, envp); - * } - * - * The parent sends a signal immediately after forking. - * Since the child may not have called `execve()` yet, - * there is no telling what process receives the signal, - * our fork or /bin/cat. - * - * To avoid ambiguity, we create a pipe with both ends - * marked close-on-exec. Then, after the call to `fork()`, - * the parent polls the read end until it EOFs or errors with EPIPE. - */ - err = uv__make_pipe(signal_pipe, 0); - if (err) - goto error; - #if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); #endif - /* Acquire write lock to prevent opening new fds in worker threads */ - uv_rwlock_wrlock(&loop->cloexec_lock); - - /* Start the child with most signals blocked, to avoid any issues before we - * can reset them, but allow program failures to exit (and not hang). */ - sigfillset(&signewset); - sigdelset(&signewset, SIGKILL); - sigdelset(&signewset, SIGSTOP); - sigdelset(&signewset, SIGTRAP); - sigdelset(&signewset, SIGSEGV); - sigdelset(&signewset, SIGBUS); - sigdelset(&signewset, SIGILL); - sigdelset(&signewset, SIGSYS); - sigdelset(&signewset, SIGABRT); - if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0) - abort(); - - pid = fork(); - if (pid == -1) - err = UV__ERR(errno); - - if (pid == 0) - uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]); + /* Spawn the child */ + exec_errorno = uv__spawn_and_init_child(loop, options, stdio_count, pipes, &pid); - if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0) - abort(); - - /* Release lock in parent process */ - uv_rwlock_wrunlock(&loop->cloexec_lock); - - uv__close(signal_pipe[1]); - - if (pid == -1) { - uv__close(signal_pipe[0]); - goto error; - } - - process->status = 0; - exec_errorno = 0; - do - r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno)); - while (r == -1 && errno == EINTR); - - if (r == 0) - ; /* okay, EOF */ - else if (r == sizeof(exec_errorno)) { - do - err = waitpid(pid, &status, 0); /* okay, read errorno */ - while (err == -1 && errno == EINTR); - assert(err == pid); - } else if (r == -1 && errno == EPIPE) { - do - err = waitpid(pid, &status, 0); /* okay, got EPIPE */ - while (err == -1 && errno == EINTR); - assert(err == pid); - } else - abort(); - - uv__close_nocheckstdio(signal_pipe[0]); - - for (i = 0; i < options->stdio_count; i++) { - err = uv__process_open_stream(options->stdio + i, pipes[i]); - if (err == 0) - continue; - - while (i--) - uv__process_close_stream(options->stdio + i); - - goto error; - } +#if 0 + /* This runs into a nodejs issue (it expects initialized streams, even if the + * exec failed). + * See https://github.com/libuv/libuv/pull/3107#issuecomment-782482608 */ + if (exec_errorno != 0) + goto error; +#endif - /* Only activate this handle if exec() happened successfully */ + /* Activate this handle if exec() happened successfully, even if we later + * fail to open a stdio handle. This ensures we can eventually reap the child + * with waitpid. */ if (exec_errorno == 0) { #if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) struct kevent event; @@ -515,12 +994,22 @@ int uv_spawn(uv_loop_t* loop, } #endif + process->pid = pid; + process->exit_cb = options->exit_cb; QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); uv__handle_start(process); } - process->pid = pid; - process->exit_cb = options->exit_cb; + for (i = 0; i < options->stdio_count; i++) { + err = uv__process_open_stream(options->stdio + i, pipes[i]); + if (err == 0) + continue; + + while (i--) + uv__process_close_stream(options->stdio + i); + + goto error; + } if (pipes != pipes_storage) uv__free(pipes); From c40f8cb9f8ddf69d116952f8924a11ec0623b445 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 3 Mar 2022 20:18:28 +0800 Subject: [PATCH 141/713] android: fix build error when no ifaddrs.h (#3505) --- src/unix/linux-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 425973789a8..23a7dafec81 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -616,6 +616,7 @@ static uint64_t read_cpufreq(unsigned int cpunum) { } +#ifdef HAVE_IFADDRS_H static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) return 1; @@ -629,6 +630,7 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return exclude_type; return !exclude_type; } +#endif int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #ifndef HAVE_IFADDRS_H From f250c6c73ee45aa93ec44133c9e0c635780ea741 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 4 Mar 2022 22:35:14 +0100 Subject: [PATCH 142/713] unix,win: add uv_available_parallelism() (#3499) Replacement for the usage pattern where people use uv_cpu_info() as an imperfect heuristic for determining the amount of parallelism that is available to their programs. Fixes #3493. --- docs/src/misc.rst | 19 +++++++++++++++++++ include/uv.h | 1 + src/unix/core.c | 33 +++++++++++++++++++++++++++++++++ src/win/util.c | 17 +++++++++++++++++ test/test-platform-output.c | 5 +++++ 5 files changed, 75 insertions(+) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 38fbb56081e..bae44814f19 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -334,11 +334,30 @@ API .. versionadded:: 1.16.0 +.. c:function:: unsigned int uv_available_parallelism(void) + + Returns an estimate of the default amount of parallelism a program should + use. Always returns a non-zero value. + + On Linux, inspects the calling thread's CPU affinity mask to determine if + it has been pinned to specific CPUs. + + On Windows, the available parallelism may be underreported on systems with + more than 64 logical CPUs. + + On other platforms, reports the number of CPUs that the operating system + considers to be online. + + .. versionadded:: 1.44.0 + .. c:function:: int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) Gets information about the CPUs on the system. The `cpu_infos` array will have `count` elements and needs to be freed with :c:func:`uv_free_cpu_info`. + Use :c:func:`uv_available_parallelism` if you need to know how many CPUs + are available for threads or child processes. + .. c:function:: void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) Frees the `cpu_infos` array previously allocated with :c:func:`uv_cpu_info`. diff --git a/include/uv.h b/include/uv.h index 9a418b995cd..ee1c94ccd38 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1242,6 +1242,7 @@ UV_EXTERN uv_pid_t uv_os_getppid(void); UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority); UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority); +UV_EXTERN unsigned int uv_available_parallelism(void); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); diff --git a/src/unix/core.c b/src/unix/core.c index 0bb334bd952..c0448b31e6c 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -84,6 +84,7 @@ extern char** environ; #endif #if defined(__linux__) +# include # include # define uv__accept4 accept4 #endif @@ -1648,3 +1649,35 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) { /* Out of tokens (path entries), and no match found */ return UV_EINVAL; } + + +unsigned int uv_available_parallelism(void) { +#ifdef __linux__ + cpu_set_t set; + long rc; + + memset(&set, 0, sizeof(set)); + + /* sysconf(_SC_NPROCESSORS_ONLN) in musl calls sched_getaffinity() but in + * glibc it's... complicated... so for consistency try sched_getaffinity() + * before falling back to sysconf(_SC_NPROCESSORS_ONLN). + */ + if (0 == sched_getaffinity(0, sizeof(set), &set)) + rc = CPU_COUNT(&set); + else + rc = sysconf(_SC_NPROCESSORS_ONLN); + + if (rc < 1) + rc = 1; + + return (unsigned) rc; +#else /* __linux__ */ + long rc; + + rc = sysconf(_SC_NPROCESSORS_ONLN); + if (rc < 1) + rc = 1; + + return (unsigned) rc; +#endif /* __linux__ */ +} diff --git a/src/win/util.c b/src/win/util.c index ee70ebc2083..99432053cc3 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -536,6 +536,23 @@ int uv_uptime(double* uptime) { } +unsigned int uv_available_parallelism(void) { + SYSTEM_INFO info; + unsigned rc; + + /* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems + * with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458 + */ + GetSystemInfo(&info); + + rc = info.dwNumberOfProcessors; + if (rc < 1) + rc = 1; + + return rc; +} + + int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { uv_cpu_info_t* cpu_infos; SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; diff --git a/test/test-platform-output.c b/test/test-platform-output.c index 341c7ae54ed..5827dca1cb2 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -41,6 +41,7 @@ TEST_IMPL(platform_output) { uv_interface_address_t* interfaces; uv_passwd_t pwd; uv_utsname_t uname; + unsigned par; int count; int i; int err; @@ -88,6 +89,10 @@ TEST_IMPL(platform_output) { printf(" maximum resident set size: %llu\n", (unsigned long long) rusage.ru_maxrss); + par = uv_available_parallelism(); + ASSERT_GE(par, 1); + printf("uv_available_parallelism: %u\n", par); + err = uv_cpu_info(&cpus, &count); #if defined(__CYGWIN__) || defined(__MSYS__) ASSERT(err == UV_ENOSYS); From 60fbcad9acbefd0cf9ecd73fbf8ddec54a130877 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 4 Mar 2022 21:38:31 -0500 Subject: [PATCH 143/713] process: remove OpenBSD from kevent list (#3506) From user reports, it appears that OpenBSD has a broken kevent NOTE_EXIT implementation. However, we can simply go back to the old, slower version therefore. Fix: https://github.com/libuv/libuv/issues/3504 --- src/unix/process.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index b85aa3b94ed..e634209be13 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -63,12 +63,12 @@ extern char **environ; # include "zos-base.h" #endif -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) #include #endif -#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) +#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)) static void uv__chld(uv_signal_t* handle, int signum) { assert(signum == SIGCHLD); uv__wait_children(handle->loop); @@ -964,7 +964,7 @@ int uv_spawn(uv_loop_t* loop, goto error; } -#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) +#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)) uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); #endif @@ -983,7 +983,7 @@ int uv_spawn(uv_loop_t* loop, * fail to open a stdio handle. This ensures we can eventually reap the child * with waitpid. */ if (exec_errorno == 0) { -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) struct kevent event; EV_SET(&event, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, 0); if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) { From fd34b17f9093293e95ea881849c7c3f37f5dc043 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 5 Mar 2022 10:12:26 +0100 Subject: [PATCH 144/713] zos: fix build breakage (#3513) Introduced earlier today in commit f250c6c7. _SC_NPROCESSORS_ONLN does not seem to be defined on that platform. --- src/unix/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/unix/core.c b/src/unix/core.c index c0448b31e6c..459e3c917b9 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1671,6 +1671,8 @@ unsigned int uv_available_parallelism(void) { rc = 1; return (unsigned) rc; +#elif defined(__MVS__) + return 1; /* TODO(bnoordhuis) Read from CSD_NUMBER_ONLINE_CPUS? */ #else /* __linux__ */ long rc; From 6ac063d10e060e0664b5d48cf9f44fbc220f1cfa Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 5 Mar 2022 12:52:04 -0500 Subject: [PATCH 145/713] process: only use F_DUPFD_CLOEXEC if it is defined (#3512) We can save a syscall on most modern systems (required by POSIX 2008), but not on all systems. Also handle errors from CLOEXEC. Even though fcntl does not really define there to be any, it could theoretically be EBADF if the user happened to pass a bad file descriptor to the same number fd (such that no other code happened to already fail on that). --- src/unix/process.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index e634209be13..ead54334405 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -275,9 +275,20 @@ static void uv__process_child_init(const uv_process_options_t* options, use_fd = pipes[fd][1]; if (use_fd < 0 || use_fd >= fd) continue; +#ifdef F_DUPFD_CLOEXEC /* POSIX 2008 */ pipes[fd][1] = fcntl(use_fd, F_DUPFD_CLOEXEC, stdio_count); +#else + pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); +#endif if (pipes[fd][1] == -1) uv__write_errno(error_fd); +#ifndef F_DUPFD_CLOEXEC /* POSIX 2008 */ + n = uv__cloexec_fcntl(pipes[fd][1], 1); + if (n) { + uv__write_int(error_fd, n); + _exit(127); + } +#endif } for (fd = 0; fd < stdio_count; fd++) { @@ -300,8 +311,13 @@ static void uv__process_child_init(const uv_process_options_t* options, } if (fd == use_fd) { - if (close_fd == -1) - uv__cloexec_fcntl(use_fd, 0); + if (close_fd == -1) { + n = uv__cloexec_fcntl(use_fd, 0); + if (n) { + uv__write_int(error_fd, n); + _exit(127); + } + } } else { fd = dup2(use_fd, fd); From 8e67d8b364a3c44f4fd5a2df5914f13979de7c91 Mon Sep 17 00:00:00 2001 From: roflcopter4 <15476346+roflcopter4@users.noreply.github.com> Date: Sat, 5 Mar 2022 10:54:41 -0700 Subject: [PATCH 146/713] win,poll: add the MSAFD GUID for AF_UNIX (#3511) Enables the "fast poll" mechanism for the new(ish) Unix sockets in Windows 10. --- include/uv/win.h | 2 +- src/win/poll.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/uv/win.h b/include/uv/win.h index 59a5d86e736..62be4b04ea8 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -223,7 +223,7 @@ typedef struct _AFD_POLL_INFO { AFD_POLL_HANDLE_INFO Handles[1]; } AFD_POLL_INFO, *PAFD_POLL_INFO; -#define UV_MSAFD_PROVIDER_COUNT 3 +#define UV_MSAFD_PROVIDER_COUNT 4 /** diff --git a/src/win/poll.c b/src/win/poll.c index 53a4fd97612..bd531b06792 100644 --- a/src/win/poll.c +++ b/src/win/poll.c @@ -34,7 +34,9 @@ static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = { {0xf9eab0c0, 0x26d4, 0x11d0, {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}}, {0x9fc48064, 0x7298, 0x43e4, - {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}} + {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}, + {0xa00943d9, 0x9c2e, 0x4633, + {0x9b, 0x59, 0x00, 0x57, 0xa3, 0x16, 0x09, 0x94}} }; typedef struct uv_single_fd_set_s { From c8583bbdf1760cdfc2f3c54abaef4c8295c2bef5 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 5 Mar 2022 18:55:49 +0100 Subject: [PATCH 147/713] unix: simplify uv__cloexec_fcntl() (#3492) FD_CLOEXEC is the only defined flag for fcntl(F_SETFD) so don't bother getting the status of that flag first with fcntl(F_GETFD), just set it. --- src/unix/core.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 459e3c917b9..c47f0d95824 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -651,21 +651,9 @@ int uv__cloexec_fcntl(int fd, int set) { int flags; int r; - do - r = fcntl(fd, F_GETFD); - while (r == -1 && errno == EINTR); - - if (r == -1) - return UV__ERR(errno); - - /* Bail out now if already set/clear. */ - if (!!(r & FD_CLOEXEC) == !!set) - return 0; - + flags = 0; if (set) - flags = r | FD_CLOEXEC; - else - flags = r & ~FD_CLOEXEC; + flags = FD_CLOEXEC; do r = fcntl(fd, F_SETFD, flags); From 538d718ff4996754c2935388c39e8a2ff305d6a6 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 5 Mar 2022 00:15:46 -0500 Subject: [PATCH 148/713] doc: add secondary GPG ID for vtjnash --- MAINTAINERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 9420dbbfecb..fa7c26e5d8d 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -17,6 +17,7 @@ libuv is currently managed by the following individuals: - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) * **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) * **Jiawen Geng** ([@gengjiawen](https://github.com/gengjiawen)) * **John Barboza** ([@jbarz](https://github.com/jbarz)) * **Kaoru Takanashi** ([@erw7](https://github.com/erw7)) From 20a2b1c3417bd32e82fe887d1161551107c13558 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 6 Mar 2022 15:01:33 -0500 Subject: [PATCH 149/713] unix: remove uv__cloexec_ioctl() (#3515) Now that uv__cloexec_fcntl() is simplified (https://github.com/libuv/libuv/pull/3492), there is no benefit to maintaining duplicate code paths for the same thing. --- src/unix/core.c | 16 +--------------- src/unix/internal.h | 5 +---- src/unix/process.c | 4 ++-- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index c47f0d95824..def5b8f7b52 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -599,20 +599,6 @@ int uv__nonblock_ioctl(int fd, int set) { return 0; } - - -int uv__cloexec_ioctl(int fd, int set) { - int r; - - do - r = ioctl(fd, set ? FIOCLEX : FIONCLEX); - while (r == -1 && errno == EINTR); - - if (r) - return UV__ERR(errno); - - return 0; -} #endif @@ -647,7 +633,7 @@ int uv__nonblock_fcntl(int fd, int set) { } -int uv__cloexec_fcntl(int fd, int set) { +int uv__cloexec(int fd, int set) { int flags; int r; diff --git a/src/unix/internal.h b/src/unix/internal.h index 2fa903e910e..f418572dea6 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -175,11 +175,9 @@ struct uv__stream_queued_fds_s { defined(__linux__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) -#define uv__cloexec uv__cloexec_ioctl #define uv__nonblock uv__nonblock_ioctl #define UV__NONBLOCK_IS_IOCTL 1 #else -#define uv__cloexec uv__cloexec_fcntl #define uv__nonblock uv__nonblock_fcntl #define UV__NONBLOCK_IS_IOCTL 0 #endif @@ -197,8 +195,7 @@ struct uv__stream_queued_fds_s { #endif /* core */ -int uv__cloexec_ioctl(int fd, int set); -int uv__cloexec_fcntl(int fd, int set); +int uv__cloexec(int fd, int set); int uv__nonblock_ioctl(int fd, int set); int uv__nonblock_fcntl(int fd, int set); int uv__close(int fd); /* preserves errno */ diff --git a/src/unix/process.c b/src/unix/process.c index ead54334405..270d5287829 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -283,7 +283,7 @@ static void uv__process_child_init(const uv_process_options_t* options, if (pipes[fd][1] == -1) uv__write_errno(error_fd); #ifndef F_DUPFD_CLOEXEC /* POSIX 2008 */ - n = uv__cloexec_fcntl(pipes[fd][1], 1); + n = uv__cloexec(pipes[fd][1], 1); if (n) { uv__write_int(error_fd, n); _exit(127); @@ -312,7 +312,7 @@ static void uv__process_child_init(const uv_process_options_t* options, if (fd == use_fd) { if (close_fd == -1) { - n = uv__cloexec_fcntl(use_fd, 0); + n = uv__cloexec(use_fd, 0); if (n) { uv__write_int(error_fd, n); _exit(127); From d2bff508457336d808ba7148b33088f6acbfe0a6 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 7 Mar 2022 11:39:08 -0500 Subject: [PATCH 150/713] 2022.03.07, Version 1.44.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.43.0: * darwin: remove EPROTOTYPE error workaround (Ben Noordhuis) * doc: fix v1.43.0 changelog entries (cjihrig) * win: replace CRITICAL_SECTION+Semaphore with SRWLock (David Machaj) * darwin: translate EPROTOTYPE to ECONNRESET (Ben Noordhuis) * android: use libc getifaddrs() (Ben Noordhuis) * unix: fix STATIC_ASSERT to check what it means to check (Jessica Clarke) * unix: ensure struct msghdr is zeroed in recvmmsg (Ondřej Surý) * test: test with maximum recvmmsg buffer (Ondřej Surý) * unix: don't allow too small thread stack size (Ben Noordhuis) * bsd: ensure mutex is initialized (Ben Noordhuis) * doc: add gengjiawen as maintainer (gengjiawen) * process: monitor for exit with kqueue on BSDs (Jeremy Rose) * test: fix flaky uv_fs_lutime test (Momtchil Momtchev) * build: fix cmake install locations (Jameson Nash) * thread,win: fix C90 style nit (ssrlive) * build: rename CFLAGS to AM_CFLAGS (Jameson Nash) * doc/guide: update content and sample code (woclass) * process,bsd: handle kevent NOTE_EXIT failure (Jameson Nash) * test: remove flaky test ipc_closed_handle (Ben Noordhuis) * darwin: bump minimum supported version to 10.15 (Ben Noordhuis) * win: return fractional seconds in uv_uptime() (Luca Adrian L) * build: export uv_a for cmake (WenTao Ou) * loop: add pending work to loop-alive check (Jameson Nash) * win: use GetTickCount64 for uptime again (Jameson Nash) * win: restrict system DLL load paths (jonilaitinen) * win,errors: remap ERROR_ACCESS_DENIED to UV_EACCES (Darshan Sen) * bench: add `uv_queue_work` ping-pong measurement (Momtchil Momtchev) * build: fix error C4146 on MSVC (UMU) * test: fix benchmark-ping-udp (Ryan Liptak) * win,fs: consider broken pipe error a normal EOF (Momtchil Momtchev) * document the values of enum uv_stdio_flags (Paul Evans) * win,loop: add missing uv_update_time (twosee) * win,fs: avoid closing an invalid handle (Jameson Nash) * fix oopsie from * doc: clarify android api level (Ben Noordhuis) * win: fix style nits [NFC] (Jameson Nash) * test: fix flaky udp_mmsg test (Santiago Gimeno) * test: fix ipc_send_recv_pipe flakiness (Ben Noordhuis) * doc: checkout -> check out (wyckster) * core: change uv_get_password uid/gid to unsigned (Jameson Nash) * hurd: unbreak build on GNU/Hurd (Vittore F. Scolari) * freebsd: use copy_file_range() in uv_fs_sendfile() (David Carlier) * test: use closefd in runner-unix.c (Guilherme Íscaro) * Reland "macos: use posix_spawn instead of fork" (Jameson Nash) * android: fix build error when no ifaddrs.h (ssrlive) * unix,win: add uv_available_parallelism() (Ben Noordhuis) * process: remove OpenBSD from kevent list (Jameson Nash) * zos: fix build breakage (Ben Noordhuis) * process: only use F_DUPFD_CLOEXEC if it is defined (Jameson Nash) * win,poll: add the MSAFD GUID for AF_UNIX (roflcopter4) * unix: simplify uv__cloexec_fcntl() (Ben Noordhuis) * doc: add secondary GPG ID for vtjnash (Jameson Nash) * unix: remove uv__cloexec_ioctl() (Jameson Nash) --- AUTHORS | 12 +++++ ChangeLog | 111 +++++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 8 ++-- 4 files changed, 128 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index a18d09668b9..c1a98dbf164 100644 --- a/AUTHORS +++ b/AUTHORS @@ -496,3 +496,15 @@ Jesper Storm Bache Campbell He Andrey Hohutkin deal +David Machaj <46852402+dmachaj@users.noreply.github.com> +Jessica Clarke +Jeremy Rose +woclass +Luca Adrian L +WenTao Ou +jonilaitinen +UMU +Paul Evans +wyckster +Vittore F. Scolari +roflcopter4 <15476346+roflcopter4@users.noreply.github.com> diff --git a/ChangeLog b/ChangeLog index 0a41c5760bc..1c239131256 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,114 @@ +2022.03.07, Version 1.44.0 (Stable) + +Changes since version 1.43.0: + +* darwin: remove EPROTOTYPE error workaround (Ben Noordhuis) + +* doc: fix v1.43.0 changelog entries (cjihrig) + +* win: replace CRITICAL_SECTION+Semaphore with SRWLock (David Machaj) + +* darwin: translate EPROTOTYPE to ECONNRESET (Ben Noordhuis) + +* android: use libc getifaddrs() (Ben Noordhuis) + +* unix: fix STATIC_ASSERT to check what it means to check (Jessica Clarke) + +* unix: ensure struct msghdr is zeroed in recvmmsg (Ondřej Surý) + +* test: test with maximum recvmmsg buffer (Ondřej Surý) + +* unix: don't allow too small thread stack size (Ben Noordhuis) + +* bsd: ensure mutex is initialized (Ben Noordhuis) + +* doc: add gengjiawen as maintainer (gengjiawen) + +* process: monitor for exit with kqueue on BSDs (Jeremy Rose) + +* test: fix flaky uv_fs_lutime test (Momtchil Momtchev) + +* build: fix cmake install locations (Jameson Nash) + +* thread,win: fix C90 style nit (ssrlive) + +* build: rename CFLAGS to AM_CFLAGS (Jameson Nash) + +* doc/guide: update content and sample code (woclass) + +* process,bsd: handle kevent NOTE_EXIT failure (Jameson Nash) + +* test: remove flaky test ipc_closed_handle (Ben Noordhuis) + +* darwin: bump minimum supported version to 10.15 (Ben Noordhuis) + +* win: return fractional seconds in uv_uptime() (Luca Adrian L) + +* build: export uv_a for cmake (WenTao Ou) + +* loop: add pending work to loop-alive check (Jameson Nash) + +* win: use GetTickCount64 for uptime again (Jameson Nash) + +* win: restrict system DLL load paths (jonilaitinen) + +* win,errors: remap ERROR_ACCESS_DENIED to UV_EACCES (Darshan Sen) + +* bench: add `uv_queue_work` ping-pong measurement (Momtchil Momtchev) + +* build: fix error C4146 on MSVC (UMU) + +* test: fix benchmark-ping-udp (Ryan Liptak) + +* win,fs: consider broken pipe error a normal EOF (Momtchil Momtchev) + +* document the values of enum uv_stdio_flags (Paul Evans) + +* win,loop: add missing uv_update_time (twosee) + +* win,fs: avoid closing an invalid handle (Jameson Nash) + +* fix oopsie from + +* doc: clarify android api level (Ben Noordhuis) + +* win: fix style nits [NFC] (Jameson Nash) + +* test: fix flaky udp_mmsg test (Santiago Gimeno) + +* test: fix ipc_send_recv_pipe flakiness (Ben Noordhuis) + +* doc: checkout -> check out (wyckster) + +* core: change uv_get_password uid/gid to unsigned (Jameson Nash) + +* hurd: unbreak build on GNU/Hurd (Vittore F. Scolari) + +* freebsd: use copy_file_range() in uv_fs_sendfile() (David Carlier) + +* test: use closefd in runner-unix.c (Guilherme Íscaro) + +* Reland "macos: use posix_spawn instead of fork" (Jameson Nash) + +* android: fix build error when no ifaddrs.h (ssrlive) + +* unix,win: add uv_available_parallelism() (Ben Noordhuis) + +* process: remove OpenBSD from kevent list (Jameson Nash) + +* zos: fix build breakage (Ben Noordhuis) + +* process: only use F_DUPFD_CLOEXEC if it is defined (Jameson Nash) + +* win,poll: add the MSAFD GUID for AF_UNIX (roflcopter4) + +* unix: simplify uv__cloexec_fcntl() (Ben Noordhuis) + +* doc: add secondary GPG ID for vtjnash (Jameson Nash) + +* unix: remove uv__cloexec_ioctl() (Jameson Nash) + + 2022.01.05, Version 1.43.0 (Stable), 988f2bfc4defb9a85a536a3e645834c161143ee0 Changes since version 1.42.0: diff --git a/configure.ac b/configure.ac index bdb0c75ea50..40715b3f4c9 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.43.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.44.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 1934f390dc5..424640194aa 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 43 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 44 +#define UV_VERSION_PATCH 0 +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 8367fc2aac77ad604481ffdfbdb4afb22aada8dc Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 7 Mar 2022 11:39:19 -0500 Subject: [PATCH 151/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 1c239131256..0c19db28ec4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2022.03.07, Version 1.44.0 (Stable) +2022.03.07, Version 1.44.0 (Stable), d2bff508457336d808ba7148b33088f6acbfe0a6 Changes since version 1.43.0: From 761de533b2485e7c5575e1f0f228761325deb6ad Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 7 Mar 2022 12:18:03 -0500 Subject: [PATCH 152/713] Now working on version 1.44.1 Fixes: https://github.com/libuv/libuv/issues/3452 --- configure.ac | 2 +- include/uv/version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 40715b3f4c9..87e5197132a 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.44.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.44.1-dev], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 424640194aa..e3839ce2c83 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 44 -#define UV_VERSION_PATCH 0 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 1 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 4296fec7f50145e2a307f3db7ae22984713976a7 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 7 Mar 2022 17:07:49 -0500 Subject: [PATCH 153/713] process: simplify uv__write_int calls (#3519) --- src/unix/process.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index 270d5287829..1157006d7e5 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -216,16 +216,14 @@ static void uv__write_int(int fd, int val) { n = write(fd, &val, sizeof(val)); while (n == -1 && errno == EINTR); - if (n == -1 && errno == EPIPE) - return; /* parent process has quit */ - - assert(n == sizeof(val)); + /* The write might have failed (e.g. if the parent process has died), + * but we have nothing left but to _exit ourself now too. */ + _exit(127); } static void uv__write_errno(int error_fd) { uv__write_int(error_fd, UV__ERR(errno)); - _exit(127); } @@ -284,10 +282,8 @@ static void uv__process_child_init(const uv_process_options_t* options, uv__write_errno(error_fd); #ifndef F_DUPFD_CLOEXEC /* POSIX 2008 */ n = uv__cloexec(pipes[fd][1], 1); - if (n) { + if (n) uv__write_int(error_fd, n); - _exit(127); - } #endif } @@ -313,10 +309,8 @@ static void uv__process_child_init(const uv_process_options_t* options, if (fd == use_fd) { if (close_fd == -1) { n = uv__cloexec(use_fd, 0); - if (n) { + if (n) uv__write_int(error_fd, n); - _exit(127); - } } } else { @@ -368,7 +362,6 @@ static void uv__process_child_init(const uv_process_options_t* options, #endif uv__write_errno(error_fd); - abort(); } #endif From 3c569c00dfb4e5fd93a4401bdc307eca6b29102e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 9 Mar 2022 11:06:39 +0100 Subject: [PATCH 154/713] macos: don't use thread-unsafe strtok() (#3524) Co-authored-by: Jameson Nash --- src/unix/process.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index 1157006d7e5..3c0f19f4f59 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -387,30 +387,22 @@ static void uv__spawn_init_posix_spawn_fncs(void) { static void uv__spawn_init_can_use_setsid(void) { - static const int MACOS_CATALINA_VERSION_MAJOR = 19; - char version_str[256]; - char* version_major_str; - size_t version_str_size = 256; - int r; - int version_major; - - /* Get a version string */ - r = sysctlbyname("kern.osrelease", version_str, &version_str_size, NULL, 0); - if (r != 0) + int which[] = {CTL_KERN, KERN_OSRELEASE}; + unsigned major; + unsigned minor; + unsigned patch; + char buf[256]; + size_t len; + + len = sizeof(buf); + if (sysctl(which, ARRAY_SIZE(which), buf, &len, NULL, 0)) return; - /* Try to get the major version number. If not found - * fall back to the fork/exec flow */ - version_major_str = strtok(version_str, "."); - if (version_major_str == NULL) + /* NULL specifies to use LC_C_LOCALE */ + if (3 != sscanf_l(buf, NULL, "%u.%u.%u", &major, &minor, &patch)) return; - /* Parse the version major as a number. If it is greater than - * the major version for macOS Catalina (aka macOS 10.15), then - * the POSIX_SPAWN_SETSID flag is available */ - version_major = atoi_l(version_major_str, NULL); /* Use LC_C_LOCALE */ - if (version_major >= MACOS_CATALINA_VERSION_MAJOR) - posix_spawn_can_use_setsid = 1; + posix_spawn_can_use_setsid = (major >= 19); /* macOS Catalina */ } From bae2992cb0d4b9dd1f8e0fb5f3e01651dbf5c4d6 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 9 Mar 2022 12:25:51 -0500 Subject: [PATCH 155/713] process: fix hang after NOTE_EXIT (#3521) Bug #3504 seems to affect more platforms than just OpenBSD. As this seems to be a race condition in these kernels, we do not want to fail because of it. Instead, we remove the WNOHANG flag from waitpid, and track exactly which processes have exited. Should also be a slight speed improvement for excessively large numbers of live children. --- src/unix/kqueue.c | 15 +++++++++++++-- src/unix/process.c | 34 ++++++++++++++++++++++++++++------ src/uv-common.h | 5 ++++- 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 857eb1d54bf..036055149fc 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -117,6 +117,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { unsigned int revents; QUEUE* q; uv__io_t* w; + uv_process_t* process; sigset_t* pset; sigset_t set; uint64_t base; @@ -284,12 +285,22 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; for (i = 0; i < nfds; i++) { ev = events + i; + fd = ev->ident; + + /* Handle kevent NOTE_EXIT results */ if (ev->filter == EVFILT_PROC) { - loop->flags |= UV_LOOP_REAP_CHILDREN; + QUEUE_FOREACH(q, &loop->process_handles) { + process = QUEUE_DATA(q, uv_process_t, queue); + if (process->pid == fd) { + process->flags |= UV_HANDLE_REAP; + loop->flags |= UV_LOOP_REAP_CHILDREN; + break; + } + } nevents++; continue; } - fd = ev->ident; + /* Skip invalidated events, see uv__platform_invalidate_fd */ if (fd == -1) continue; diff --git a/src/unix/process.c b/src/unix/process.c index 3c0f19f4f59..8802e4f30c3 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -63,12 +63,18 @@ extern char **environ; # include "zos-base.h" #endif -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) +#if defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) #include +#else +#define UV_USE_SIGCHLD #endif -#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)) +#ifdef UV_USE_SIGCHLD static void uv__chld(uv_signal_t* handle, int signum) { assert(signum == SIGCHLD); uv__wait_children(handle->loop); @@ -80,6 +86,7 @@ void uv__wait_children(uv_loop_t* loop) { int exit_status; int term_signal; int status; + int options; pid_t pid; QUEUE pending; QUEUE* q; @@ -93,19 +100,33 @@ void uv__wait_children(uv_loop_t* loop) { process = QUEUE_DATA(q, uv_process_t, queue); q = QUEUE_NEXT(q); +#ifndef UV_USE_SIGCHLD + if ((process->flags & UV_HANDLE_REAP) == 0) + continue; + options = 0; + process->flags &= ~UV_HANDLE_REAP; +#else + options = WNOHANG; +#endif + do - pid = waitpid(process->pid, &status, WNOHANG); + pid = waitpid(process->pid, &status, options); while (pid == -1 && errno == EINTR); - if (pid == 0) +#ifdef UV_USE_SIGCHLD + if (pid == 0) /* Not yet exited */ continue; +#endif if (pid == -1) { if (errno != ECHILD) abort(); + /* The child died, and we missed it. This probably means someone else + * stole the waitpid from us. Handle this by not handling it at all. */ continue; } + assert(pid == process->pid); process->status = status; QUEUE_REMOVE(&process->queue); QUEUE_INSERT_TAIL(&pending, &process->queue); @@ -965,7 +986,7 @@ int uv_spawn(uv_loop_t* loop, goto error; } -#if !(defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)) +#ifdef UV_USE_SIGCHLD uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); #endif @@ -984,13 +1005,14 @@ int uv_spawn(uv_loop_t* loop, * fail to open a stdio handle. This ensures we can eventually reap the child * with waitpid. */ if (exec_errorno == 0) { -#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) +#ifndef UV_USE_SIGCHLD struct kevent event; EV_SET(&event, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, 0); if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) { if (errno != ESRCH) abort(); /* Process already exited. Call waitpid on the next loop iteration. */ + process->flags |= UV_HANDLE_REAP; loop->flags |= UV_LOOP_REAP_CHILDREN; } #endif diff --git a/src/uv-common.h b/src/uv-common.h index 8a190bf8fa8..6001b0cf68d 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -130,7 +130,10 @@ enum { UV_SIGNAL_ONE_SHOT = 0x02000000, /* Only used by uv_poll_t handles. */ - UV_HANDLE_POLL_SLOW = 0x01000000 + UV_HANDLE_POLL_SLOW = 0x01000000, + + /* Only used by uv_process_t handles. */ + UV_HANDLE_REAP = 0x10000000 }; int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); From e8b7eb6908a847ffbe6ab2eec7428e43a0aa53a2 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 9 Mar 2022 12:54:54 -0500 Subject: [PATCH 156/713] 2022.03.09, Version 1.44.1 (Stable) Changes since version 1.44.0: * process: simplify uv__write_int calls (Jameson Nash) * macos: don't use thread-unsafe strtok() (Ben Noordhuis) * process: fix hang after NOTE_EXIT (Jameson Nash) --- ChangeLog | 11 +++++++++++ configure.ac | 2 +- include/uv/version.h | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0c19db28ec4..ea28356d53b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2022.03.09, Version 1.44.1 (Stable) + +Changes since version 1.44.0: + +* process: simplify uv__write_int calls (Jameson Nash) + +* macos: don't use thread-unsafe strtok() (Ben Noordhuis) + +* process: fix hang after NOTE_EXIT (Jameson Nash) + + 2022.03.07, Version 1.44.0 (Stable), d2bff508457336d808ba7148b33088f6acbfe0a6 Changes since version 1.43.0: diff --git a/configure.ac b/configure.ac index 87e5197132a..bd1e9c61365 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.44.1-dev], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.44.1], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index e3839ce2c83..56ac1bf41d6 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -33,8 +33,8 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 44 #define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From ee2668e586c51949b1ff6dbf73458f83ed98a76e Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 9 Mar 2022 12:55:07 -0500 Subject: [PATCH 157/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ea28356d53b..48ee5490d11 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2022.03.09, Version 1.44.1 (Stable) +2022.03.09, Version 1.44.1 (Stable), e8b7eb6908a847ffbe6ab2eec7428e43a0aa53a2 Changes since version 1.44.0: From df63ee1a1de6d99821c172ea9590cba72917e718 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 9 Mar 2022 12:58:37 -0500 Subject: [PATCH 158/713] Now working on version 1.44.2 Fixes: https://github.com/libuv/libuv/issues/3522 --- configure.ac | 2 +- include/uv/version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index bd1e9c61365..1c2a026a78f 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.44.1], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.44.2-dev], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 56ac1bf41d6..f7f49520c4a 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 44 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 2 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 5ec89b8c500f80b184d0b275ffd7a814e1a5f8be Mon Sep 17 00:00:00 2001 From: V-for-Vasili Date: Thu, 10 Mar 2022 18:53:04 -0500 Subject: [PATCH 159/713] aix, ibmi: handle server hang when remote sends TCP RST (#3482) Workaround getsockname() not working for a TCP handle that has received RST from the remote. Co-authored-by: Jameson Nash --- CMakeLists.txt | 1 + Makefile.am | 1 + src/unix/internal.h | 1 - src/unix/pipe.c | 2 +- src/unix/stream.c | 43 ----------------- src/unix/tty.c | 45 ++++++++++++++---- test/test-list.h | 4 ++ test/test-tcp-rst.c | 111 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 154 insertions(+), 54 deletions(-) create mode 100644 test/test-tcp-rst.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ac524127375..628812d5d73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -574,6 +574,7 @@ if(LIBUV_BUILD_TESTS) test/test-tcp-open.c test/test-tcp-read-stop.c test/test-tcp-read-stop-start.c + test/test-tcp-rst.c test/test-tcp-shutdown-after-write.c test/test-tcp-try-write.c test/test-tcp-try-write-error.c diff --git a/Makefile.am b/Makefile.am index d1ec1a5e2ab..895dba51cd8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -266,6 +266,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-tcp-open.c \ test/test-tcp-read-stop.c \ test/test-tcp-read-stop-start.c \ + test/test-tcp-rst.c \ test/test-tcp-shutdown-after-write.c \ test/test-tcp-unexpected-read.c \ test/test-tcp-oob.c \ diff --git a/src/unix/internal.h b/src/unix/internal.h index f418572dea6..cee35c2106a 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -277,7 +277,6 @@ void uv__tcp_close(uv_tcp_t* handle); size_t uv__thread_stack_size(void); void uv__udp_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle); -uv_handle_type uv__handle_type(int fd); FILE* uv__open_file(const char* path); int uv__getpwuid_r(uv_passwd_t* pwd); int uv__search_path(const char* prog, char* buf, size_t* buflen); diff --git a/src/unix/pipe.c b/src/unix/pipe.c index fcc2cba1a5d..f373c86ea00 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -319,7 +319,7 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { if (handle->accepted_fd == -1) return UV_UNKNOWN_HANDLE; else - return uv__handle_type(handle->accepted_fd); + return uv_guess_handle(handle->accepted_fd); } diff --git a/src/unix/stream.c b/src/unix/stream.c index 619b6250129..9615673ace8 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -964,49 +964,6 @@ static void uv__write_callbacks(uv_stream_t* stream) { } -uv_handle_type uv__handle_type(int fd) { - struct sockaddr_storage ss; - socklen_t sslen; - socklen_t len; - int type; - - memset(&ss, 0, sizeof(ss)); - sslen = sizeof(ss); - - if (getsockname(fd, (struct sockaddr*)&ss, &sslen)) - return UV_UNKNOWN_HANDLE; - - len = sizeof type; - - if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len)) - return UV_UNKNOWN_HANDLE; - - if (type == SOCK_STREAM) { -#if defined(_AIX) || defined(__DragonFly__) - /* on AIX/DragonFly the getsockname call returns an empty sa structure - * for sockets of type AF_UNIX. For all other types it will - * return a properly filled in structure. - */ - if (sslen == 0) - return UV_NAMED_PIPE; -#endif - switch (ss.ss_family) { - case AF_UNIX: - return UV_NAMED_PIPE; - case AF_INET: - case AF_INET6: - return UV_TCP; - } - } - - if (type == SOCK_DGRAM && - (ss.ss_family == AF_INET || ss.ss_family == AF_INET6)) - return UV_UDP; - - return UV_UNKNOWN_HANDLE; -} - - static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { stream->flags |= UV_HANDLE_READ_EOF; stream->flags &= ~UV_HANDLE_READING; diff --git a/src/unix/tty.c b/src/unix/tty.c index 9442cf16360..f34e1ef1896 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -331,7 +331,7 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { uv_handle_type uv_guess_handle(uv_file file) { - struct sockaddr sa; + struct sockaddr_storage ss; struct stat s; socklen_t len; int type; @@ -342,8 +342,23 @@ uv_handle_type uv_guess_handle(uv_file file) { if (isatty(file)) return UV_TTY; - if (fstat(file, &s)) + if (fstat(file, &s)) { +#if defined(__PASE__) + // On ibmi receiving RST from TCP instead of FIN immediately puts fd into + // an error state. fstat will return EINVAL, getsockname will also return + // EINVAL, even if sockaddr_storage is valid. (If file does not refer to a + // socket, ENOTSOCK is returned instead.) + // In such cases, we will permit the user to open the connection as uv_tcp + // still, so that the user can get immediately notified of the error in + // their read callback and close this fd. + len = sizeof(ss); + if (getsockname(file, (struct sockaddr*) &ss, &len)) { + if (errno == EINVAL) + return UV_TCP; + } +#endif return UV_UNKNOWN_HANDLE; + } if (S_ISREG(s.st_mode)) return UV_FILE; @@ -357,16 +372,28 @@ uv_handle_type uv_guess_handle(uv_file file) { if (!S_ISSOCK(s.st_mode)) return UV_UNKNOWN_HANDLE; - len = sizeof(type); - if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len)) + len = sizeof(ss); + if (getsockname(file, (struct sockaddr*) &ss, &len)) { +#if defined(_AIX) + // On aix receiving RST from TCP instead of FIN immediately puts fd into + // an error state. In such case getsockname will return EINVAL, even if + // sockaddr_storage is valid. + // In such cases, we will permit the user to open the connection as uv_tcp + // still, so that the user can get immediately notified of the error in + // their read callback and close this fd. + if (errno == EINVAL) { + return UV_TCP; + } +#endif return UV_UNKNOWN_HANDLE; + } - len = sizeof(sa); - if (getsockname(file, &sa, &len)) + len = sizeof(type); + if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len)) return UV_UNKNOWN_HANDLE; if (type == SOCK_DGRAM) - if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) + if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) return UV_UDP; if (type == SOCK_STREAM) { @@ -379,9 +406,9 @@ uv_handle_type uv_guess_handle(uv_file file) { return UV_NAMED_PIPE; #endif /* defined(_AIX) || defined(__DragonFly__) */ - if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) + if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) return UV_TCP; - if (sa.sa_family == AF_UNIX) + if (ss.ss_family == AF_UNIX) return UV_NAMED_PIPE; } diff --git a/test/test-list.h b/test/test-list.h index 15a3bad05a6..3d9bc397c36 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -147,6 +147,7 @@ TEST_DECLARE (tcp_write_to_half_open_connection) TEST_DECLARE (tcp_unexpected_read) TEST_DECLARE (tcp_read_stop) TEST_DECLARE (tcp_read_stop_start) +TEST_DECLARE (tcp_rst) TEST_DECLARE (tcp_bind6_error_addrinuse) TEST_DECLARE (tcp_bind6_error_addrnotavail) TEST_DECLARE (tcp_bind6_error_fault) @@ -723,6 +724,9 @@ TASK_LIST_START TEST_ENTRY (tcp_read_stop_start) + TEST_ENTRY (tcp_rst) + TEST_HELPER (tcp_rst, tcp4_echo_server) + TEST_ENTRY (tcp_bind6_error_addrinuse) TEST_ENTRY (tcp_bind6_error_addrnotavail) TEST_ENTRY (tcp_bind6_error_fault) diff --git a/test/test-tcp-rst.c b/test/test-tcp-rst.c new file mode 100644 index 00000000000..04468dc06e3 --- /dev/null +++ b/test/test-tcp-rst.c @@ -0,0 +1,111 @@ +/* Copyright libuv project and contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_tcp_t tcp; +static uv_connect_t connect_req; +static uv_shutdown_t shutdown_req; +static uv_buf_t qbuf; +static int called_alloc_cb; +static int called_connect_cb; +static int called_shutdown_cb; +static int called_close_cb; + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle == (uv_handle_t*) &tcp); + called_close_cb++; +} + + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = malloc(size); + buf->len = size; + called_alloc_cb++; +} + + +static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) { + ASSERT_PTR_EQ((uv_tcp_t*) t, &tcp); + ASSERT_EQ(nread, UV_ECONNRESET); + + int fd; + ASSERT_EQ(0, uv_fileno((uv_handle_t*) t, &fd)); + uv_handle_type type = uv_guess_handle(fd); + ASSERT_EQ(type, UV_TCP); + + uv_close((uv_handle_t *) t, close_cb); + free(buf->base); +} + + +static void connect_cb(uv_connect_t *req, int status) { + ASSERT_EQ(status, 0); + ASSERT_PTR_EQ(req, &connect_req); + + /* Start reading from the connection so we receive the RST in uv__read. */ + ASSERT_EQ(0, uv_read_start((uv_stream_t*) &tcp, alloc_cb, read_cb)); + + /* Write 'QSH' to receive RST from the echo server. */ + ASSERT_EQ(qbuf.len, uv_try_write((uv_stream_t*) &tcp, &qbuf, 1)); + + called_connect_cb++; + ASSERT_EQ(called_shutdown_cb, 0); +} + + +/* + * This test has a client which connects to the echo_server and receives TCP + * RST. Test checks that uv_guess_handle still works on a reset TCP handle. + */ +TEST_IMPL(tcp_rst) { +#ifndef _WIN32 + struct sockaddr_in server_addr; + int r; + + qbuf.base = "QSH"; + qbuf.len = 3; + + ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + r = uv_tcp_init(uv_default_loop(), &tcp); + ASSERT_EQ(r, 0); + + r = uv_tcp_connect(&connect_req, + &tcp, + (const struct sockaddr*) &server_addr, + connect_cb); + ASSERT_EQ(r, 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT_EQ(called_alloc_cb, 1); + ASSERT_EQ(called_connect_cb, 1); + ASSERT_EQ(called_shutdown_cb, 0); + ASSERT_EQ(called_close_cb, 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +#else + RETURN_SKIP("Unix only test"); +#endif +} From 08fe5aabff2af47600463736912e0849abdb3e94 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 11 Mar 2022 11:59:38 -0500 Subject: [PATCH 160/713] build: make CI a bit noisier (#3532) Github Actions will already hide the output, so we don't need to also suppress the output. That can sometimes hide problems that might have only been visible on inspection. --- .github/workflows/CI.yml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 19fc0cf036b..b752bee9fa5 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -27,11 +27,19 @@ jobs: cd build cmake .. -DBUILD_TESTING=ON -G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }} cmake --build . + - name: platform_output + shell: cmd + run: | + build\\Debug\\uv_run_tests.exe platform_output + - name: platform_output_a + shell: cmd + run: | + build\\Debug\\uv_run_tests_a.exe platform_output - name: Test shell: cmd run: | cd build - ctest -C Debug --output-on-failure + ctest -C Debug -V build-android: runs-on: ubuntu-latest @@ -62,6 +70,12 @@ jobs: cd build && cmake .. -DBUILD_TESTING=ON -G Ninja cmake --build . ls -lh + - name: platform_output + run: | + ./build/uv_run_tests platform_output + - name: platform_output_a + run: | + ./build/uv_run_tests_a platform_output - name: Test run: | cd build && ctest -V From bc9cd5634541ee9f1cab7eb643c78766045347c8 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 11 Mar 2022 12:05:24 -0500 Subject: [PATCH 161/713] process: reset the signal mask if the fork fails (#3537) Fix a regression that sneaked into posix spawn changes. Refs: https://github.com/libuv/libuv/pull/3257 --- src/unix/process.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index 8802e4f30c3..c8816b85b7e 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -812,11 +812,6 @@ static int uv__spawn_and_init_child_fork(const uv_process_options_t* options, *pid = fork(); - if (*pid == -1) { - /* Failed to fork */ - return UV__ERR(errno); - } - if (*pid == 0) { /* Fork succeeded, in the child process */ uv__process_child_init(options, stdio_count, pipes, error_fd); @@ -826,6 +821,10 @@ static int uv__spawn_and_init_child_fork(const uv_process_options_t* options, if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0) abort(); + if (*pid == -1) + /* Failed to fork */ + return UV__ERR(errno); + /* Fork succeeded, in the parent process */ return 0; } From 442e471cfc91597e7d662c76608d3eb7602d9368 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Sun, 13 Mar 2022 17:50:09 -0400 Subject: [PATCH 162/713] zos: implement cmpxchgi() using assembly (#3543) Use hand-rolled assembly to resolve a runtime bug related to the codegen from builtin __plo_CSST. Co-authored-by: ccw --- src/unix/atomic-ops.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h index c48d058435a..664a9426706 100644 --- a/src/unix/atomic-ops.h +++ b/src/unix/atomic-ops.h @@ -37,12 +37,11 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { : "memory"); return out; #elif defined(__MVS__) - unsigned int op4; - if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, - (unsigned int*) ptr, *ptr, &op4)) - return oldval; - else - return op4; + /* Use hand-rolled assembly because codegen from builtin __plo_CSST results in + * a runtime bug. + */ + __asm(" cs %0,%2,%1 \n " : "+r"(oldval), "+m"(*ptr) : "r"(newval) :); + return oldval; #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval); #else From 739e441d4d4135e411e94a6e4c190a7fa32ac400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claes=20N=C3=A4st=C3=A9n?= Date: Tue, 15 Mar 2022 13:51:00 +0100 Subject: [PATCH 163/713] build: AC_SUBST for AM_CFLAGS (#3551) Using autoconf 2.71 and automake 1.16.5 the CFLAGS from CC_CHECK_CFLAGS_APPEND does not get set in the Makefile without AC_SUBST causing compilation to fail on Solaris due to missing -std=gnu89 --- m4/libuv-check-flags.m4 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/m4/libuv-check-flags.m4 b/m4/libuv-check-flags.m4 index 46b9dd86a7d..9d0aad82a2d 100644 --- a/m4/libuv-check-flags.m4 +++ b/m4/libuv-check-flags.m4 @@ -73,6 +73,8 @@ AC_DEFUN([CC_CHECK_CFLAG_APPEND], [ AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], [AM_CFLAGS="$AM_CFLAGS $1"; DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; $2], [$3]) + + AC_SUBST([AM_CFLAGS]) ]) dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not]) From c1128f3db3fe85039f9dc9423b353a3ad673a13a Mon Sep 17 00:00:00 2001 From: V-for-Vasili Date: Fri, 18 Mar 2022 08:03:47 -0400 Subject: [PATCH 164/713] ibmi: Implement UDP disconnect (#3561) On IBM i a connectionless transport socket can be disconnected by either setting the addr parameter to NULL or setting the addr_length parameter to zero, and issuing another connect(). Refs: https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/connec.htm --- src/unix/udp.c | 8 ++++++++ test/test-udp-connect.c | 4 ---- test/test-udp-connect6.c | 4 ---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index aad7a6dcf61..d9c15e4effd 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -704,7 +704,15 @@ int uv__udp_disconnect(uv_udp_t* handle) { do { errno = 0; +#ifdef __PASE__ + // On IBMi a connectionless transport socket can be disconnected by + // either setting the addr parameter to NULL or setting the + // addr_length parameter to zero, and issuing another connect(). + // https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/connec.htm + r = connect(handle->io_watcher.fd, (struct sockaddr*) NULL, 0); +#else r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr)); +#endif } while (r == -1 && errno == EINTR); if (r == -1) { diff --git a/test/test-udp-connect.c b/test/test-udp-connect.c index cd159b68da4..0be702efef4 100644 --- a/test/test-udp-connect.c +++ b/test/test-udp-connect.c @@ -98,10 +98,6 @@ static void sv_recv_cb(uv_udp_t* handle, TEST_IMPL(udp_connect) { -#if defined(__PASE__) - RETURN_SKIP( - "IBMi PASE's UDP connection can not be disconnected with AF_UNSPEC."); -#endif uv_udp_send_t req; struct sockaddr_in ext_addr; struct sockaddr_in tmp_addr; diff --git a/test/test-udp-connect6.c b/test/test-udp-connect6.c index 8e385af99b2..d000daf17fb 100644 --- a/test/test-udp-connect6.c +++ b/test/test-udp-connect6.c @@ -98,10 +98,6 @@ static void sv_recv_cb(uv_udp_t* handle, TEST_IMPL(udp_connect6) { -#if defined(__PASE__) - RETURN_SKIP( - "IBMi PASE's UDP connection can not be disconnected with AF_UNSPEC."); -#endif uv_udp_send_t req; struct sockaddr_in6 ext_addr; struct sockaddr_in6 tmp_addr; From ff8290179c6658c2e57965a718154f154b454765 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 19 Mar 2022 10:32:33 +0100 Subject: [PATCH 165/713] doc: update active maintainers list (#3527) --- MAINTAINERS.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index fa7c26e5d8d..477901f8680 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -1,10 +1,7 @@ - # Project Maintainers libuv is currently managed by the following individuals: -* **Anna Henningsen** ([@addaleax](https://github.com/addaleax)) -* **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz)) * **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis)) - GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis) * **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus)) @@ -13,13 +10,10 @@ libuv is currently managed by the following individuals: - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) -* **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq)) - - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) * **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) * **Jiawen Geng** ([@gengjiawen](https://github.com/gengjiawen)) -* **John Barboza** ([@jbarz](https://github.com/jbarz)) * **Kaoru Takanashi** ([@erw7](https://github.com/erw7)) - GPG Key: 5804 F999 8A92 2AFB A398 47A0 7183 5090 6134 887F (pubkey-erw7) * **Richard Lau** ([@richardlau](https://github.com/richardlau)) @@ -29,6 +23,13 @@ libuv is currently managed by the following individuals: * **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul)) - GPG key: FDF5 1936 4458 319F A823 3DC9 410E 5553 AE9B C059 (pubkey-saghul) +## Project Maintainers emeriti + +* **Anna Henningsen** ([@addaleax](https://github.com/addaleax)) +* **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz)) +* **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq)) +* **John Barboza** ([@jbarz](https://github.com/jbarz)) + ## Storing a maintainer key in Git It's quite handy to store a maintainer's signature as a git blob, and have From 0b23a1ee7ec753db76d0d33d2e66c4f11d4f310e Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sat, 19 Mar 2022 06:30:36 -0400 Subject: [PATCH 166/713] build: fix kFreeBSD build (#3566) Define _GNU_SOURCE and link against libdl for dlopen. Link to freebsd-glue for cmake builds. This was previously fixed for Makefile builds in c5d2bf12f7565e143b6becd2560428e602485d06 --- CMakeLists.txt | 5 +++++ Makefile.am | 4 ++++ configure.ac | 1 + 3 files changed, 10 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 628812d5d73..4c50cc560fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -269,6 +269,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "GNU") src/unix/hurd.c) endif() +if(CMAKE_SYSTEM_NAME STREQUAL "kFreeBSD") + list(APPEND uv_defines _GNU_SOURCE) + list(APPEND uv_libraries dl freebsd-glue) +endif() + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") list(APPEND uv_defines _GNU_SOURCE _POSIX_C_SOURCE=200112) list(APPEND uv_libraries dl rt) diff --git a/Makefile.am b/Makefile.am index 895dba51cd8..32fccede981 100644 --- a/Makefile.am +++ b/Makefile.am @@ -464,6 +464,10 @@ libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/hurd.c endif +if KFREEBSD +libuv_la_CFLAGS += -D_GNU_SOURCE +endif + if LINUX uvinclude_HEADERS += include/uv/linux.h libuv_la_CFLAGS += -D_GNU_SOURCE diff --git a/configure.ac b/configure.ac index 1c2a026a78f..a9012d40480 100644 --- a/configure.ac +++ b/configure.ac @@ -60,6 +60,7 @@ AM_CONDITIONAL([CYGWIN], [AS_CASE([$host_os],[cygwin*], [true], [false]) AM_CONDITIONAL([DARWIN], [AS_CASE([$host_os],[darwin*], [true], [false])]) AM_CONDITIONAL([DRAGONFLY],[AS_CASE([$host_os],[dragonfly*], [true], [false])]) AM_CONDITIONAL([FREEBSD], [AS_CASE([$host_os],[*freebsd*], [true], [false])]) +AM_CONDITIONAL([KFREEBSD], [AS_CASE([$host_os],[kfreebsd*], [true], [false])]) AM_CONDITIONAL([HAIKU], [AS_CASE([$host_os],[haiku], [true], [false])]) AM_CONDITIONAL([HURD], [AS_CASE([$host_os],[gnu*], [true], [false])]) AM_CONDITIONAL([LINUX], [AS_CASE([$host_os],[linux*], [true], [false])]) From 4d8af0c9456d64e2829fa2076a736441cd7585fc Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Sun, 20 Mar 2022 15:34:19 +0530 Subject: [PATCH 167/713] build: remove Windows 2016 workflows (#3379) Refs: https://github.blog/changelog/2021-10-19-github-actions-the-windows-2016-runner-image-will-be-removed-from-github-hosted-runners-on-march-15-2022/ Signed-off-by: Darshan Sen --- .github/workflows/CI.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index b752bee9fa5..8f592be6fae 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -10,8 +10,6 @@ jobs: fail-fast: false matrix: config: - - {toolchain: Visual Studio 15 2017, arch: Win32, server: 2016} - - {toolchain: Visual Studio 15 2017, arch: x64, server: 2016} - {toolchain: Visual Studio 16 2019, arch: Win32, server: 2019} - {toolchain: Visual Studio 16 2019, arch: x64, server: 2019} - {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022} From a6ba1d709eea338df4a6ba125a01efa20de34ad7 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Sun, 20 Mar 2022 15:36:14 +0530 Subject: [PATCH 168/713] Revert "win,errors: remap ERROR_ACCESS_DENIED to UV_EACCES (#3193)" (#3565) Although the change remapped the error code to the correct one, a lot of code already depends on the incorrect one, so it's not worth the breakage. This reverts commit 04a35efe69001a27e177aebde6c8db6f4cca7e4b. Refs: https://github.com/nodejs/node/pull/42340 Signed-off-by: Darshan Sen --- src/win/error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/error.c b/src/win/error.c index 20ac19ef6e0..3a269da87a9 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -73,7 +73,6 @@ int uv_translate_sys_error(int sys_errno) { case WSAEACCES: return UV_EACCES; case ERROR_ELEVATION_REQUIRED: return UV_EACCES; case ERROR_CANT_ACCESS_FILE: return UV_EACCES; - case ERROR_ACCESS_DENIED: return UV_EACCES; case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; case WSAEADDRINUSE: return UV_EADDRINUSE; case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; @@ -155,6 +154,7 @@ int uv_translate_sys_error(int sys_errno) { case WSAENOTSOCK: return UV_ENOTSOCK; case ERROR_NOT_SUPPORTED: return UV_ENOTSUP; case ERROR_BROKEN_PIPE: return UV_EOF; + case ERROR_ACCESS_DENIED: return UV_EPERM; case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM; case ERROR_BAD_PIPE: return UV_EPIPE; case ERROR_NO_DATA: return UV_EPIPE; From 93309c6dbf07e4eb0ddfaf3757a874093e4d2198 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 21 Mar 2022 15:44:43 -0400 Subject: [PATCH 169/713] unix: simplify getpwuid call (#3535) As suggested in https://github.com/libuv/libuv/pull/3523#discussion_r821550169 --- src/unix/core.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index def5b8f7b52..aade3b3760a 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1162,24 +1162,17 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { size_t name_size; size_t homedir_size; size_t shell_size; - long initsize; int r; if (pwd == NULL) return UV_EINVAL; - initsize = sysconf(_SC_GETPW_R_SIZE_MAX); - - if (initsize <= 0) - bufsize = 4096; - else - bufsize = (size_t) initsize; - uid = geteuid(); - buf = NULL; - for (;;) { - uv__free(buf); + /* Calling sysconf(_SC_GETPW_R_SIZE_MAX) would get the suggested size, but it + * is frequently 1024 or 4096, so we can just use that directly. The pwent + * will not usually be large. */ + for (bufsize = 2000;; bufsize *= 2) { buf = uv__malloc(bufsize); if (buf == NULL) @@ -1189,21 +1182,18 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { r = getpwuid_r(uid, &pw, buf, bufsize, &result); while (r == EINTR); + if (r != 0 || result == NULL) + uv__free(buf); + if (r != ERANGE) break; - - bufsize *= 2; } - if (r != 0) { - uv__free(buf); + if (r != 0) return UV__ERR(r); - } - if (result == NULL) { - uv__free(buf); + if (result == NULL) return UV_ENOENT; - } /* Allocate memory for the username, shell, and home directory */ name_size = strlen(pw.pw_name) + 1; From 8528c622b0d55699c8009bc3c2ed0f76fdb45ee5 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 21 Mar 2022 18:34:00 -0400 Subject: [PATCH 170/713] build: filter CI by paths and branches (#3569) Avoids some unnecessary CI work, particularly on forks, which would often start a build on every push. --- .github/workflows/{CI.yml => CI-unix.yml} | 51 ++++++----------------- .github/workflows/CI-win.yml | 51 +++++++++++++++++++++++ .github/workflows/sanitizer.yml | 23 ++++++++-- 3 files changed, 83 insertions(+), 42 deletions(-) rename .github/workflows/{CI.yml => CI-unix.yml} (79%) create mode 100644 .github/workflows/CI-win.yml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI-unix.yml similarity index 79% rename from .github/workflows/CI.yml rename to .github/workflows/CI-unix.yml index 8f592be6fae..132c7ed37b6 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI-unix.yml @@ -1,44 +1,19 @@ -name: CI +name: CI-unix -on: [push, pull_request] +on: + pull_request: + paths: + - '**' + - '!docs/**' + - '!src/win/**' + - '!.**' + - '.github/workflows/CI-unix.yml' + push: + branches: + - v[0-9].* + - master jobs: - build-windows: - runs-on: windows-${{ matrix.config.server }} - name: build-${{ matrix.config.toolchain}}-${{ matrix.config.arch}} - strategy: - fail-fast: false - matrix: - config: - - {toolchain: Visual Studio 16 2019, arch: Win32, server: 2019} - - {toolchain: Visual Studio 16 2019, arch: x64, server: 2019} - - {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022} - - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022} - steps: - - uses: actions/checkout@v2 - - name: Envinfo - run: npx envinfo - - name: Build - shell: cmd - run: | - mkdir -p build - cd build - cmake .. -DBUILD_TESTING=ON -G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }} - cmake --build . - - name: platform_output - shell: cmd - run: | - build\\Debug\\uv_run_tests.exe platform_output - - name: platform_output_a - shell: cmd - run: | - build\\Debug\\uv_run_tests_a.exe platform_output - - name: Test - shell: cmd - run: | - cd build - ctest -C Debug -V - build-android: runs-on: ubuntu-latest container: reactnativecommunity/react-native-android:2020-5-20 diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml new file mode 100644 index 00000000000..9e2a535ecec --- /dev/null +++ b/.github/workflows/CI-win.yml @@ -0,0 +1,51 @@ +name: CI-win + +on: + pull_request: + paths: + - '**' + - '!docs/**' + - '!src/win/**' + - '!.**' + - '.github/workflows/CI-win.yml' + push: + branches: + - v[0-9].* + - master + +jobs: + build-windows: + runs-on: windows-${{ matrix.config.server }} + name: build-${{ matrix.config.toolchain}}-${{ matrix.config.arch}} + strategy: + fail-fast: false + matrix: + config: + - {toolchain: Visual Studio 16 2019, arch: Win32, server: 2019} + - {toolchain: Visual Studio 16 2019, arch: x64, server: 2019} + - {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022} + - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022} + steps: + - uses: actions/checkout@v2 + - name: Envinfo + run: npx envinfo + - name: Build + shell: cmd + run: | + mkdir -p build + cd build + cmake .. -DBUILD_TESTING=ON -G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }} + cmake --build . + - name: platform_output + shell: cmd + run: | + build\\Debug\\uv_run_tests.exe platform_output + - name: platform_output_a + shell: cmd + run: | + build\\Debug\\uv_run_tests_a.exe platform_output + - name: Test + shell: cmd + run: | + cd build + ctest -C Debug -V diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index c0a54b28235..3c39117faa3 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -1,6 +1,16 @@ name: Sanitizer checks -on: [push, pull_request] +on: + pull_request: + paths: + - '**' + - '!docs/**' + - '!.**' + - '.github/workflows/sanitizer.yml' + push: + branches: + - v[0-9].* + - master jobs: sanitizers: @@ -12,15 +22,20 @@ jobs: sudo apt-get install ninja-build - name: Envinfo run: npx envinfo - - name: TSAN + - name: TSAN Build run: | mkdir build-tsan (cd build-tsan && cmake .. -G Ninja -DBUILD_TESTING=ON -DTSAN=ON -DCMAKE_BUILD_TYPE=Release) cmake --build build-tsan - ./build-tsan/uv_run_tests_a || true # currently permit failures - - name: ASAN + - name: TSAN Test + continue-on-error: true # currently permit failures + run: | + ./build-tsan/uv_run_tests_a + - name: ASAN Build run: | mkdir build-asan (cd build-asan && cmake .. -G Ninja -DBUILD_TESTING=ON -DASAN=ON -DCMAKE_BUILD_TYPE=Debug) cmake --build build-asan + - name: ASAN Test + run: | ./build-asan/uv_run_tests_a From e64ec13c1352dacf9fc76769ab0a9b2c51b35582 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 21 Mar 2022 20:32:22 -0400 Subject: [PATCH 171/713] build: add iOS to macos CI (#3564) Smokescreen for build errors on iOS, currently ignoring failures due to aforementioned build errors. --- .github/workflows/CI-unix.yml | 42 +++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 132c7ed37b6..aa2589c7121 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -21,12 +21,15 @@ jobs: - uses: actions/checkout@v2 - name: Envinfo run: npx envinfo - - name: Build android arm64 + - name: Configure android arm64 # see build options you can use in https://developer.android.com/ndk/guides/cmake run: | - mkdir build && cd build + mkdir build + cd build $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/20.0.5594570/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-24 .. - $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake --build . + - name: Build android arm64 + run: | + $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake --build build build-macos: runs-on: macos-10.15 @@ -37,11 +40,14 @@ jobs: - name: Setup run: | brew install ninja - - name: Build + - name: Configure run: | mkdir build - cd build && cmake .. -DBUILD_TESTING=ON -G Ninja - cmake --build . + cd build + cmake .. -DBUILD_TESTING=ON -G Ninja + - name: Build + run: | + cmake --build build ls -lh - name: platform_output run: | @@ -53,6 +59,21 @@ jobs: run: | cd build && ctest -V + build-ios: + runs-on: macos-10.15 + steps: + - uses: actions/checkout@v2 + - name: Configure + run: | + mkdir build-ios + cd build-ios + cmake .. -GXcode -DCMAKE_SYSTEM_NAME:STRING=iOS -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED:BOOL=NO -DCMAKE_CONFIGURATION_TYPES:STRING=Release + - name: Build + continue-on-error: true # XXX: allow failure + run: | + cmake --build build-ios + ls -lh + build-cross-qemu: runs-on: ubuntu-latest name: build-cross-qemu-${{ matrix.config.target }} @@ -94,11 +115,14 @@ jobs: run: | sudo apt update sudo apt install ${{ matrix.config.toolchain }} -y - - name: Build + - name: Configure with ${{ matrix.config.cc }} run: | mkdir build - cd build && cmake .. -DBUILD_TESTING=ON -DQEMU=ON -DCMAKE_C_COMPILER=${{ matrix.config.cc }} - cmake --build . + cd build + cmake .. -DBUILD_TESTING=ON -DQEMU=ON -DCMAKE_C_COMPILER=${{ matrix.config.cc }} + - name: Build + run: | + cmake --build build ls -lh - name: Test run: | From abf201a894f406b0f516d151347825e6231f9f0d Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 22 Mar 2022 15:09:06 -0400 Subject: [PATCH 172/713] build: re-enable CI for windows changes (#3572) I got the conditional reversed in https://github.com/libuv/libuv/pull/3564 --- .github/workflows/CI-win.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index 9e2a535ecec..9b9aa7721eb 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -5,7 +5,7 @@ on: paths: - '**' - '!docs/**' - - '!src/win/**' + - '!src/unix/**' - '!.**' - '.github/workflows/CI-win.yml' push: From 264f16dcf6a7ed57340a9cc19dc9d5c22aa2572e Mon Sep 17 00:00:00 2001 From: "Denny C. Dai" Date: Tue, 22 Mar 2022 12:11:26 -0700 Subject: [PATCH 173/713] process,iOS: fix build breakage in process.c (#3563) Remove the `TARGET_OS_IPHONE` ifdef to include posix spawn headers for iOS build. Previously https://github.com/libuv/libuv/pull/3257 introduced posix spawn with \_\_APPLE\_\_ platform only, which resulted in a number of spawn related definitions not found for iOS (such as `uv__posix_spawn_fncs_tag`). Co-authored-by: Jameson Nash --- .github/workflows/CI-unix.yml | 6 +++--- src/unix/process.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index aa2589c7121..506c00bcf75 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -30,6 +30,7 @@ jobs: - name: Build android arm64 run: | $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake --build build + ls -lh build build-macos: runs-on: macos-10.15 @@ -69,10 +70,9 @@ jobs: cd build-ios cmake .. -GXcode -DCMAKE_SYSTEM_NAME:STRING=iOS -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED:BOOL=NO -DCMAKE_CONFIGURATION_TYPES:STRING=Release - name: Build - continue-on-error: true # XXX: allow failure run: | cmake --build build-ios - ls -lh + ls -lh build-ios build-cross-qemu: runs-on: ubuntu-latest @@ -123,7 +123,7 @@ jobs: - name: Build run: | cmake --build build - ls -lh + ls -lh build - name: Test run: | ${{ matrix.config.qemu }} build/uv_run_tests_a diff --git a/src/unix/process.c b/src/unix/process.c index c8816b85b7e..16ba6c87cf6 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -35,7 +35,7 @@ #include #include -#if defined(__APPLE__) && !TARGET_OS_IPHONE +#if defined(__APPLE__) # include # include # include From 9f2ed35da0c2c87781f141cbe572e98e3bb4ef7b Mon Sep 17 00:00:00 2001 From: V-for-Vasili Date: Tue, 22 Mar 2022 15:13:10 -0400 Subject: [PATCH 174/713] test: remove unused declarations in tcp_rst test (#3574) Refs: https://github.com/libuv/libuv/pull/3482 --- test/test-tcp-rst.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/test-tcp-rst.c b/test/test-tcp-rst.c index 04468dc06e3..ed48e741908 100644 --- a/test/test-tcp-rst.c +++ b/test/test-tcp-rst.c @@ -24,11 +24,9 @@ static uv_tcp_t tcp; static uv_connect_t connect_req; -static uv_shutdown_t shutdown_req; static uv_buf_t qbuf; static int called_alloc_cb; static int called_connect_cb; -static int called_shutdown_cb; static int called_close_cb; @@ -70,7 +68,6 @@ static void connect_cb(uv_connect_t *req, int status) { ASSERT_EQ(qbuf.len, uv_try_write((uv_stream_t*) &tcp, &qbuf, 1)); called_connect_cb++; - ASSERT_EQ(called_shutdown_cb, 0); } @@ -100,7 +97,6 @@ TEST_IMPL(tcp_rst) { ASSERT_EQ(called_alloc_cb, 1); ASSERT_EQ(called_connect_cb, 1); - ASSERT_EQ(called_shutdown_cb, 0); ASSERT_EQ(called_close_cb, 1); MAKE_VALGRIND_HAPPY(); From 2a31fe8552acdfd920358373d3a5b406aae8bf34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilherme=20=C3=8Dscaro?= Date: Tue, 22 Mar 2022 19:15:00 +0000 Subject: [PATCH 175/713] core: add thread-safe strtok implementation (#3553) This commit adds the support for a custom strtok implementation, which is reentrant. On some systems strtok_r or strstep is available for that purpose; however, since these are an extension, it is difficult to control if it will be available on every supported system. --- CMakeLists.txt | 2 ++ Makefile.am | 5 ++- src/strtok.c | 52 +++++++++++++++++++++++++++ src/strtok.h | 27 ++++++++++++++ src/unix/core.c | 6 ++-- test/test-list.h | 2 ++ test/test-strtok.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 src/strtok.c create mode 100644 src/strtok.h create mode 100644 test/test-strtok.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c50cc560fc..ee06d4df7af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,7 @@ set(uv_sources src/inet.c src/random.c src/strscpy.c + src/strtok.c src/threadpool.c src/timer.c src/uv-common.c @@ -562,6 +563,7 @@ if(LIBUV_BUILD_TESTS) test/test-spawn.c test/test-stdio-over-pipes.c test/test-strscpy.c + test/test-strtok.c test/test-tcp-alloc-cb-fail.c test/test-tcp-bind-error.c test/test-tcp-bind6-error.c diff --git a/Makefile.am b/Makefile.am index 32fccede981..a377759f9ea 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,7 +43,9 @@ libuv_la_SOURCES = src/fs-poll.c \ src/uv-data-getter-setters.c \ src/uv-common.c \ src/uv-common.h \ - src/version.c + src/version.c \ + src/strtok.c \ + src/strtok.h if SUNOS # Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers @@ -250,6 +252,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-spawn.c \ test/test-stdio-over-pipes.c \ test/test-strscpy.c \ + test/test-strtok.c \ test/test-tcp-alloc-cb-fail.c \ test/test-tcp-bind-error.c \ test/test-tcp-bind6-error.c \ diff --git a/src/strtok.c b/src/strtok.c new file mode 100644 index 00000000000..45ddea50b1a --- /dev/null +++ b/src/strtok.c @@ -0,0 +1,52 @@ +/* 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 +#include "strtok.h" + +char* uv__strtok(char* str, const char* sep, char** itr) { + const char* sep_itr; + char* tmp; + char* start; + + if (str == NULL) + start = tmp = *itr; + else + start = tmp = str; + + if (tmp == NULL) + return NULL; + + while (*tmp != '\0') { + sep_itr = sep; + while (*sep_itr != '\0') { + if (*tmp == *sep_itr) { + *itr = tmp + 1; + *tmp = '\0'; + return start; + } + sep_itr++; + } + tmp++; + } + *itr = NULL; + return start; +} diff --git a/src/strtok.h b/src/strtok.h new file mode 100644 index 00000000000..3799ff55436 --- /dev/null +++ b/src/strtok.h @@ -0,0 +1,27 @@ +/* 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. + */ + +#ifndef UV_STRTOK_H_ +#define UV_STRTOK_H_ + +char* uv__strtok(char* str, const char* sep, char** itr); + +#endif /* UV_STRTOK_H_ */ diff --git a/src/unix/core.c b/src/unix/core.c index aade3b3760a..edd457a1da1 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -20,6 +20,7 @@ #include "uv.h" #include "internal.h" +#include "strtok.h" #include /* NULL */ #include /* printf */ @@ -1546,6 +1547,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) { char* cloned_path; char* path_env; char* token; + char* itr; if (buf == NULL || buflen == NULL || *buflen == 0) return UV_EINVAL; @@ -1587,7 +1589,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) { if (cloned_path == NULL) return UV_ENOMEM; - token = strtok(cloned_path, ":"); + token = uv__strtok(cloned_path, ":", &itr); while (token != NULL) { snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, prog); if (realpath(trypath, abspath) == abspath) { @@ -1606,7 +1608,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) { return 0; } } - token = strtok(NULL, ":"); + token = uv__strtok(NULL, ":", &itr); } uv__free(cloned_path); diff --git a/test/test-list.h b/test/test-list.h index 3d9bc397c36..44751658fa5 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -423,6 +423,7 @@ TEST_DECLARE (fs_invalid_mkdir_name) #endif TEST_DECLARE (fs_get_system_error) TEST_DECLARE (strscpy) +TEST_DECLARE (strtok) TEST_DECLARE (threadpool_queue_work_simple) TEST_DECLARE (threadpool_queue_work_einval) TEST_DECLARE (threadpool_multiple_event_loops) @@ -1088,6 +1089,7 @@ TASK_LIST_START TEST_ENTRY (get_osfhandle_valid_handle) TEST_ENTRY (open_osfhandle_valid_handle) TEST_ENTRY (strscpy) + TEST_ENTRY (strtok) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) TEST_ENTRY_CUSTOM (threadpool_multiple_event_loops, 0, 0, 60000) diff --git a/test/test-strtok.c b/test/test-strtok.c new file mode 100644 index 00000000000..6c3d835914c --- /dev/null +++ b/test/test-strtok.c @@ -0,0 +1,90 @@ +/* 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 + +#include "../src/strtok.h" +#include "../src/strtok.c" + +struct strtok_test_case { + const char* str; + const char* sep; +}; + +const char* tokens[] = { + "abc", + NULL, + + "abc", + "abf", + NULL, + + "This", + "is.a", + "test", + "of", + "the", + "string", + "tokenizer", + "function.", + NULL, + + "Hello", + "This-is-a-nice", + "-string", + NULL +}; + +#define ASSERT_STRCMP(x, y) \ + ASSERT((x != NULL && y != NULL && strcmp(x, y) == 0) || (x == y && x == NULL)) + +TEST_IMPL(strtok) { + struct strtok_test_case tests[] = { + { "abc", "" }, + { "abc.abf", "." }, + { "This;is.a:test:of=the/string\\tokenizer-function.", "\\/:;=-" }, + { "Hello This-is-a-nice.-string", " ." }, + }; + size_t tokens_len = ARRAY_SIZE(tokens); + size_t tests_len = ARRAY_SIZE(tests); + size_t i; + size_t j; + char* itr; + char* tok_r; + char current_test[2048]; + + for (i = 0, j = 0; i < tests_len; i += 1) { + ASSERT(j < tokens_len); + snprintf(current_test, sizeof(current_test), "%s", tests[i].str); + tok_r = uv__strtok(current_test, tests[i].sep, &itr); + ASSERT_STRCMP(tok_r, tokens[j]); + j++; + while (tok_r) { + ASSERT(j < tokens_len); + tok_r = uv__strtok(NULL, tests[i].sep, &itr); + ASSERT_STRCMP(tok_r, tokens[j]); + j++; + } + } + return 0; +} From e6c67bf8039d4a5a3c9900af80e4b86cd6773ffe Mon Sep 17 00:00:00 2001 From: twosee Date: Fri, 1 Apr 2022 01:53:41 +0800 Subject: [PATCH 176/713] win: fix incompatible-types warning (#3581) Introduced by https://github.com/libuv/libuv/pull/3350. --- src/win/udp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/udp.c b/src/win/udp.c index 407aa6cbdb1..c99cb0fec02 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -1087,7 +1087,7 @@ int uv__udp_disconnect(uv_udp_t* handle) { memset(&addr, 0, sizeof(addr)); - err = connect(handle->socket, &addr, sizeof(addr)); + err = connect(handle->socket, (struct sockaddr*) &addr, sizeof(addr)); if (err) return uv_translate_sys_error(WSAGetLastError()); From 223e526f27910c69672a7690ef400975fd6fe1bf Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 6 Apr 2022 13:40:51 +0200 Subject: [PATCH 177/713] test: fix flaky file watcher test (#3591) FSEvents on macOS sometimes sends one change event, sometimes two. Make the test more lenient. Fixes #3589. --- test/test-fs-event.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index cbe63190780..0e17e7df982 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -334,19 +334,8 @@ static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename, uv_close((uv_handle_t*)handle, close_cb); } -static void timer_cb_close_handle(uv_timer_t* timer) { - uv_handle_t* handle; - - ASSERT_NOT_NULL(timer); - handle = timer->data; - - uv_close((uv_handle_t*)timer, NULL); - uv_close((uv_handle_t*)handle, close_cb); -} - static void fs_event_cb_file_current_dir(uv_fs_event_t* handle, const char* filename, int events, int status) { - ASSERT(fs_event_cb_called == 0); ++fs_event_cb_called; ASSERT(handle == &fs_event); @@ -358,13 +347,7 @@ static void fs_event_cb_file_current_dir(uv_fs_event_t* handle, ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0); #endif - /* Regression test for SunOS: touch should generate just one event. */ - { - static uv_timer_t timer; - uv_timer_init(handle->loop, &timer); - timer.data = handle; - uv_timer_start(&timer, timer_cb_close_handle, 250, 0); - } + uv_close((uv_handle_t*)handle, close_cb); } static void timer_cb_file(uv_timer_t* handle) { @@ -738,7 +721,8 @@ TEST_IMPL(fs_event_watch_file_current_dir) { uv_run(loop, UV_RUN_DEFAULT); ASSERT(timer_cb_touch_called == 1); - ASSERT(fs_event_cb_called == 1); + /* FSEvents on macOS sometimes sends one change event, sometimes two. */ + ASSERT_NE(0, fs_event_cb_called); ASSERT(close_cb_called == 1); /* Cleanup */ From 7233c428ec122c121b5d6dac1b339ebf54960e64 Mon Sep 17 00:00:00 2001 From: V-for-Vasili Date: Wed, 6 Apr 2022 08:07:05 -0400 Subject: [PATCH 178/713] build: fix AIX xlc autotools build (#3588) --- configure.ac | 4 +++- m4/libuv-check-flags.m4 | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a9012d40480..808c949d4a0 100644 --- a/configure.ac +++ b/configure.ac @@ -28,7 +28,9 @@ AM_PROG_CC_C_O CC_ATTRIBUTE_VISIBILITY([default], [ CC_FLAG_VISIBILITY([CFLAGS="${CFLAGS} -fvisibility=hidden"]) ]) -CC_CHECK_CFLAGS_APPEND([-fno-strict-aliasing]) +# Xlc has a flag "-f". Need to use CC_CHECK_FLAG_SUPPORTED_APPEND so +# we exclude -fno-strict-aliasing for xlc +CC_CHECK_FLAG_SUPPORTED_APPEND([-fno-strict-aliasing]) CC_CHECK_CFLAGS_APPEND([-g]) CC_CHECK_CFLAGS_APPEND([-std=gnu89]) CC_CHECK_CFLAGS_APPEND([-Wall]) diff --git a/m4/libuv-check-flags.m4 b/m4/libuv-check-flags.m4 index 9d0aad82a2d..2a01308d37a 100644 --- a/m4/libuv-check-flags.m4 +++ b/m4/libuv-check-flags.m4 @@ -104,6 +104,20 @@ AC_DEFUN([CC_CHECK_LDFLAGS], [ [$2], [$3]) ]) +dnl Check if flag is supported by both compiler and linker +dnl If so, append it to AM_CFLAGS +dnl CC_CHECK_FLAG_SUPPORTED_APPEND([FLAG]) + +AC_DEFUN([CC_CHECK_FLAG_SUPPORTED_APPEND], [ + CC_CHECK_CFLAGS([$1], + [CC_CHECK_LDFLAGS([$1], + [AM_CFLAGS="$AM_CFLAGS $1"; + DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; + AC_SUBST([AM_CFLAGS]) + ]) + ]) +]) + dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for dnl the current linker to avoid undefined references in a shared object. AC_DEFUN([CC_NOUNDEFINED], [ From 1fe609ea05ab37298fdfd34eed63647493002abb Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 6 Apr 2022 15:49:21 +0200 Subject: [PATCH 179/713] unix,win: fix UV_RUN_ONCE + uv_idle_stop loop hang (#3590) Wrong accounting of idle handles in uv_run() made it sleep when there was nothing left to do. Do a non-blocking poll for I/O instead. --- src/unix/core.c | 19 +++++++++---------- src/win/core.c | 8 +++++--- src/win/req-inl.h | 6 ++---- test/test-idle.c | 26 ++++++++++++++++++++++++++ test/test-list.h | 2 ++ 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index edd457a1da1..ae160f0c2f8 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -94,7 +94,7 @@ extern char** environ; # include #endif -static int uv__run_pending(uv_loop_t* loop); +static void uv__run_pending(uv_loop_t* loop); /* Verify that uv_buf_t is ABI-compatible with struct iovec. */ STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec)); @@ -372,7 +372,7 @@ int uv_loop_alive(const uv_loop_t* loop) { int uv_run(uv_loop_t* loop, uv_run_mode mode) { int timeout; int r; - int ran_pending; + int can_sleep; r = uv__loop_alive(loop); if (!r) @@ -381,12 +381,16 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { while (r != 0 && loop->stop_flag == 0) { uv__update_time(loop); uv__run_timers(loop); - ran_pending = uv__run_pending(loop); + + can_sleep = + QUEUE_EMPTY(&loop->pending_queue) && QUEUE_EMPTY(&loop->idle_handles); + + uv__run_pending(loop); uv__run_idle(loop); uv__run_prepare(loop); timeout = 0; - if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) + if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT) timeout = uv__backend_timeout(loop); uv__io_poll(loop, timeout); @@ -780,14 +784,11 @@ int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) { } -static int uv__run_pending(uv_loop_t* loop) { +static void uv__run_pending(uv_loop_t* loop) { QUEUE* q; QUEUE pq; uv__io_t* w; - if (QUEUE_EMPTY(&loop->pending_queue)) - return 0; - QUEUE_MOVE(&loop->pending_queue, &pq); while (!QUEUE_EMPTY(&pq)) { @@ -797,8 +798,6 @@ static int uv__run_pending(uv_loop_t* loop) { w = QUEUE_DATA(q, uv__io_t, pending_queue); w->cb(loop, w, POLLOUT); } - - return 1; } diff --git a/src/win/core.c b/src/win/core.c index c08dedc47c2..664ffac976c 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -592,7 +592,7 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { int uv_run(uv_loop_t *loop, uv_run_mode mode) { DWORD timeout; int r; - int ran_pending; + int can_sleep; r = uv__loop_alive(loop); if (!r) @@ -602,12 +602,14 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { uv_update_time(loop); uv__run_timers(loop); - ran_pending = uv__process_reqs(loop); + can_sleep = loop->pending_reqs_tail == NULL && loop->idle_handles == NULL; + + uv__process_reqs(loop); uv__idle_invoke(loop); uv__prepare_invoke(loop); timeout = 0; - if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) + if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT) timeout = uv_backend_timeout(loop); if (pGetQueuedCompletionStatusEx) diff --git a/src/win/req-inl.h b/src/win/req-inl.h index b7a345640a7..48760a06bbe 100644 --- a/src/win/req-inl.h +++ b/src/win/req-inl.h @@ -138,13 +138,13 @@ INLINE static void uv__insert_pending_req(uv_loop_t* loop, uv_req_t* req) { } while (0) -INLINE static int uv__process_reqs(uv_loop_t* loop) { +INLINE static void uv__process_reqs(uv_loop_t* loop) { uv_req_t* req; uv_req_t* first; uv_req_t* next; if (loop->pending_reqs_tail == NULL) - return 0; + return; first = loop->pending_reqs_tail->next_req; next = first; @@ -214,8 +214,6 @@ INLINE static int uv__process_reqs(uv_loop_t* loop) { assert(0); } } - - return 1; } #endif /* UV_WIN_REQ_INL_H_ */ diff --git a/test/test-idle.c b/test/test-idle.c index f49d1964827..427cf545beb 100644 --- a/test/test-idle.c +++ b/test/test-idle.c @@ -97,3 +97,29 @@ TEST_IMPL(idle_starvation) { MAKE_VALGRIND_HAPPY(); return 0; } + + +static void idle_stop(uv_idle_t* handle) { + uv_idle_stop(handle); +} + + +TEST_IMPL(idle_check) { + ASSERT_EQ(0, uv_idle_init(uv_default_loop(), &idle_handle)); + ASSERT_EQ(0, uv_idle_start(&idle_handle, idle_stop)); + + ASSERT_EQ(0, uv_check_init(uv_default_loop(), &check_handle)); + ASSERT_EQ(0, uv_check_start(&check_handle, check_cb)); + + ASSERT_EQ(1, uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_EQ(1, check_cb_called); + + ASSERT_EQ(0, close_cb_called); + uv_close((uv_handle_t*) &idle_handle, close_cb); + uv_close((uv_handle_t*) &check_handle, close_cb); + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_EQ(2, close_cb_called); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 44751658fa5..26c14b06802 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -225,6 +225,7 @@ TEST_DECLARE (timer_is_closing) TEST_DECLARE (timer_null_callback) TEST_DECLARE (timer_early_check) TEST_DECLARE (idle_starvation) +TEST_DECLARE (idle_check) TEST_DECLARE (loop_handles) TEST_DECLARE (get_loadavg) TEST_DECLARE (walk_handles) @@ -819,6 +820,7 @@ TASK_LIST_START TEST_ENTRY (timer_early_check) TEST_ENTRY (idle_starvation) + TEST_ENTRY (idle_check) TEST_ENTRY (ref) TEST_ENTRY (idle_ref) From 69ebb2d720ac476248460e1fb3f0f3d10af483dc Mon Sep 17 00:00:00 2001 From: twosee Date: Fri, 8 Apr 2022 09:44:45 +0800 Subject: [PATCH 180/713] win: fix unexpected ECONNRESET error on TCP socket (#3584) --- CMakeLists.txt | 1 + Makefile.am | 1 + src/win/tcp.c | 4 +- test/test-list.h | 2 + test/test-tcp-close-after-read-timeout.c | 183 +++++++++++++++++++++++ 5 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 test/test-tcp-close-after-read-timeout.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ee06d4df7af..3f712a80ac4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -568,6 +568,7 @@ if(LIBUV_BUILD_TESTS) test/test-tcp-bind-error.c test/test-tcp-bind6-error.c test/test-tcp-close-accept.c + test/test-tcp-close-after-read-timeout.c test/test-tcp-close-while-connecting.c test/test-tcp-close.c test/test-tcp-close-reset.c diff --git a/Makefile.am b/Makefile.am index a377759f9ea..a7ee5d469ea 100644 --- a/Makefile.am +++ b/Makefile.am @@ -258,6 +258,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-tcp-bind6-error.c \ test/test-tcp-close-accept.c \ test/test-tcp-close-while-connecting.c \ + test/test-tcp-close-after-read-timeout.c \ test/test-tcp-close.c \ test/test-tcp-close-reset.c \ test/test-tcp-create-socket-early.c \ diff --git a/src/win/tcp.c b/src/win/tcp.c index 1d9085c9e42..08083df350c 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -1411,7 +1411,7 @@ static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) { int writing; socket = tcp->socket; - reading = tcp->flags & UV_HANDLE_READING; + reading = tcp->flags & UV_HANDLE_READ_PENDING; writing = tcp->stream.conn.write_reqs_pending > 0; if (!reading && !writing) return; @@ -1458,10 +1458,10 @@ static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) { void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { if (tcp->flags & UV_HANDLE_CONNECTION) { - uv__tcp_try_cancel_reqs(tcp); if (tcp->flags & UV_HANDLE_READING) { uv_read_stop((uv_stream_t*) tcp); } + uv__tcp_try_cancel_reqs(tcp); } else { if (tcp->tcp.serv.accept_reqs != NULL) { /* First close the incoming sockets to cancel the accept operations before diff --git a/test/test-list.h b/test/test-list.h index 26c14b06802..833047e8830 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -129,6 +129,7 @@ TEST_DECLARE (tcp_connect_timeout) TEST_DECLARE (tcp_local_connect_timeout) TEST_DECLARE (tcp6_local_connect_timeout) TEST_DECLARE (tcp_close_while_connecting) +TEST_DECLARE (tcp_close_after_read_timeout) TEST_DECLARE (tcp_close) TEST_DECLARE (tcp_close_reset_accepted) TEST_DECLARE (tcp_close_reset_accepted_after_shutdown) @@ -704,6 +705,7 @@ TASK_LIST_START TEST_ENTRY (tcp_local_connect_timeout) TEST_ENTRY (tcp6_local_connect_timeout) TEST_ENTRY (tcp_close_while_connecting) + TEST_ENTRY (tcp_close_after_read_timeout) TEST_ENTRY (tcp_close) TEST_ENTRY (tcp_close_reset_accepted) TEST_ENTRY (tcp_close_reset_accepted_after_shutdown) diff --git a/test/test-tcp-close-after-read-timeout.c b/test/test-tcp-close-after-read-timeout.c new file mode 100644 index 00000000000..493492dba6a --- /dev/null +++ b/test/test-tcp-close-after-read-timeout.c @@ -0,0 +1,183 @@ +/* Copyright libuv project and contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_tcp_t client; +static uv_tcp_t connection; +static uv_connect_t connect_req; +static uv_timer_t timer; + +static int read_cb_called; +static int on_close_called; + +static void on_connection(uv_stream_t* server, int status); + +static void on_client_connect(uv_connect_t* req, int status); +static void on_client_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf); +static void on_client_read(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf); +static void on_client_timeout(uv_timer_t* handle); + +static void on_close(uv_handle_t* handle); + + +static void on_client_connect(uv_connect_t* conn_req, int status) { + int r; + + r = uv_read_start((uv_stream_t*) &client, on_client_alloc, on_client_read); + ASSERT_EQ(r, 0); + + r = uv_timer_start(&timer, on_client_timeout, 1000, 0); + ASSERT_EQ(r, 0); +} + + +static void on_client_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[8]; + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void on_client_read(uv_stream_t* stream, ssize_t nread, + const uv_buf_t* buf) { + ASSERT_LT(nread, 0); + read_cb_called++; +} + + +static void on_client_timeout(uv_timer_t* handle) { + ASSERT_EQ(handle, &timer); + ASSERT_EQ(read_cb_called, 0); + uv_read_stop((uv_stream_t*) &client); + uv_close((uv_handle_t*) &client, on_close); + uv_close((uv_handle_t*) &timer, on_close); +} + + +static void on_connection_alloc(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[8]; + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void on_connection_read(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf) { + ASSERT_EQ(nread, UV_EOF); + read_cb_called++; + uv_close((uv_handle_t*) stream, on_close); +} + + +static void on_connection(uv_stream_t* server, int status) { + int r; + + ASSERT_EQ(status, 0); + ASSERT_EQ(uv_accept(server, (uv_stream_t*) &connection), 0); + + r = uv_read_start((uv_stream_t*) &connection, + on_connection_alloc, + on_connection_read); + ASSERT_EQ(r, 0); +} + + +static void on_close(uv_handle_t* handle) { + ASSERT(handle == (uv_handle_t*) &client || + handle == (uv_handle_t*) &connection || + handle == (uv_handle_t*) &timer); + on_close_called++; +} + + +static void start_server(uv_loop_t* loop, uv_tcp_t* handle) { + struct sockaddr_in addr; + int r; + + ASSERT_EQ(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr), 0); + + r = uv_tcp_init(loop, handle); + ASSERT_EQ(r, 0); + + r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0); + ASSERT_EQ(r, 0); + + r = uv_listen((uv_stream_t*) handle, 128, on_connection); + ASSERT_EQ(r, 0); + + uv_unref((uv_handle_t*) handle); +} + + +/* Check that pending write requests have their callbacks + * invoked when the handle is closed. + */ +TEST_IMPL(tcp_close_after_read_timeout) { + struct sockaddr_in addr; + uv_tcp_t tcp_server; + uv_loop_t* loop; + int r; + + ASSERT_EQ(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr), 0); + + loop = uv_default_loop(); + + /* We can't use the echo server, it doesn't handle ECONNRESET. */ + start_server(loop, &tcp_server); + + r = uv_tcp_init(loop, &client); + ASSERT_EQ(r, 0); + + r = uv_tcp_connect(&connect_req, + &client, + (const struct sockaddr*) &addr, + on_client_connect); + ASSERT_EQ(r, 0); + + r = uv_tcp_init(loop, &connection); + ASSERT_EQ(r, 0); + + r = uv_timer_init(loop, &timer); + ASSERT_EQ(r, 0); + + ASSERT_EQ(read_cb_called, 0); + ASSERT_EQ(on_close_called, 0); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT_EQ(r, 0); + + ASSERT_EQ(read_cb_called, 1); + ASSERT_EQ(on_close_called, 3); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From a78671543b671d93fa349dcaa3f87f8ed4bcd116 Mon Sep 17 00:00:00 2001 From: Jiawen Geng Date: Mon, 11 Apr 2022 09:52:28 +0800 Subject: [PATCH 181/713] doc: make sample cross-platform build (#3592) Co-authored-by: Ben Noordhuis --- .github/workflows/CI-sample.yml | 32 +++++++++++++++++++++ docs/code/CMakeLists.txt | 51 +++++++++++++++++++++++++++++++++ docs/code/cgi/main.c | 4 +-- docs/code/interfaces/main.c | 14 ++++----- docs/code/thread-create/main.c | 5 ++-- docs/code/udp-dhcp/main.c | 3 +- docs/code/uvcat/main.c | 1 - docs/code/uvtee/main.c | 1 - 8 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/CI-sample.yml create mode 100644 docs/code/CMakeLists.txt diff --git a/.github/workflows/CI-sample.yml b/.github/workflows/CI-sample.yml new file mode 100644 index 00000000000..409ef56877e --- /dev/null +++ b/.github/workflows/CI-sample.yml @@ -0,0 +1,32 @@ +name: ci-sample + +on: + pull_request: + paths: + - '**' + - '!docs/**' + - '!.**' + - '.github/workflows/CI-sample.yml' + push: + branches: + - v[0-9].* + - master + +jobs: + build: + strategy: + fail-fast: false + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] + runs-on: ${{matrix.os}} + steps: + - uses: actions/checkout@v2 + - name: setup + run: cmake -E make_directory ${{runner.workspace}}/libuv/docs/code/build + - name: configure + # you may like use Ninja on unix-like OS, but for windows, the only easy way is to use Visual Studio if you want Ninja + run: cmake .. + working-directory: ${{runner.workspace}}/libuv/docs/code/build + - name: build + run: cmake --build . + working-directory: ${{runner.workspace}}/libuv/docs/code/build diff --git a/docs/code/CMakeLists.txt b/docs/code/CMakeLists.txt new file mode 100644 index 00000000000..3d01991b268 --- /dev/null +++ b/docs/code/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required(VERSION 3.5) + +project(libuv_sample) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +add_subdirectory("../../" build) + +set(SIMPLE_SAMPLES + cgi + helloworld + dns + detach + default-loop + idle-basic + idle-compute + interfaces + locks + onchange + pipe-echo-server + ref-timer + spawn + tcp-echo-server + thread-create + udp-dhcp + uvcat + uvstop + uvtee + ) +IF (NOT WIN32) + list(APPEND SIMPLE_SAMPLES + signal + progress + queue-cancel + queue-work + tty + tty-gravity + ) +ENDIF() + +foreach (X IN LISTS SIMPLE_SAMPLES) + add_executable(${X} ${X}/main.c) + target_link_libraries(${X} uv_a) +endforeach () + + +FIND_PACKAGE(CURL) +IF(CURL_FOUND) + add_executable(uvwget uvwget/main.c) + target_link_libraries(uvwget uv_a ${CURL_LIBRARIES}) +ENDIF(CURL_FOUND) diff --git a/docs/code/cgi/main.c b/docs/code/cgi/main.c index d2e34265a0a..97422110d35 100644 --- a/docs/code/cgi/main.c +++ b/docs/code/cgi/main.c @@ -15,8 +15,8 @@ void cleanup_handles(uv_process_t *req, int64_t exit_status, int term_signal) { } void invoke_cgi_script(uv_tcp_t *client) { - size_t size = 500; - char path[size]; + char path[500]; + size_t size = sizeof(path); uv_exepath(path, &size); strcpy(path + (strlen(path) - strlen("cgi")), "tick"); diff --git a/docs/code/interfaces/main.c b/docs/code/interfaces/main.c index cac12c26617..744a47f26a4 100644 --- a/docs/code/interfaces/main.c +++ b/docs/code/interfaces/main.c @@ -11,17 +11,17 @@ int main() { printf("Number of interfaces: %d\n", count); while (i--) { - uv_interface_address_t interface = info[i]; + uv_interface_address_t interface_a = info[i]; - printf("Name: %s\n", interface.name); - printf("Internal? %s\n", interface.is_internal ? "Yes" : "No"); + printf("Name: %s\n", interface_a.name); + printf("Internal? %s\n", interface_a.is_internal ? "Yes" : "No"); - if (interface.address.address4.sin_family == AF_INET) { - uv_ip4_name(&interface.address.address4, buf, sizeof(buf)); + if (interface_a.address.address4.sin_family == AF_INET) { + uv_ip4_name(&interface_a.address.address4, buf, sizeof(buf)); printf("IPv4 address: %s\n", buf); } - else if (interface.address.address4.sin_family == AF_INET6) { - uv_ip6_name(&interface.address.address6, buf, sizeof(buf)); + else if (interface_a.address.address4.sin_family == AF_INET6) { + uv_ip6_name(&interface_a.address.address6, buf, sizeof(buf)); printf("IPv6 address: %s\n", buf); } diff --git a/docs/code/thread-create/main.c b/docs/code/thread-create/main.c index 70224c1e202..7e345ef0836 100644 --- a/docs/code/thread-create/main.c +++ b/docs/code/thread-create/main.c @@ -1,5 +1,4 @@ #include -#include #include @@ -7,7 +6,7 @@ void hare(void *arg) { int tracklen = *((int *) arg); while (tracklen) { tracklen--; - sleep(1); + uv_sleep(1000); fprintf(stderr, "Hare ran another step\n"); } fprintf(stderr, "Hare done running!\n"); @@ -18,7 +17,7 @@ void tortoise(void *arg) { while (tracklen) { tracklen--; fprintf(stderr, "Tortoise ran another step\n"); - sleep(3); + uv_sleep(3000); } fprintf(stderr, "Tortoise done running!\n"); } diff --git a/docs/code/udp-dhcp/main.c b/docs/code/udp-dhcp/main.c index fc2ca0c8a8d..4dc28390308 100644 --- a/docs/code/udp-dhcp/main.c +++ b/docs/code/udp-dhcp/main.c @@ -53,7 +53,8 @@ uv_buf_t make_discover_msg() { // HOPS buffer.base[3] = 0x0; // XID 4 bytes - buffer.base[4] = (unsigned int) random(); + if (uv_random(NULL, NULL, &buffer.base[4], 4, 0, NULL)) + abort(); // SECS buffer.base[8] = 0x0; // FLAGS diff --git a/docs/code/uvcat/main.c b/docs/code/uvcat/main.c index b03b09449ac..01923f2ae26 100644 --- a/docs/code/uvcat/main.c +++ b/docs/code/uvcat/main.c @@ -1,7 +1,6 @@ #include #include #include -#include #include void on_read(uv_fs_t *req); diff --git a/docs/code/uvtee/main.c b/docs/code/uvtee/main.c index 6216c2eb4df..be307b9a67f 100644 --- a/docs/code/uvtee/main.c +++ b/docs/code/uvtee/main.c @@ -1,6 +1,5 @@ #include #include -#include #include #include From b51e940dfa3be76e7b88d877c6cb4c1cfd46e65f Mon Sep 17 00:00:00 2001 From: Hannah Shi Date: Mon, 11 Apr 2022 08:22:37 -0700 Subject: [PATCH 182/713] test: separate some static variables by test cases (#3567) --- test/test-getsockname.c | 17 +++++++++-------- test/test-timer.c | 27 +++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/test/test-getsockname.c b/test/test-getsockname.c index 7c77fcb0a9b..6e0f8c18982 100644 --- a/test/test-getsockname.c +++ b/test/test-getsockname.c @@ -30,8 +30,9 @@ static const int server_port = TEST_PORT; /* Will be updated right after making the uv_connect_call */ static int connect_port = -1; -static int getsocknamecount = 0; +static int getsocknamecount_tcp = 0; static int getpeernamecount = 0; +static int getsocknamecount_udp = 0; static uv_loop_t* loop; static uv_tcp_t tcp; @@ -131,7 +132,7 @@ static void on_connection(uv_stream_t* server, int status) { r = uv_tcp_getsockname(handle, &sockname, &namelen); ASSERT(r == 0); check_sockname(&sockname, "127.0.0.1", server_port, "accepted socket"); - getsocknamecount++; + getsocknamecount_tcp++; namelen = sizeof peername; r = uv_tcp_getpeername(handle, &peername, &namelen); @@ -154,7 +155,7 @@ static void on_connect(uv_connect_t* req, int status) { r = uv_tcp_getsockname((uv_tcp_t*) req->handle, &sockname, &namelen); ASSERT(r == 0); check_sockname(&sockname, "127.0.0.1", 0, "connected socket"); - getsocknamecount++; + getsocknamecount_tcp++; namelen = sizeof peername; r = uv_tcp_getpeername((uv_tcp_t*) req->handle, &peername, &namelen); @@ -197,7 +198,7 @@ static int tcp_listener(void) { r = uv_tcp_getsockname(&tcpServer, &sockname, &namelen); ASSERT(r == 0); check_sockname(&sockname, "0.0.0.0", server_port, "server socket"); - getsocknamecount++; + getsocknamecount_tcp++; namelen = sizeof sockname; r = uv_tcp_getpeername(&tcpServer, &peername, &namelen); @@ -256,7 +257,7 @@ static void udp_recv(uv_udp_t* handle, r = uv_udp_getsockname(&udp, &sockname, &namelen); ASSERT(r == 0); check_sockname(&sockname, "0.0.0.0", 0, "udp receiving socket"); - getsocknamecount++; + getsocknamecount_udp++; uv_close((uv_handle_t*) &udp, NULL); uv_close((uv_handle_t*) handle, NULL); @@ -293,7 +294,7 @@ static int udp_listener(void) { r = uv_udp_getsockname(&udpServer, &sockname, &namelen); ASSERT(r == 0); check_sockname(&sockname, "0.0.0.0", server_port, "udp listener socket"); - getsocknamecount++; + getsocknamecount_udp++; r = uv_udp_recv_start(&udpServer, alloc, udp_recv); ASSERT(r == 0); @@ -333,7 +334,7 @@ TEST_IMPL(getsockname_tcp) { uv_run(loop, UV_RUN_DEFAULT); - ASSERT(getsocknamecount == 3); + ASSERT(getsocknamecount_tcp == 3); ASSERT(getpeernamecount == 3); MAKE_VALGRIND_HAPPY(); @@ -351,7 +352,7 @@ TEST_IMPL(getsockname_udp) { uv_run(loop, UV_RUN_DEFAULT); - ASSERT(getsocknamecount == 2); + ASSERT(getsocknamecount_udp == 2); ASSERT(udp.send_queue_size == 0); ASSERT(udpServer.send_queue_size == 0); diff --git a/test/test-timer.c b/test/test-timer.c index d0921a96730..a9fa534f5ad 100644 --- a/test/test-timer.c +++ b/test/test-timer.c @@ -25,6 +25,8 @@ static int once_cb_called = 0; static int once_close_cb_called = 0; +static int twice_cb_called = 0; +static int twice_close_cb_called = 0; static int repeat_cb_called = 0; static int repeat_close_cb_called = 0; static int order_cb_called = 0; @@ -58,6 +60,27 @@ static void once_cb(uv_timer_t* handle) { uv_update_time(uv_default_loop()); } +static void twice_close_cb(uv_handle_t* handle) { + printf("TWICE_CLOSE_CB\n"); + + ASSERT_NOT_NULL(handle); + ASSERT(0 == uv_is_active(handle)); + + twice_close_cb_called++; +} + +static void twice_cb(uv_timer_t* handle) { + printf("TWICE_CB %d\n", twice_cb_called); + + ASSERT_NOT_NULL(handle); + ASSERT(0 == uv_is_active((uv_handle_t*) handle)); + + twice_cb_called++; + + uv_close((uv_handle_t*)handle, twice_close_cb); +} + + static void repeat_close_cb(uv_handle_t* handle) { printf("REPEAT_CLOSE_CB\n"); @@ -144,12 +167,12 @@ TEST_IMPL(timer_start_twice) { ASSERT(r == 0); r = uv_timer_start(&once, never_cb, 86400 * 1000, 0); ASSERT(r == 0); - r = uv_timer_start(&once, once_cb, 10, 0); + r = uv_timer_start(&once, twice_cb, 10, 0); ASSERT(r == 0); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); - ASSERT(once_cb_called == 1); + ASSERT(twice_cb_called == 1); MAKE_VALGRIND_HAPPY(); return 0; From 612c28b89fd39a7348829e0af91de2484406b651 Mon Sep 17 00:00:00 2001 From: Andy Fiddaman Date: Mon, 11 Apr 2022 16:25:59 +0100 Subject: [PATCH 183/713] sunos: fs-event callback can be called after uv_close() (#3542) On illumos and Solaris, fs events are implemented with PORT_SOURCE_FILE type event ports. These are one-shot so need re-arming each time they fire. Once they are armed and an event occurs, the kernel removes them from the current cache list and puts them on an event queue to be read by the application. There's a window in closing one of these ports when it could have triggered and be pending delivery. In that case, the attempt to disarm (dissociate) the event will fail with ENOENT but libuv still goes ahead and closes down the handle. In particular, the close callback (uv_close() argument) will be called but then the event will subsequently be delivered if the loop is still active; this should not happen. --- src/unix/core.c | 9 +++++++++ src/unix/sunos.c | 36 +++++++++++++++++++++++++++++------- test/test-fs-event.c | 38 ++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 4 files changed, 78 insertions(+), 7 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index ae160f0c2f8..d5758de493b 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -160,6 +160,15 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { case UV_FS_EVENT: uv__fs_event_close((uv_fs_event_t*)handle); +#if defined(__sun) + /* + * On Solaris and illumos, we will not be able to dissociate the watcher + * for an event which is pending delivery, so we cannot always call + * uv__make_close_pending() straight away. The backend will call the + * function once the event has cleared. + */ + return; +#endif break; case UV_POLL: diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 2bf297e5d96..7835bed75e0 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -154,7 +154,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { sigset_t set; uint64_t base; uint64_t diff; - uint64_t idle_poll; unsigned int nfds; unsigned int i; int saved_errno; @@ -424,7 +423,7 @@ void uv_loadavg(double avg[3]) { #if defined(PORT_SOURCE_FILE) static int uv__fs_event_rearm(uv_fs_event_t *handle) { - if (handle->fd == -1) + if (handle->fd == PORT_DELETED) return UV_EBADF; if (port_associate(handle->loop->fs_fd, @@ -475,6 +474,12 @@ static void uv__fs_event_read(uv_loop_t* loop, handle = (uv_fs_event_t*) pe.portev_user; assert((r == 0) && "unexpected port_get() error"); + if (uv__is_closing(handle)) { + uv__handle_stop(handle); + uv__make_close_pending((uv_handle_t*) handle); + break; + } + events = 0; if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED)) events |= UV_CHANGE; @@ -542,12 +547,14 @@ int uv_fs_event_start(uv_fs_event_t* handle, } -int uv_fs_event_stop(uv_fs_event_t* handle) { +static int uv__fs_event_stop(uv_fs_event_t* handle) { + int ret = 0; + if (!uv__is_active(handle)) return 0; - if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) { - port_dissociate(handle->loop->fs_fd, + if (handle->fd == PORT_LOADED) { + ret = port_dissociate(handle->loop->fs_fd, PORT_SOURCE_FILE, (uintptr_t) &handle->fo); } @@ -556,13 +563,28 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { uv__free(handle->path); handle->path = NULL; handle->fo.fo_name = NULL; - uv__handle_stop(handle); + if (ret == 0) + uv__handle_stop(handle); + + return ret; +} +int uv_fs_event_stop(uv_fs_event_t* handle) { + (void) uv__fs_event_stop(handle); return 0; } void uv__fs_event_close(uv_fs_event_t* handle) { - uv_fs_event_stop(handle); + /* + * If we were unable to dissociate the port here, then it is most likely + * that there is a pending queued event. When this happens, we don't want + * to complete the close as it will free the underlying memory for the + * handle, causing a use-after-free problem when the event is processed. + * We defer the final cleanup until after the event is consumed in + * uv__fs_event_read(). + */ + if (uv__fs_event_stop(handle) == 0) + uv__make_close_pending((uv_handle_t*) handle); } #else /* !defined(PORT_SOURCE_FILE) */ diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 0e17e7df982..a08bfb9100c 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -907,6 +907,44 @@ TEST_IMPL(fs_event_close_with_pending_event) { return 0; } +TEST_IMPL(fs_event_close_with_pending_delete_event) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + create_dir("watch_dir"); + create_file("watch_dir/file"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file", 0); + ASSERT(r == 0); + + /* Generate an fs event. */ + remove("watch_dir/file"); + + /* Allow time for the remove event to propagate to the pending list. */ + /* XXX - perhaps just for __sun? */ + uv_sleep(1100); + uv_update_time(loop); + + uv_close((uv_handle_t*)&fs_event, close_cb); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + /* Clean up */ + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + TEST_IMPL(fs_event_close_in_callback) { #if defined(NO_FS_EVENTS) RETURN_SKIP(NO_FS_EVENTS); diff --git a/test/test-list.h b/test/test-list.h index 833047e8830..2f0237152b1 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -389,6 +389,7 @@ TEST_DECLARE (fs_event_no_callback_after_close) TEST_DECLARE (fs_event_no_callback_on_close) TEST_DECLARE (fs_event_immediate_close) TEST_DECLARE (fs_event_close_with_pending_event) +TEST_DECLARE (fs_event_close_with_pending_delete_event) TEST_DECLARE (fs_event_close_in_callback) TEST_DECLARE (fs_event_start_and_close) TEST_DECLARE (fs_event_error_reporting) @@ -1057,6 +1058,7 @@ TASK_LIST_START TEST_ENTRY (fs_event_no_callback_on_close) TEST_ENTRY (fs_event_immediate_close) TEST_ENTRY (fs_event_close_with_pending_event) + TEST_ENTRY (fs_event_close_with_pending_delete_event) TEST_ENTRY (fs_event_close_in_callback) TEST_ENTRY (fs_event_start_and_close) TEST_ENTRY_CUSTOM (fs_event_error_reporting, 0, 0, 60000) From 07c4cacb585acdf78b17e78d24723dadb9bc9a0e Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Wed, 8 Dec 2021 14:43:09 -0500 Subject: [PATCH 184/713] uv: re-register interest in a file after change (#3540 1/3) The file is implicitly unregistered when the change notification is sent, only one notification is sent per registration. So we need to re-register interest in a file after each change notification we receive. Co-authored-by: Gaby Baghdadi --- src/unix/os390.c | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index bf0448b5190..9a96bedd191 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -540,16 +540,11 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { } -int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, - const char* filename, unsigned int flags) { +static int os390_regfileint(uv_fs_event_t* handle, char* path) { uv__os390_epoll* ep; _RFIS reg_struct; - char* path; int rc; - if (uv__is_active(handle)) - return UV_EINVAL; - ep = handle->loop->ep; assert(ep->msg_queue != -1); @@ -558,19 +553,38 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, reg_struct.__rfis_type = 1; memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle)); + rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); + if (rc != 0) + return UV__ERR(errno); + + memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok, + sizeof(handle->rfis_rftok)); + + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, + const char* filename, unsigned int flags) { + char* path; + int rc; + + if (uv__is_active(handle)) + return UV_EINVAL; + path = uv__strdup(filename); if (path == NULL) return UV_ENOMEM; - rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); - if (rc != 0) - return UV__ERR(errno); + rc = os390_regfileint(handle, path); + if (rc != 0) { + uv__free(path); + return rc; + } uv__handle_start(handle); handle->path = path; handle->cb = cb; - memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok, - sizeof(handle->rfis_rftok)); return 0; } @@ -603,6 +617,10 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { abort(); uv__handle_stop(handle); + if (handle->path != NULL) { + uv__free(handle->path); + handle->path = NULL; + } return 0; } @@ -639,6 +657,14 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) { */ __a2e_l(msg.__rfim_utok, sizeof(msg.__rfim_utok)); handle = *(uv_fs_event_t**)(msg.__rfim_utok); + assert(handle != NULL); + /* The file is implicitly unregistered when the change notification is + * sent, only one notification is sent per registration. So we need to + * re-register interest in a file after each change notification we + * receive. + */ + if (handle->path != NULL) + os390_regfileint(handle, handle->path); handle->cb(handle, uv__basename_r(handle->path), events, 0); return 1; } From 571f8981921c307ff4995520c5f4171dcce34668 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Wed, 8 Dec 2021 15:27:42 -0500 Subject: [PATCH 185/713] uv: register UV_RENAME event for _RFIM_UNLINK (#3540 2/3) `rename()` can be used to rename a file path via _RFIM_UNLINK. So register it as a UV_RENAME event. Co-authored-by: Igor Todorovski --- src/unix/os390.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index 9a96bedd191..62b427080b8 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -646,7 +646,7 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) { events = 0; if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE) events = UV_CHANGE; - else if (msg.__rfim_event == _RFIM_RENAME) + else if (msg.__rfim_event == _RFIM_RENAME || msg.__rfim_event == _RFIM_UNLINK) events = UV_RENAME; else /* Some event that we are not interested in. */ From 6d9275e41222b8cdb2b032d6e220be0d18549c8b Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Wed, 8 Dec 2021 15:29:34 -0500 Subject: [PATCH 186/713] uv: register __rfim_event 156 as UV_RENAME (#3540 3/3) When the watched file is moved or removed, or an editor (e.g. vim) renames then creates the file, the __rfim_event 156 occurs. This is an undocumented event that should not happen, but register it as UV_RENAME for now since it is functionally equivalent. Co-authored-by: Gaby Baghdadi --- src/unix/os390.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/unix/os390.c b/src/unix/os390.c index 62b427080b8..6911ea7f415 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -648,6 +648,14 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) { events = UV_CHANGE; else if (msg.__rfim_event == _RFIM_RENAME || msg.__rfim_event == _RFIM_UNLINK) events = UV_RENAME; + else if (msg.__rfim_event == 156) + /* TODO(gabylb): zos - this event should not happen, need to investigate. + * + * This event seems to occur when the watched file is [re]moved, or an + * editor (like vim) renames then creates the file on save (for vim, that's + * when backupcopy=no|auto). + */ + events = UV_RENAME; else /* Some event that we are not interested in. */ return 0; From 6dfcdb987800da42fd22e22db9a8ab159482180e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 12 Apr 2022 12:18:01 +0200 Subject: [PATCH 187/713] doc: remove smartos from supported platforms (#3594) Commit 3af55129 from 2017 distinguished between smartos and other sunos spawn but [0] makes it clear ("a new chapter" - barf) that smartos is dead. Stop mentioning smartos and put everything under the sunos umbrella. [0] https://www.joyent.com/blog/a-new-chapter-begins-for-triton-and-smartos --- SUPPORTED_PLATFORMS.md | 1 - 1 file changed, 1 deletion(-) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 3a58f186399..0c1dd4e29fa 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -10,7 +10,6 @@ | 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 | | -| SmartOS | Tier 3 | >= 14.4 | | | Android | Tier 3 | NDK >= r15b | Android 7.0, `-DANDROID_PLATFORM=android-24` | | MinGW | Tier 3 | MinGW32 and MinGW-w64 | | | SunOS | Tier 3 | Solaris 121 and later | | From 7c9b3938df9cc1eb9e1efec249a171c31b1a9a3a Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 15 Apr 2022 14:10:27 -0400 Subject: [PATCH 188/713] macos: avoid posix_spawnp() cwd bug (#3597) macOS 10.15 has a bug where configuring the working directory with posix_spawn_file_actions_addchdir_np() makes posix_spawnp() fail with ENOENT even though the executable is spawned successfully. Co-authored-by: Ben Noordhuis --- src/unix/process.c | 18 ++++++++---------- test/test-list.h | 2 ++ test/test-spawn.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index 16ba6c87cf6..3a1b5b74753 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -671,27 +671,25 @@ static int uv__spawn_resolve_and_spawn(const uv_process_options_t* options, if (options->env != NULL) env = options->env; - /* If options->file contains a slash, posix_spawn/posix_spawnp behave - * the same, and don't involve PATH resolution at all. Otherwise, if - * options->file does not include a slash, but no custom environment is - * to be used, the environment used for path resolution as well for the - * child process is that of the parent process, so posix_spawnp is the - * way to go. */ - if (strchr(options->file, '/') != NULL || options->env == NULL) { + /* If options->file contains a slash, posix_spawn/posix_spawnp should behave + * the same, and do not involve PATH resolution at all. The libc + * `posix_spawnp` provided by Apple is buggy (since 10.15), so we now emulate it + * here, per https://github.com/libuv/libuv/pull/3583. */ + if (strchr(options->file, '/') != NULL) { do - err = posix_spawnp(pid, options->file, actions, attrs, options->args, env); + err = posix_spawn(pid, options->file, actions, attrs, options->args, env); while (err == EINTR); return err; } /* Look for the definition of PATH in the provided env */ - path = uv__spawn_find_path_in_env(options->env); + path = uv__spawn_find_path_in_env(env); /* The following resolution logic (execvpe emulation) is copied from * https://git.musl-libc.org/cgit/musl/tree/src/process/execvp.c * and adapted to work for our specific usage */ - /* If no path was provided in options->env, use the default value + /* If no path was provided in env, use the default value * to look for the executable */ if (path == NULL) path = _PATH_DEFPATH; diff --git a/test/test-list.h b/test/test-list.h index 2f0237152b1..d75fc48e71f 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -321,6 +321,7 @@ TEST_DECLARE (spawn_inherit_streams) TEST_DECLARE (spawn_quoted_path) TEST_DECLARE (spawn_tcp_server) TEST_DECLARE (spawn_exercise_sigchld_issue) +TEST_DECLARE (spawn_relative_path) TEST_DECLARE (fs_poll) TEST_DECLARE (fs_poll_getpath) TEST_DECLARE (fs_poll_close_request) @@ -956,6 +957,7 @@ TASK_LIST_START TEST_ENTRY (spawn_quoted_path) TEST_ENTRY (spawn_tcp_server) TEST_ENTRY (spawn_exercise_sigchld_issue) + TEST_ENTRY (spawn_relative_path) TEST_ENTRY (fs_poll) TEST_ENTRY (fs_poll_getpath) TEST_ENTRY (fs_poll_close_request) diff --git a/test/test-spawn.c b/test/test-spawn.c index dfd5458ef37..de9c710020e 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1981,3 +1981,37 @@ void spawn_stdin_stdout(void) { } } #endif /* !_WIN32 */ + +TEST_IMPL(spawn_relative_path) { + char* sep; + + init_process_options("spawn_helper1", exit_cb); + + exepath_size = sizeof(exepath) - 2; + ASSERT_EQ(0, uv_exepath(exepath, &exepath_size)); + exepath[exepath_size] = '\0'; + + /* Poor man's basename(3). */ + sep = strrchr(exepath, '/'); + if (sep == NULL) + sep = strrchr(exepath, '\\'); + ASSERT_NOT_NULL(sep); + + /* Split into dirname and basename and make basename relative. */ + memmove(sep + 2, sep, 1 + strlen(sep)); + sep[0] = '\0'; + sep[1] = '.'; + sep[2] = '/'; + + options.cwd = exepath; + options.file = options.args[0] = sep + 1; + + ASSERT_EQ(0, uv_spawn(uv_default_loop(), &process, &options)); + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From 9e59aa1bc8c4d215ea3e05eafec7181747206f67 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 19 Apr 2022 11:16:25 -0400 Subject: [PATCH 189/713] release: check versions of autogen scripts are newer (#3554) Use libtoolize --force to ensure it updates m4 directory with the latest files. Add an option "release" to the autogen.sh script that checks the versions of the input tools, so that we know they are always using the latest version for each release. --- autogen.sh | 35 ++++++++++++++++++++++++++++++++--- m4/libuv-check-versions.m4 | 7 +++++++ 2 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 m4/libuv-check-versions.m4 diff --git a/autogen.sh b/autogen.sh index 271c2ee8c33..bfd8f3e6df0 100755 --- a/autogen.sh +++ b/autogen.sh @@ -14,9 +14,16 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +set -eu cd `dirname "$0"` -if [ "$LIBTOOLIZE" = "" ] && [ "`uname`" = "Darwin" ]; then +if [ "${1:-dev}" == "release" ]; then + export LIBUV_RELEASE=true +else + export LIBUV_RELEASE=false +fi + +if [ "${LIBTOOLIZE:-}" = "" ] && [ "`uname`" = "Darwin" ]; then LIBTOOLIZE=glibtoolize fi @@ -25,9 +32,17 @@ AUTOCONF=${AUTOCONF:-autoconf} AUTOMAKE=${AUTOMAKE:-automake} LIBTOOLIZE=${LIBTOOLIZE:-libtoolize} +aclocal_version=`"$ACLOCAL" --version | head -n 1 | sed 's/[^.0-9]//g'` +autoconf_version=`"$AUTOCONF" --version | head -n 1 | sed 's/[^.0-9]//g'` automake_version=`"$AUTOMAKE" --version | head -n 1 | sed 's/[^.0-9]//g'` automake_version_major=`echo "$automake_version" | cut -d. -f1` automake_version_minor=`echo "$automake_version" | cut -d. -f2` +libtoolize_version=`"$LIBTOOLIZE" --version | head -n 1 | sed 's/[^.0-9]//g'` + +if [ $aclocal_version != $automake_version ]; then + echo "FATAL: aclocal version appears not to be from the same as automake" + exit 1 +fi UV_EXTRA_AUTOMAKE_FLAGS= if test "$automake_version_major" -gt 1 || \ @@ -39,8 +54,22 @@ fi echo "m4_define([UV_EXTRA_AUTOMAKE_FLAGS], [$UV_EXTRA_AUTOMAKE_FLAGS])" \ > m4/libuv-extra-automake-flags.m4 -set -ex -"$LIBTOOLIZE" --copy +(set -x +"$LIBTOOLIZE" --copy --force "$ACLOCAL" -I m4 +) +if $LIBUV_RELEASE; then + "$AUTOCONF" -o /dev/null m4/libuv-check-versions.m4 + echo " +AC_PREREQ($autoconf_version) +AC_INIT([libuv-release-check], [0.0]) +AM_INIT_AUTOMAKE([$automake_version]) +LT_PREREQ($libtoolize_version) +AC_OUTPUT +" > m4/libuv-check-versions.m4 +fi +( +set -x "$AUTOCONF" "$AUTOMAKE" --add-missing --copy +) diff --git a/m4/libuv-check-versions.m4 b/m4/libuv-check-versions.m4 new file mode 100644 index 00000000000..a280596daa3 --- /dev/null +++ b/m4/libuv-check-versions.m4 @@ -0,0 +1,7 @@ + +AC_PREREQ(2.71) +AC_INIT([libuv-release-check], [0.0]) +AM_INIT_AUTOMAKE([1.16.5]) +LT_PREREQ(2.4.6) +AC_OUTPUT + From a302ad427d96ad21582edb6fc9b860eae4156225 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 27 Apr 2022 10:18:40 +0200 Subject: [PATCH 190/713] test: rewrite embed test (#3608) - fix busy loop - fix multi-thread race conditions - reduce amount of platform-specific code Fixes: https://github.com/libuv/libuv/issues/3606 --- test/test-embed.c | 136 +++++++++++++--------------------------------- 1 file changed, 38 insertions(+), 98 deletions(-) diff --git a/test/test-embed.c b/test/test-embed.c index c6ddceb149d..fd39185ea75 100644 --- a/test/test-embed.c +++ b/test/test-embed.c @@ -1,4 +1,4 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. +/* 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 @@ -25,115 +25,55 @@ #include #include -#ifndef HAVE_KQUEUE -# if defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) -# define HAVE_KQUEUE 1 -# endif +#ifndef _WIN32 +#include #endif -#ifndef HAVE_EPOLL -# if defined(__linux__) -# define HAVE_EPOLL 1 -# endif -#endif - -#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) - -#if defined(HAVE_KQUEUE) -# include -# include -# include -#endif - -#if defined(HAVE_EPOLL) -# include -#endif - -static uv_thread_t embed_thread; -static uv_sem_t embed_sem; -static uv_timer_t embed_timer; -static uv_async_t embed_async; -static volatile int embed_closed; - -static int embed_timer_called; - - -static void embed_thread_runner(void* arg) { - int r; - int fd; - int timeout; - - while (!embed_closed) { - fd = uv_backend_fd(uv_default_loop()); - timeout = uv_backend_timeout(uv_default_loop()); - - do { -#if defined(HAVE_KQUEUE) - struct timespec ts; - ts.tv_sec = timeout / 1000; - ts.tv_nsec = (timeout % 1000) * 1000000; - r = kevent(fd, NULL, 0, NULL, 0, &ts); -#elif defined(HAVE_EPOLL) - { - struct epoll_event ev; - r = epoll_wait(fd, &ev, 1, timeout); - } -#endif - } while (r == -1 && errno == EINTR); - uv_async_send(&embed_async); - uv_sem_wait(&embed_sem); - } -} - +static uv_async_t async; +static uv_barrier_t barrier; -static void embed_cb(uv_async_t* async) { - uv_run(uv_default_loop(), UV_RUN_ONCE); - uv_sem_post(&embed_sem); +static void thread_main(void* arg) { + ASSERT_LE(0, uv_barrier_wait(&barrier)); + uv_sleep(250); + ASSERT_EQ(0, uv_async_send(&async)); } -static void embed_timer_cb(uv_timer_t* timer) { - embed_timer_called++; - embed_closed = 1; - - uv_close((uv_handle_t*) &embed_async, NULL); +static void async_cb(uv_async_t* handle) { + uv_close((uv_handle_t*) handle, NULL); } -#endif TEST_IMPL(embed) { -#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) - uv_loop_t external; - - ASSERT(0 == uv_loop_init(&external)); - - embed_timer_called = 0; - embed_closed = 0; - - uv_async_init(&external, &embed_async, embed_cb); - - /* Start timer in default loop */ - uv_timer_init(uv_default_loop(), &embed_timer); - uv_timer_start(&embed_timer, embed_timer_cb, 250, 0); - - /* Start worker that will interrupt external loop */ - uv_sem_init(&embed_sem, 0); - uv_thread_create(&embed_thread, embed_thread_runner, NULL); - - /* But run external loop */ - uv_run(&external, UV_RUN_DEFAULT); - - uv_thread_join(&embed_thread); - uv_loop_close(&external); - - ASSERT(embed_timer_called == 1); + uv_thread_t thread; + uv_loop_t* loop; + + loop = uv_default_loop(); + ASSERT_EQ(0, uv_async_init(loop, &async, async_cb)); + ASSERT_EQ(0, uv_barrier_init(&barrier, 2)); + ASSERT_EQ(0, uv_thread_create(&thread, thread_main, NULL)); + ASSERT_LE(0, uv_barrier_wait(&barrier)); + + while (uv_loop_alive(loop)) { +#ifdef _WIN32 + ASSERT_LE(0, uv_run(loop, UV_RUN_ONCE)); +#else + int rc; + do { + struct pollfd p; + p.fd = uv_backend_fd(loop); + p.events = POLLIN; + p.revents = 0; + rc = poll(&p, 1, uv_backend_timeout(loop)); + } while (rc == -1 && errno == EINTR); + ASSERT_LE(0, uv_run(loop, UV_RUN_NOWAIT)); #endif + } + + ASSERT_EQ(0, uv_thread_join(&thread)); + uv_barrier_destroy(&barrier); + MAKE_VALGRIND_HAPPY(); return 0; } From 4e63e488792a1b6f846c0ca1bf40fd67da3df0c6 Mon Sep 17 00:00:00 2001 From: tuftedocelot Date: Wed, 27 Apr 2022 02:19:28 -0600 Subject: [PATCH 191/713] openbsd: use utimensat instead of lutimes (#3607) OpenBSD doesn't have lutimes so utimensat should be used instead. --- src/unix/fs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index b3211ec1066..933c9c0dc2d 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1181,7 +1181,8 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) { defined(_AIX71) || \ defined(__sun) || \ defined(__HAIKU__) || \ - defined(__GNU__) + defined(__GNU__) || \ + defined(__OpenBSD__) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); From e0680d3061f90469d964c52939304e3c37f44700 Mon Sep 17 00:00:00 2001 From: blogdaren Date: Wed, 27 Apr 2022 16:23:28 +0800 Subject: [PATCH 192/713] doc: fix link to uvwget example main() function (#3605) --- docs/src/guide/utilities.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/guide/utilities.rst b/docs/src/guide/utilities.rst index 4657b1b0bf6..e2f3cf6a633 100644 --- a/docs/src/guide/utilities.rst +++ b/docs/src/guide/utilities.rst @@ -220,7 +220,7 @@ progress with the download whenever libuv notifies of I/O readiness. .. literalinclude:: ../../code/uvwget/main.c :language: c :linenos: - :lines: 1-9,140- + :lines: 1-9,142- :emphasize-lines: 7,21,24-25 The way each library is integrated with libuv will vary. In the case of From 03a698b9c68622789eb78228409d8a82d22ddd3f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 27 Apr 2022 22:44:00 +0200 Subject: [PATCH 193/713] unix: use MSG_CMSG_CLOEXEC where supported (#3609) Use MSG_CMSG_CLOEXEC on Unix-y platforms that support it (all except macOS and SunOS spawn.) Remove the feature test for Linux. Libuv's kernel baseline is 2.6.32 and MSG_CMSG_CLOEXEC was added in 2.6.23. --- src/unix/core.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index d5758de493b..ca36998990a 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -667,28 +667,23 @@ int uv__cloexec(int fd, int set) { ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { - struct cmsghdr* cmsg; +#if defined(__ANDROID__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) || \ + defined(__linux__) ssize_t rc; + rc = recvmsg(fd, msg, flags | MSG_CMSG_CLOEXEC); + if (rc == -1) + return UV__ERR(errno); + return rc; +#else + struct cmsghdr* cmsg; int* pfd; int* end; -#if defined(__linux__) - static int no_msg_cmsg_cloexec; - if (0 == uv__load_relaxed(&no_msg_cmsg_cloexec)) { - rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */ - if (rc != -1) - return rc; - if (errno != EINVAL) - return UV__ERR(errno); - rc = recvmsg(fd, msg, flags); - if (rc == -1) - return UV__ERR(errno); - uv__store_relaxed(&no_msg_cmsg_cloexec, 1); - } else { - rc = recvmsg(fd, msg, flags); - } -#else + ssize_t rc; rc = recvmsg(fd, msg, flags); -#endif if (rc == -1) return UV__ERR(errno); if (msg->msg_controllen == 0) @@ -701,6 +696,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { pfd += 1) uv__cloexec(*pfd, 1); return rc; +#endif } From 7825bfb49dbb60a694ec25b66c099af3d7a787e8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 9 May 2022 09:17:35 +0200 Subject: [PATCH 194/713] test: remove disabled callback_order test (#3619) This test has always been disabled for the 10 years of its existence and there are other tests that exercise "what happens when" event ordering. Fixes: https://github.com/libuv/libuv/issues/3618 --- CMakeLists.txt | 1 - Makefile.am | 1 - test/test-callback-order.c | 77 -------------------------------------- test/test-list.h | 4 -- 4 files changed, 83 deletions(-) delete mode 100644 test/test-callback-order.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f712a80ac4..7f466826c50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -464,7 +464,6 @@ if(LIBUV_BUILD_TESTS) test/test-async-null-cb.c test/test-async.c test/test-barrier.c - test/test-callback-order.c test/test-callback-stack.c test/test-close-fd.c test/test-close-order.c diff --git a/Makefile.am b/Makefile.am index a7ee5d469ea..0c6d96598ae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -152,7 +152,6 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-async.c \ test/test-async-null-cb.c \ test/test-barrier.c \ - test/test-callback-order.c \ test/test-callback-stack.c \ test/test-close-fd.c \ test/test-close-order.c \ diff --git a/test/test-callback-order.c b/test/test-callback-order.c deleted file mode 100644 index 8bc2c4f75de..00000000000 --- a/test/test-callback-order.c +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "uv.h" -#include "task.h" - -static int idle_cb_called; -static int timer_cb_called; - -static uv_idle_t idle_handle; -static uv_timer_t timer_handle; - - -/* idle_cb should run before timer_cb */ -static void idle_cb(uv_idle_t* handle) { - ASSERT(idle_cb_called == 0); - ASSERT(timer_cb_called == 0); - uv_idle_stop(handle); - idle_cb_called++; -} - - -static void timer_cb(uv_timer_t* handle) { - ASSERT(idle_cb_called == 1); - ASSERT(timer_cb_called == 0); - uv_timer_stop(handle); - timer_cb_called++; -} - - -static void next_tick(uv_idle_t* handle) { - uv_loop_t* loop = handle->loop; - uv_idle_stop(handle); - uv_idle_init(loop, &idle_handle); - uv_idle_start(&idle_handle, idle_cb); - uv_timer_init(loop, &timer_handle); - uv_timer_start(&timer_handle, timer_cb, 0, 0); -} - - -TEST_IMPL(callback_order) { - uv_loop_t* loop; - uv_idle_t idle; - - loop = uv_default_loop(); - uv_idle_init(loop, &idle); - uv_idle_start(&idle, next_tick); - - ASSERT(idle_cb_called == 0); - ASSERT(timer_cb_called == 0); - - uv_run(loop, UV_RUN_DEFAULT); - - ASSERT(idle_cb_called == 1); - ASSERT(timer_cb_called == 1); - - MAKE_VALGRIND_HAPPY(); - return 0; -} diff --git a/test/test-list.h b/test/test-list.h index d75fc48e71f..90393393296 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -22,7 +22,6 @@ #include "uv.h" TEST_DECLARE (platform_output) -TEST_DECLARE (callback_order) TEST_DECLARE (close_order) TEST_DECLARE (run_once) TEST_DECLARE (run_nowait) @@ -547,9 +546,6 @@ TEST_DECLARE (metrics_idle_time_zero) TASK_LIST_START TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000) -#if 0 - TEST_ENTRY (callback_order) -#endif TEST_ENTRY (test_macros) TEST_ENTRY (close_order) TEST_ENTRY (run_once) From ec67735412bc80c0f44fa7cb1cacd87b5ba97be8 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 13 May 2022 06:40:02 -0400 Subject: [PATCH 195/713] win,pipe: fix bugs with pipe resource lifetime management (#3611) If `uv_close` was called while a connect was pending, we would fail to release the resources for the connection, since we had not yet set the type of the struct. Fix a thread data-race on slow connect path code: only permitted to write to `req` on threads, as anything else causes data race corruption. There seemed be a small variety of other resource management bugs in edge cases, which turned out to make this a lot larger than initially expected. Refs: https://github.com/libuv/libuv/pull/3598#issuecomment-1111513567 --- include/uv/win.h | 6 ++ src/win/pipe.c | 162 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 121 insertions(+), 47 deletions(-) diff --git a/include/uv/win.h b/include/uv/win.h index 62be4b04ea8..56a4cf1151c 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -377,6 +377,12 @@ typedef struct { OVERLAPPED overlapped; \ size_t queued_bytes; \ } io; \ + /* in v2, we can move these to the UV_CONNECT_PRIVATE_FIELDS */ \ + struct { \ + ULONG_PTR result; /* overlapped.Internal is reused to hold the result */\ + HANDLE pipeHandle; \ + DWORD duplex_flags; \ + } connect; \ } u; \ struct uv_req_s* next_req; diff --git a/src/win/pipe.c b/src/win/pipe.c index a4bab2c4838..67e28300896 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -121,14 +121,10 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { static void uv__pipe_connection_init(uv_pipe_t* handle) { + assert(!(handle->flags & UV_HANDLE_PIPESERVER)); uv__connection_init((uv_stream_t*) handle); handle->read_req.data = handle; handle->pipe.conn.eof_timer = NULL; - assert(!(handle->flags & UV_HANDLE_PIPESERVER)); - if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { - handle->pipe.conn.readfile_thread_handle = NULL; - InitializeCriticalSection(&handle->pipe.conn.readfile_thread_lock); - } } @@ -393,6 +389,8 @@ int uv__create_stdio_pipe_pair(uv_loop_t* loop, unsigned int client_flags; int err; + uv__pipe_connection_init(parent_pipe); + server_pipe = INVALID_HANDLE_VALUE; client_pipe = INVALID_HANDLE_VALUE; @@ -427,7 +425,6 @@ int uv__create_stdio_pipe_pair(uv_loop_t* loop, goto error; } - uv__pipe_connection_init(parent_pipe); parent_pipe->handle = server_pipe; *child_pipe_ptr = client_pipe; @@ -462,7 +459,9 @@ static int uv__set_pipe_handle(uv_loop_t* loop, DWORD current_mode = 0; DWORD err = 0; - if (handle->flags & UV_HANDLE_PIPESERVER) + assert(handle->flags & UV_HANDLE_CONNECTION); + assert(!(handle->flags & UV_HANDLE_PIPESERVER)); + if (handle->flags & UV_HANDLE_CLOSING) return UV_EINVAL; if (handle->handle != INVALID_HANDLE_VALUE) return UV_EBUSY; @@ -478,18 +477,17 @@ static int uv__set_pipe_handle(uv_loop_t* loop, */ if (!GetNamedPipeHandleState(pipeHandle, ¤t_mode, NULL, NULL, NULL, NULL, 0)) { - return -1; + return uv_translate_sys_error(GetLastError()); } else if (current_mode & PIPE_NOWAIT) { - SetLastError(ERROR_ACCESS_DENIED); - return -1; + return UV_EACCES; } } else { /* If this returns ERROR_INVALID_PARAMETER we probably opened * something that is not a pipe. */ if (err == ERROR_INVALID_PARAMETER) { - SetLastError(WSAENOTSOCK); + return UV_ENOTSOCK; } - return -1; + return uv_translate_sys_error(err); } } @@ -500,13 +498,15 @@ static int uv__set_pipe_handle(uv_loop_t* loop, sizeof(mode_info), FileModeInformation); if (nt_status != STATUS_SUCCESS) { - return -1; + return uv_translate_sys_error(err); } if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT || mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) { /* Non-overlapped pipe. */ handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE; + handle->pipe.conn.readfile_thread_handle = NULL; + InitializeCriticalSection(&handle->pipe.conn.readfile_thread_lock); } else { /* Overlapped pipe. Try to associate with IOCP. */ if (CreateIoCompletionPort(pipeHandle, @@ -815,7 +815,7 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { assert(loop); /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait - * for the pipe to become available with WaitNamedPipe. */ + * up to 30 seconds for the pipe to become available with WaitNamedPipe. */ while (WaitNamedPipeW(handle->name, 30000)) { /* The pipe is now available, try to connect. */ pipeHandle = open_named_pipe(handle->name, &duplex_flags); @@ -825,9 +825,10 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { SwitchToThread(); } - if (pipeHandle != INVALID_HANDLE_VALUE && - !uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) { + if (pipeHandle != INVALID_HANDLE_VALUE) { SET_REQ_SUCCESS(req); + req->u.connect.pipeHandle = pipeHandle; + req->u.connect.duplex_flags = duplex_flags; } else { SET_REQ_ERROR(req, GetLastError()); } @@ -849,6 +850,18 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, UV_REQ_INIT(req, UV_CONNECT); req->handle = (uv_stream_t*) handle; req->cb = cb; + req->u.connect.pipeHandle = INVALID_HANDLE_VALUE; + req->u.connect.duplex_flags = 0; + + if (handle->flags & UV_HANDLE_PIPESERVER) { + err = ERROR_INVALID_PARAMETER; + goto error; + } + if (handle->flags & UV_HANDLE_CONNECTION) { + err = ERROR_PIPE_BUSY; + goto error; + } + uv__pipe_connection_init(handle); /* Convert name to UTF16. */ nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); @@ -888,17 +901,8 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, goto error; } - assert(pipeHandle != INVALID_HANDLE_VALUE); - - if (uv__set_pipe_handle(loop, - (uv_pipe_t*) req->handle, - pipeHandle, - -1, - duplex_flags)) { - err = GetLastError(); - goto error; - } - + req->u.connect.pipeHandle = pipeHandle; + req->u.connect.duplex_flags = duplex_flags; SET_REQ_SUCCESS(req); uv__insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; @@ -937,7 +941,7 @@ void uv__pipe_interrupt_read(uv_pipe_t* handle) { /* Cancel asynchronous read. */ r = CancelIoEx(handle->handle, &handle->read_req.u.io.overlapped); assert(r || GetLastError() == ERROR_NOT_FOUND); - + (void) r; } else { /* Cancel synchronous read (which is happening in the thread pool). */ HANDLE thread; @@ -1099,6 +1103,7 @@ int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) { } else { pipe_client = (uv_pipe_t*) client; + uv__pipe_connection_init(pipe_client); /* Find a connection instance that has been connected, but not yet * accepted. */ @@ -1110,7 +1115,6 @@ int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) { } /* Initialize the client handle and copy the pipeHandle to the client */ - uv__pipe_connection_init(pipe_client); pipe_client->handle = req->pipeHandle; pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; @@ -2140,22 +2144,28 @@ void uv__process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, uv_connect_t* req) { + HANDLE pipeHandle; + DWORD duplex_flags; int err; assert(handle->type == UV_NAMED_PIPE); UNREGISTER_HANDLE_REQ(loop, handle, req); - if (req->cb) { - err = 0; - if (REQ_SUCCESS(req)) { - uv__pipe_connection_init(handle); - } else { - err = GET_REQ_ERROR(req); - } - req->cb(req, uv_translate_sys_error(err)); + err = 0; + if (REQ_SUCCESS(req)) { + pipeHandle = req->u.connect.pipeHandle; + duplex_flags = req->u.connect.duplex_flags; + err = uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags); + if (err) + CloseHandle(pipeHandle); + } else { + err = uv_translate_sys_error(GET_REQ_ERROR(req)); } + if (req->cb) + req->cb(req, err); + DECREASE_PENDING_REQ_COUNT(handle); } @@ -2200,7 +2210,8 @@ static void eof_timer_init(uv_pipe_t* pipe) { pipe->pipe.conn.eof_timer = (uv_timer_t*) uv__malloc(sizeof *pipe->pipe.conn.eof_timer); r = uv_timer_init(pipe->loop, pipe->pipe.conn.eof_timer); - assert(r == 0); /* timers can't fail */ + assert(r == 0); /* timers can't fail */ + (void) r; pipe->pipe.conn.eof_timer->data = pipe; uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer); } @@ -2280,10 +2291,16 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { IO_STATUS_BLOCK io_status; FILE_ACCESS_INFORMATION access; DWORD duplex_flags = 0; + int err; if (os_handle == INVALID_HANDLE_VALUE) return UV_EBADF; + if (pipe->flags & UV_HANDLE_PIPESERVER) + return UV_EINVAL; + if (pipe->flags & UV_HANDLE_CONNECTION) + return UV_EBUSY; + uv__pipe_connection_init(pipe); uv__once_init(); /* In order to avoid closing a stdio file descriptor 0-2, duplicate the * underlying OS handle and forget about the original fd. @@ -2300,6 +2317,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { FALSE, DUPLICATE_SAME_ACCESS)) return uv_translate_sys_error(GetLastError()); + assert(os_handle != INVALID_HANDLE_VALUE); file = -1; } @@ -2327,17 +2345,17 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { if (access.AccessFlags & FILE_READ_DATA) duplex_flags |= UV_HANDLE_READABLE; - if (os_handle == INVALID_HANDLE_VALUE || - uv__set_pipe_handle(pipe->loop, - pipe, - os_handle, - file, - duplex_flags) == -1) { - return UV_EINVAL; + err = uv__set_pipe_handle(pipe->loop, + pipe, + os_handle, + file, + duplex_flags); + if (err) { + if (file == -1) + CloseHandle(os_handle); + return err; } - uv__pipe_connection_init(pipe); - if (pipe->ipc) { assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); pipe->pipe.conn.ipc_remote_pid = uv_os_getppid(); @@ -2361,6 +2379,51 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) uv__once_init(); name_info = NULL; + if (handle->name != NULL) { + /* The user might try to query the name before we are connected, + * and this is just easier to return the cached value if we have it. */ + name_buf = handle->name; + name_len = wcslen(name_buf); + + /* check how much space we need */ + addrlen = WideCharToMultiByte(CP_UTF8, + 0, + name_buf, + name_len, + NULL, + 0, + NULL, + NULL); + if (!addrlen) { + *size = 0; + err = uv_translate_sys_error(GetLastError()); + return err; + } else if (addrlen >= *size) { + *size = addrlen + 1; + err = UV_ENOBUFS; + goto error; + } + + addrlen = WideCharToMultiByte(CP_UTF8, + 0, + name_buf, + name_len, + buffer, + addrlen, + NULL, + NULL); + if (!addrlen) { + *size = 0; + err = uv_translate_sys_error(GetLastError()); + return err; + } + + *size = addrlen; + buffer[addrlen] = '\0'; + + return 0; + } + if (handle->handle == INVALID_HANDLE_VALUE) { *size = 0; return UV_EINVAL; @@ -2498,6 +2561,11 @@ int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) { if (handle->handle != INVALID_HANDLE_VALUE) return uv__pipe_getname(handle, buffer, size); + if (handle->flags & UV_HANDLE_CONNECTION) { + if (handle->name != NULL) + return uv__pipe_getname(handle, buffer, size); + } + return UV_EBADF; } From ee3718dd71061dccfd1f85b973ae49e27909f147 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 13 May 2022 06:41:33 -0400 Subject: [PATCH 196/713] loop: better align order-of-events behavior between platforms (#3598) Previously, Windows would always defer event processing to the loop after they were received. This could cause confusion for users who were using prepare and idle callbacks, as seen from this bug in nodejs[^1] and this discussion in libuv[^2], and even some discrepancies in the libuv tests too[^3]. [^1]: https://github.com/nodejs/node/pull/42340 [^2]: https://github.com/libuv/libuv/discussions/3550 [^3]: See change to test-spawn.c in this PR So rather than declare those usages to be wrong, we change libuv to meet those users expectations. Replaces: https://github.com/libuv/libuv/pull/3585 --- src/unix/core.c | 5 +++++ src/win/core.c | 5 +++++ test/test-pipe-set-non-blocking.c | 3 +-- test/test-spawn.c | 3 --- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index ca36998990a..3149152bf65 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -404,6 +404,11 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { uv__io_poll(loop, timeout); + /* Process immediate callbacks (e.g. write_cb) a small fixed number of + * times to avoid loop starvation.*/ + for (r = 0; r < 8 && !QUEUE_EMPTY(&loop->pending_queue); r++) + uv__run_pending(loop); + /* Run one final update on the provider_idle_time in case uv__io_poll * returned because the timeout expired, but no events were received. This * call will be ignored if the provider_entry_time was either never set (if diff --git a/src/win/core.c b/src/win/core.c index 664ffac976c..67af93e6571 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -617,6 +617,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { else uv__poll_wine(loop, timeout); + /* Process immediate callbacks (e.g. write_cb) a small fixed number of + * times to avoid loop starvation.*/ + for (r = 0; r < 8 && loop->pending_reqs_tail != NULL; r++) + uv__process_reqs(loop); + /* Run one final update on the provider_idle_time in case uv__poll* * returned because the timeout expired, but no events were received. This * call will be ignored if the provider_entry_time was either never set (if diff --git a/test/test-pipe-set-non-blocking.c b/test/test-pipe-set-non-blocking.c index 827e7264108..c780460950e 100644 --- a/test/test-pipe-set-non-blocking.c +++ b/test/test-pipe-set-non-blocking.c @@ -102,8 +102,7 @@ TEST_IMPL(pipe_set_non_blocking) { ASSERT(n == UV_EAGAIN); /* E_NOTIMPL */ ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &pipe_handle, &buf, 1, write_cb)); ASSERT_NOT_NULL(write_req.handle); - ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_ONCE)); /* queue write_cb */ - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); /* process write_cb */ + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); ASSERT_NULL(write_req.handle); /* check for signaled completion of write_cb */ n = buf.len; #endif diff --git a/test/test-spawn.c b/test/test-spawn.c index de9c710020e..7a07482b1c9 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1675,9 +1675,6 @@ TEST_IMPL(closed_fd_events) { ASSERT(req.result == 1); uv_fs_req_cleanup(&req); -#ifdef _WIN32 - ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_ONCE)); -#endif ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); /* should have received just one byte */ From 1b8cc561949565190d54195042b8028f488ed068 Mon Sep 17 00:00:00 2001 From: V-for-Vasili Date: Fri, 13 May 2022 06:43:28 -0400 Subject: [PATCH 197/713] aix,test: uv_backend_fd is not supported by poll (#3621) Fixes: https://github.com/libuv/libuv/issues/3614 Co-authored-by: Vasili Skurydzin --- test/test-embed.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-embed.c b/test/test-embed.c index fd39185ea75..1d3355fdc67 100644 --- a/test/test-embed.c +++ b/test/test-embed.c @@ -25,7 +25,7 @@ #include #include -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(_AIX) #include #endif @@ -56,7 +56,7 @@ TEST_IMPL(embed) { ASSERT_LE(0, uv_barrier_wait(&barrier)); while (uv_loop_alive(loop)) { -#ifdef _WIN32 +#if defined(_WIN32) || defined(_AIX) ASSERT_LE(0, uv_run(loop, UV_RUN_ONCE)); #else int rc; From 730e07e2f77a4001bdf6894112271c926399f5a8 Mon Sep 17 00:00:00 2001 From: chucksilvers Date: Tue, 17 May 2022 04:43:52 -0700 Subject: [PATCH 198/713] kqueue: skip EVFILT_PROC when invalidating fds (#3629) On NetBSD with libuv 1.44.1 we see that cmake occasionally hangs waiting for a child process to exit, with libuv waiting forever for `kevent` to deliver more events that never come. The child process has already exited and is waiting to be collected with `waitpid`. The hang occurs when the batch of events returned by one call to `kevent` contains both a EVFILT_READ event for an fd and a later EVFILT_PROC record for the PID with the same value as the earlier fd. What happens is that `uv__platform_invalidate_fd` is called to invalidate events later in the same batch for the fd, but `uv__platform_invalidate_fd` invalidates the later EVFILT_PROC event too because it sees the same "ident" value and does not check the "filter" value to differentiate "ident" values that refer to fds vs. "ident" values that refer to PIDs. Add a check for the "filter" value to avoid confusing these two different kinds of event "ident" values. --- src/unix/kqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 036055149fc..5dac76ae753 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -456,7 +456,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { /* Invalidate events with same file descriptor */ for (i = 0; i < nfds; i++) - if ((int) events[i].ident == fd) + if ((int) events[i].ident == fd && events[i].filter != EVFILT_PROC) events[i].ident = -1; } From 99ab53e9980dc0b2fb31b4615ce754bf1f35826f Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Tue, 24 May 2022 23:04:47 +0800 Subject: [PATCH 199/713] darwin: fix atomic-ops.h ppc64 build (#3634) --- src/unix/atomic-ops.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h index 664a9426706..58043c42fbd 100644 --- a/src/unix/atomic-ops.h +++ b/src/unix/atomic-ops.h @@ -54,7 +54,9 @@ UV_UNUSED(static void cpu_relax(void)) { __asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */ #elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__) __asm__ __volatile__ ("yield" ::: "memory"); -#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) +#elif (defined(__ppc__) || defined(__ppc64__)) && defined(__APPLE__) + __asm volatile ("" : : : "memory"); +#elif !defined(__APPLE__) && (defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)) __asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory"); #endif } From 51dcac5da7ca020eaf8a73f6f16a8a9f8f178179 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Wed, 25 May 2022 09:12:57 -0400 Subject: [PATCH 200/713] zos: don't err when killing a zombie process (#3625) On z/OS, EPERM is returned if the process being killed is a zombie. However, this shouldn't be treated as an error, so return 0 instead. Co-authored-by: Muntasir Mallick Co-authored-by: Gaby Baghdadi --- src/unix/process.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index 3a1b5b74753..f84153687f7 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -1063,9 +1063,16 @@ int uv_process_kill(uv_process_t* process, int signum) { int uv_kill(int pid, int signum) { - if (kill(pid, signum)) + if (kill(pid, signum)) { +#if defined(__MVS__) + /* EPERM is returned if the process is a zombie. */ + siginfo_t infop; + if (errno == EPERM && + waitid(P_PID, pid, &infop, WNOHANG | WNOWAIT | WEXITED) == 0) + return 0; +#endif return UV__ERR(errno); - else + } else return 0; } From 77c8e993ec66e0b3361b288585666e1914aaec6f Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Sat, 11 Jun 2022 00:22:06 -0400 Subject: [PATCH 201/713] zos: avoid fs event callbacks after uv_close() (#3620) On z/OS, fs events are implemented by registering file interest. When closing a fs event handle, it's possible that a change notification has already been generated. In that case, the attempt to unregister file interest will fail with EALREADY. This will result in the fs event being delivered even though the handle is closing, which should not happen. Fixes: https://github.com/libuv/libuv/issues/3601 --- src/unix/core.c | 6 +++--- src/unix/os390.c | 50 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 3149152bf65..fd4f3480903 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -160,10 +160,10 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { case UV_FS_EVENT: uv__fs_event_close((uv_fs_event_t*)handle); -#if defined(__sun) +#if defined(__sun) || defined(__MVS__) /* - * On Solaris and illumos, we will not be able to dissociate the watcher - * for an event which is pending delivery, so we cannot always call + * On Solaris, illumos, and z/OS we will not be able to dissociate the + * watcher for an event which is pending delivery, so we cannot always call * uv__make_close_pending() straight away. The backend will call the * function once the event has cleared. */ diff --git a/src/unix/os390.c b/src/unix/os390.c index 6911ea7f415..df8b5877e41 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -529,11 +529,6 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { } -void uv__fs_event_close(uv_fs_event_t* handle) { - uv_fs_event_stop(handle); -} - - int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); return 0; @@ -590,7 +585,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, } -int uv_fs_event_stop(uv_fs_event_t* handle) { +int uv__fs_event_stop(uv_fs_event_t* handle) { uv__os390_epoll* ep; _RFIS reg_struct; int rc; @@ -616,16 +611,40 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { if (rc != 0 && errno != EALREADY && errno != ENOENT) abort(); - uv__handle_stop(handle); if (handle->path != NULL) { uv__free(handle->path); handle->path = NULL; } + if (rc != 0 && errno == EALREADY) + return -1; + + uv__handle_stop(handle); + return 0; } +int uv_fs_event_stop(uv_fs_event_t* handle) { + uv__fs_event_stop(handle); + return 0; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + /* + * If we were unable to unregister file interest here, then it is most likely + * that there is a pending queued change notification. When this happens, we + * don't want to complete the close as it will free the underlying memory for + * the handle, causing a use-after-free problem when the event is processed. + * We defer the final cleanup until after the event is consumed in + * os390_message_queue_handler(). + */ + if (uv__fs_event_stop(handle) == 0) + uv__make_close_pending((uv_handle_t*) handle); +} + + static int os390_message_queue_handler(uv__os390_epoll* ep) { uv_fs_event_t* handle; int msglen; @@ -666,13 +685,25 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) { __a2e_l(msg.__rfim_utok, sizeof(msg.__rfim_utok)); handle = *(uv_fs_event_t**)(msg.__rfim_utok); assert(handle != NULL); + + assert((handle->flags & UV_HANDLE_CLOSED) == 0); + if (uv__is_closing(handle)) { + uv__handle_stop(handle); + uv__make_close_pending((uv_handle_t*) handle); + return 0; + } else if (handle->path == NULL) { + /* _RFIS_UNREG returned EALREADY. */ + uv__handle_stop(handle); + return 0; + } + /* The file is implicitly unregistered when the change notification is * sent, only one notification is sent per registration. So we need to * re-register interest in a file after each change notification we * receive. */ - if (handle->path != NULL) - os390_regfileint(handle, handle->path); + assert(handle->path != NULL); + os390_regfileint(handle, handle->path); handle->cb(handle, uv__basename_r(handle->path), events, 0); return 1; } @@ -830,6 +861,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { ep = loop->ep; if (pe->is_msg) { os390_message_queue_handler(ep); + nevents++; continue; } From 75ad046bfb92b22a89fe399e351bb65f3bcf9e9a Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Mon, 16 May 2022 19:02:02 -0400 Subject: [PATCH 202/713] zos: correctly format interface addresses names (#3640 1/3) On z/OS, the interface address name contains EBCDIC and may be padded with whitespaces. The whitespace padding needs to be trimmed, and the interface address name needs to be converted from EBCDIC to ASCII. Co-authored-by: John Barboza Co-authored-by: Igor Todorovski --- src/unix/os390.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index df8b5877e41..f4ad84ba1b8 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -278,7 +278,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, __net_ifconf6header_t ifc; __net_ifconf6entry_t* ifr; __net_ifconf6entry_t* p; - __net_ifconf6entry_t flg; + unsigned int i; *count = 0; /* Assume maximum buffer size allowable */ @@ -335,16 +335,24 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, /* All conditions above must match count loop */ - address->name = uv__strdup(p->__nif6e_name); - - if (p->__nif6e_addr.sin6_family == AF_INET6) - address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr); - else - address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr); + i = 0; + /* Ignore EBCDIC space (0x40) padding in name */ + while (i < ARRAY_SIZE(p->__nif6e_name) && + p->__nif6e_name[i] != 0x40 && + p->__nif6e_name[i] != 0) + ++i; + address->name = uv__malloc(i + 1); + if (address->name == NULL) + return UV_ENOMEM; + memcpy(address->name, p->__nif6e_name, i); + address->name[i] = '\0'; + __e2a_s(address->name); + + address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr); /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ - address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0; + address->is_internal = p->__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0; memset(address->phys_addr, 0, sizeof(address->phys_addr)); address++; } @@ -363,6 +371,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifreq* ifr; struct ifreq* p; int count_v6; + unsigned int i; *count = 0; *addresses = NULL; @@ -455,13 +464,20 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* All conditions above must match count loop */ - address->name = uv__strdup(p->ifr_name); - - if (p->ifr_addr.sa_family == AF_INET6) { - address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); - } else { - address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); - } + i = 0; + /* Ignore EBCDIC space (0x40) padding in name */ + while (i < ARRAY_SIZE(p->ifr_name) && + p->ifr_name[i] != 0x40 && + p->ifr_name[i] != 0) + ++i; + address->name = uv__malloc(i + 1); + if (address->name == NULL) + return UV_ENOMEM; + memcpy(address->name, p->ifr_name, i); + address->name[i] = '\0'; + __e2a_s(address->name); + + address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; memset(address->phys_addr, 0, sizeof(address->phys_addr)); From 524c5ed87d7cce85df7118eb261c7b47c563c7ad Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Tue, 17 May 2022 12:18:54 -0400 Subject: [PATCH 203/713] zos: add uv_interface_addresses() netmask support (#3640 2/3) Use SIOCGIFNETMASK ioctl to retrieve the netmask for IPv4. However, this approach is not supported for IPv6. For IPv6 netmask, z/OS currently only provides the prefix length through the __nif6e_prefixlen in __net_ifconf6entry_t struct, but this can be used to calculate the IPv6 netmask similar to android implementation. Co-authored-by: Igor Todorovski --- src/unix/os390.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index f4ad84ba1b8..07ca7867d7d 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -279,6 +279,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, __net_ifconf6entry_t* ifr; __net_ifconf6entry_t* p; unsigned int i; + unsigned char netmask[16] = {0}; *count = 0; /* Assume maximum buffer size allowable */ @@ -303,8 +304,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, p = ifr; ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen); - if (!(p->__nif6e_addr.sin6_family == AF_INET6 || - p->__nif6e_addr.sin6_family == AF_INET)) + if (!(p->__nif6e_addr.sin6_family == AF_INET6)) continue; if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) @@ -326,8 +326,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, p = ifr; ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen); - if (!(p->__nif6e_addr.sin6_family == AF_INET6 || - p->__nif6e_addr.sin6_family == AF_INET)) + if (!(p->__nif6e_addr.sin6_family == AF_INET6)) continue; if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) @@ -350,7 +349,15 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr); - /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ + for (i = 0; i < (p->__nif6e_prefixlen / 8); i++) + netmask[i] = 0xFF; + + if (p->__nif6e_prefixlen % 8) + netmask[i] = 0xFF << (8 - (p->__nif6e_prefixlen % 8)); + + address->netmask.netmask6.sin6_len = p->__nif6e_prefixlen; + memcpy(&(address->netmask.netmask6.sin6_addr), netmask, 16); + address->netmask.netmask6.sin6_family = AF_INET6; address->is_internal = p->__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0; memset(address->phys_addr, 0, sizeof(address->phys_addr)); @@ -479,6 +486,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); + if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) { + uv__close(sockfd); + return UV__ERR(errno); + } + + address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr); + address->netmask.netmask4.sin_family = AF_INET; address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; memset(address->phys_addr, 0, sizeof(address->phys_addr)); address++; From d938c104e1f27deea44a99f2936ad753eab19d7a Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Tue, 17 May 2022 12:18:18 -0400 Subject: [PATCH 204/713] zos: improve memory management of ip addresses (#3640 3/3) Fixes an issue where under certain conditions, dynamically allocated ip addresses, strings, and buffers were either leaking memory, being incorrectly freed, or not performing error checks. Also fixes an issue where the uv_interface_address_t struct was not correctly initialized to 0, so use calloc() instead of malloc(). Co-authored-by: Igor Todorovski --- src/unix/os390.c | 100 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 19 deletions(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index 07ca7867d7d..7b2fc6aac21 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -279,6 +279,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, __net_ifconf6entry_t* ifr; __net_ifconf6entry_t* p; unsigned int i; + int count_names; unsigned char netmask[16] = {0}; *count = 0; @@ -288,17 +289,27 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) return UV__ERR(errno); + ifc.__nif6h_buffer = uv__calloc(1, maxsize); + + if (ifc.__nif6h_buffer == NULL) { + uv__close(sockfd); + return UV_ENOMEM; + } + ifc.__nif6h_version = 1; ifc.__nif6h_buflen = maxsize; - ifc.__nif6h_buffer = uv__calloc(1, maxsize);; if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) { + /* This will error on a system that does not support IPv6. However, we want + * to treat this as there being 0 interfaces so we can continue to get IPv4 + * interfaces in uv_interface_addresses(). So return 0 instead of the error. + */ + uv__free(ifc.__nif6h_buffer); uv__close(sockfd); - return UV__ERR(errno); + errno = 0; + return 0; } - - *count = 0; ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { p = ifr; @@ -313,14 +324,22 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, ++(*count); } + if ((*count) == 0) { + uv__free(ifc.__nif6h_buffer); + uv__close(sockfd); + return 0; + } + /* Alloc the return interface structs */ - *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); + *addresses = uv__calloc(1, *count * sizeof(uv_interface_address_t)); if (!(*addresses)) { + uv__free(ifc.__nif6h_buffer); uv__close(sockfd); return UV_ENOMEM; } address = *addresses; + count_names = 0; ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { p = ifr; @@ -341,11 +360,16 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, p->__nif6e_name[i] != 0) ++i; address->name = uv__malloc(i + 1); - if (address->name == NULL) + if (address->name == NULL) { + uv_free_interface_addresses(*addresses, count_names); + uv__free(ifc.__nif6h_buffer); + uv__close(sockfd); return UV_ENOMEM; + } memcpy(address->name, p->__nif6e_name, i); address->name[i] = '\0'; __e2a_s(address->name); + count_names++; address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr); @@ -360,10 +384,10 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, address->netmask.netmask6.sin6_family = AF_INET6; address->is_internal = p->__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0; - memset(address->phys_addr, 0, sizeof(address->phys_addr)); address++; } + uv__free(ifc.__nif6h_buffer); uv__close(sockfd); return 0; } @@ -377,15 +401,18 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifreq flg; struct ifreq* ifr; struct ifreq* p; + uv_interface_address_t* addresses_v6; int count_v6; unsigned int i; + int rc; + int count_names; *count = 0; *addresses = NULL; /* get the ipv6 addresses first */ - uv_interface_address_t* addresses_v6; - uv__interface_addresses_v6(&addresses_v6, &count_v6); + if ((rc = uv__interface_addresses_v6(&addresses_v6, &count_v6)) != 0) + return rc; /* now get the ipv4 addresses */ @@ -393,12 +420,27 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { maxsize = 16384; sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - if (0 > sockfd) + if (0 > sockfd) { + if (count_v6) + uv_free_interface_addresses(addresses_v6, count_v6); return UV__ERR(errno); + } ifc.ifc_req = uv__calloc(1, maxsize); + + if (ifc.ifc_req == NULL) { + if (count_v6) + uv_free_interface_addresses(addresses_v6, count_v6); + uv__close(sockfd); + return UV_ENOMEM; + } + ifc.ifc_len = maxsize; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { + if (count_v6) + uv_free_interface_addresses(addresses_v6, count_v6); + uv__free(ifc.ifc_req); uv__close(sockfd); return UV__ERR(errno); } @@ -419,6 +461,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + if (count_v6) + uv_free_interface_addresses(addresses_v6, count_v6); + uv__free(ifc.ifc_req); uv__close(sockfd); return UV__ERR(errno); } @@ -429,27 +474,35 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { (*count)++; } - if (*count == 0) { + if (*count == 0 && count_v6 == 0) { + uv__free(ifc.ifc_req); uv__close(sockfd); return 0; } /* Alloc the return interface structs */ - *addresses = uv__malloc((*count + count_v6) * + *addresses = uv__calloc(1, (*count + count_v6) * sizeof(uv_interface_address_t)); if (!(*addresses)) { + if (count_v6) + uv_free_interface_addresses(addresses_v6, count_v6); + uv__free(ifc.ifc_req); uv__close(sockfd); return UV_ENOMEM; } address = *addresses; - /* copy over the ipv6 addresses */ - memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t)); - address += count_v6; - *count += count_v6; - uv__free(addresses_v6); + /* copy over the ipv6 addresses if any are found */ + if (count_v6) { + memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t)); + address += count_v6; + *count += count_v6; + /* free ipv6 addresses, but keep address names */ + uv__free(addresses_v6); + } + count_names = *count; ifr = ifc.ifc_req; while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { p = ifr; @@ -462,6 +515,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv_free_interface_addresses(*addresses, count_names); + uv__free(ifc.ifc_req); uv__close(sockfd); return UV_ENOSYS; } @@ -478,15 +533,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { p->ifr_name[i] != 0) ++i; address->name = uv__malloc(i + 1); - if (address->name == NULL) + if (address->name == NULL) { + uv_free_interface_addresses(*addresses, count_names); + uv__free(ifc.ifc_req); + uv__close(sockfd); return UV_ENOMEM; + } memcpy(address->name, p->ifr_name, i); address->name[i] = '\0'; __e2a_s(address->name); + count_names++; address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) { + uv_free_interface_addresses(*addresses, count_names); + uv__free(ifc.ifc_req); uv__close(sockfd); return UV__ERR(errno); } @@ -494,13 +556,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr); address->netmask.netmask4.sin_family = AF_INET; address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; - memset(address->phys_addr, 0, sizeof(address->phys_addr)); address++; } #undef ADDR_SIZE #undef MAX + uv__free(ifc.ifc_req); uv__close(sockfd); return 0; } From 8bcd689c048af5aab26842ac5ff903fa3192d57c Mon Sep 17 00:00:00 2001 From: theanarkh <2923878201@qq.com> Date: Sat, 11 Jun 2022 12:32:08 +0800 Subject: [PATCH 205/713] tcp,pipe: fail `bind` or `listen` after `close` (#3641) Return `UV_EINVAL` in `bind` and `listen` when `handle` is `UV_HANDLE_CLOSING` or `UV_HANDLE_CLOSED`. Fixes: https://github.com/libuv/libuv/issues/3503 --- src/unix/pipe.c | 4 +++- src/unix/stream.c | 4 +++- src/uv-common.c | 4 +++- src/win/pipe.c | 4 +++- src/win/stream.c | 4 +++- test/test-list.h | 4 ++++ test/test-pipe-bind-error.c | 16 ++++++++++++++++ test/test-tcp-bind-error.c | 18 ++++++++++++++++++ 8 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index f373c86ea00..e8cfa1481c3 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -51,7 +51,9 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { /* Already bound? */ if (uv__stream_fd(handle) >= 0) return UV_EINVAL; - + if (uv__is_closing(handle)) { + return UV_EINVAL; + } /* Make a copy of the file name, it outlives this function's scope. */ pipe_fname = uv__strdup(name); if (pipe_fname == NULL) diff --git a/src/unix/stream.c b/src/unix/stream.c index 9615673ace8..93c6b9343c9 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -641,7 +641,9 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { int err; - + if (uv__is_closing(stream)) { + return UV_EINVAL; + } switch (stream->type) { case UV_TCP: err = uv__tcp_listen((uv_tcp_t*)stream, backlog, cb); diff --git a/src/uv-common.c b/src/uv-common.c index f43dd3dee7e..efc9eb50ee3 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -295,7 +295,9 @@ int uv_tcp_bind(uv_tcp_t* handle, if (handle->type != UV_TCP) return UV_EINVAL; - + if (uv__is_closing(handle)) { + return UV_EINVAL; + } if (addr->sa_family == AF_INET) addrlen = sizeof(struct sockaddr_in); else if (addr->sa_family == AF_INET6) diff --git a/src/win/pipe.c b/src/win/pipe.c index 67e28300896..08950d6adb3 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -731,7 +731,9 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { if (!name) { return UV_EINVAL; } - + if (uv__is_closing(handle)) { + return UV_EINVAL; + } if (!(handle->flags & UV_HANDLE_PIPESERVER)) { handle->pipe.serv.pending_instances = default_pending_pipe_instances; } diff --git a/src/win/stream.c b/src/win/stream.c index b304d170cc7..19af05683f5 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -29,7 +29,9 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { int err; - + if (uv__is_closing(stream)) { + return UV_EINVAL; + } err = ERROR_INVALID_PARAMETER; switch (stream->type) { case UV_TCP: diff --git a/test/test-list.h b/test/test-list.h index 90393393296..e74c10098b2 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -122,6 +122,7 @@ TEST_DECLARE (tcp_bind_error_inval) TEST_DECLARE (tcp_bind_localhost_ok) TEST_DECLARE (tcp_bind_invalid_flags) TEST_DECLARE (tcp_bind_writable_flags) +TEST_DECLARE (tcp_bind_or_listen_error_after_close) TEST_DECLARE (tcp_listen_without_bind) TEST_DECLARE (tcp_connect_error_fault) TEST_DECLARE (tcp_connect_timeout) @@ -192,6 +193,7 @@ TEST_DECLARE (pipe_bind_error_addrnotavail) TEST_DECLARE (pipe_bind_error_inval) TEST_DECLARE (pipe_connect_multiple) TEST_DECLARE (pipe_listen_without_bind) +TEST_DECLARE (pipe_bind_or_listen_error_after_close) TEST_DECLARE (pipe_connect_bad_name) TEST_DECLARE (pipe_connect_to_file) TEST_DECLARE (pipe_connect_on_prepare) @@ -697,6 +699,7 @@ TASK_LIST_START TEST_ENTRY (tcp_bind_localhost_ok) TEST_ENTRY (tcp_bind_invalid_flags) TEST_ENTRY (tcp_bind_writable_flags) + TEST_ENTRY (tcp_bind_or_listen_error_after_close) TEST_ENTRY (tcp_listen_without_bind) TEST_ENTRY (tcp_connect_error_fault) TEST_ENTRY (tcp_connect_timeout) @@ -775,6 +778,7 @@ TASK_LIST_START TEST_ENTRY (pipe_bind_error_inval) TEST_ENTRY (pipe_connect_multiple) TEST_ENTRY (pipe_listen_without_bind) + TEST_ENTRY (pipe_bind_or_listen_error_after_close) TEST_ENTRY (pipe_getsockname) TEST_ENTRY (pipe_getsockname_abstract) TEST_ENTRY (pipe_getsockname_blocking) diff --git a/test/test-pipe-bind-error.c b/test/test-pipe-bind-error.c index ce35052f537..aacde456543 100644 --- a/test/test-pipe-bind-error.c +++ b/test/test-pipe-bind-error.c @@ -137,3 +137,19 @@ TEST_IMPL(pipe_listen_without_bind) { MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(pipe_bind_or_listen_error_after_close) { + uv_pipe_t server; + + ASSERT_EQ(uv_pipe_init(uv_default_loop(), &server, 0), 0); + uv_close((uv_handle_t*) &server, NULL); + + ASSERT_EQ(uv_pipe_bind(&server, TEST_PIPENAME), UV_EINVAL); + + ASSERT_EQ(uv_listen((uv_stream_t*) &server, SOMAXCONN, NULL), UV_EINVAL); + + ASSERT_EQ(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-bind-error.c b/test/test-tcp-bind-error.c index fdd1fe07450..c3ca6ec824a 100644 --- a/test/test-tcp-bind-error.c +++ b/test/test-tcp-bind-error.c @@ -297,3 +297,21 @@ TEST_IMPL(tcp_bind_writable_flags) { MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(tcp_bind_or_listen_error_after_close) { + uv_tcp_t tcp; + struct sockaddr_in addr; + + memset(&addr, 0, sizeof(addr)); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(9999); + addr.sin_family = AF_INET; + + ASSERT_EQ(uv_tcp_init(uv_default_loop(), &tcp), 0); + uv_close((uv_handle_t*) &tcp, NULL); + ASSERT_EQ(uv_tcp_bind(&tcp, (struct sockaddr*) &addr, 0), UV_EINVAL); + ASSERT_EQ(uv_listen((uv_stream_t*) &tcp, 5, NULL), UV_EINVAL); + ASSERT_EQ(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0); + MAKE_VALGRIND_HAPPY(); + return 0; +} From 0b1c752b5c40a85d5c749cd30ee6811997a8f71e Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Fri, 17 Jun 2022 06:55:44 -0400 Subject: [PATCH 206/713] zos: implement uv_available_parallelism() (#3650) Implement uv_available_parallelism() for z/OS by reporting the number of online cpu using __get_num_online_cpus() from ZOSLIB. --- src/unix/core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index fd4f3480903..54c769f37f2 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -81,7 +81,8 @@ extern char** environ; #endif #if defined(__MVS__) -#include +# include +# include "zos-sys-info.h" #endif #if defined(__linux__) @@ -1647,7 +1648,13 @@ unsigned int uv_available_parallelism(void) { return (unsigned) rc; #elif defined(__MVS__) - return 1; /* TODO(bnoordhuis) Read from CSD_NUMBER_ONLINE_CPUS? */ + int rc; + + rc = __get_num_online_cpus(); + if (rc < 1) + rc = 1; + + return (unsigned) rc; #else /* __linux__ */ long rc; From e3aaff185fa9f48569d61a765c3055894909b2ba Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 17 Jun 2022 16:06:15 -0400 Subject: [PATCH 207/713] udp,win: fix UDP compiler warning (#3647) Previously it would pass a pointer to uninitialized memory to WSASendTo, which triggered a compiler warning. However, `addrlen` will be 0, so it seems unlikely to trigger an error or uninitialized memory access. Refs: https://github.com/libuv/leps/pull/10 Refs: https://github.com/libuv/libuv/pull/1872 Refs: https://github.com/libuv/libuv/pull/2217 --- src/win/udp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/win/udp.c b/src/win/udp.c index c99cb0fec02..eaebc1eda8f 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -1146,6 +1146,7 @@ int uv__udp_try_send(uv_udp_t* handle, err = uv__convert_to_localhost_if_unspecified(addr, &converted); if (err) return err; + addr = (const struct sockaddr*) &converted; } /* Already sending a message.*/ @@ -1169,7 +1170,7 @@ int uv__udp_try_send(uv_udp_t* handle, nbufs, &bytes, 0, - (const struct sockaddr*) &converted, + addr, addrlen, NULL, NULL); From 27eec099d60a3aa8a9e4e14906a6f79f98d1e67f Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Tue, 28 Jun 2022 23:42:11 -0400 Subject: [PATCH 208/713] zos: fix early exit of epoll_wait() (#3653) This fixes an early exit bug in z/OS implementation of epoll_wait(), resulting in some file events not being correctly captured. The problem is that reventcount should only be incremented by 1, because _NFDS counts as 1 even for fds with multiple revents set. Also makes a few minor improvements to remove redundant checks. Co-authored-by: Igor Todorovski --- src/unix/os390-syscalls.c | 36 +++++++++++++++++++----------------- src/unix/os390.c | 1 - 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c index a74112701a4..5861aaaa202 100644 --- a/src/unix/os390-syscalls.c +++ b/src/unix/os390-syscalls.c @@ -284,6 +284,8 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, nmsgsfds_t size; struct pollfd* pfds; int pollret; + int pollfdret; + int pollmsgret; int reventcount; int nevents; struct pollfd msg_fd; @@ -304,24 +306,24 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, return -1; } - if (lst->size > 0) - _SET_FDS_MSGS(size, 1, lst->size - 1); - else - _SET_FDS_MSGS(size, 0, 0); + assert(lst->size > 0); + _SET_FDS_MSGS(size, 1, lst->size - 1); pfds = lst->items; pollret = poll(pfds, size, timeout); if (pollret <= 0) return pollret; - assert(lst->size > 0); - - pollret = _NFDS(pollret) + _NMSGS(pollret); + pollfdret = _NFDS(pollret); + pollmsgret = _NMSGS(pollret); reventcount = 0; nevents = 0; - msg_fd = pfds[lst->size - 1]; + msg_fd = pfds[lst->size - 1]; /* message queue is always last entry */ + maxevents = maxevents - pollmsgret; /* allow spot for message queue */ for (i = 0; - i < lst->size && i < maxevents && reventcount < pollret; ++i) { + i < lst->size - 1 && + nevents < maxevents && + reventcount < pollfdret; ++i) { struct epoll_event ev; struct pollfd* pfd; @@ -332,18 +334,18 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, ev.fd = pfd->fd; ev.events = pfd->revents; ev.is_msg = 0; - if (pfd->revents & POLLIN && pfd->revents & POLLOUT) - reventcount += 2; - else if (pfd->revents & (POLLIN | POLLOUT)) - ++reventcount; - pfd->revents = 0; + reventcount++; events[nevents++] = ev; } - if (msg_fd.revents != 0 && msg_fd.fd != -1) - if (i == lst->size) - events[nevents - 1].is_msg = 1; + if (pollmsgret > 0 && msg_fd.revents != 0 && msg_fd.fd != -1) { + struct epoll_event ev; + ev.fd = msg_fd.fd; + ev.events = msg_fd.revents; + ev.is_msg = 1; + events[nevents++] = ev; + } return nevents; } diff --git a/src/unix/os390.c b/src/unix/os390.c index 7b2fc6aac21..e8e388b1740 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -1030,6 +1030,5 @@ int uv__io_fork(uv_loop_t* loop) { */ loop->ep = NULL; - uv__platform_loop_delete(loop); return uv__platform_loop_init(loop); } From 2108309302ec66c71646b762ee32d8ef0ad9618e Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 29 Jun 2022 05:42:52 +0200 Subject: [PATCH 209/713] unix,tcp: fix errno handling in uv__tcp_bind() (#3652) The errno value is only meaningful if bind() fails and returns -1. Some bind() implementations may return success but modify errno value internally, like the socket_wrapper library used by the Samba testsuite. --- src/unix/tcp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 789807f05d2..f1040e98797 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -184,14 +184,15 @@ int uv__tcp_bind(uv_tcp_t* tcp, #endif errno = 0; - if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) { + err = bind(tcp->io_watcher.fd, addr, addrlen); + if (err == -1 && errno != EADDRINUSE) { if (errno == EAFNOSUPPORT) /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a * socket created with AF_INET to an AF_INET6 address or vice versa. */ return UV_EINVAL; return UV__ERR(errno); } - tcp->delayed_error = UV__ERR(errno); + tcp->delayed_error = (err == -1) ? UV__ERR(errno) : 0; tcp->flags |= UV_HANDLE_BOUND; if (addr->sa_family == AF_INET6) From 1a91b51976a1adc6972081faa78b6b70022254d3 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 28 Jun 2022 23:44:03 -0400 Subject: [PATCH 210/713] shutdown,unix: reduce code duplication (#3648) The UV_ECANCELED codepath had an incorrect comment, and the implementation was generally less robust (for example, not checking if `cb` was NULL), so we can merge these codepaths for cleaner code. --- src/unix/stream.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 93c6b9343c9..9c0d6e70d4b 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -66,6 +66,7 @@ static void uv__read(uv_stream_t* stream); static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); static void uv__write_callbacks(uv_stream_t* stream); static size_t uv__write_req_size(uv_write_t* req); +static void uv__drain(uv_stream_t* stream); void uv__stream_init(uv_loop_t* loop, @@ -453,17 +454,7 @@ void uv__stream_destroy(uv_stream_t* stream) { uv__stream_flush_write_queue(stream, UV_ECANCELED); uv__write_callbacks(stream); - - if (stream->shutdown_req) { - /* The ECANCELED error code is a lie, the shutdown(2) syscall is a - * fait accompli at this point. Maybe we should revisit this in v0.11. - * A possible reason for leaving it unchanged is that it informs the - * callee that the handle has been destroyed. - */ - uv__req_unregister(stream->loop, stream->shutdown_req); - stream->shutdown_req->cb(stream->shutdown_req, UV_ECANCELED); - stream->shutdown_req = NULL; - } + uv__drain(stream); assert(stream->write_queue_size == 0); } @@ -668,26 +659,31 @@ static void uv__drain(uv_stream_t* stream) { uv_shutdown_t* req; int err; + if (!(stream->flags & UV_HANDLE_SHUTTING)) + return; + assert(QUEUE_EMPTY(&stream->write_queue)); - uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); - uv__stream_osx_interrupt_select(stream); + req = stream->shutdown_req; + assert(req); - /* Shutdown? */ - if ((stream->flags & UV_HANDLE_SHUTTING) && - !(stream->flags & UV_HANDLE_CLOSING) && - !(stream->flags & UV_HANDLE_SHUT)) { - assert(stream->shutdown_req); + if (!(stream->flags & UV_HANDLE_CLOSING)) { + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + uv__stream_osx_interrupt_select(stream); + } - req = stream->shutdown_req; + if ((stream->flags & UV_HANDLE_CLOSING) || + !(stream->flags & UV_HANDLE_SHUT)) { stream->shutdown_req = NULL; stream->flags &= ~UV_HANDLE_SHUTTING; uv__req_unregister(stream->loop, req); err = 0; - if (shutdown(uv__stream_fd(stream), SHUT_WR)) + if (stream->flags & UV_HANDLE_CLOSING) + /* The user destroyed the stream before we got to do the shutdown. */ + err = UV_ECANCELED; + else if (shutdown(uv__stream_fd(stream), SHUT_WR)) err = UV__ERR(errno); - - if (err == 0) + else /* Success. */ stream->flags |= UV_HANDLE_SHUT; if (req->cb != NULL) From 3136561cd0f68447bd72b4e0796f894637f169c3 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 6 Jul 2022 07:02:05 +0200 Subject: [PATCH 211/713] unix: fix c99 comments (#3667) Causes compilation errors for people that build libuv with a C89 compiler. Refs: https://github.com/libuv/libuv/discussions/3666 --- src/unix/stream.c | 1 - src/unix/tty.c | 28 +++++++++++++++------------- src/unix/udp.c | 9 +++++---- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 9c0d6e70d4b..74430caa218 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -924,7 +924,6 @@ static void uv__write(uv_stream_t* stream) { } req->error = n; - // XXX(jwn): this must call uv__stream_flush_write_queue(stream, n) here, since we won't generate any more events uv__write_req_finish(req); uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); diff --git a/src/unix/tty.c b/src/unix/tty.c index f34e1ef1896..690e591a298 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -344,13 +344,14 @@ uv_handle_type uv_guess_handle(uv_file file) { if (fstat(file, &s)) { #if defined(__PASE__) - // On ibmi receiving RST from TCP instead of FIN immediately puts fd into - // an error state. fstat will return EINVAL, getsockname will also return - // EINVAL, even if sockaddr_storage is valid. (If file does not refer to a - // socket, ENOTSOCK is returned instead.) - // In such cases, we will permit the user to open the connection as uv_tcp - // still, so that the user can get immediately notified of the error in - // their read callback and close this fd. + /* On ibmi receiving RST from TCP instead of FIN immediately puts fd into + * an error state. fstat will return EINVAL, getsockname will also return + * EINVAL, even if sockaddr_storage is valid. (If file does not refer to a + * socket, ENOTSOCK is returned instead.) + * In such cases, we will permit the user to open the connection as uv_tcp + * still, so that the user can get immediately notified of the error in + * their read callback and close this fd. + */ len = sizeof(ss); if (getsockname(file, (struct sockaddr*) &ss, &len)) { if (errno == EINVAL) @@ -375,12 +376,13 @@ uv_handle_type uv_guess_handle(uv_file file) { len = sizeof(ss); if (getsockname(file, (struct sockaddr*) &ss, &len)) { #if defined(_AIX) - // On aix receiving RST from TCP instead of FIN immediately puts fd into - // an error state. In such case getsockname will return EINVAL, even if - // sockaddr_storage is valid. - // In such cases, we will permit the user to open the connection as uv_tcp - // still, so that the user can get immediately notified of the error in - // their read callback and close this fd. + /* On aix receiving RST from TCP instead of FIN immediately puts fd into + * an error state. In such case getsockname will return EINVAL, even if + * sockaddr_storage is valid. + * In such cases, we will permit the user to open the connection as uv_tcp + * still, so that the user can get immediately notified of the error in + * their read callback and close this fd. + */ if (errno == EINVAL) { return UV_TCP; } diff --git a/src/unix/udp.c b/src/unix/udp.c index d9c15e4effd..4d985b88ba9 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -705,10 +705,11 @@ int uv__udp_disconnect(uv_udp_t* handle) { do { errno = 0; #ifdef __PASE__ - // On IBMi a connectionless transport socket can be disconnected by - // either setting the addr parameter to NULL or setting the - // addr_length parameter to zero, and issuing another connect(). - // https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/connec.htm + /* On IBMi a connectionless transport socket can be disconnected by + * either setting the addr parameter to NULL or setting the + * addr_length parameter to zero, and issuing another connect(). + * https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/connec.htm + */ r = connect(handle->io_watcher.fd, (struct sockaddr*) NULL, 0); #else r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr)); From 7ca20a2679a9d9bc840aa0fb138f32662779ffbf Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 6 Jul 2022 07:41:51 +0200 Subject: [PATCH 212/713] unix: retry tcgetattr/tcsetattr() on EINTR (#3669) EINTR is explicitly documented as a possible error code of tcsetattr(). The documentation for tcgetattr() is silent on the subject but better safe than sorry. Fixes: https://github.com/libuv/libuv/issues/3645 --- src/unix/tty.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/unix/tty.c b/src/unix/tty.c index 690e591a298..b41505258ff 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -66,6 +66,19 @@ static int orig_termios_fd = -1; static struct termios orig_termios; static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; +int uv__tcsetattr(int fd, int how, const struct termios *term) { + int rc; + + do + rc = tcsetattr(fd, how, term); + while (rc == -1 && errno == EINTR); + + if (rc == -1) + return UV__ERR(errno); + + return 0; +} + static int uv__tty_is_slave(const int fd) { int result; #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) @@ -268,13 +281,18 @@ static void uv__tty_make_raw(struct termios* tio) { int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { struct termios tmp; int fd; + int rc; if (tty->mode == (int) mode) return 0; fd = uv__stream_fd(tty); if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) { - if (tcgetattr(fd, &tty->orig_termios)) + do + rc = tcgetattr(fd, &tty->orig_termios); + while (rc == -1 && errno == EINTR); + + if (rc == -1) return UV__ERR(errno); /* This is used for uv_tty_reset_mode() */ @@ -304,11 +322,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { } /* Apply changes after draining */ - if (tcsetattr(fd, TCSADRAIN, &tmp)) - return UV__ERR(errno); + rc = uv__tcsetattr(fd, TCSADRAIN, &tmp); + if (rc == 0) + tty->mode = mode; - tty->mode = mode; - return 0; + return rc; } @@ -432,8 +450,7 @@ int uv_tty_reset_mode(void) { err = 0; if (orig_termios_fd != -1) - if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios)) - err = UV__ERR(errno); + err = uv__tcsetattr(orig_termios_fd, TCSANOW, &orig_termios); uv_spinlock_unlock(&termios_spinlock); errno = saved_errno; From f1635257cbabc683877619365f56deb92d4427a0 Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Fri, 8 Jul 2022 03:07:29 +0900 Subject: [PATCH 213/713] docs: update introduction.rst (#3664) Github -> GitHub --- docs/src/guide/introduction.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/guide/introduction.rst b/docs/src/guide/introduction.rst index 819e9f759f3..91f0fa55818 100644 --- a/docs/src/guide/introduction.rst +++ b/docs/src/guide/introduction.rst @@ -53,7 +53,7 @@ Code ---- All the example code and the source of the book is included as part of -the libuv_ project on Github. +the libuv_ project on GitHub. Clone or Download libuv_, then build it:: sh autogen.sh From 6999994def3b05ae1ed5edf594642d975e3bed05 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 7 Jul 2022 15:24:35 -0400 Subject: [PATCH 214/713] unix,stream: optimize uv_shutdown() codepath (#3646) Once the write queue is empty, we can fire the event immediately, without needing a lot of syscalls and then waiting for the kernel to feed us the event on the next tick. This also makes it more similar to how it would behave if there was a write still in the queue also, which we dispatch later in the same event loop iteration, then drain. --- src/unix/stream.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 74430caa218..b08878800eb 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1232,7 +1232,8 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { assert(uv__stream_fd(stream) >= 0); - /* Initialize request */ + /* Initialize request. The `shutdown(2)` call will always be deferred until + * `uv__drain`, just before the callback is run. */ uv__req_init(stream->loop, req, UV_SHUTDOWN); req->handle = stream; req->cb = cb; @@ -1240,8 +1241,8 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { stream->flags |= UV_HANDLE_SHUTTING; stream->flags &= ~UV_HANDLE_WRITABLE; - uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); - uv__stream_osx_interrupt_select(stream); + if (QUEUE_EMPTY(&stream->write_queue)) + uv__io_feed(stream->loop, &stream->io_watcher); return 0; } From c4d73c306b87e32acba3a77f933da72ac5604659 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Thu, 7 Jul 2022 18:21:37 -0400 Subject: [PATCH 215/713] zos: delay signal handling until after normal i/o (#3643) Port the changes made to AIX and other unix systems in #611 to z/OS. Defers the signal watcher that is used for process management until after the dispatch of regular i/o watchers. Refs: https://github.com/libuv/libuv/pull/611 Co-authored-by: Igor Todorovski --- src/unix/os390.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index e8e388b1740..3b16318ce28 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -807,6 +807,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { struct epoll_event* pe; struct epoll_event e; uv__os390_epoll* ep; + int have_signals; int real_timeout; QUEUE* q; uv__io_t* w; @@ -869,6 +870,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { count = 48; /* Benchmarks suggest this gives the best throughput. */ real_timeout = timeout; int nevents = 0; + have_signals = 0; if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { reset_timeout = 1; @@ -983,19 +985,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { pe->events |= w->pevents & (POLLIN | POLLOUT); if (pe->events != 0) { - uv__metrics_update_idle_time(loop); - w->cb(loop, w, pe->events); + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) { + have_signals = 1; + } else { + uv__metrics_update_idle_time(loop); + w->cb(loop, w, pe->events); + } nevents++; } } - loop->watchers[loop->nwatchers] = NULL; - loop->watchers[loop->nwatchers + 1] = NULL; if (reset_timeout != 0) { timeout = user_timeout; reset_timeout = 0; } + if (have_signals != 0) { + uv__metrics_update_idle_time(loop); + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + } + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ From 47e95602c45876a470430b85f98fddeb4e3ebe39 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 11 Jul 2022 12:24:49 -0400 Subject: [PATCH 216/713] stream: uv__drain() always needs to stop POLLOUT (#3675) Regression caused by 1a91b51976a1adc6972081faa78b6b70022254d3 mistake. Refs: https://github.com/libuv/libuv/pull/3648 Fixes: https://github.com/libuv/libuv/pull/3648/3671 --- src/unix/stream.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index b08878800eb..b1f6359e0de 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -659,18 +659,18 @@ static void uv__drain(uv_stream_t* stream) { uv_shutdown_t* req; int err; - if (!(stream->flags & UV_HANDLE_SHUTTING)) - return; - assert(QUEUE_EMPTY(&stream->write_queue)); - req = stream->shutdown_req; - assert(req); - if (!(stream->flags & UV_HANDLE_CLOSING)) { uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); } + if (!(stream->flags & UV_HANDLE_SHUTTING)) + return; + + req = stream->shutdown_req; + assert(req); + if ((stream->flags & UV_HANDLE_CLOSING) || !(stream->flags & UV_HANDLE_SHUT)) { stream->shutdown_req = NULL; From f5e4d85cd25889f4afb3ddbc1649fe34438ef517 Mon Sep 17 00:00:00 2001 From: Stacey Marshall Date: Mon, 11 Jul 2022 17:29:25 +0100 Subject: [PATCH 217/713] unix,tcp: allow EINVAL errno from setsockopt in uv_tcp_close_reset() (#3662) Some setsockopt() implememantations may return with errno of EINVAL when the socket has been shut down already, as documented in the Open Group Specifications Issue 7, 2018. When this happens, reset errno and continue to mark the socket closed and handle any callback. --- src/unix/tcp.c | 12 ++++++++-- test/test-list.h | 2 ++ test/test-tcp-close-reset.c | 46 +++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index f1040e98797..73fc657a86d 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -321,8 +321,16 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) { return UV_EINVAL; fd = uv__stream_fd(handle); - if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l))) - return UV__ERR(errno); + if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l))) { + if (errno == EINVAL) { + /* Open Group Specifications Issue 7, 2018 edition states that + * EINVAL may mean the socket has been shut down already. + * Behavior observed on Solaris, illumos and macOS. */ + errno = 0; + } else { + return UV__ERR(errno); + } + } uv_close((uv_handle_t*) handle, close_cb); return 0; diff --git a/test/test-list.h b/test/test-list.h index e74c10098b2..b19c10c7e40 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -133,6 +133,7 @@ TEST_DECLARE (tcp_close_after_read_timeout) TEST_DECLARE (tcp_close) TEST_DECLARE (tcp_close_reset_accepted) TEST_DECLARE (tcp_close_reset_accepted_after_shutdown) +TEST_DECLARE (tcp_close_reset_accepted_after_socket_shutdown) TEST_DECLARE (tcp_close_reset_client) TEST_DECLARE (tcp_close_reset_client_after_shutdown) TEST_DECLARE (tcp_create_early) @@ -710,6 +711,7 @@ TASK_LIST_START TEST_ENTRY (tcp_close) TEST_ENTRY (tcp_close_reset_accepted) TEST_ENTRY (tcp_close_reset_accepted_after_shutdown) + TEST_ENTRY (tcp_close_reset_accepted_after_socket_shutdown) TEST_ENTRY (tcp_close_reset_client) TEST_ENTRY (tcp_close_reset_client_after_shutdown) TEST_ENTRY (tcp_create_early) diff --git a/test/test-tcp-close-reset.c b/test/test-tcp-close-reset.c index 7ca55c4c7f9..66dfc82eb47 100644 --- a/test/test-tcp-close-reset.c +++ b/test/test-tcp-close-reset.c @@ -25,6 +25,12 @@ #include #include /* memset */ +#ifdef _WIN32 +# define INVALID_FD (INVALID_HANDLE_VALUE) +#else +# define INVALID_FD (-1) +#endif + static uv_loop_t* loop; static uv_tcp_t tcp_server; static uv_tcp_t tcp_client; @@ -62,9 +68,22 @@ static void do_write(uv_tcp_t* handle) { static void do_close(uv_tcp_t* handle) { + uv_os_fd_t fd; + int r; + if (shutdown_before_close == 1) { ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) handle, shutdown_cb)); ASSERT(UV_EINVAL == uv_tcp_close_reset(handle, close_cb)); + } else if (shutdown_before_close == 2) { + r = uv_fileno((const uv_handle_t*) handle, &fd); + ASSERT_EQ(r, 0); + ASSERT_NE(fd, INVALID_FD); +#ifdef _WIN32 + ASSERT_EQ(0, shutdown(fd, SD_BOTH)); +#else + ASSERT_EQ(0, shutdown(fd, SHUT_RDWR)); +#endif + ASSERT_EQ(0, uv_tcp_close_reset(handle, close_cb)); } else { ASSERT(0 == uv_tcp_close_reset(handle, close_cb)); ASSERT(UV_ENOTCONN == uv_shutdown(&shutdown_req, (uv_stream_t*) handle, shutdown_cb)); @@ -288,3 +307,30 @@ TEST_IMPL(tcp_close_reset_accepted_after_shutdown) { MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(tcp_close_reset_accepted_after_socket_shutdown) { + int r; + + loop = uv_default_loop(); + + start_server(loop, &tcp_server); + + client_close = 0; + shutdown_before_close = 2; + + do_connect(loop, &tcp_client); + + ASSERT_EQ(write_cb_called, 0); + ASSERT_EQ(close_cb_called, 0); + ASSERT_EQ(shutdown_cb_called, 0); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT_EQ(r, 0); + + ASSERT_EQ(write_cb_called, 4); + ASSERT_EQ(close_cb_called, 1); + ASSERT_EQ(shutdown_cb_called, 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From ee970e38a6325d9cbc0dbd4b90e813c0a27dd8a8 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 11 Jul 2022 12:30:20 -0400 Subject: [PATCH 218/713] win,shutdown: improve how shutdown is dispatched (#3649) Split this off from endgame, so that it can be handled separately and earlier, rather than trying to detect inside endgame which case we are in. There appear to be some race conditions on the `handle` field still however, which this does not yet attempt to address. --- src/win/internal.h | 9 +- src/win/pipe.c | 284 +++++++++++++++++++++------------------------ src/win/req-inl.h | 7 +- src/win/stream.c | 7 +- src/win/tcp.c | 127 ++++++++++---------- src/win/tty.c | 66 ++++++----- 6 files changed, 246 insertions(+), 254 deletions(-) diff --git a/src/win/internal.h b/src/win/internal.h index 17e399be5c7..89c72b8a1a6 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -88,6 +88,9 @@ void uv__process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req); void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, uv_connect_t* req); +void uv__process_tcp_shutdown_req(uv_loop_t* loop, + uv_tcp_t* stream, + uv_shutdown_t* req); void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp); void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); @@ -130,6 +133,7 @@ int uv__pipe_write(uv_loop_t* loop, size_t nbufs, uv_stream_t* send_handle, uv_write_cb cb); +void uv__pipe_shutdown(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req); void uv__process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, uv_req_t* req); @@ -143,7 +147,6 @@ void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req); void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle); -void uv__pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle); void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); @@ -177,7 +180,9 @@ void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, */ void uv__process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, uv_connect_t* req); - +void uv__process_tty_shutdown_req(uv_loop_t* loop, + uv_tty_t* stream, + uv_shutdown_t* req); void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle); diff --git a/src/win/pipe.c b/src/win/pipe.c index 08950d6adb3..998461811fb 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -578,135 +578,109 @@ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) { } -void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { - int err; +void uv__pipe_shutdown(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t *req) { DWORD result; - uv_shutdown_t* req; NTSTATUS nt_status; IO_STATUS_BLOCK io_status; FILE_PIPE_LOCAL_INFORMATION pipe_info; - uv__ipc_xfer_queue_item_t* xfer_queue_item; - if ((handle->flags & UV_HANDLE_CONNECTION) && - handle->stream.conn.shutdown_req != NULL && - handle->stream.conn.write_reqs_pending == 0) { - req = handle->stream.conn.shutdown_req; - - /* Clear the shutdown_req field so we don't go here again. */ - handle->stream.conn.shutdown_req = NULL; - - if (handle->flags & UV_HANDLE_CLOSING) { - UNREGISTER_HANDLE_REQ(loop, handle, req); - - /* Already closing. Cancel the shutdown. */ - if (req->cb) { - req->cb(req, UV_ECANCELED); - } - - DECREASE_PENDING_REQ_COUNT(handle); - return; - } - - /* Try to avoid flushing the pipe buffer in the thread pool. */ - nt_status = pNtQueryInformationFile(handle->handle, - &io_status, - &pipe_info, - sizeof pipe_info, - FilePipeLocalInformation); - - if (nt_status != STATUS_SUCCESS) { - /* Failure */ - UNREGISTER_HANDLE_REQ(loop, handle, req); - - handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */ - if (req->cb) { - err = pRtlNtStatusToDosError(nt_status); - req->cb(req, uv_translate_sys_error(err)); - } - - DECREASE_PENDING_REQ_COUNT(handle); - return; - } + assert(handle->flags & UV_HANDLE_CONNECTION); + assert(req != NULL); + assert(handle->stream.conn.write_reqs_pending == 0); + SET_REQ_SUCCESS(req); - if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) { - /* Short-circuit, no need to call FlushFileBuffers. */ - uv__insert_pending_req(loop, (uv_req_t*) req); - return; - } + if (handle->flags & UV_HANDLE_CLOSING) { + uv__insert_pending_req(loop, (uv_req_t*) req); + return; + } - /* Run FlushFileBuffers in the thread pool. */ - result = QueueUserWorkItem(pipe_shutdown_thread_proc, - req, - WT_EXECUTELONGFUNCTION); - if (result) { - return; + /* Try to avoid flushing the pipe buffer in the thread pool. */ + nt_status = pNtQueryInformationFile(handle->handle, + &io_status, + &pipe_info, + sizeof pipe_info, + FilePipeLocalInformation); - } else { - /* Failure. */ - UNREGISTER_HANDLE_REQ(loop, handle, req); + if (nt_status != STATUS_SUCCESS) { + SET_REQ_ERROR(req, pRtlNtStatusToDosError(nt_status)); + handle->flags |= UV_HANDLE_WRITABLE; /* Questionable. */ + uv__insert_pending_req(loop, (uv_req_t*) req); + return; + } - handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */ - if (req->cb) { - err = GetLastError(); - req->cb(req, uv_translate_sys_error(err)); - } + if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) { + /* Short-circuit, no need to call FlushFileBuffers: + * all writes have been read. */ + uv__insert_pending_req(loop, (uv_req_t*) req); + return; + } - DECREASE_PENDING_REQ_COUNT(handle); - return; - } + /* Run FlushFileBuffers in the thread pool. */ + result = QueueUserWorkItem(pipe_shutdown_thread_proc, + req, + WT_EXECUTELONGFUNCTION); + if (!result) { + SET_REQ_ERROR(req, GetLastError()); + handle->flags |= UV_HANDLE_WRITABLE; /* Questionable. */ + uv__insert_pending_req(loop, (uv_req_t*) req); + return; } +} - if (handle->flags & UV_HANDLE_CLOSING && - handle->reqs_pending == 0) { - assert(!(handle->flags & UV_HANDLE_CLOSED)); - if (handle->flags & UV_HANDLE_CONNECTION) { - /* Free pending sockets */ - while (!QUEUE_EMPTY(&handle->pipe.conn.ipc_xfer_queue)) { - QUEUE* q; - SOCKET socket; +void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { + uv__ipc_xfer_queue_item_t* xfer_queue_item; - q = QUEUE_HEAD(&handle->pipe.conn.ipc_xfer_queue); - QUEUE_REMOVE(q); - xfer_queue_item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member); + assert(handle->reqs_pending == 0); + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); - /* Materialize socket and close it */ - socket = WSASocketW(FROM_PROTOCOL_INFO, - FROM_PROTOCOL_INFO, - FROM_PROTOCOL_INFO, - &xfer_queue_item->xfer_info.socket_info, - 0, - WSA_FLAG_OVERLAPPED); - uv__free(xfer_queue_item); + if (handle->flags & UV_HANDLE_CONNECTION) { + /* Free pending sockets */ + while (!QUEUE_EMPTY(&handle->pipe.conn.ipc_xfer_queue)) { + QUEUE* q; + SOCKET socket; + + q = QUEUE_HEAD(&handle->pipe.conn.ipc_xfer_queue); + QUEUE_REMOVE(q); + xfer_queue_item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member); + + /* Materialize socket and close it */ + socket = WSASocketW(FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + &xfer_queue_item->xfer_info.socket_info, + 0, + WSA_FLAG_OVERLAPPED); + uv__free(xfer_queue_item); + + if (socket != INVALID_SOCKET) + closesocket(socket); + } + handle->pipe.conn.ipc_xfer_queue_length = 0; - if (socket != INVALID_SOCKET) - closesocket(socket); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(handle->read_req.wait_handle); + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; } - handle->pipe.conn.ipc_xfer_queue_length = 0; - - if (handle->flags & UV_HANDLE_EMULATE_IOCP) { - if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { - UnregisterWait(handle->read_req.wait_handle); - handle->read_req.wait_handle = INVALID_HANDLE_VALUE; - } - if (handle->read_req.event_handle != NULL) { - CloseHandle(handle->read_req.event_handle); - handle->read_req.event_handle = NULL; - } + if (handle->read_req.event_handle != NULL) { + CloseHandle(handle->read_req.event_handle); + handle->read_req.event_handle = NULL; } - - if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) - DeleteCriticalSection(&handle->pipe.conn.readfile_thread_lock); } - if (handle->flags & UV_HANDLE_PIPESERVER) { - assert(handle->pipe.serv.accept_reqs); - uv__free(handle->pipe.serv.accept_reqs); - handle->pipe.serv.accept_reqs = NULL; - } + if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) + DeleteCriticalSection(&handle->pipe.conn.readfile_thread_lock); + } - uv__handle_close(handle); + if (handle->flags & UV_HANDLE_PIPESERVER) { + assert(handle->pipe.serv.accept_reqs); + uv__free(handle->pipe.serv.accept_reqs); + handle->pipe.serv.accept_reqs = NULL; } + + uv__handle_close(handle); } @@ -979,17 +953,30 @@ void uv__pipe_interrupt_read(uv_pipe_t* handle) { void uv__pipe_read_stop(uv_pipe_t* handle) { handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(handle->loop, handle); - uv__pipe_interrupt_read(handle); } /* Cleans up uv_pipe_t (server or connection) and all resources associated with * it. */ -void uv__pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { +void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { int i; HANDLE pipeHandle; + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); + + uv__handle_closing(handle); + uv__pipe_interrupt_read(handle); if (handle->name) { @@ -1009,35 +996,17 @@ void uv__pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { } if (handle->flags & UV_HANDLE_CONNECTION) { - handle->flags &= ~UV_HANDLE_WRITABLE; eof_timer_destroy(handle); } if ((handle->flags & UV_HANDLE_CONNECTION) - && handle->handle != INVALID_HANDLE_VALUE) + && handle->handle != INVALID_HANDLE_VALUE) { + /* This will eventually destroy the write queue for us too. */ close_pipe(handle); -} - - -void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { - if (handle->flags & UV_HANDLE_READING) { - handle->flags &= ~UV_HANDLE_READING; - DECREASE_ACTIVE_COUNT(loop, handle); } - if (handle->flags & UV_HANDLE_LISTENING) { - handle->flags &= ~UV_HANDLE_LISTENING; - DECREASE_ACTIVE_COUNT(loop, handle); - } - - uv__pipe_cleanup(loop, handle); - - if (handle->reqs_pending == 0) { + if (handle->reqs_pending == 0) uv__want_endgame(loop, (uv_handle_t*) handle); - } - - handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); - uv__handle_closing(handle); } @@ -2100,10 +2069,9 @@ void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, uv__queue_non_overlapped_write(handle); } - if (handle->stream.conn.shutdown_req != NULL && - handle->stream.conn.write_reqs_pending == 0) { - uv__want_endgame(loop, (uv_handle_t*)handle); - } + if (handle->stream.conn.write_reqs_pending == 0) + if (handle->flags & UV_HANDLE_SHUTTING) + uv__pipe_shutdown(loop, handle, handle->stream.conn.shutdown_req); DECREASE_PENDING_REQ_COUNT(handle); } @@ -2116,7 +2084,7 @@ void uv__process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, assert(handle->type == UV_NAMED_PIPE); if (handle->flags & UV_HANDLE_CLOSING) { - /* The req->pipeHandle should be freed already in uv__pipe_cleanup(). */ + /* The req->pipeHandle should be freed already in uv__pipe_close(). */ assert(req->pipeHandle == INVALID_HANDLE_VALUE); DECREASE_PENDING_REQ_COUNT(handle); return; @@ -2172,32 +2140,46 @@ void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, } + void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req) { + int err; + assert(handle->type == UV_NAMED_PIPE); + /* Clear the shutdown_req field so we don't go here again. */ + handle->stream.conn.shutdown_req = NULL; + handle->flags &= ~UV_HANDLE_SHUTTING; UNREGISTER_HANDLE_REQ(loop, handle, req); - if (handle->flags & UV_HANDLE_READABLE) { - /* Initialize and optionally start the eof timer. Only do this if the pipe - * is readable and we haven't seen EOF come in ourselves. */ - eof_timer_init(handle); + if (handle->flags & UV_HANDLE_CLOSING) { + /* Already closing. Cancel the shutdown. */ + err = UV_ECANCELED; + } else if (!REQ_SUCCESS(req)) { + /* An error occurred in trying to shutdown gracefully. */ + err = uv_translate_sys_error(GET_REQ_ERROR(req)); + } else { + if (handle->flags & UV_HANDLE_READABLE) { + /* Initialize and optionally start the eof timer. Only do this if the pipe + * is readable and we haven't seen EOF come in ourselves. */ + eof_timer_init(handle); + + /* If reading start the timer right now. Otherwise uv__pipe_queue_read will + * start it. */ + if (handle->flags & UV_HANDLE_READ_PENDING) { + eof_timer_start(handle); + } - /* If reading start the timer right now. Otherwise uv__pipe_queue_read will - * start it. */ - if (handle->flags & UV_HANDLE_READ_PENDING) { - eof_timer_start(handle); + } else { + /* This pipe is not readable. We can just close it to let the other end + * know that we're done writing. */ + close_pipe(handle); } - - } else { - /* This pipe is not readable. We can just close it to let the other end - * know that we're done writing. */ - close_pipe(handle); + err = 0; } - if (req->cb) { - req->cb(req, 0); - } + if (req->cb) + req->cb(req, err); DECREASE_PENDING_REQ_COUNT(handle); } diff --git a/src/win/req-inl.h b/src/win/req-inl.h index 48760a06bbe..9e2075906f5 100644 --- a/src/win/req-inl.h +++ b/src/win/req-inl.h @@ -172,12 +172,7 @@ INLINE static void uv__process_reqs(uv_loop_t* loop) { break; case UV_SHUTDOWN: - /* Tcp shutdown requests don't come here. */ - assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE); - uv__process_pipe_shutdown_req( - loop, - (uv_pipe_t*) ((uv_shutdown_t*) req)->handle, - (uv_shutdown_t*) req); + DELEGATE_STREAM_REQ(loop, (uv_shutdown_t*) req, shutdown, handle); break; case UV_UDP_RECV: diff --git a/src/win/stream.c b/src/win/stream.c index 19af05683f5..292bf588da6 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -219,7 +219,12 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); - uv__want_endgame(loop, (uv_handle_t*)handle); + if (handle->stream.conn.write_reqs_pending == 0) { + if (handle->type == UV_NAMED_PIPE) + uv__pipe_shutdown(loop, (uv_pipe_t*) handle, req); + else + uv__insert_pending_req(loop, (uv_req_t*) req); + } return 0; } diff --git a/src/win/tcp.c b/src/win/tcp.c index 08083df350c..b6aa4c51205 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -205,73 +205,76 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) { } -void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { +void uv__process_tcp_shutdown_req(uv_loop_t* loop, uv_tcp_t* stream, uv_shutdown_t *req) { int err; - unsigned int i; - uv_tcp_accept_t* req; - if (handle->flags & UV_HANDLE_CONNECTION && - handle->stream.conn.shutdown_req != NULL && - handle->stream.conn.write_reqs_pending == 0) { + assert(req); + assert(stream->stream.conn.write_reqs_pending == 0); + assert(!(stream->flags & UV_HANDLE_SHUT)); + assert(stream->flags & UV_HANDLE_CONNECTION); - UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req); + stream->stream.conn.shutdown_req = NULL; + stream->flags &= ~UV_HANDLE_SHUTTING; + UNREGISTER_HANDLE_REQ(loop, stream, req); - err = 0; - if (handle->flags & UV_HANDLE_CLOSING) { - err = ERROR_OPERATION_ABORTED; - } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) { - err = WSAGetLastError(); - } + err = 0; + if (stream->flags & UV_HANDLE_CLOSING) + /* The user destroyed the stream before we got to do the shutdown. */ + err = UV_ECANCELED; + else if (shutdown(stream->socket, SD_SEND) == SOCKET_ERROR) + err = uv_translate_sys_error(WSAGetLastError()); + else /* Success. */ + stream->flags |= UV_HANDLE_SHUT; + + if (req->cb) + req->cb(req, err); - if (handle->stream.conn.shutdown_req->cb) { - handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, - uv_translate_sys_error(err)); - } + DECREASE_PENDING_REQ_COUNT(stream); +} - handle->stream.conn.shutdown_req = NULL; - DECREASE_PENDING_REQ_COUNT(handle); - return; - } - if (handle->flags & UV_HANDLE_CLOSING && - handle->reqs_pending == 0) { - assert(!(handle->flags & UV_HANDLE_CLOSED)); - assert(handle->socket == INVALID_SOCKET); +void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { + unsigned int i; + uv_tcp_accept_t* req; + + assert(handle->flags & UV_HANDLE_CLOSING); + assert(handle->reqs_pending == 0); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + assert(handle->socket == INVALID_SOCKET); - if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) { - if (handle->flags & UV_HANDLE_EMULATE_IOCP) { - for (i = 0; i < uv_simultaneous_server_accepts; i++) { - req = &handle->tcp.serv.accept_reqs[i]; - if (req->wait_handle != INVALID_HANDLE_VALUE) { - UnregisterWait(req->wait_handle); - req->wait_handle = INVALID_HANDLE_VALUE; - } - if (req->event_handle != NULL) { - CloseHandle(req->event_handle); - req->event_handle = NULL; - } + if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) { + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { + for (i = 0; i < uv_simultaneous_server_accepts; i++) { + req = &handle->tcp.serv.accept_reqs[i]; + if (req->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(req->wait_handle); + req->wait_handle = INVALID_HANDLE_VALUE; + } + if (req->event_handle != NULL) { + CloseHandle(req->event_handle); + req->event_handle = NULL; } } - - uv__free(handle->tcp.serv.accept_reqs); - handle->tcp.serv.accept_reqs = NULL; } - if (handle->flags & UV_HANDLE_CONNECTION && - handle->flags & UV_HANDLE_EMULATE_IOCP) { - if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { - UnregisterWait(handle->read_req.wait_handle); - handle->read_req.wait_handle = INVALID_HANDLE_VALUE; - } - if (handle->read_req.event_handle != NULL) { - CloseHandle(handle->read_req.event_handle); - handle->read_req.event_handle = NULL; - } - } + uv__free(handle->tcp.serv.accept_reqs); + handle->tcp.serv.accept_reqs = NULL; + } - uv__handle_close(handle); - loop->active_tcp_streams--; + if (handle->flags & UV_HANDLE_CONNECTION && + handle->flags & UV_HANDLE_EMULATE_IOCP) { + if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(handle->read_req.wait_handle); + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + } + if (handle->read_req.event_handle != NULL) { + CloseHandle(handle->read_req.event_handle); + handle->read_req.event_handle = NULL; + } } + + uv__handle_close(handle); + loop->active_tcp_streams--; } @@ -1160,9 +1163,10 @@ void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, closesocket(handle->socket); handle->socket = INVALID_SOCKET; } - if (handle->stream.conn.shutdown_req != NULL) { - uv__want_endgame(loop, (uv_handle_t*)handle); - } + if (handle->flags & UV_HANDLE_SHUTTING) + uv__process_tcp_shutdown_req(loop, + handle, + handle->stream.conn.shutdown_req); } DECREASE_PENDING_REQ_COUNT(handle); @@ -1483,6 +1487,9 @@ void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { DECREASE_ACTIVE_COUNT(loop, tcp); } + tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); + uv__handle_closing(tcp); + /* If any overlapped req failed to cancel, calling `closesocket` now would * cause Win32 to send an RST packet. Try to avoid that for writes, if * possibly applicable, by waiting to process the completion notifications @@ -1494,12 +1501,8 @@ void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { tcp->socket = INVALID_SOCKET; } - tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); - uv__handle_closing(tcp); - - if (tcp->reqs_pending == 0) { - uv__want_endgame(tcp->loop, (uv_handle_t*)tcp); - } + if (tcp->reqs_pending == 0) + uv__want_endgame(loop, (uv_handle_t*) tcp); } diff --git a/src/win/tty.c b/src/win/tty.c index 98c58883dcc..267ca645199 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -2237,11 +2237,13 @@ void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, req->cb(req, uv_translate_sys_error(err)); } + handle->stream.conn.write_reqs_pending--; - if (handle->stream.conn.shutdown_req != NULL && - handle->stream.conn.write_reqs_pending == 0) { - uv__want_endgame(loop, (uv_handle_t*)handle); - } + if (handle->stream.conn.write_reqs_pending == 0) + if (handle->flags & UV_HANDLE_SHUTTING) + uv__process_tty_shutdown_req(loop, + handle, + handle->stream.conn.shutdown_req); DECREASE_PENDING_REQ_COUNT(handle); } @@ -2262,43 +2264,43 @@ void uv__tty_close(uv_tty_t* handle) { handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); uv__handle_closing(handle); - if (handle->reqs_pending == 0) { + if (handle->reqs_pending == 0) uv__want_endgame(handle->loop, (uv_handle_t*) handle); - } } -void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { - if (!(handle->flags & UV_HANDLE_TTY_READABLE) && - handle->stream.conn.shutdown_req != NULL && - handle->stream.conn.write_reqs_pending == 0) { - UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req); - - /* TTY shutdown is really just a no-op */ - if (handle->stream.conn.shutdown_req->cb) { - if (handle->flags & UV_HANDLE_CLOSING) { - handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED); - } else { - handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0); - } - } +void uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown_t* req) { + assert(stream->stream.conn.write_reqs_pending == 0); + assert(req); - handle->stream.conn.shutdown_req = NULL; + stream->stream.conn.shutdown_req = NULL; + stream->flags &= ~UV_HANDLE_SHUTTING; + UNREGISTER_HANDLE_REQ(loop, stream, req); - DECREASE_PENDING_REQ_COUNT(handle); - return; + /* TTY shutdown is really just a no-op */ + if (req->cb) { + if (stream->flags & UV_HANDLE_CLOSING) { + req->cb(req, UV_ECANCELED); + } else { + req->cb(req, 0); + } } - if (handle->flags & UV_HANDLE_CLOSING && - handle->reqs_pending == 0) { - /* The wait handle used for raw reading should be unregistered when the - * wait callback runs. */ - assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || - handle->tty.rd.read_raw_wait == NULL); + DECREASE_PENDING_REQ_COUNT(stream); +} - assert(!(handle->flags & UV_HANDLE_CLOSED)); - uv__handle_close(handle); - } + +void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { + assert(handle->flags & UV_HANDLE_CLOSING); + assert(handle->reqs_pending == 0); + + /* The wait handle used for raw reading should be unregistered when the + * wait callback runs. */ + assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || + handle->tty.rd.read_raw_wait == NULL); + + assert(!(handle->flags & UV_HANDLE_CLOSED)); + uv__handle_close(handle); } From 0c1fa696aa502eb749c2c4735005f41ba00a27b8 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 12 Jul 2022 12:16:33 -0400 Subject: [PATCH 219/713] 2022.07.12, Version 1.44.2 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.44.1: * Add SHA to ChangeLog (Jameson Nash) * aix, ibmi: handle server hang when remote sends TCP RST (V-for-Vasili) * build: make CI a bit noisier (Jameson Nash) * process: reset the signal mask if the fork fails (Jameson Nash) * zos: implement cmpxchgi() using assembly (Shuowang (Wayne) Zhang) * build: AC_SUBST for AM_CFLAGS (Claes Nästén) * ibmi: Implement UDP disconnect (V-for-Vasili) * doc: update active maintainers list (Ben Noordhuis) * build: fix kFreeBSD build (James McCoy) * build: remove Windows 2016 workflows (Darshan Sen) * Revert "win,errors: remap ERROR_ACCESS_DENIED to UV_EACCES" (Darshan Sen) * unix: simplify getpwuid call (Jameson Nash) * build: filter CI by paths and branches (Jameson Nash) * build: add iOS to macos CI (Jameson Nash) * build: re-enable CI for windows changes (Jameson Nash) * process,iOS: fix build breakage in process.c (Denny C. Dai) * test: remove unused declarations in tcp_rst test (V-for-Vasili) * core: add thread-safe strtok implementation (Guilherme Íscaro) * win: fix incompatible-types warning (twosee) * test: fix flaky file watcher test (Ben Noordhuis) * build: fix AIX xlc autotools build (V-for-Vasili) * unix,win: fix UV_RUN_ONCE + uv_idle_stop loop hang (Ben Noordhuis) * win: fix unexpected ECONNRESET error on TCP socket (twosee) * doc: make sample cross-platform build (gengjiawen) * test: separate some static variables by test cases (Hannah Shi) * sunos: fs-event callback can be called after uv_close() (Andy Fiddaman) * uv: re-register interest in a file after change (Shuowang (Wayne) Zhang) * uv: register UV_RENAME event for _RFIM_UNLINK (Shuowang (Wayne) Zhang) * uv: register __rfim_event 156 as UV_RENAME (Shuowang (Wayne) Zhang) * doc: remove smartos from supported platforms (Ben Noordhuis) * macos: avoid posix_spawnp() cwd bug (Jameson Nash) * release: check versions of autogen scripts are newer (Jameson Nash) * test: rewrite embed test (Ben Noordhuis) * openbsd: use utimensat instead of lutimes (tuftedocelot) * doc: fix link to uvwget example main() function (blogdaren) * unix: use MSG_CMSG_CLOEXEC where supported (Ben Noordhuis) * test: remove disabled callback_order test (Ben Noordhuis) * win,pipe: fix bugs with pipe resource lifetime management (Jameson Nash) * loop: better align order-of-events behavior between platforms (Jameson Nash) * aix,test: uv_backend_fd is not supported by poll (V-for-Vasili) * kqueue: skip EVFILT_PROC when invalidating fds (chucksilvers) * darwin: fix atomic-ops.h ppc64 build (Sergey Fedorov) * zos: don't err when killing a zombie process (Shuowang (Wayne) Zhang) * zos: avoid fs event callbacks after uv_close() (Shuowang (Wayne) Zhang) * zos: correctly format interface addresses names (Shuowang (Wayne) Zhang) * zos: add uv_interface_addresses() netmask support (Shuowang (Wayne) Zhang) * zos: improve memory management of ip addresses (Shuowang (Wayne) Zhang) * tcp,pipe: fail `bind` or `listen` after `close` (theanarkh) * zos: implement uv_available_parallelism() (Shuowang (Wayne) Zhang) * udp,win: fix UDP compiler warning (Jameson Nash) * zos: fix early exit of epoll_wait() (Shuowang (Wayne) Zhang) * unix,tcp: fix errno handling in uv__tcp_bind() (Samuel Cabrero) * shutdown,unix: reduce code duplication (Jameson Nash) * unix: fix c99 comments (Ben Noordhuis) * unix: retry tcgetattr/tcsetattr() on EINTR (Ben Noordhuis) * docs: update introduction.rst (Ikko Ashimine) * unix,stream: optimize uv_shutdown() codepath (Jameson Nash) * zos: delay signal handling until after normal i/o (Shuowang (Wayne) Zhang) * stream: uv__drain() always needs to stop POLLOUT (Jameson Nash) * unix,tcp: allow EINVAL errno from setsockopt in uv_tcp_close_reset() (Stacey Marshall) * win,shutdown: improve how shutdown is dispatched (Jameson Nash) --- AUTHORS | 9 +++ ChangeLog | 128 +++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 4 +- m4/libuv-check-versions.m4 | 2 +- 5 files changed, 141 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index c1a98dbf164..e03100eab9d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -508,3 +508,12 @@ Paul Evans wyckster Vittore F. Scolari roflcopter4 <15476346+roflcopter4@users.noreply.github.com> +V-for-Vasili +Denny C. Dai +Hannah Shi +tuftedocelot +blogdaren +chucksilvers +Sergey Fedorov +theanarkh <2923878201@qq.com> +Samuel Cabrero diff --git a/ChangeLog b/ChangeLog index 48ee5490d11..cfbfed4fa6d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,131 @@ +2022.07.12, Version 1.44.2 (Stable) + +Changes since version 1.44.1: + +* Add SHA to ChangeLog (Jameson Nash) + +* aix, ibmi: handle server hang when remote sends TCP RST (V-for-Vasili) + +* build: make CI a bit noisier (Jameson Nash) + +* process: reset the signal mask if the fork fails (Jameson Nash) + +* zos: implement cmpxchgi() using assembly (Shuowang (Wayne) Zhang) + +* build: AC_SUBST for AM_CFLAGS (Claes Nästén) + +* ibmi: Implement UDP disconnect (V-for-Vasili) + +* doc: update active maintainers list (Ben Noordhuis) + +* build: fix kFreeBSD build (James McCoy) + +* build: remove Windows 2016 workflows (Darshan Sen) + +* Revert "win,errors: remap ERROR_ACCESS_DENIED to UV_EACCES" (Darshan Sen) + +* unix: simplify getpwuid call (Jameson Nash) + +* build: filter CI by paths and branches (Jameson Nash) + +* build: add iOS to macos CI (Jameson Nash) + +* build: re-enable CI for windows changes (Jameson Nash) + +* process,iOS: fix build breakage in process.c (Denny C. Dai) + +* test: remove unused declarations in tcp_rst test (V-for-Vasili) + +* core: add thread-safe strtok implementation (Guilherme Íscaro) + +* win: fix incompatible-types warning (twosee) + +* test: fix flaky file watcher test (Ben Noordhuis) + +* build: fix AIX xlc autotools build (V-for-Vasili) + +* unix,win: fix UV_RUN_ONCE + uv_idle_stop loop hang (Ben Noordhuis) + +* win: fix unexpected ECONNRESET error on TCP socket (twosee) + +* doc: make sample cross-platform build (gengjiawen) + +* test: separate some static variables by test cases (Hannah Shi) + +* sunos: fs-event callback can be called after uv_close() (Andy Fiddaman) + +* uv: re-register interest in a file after change (Shuowang (Wayne) Zhang) + +* uv: register UV_RENAME event for _RFIM_UNLINK (Shuowang (Wayne) Zhang) + +* uv: register __rfim_event 156 as UV_RENAME (Shuowang (Wayne) Zhang) + +* doc: remove smartos from supported platforms (Ben Noordhuis) + +* macos: avoid posix_spawnp() cwd bug (Jameson Nash) + +* release: check versions of autogen scripts are newer (Jameson Nash) + +* test: rewrite embed test (Ben Noordhuis) + +* openbsd: use utimensat instead of lutimes (tuftedocelot) + +* doc: fix link to uvwget example main() function (blogdaren) + +* unix: use MSG_CMSG_CLOEXEC where supported (Ben Noordhuis) + +* test: remove disabled callback_order test (Ben Noordhuis) + +* win,pipe: fix bugs with pipe resource lifetime management (Jameson Nash) + +* loop: better align order-of-events behavior between platforms (Jameson Nash) + +* aix,test: uv_backend_fd is not supported by poll (V-for-Vasili) + +* kqueue: skip EVFILT_PROC when invalidating fds (chucksilvers) + +* darwin: fix atomic-ops.h ppc64 build (Sergey Fedorov) + +* zos: don't err when killing a zombie process (Shuowang (Wayne) Zhang) + +* zos: avoid fs event callbacks after uv_close() (Shuowang (Wayne) Zhang) + +* zos: correctly format interface addresses names (Shuowang (Wayne) Zhang) + +* zos: add uv_interface_addresses() netmask support (Shuowang (Wayne) Zhang) + +* zos: improve memory management of ip addresses (Shuowang (Wayne) Zhang) + +* tcp,pipe: fail `bind` or `listen` after `close` (theanarkh) + +* zos: implement uv_available_parallelism() (Shuowang (Wayne) Zhang) + +* udp,win: fix UDP compiler warning (Jameson Nash) + +* zos: fix early exit of epoll_wait() (Shuowang (Wayne) Zhang) + +* unix,tcp: fix errno handling in uv__tcp_bind() (Samuel Cabrero) + +* shutdown,unix: reduce code duplication (Jameson Nash) + +* unix: fix c99 comments (Ben Noordhuis) + +* unix: retry tcgetattr/tcsetattr() on EINTR (Ben Noordhuis) + +* docs: update introduction.rst (Ikko Ashimine) + +* unix,stream: optimize uv_shutdown() codepath (Jameson Nash) + +* zos: delay signal handling until after normal i/o (Shuowang (Wayne) Zhang) + +* stream: uv__drain() always needs to stop POLLOUT (Jameson Nash) + +* unix,tcp: allow EINVAL errno from setsockopt in uv_tcp_close_reset() (Stacey + Marshall) + +* win,shutdown: improve how shutdown is dispatched (Jameson Nash) + + 2022.03.09, Version 1.44.1 (Stable), e8b7eb6908a847ffbe6ab2eec7428e43a0aa53a2 Changes since version 1.44.0: diff --git a/configure.ac b/configure.ac index 808c949d4a0..82d1640c8e3 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.44.2-dev], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.44.2], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index f7f49520c4a..9c9d292f695 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -33,8 +33,8 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 44 #define UV_VERSION_PATCH 2 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ diff --git a/m4/libuv-check-versions.m4 b/m4/libuv-check-versions.m4 index a280596daa3..795b07571fc 100644 --- a/m4/libuv-check-versions.m4 +++ b/m4/libuv-check-versions.m4 @@ -2,6 +2,6 @@ AC_PREREQ(2.71) AC_INIT([libuv-release-check], [0.0]) AM_INIT_AUTOMAKE([1.16.5]) -LT_PREREQ(2.4.6) +LT_PREREQ(2.4.7) AC_OUTPUT From 57a9a7196fed3a41285be1b786a975ca039923a8 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 12 Jul 2022 12:17:13 -0400 Subject: [PATCH 220/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index cfbfed4fa6d..6a883842a83 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2022.07.12, Version 1.44.2 (Stable) +2022.07.12, Version 1.44.2 (Stable), 0c1fa696aa502eb749c2c4735005f41ba00a27b8 Changes since version 1.44.1: From e81cc74ca25865e88bab2a977aaa8ee2808cee12 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 12 Jul 2022 12:22:04 -0400 Subject: [PATCH 221/713] Now working on version 1.44.3 Fixes: https://github.com/libuv/libuv/issues/3586 --- configure.ac | 2 +- include/uv/version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 82d1640c8e3..0f272561e71 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.44.2], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.44.3-dev], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 9c9d292f695..82517af7160 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 44 -#define UV_VERSION_PATCH 2 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 3 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 495ffca2c2736fbe4c8b8471d5a2acab75695f95 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 15 Jul 2022 10:39:14 +0200 Subject: [PATCH 222/713] win: remove stdint-msvc2008.h (#3673) Support for VS 2008 was removed two years ago in commit a779fccfd so this file can safely be deleted. --- LICENSE | 3 - include/uv.h | 7 +- include/uv/stdint-msvc2008.h | 247 ----------------------------------- include/uv/win.h | 7 +- src/inet.c | 7 +- src/uv-common.h | 7 +- src/win/tty.c | 7 +- test/task.h | 7 +- 8 files changed, 6 insertions(+), 286 deletions(-) delete mode 100644 include/uv/stdint-msvc2008.h diff --git a/LICENSE b/LICENSE index eb126dab3aa..f752e4869c4 100644 --- a/LICENSE +++ b/LICENSE @@ -59,8 +59,5 @@ The externally maintained libraries used by libuv are: copyright the Internet Systems Consortium, Inc., and licensed under the ISC license. - - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three - clause BSD license. - - pthread-fixes.c, copyright Google Inc. and Sony Mobile Communications AB. Three clause BSD license. diff --git a/include/uv.h b/include/uv.h index ee1c94ccd38..d68c5c84e8a 100644 --- a/include/uv.h +++ b/include/uv.h @@ -55,12 +55,7 @@ extern "C" { #include "uv/version.h" #include #include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -# include "uv/stdint-msvc2008.h" -#else -# include -#endif +#include #if defined(_WIN32) # include "uv/win.h" diff --git a/include/uv/stdint-msvc2008.h b/include/uv/stdint-msvc2008.h deleted file mode 100644 index d02608a5972..00000000000 --- a/include/uv/stdint-msvc2008.h +++ /dev/null @@ -1,247 +0,0 @@ -// ISO C9x compliant stdint.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 -// -// Copyright (c) 2006-2008 Alexander Chemeris -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. The name of the author may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_STDINT_H_ // [ -#define _MSC_STDINT_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include - -// For Visual Studio 6 in C++ mode and for many Visual Studio versions when -// compiling for ARM we should wrap include with 'extern "C++" {}' -// or compiler give many errors like this: -// error C2733: second C linkage of overloaded function 'wmemchr' not allowed -#ifdef __cplusplus -extern "C" { -#endif -# include -#ifdef __cplusplus -} -#endif - -// Define _W64 macros to mark types changing their size, like intptr_t. -#ifndef _W64 -# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 -# define _W64 __w64 -# else -# define _W64 -# endif -#endif - - -// 7.18.1 Integer types - -// 7.18.1.1 Exact-width integer types - -// Visual Studio 6 and Embedded Visual C++ 4 doesn't -// realize that, e.g. char has the same size as __int8 -// so we give up on __intX for them. -#if (_MSC_VER < 1300) - typedef signed char int8_t; - typedef signed short int16_t; - typedef signed int int32_t; - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; -#else - typedef signed __int8 int8_t; - typedef signed __int16 int16_t; - typedef signed __int32 int32_t; - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; -#endif -typedef signed __int64 int64_t; -typedef unsigned __int64 uint64_t; - - -// 7.18.1.2 Minimum-width integer types -typedef int8_t int_least8_t; -typedef int16_t int_least16_t; -typedef int32_t int_least32_t; -typedef int64_t int_least64_t; -typedef uint8_t uint_least8_t; -typedef uint16_t uint_least16_t; -typedef uint32_t uint_least32_t; -typedef uint64_t uint_least64_t; - -// 7.18.1.3 Fastest minimum-width integer types -typedef int8_t int_fast8_t; -typedef int16_t int_fast16_t; -typedef int32_t int_fast32_t; -typedef int64_t int_fast64_t; -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; - -// 7.18.1.4 Integer types capable of holding object pointers -#ifdef _WIN64 // [ - typedef signed __int64 intptr_t; - typedef unsigned __int64 uintptr_t; -#else // _WIN64 ][ - typedef _W64 signed int intptr_t; - typedef _W64 unsigned int uintptr_t; -#endif // _WIN64 ] - -// 7.18.1.5 Greatest-width integer types -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; - - -// 7.18.2 Limits of specified-width integer types - -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 - -// 7.18.2.1 Limits of exact-width integer types -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX - -// 7.18.2.2 Limits of minimum-width integer types -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -// 7.18.2.3 Limits of fastest minimum-width integer types -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -// 7.18.2.4 Limits of integer types capable of holding object pointers -#ifdef _WIN64 // [ -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX -#else // _WIN64 ][ -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX -#endif // _WIN64 ] - -// 7.18.2.5 Limits of greatest-width integer types -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -// 7.18.3 Limits of other integer types - -#ifdef _WIN64 // [ -# define PTRDIFF_MIN _I64_MIN -# define PTRDIFF_MAX _I64_MAX -#else // _WIN64 ][ -# define PTRDIFF_MIN _I32_MIN -# define PTRDIFF_MAX _I32_MAX -#endif // _WIN64 ] - -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX - -#ifndef SIZE_MAX // [ -# ifdef _WIN64 // [ -# define SIZE_MAX _UI64_MAX -# else // _WIN64 ][ -# define SIZE_MAX _UI32_MAX -# endif // _WIN64 ] -#endif // SIZE_MAX ] - -// WCHAR_MIN and WCHAR_MAX are also defined in -#ifndef WCHAR_MIN // [ -# define WCHAR_MIN 0 -#endif // WCHAR_MIN ] -#ifndef WCHAR_MAX // [ -# define WCHAR_MAX _UI16_MAX -#endif // WCHAR_MAX ] - -#define WINT_MIN 0 -#define WINT_MAX _UI16_MAX - -#endif // __STDC_LIMIT_MACROS ] - - -// 7.18.4 Limits of other integer types - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 - -// 7.18.4.1 Macros for minimum-width integer constants - -#define INT8_C(val) val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val) val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -// 7.18.4.2 Macros for greatest-width integer constants -#define INTMAX_C INT64_C -#define UINTMAX_C UINT64_C - -#endif // __STDC_CONSTANT_MACROS ] - - -#endif // _MSC_STDINT_H_ ] diff --git a/include/uv/win.h b/include/uv/win.h index 56a4cf1151c..582d2e877e0 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -59,12 +59,7 @@ typedef struct pollfd { #include #include #include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -# include "uv/stdint-msvc2008.h" -#else -# include -#endif +#include #include "uv/tree.h" #include "uv/threadpool.h" diff --git a/src/inet.c b/src/inet.c index ddabf22fa52..4b630f53bb8 100644 --- a/src/inet.c +++ b/src/inet.c @@ -17,12 +17,7 @@ #include #include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -# include "uv/stdint-msvc2008.h" -#else -# include -#endif +#include #include "uv.h" #include "uv-common.h" diff --git a/src/uv-common.h b/src/uv-common.h index 6001b0cf68d..38be9c71332 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -30,12 +30,7 @@ #include #include #include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -# include "uv/stdint-msvc2008.h" -#else -# include -#endif +#include #include "uv.h" #include "uv/tree.h" diff --git a/src/win/tty.c b/src/win/tty.c index 267ca645199..0462045c56d 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -23,12 +23,7 @@ #include #include #include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -# include "uv/stdint-msvc2008.h" -#else -# include -#endif +#include #ifndef COMMON_LVB_REVERSE_VIDEO # define COMMON_LVB_REVERSE_VIDEO 0x4000 diff --git a/test/task.h b/test/task.h index 925f1b1c0ae..44fa25bfbff 100644 --- a/test/task.h +++ b/test/task.h @@ -29,12 +29,7 @@ #include #include #include - -#if defined(_MSC_VER) && _MSC_VER < 1600 -# include "uv/stdint-msvc2008.h" -#else -# include -#endif +#include #if !defined(_WIN32) # include From 06948c6ee502862524f233af4e2c3e4ca876f5f6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 15 Jul 2022 11:18:38 +0200 Subject: [PATCH 223/713] android: remove pthread-fixes.c (#3674) This was a kludge for a bug in old versions (API level <= 16) of the Android SDK. The os390 port had a build dependency on the file but does not actually use it so that too has been removed. --- CMakeLists.txt | 2 -- LICENSE | 3 --- Makefile.am | 4 +-- src/unix/internal.h | 8 ------ src/unix/pthread-fixes.c | 58 ---------------------------------------- 5 files changed, 1 insertion(+), 74 deletions(-) delete mode 100644 src/unix/pthread-fixes.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f466826c50..ddf3cdc3762 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,7 +220,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android") src/unix/linux-inotify.c src/unix/linux-syscalls.c src/unix/procfs-exepath.c - src/unix/pthread-fixes.c src/unix/random-getentropy.c src/unix/random-getrandom.c src/unix/random-sysctl-linux.c @@ -316,7 +315,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OS390") list(APPEND uv_defines _XOPEN_SOURCE=600) list(APPEND uv_defines _XOPEN_SOURCE_EXTENDED) list(APPEND uv_sources - src/unix/pthread-fixes.c src/unix/os390.c src/unix/os390-syscalls.c src/unix/os390-proctitle.c) diff --git a/LICENSE b/LICENSE index f752e4869c4..3d7f8f80f9b 100644 --- a/LICENSE +++ b/LICENSE @@ -58,6 +58,3 @@ The externally maintained libraries used by libuv are: - inet_pton and inet_ntop implementations, contained in src/inet.c, are copyright the Internet Systems Consortium, Inc., and licensed under the ISC license. - - - pthread-fixes.c, copyright Google Inc. and Sony Mobile Communications AB. - Three clause BSD license. diff --git a/Makefile.am b/Makefile.am index 0c6d96598ae..49a2a30468a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -393,7 +393,6 @@ endif if ANDROID libuv_la_CFLAGS += -D_GNU_SOURCE -libuv_la_SOURCES += src/unix/pthread-fixes.c endif if CYGWIN @@ -546,8 +545,7 @@ libuv_la_CFLAGS += -D_UNIX03_THREADS \ -qXPLINK \ -qFLOAT=IEEE libuv_la_LDFLAGS += -qXPLINK -libuv_la_SOURCES += src/unix/pthread-fixes.c \ - src/unix/os390.c \ +libuv_la_SOURCES += src/unix/os390.c \ src/unix/os390-syscalls.c \ src/unix/proctitle.c endif diff --git a/src/unix/internal.h b/src/unix/internal.h index cee35c2106a..65f09807130 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -79,14 +79,6 @@ # define UV__PATH_MAX 8192 #endif -#if defined(__ANDROID__) -int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); -# ifdef pthread_sigmask -# undef pthread_sigmask -# endif -# define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset) -#endif - #define ACCESS_ONCE(type, var) \ (*(volatile type*) &(var)) diff --git a/src/unix/pthread-fixes.c b/src/unix/pthread-fixes.c deleted file mode 100644 index 022d79c4e21..00000000000 --- a/src/unix/pthread-fixes.c +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (c) 2013, Sony Mobile Communications AB - * Copyright (c) 2012, Google Inc. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* Android versions < 4.1 have a broken pthread_sigmask. */ -#include "uv-common.h" - -#include -#include -#include - -int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { - static int workaround; - int err; - - if (uv__load_relaxed(&workaround)) { - return sigprocmask(how, set, oset); - } else { - err = pthread_sigmask(how, set, oset); - if (err) { - if (err == EINVAL && sigprocmask(how, set, oset) == 0) { - uv__store_relaxed(&workaround, 1); - return 0; - } else { - return -1; - } - } - } - - return 0; -} From fb85db1d3ec304934f0b2afe61cf7e30de10af86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=87=AA=E5=8F=91=E5=AF=B9=E7=A7=B0=E7=A0=B4=E7=BC=BA?= <429839446@qq.com> Date: Tue, 19 Jul 2022 03:49:17 +0800 Subject: [PATCH 224/713] build: enable MSVC_RUNTIME_LIBRARY setting (#3624) --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ddf3cdc3762..2c42c3ffe21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,12 @@ cmake_minimum_required(VERSION 3.4) -project(libuv LANGUAGES C) cmake_policy(SET CMP0057 NEW) # Enable IN_LIST operator cmake_policy(SET CMP0064 NEW) # Support if (TEST) operator +if(POLICY CMP0091) + cmake_policy(SET CMP0091 NEW) # Enable MSVC_RUNTIME_LIBRARY setting +endif() + +project(libuv LANGUAGES C) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") From ac5180e29cb6db5bfaf2ea2419b50da146fef06e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 19 Jul 2022 10:09:09 +0200 Subject: [PATCH 225/713] unix: switch to c11 atomics (#3688) Fixes: https://github.com/libuv/libuv/issues/3683 --- Makefile.am | 2 -- src/unix/async.c | 43 +++++++++++++++++++++++------ src/unix/atomic-ops.h | 64 ------------------------------------------- src/unix/spinlock.h | 53 ----------------------------------- src/unix/tty.c | 20 ++++++++++---- 5 files changed, 48 insertions(+), 134 deletions(-) delete mode 100644 src/unix/atomic-ops.h delete mode 100644 src/unix/spinlock.h diff --git a/Makefile.am b/Makefile.am index 49a2a30468a..542f63356df 100644 --- a/Makefile.am +++ b/Makefile.am @@ -96,7 +96,6 @@ else # WINNT uvinclude_HEADERS += include/uv/unix.h AM_CPPFLAGS += -I$(top_srcdir)/src/unix libuv_la_SOURCES += src/unix/async.c \ - src/unix/atomic-ops.h \ src/unix/core.c \ src/unix/dl.c \ src/unix/fs.c \ @@ -110,7 +109,6 @@ libuv_la_SOURCES += src/unix/async.c \ src/unix/process.c \ src/unix/random-devurandom.c \ src/unix/signal.c \ - src/unix/spinlock.h \ src/unix/stream.c \ src/unix/tcp.c \ src/unix/thread.c \ diff --git a/src/unix/async.c b/src/unix/async.c index e1805c32379..1f4a3061310 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -24,9 +24,9 @@ #include "uv.h" #include "internal.h" -#include "atomic-ops.h" #include +#include #include /* snprintf() */ #include #include @@ -40,6 +40,7 @@ static void uv__async_send(uv_loop_t* loop); static int uv__async_start(uv_loop_t* loop); +static void uv__cpu_relax(void); int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { @@ -61,19 +62,26 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { int uv_async_send(uv_async_t* handle) { + _Atomic int* pending; + int expected; + + pending = (_Atomic int*) &handle->pending; + /* Do a cheap read first. */ - if (ACCESS_ONCE(int, handle->pending) != 0) + if (atomic_load_explicit(pending, memory_order_relaxed) != 0) return 0; /* Tell the other thread we're busy with the handle. */ - if (cmpxchgi(&handle->pending, 0, 1) != 0) + expected = 0; + if (!atomic_compare_exchange_strong(pending, &expected, 1)) return 0; /* Wake up the other thread's event loop. */ uv__async_send(handle->loop); /* Tell the other thread we're done. */ - if (cmpxchgi(&handle->pending, 1, 2) != 1) + expected = 1; + if (!atomic_compare_exchange_strong(pending, &expected, 2)) abort(); return 0; @@ -82,8 +90,11 @@ int uv_async_send(uv_async_t* handle) { /* Only call this from the event loop thread. */ static int uv__async_spin(uv_async_t* handle) { + _Atomic int* pending; + int expected; int i; - int rc; + + pending = (_Atomic int*) &handle->pending; for (;;) { /* 997 is not completely chosen at random. It's a prime number, acyclical @@ -94,13 +105,14 @@ static int uv__async_spin(uv_async_t* handle) { * rc=1 -- handle is pending, other thread is still working with it. * rc=2 -- handle is pending, other thread is done. */ - rc = cmpxchgi(&handle->pending, 2, 0); + expected = 2; + atomic_compare_exchange_strong(pending, &expected, 0); - if (rc != 1) - return rc; + if (expected != 1) + return expected; /* Other thread is busy with this handle, spin until it's done. */ - cpu_relax(); + uv__cpu_relax(); } /* Yield the CPU. We may have preempted the other thread while it's @@ -251,3 +263,16 @@ void uv__async_stop(uv_loop_t* loop) { uv__close(loop->async_io_watcher.fd); loop->async_io_watcher.fd = -1; } + + +static void uv__cpu_relax(void) { +#if defined(__i386__) || defined(__x86_64__) + __asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */ +#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__) + __asm__ __volatile__ ("yield" ::: "memory"); +#elif (defined(__ppc__) || defined(__ppc64__)) && defined(__APPLE__) + __asm volatile ("" : : : "memory"); +#elif !defined(__APPLE__) && (defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)) + __asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory"); +#endif +} diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h deleted file mode 100644 index 58043c42fbd..00000000000 --- a/src/unix/atomic-ops.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (c) 2013, Ben Noordhuis - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef UV_ATOMIC_OPS_H_ -#define UV_ATOMIC_OPS_H_ - -#include "internal.h" /* UV_UNUSED */ - -#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) -#include -#endif - -UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)); -UV_UNUSED(static void cpu_relax(void)); - -/* Prefer hand-rolled assembly over the gcc builtins because the latter also - * issue full memory barriers. - */ -UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { -#if defined(__i386__) || defined(__x86_64__) - int out; - __asm__ __volatile__ ("lock; cmpxchg %2, %1;" - : "=a" (out), "+m" (*(volatile int*) ptr) - : "r" (newval), "0" (oldval) - : "memory"); - return out; -#elif defined(__MVS__) - /* Use hand-rolled assembly because codegen from builtin __plo_CSST results in - * a runtime bug. - */ - __asm(" cs %0,%2,%1 \n " : "+r"(oldval), "+m"(*ptr) : "r"(newval) :); - return oldval; -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) - return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval); -#else - return __sync_val_compare_and_swap(ptr, oldval, newval); -#endif -} - -UV_UNUSED(static void cpu_relax(void)) { -#if defined(__i386__) || defined(__x86_64__) - __asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */ -#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__) - __asm__ __volatile__ ("yield" ::: "memory"); -#elif (defined(__ppc__) || defined(__ppc64__)) && defined(__APPLE__) - __asm volatile ("" : : : "memory"); -#elif !defined(__APPLE__) && (defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)) - __asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory"); -#endif -} - -#endif /* UV_ATOMIC_OPS_H_ */ diff --git a/src/unix/spinlock.h b/src/unix/spinlock.h deleted file mode 100644 index a20c83cc601..00000000000 --- a/src/unix/spinlock.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (c) 2013, Ben Noordhuis - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef UV_SPINLOCK_H_ -#define UV_SPINLOCK_H_ - -#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */ -#include "atomic-ops.h" - -#define UV_SPINLOCK_INITIALIZER { 0 } - -typedef struct { - int lock; -} uv_spinlock_t; - -UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)); -UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)); -UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)); -UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)); - -UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) { - ACCESS_ONCE(int, spinlock->lock) = 0; -} - -UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) { - while (!uv_spinlock_trylock(spinlock)) cpu_relax(); -} - -UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) { - ACCESS_ONCE(int, spinlock->lock) = 0; -} - -UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) { - /* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing. - * Not really critical until we have locks that are (frequently) contended - * for by several threads. - */ - return 0 == cmpxchgi(&spinlock->lock, 0, 1); -} - -#endif /* UV_SPINLOCK_H_ */ diff --git a/src/unix/tty.c b/src/unix/tty.c index b41505258ff..a5bad72fe57 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -21,8 +21,8 @@ #include "uv.h" #include "internal.h" -#include "spinlock.h" +#include #include #include #include @@ -64,7 +64,7 @@ static int isreallyatty(int file) { static int orig_termios_fd = -1; static struct termios orig_termios; -static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; +static _Atomic int termios_spinlock; int uv__tcsetattr(int fd, int how, const struct termios *term) { int rc; @@ -280,6 +280,7 @@ static void uv__tty_make_raw(struct termios* tio) { int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { struct termios tmp; + int expected; int fd; int rc; @@ -296,12 +297,16 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { return UV__ERR(errno); /* This is used for uv_tty_reset_mode() */ - uv_spinlock_lock(&termios_spinlock); + do + expected = 0; + while (!atomic_compare_exchange_strong(&termios_spinlock, &expected, 1)); + if (orig_termios_fd == -1) { orig_termios = tty->orig_termios; orig_termios_fd = fd; } - uv_spinlock_unlock(&termios_spinlock); + + atomic_store(&termios_spinlock, 0); } tmp = tty->orig_termios; @@ -442,17 +447,20 @@ uv_handle_type uv_guess_handle(uv_file file) { */ int uv_tty_reset_mode(void) { int saved_errno; + int expected; int err; saved_errno = errno; - if (!uv_spinlock_trylock(&termios_spinlock)) + + expected = 0; + if (!atomic_compare_exchange_strong(&termios_spinlock, &expected, 1)) return UV_EBUSY; /* In uv_tty_set_mode(). */ err = 0; if (orig_termios_fd != -1) err = uv__tcsetattr(orig_termios_fd, TCSANOW, &orig_termios); - uv_spinlock_unlock(&termios_spinlock); + atomic_store(&termios_spinlock, 0); errno = saved_errno; return err; From 6c692ad1cbcc5083ec90954a4b091b660aedfc10 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 20 Jul 2022 12:42:50 +0200 Subject: [PATCH 226/713] unix: don't accept() connections in a loop (#3696) After analysis of many real-world programs I've come to conclude that accepting in a loop is nearly always suboptimal. 1. 99.9% of the time the second accept() call fails with EAGAIN, meaning there are no additional connections to accept. Not super expensive in isolation but it adds up. 2. When there are more connections to accept but the listen socket is shared between multiple processes (ex. the Node.js cluster module), libuv's greedy behavior necessitated the UV_TCP_SINGLE_ACCEPT hack to slow it down in order to give other processes a chance. Accepting a single connection and relying on level-triggered polling to get notified on the next incoming connection both simplifies the code and optimizes for the common case. --- src/unix/core.c | 5 ---- src/unix/kqueue.c | 3 --- src/unix/stream.c | 66 +++++++++-------------------------------------- src/unix/tcp.c | 16 ------------ 4 files changed, 12 insertions(+), 78 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 54c769f37f2..a5fe9c08c9b 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -867,11 +867,6 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { w->fd = fd; w->events = 0; w->pevents = 0; - -#if defined(UV_HAVE_KQUEUE) - w->rcount = 0; - w->wcount = 0; -#endif /* defined(UV_HAVE_KQUEUE) */ } diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 5dac76ae753..8c5617b2ada 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -333,7 +333,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (ev->filter == EVFILT_READ) { if (w->pevents & POLLIN) { revents |= POLLIN; - w->rcount = ev->data; } else { /* TODO batch up */ struct kevent events[1]; @@ -349,7 +348,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (ev->filter == EV_OOBAND) { if (w->pevents & UV__POLLPRI) { revents |= UV__POLLPRI; - w->rcount = ev->data; } else { /* TODO batch up */ struct kevent events[1]; @@ -363,7 +361,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (ev->filter == EVFILT_WRITE) { if (w->pevents & POLLOUT) { revents |= POLLOUT; - w->wcount = ev->data; } else { /* TODO batch up */ struct kevent events[1]; diff --git a/src/unix/stream.c b/src/unix/stream.c index b1f6359e0de..72d273f0ad4 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -495,76 +495,34 @@ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) { } -#if defined(UV_HAVE_KQUEUE) -# define UV_DEC_BACKLOG(w) w->rcount--; -#else -# define UV_DEC_BACKLOG(w) /* no-op */ -#endif /* defined(UV_HAVE_KQUEUE) */ - - void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { uv_stream_t* stream; int err; + int fd; stream = container_of(w, uv_stream_t, io_watcher); assert(events & POLLIN); assert(stream->accepted_fd == -1); assert(!(stream->flags & UV_HANDLE_CLOSING)); - uv__io_start(stream->loop, &stream->io_watcher, POLLIN); - - /* connection_cb can close the server socket while we're - * in the loop so check it on each iteration. - */ - while (uv__stream_fd(stream) != -1) { - assert(stream->accepted_fd == -1); - -#if defined(UV_HAVE_KQUEUE) - if (w->rcount <= 0) - return; -#endif /* defined(UV_HAVE_KQUEUE) */ - - err = uv__accept(uv__stream_fd(stream)); - if (err < 0) { - if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK)) - return; /* Not an error. */ - - if (err == UV_ECONNABORTED) - continue; /* Ignore. Nothing we can do about that. */ - - if (err == UV_EMFILE || err == UV_ENFILE) { - err = uv__emfile_trick(loop, uv__stream_fd(stream)); - if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK)) - break; - } + fd = uv__stream_fd(stream); + err = uv__accept(fd); - stream->connection_cb(stream, err); - continue; - } + if (err == UV_EMFILE || err == UV_ENFILE) + err = uv__emfile_trick(loop, fd); /* Shed load. */ - UV_DEC_BACKLOG(w) - stream->accepted_fd = err; - stream->connection_cb(stream, 0); + if (err < 0) + return; - if (stream->accepted_fd != -1) { - /* The user hasn't yet accepted called uv_accept() */ - uv__io_stop(loop, &stream->io_watcher, POLLIN); - return; - } + stream->accepted_fd = err; + stream->connection_cb(stream, 0); - if (stream->type == UV_TCP && - (stream->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) { - /* Give other processes a chance to accept connections. */ - struct timespec timeout = { 0, 1 }; - nanosleep(&timeout, NULL); - } - } + if (stream->accepted_fd != -1) + /* The user hasn't yet accepted called uv_accept() */ + uv__io_stop(loop, &stream->io_watcher, POLLIN); } -#undef UV_DEC_BACKLOG - - int uv_accept(uv_stream_t* server, uv_stream_t* client) { int err; diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 73fc657a86d..81dfa620329 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -338,24 +338,12 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) { int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { - static int single_accept_cached = -1; unsigned long flags; - int single_accept; int err; if (tcp->delayed_error) return tcp->delayed_error; - single_accept = uv__load_relaxed(&single_accept_cached); - if (single_accept == -1) { - const char* val = getenv("UV_TCP_SINGLE_ACCEPT"); - single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */ - uv__store_relaxed(&single_accept_cached, single_accept); - } - - if (single_accept) - tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; - flags = 0; #if defined(__MVS__) /* on zOS the listen call does not bind automatically @@ -460,10 +448,6 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { - if (enable) - handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT; - else - handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; return 0; } From df0ac426f346c711691af59d467cb31ca58b54fd Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 27 Jul 2022 21:11:41 +0200 Subject: [PATCH 227/713] win: fix off-by-1 buffer overrun in uv_exepath() (#3695) uv_exepath() wrote the nul byte *after* the end of the buffer. It's not necessary to write said nul byte in the first place because that was a workaround for a bug in the Windows XP version of GetModuleFileName(). Fix uv_cwd() in the same fashion, it doesn't need the nul byte either. Fixes: https://github.com/libuv/libuv/issues/3691 --- src/win/util.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/win/util.c b/src/win/util.c index 99432053cc3..dd4a747bff8 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -121,9 +121,6 @@ int uv_exepath(char* buffer, size_t* size_ptr) { goto error; } - /* utf16_len contains the length, *not* including the terminating null. */ - utf16_buffer[utf16_len] = L'\0'; - /* Convert to UTF-8 */ utf8_len = WideCharToMultiByte(CP_UTF8, 0, @@ -175,9 +172,6 @@ int uv_cwd(char* buffer, size_t* size) { return uv_translate_sys_error(GetLastError()); } - /* utf16_len contains the length, *not* including the terminating null. */ - utf16_buffer[utf16_len] = L'\0'; - /* The returned directory should not have a trailing slash, unless it points * at a drive root, like c:\. Remove it if needed. */ if (utf16_buffer[utf16_len - 1] == L'\\' && From 850f002cb2ff6f17325ad6b431310e5e2de03a58 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 27 Jul 2022 22:53:28 +0200 Subject: [PATCH 228/713] build: switch ci from macos-10.15 to macos-11 (#3707) The former will be removed by GitHub in August. Fixes: https://github.com/libuv/libuv/issues/3697 --- .github/workflows/CI-unix.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 506c00bcf75..d0d2d46edbe 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -33,7 +33,7 @@ jobs: ls -lh build build-macos: - runs-on: macos-10.15 + runs-on: macos-11 steps: - uses: actions/checkout@v2 - name: Envinfo @@ -61,7 +61,7 @@ jobs: cd build && ctest -V build-ios: - runs-on: macos-10.15 + runs-on: macos-11 steps: - uses: actions/checkout@v2 - name: Configure From 4db0a9a6b73b2c29c4e19930702203790734e2d3 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 28 Jul 2022 00:34:03 +0200 Subject: [PATCH 229/713] win: fix thread race in uv_cwd() and uv_chdir() (#3708) Another thread can change the working directory between calls to GetCurrentDirectoryW(). The first call was used to determine the size of the buffer to use in the second call. Retry if the reported size does not match the expected size because the buffer's contents is undefined in that case. --- src/win/util.c | 100 ++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 43 deletions(-) diff --git a/src/win/util.c b/src/win/util.c index dd4a747bff8..6df86111282 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -148,6 +148,51 @@ int uv_exepath(char* buffer, size_t* size_ptr) { } +static int uv__cwd(WCHAR** buf, DWORD *len) { + WCHAR* p; + DWORD n; + DWORD t; + + t = GetCurrentDirectoryW(0, NULL); + for (;;) { + if (t == 0) + return uv_translate_sys_error(GetLastError()); + + /* |t| is the size of the buffer _including_ nul. */ + p = uv__malloc(t * sizeof(*p)); + if (p == NULL) + return UV_ENOMEM; + + /* |n| is the size of the buffer _excluding_ nul but _only on success_. + * If |t| was too small because another thread changed the working + * directory, |n| is the size the buffer should be _including_ nul. + * It therefore follows we must resize when n >= t and fail when n == 0. + */ + n = GetCurrentDirectoryW(t, p); + if (n > 0) + if (n < t) + break; + + uv__free(p); + t = n; + } + + /* The returned directory should not have a trailing slash, unless it points + * at a drive root, like c:\. Remove it if needed. + */ + t = n - 1; + if (p[t] == L'\\' && !(n == 3 && p[1] == L':')) { + p[t] = L'\0'; + n = t; + } + + *buf = p; + *len = n; + + return 0; +} + + int uv_cwd(char* buffer, size_t* size) { DWORD utf16_len; WCHAR *utf16_buffer; @@ -157,27 +202,9 @@ int uv_cwd(char* buffer, size_t* size) { return UV_EINVAL; } - utf16_len = GetCurrentDirectoryW(0, NULL); - if (utf16_len == 0) { - return uv_translate_sys_error(GetLastError()); - } - utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR)); - if (utf16_buffer == NULL) { - return UV_ENOMEM; - } - - utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer); - if (utf16_len == 0) { - uv__free(utf16_buffer); - return uv_translate_sys_error(GetLastError()); - } - - /* The returned directory should not have a trailing slash, unless it points - * at a drive root, like c:\. Remove it if needed. */ - if (utf16_buffer[utf16_len - 1] == L'\\' && - !(utf16_len == 3 && utf16_buffer[1] == L':')) { - utf16_len--; - utf16_buffer[utf16_len] = L'\0'; + r = uv__cwd(&utf16_buffer, &utf16_len); + if (r < 0) { + return r; } /* Check how much space we need */ @@ -220,8 +247,9 @@ int uv_cwd(char* buffer, size_t* size) { int uv_chdir(const char* dir) { WCHAR *utf16_buffer; - size_t utf16_len, new_utf16_len; + size_t utf16_len; WCHAR drive_letter, env_var[4]; + int r; if (dir == NULL) { return UV_EINVAL; @@ -259,29 +287,15 @@ int uv_chdir(const char* dir) { /* Windows stores the drive-local path in an "hidden" environment variable, * which has the form "=C:=C:\Windows". SetCurrentDirectory does not update * this, so we'll have to do it. */ - new_utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer); - if (new_utf16_len > utf16_len ) { - uv__free(utf16_buffer); - utf16_buffer = uv__malloc(new_utf16_len * sizeof(WCHAR)); - if (utf16_buffer == NULL) { - /* When updating the environment variable fails, return UV_OK anyway. - * We did successfully change current working directory, only updating - * hidden env variable failed. */ - return 0; - } - new_utf16_len = GetCurrentDirectoryW(new_utf16_len, utf16_buffer); - } - if (utf16_len == 0) { - uv__free(utf16_buffer); + r = uv__cwd(&utf16_buffer, &utf16_len); + if (r == UV_ENOMEM) { + /* When updating the environment variable fails, return UV_OK anyway. + * We did successfully change current working directory, only updating + * hidden env variable failed. */ return 0; } - - /* The returned directory should not have a trailing slash, unless it points - * at a drive root, like c:\. Remove it if needed. */ - if (utf16_buffer[utf16_len - 1] == L'\\' && - !(utf16_len == 3 && utf16_buffer[1] == L':')) { - utf16_len--; - utf16_buffer[utf16_len] = L'\0'; + if (r < 0) { + return r; } if (utf16_len < 2 || utf16_buffer[1] != L':') { From 7bccb562e415030050cfbd1e69eeefd69ce57aca Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 3 Aug 2022 21:24:32 +0200 Subject: [PATCH 230/713] unix,win: remove UV_HANDLE_SHUTTING flag (#3705) Replace it with a `uv__is_stream_shutting()` macro that checks the `shutdown_req` field. It partially fixes: https://github.com/libuv/libuv/issues/3663. --- src/unix/stream.c | 6 ++---- src/unix/tcp.c | 2 +- src/uv-common.h | 9 ++++++++- src/win/pipe.c | 7 +++---- src/win/stream.c | 3 +-- src/win/tcp.c | 5 ++--- src/win/tty.c | 11 +++++------ 7 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 72d273f0ad4..95ca92d564c 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -623,7 +623,7 @@ static void uv__drain(uv_stream_t* stream) { uv__stream_osx_interrupt_select(stream); } - if (!(stream->flags & UV_HANDLE_SHUTTING)) + if (!uv__is_stream_shutting(stream)) return; req = stream->shutdown_req; @@ -632,7 +632,6 @@ static void uv__drain(uv_stream_t* stream) { if ((stream->flags & UV_HANDLE_CLOSING) || !(stream->flags & UV_HANDLE_SHUT)) { stream->shutdown_req = NULL; - stream->flags &= ~UV_HANDLE_SHUTTING; uv__req_unregister(stream->loop, req); err = 0; @@ -1183,7 +1182,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { if (!(stream->flags & UV_HANDLE_WRITABLE) || stream->flags & UV_HANDLE_SHUT || - stream->flags & UV_HANDLE_SHUTTING || + uv__is_stream_shutting(stream) || uv__is_closing(stream)) { return UV_ENOTCONN; } @@ -1196,7 +1195,6 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { req->handle = stream; req->cb = cb; stream->shutdown_req = req; - stream->flags |= UV_HANDLE_SHUTTING; stream->flags &= ~UV_HANDLE_WRITABLE; if (QUEUE_EMPTY(&stream->write_queue)) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 81dfa620329..881f392b821 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -317,7 +317,7 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) { struct linger l = { 1, 0 }; /* Disallow setting SO_LINGER to zero due to some platform inconsistencies */ - if (handle->flags & UV_HANDLE_SHUTTING) + if (uv__is_stream_shutting(handle)) return UV_EINVAL; fd = uv__stream_fd(handle); diff --git a/src/uv-common.h b/src/uv-common.h index 38be9c71332..bbfaaf708aa 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -78,7 +78,6 @@ enum { /* Used by streams. */ UV_HANDLE_LISTENING = 0x00000040, UV_HANDLE_CONNECTION = 0x00000080, - UV_HANDLE_SHUTTING = 0x00000100, UV_HANDLE_SHUT = 0x00000200, UV_HANDLE_READ_PARTIAL = 0x00000400, UV_HANDLE_READ_EOF = 0x00000800, @@ -258,6 +257,14 @@ void uv__threadpool_cleanup(void); #define uv__is_closing(h) \ (((h)->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED)) != 0) +#if defined(_WIN32) +# define uv__is_stream_shutting(h) \ + (h->stream.conn.shutdown_req != NULL) +#else +# define uv__is_stream_shutting(h) \ + (h->shutdown_req != NULL) +#endif + #define uv__handle_start(h) \ do { \ if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break; \ diff --git a/src/win/pipe.c b/src/win/pipe.c index 998461811fb..bf605b101e4 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -2069,9 +2069,9 @@ void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, uv__queue_non_overlapped_write(handle); } - if (handle->stream.conn.write_reqs_pending == 0) - if (handle->flags & UV_HANDLE_SHUTTING) - uv__pipe_shutdown(loop, handle, handle->stream.conn.shutdown_req); + if (handle->stream.conn.write_reqs_pending == 0 && + uv__is_stream_shutting(handle)) + uv__pipe_shutdown(loop, handle, handle->stream.conn.shutdown_req); DECREASE_PENDING_REQ_COUNT(handle); } @@ -2149,7 +2149,6 @@ void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, /* Clear the shutdown_req field so we don't go here again. */ handle->stream.conn.shutdown_req = NULL; - handle->flags &= ~UV_HANDLE_SHUTTING; UNREGISTER_HANDLE_REQ(loop, handle, req); if (handle->flags & UV_HANDLE_CLOSING) { diff --git a/src/win/stream.c b/src/win/stream.c index 292bf588da6..7bf9ca388cb 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -204,7 +204,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { uv_loop_t* loop = handle->loop; if (!(handle->flags & UV_HANDLE_WRITABLE) || - handle->flags & UV_HANDLE_SHUTTING || + uv__is_stream_shutting(handle) || uv__is_closing(handle)) { return UV_ENOTCONN; } @@ -214,7 +214,6 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { req->cb = cb; handle->flags &= ~UV_HANDLE_WRITABLE; - handle->flags |= UV_HANDLE_SHUTTING; handle->stream.conn.shutdown_req = req; handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); diff --git a/src/win/tcp.c b/src/win/tcp.c index b6aa4c51205..f061ed76caf 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -214,7 +214,6 @@ void uv__process_tcp_shutdown_req(uv_loop_t* loop, uv_tcp_t* stream, uv_shutdown assert(stream->flags & UV_HANDLE_CONNECTION); stream->stream.conn.shutdown_req = NULL; - stream->flags &= ~UV_HANDLE_SHUTTING; UNREGISTER_HANDLE_REQ(loop, stream, req); err = 0; @@ -550,7 +549,7 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) { struct linger l = { 1, 0 }; /* Disallow setting SO_LINGER to zero due to some platform inconsistencies */ - if (handle->flags & UV_HANDLE_SHUTTING) + if (uv__is_stream_shutting(handle)) return UV_EINVAL; if (0 != setsockopt(handle->socket, SOL_SOCKET, SO_LINGER, (const char*)&l, sizeof(l))) @@ -1163,7 +1162,7 @@ void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, closesocket(handle->socket); handle->socket = INVALID_SOCKET; } - if (handle->flags & UV_HANDLE_SHUTTING) + if (uv__is_stream_shutting(handle)) uv__process_tcp_shutdown_req(loop, handle, handle->stream.conn.shutdown_req); diff --git a/src/win/tty.c b/src/win/tty.c index 0462045c56d..c41a16ef00f 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -2234,11 +2234,11 @@ void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, handle->stream.conn.write_reqs_pending--; - if (handle->stream.conn.write_reqs_pending == 0) - if (handle->flags & UV_HANDLE_SHUTTING) - uv__process_tty_shutdown_req(loop, - handle, - handle->stream.conn.shutdown_req); + if (handle->stream.conn.write_reqs_pending == 0 && + uv__is_stream_shutting(handle)) + uv__process_tty_shutdown_req(loop, + handle, + handle->stream.conn.shutdown_req); DECREASE_PENDING_REQ_COUNT(handle); } @@ -2269,7 +2269,6 @@ void uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown assert(req); stream->stream.conn.shutdown_req = NULL; - stream->flags &= ~UV_HANDLE_SHUTTING; UNREGISTER_HANDLE_REQ(loop, stream, req); /* TTY shutdown is really just a no-op */ From 97dcdb1926f6aca43171e1614338bcef067abd59 Mon Sep 17 00:00:00 2001 From: Luan Devecchi Date: Sat, 13 Aug 2022 13:16:28 -0300 Subject: [PATCH 231/713] win: support Windows 11 in uv_os_uname() (#3718) Fixes: https://github.com/libuv/libuv/issues/3381 Fixes: https://github.com/nodejs/node/issues/40862 --- src/win/util.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/win/util.c b/src/win/util.c index 6df86111282..695f849441e 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1777,6 +1777,22 @@ int uv_os_uname(uv_utsname_t* buffer) { RegCloseKey(registry_key); if (r == ERROR_SUCCESS) { + /* Windows 11 shares dwMajorVersion with Windows 10 + * this workaround tries to disambiguate that by checking + * if the dwBuildNumber is from Windows 11 releases (>= 22000). + * + * This workaround replaces the ProductName key value + * from "Windows 10 *" to "Windows 11 *" */ + if (os_info.dwMajorVersion == 10 && + os_info.dwBuildNumber >= 22000 && + product_name_w_size >= ARRAY_SIZE(L"Windows 10")) { + /* If ProductName starts with "Windows 10" */ + if (wcsncmp(product_name_w, L"Windows 10", ARRAY_SIZE(L"Windows 10") - 1) == 0) { + /* Bump 10 to 11 */ + product_name_w[9] = '1'; + } + } + version_size = WideCharToMultiByte(CP_UTF8, 0, product_name_w, From fb76f210eb6f093bc06a2f07646e56851818ccf2 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 21 Aug 2022 23:29:42 +0200 Subject: [PATCH 232/713] unix: fix uv_getrusage() ru_maxrss reporting (#3721) Most platforms report it in kilobytes but macOS and Solaris report it in bytes and pages respectively. Fixes: https://github.com/nodejs/node/issues/44332 --- docs/src/misc.rst | 5 ++++- src/unix/core.c | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index bae44814f19..f6d26efc287 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -119,7 +119,10 @@ Data types } uv_rusage_t; Members marked with `(X)` are unsupported on Windows. - See :man:`getrusage(2)` for supported fields on Unix + See :man:`getrusage(2)` for supported fields on UNIX-like platforms. + + The maximum resident set size is reported in kilobytes, the unit most + platforms use natively. .. c:type:: uv_cpu_info_t diff --git a/src/unix/core.c b/src/unix/core.c index a5fe9c08c9b..aaa980b86ef 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -986,6 +986,15 @@ int uv_getrusage(uv_rusage_t* rusage) { rusage->ru_nivcsw = usage.ru_nivcsw; #endif + /* Most platforms report ru_maxrss in kilobytes; macOS and Solaris are + * the outliers because of course they are. + */ +#if defined(__APPLE__) && !TARGET_OS_IPHONE + rusage->ru_maxrss /= 1024; /* macOS reports bytes. */ +#elif defined(__sun) + rusage->ru_maxrss /= getpagesize() / 1024; /* Solaris reports pages. */ +#endif + return 0; } From a855c741835380db3f9dc2b319e4d408c3d4a250 Mon Sep 17 00:00:00 2001 From: Steven Schveighoffer Date: Wed, 7 Sep 2022 11:19:08 -0400 Subject: [PATCH 233/713] doc: add note about offset -1 in uv_fs_read/write (#3677) --- docs/src/fs.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 0bf2abed5e1..e6e7088e573 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -218,7 +218,8 @@ API .. c:function:: int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb) - Equivalent to :man:`preadv(2)`. + Equivalent to :man:`preadv(2)`. If the `offset` argument is `-1`, then + the current file offset is used and updated. .. warning:: On Windows, under non-MSVC environments (e.g. when GCC or Clang is used @@ -231,7 +232,8 @@ API .. c:function:: int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb) - Equivalent to :man:`pwritev(2)`. + Equivalent to :man:`pwritev(2)`. If the `offset` argument is `-1`, then + the current file offset is used and updated. .. warning:: On Windows, under non-MSVC environments (e.g. when GCC or Clang is used From 9d898acc564351dde74e9ed9865144e5c41f5beb Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 7 Sep 2022 17:21:24 +0200 Subject: [PATCH 234/713] test: fix musl libc.a dlerror() test expectation (#3735) Dynamic loading with musl only works with libc.so because it is is implemented in musl's dynamic linker, not in libc proper. libc.a contains just a stub dlopen() that always fails with a "Dynamic loading not supported" error message. Update the test to handle that. Fix: https://github.com/libuv/libuv/issues/3706 --- test/test-dlerror.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/test-dlerror.c b/test/test-dlerror.c index a436ec016bf..631e67cc5f3 100644 --- a/test/test-dlerror.c +++ b/test/test-dlerror.c @@ -43,7 +43,9 @@ TEST_IMPL(dlerror) { msg = uv_dlerror(&lib); ASSERT_NOT_NULL(msg); #if !defined(__OpenBSD__) && !defined(__QNX__) - ASSERT_NOT_NULL(strstr(msg, path)); + /* musl's libc.a does not support dlopen(), only libc.so does. */ + if (NULL == strstr(msg, "Dynamic loading not supported")) + ASSERT_NOT_NULL(strstr(msg, path)); #endif ASSERT_NULL(strstr(msg, dlerror_no_error)); @@ -51,7 +53,9 @@ TEST_IMPL(dlerror) { msg = uv_dlerror(&lib); ASSERT_NOT_NULL(msg); #if !defined(__OpenBSD__) && !defined(__QNX__) - ASSERT_NOT_NULL(strstr(msg, path)); + /* musl's libc.a does not support dlopen(), only libc.so does. */ + if (NULL == strstr(msg, "Dynamic loading not supported")) + ASSERT_NOT_NULL(strstr(msg, path)); #endif ASSERT_NULL(strstr(msg, dlerror_no_error)); From 0f478a7de7416f067a738f51194891b683c046f2 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 12 Sep 2022 22:59:43 +0200 Subject: [PATCH 235/713] kqueue: DRY file descriptor deletion logic (#3746) Remove the TODO that says to batch up kevent(EV_DELETE) system calls. It's unduly complicated in case of errors. If you pass an out array to kevent(), it will store error records that tell you which file descriptor caused the error but it also stores new events in the array, complicating state management. If you don't pass an out array, it simply doesn't tell you anything except that _something_ failed. Optimistically trying batch deletion and falling back to one-by-one deletion is probably possible but is something of a deoptimization and also feels somewhat dangerous. macOS has a mostly-undocumented kevent_qos() system call that accepts a KEVENT_FLAG_ERROR_EVENTS flag that fixes the first problem but that of course isn't portable. Long story short, it seems like too much hassle for too little payoff. Libuv has been doing one-by-one deletion for over a decade now and no one complained about performance so far so let's just stick with that. --- src/unix/kqueue.c | 63 ++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 8c5617b2ada..c7fbba94065 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -109,6 +109,21 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { } +static void uv__kqueue_delete(int kqfd, const struct kevent *ev) { + struct kevent change; + + EV_SET(&change, ev->ident, ev->filter, EV_DELETE, 0, 0, 0); + + if (0 == kevent(kqfd, &change, 1, NULL, 0, NULL)) + return; + + if (errno == EBADF || errno == ENOENT) + return; + + abort(); +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { struct kevent events[1024]; struct kevent* ev; @@ -307,15 +322,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w = loop->watchers[fd]; if (w == NULL) { - /* File descriptor that we've stopped watching, disarm it. - * TODO: batch up. */ - struct kevent events[1]; - - EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); - if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) - if (errno != EBADF && errno != ENOENT) - abort(); - + /* File descriptor that we've stopped watching, disarm it. */ + uv__kqueue_delete(loop->backend_fd, ev); continue; } @@ -331,44 +339,27 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { revents = 0; if (ev->filter == EVFILT_READ) { - if (w->pevents & POLLIN) { + if (w->pevents & POLLIN) revents |= POLLIN; - } else { - /* TODO batch up */ - struct kevent events[1]; - EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); - if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) - if (errno != ENOENT) - abort(); - } + else + uv__kqueue_delete(loop->backend_fd, ev); + if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) revents |= UV__POLLRDHUP; } if (ev->filter == EV_OOBAND) { - if (w->pevents & UV__POLLPRI) { + if (w->pevents & UV__POLLPRI) revents |= UV__POLLPRI; - } else { - /* TODO batch up */ - struct kevent events[1]; - EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); - if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) - if (errno != ENOENT) - abort(); - } + else + uv__kqueue_delete(loop->backend_fd, ev); } if (ev->filter == EVFILT_WRITE) { - if (w->pevents & POLLOUT) { + if (w->pevents & POLLOUT) revents |= POLLOUT; - } else { - /* TODO batch up */ - struct kevent events[1]; - EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); - if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) - if (errno != ENOENT) - abort(); - } + else + uv__kqueue_delete(loop->backend_fd, ev); } if (ev->flags & EV_ERROR) From d59b2905f9e0e8cddd7033e3a0b87cdec415c908 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 15 Sep 2022 08:56:56 +0200 Subject: [PATCH 236/713] linux: teach uv_get_constrained_memory() cgroupsv2 (#3744) Fixes: https://github.com/libuv/libuv/issues/2315 --- src/unix/linux-core.c | 54 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 23a7dafec81..75491f4b7cd 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -793,27 +793,61 @@ uint64_t uv_get_total_memory(void) { } -static uint64_t uv__read_cgroups_uint64(const char* cgroup, const char* param) { - char filename[256]; +static uint64_t uv__read_uint64(const char* filename) { char buf[32]; /* Large enough to hold an encoded uint64_t. */ uint64_t rc; rc = 0; - snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%s/%s", cgroup, param); if (0 == uv__slurp(filename, buf, sizeof(buf))) - sscanf(buf, "%" PRIu64, &rc); + if (1 != sscanf(buf, "%" PRIu64, &rc)) + if (0 == strcmp(buf, "max\n")) + rc = ~0ull; return rc; } +/* This might return 0 if there was a problem getting the memory limit from + * cgroups. This is OK because a return value of 0 signifies that the memory + * limit is unknown. + */ +static uint64_t uv__get_constrained_memory_fallback(void) { + return uv__read_uint64("/sys/fs/cgroup/memory/memory.limit_in_bytes"); +} + + uint64_t uv_get_constrained_memory(void) { - /* - * This might return 0 if there was a problem getting the memory limit from - * cgroups. This is OK because a return value of 0 signifies that the memory - * limit is unknown. - */ - return uv__read_cgroups_uint64("memory", "memory.limit_in_bytes"); + char filename[4097]; + char buf[1024]; + uint64_t high; + uint64_t max; + char* p; + + if (uv__slurp("/proc/self/cgroup", buf, sizeof(buf))) + return uv__get_constrained_memory_fallback(); + + if (memcmp(buf, "0::/", 4)) + return uv__get_constrained_memory_fallback(); + + p = strchr(buf, '\n'); + if (p != NULL) + *p = '\0'; + + p = buf + 4; + + snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%s/memory.max", p); + max = uv__read_uint64(filename); + + if (max == 0) + return uv__get_constrained_memory_fallback(); + + snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%s/memory.high", p); + high = uv__read_uint64(filename); + + if (high == 0) + return uv__get_constrained_memory_fallback(); + + return high < max ? high : max; } From 48c90d3781a37102afc6008d8795f4c3595de14e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 18 Sep 2022 13:56:43 +0200 Subject: [PATCH 237/713] build: upgrade qemu-user-static package 4.2 is three years old by now. The linux/alpha emulator in that version doesn't support the epoll_create1() system call. --- .github/workflows/CI-unix.yml | 8 ++------ test/test-fs.c | 7 +++++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index d0d2d46edbe..feef54e39fb 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -104,13 +104,9 @@ jobs: - uses: actions/checkout@v2 - name: Install QEMU # this ensure install latest qemu on ubuntu, apt get version is old - env: - QEMU_SRC: "http://archive.ubuntu.com/ubuntu/pool/universe/q/qemu" - QEMU_VER: "qemu-user-static_4\\.2-.*_amd64.deb$" run: | - DEB=`curl -s $QEMU_SRC/ | grep -o -E 'href="([^"#]+)"' | cut -d'"' -f2 | grep $QEMU_VER | tail -1` - wget $QEMU_SRC/$DEB - sudo dpkg -i $DEB + wget http://archive.ubuntu.com/ubuntu/pool/universe/q/qemu/qemu-user-static_7.0+dfsg-7ubuntu1_amd64.deb + sudo dpkg -i qemu-user-static_7.0+dfsg-7ubuntu1_amd64.deb - name: Install ${{ matrix.config.toolchain }} run: | sudo apt update diff --git a/test/test-fs.c b/test/test-fs.c index c879f629848..13d7b448d51 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1393,6 +1393,13 @@ TEST_IMPL(fs_fstat) { struct stat t; #endif +#if defined(__s390__) && defined(__QEMU__) + /* qemu-user-s390x has this weird bug where statx() reports nanoseconds + * but plain fstat() does not. + */ + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + /* Setup. */ unlink("test_file"); From d651403b47e7d32806bfc4dd6f6f2f11ea77bf3f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 18 Sep 2022 13:14:10 +0200 Subject: [PATCH 238/713] linux: move epoll.c back into linux-core.c epoll.c is only used on Android and Linux after commit 5fe59726 ("sunos: restore use of event ports") so move it back into linux-core.c This commit removes a workaround for pre-2.6.27 kernels that don't have the epoll_create1() system call. --- CMakeLists.txt | 6 +- Makefile.am | 3 +- src/unix/epoll.c | 422 ------------------------------------------ src/unix/internal.h | 1 - src/unix/linux-core.c | 383 +++++++++++++++++++++++++++++++++++++- 5 files changed, 383 insertions(+), 432 deletions(-) delete mode 100644 src/unix/epoll.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c42c3ffe21..d64740c33d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -226,8 +226,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android") src/unix/procfs-exepath.c src/unix/random-getentropy.c src/unix/random-getrandom.c - src/unix/random-sysctl-linux.c - src/unix/epoll.c) + src/unix/random-sysctl-linux.c) endif() if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "Android|Linux") @@ -287,8 +286,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") src/unix/linux-syscalls.c src/unix/procfs-exepath.c src/unix/random-getrandom.c - src/unix/random-sysctl-linux.c - src/unix/epoll.c) + src/unix/random-sysctl-linux.c) endif() if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") diff --git a/Makefile.am b/Makefile.am index 542f63356df..01329362e7d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -478,8 +478,7 @@ libuv_la_SOURCES += src/unix/linux-core.c \ src/unix/procfs-exepath.c \ src/unix/proctitle.c \ src/unix/random-getrandom.c \ - src/unix/random-sysctl-linux.c \ - src/unix/epoll.c + src/unix/random-sysctl-linux.c test_run_tests_LDFLAGS += -lutil endif diff --git a/src/unix/epoll.c b/src/unix/epoll.c deleted file mode 100644 index 97348e254b4..00000000000 --- a/src/unix/epoll.c +++ /dev/null @@ -1,422 +0,0 @@ -/* Copyright libuv contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "uv.h" -#include "internal.h" -#include -#include - -int uv__epoll_init(uv_loop_t* loop) { - int fd; - fd = epoll_create1(O_CLOEXEC); - - /* epoll_create1() can fail either because it's not implemented (old kernel) - * or because it doesn't understand the O_CLOEXEC flag. - */ - if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) { - fd = epoll_create(256); - - if (fd != -1) - uv__cloexec(fd, 1); - } - - loop->backend_fd = fd; - if (fd == -1) - return UV__ERR(errno); - - return 0; -} - - -void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { - struct epoll_event* events; - struct epoll_event dummy; - uintptr_t i; - uintptr_t nfds; - - assert(loop->watchers != NULL); - assert(fd >= 0); - - events = (struct epoll_event*) loop->watchers[loop->nwatchers]; - nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; - if (events != NULL) - /* Invalidate events with same file descriptor */ - for (i = 0; i < nfds; i++) - if (events[i].data.fd == fd) - events[i].data.fd = -1; - - /* Remove the file descriptor from the epoll. - * This avoids a problem where the same file description remains open - * in another process, causing repeated junk epoll events. - * - * We pass in a dummy epoll_event, to work around a bug in old kernels. - */ - if (loop->backend_fd >= 0) { - /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that - * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. - */ - memset(&dummy, 0, sizeof(dummy)); - epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy); - } -} - - -int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct epoll_event e; - int rc; - - memset(&e, 0, sizeof(e)); - e.events = POLLIN; - e.data.fd = -1; - - rc = 0; - if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e)) - if (errno != EEXIST) - rc = UV__ERR(errno); - - if (rc == 0) - if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e)) - abort(); - - return rc; -} - - -void uv__io_poll(uv_loop_t* loop, int timeout) { - /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes - * effectively infinite on 32 bits architectures. To avoid blocking - * indefinitely, we cap the timeout and poll again if necessary. - * - * Note that "30 minutes" is a simplification because it depends on - * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200, - * that being the largest value I have seen in the wild (and only once.) - */ - static const int max_safe_timeout = 1789569; - static int no_epoll_pwait_cached; - static int no_epoll_wait_cached; - int no_epoll_pwait; - int no_epoll_wait; - struct epoll_event events[1024]; - struct epoll_event* pe; - struct epoll_event e; - int real_timeout; - QUEUE* q; - uv__io_t* w; - sigset_t sigset; - uint64_t sigmask; - uint64_t base; - int have_signals; - int nevents; - int count; - int nfds; - int fd; - int op; - int i; - int user_timeout; - int reset_timeout; - - if (loop->nfds == 0) { - assert(QUEUE_EMPTY(&loop->watcher_queue)); - return; - } - - memset(&e, 0, sizeof(e)); - - while (!QUEUE_EMPTY(&loop->watcher_queue)) { - q = QUEUE_HEAD(&loop->watcher_queue); - QUEUE_REMOVE(q); - QUEUE_INIT(q); - - w = QUEUE_DATA(q, uv__io_t, watcher_queue); - assert(w->pevents != 0); - assert(w->fd >= 0); - assert(w->fd < (int) loop->nwatchers); - - e.events = w->pevents; - e.data.fd = w->fd; - - if (w->events == 0) - op = EPOLL_CTL_ADD; - else - op = EPOLL_CTL_MOD; - - /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching - * events, skip the syscall and squelch the events after epoll_wait(). - */ - if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) { - if (errno != EEXIST) - abort(); - - assert(op == EPOLL_CTL_ADD); - - /* We've reactivated a file descriptor that's been watched before. */ - if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e)) - abort(); - } - - w->events = w->pevents; - } - - sigmask = 0; - if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { - sigemptyset(&sigset); - sigaddset(&sigset, SIGPROF); - sigmask |= 1 << (SIGPROF - 1); - } - - assert(timeout >= -1); - base = loop->time; - count = 48; /* Benchmarks suggest this gives the best throughput. */ - real_timeout = timeout; - - if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { - reset_timeout = 1; - user_timeout = timeout; - timeout = 0; - } else { - reset_timeout = 0; - user_timeout = 0; - } - - /* You could argue there is a dependency between these two but - * ultimately we don't care about their ordering with respect - * to one another. Worst case, we make a few system calls that - * could have been avoided because another thread already knows - * they fail with ENOSYS. Hardly the end of the world. - */ - no_epoll_pwait = uv__load_relaxed(&no_epoll_pwait_cached); - no_epoll_wait = uv__load_relaxed(&no_epoll_wait_cached); - - for (;;) { - /* Only need to set the provider_entry_time if timeout != 0. The function - * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. - */ - if (timeout != 0) - uv__metrics_set_provider_entry_time(loop); - - /* See the comment for max_safe_timeout for an explanation of why - * this is necessary. Executive summary: kernel bug workaround. - */ - if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) - timeout = max_safe_timeout; - - if (sigmask != 0 && no_epoll_pwait != 0) - if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) - abort(); - - if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) { - nfds = epoll_pwait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout, - &sigset); - if (nfds == -1 && errno == ENOSYS) { - uv__store_relaxed(&no_epoll_pwait_cached, 1); - no_epoll_pwait = 1; - } - } else { - nfds = epoll_wait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout); - if (nfds == -1 && errno == ENOSYS) { - uv__store_relaxed(&no_epoll_wait_cached, 1); - no_epoll_wait = 1; - } - } - - if (sigmask != 0 && no_epoll_pwait != 0) - if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)) - abort(); - - /* Update loop->time unconditionally. It's tempting to skip the update when - * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the - * operating system didn't reschedule our process while in the syscall. - */ - SAVE_ERRNO(uv__update_time(loop)); - - if (nfds == 0) { - assert(timeout != -1); - - if (reset_timeout != 0) { - timeout = user_timeout; - reset_timeout = 0; - } - - if (timeout == -1) - continue; - - if (timeout == 0) - return; - - /* We may have been inside the system call for longer than |timeout| - * milliseconds so we need to update the timestamp to avoid drift. - */ - goto update_timeout; - } - - if (nfds == -1) { - if (errno == ENOSYS) { - /* epoll_wait() or epoll_pwait() failed, try the other system call. */ - assert(no_epoll_wait == 0 || no_epoll_pwait == 0); - continue; - } - - if (errno != EINTR) - abort(); - - if (reset_timeout != 0) { - timeout = user_timeout; - reset_timeout = 0; - } - - if (timeout == -1) - continue; - - if (timeout == 0) - return; - - /* Interrupted by a signal. Update timeout and poll again. */ - goto update_timeout; - } - - have_signals = 0; - nevents = 0; - - { - /* Squelch a -Waddress-of-packed-member warning with gcc >= 9. */ - union { - struct epoll_event* events; - uv__io_t* watchers; - } x; - - x.events = events; - assert(loop->watchers != NULL); - loop->watchers[loop->nwatchers] = x.watchers; - loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; - } - - for (i = 0; i < nfds; i++) { - pe = events + i; - fd = pe->data.fd; - - /* Skip invalidated events, see uv__platform_invalidate_fd */ - if (fd == -1) - continue; - - assert(fd >= 0); - assert((unsigned) fd < loop->nwatchers); - - w = loop->watchers[fd]; - - if (w == NULL) { - /* File descriptor that we've stopped watching, disarm it. - * - * Ignore all errors because we may be racing with another thread - * when the file descriptor is closed. - */ - epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe); - continue; - } - - /* Give users only events they're interested in. Prevents spurious - * callbacks when previous callback invocation in this loop has stopped - * the current watcher. Also, filters out events that users has not - * requested us to watch. - */ - pe->events &= w->pevents | POLLERR | POLLHUP; - - /* Work around an epoll quirk where it sometimes reports just the - * EPOLLERR or EPOLLHUP event. In order to force the event loop to - * move forward, we merge in the read/write events that the watcher - * is interested in; uv__read() and uv__write() will then deal with - * the error or hangup in the usual fashion. - * - * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user - * reads the available data, calls uv_read_stop(), then sometime later - * calls uv_read_start() again. By then, libuv has forgotten about the - * hangup and the kernel won't report EPOLLIN again because there's - * nothing left to read. If anything, libuv is to blame here. The - * current hack is just a quick bandaid; to properly fix it, libuv - * needs to remember the error/hangup event. We should get that for - * free when we switch over to edge-triggered I/O. - */ - if (pe->events == POLLERR || pe->events == POLLHUP) - pe->events |= - w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); - - if (pe->events != 0) { - /* Run signal watchers last. This also affects child process watchers - * because those are implemented in terms of signal watchers. - */ - if (w == &loop->signal_io_watcher) { - have_signals = 1; - } else { - uv__metrics_update_idle_time(loop); - w->cb(loop, w, pe->events); - } - - nevents++; - } - } - - if (reset_timeout != 0) { - timeout = user_timeout; - reset_timeout = 0; - } - - if (have_signals != 0) { - uv__metrics_update_idle_time(loop); - loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); - } - - loop->watchers[loop->nwatchers] = NULL; - loop->watchers[loop->nwatchers + 1] = NULL; - - if (have_signals != 0) - return; /* Event loop should cycle now so don't poll again. */ - - if (nevents != 0) { - if (nfds == ARRAY_SIZE(events) && --count != 0) { - /* Poll for more events but don't block this time. */ - timeout = 0; - continue; - } - return; - } - - if (timeout == 0) - return; - - if (timeout == -1) - continue; - -update_timeout: - assert(timeout > 0); - - real_timeout -= (loop->time - base); - if (real_timeout <= 0) - return; - - timeout = real_timeout; - } -} - diff --git a/src/unix/internal.h b/src/unix/internal.h index 65f09807130..bb5f596285d 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -250,7 +250,6 @@ int uv__signal_loop_fork(uv_loop_t* loop); /* platform specific */ uint64_t uv__hrtime(uv_clocktype_t type); int uv__kqueue_init(uv_loop_t* loop); -int uv__epoll_init(uv_loop_t* loop); int uv__platform_loop_init(uv_loop_t* loop); void uv__platform_loop_delete(uv_loop_t* loop); void uv__platform_invalidate_fd(uv_loop_t* loop, int fd); diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 75491f4b7cd..40266451993 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -82,12 +82,16 @@ static int read_times(FILE* statfile_fp, static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); static uint64_t read_cpufreq(unsigned int cpunum); + int uv__platform_loop_init(uv_loop_t* loop) { - - loop->inotify_fd = -1; loop->inotify_watchers = NULL; + loop->inotify_fd = -1; + loop->backend_fd = epoll_create1(O_CLOEXEC); + + if (loop->backend_fd == -1) + return UV__ERR(errno); - return uv__epoll_init(loop); + return 0; } @@ -117,6 +121,379 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct epoll_event* events; + struct epoll_event dummy; + uintptr_t i; + uintptr_t nfds; + + assert(loop->watchers != NULL); + assert(fd >= 0); + + events = (struct epoll_event*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; + if (events != NULL) + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if (events[i].data.fd == fd) + events[i].data.fd = -1; + + /* Remove the file descriptor from the epoll. + * This avoids a problem where the same file description remains open + * in another process, causing repeated junk epoll events. + * + * We pass in a dummy epoll_event, to work around a bug in old kernels. + */ + if (loop->backend_fd >= 0) { + /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that + * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. + */ + memset(&dummy, 0, sizeof(dummy)); + epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy); + } +} + + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct epoll_event e; + int rc; + + memset(&e, 0, sizeof(e)); + e.events = POLLIN; + e.data.fd = -1; + + rc = 0; + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e)) + if (errno != EEXIST) + rc = UV__ERR(errno); + + if (rc == 0) + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e)) + abort(); + + return rc; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes + * effectively infinite on 32 bits architectures. To avoid blocking + * indefinitely, we cap the timeout and poll again if necessary. + * + * Note that "30 minutes" is a simplification because it depends on + * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200, + * that being the largest value I have seen in the wild (and only once.) + */ + static const int max_safe_timeout = 1789569; + static int no_epoll_pwait_cached; + static int no_epoll_wait_cached; + int no_epoll_pwait; + int no_epoll_wait; + struct epoll_event events[1024]; + struct epoll_event* pe; + struct epoll_event e; + int real_timeout; + QUEUE* q; + uv__io_t* w; + sigset_t sigset; + uint64_t sigmask; + uint64_t base; + int have_signals; + int nevents; + int count; + int nfds; + int fd; + int op; + int i; + int user_timeout; + int reset_timeout; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + memset(&e, 0, sizeof(e)); + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + e.events = w->pevents; + e.data.fd = w->fd; + + if (w->events == 0) + op = EPOLL_CTL_ADD; + else + op = EPOLL_CTL_MOD; + + /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching + * events, skip the syscall and squelch the events after epoll_wait(). + */ + if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) { + if (errno != EEXIST) + abort(); + + assert(op == EPOLL_CTL_ADD); + + /* We've reactivated a file descriptor that's been watched before. */ + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e)) + abort(); + } + + w->events = w->pevents; + } + + sigmask = 0; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + sigemptyset(&sigset); + sigaddset(&sigset, SIGPROF); + sigmask |= 1 << (SIGPROF - 1); + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + real_timeout = timeout; + + if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + reset_timeout = 1; + user_timeout = timeout; + timeout = 0; + } else { + reset_timeout = 0; + user_timeout = 0; + } + + /* You could argue there is a dependency between these two but + * ultimately we don't care about their ordering with respect + * to one another. Worst case, we make a few system calls that + * could have been avoided because another thread already knows + * they fail with ENOSYS. Hardly the end of the world. + */ + no_epoll_pwait = uv__load_relaxed(&no_epoll_pwait_cached); + no_epoll_wait = uv__load_relaxed(&no_epoll_wait_cached); + + for (;;) { + /* Only need to set the provider_entry_time if timeout != 0. The function + * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. + */ + if (timeout != 0) + uv__metrics_set_provider_entry_time(loop); + + /* See the comment for max_safe_timeout for an explanation of why + * this is necessary. Executive summary: kernel bug workaround. + */ + if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) + timeout = max_safe_timeout; + + if (sigmask != 0 && no_epoll_pwait != 0) + if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) + abort(); + + if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) { + nfds = epoll_pwait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout, + &sigset); + if (nfds == -1 && errno == ENOSYS) { + uv__store_relaxed(&no_epoll_pwait_cached, 1); + no_epoll_pwait = 1; + } + } else { + nfds = epoll_wait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout); + if (nfds == -1 && errno == ENOSYS) { + uv__store_relaxed(&no_epoll_wait_cached, 1); + no_epoll_wait = 1; + } + } + + if (sigmask != 0 && no_epoll_pwait != 0) + if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)) + abort(); + + /* Update loop->time unconditionally. It's tempting to skip the update when + * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the + * operating system didn't reschedule our process while in the syscall. + */ + SAVE_ERRNO(uv__update_time(loop)); + + if (nfds == 0) { + assert(timeout != -1); + + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* We may have been inside the system call for longer than |timeout| + * milliseconds so we need to update the timestamp to avoid drift. + */ + goto update_timeout; + } + + if (nfds == -1) { + if (errno == ENOSYS) { + /* epoll_wait() or epoll_pwait() failed, try the other system call. */ + assert(no_epoll_wait == 0 || no_epoll_pwait == 0); + continue; + } + + if (errno != EINTR) + abort(); + + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + have_signals = 0; + nevents = 0; + + { + /* Squelch a -Waddress-of-packed-member warning with gcc >= 9. */ + union { + struct epoll_event* events; + uv__io_t* watchers; + } x; + + x.events = events; + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = x.watchers; + loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; + } + + for (i = 0; i < nfds; i++) { + pe = events + i; + fd = pe->data.fd; + + /* Skip invalidated events, see uv__platform_invalidate_fd */ + if (fd == -1) + continue; + + assert(fd >= 0); + assert((unsigned) fd < loop->nwatchers); + + w = loop->watchers[fd]; + + if (w == NULL) { + /* File descriptor that we've stopped watching, disarm it. + * + * Ignore all errors because we may be racing with another thread + * when the file descriptor is closed. + */ + epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe); + continue; + } + + /* Give users only events they're interested in. Prevents spurious + * callbacks when previous callback invocation in this loop has stopped + * the current watcher. Also, filters out events that users has not + * requested us to watch. + */ + pe->events &= w->pevents | POLLERR | POLLHUP; + + /* Work around an epoll quirk where it sometimes reports just the + * EPOLLERR or EPOLLHUP event. In order to force the event loop to + * move forward, we merge in the read/write events that the watcher + * is interested in; uv__read() and uv__write() will then deal with + * the error or hangup in the usual fashion. + * + * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user + * reads the available data, calls uv_read_stop(), then sometime later + * calls uv_read_start() again. By then, libuv has forgotten about the + * hangup and the kernel won't report EPOLLIN again because there's + * nothing left to read. If anything, libuv is to blame here. The + * current hack is just a quick bandaid; to properly fix it, libuv + * needs to remember the error/hangup event. We should get that for + * free when we switch over to edge-triggered I/O. + */ + if (pe->events == POLLERR || pe->events == POLLHUP) + pe->events |= + w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); + + if (pe->events != 0) { + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) { + have_signals = 1; + } else { + uv__metrics_update_idle_time(loop); + w->cb(loop, w, pe->events); + } + + nevents++; + } + } + + if (reset_timeout != 0) { + timeout = user_timeout; + reset_timeout = 0; + } + + if (have_signals != 0) { + uv__metrics_update_idle_time(loop); + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + } + + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) { + if (nfds == ARRAY_SIZE(events) && --count != 0) { + /* Poll for more events but don't block this time. */ + timeout = 0; + continue; + } + return; + } + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + real_timeout -= (loop->time - base); + if (real_timeout <= 0) + return; + + timeout = real_timeout; + } +} uint64_t uv__hrtime(uv_clocktype_t type) { static clock_t fast_clock_id = -1; From 47effc4bd39e4e13c59102bab3e789783725ecb6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 22 Sep 2022 09:25:35 +0200 Subject: [PATCH 239/713] unix: remove pre-macos 10.8 compatibility hack (#3759) --- src/unix/fs.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 933c9c0dc2d..902cd772a7e 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -527,19 +527,12 @@ static ssize_t uv__fs_read(uv_fs_t* req) { } -#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8) -#define UV_CONST_DIRENT uv__dirent_t -#else -#define UV_CONST_DIRENT const uv__dirent_t -#endif - - -static int uv__fs_scandir_filter(UV_CONST_DIRENT* dent) { +static int uv__fs_scandir_filter(const uv__dirent_t* dent) { return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0; } -static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) { +static int uv__fs_scandir_sort(const uv__dirent_t** a, const uv__dirent_t** b) { return strcmp((*a)->d_name, (*b)->d_name); } From b00d1bd225b602570baee82a6152eaa823a84fa6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 22 Sep 2022 09:25:55 +0200 Subject: [PATCH 240/713] unix,win: fix memory leak in uv_fs_scandir() (#3760) uv_fs_scandir() leaked an entry when you called it on a directory with a single entry _and_ you didn't run the iterator until UV_EOF. Fixes: https://github.com/libuv/libuv/issues/3748 --- Makefile.am | 1 + src/uv-common.c | 20 ++++++++++++++------ test/fixtures/one_file/one_file | 0 test/test-fs.c | 18 ++++++++++++++++++ test/test-list.h | 2 ++ 5 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 test/fixtures/one_file/one_file diff --git a/Makefile.am b/Makefile.am index 01329362e7d..deec449de4f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -120,6 +120,7 @@ endif # WINNT EXTRA_DIST = test/fixtures/empty_file \ test/fixtures/load_error.node \ test/fixtures/lorem_ipsum.txt \ + test/fixtures/one_file/one_file \ include \ docs \ img \ diff --git a/src/uv-common.c b/src/uv-common.c index efc9eb50ee3..6bb574738c0 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -650,14 +650,22 @@ static unsigned int* uv__get_nbufs(uv_fs_t* req) { void uv__fs_scandir_cleanup(uv_fs_t* req) { uv__dirent_t** dents; + unsigned int* nbufs; + unsigned int i; + unsigned int n; - unsigned int* nbufs = uv__get_nbufs(req); + if (req->result >= 0) { + dents = req->ptr; + nbufs = uv__get_nbufs(req); - dents = req->ptr; - if (*nbufs > 0 && *nbufs != (unsigned int) req->result) - (*nbufs)--; - for (; *nbufs < (unsigned int) req->result; (*nbufs)++) - uv__fs_scandir_free(dents[*nbufs]); + i = 0; + if (*nbufs > 0) + i = *nbufs - 1; + + n = (unsigned int) req->result; + for (; i < n; i++) + uv__fs_scandir_free(dents[i]); + } uv__fs_scandir_free(req->ptr); req->ptr = NULL; diff --git a/test/fixtures/one_file/one_file b/test/fixtures/one_file/one_file new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/test-fs.c b/test/test-fs.c index 13d7b448d51..e49eaa9b30f 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2931,6 +2931,24 @@ TEST_IMPL(fs_scandir_file) { } +/* Run in Valgrind. Should not leak when the iterator isn't exhausted. */ +TEST_IMPL(fs_scandir_early_exit) { + uv_dirent_t d; + uv_fs_t req; + + ASSERT_LT(0, uv_fs_scandir(NULL, &req, "test/fixtures/one_file", 0, NULL)); + ASSERT_NE(UV_EOF, uv_fs_scandir_next(&req, &d)); + uv_fs_req_cleanup(&req); + + ASSERT_LT(0, uv_fs_scandir(NULL, &req, "test/fixtures", 0, NULL)); + ASSERT_NE(UV_EOF, uv_fs_scandir_next(&req, &d)); + uv_fs_req_cleanup(&req); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + TEST_IMPL(fs_open_dir) { const char* path; uv_fs_t req; diff --git a/test/test-list.h b/test/test-list.h index b19c10c7e40..ce4d4920cb6 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -401,6 +401,7 @@ TEST_DECLARE (fs_event_stop_in_cb) TEST_DECLARE (fs_scandir_empty_dir) TEST_DECLARE (fs_scandir_non_existent_dir) TEST_DECLARE (fs_scandir_file) +TEST_DECLARE (fs_scandir_early_exit) TEST_DECLARE (fs_open_dir) TEST_DECLARE (fs_readdir_empty_dir) TEST_DECLARE (fs_readdir_file) @@ -1071,6 +1072,7 @@ TASK_LIST_START TEST_ENTRY (fs_scandir_empty_dir) TEST_ENTRY (fs_scandir_non_existent_dir) TEST_ENTRY (fs_scandir_file) + TEST_ENTRY (fs_scandir_early_exit) TEST_ENTRY (fs_open_dir) TEST_ENTRY (fs_readdir_empty_dir) TEST_ENTRY (fs_readdir_file) From c798dd7ae58d18d982bda5471dc77b364c7ed565 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 26 Sep 2022 11:29:50 +0200 Subject: [PATCH 241/713] build: restore qemu download logic (#3768) I recently changed it to download a fixed .deb but seems it's updated more frequently than I anticipated because the dfsg-7ubuntu1_package is already gone, replaced with dfsg-7ubuntu2. Bring back the downloader logic that fetches the filename from the directory listing. --- .github/workflows/CI-unix.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index feef54e39fb..7ef80a623ce 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -104,9 +104,13 @@ jobs: - uses: actions/checkout@v2 - name: Install QEMU # this ensure install latest qemu on ubuntu, apt get version is old + env: + QEMU_SRC: "http://archive.ubuntu.com/ubuntu/pool/universe/q/qemu" + QEMU_VER: "qemu-user-static_7\\.0+dfsg-.*_amd64.deb$" run: | - wget http://archive.ubuntu.com/ubuntu/pool/universe/q/qemu/qemu-user-static_7.0+dfsg-7ubuntu1_amd64.deb - sudo dpkg -i qemu-user-static_7.0+dfsg-7ubuntu1_amd64.deb + DEB=`curl -s $QEMU_SRC/ | grep -o -E 'href="([^"#]+)"' | cut -d'"' -f2 | grep $QEMU_VER | tail -1` + wget $QEMU_SRC/$DEB + sudo dpkg -i $DEB - name: Install ${{ matrix.config.toolchain }} run: | sudo apt update From 81264cfcaf05b09b4733eaa607969d52b4856e34 Mon Sep 17 00:00:00 2001 From: number201724 Date: Mon, 26 Sep 2022 17:35:23 +0800 Subject: [PATCH 242/713] win: fix uv__pipe_accept memory leak (#3767) --- src/win/pipe.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index bf605b101e4..1babe05c24c 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1067,11 +1067,12 @@ 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; - uv__free(item); - } else { pipe_client = (uv_pipe_t*) client; uv__pipe_connection_init(pipe_client); From cdbba74d7a756587a696fb3545051f9a525b85ac Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 27 Sep 2022 08:43:40 -0700 Subject: [PATCH 243/713] doc: update LINKS.md (#3772) --- LINKS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LINKS.md b/LINKS.md index b8204e56e16..6f91d08a274 100644 --- a/LINKS.md +++ b/LINKS.md @@ -10,7 +10,7 @@ * [H2O](https://github.com/h2o/h2o): An optimized HTTP server with support for HTTP/1.x and HTTP/2. * [Igropyr](https://github.com/guenchi/Igropyr): a async Scheme http server base on libuv. * [Julia](http://julialang.org/): Scientific computing programming language -* [Kestrel](https://github.com/aspnet/AspNetCore/tree/master/src/Servers/Kestrel): web server (C# + libuv + [ASP.NET Core](http://github.com/aspnet)) +* [Kestrel](https://github.com/dotnet/aspnetcore/tree/main/src/Servers/Kestrel): web server (C# + libuv + [ASP.NET Core](http://github.com/aspnet)) * [Knot DNS Resolver](https://www.knot-resolver.cz/): A minimalistic DNS caching resolver * [Lever](http://leverlanguage.com): runtime, libuv at the 0.9.0 release * [libnode](https://github.com/plenluno/libnode): C++ implementation of Node.js From 71a782b64125b2dc1d9ecdf62aec934df55c53be Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 1 Oct 2022 13:43:47 +0200 Subject: [PATCH 244/713] unix: simplify atomic op in uv_tty_reset_mode() (#3773) Compare-and-exchange is only useful in a loop. Replace it with a simple exchange. --- src/unix/tty.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/unix/tty.c b/src/unix/tty.c index a5bad72fe57..4c220e56521 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -447,13 +447,11 @@ uv_handle_type uv_guess_handle(uv_file file) { */ int uv_tty_reset_mode(void) { int saved_errno; - int expected; int err; saved_errno = errno; - expected = 0; - if (!atomic_compare_exchange_strong(&termios_spinlock, &expected, 1)) + if (atomic_exchange(&termios_spinlock, 1)) return UV_EBUSY; /* In uv_tty_set_mode(). */ err = 0; From f610339f74f7f0fcd183533d2c965ce1468b44c6 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 1 Oct 2022 19:51:09 +0200 Subject: [PATCH 245/713] build: add LIBUV_BUILD_SHARED cmake option (#3762) Co-authored-by: Tim Tavlintsev Fixes: https://github.com/libuv/libuv/issues/3637 --- CMakeLists.txt | 68 +++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d64740c33d1..3fde4091769 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,9 +21,11 @@ set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) set(CMAKE_C_STANDARD 90) +option(LIBUV_BUILD_SHARED "Build shared lib" ON) + cmake_dependent_option(LIBUV_BUILD_TESTS "Build the unit tests when BUILD_TESTING is enabled and we are the root project" ON - "BUILD_TESTING;CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) + "BUILD_TESTING;LIBUV_BUILD_SHARED;CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) cmake_dependent_option(LIBUV_BUILD_BENCH "Build the benchmarks when building unit tests and we are the root project" ON "LIBUV_BUILD_TESTS" OFF) @@ -388,25 +390,27 @@ if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|Linux|NetBSD|OpenBSD") list(APPEND uv_test_libraries util) endif() -add_library(uv SHARED ${uv_sources}) -target_compile_definitions(uv - INTERFACE - USING_UV_SHARED=1 - PRIVATE - BUILDING_UV_SHARED=1 - ${uv_defines}) -target_compile_options(uv PRIVATE ${uv_cflags}) -target_include_directories(uv - PUBLIC - $ - $ - PRIVATE - $) -if(CMAKE_SYSTEM_NAME STREQUAL "OS390") - target_include_directories(uv PUBLIC $) - set_target_properties(uv PROPERTIES LINKER_LANGUAGE CXX) +if(LIBUV_BUILD_SHARED) + add_library(uv SHARED ${uv_sources}) + target_compile_definitions(uv + INTERFACE + USING_UV_SHARED=1 + PRIVATE + BUILDING_UV_SHARED=1 + ${uv_defines}) + target_compile_options(uv PRIVATE ${uv_cflags}) + target_include_directories(uv + PUBLIC + $ + $ + PRIVATE + $) + if(CMAKE_SYSTEM_NAME STREQUAL "OS390") + target_include_directories(uv PUBLIC $) + set_target_properties(uv PROPERTIES LINKER_LANGUAGE CXX) + endif() + target_link_libraries(uv ${uv_libraries}) endif() -target_link_libraries(uv ${uv_libraries}) add_library(uv_a STATIC ${uv_sources}) target_compile_definitions(uv_a PRIVATE ${uv_defines}) @@ -667,28 +671,34 @@ string(REPLACE ";" " " LIBS "${LIBS}") file(STRINGS configure.ac configure_ac REGEX ^AC_INIT) string(REGEX MATCH "([0-9]+)[.][0-9]+[.][0-9]+" PACKAGE_VERSION "${configure_ac}") set(UV_VERSION_MAJOR "${CMAKE_MATCH_1}") -# The version in the filename is mirroring the behaviour of autotools. -set_target_properties(uv PROPERTIES - VERSION ${UV_VERSION_MAJOR}.0.0 - SOVERSION ${UV_VERSION_MAJOR}) + set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}) set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) set(prefix ${CMAKE_INSTALL_PREFIX}) -configure_file(libuv.pc.in libuv.pc @ONLY) configure_file(libuv-static.pc.in libuv-static.pc @ONLY) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) -install(FILES ${PROJECT_BINARY_DIR}/libuv.pc ${PROJECT_BINARY_DIR}/libuv-static.pc +install(FILES ${PROJECT_BINARY_DIR}/libuv-static.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) -install(TARGETS uv EXPORT libuvConfig - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(TARGETS uv_a EXPORT libuvConfig ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(EXPORT libuvConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libuv) +if(LIBUV_BUILD_SHARED) + # The version in the filename is mirroring the behaviour of autotools. + set_target_properties(uv PROPERTIES + VERSION ${UV_VERSION_MAJOR}.0.0 + SOVERSION ${UV_VERSION_MAJOR}) + configure_file(libuv.pc.in libuv.pc @ONLY) + install(FILES ${PROJECT_BINARY_DIR}/libuv.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + install(TARGETS uv EXPORT libuvConfig + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() + if(MSVC) set(CMAKE_DEBUG_POSTFIX d) endif() From 9a5a5140e5cc0ff27697db39e6f1f5fae2110600 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 2 Oct 2022 13:34:12 +0200 Subject: [PATCH 246/713] linux: remove unused or obsolete syscall wrappers (#3777) preadv, pwritev, dup3 and utimensat all exist in 2.6.32 kernels, libuv's minimum supported kernel. The wrapper for utimensat was already gone, only the define remained. --- src/unix/fs.c | 16 +++++----- src/unix/linux-syscalls.c | 67 --------------------------------------- src/unix/linux-syscalls.h | 3 -- 3 files changed, 8 insertions(+), 78 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 902cd772a7e..62e88f42374 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -490,10 +490,10 @@ static ssize_t uv__fs_read(uv_fs_t* req) { } # if defined(__linux__) else { - result = uv__preadv(req->file, - (struct iovec*)req->bufs, - req->nbufs, - req->off); + result = preadv(req->file, + (struct iovec*) req->bufs, + req->nbufs, + req->off); if (result == -1 && errno == ENOSYS) { uv__store_relaxed(&no_preadv, 1); goto retry; @@ -1234,10 +1234,10 @@ static ssize_t uv__fs_write(uv_fs_t* req) { } # if defined(__linux__) else { - r = uv__pwritev(req->file, - (struct iovec*) req->bufs, - req->nbufs, - req->off); + r = pwritev(req->file, + (struct iovec*) req->bufs, + req->nbufs, + req->off); if (r == -1 && errno == ENOSYS) { no_pwritev = 1; goto retry; diff --git a/src/unix/linux-syscalls.c b/src/unix/linux-syscalls.c index 5071cd56d1f..52e2387f3e7 100644 --- a/src/unix/linux-syscalls.c +++ b/src/unix/linux-syscalls.c @@ -50,46 +50,6 @@ # endif #endif /* __NR_sendmmsg */ -#ifndef __NR_utimensat -# if defined(__x86_64__) -# define __NR_utimensat 280 -# elif defined(__i386__) -# define __NR_utimensat 320 -# elif defined(__arm__) -# define __NR_utimensat (UV_SYSCALL_BASE + 348) -# endif -#endif /* __NR_utimensat */ - -#ifndef __NR_preadv -# if defined(__x86_64__) -# define __NR_preadv 295 -# elif defined(__i386__) -# define __NR_preadv 333 -# elif defined(__arm__) -# define __NR_preadv (UV_SYSCALL_BASE + 361) -# endif -#endif /* __NR_preadv */ - -#ifndef __NR_pwritev -# if defined(__x86_64__) -# define __NR_pwritev 296 -# elif defined(__i386__) -# define __NR_pwritev 334 -# elif defined(__arm__) -# define __NR_pwritev (UV_SYSCALL_BASE + 362) -# endif -#endif /* __NR_pwritev */ - -#ifndef __NR_dup3 -# if defined(__x86_64__) -# define __NR_dup3 292 -# elif defined(__i386__) -# define __NR_dup3 330 -# elif defined(__arm__) -# define __NR_dup3 (UV_SYSCALL_BASE + 358) -# endif -#endif /* __NR_pwritev */ - #ifndef __NR_copy_file_range # if defined(__x86_64__) # define __NR_copy_file_range 326 @@ -193,33 +153,6 @@ int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { } -ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { -#if !defined(__NR_preadv) || defined(__ANDROID_API__) && __ANDROID_API__ < 24 - return errno = ENOSYS, -1; -#else - return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); -#endif -} - - -ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { -#if !defined(__NR_pwritev) || defined(__ANDROID_API__) && __ANDROID_API__ < 24 - return errno = ENOSYS, -1; -#else - return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); -#endif -} - - -int uv__dup3(int oldfd, int newfd, int flags) { -#if !defined(__NR_dup3) || defined(__ANDROID_API__) && __ANDROID_API__ < 21 - return errno = ENOSYS, -1; -#else - return syscall(__NR_dup3, oldfd, newfd, flags); -#endif -} - - ssize_t uv__fs_copy_file_range(int fd_in, off_t* off_in, diff --git a/src/unix/linux-syscalls.h b/src/unix/linux-syscalls.h index b4d9082d46f..b8736597ad9 100644 --- a/src/unix/linux-syscalls.h +++ b/src/unix/linux-syscalls.h @@ -58,9 +58,6 @@ struct uv__statx { uint64_t unused1[14]; }; -ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset); -ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset); -int uv__dup3(int oldfd, int newfd, int flags); ssize_t uv__fs_copy_file_range(int fd_in, off_t* off_in, From cd1a510d160168388495c2b056055bc465ff4412 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 2 Oct 2022 14:09:42 +0200 Subject: [PATCH 247/713] linux: merge files back into single file (#3778) I split up linux.c around 2012 for no real reason and now I'm merging it back together, again for no real reason. I half-jest. I like the idea of having everything together because I practically forgot linux-inotify.c existed. It also makes io_uring experiments a little easier. Last but not least, it removes about 100 lines of license boilerplate. --- CMakeLists.txt | 8 +- Makefile.am | 5 +- src/unix/internal.h | 49 ++- src/unix/linux-inotify.c | 327 -------------------- src/unix/linux-syscalls.c | 197 ------------ src/unix/linux-syscalls.h | 75 ----- src/unix/{linux-core.c => linux.c} | 466 +++++++++++++++++++++++++++++ src/unix/random-getrandom.c | 2 - 8 files changed, 514 insertions(+), 615 deletions(-) delete mode 100644 src/unix/linux-inotify.c delete mode 100644 src/unix/linux-syscalls.c delete mode 100644 src/unix/linux-syscalls.h rename src/unix/{linux-core.c => linux.c} (72%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fde4091769..3d5e37592e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,9 +222,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android") list(APPEND uv_defines _GNU_SOURCE) list(APPEND uv_libraries dl) list(APPEND uv_sources - src/unix/linux-core.c - src/unix/linux-inotify.c - src/unix/linux-syscalls.c + src/unix/linux.c src/unix/procfs-exepath.c src/unix/random-getentropy.c src/unix/random-getrandom.c @@ -283,9 +281,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") list(APPEND uv_defines _GNU_SOURCE _POSIX_C_SOURCE=200112) list(APPEND uv_libraries dl rt) list(APPEND uv_sources - src/unix/linux-core.c - src/unix/linux-inotify.c - src/unix/linux-syscalls.c + src/unix/linux.c src/unix/procfs-exepath.c src/unix/random-getrandom.c src/unix/random-sysctl-linux.c) diff --git a/Makefile.am b/Makefile.am index deec449de4f..66e18b1dca5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -472,10 +472,7 @@ endif if LINUX uvinclude_HEADERS += include/uv/linux.h libuv_la_CFLAGS += -D_GNU_SOURCE -libuv_la_SOURCES += src/unix/linux-core.c \ - src/unix/linux-inotify.c \ - src/unix/linux-syscalls.c \ - src/unix/linux-syscalls.h \ +libuv_la_SOURCES += src/unix/linux.c \ src/unix/procfs-exepath.c \ src/unix/proctitle.c \ src/unix/random-getrandom.c \ diff --git a/src/unix/internal.h b/src/unix/internal.h index bb5f596285d..806bd672125 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -26,6 +26,7 @@ #include #include /* _POSIX_PATH_MAX, PATH_MAX */ +#include #include /* abort */ #include /* strrchr */ #include /* O_CLOEXEC and O_NONBLOCK, if supported. */ @@ -37,10 +38,6 @@ # define inline __inline #endif -#if defined(__linux__) -# include "linux-syscalls.h" -#endif /* __linux__ */ - #if defined(__MVS__) # include "os390-syscalls.h" #endif /* __MVS__ */ @@ -158,6 +155,37 @@ struct uv__stream_queued_fds_s { int fds[1]; }; +#ifdef __linux__ +struct uv__statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; + int32_t unused0; +}; + +struct uv__statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint16_t unused0; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct uv__statx_timestamp stx_atime; + struct uv__statx_timestamp stx_btime; + struct uv__statx_timestamp stx_ctime; + struct uv__statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t unused1[14]; +}; +#endif /* __linux__ */ #if defined(_AIX) || \ defined(__APPLE__) || \ @@ -315,6 +343,19 @@ UV_UNUSED(static char* uv__basename_r(const char* path)) { #if defined(__linux__) int uv__inotify_fork(uv_loop_t* loop, void* old_watchers); +ssize_t +uv__fs_copy_file_range(int fd_in, + off_t* off_in, + int fd_out, + off_t* off_out, + size_t len, + unsigned int flags); +int uv__statx(int dirfd, + const char* path, + int flags, + unsigned int mask, + struct uv__statx* statxbuf); +ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags); #endif typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*); diff --git a/src/unix/linux-inotify.c b/src/unix/linux-inotify.c deleted file mode 100644 index c1bd260e16e..00000000000 --- a/src/unix/linux-inotify.c +++ /dev/null @@ -1,327 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "uv.h" -#include "uv/tree.h" -#include "internal.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -struct watcher_list { - RB_ENTRY(watcher_list) entry; - QUEUE watchers; - int iterating; - char* path; - int wd; -}; - -struct watcher_root { - struct watcher_list* rbh_root; -}; -#define CAST(p) ((struct watcher_root*)(p)) - - -static int compare_watchers(const struct watcher_list* a, - const struct watcher_list* b) { - if (a->wd < b->wd) return -1; - if (a->wd > b->wd) return 1; - return 0; -} - - -RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers) - - -static void uv__inotify_read(uv_loop_t* loop, - uv__io_t* w, - unsigned int revents); - -static void maybe_free_watcher_list(struct watcher_list* w, - uv_loop_t* loop); - -static int init_inotify(uv_loop_t* loop) { - int fd; - - if (loop->inotify_fd != -1) - return 0; - - fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); - if (fd < 0) - return UV__ERR(errno); - - loop->inotify_fd = fd; - uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); - uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); - - return 0; -} - - -int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) { - /* Open the inotify_fd, and re-arm all the inotify watchers. */ - int err; - struct watcher_list* tmp_watcher_list_iter; - struct watcher_list* watcher_list; - struct watcher_list tmp_watcher_list; - QUEUE queue; - QUEUE* q; - uv_fs_event_t* handle; - char* tmp_path; - - if (old_watchers != NULL) { - /* We must restore the old watcher list to be able to close items - * out of it. - */ - loop->inotify_watchers = old_watchers; - - QUEUE_INIT(&tmp_watcher_list.watchers); - /* Note that the queue we use is shared with the start and stop() - * functions, making QUEUE_FOREACH unsafe to use. So we use the - * QUEUE_MOVE trick to safely iterate. Also don't free the watcher - * list until we're done iterating. c.f. uv__inotify_read. - */ - RB_FOREACH_SAFE(watcher_list, watcher_root, - CAST(&old_watchers), tmp_watcher_list_iter) { - watcher_list->iterating = 1; - QUEUE_MOVE(&watcher_list->watchers, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - handle = QUEUE_DATA(q, uv_fs_event_t, watchers); - /* It's critical to keep a copy of path here, because it - * will be set to NULL by stop() and then deallocated by - * maybe_free_watcher_list - */ - tmp_path = uv__strdup(handle->path); - assert(tmp_path != NULL); - QUEUE_REMOVE(q); - QUEUE_INSERT_TAIL(&watcher_list->watchers, q); - uv_fs_event_stop(handle); - - QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers); - handle->path = tmp_path; - } - watcher_list->iterating = 0; - maybe_free_watcher_list(watcher_list, loop); - } - - QUEUE_MOVE(&tmp_watcher_list.watchers, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - QUEUE_REMOVE(q); - handle = QUEUE_DATA(q, uv_fs_event_t, watchers); - tmp_path = handle->path; - handle->path = NULL; - err = uv_fs_event_start(handle, handle->cb, tmp_path, 0); - uv__free(tmp_path); - if (err) - return err; - } - } - - return 0; -} - - -static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) { - struct watcher_list w; - w.wd = wd; - return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w); -} - -static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) { - /* if the watcher_list->watchers is being iterated over, we can't free it. */ - if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) { - /* No watchers left for this path. Clean up. */ - RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w); - inotify_rm_watch(loop->inotify_fd, w->wd); - uv__free(w); - } -} - -static void uv__inotify_read(uv_loop_t* loop, - uv__io_t* dummy, - unsigned int events) { - const struct inotify_event* e; - struct watcher_list* w; - uv_fs_event_t* h; - QUEUE queue; - QUEUE* q; - const char* path; - ssize_t size; - const char *p; - /* needs to be large enough for sizeof(inotify_event) + strlen(path) */ - char buf[4096]; - - for (;;) { - do - size = read(loop->inotify_fd, buf, sizeof(buf)); - while (size == -1 && errno == EINTR); - - if (size == -1) { - assert(errno == EAGAIN || errno == EWOULDBLOCK); - break; - } - - assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */ - - /* Now we have one or more inotify_event structs. */ - for (p = buf; p < buf + size; p += sizeof(*e) + e->len) { - e = (const struct inotify_event*) p; - - events = 0; - if (e->mask & (IN_ATTRIB|IN_MODIFY)) - events |= UV_CHANGE; - if (e->mask & ~(IN_ATTRIB|IN_MODIFY)) - events |= UV_RENAME; - - w = find_watcher(loop, e->wd); - if (w == NULL) - continue; /* Stale event, no watchers left. */ - - /* inotify does not return the filename when monitoring a single file - * for modifications. Repurpose the filename for API compatibility. - * I'm not convinced this is a good thing, maybe it should go. - */ - path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path); - - /* We're about to iterate over the queue and call user's callbacks. - * What can go wrong? - * A callback could call uv_fs_event_stop() - * and the queue can change under our feet. - * So, we use QUEUE_MOVE() trick to safely iterate over the queue. - * And we don't free the watcher_list until we're done iterating. - * - * First, - * tell uv_fs_event_stop() (that could be called from a user's callback) - * not to free watcher_list. - */ - w->iterating = 1; - QUEUE_MOVE(&w->watchers, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - h = QUEUE_DATA(q, uv_fs_event_t, watchers); - - QUEUE_REMOVE(q); - QUEUE_INSERT_TAIL(&w->watchers, q); - - h->cb(h, path, events, 0); - } - /* done iterating, time to (maybe) free empty watcher_list */ - w->iterating = 0; - maybe_free_watcher_list(w, loop); - } - } -} - - -int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { - uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); - return 0; -} - - -int uv_fs_event_start(uv_fs_event_t* handle, - uv_fs_event_cb cb, - const char* path, - unsigned int flags) { - struct watcher_list* w; - size_t len; - int events; - int err; - int wd; - - if (uv__is_active(handle)) - return UV_EINVAL; - - err = init_inotify(handle->loop); - if (err) - return err; - - events = IN_ATTRIB - | IN_CREATE - | IN_MODIFY - | IN_DELETE - | IN_DELETE_SELF - | IN_MOVE_SELF - | IN_MOVED_FROM - | IN_MOVED_TO; - - wd = inotify_add_watch(handle->loop->inotify_fd, path, events); - if (wd == -1) - return UV__ERR(errno); - - w = find_watcher(handle->loop, wd); - if (w) - goto no_insert; - - len = strlen(path) + 1; - w = uv__malloc(sizeof(*w) + len); - if (w == NULL) - return UV_ENOMEM; - - w->wd = wd; - w->path = memcpy(w + 1, path, len); - QUEUE_INIT(&w->watchers); - w->iterating = 0; - RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w); - -no_insert: - uv__handle_start(handle); - QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers); - handle->path = w->path; - handle->cb = cb; - handle->wd = wd; - - return 0; -} - - -int uv_fs_event_stop(uv_fs_event_t* handle) { - struct watcher_list* w; - - if (!uv__is_active(handle)) - return 0; - - w = find_watcher(handle->loop, handle->wd); - assert(w != NULL); - - handle->wd = -1; - handle->path = NULL; - uv__handle_stop(handle); - QUEUE_REMOVE(&handle->watchers); - - maybe_free_watcher_list(w, handle->loop); - - return 0; -} - - -void uv__fs_event_close(uv_fs_event_t* handle) { - uv_fs_event_stop(handle); -} diff --git a/src/unix/linux-syscalls.c b/src/unix/linux-syscalls.c deleted file mode 100644 index 52e2387f3e7..00000000000 --- a/src/unix/linux-syscalls.c +++ /dev/null @@ -1,197 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "linux-syscalls.h" -#include -#include -#include -#include -#include - -#if defined(__arm__) -# if defined(__thumb__) || defined(__ARM_EABI__) -# define UV_SYSCALL_BASE 0 -# else -# define UV_SYSCALL_BASE 0x900000 -# endif -#endif /* __arm__ */ - -#ifndef __NR_recvmmsg -# if defined(__x86_64__) -# define __NR_recvmmsg 299 -# elif defined(__arm__) -# define __NR_recvmmsg (UV_SYSCALL_BASE + 365) -# endif -#endif /* __NR_recvmsg */ - -#ifndef __NR_sendmmsg -# if defined(__x86_64__) -# define __NR_sendmmsg 307 -# elif defined(__arm__) -# define __NR_sendmmsg (UV_SYSCALL_BASE + 374) -# endif -#endif /* __NR_sendmmsg */ - -#ifndef __NR_copy_file_range -# if defined(__x86_64__) -# define __NR_copy_file_range 326 -# elif defined(__i386__) -# define __NR_copy_file_range 377 -# elif defined(__s390__) -# define __NR_copy_file_range 375 -# elif defined(__arm__) -# define __NR_copy_file_range (UV_SYSCALL_BASE + 391) -# elif defined(__aarch64__) -# define __NR_copy_file_range 285 -# elif defined(__powerpc__) -# define __NR_copy_file_range 379 -# elif defined(__arc__) -# define __NR_copy_file_range 285 -# endif -#endif /* __NR_copy_file_range */ - -#ifndef __NR_statx -# if defined(__x86_64__) -# define __NR_statx 332 -# elif defined(__i386__) -# define __NR_statx 383 -# elif defined(__aarch64__) -# define __NR_statx 397 -# elif defined(__arm__) -# define __NR_statx (UV_SYSCALL_BASE + 397) -# elif defined(__ppc__) -# define __NR_statx 383 -# elif defined(__s390__) -# define __NR_statx 379 -# endif -#endif /* __NR_statx */ - -#ifndef __NR_getrandom -# if defined(__x86_64__) -# define __NR_getrandom 318 -# elif defined(__i386__) -# define __NR_getrandom 355 -# elif defined(__aarch64__) -# define __NR_getrandom 384 -# elif defined(__arm__) -# define __NR_getrandom (UV_SYSCALL_BASE + 384) -# elif defined(__ppc__) -# define __NR_getrandom 359 -# elif defined(__s390__) -# define __NR_getrandom 349 -# endif -#endif /* __NR_getrandom */ - -struct uv__mmsghdr; - -int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { -#if defined(__i386__) - unsigned long args[4]; - int rc; - - args[0] = (unsigned long) fd; - args[1] = (unsigned long) mmsg; - args[2] = (unsigned long) vlen; - args[3] = /* flags */ 0; - - /* socketcall() raises EINVAL when SYS_SENDMMSG is not supported. */ - rc = syscall(/* __NR_socketcall */ 102, 20 /* SYS_SENDMMSG */, args); - if (rc == -1) - if (errno == EINVAL) - errno = ENOSYS; - - return rc; -#elif defined(__NR_sendmmsg) - return syscall(__NR_sendmmsg, fd, mmsg, vlen, /* flags */ 0); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { -#if defined(__i386__) - unsigned long args[5]; - int rc; - - args[0] = (unsigned long) fd; - args[1] = (unsigned long) mmsg; - args[2] = (unsigned long) vlen; - args[3] = /* flags */ 0; - args[4] = /* timeout */ 0; - - /* socketcall() raises EINVAL when SYS_RECVMMSG is not supported. */ - rc = syscall(/* __NR_socketcall */ 102, 19 /* SYS_RECVMMSG */, args); - if (rc == -1) - if (errno == EINVAL) - errno = ENOSYS; - - return rc; -#elif defined(__NR_recvmmsg) - return syscall(__NR_recvmmsg, fd, mmsg, vlen, /* flags */ 0, /* timeout */ 0); -#else - return errno = ENOSYS, -1; -#endif -} - - -ssize_t -uv__fs_copy_file_range(int fd_in, - off_t* off_in, - int fd_out, - off_t* off_out, - size_t len, - unsigned int flags) -{ -#ifdef __NR_copy_file_range - return syscall(__NR_copy_file_range, - fd_in, - off_in, - fd_out, - off_out, - len, - flags); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__statx(int dirfd, - const char* path, - int flags, - unsigned int mask, - struct uv__statx* statxbuf) { -#if !defined(__NR_statx) || defined(__ANDROID_API__) && __ANDROID_API__ < 30 - return errno = ENOSYS, -1; -#else - return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf); -#endif -} - - -ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) { -#if !defined(__NR_getrandom) || defined(__ANDROID_API__) && __ANDROID_API__ < 28 - return errno = ENOSYS, -1; -#else - return syscall(__NR_getrandom, buf, buflen, flags); -#endif -} diff --git a/src/unix/linux-syscalls.h b/src/unix/linux-syscalls.h deleted file mode 100644 index b8736597ad9..00000000000 --- a/src/unix/linux-syscalls.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifndef UV_LINUX_SYSCALL_H_ -#define UV_LINUX_SYSCALL_H_ - -#include -#include -#include -#include -#include - -struct uv__statx_timestamp { - int64_t tv_sec; - uint32_t tv_nsec; - int32_t unused0; -}; - -struct uv__statx { - uint32_t stx_mask; - uint32_t stx_blksize; - uint64_t stx_attributes; - uint32_t stx_nlink; - uint32_t stx_uid; - uint32_t stx_gid; - uint16_t stx_mode; - uint16_t unused0; - uint64_t stx_ino; - uint64_t stx_size; - uint64_t stx_blocks; - uint64_t stx_attributes_mask; - struct uv__statx_timestamp stx_atime; - struct uv__statx_timestamp stx_btime; - struct uv__statx_timestamp stx_ctime; - struct uv__statx_timestamp stx_mtime; - uint32_t stx_rdev_major; - uint32_t stx_rdev_minor; - uint32_t stx_dev_major; - uint32_t stx_dev_minor; - uint64_t unused1[14]; -}; - -ssize_t -uv__fs_copy_file_range(int fd_in, - off_t* off_in, - int fd_out, - off_t* off_out, - size_t len, - unsigned int flags); -int uv__statx(int dirfd, - const char* path, - int flags, - unsigned int mask, - struct uv__statx* statxbuf); -ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags); - -#endif /* UV_LINUX_SYSCALL_H_ */ diff --git a/src/unix/linux-core.c b/src/unix/linux.c similarity index 72% rename from src/unix/linux-core.c rename to src/unix/linux.c index 40266451993..22c06feffa3 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux.c @@ -36,13 +36,89 @@ #include #include +#include #include #include +#include #include #include #include #include +#if defined(__arm__) +# if defined(__thumb__) || defined(__ARM_EABI__) +# define UV_SYSCALL_BASE 0 +# else +# define UV_SYSCALL_BASE 0x900000 +# endif +#endif /* __arm__ */ + +#ifndef __NR_recvmmsg +# if defined(__x86_64__) +# define __NR_recvmmsg 299 +# elif defined(__arm__) +# define __NR_recvmmsg (UV_SYSCALL_BASE + 365) +# endif +#endif /* __NR_recvmsg */ + +#ifndef __NR_sendmmsg +# if defined(__x86_64__) +# define __NR_sendmmsg 307 +# elif defined(__arm__) +# define __NR_sendmmsg (UV_SYSCALL_BASE + 374) +# endif +#endif /* __NR_sendmmsg */ + +#ifndef __NR_copy_file_range +# if defined(__x86_64__) +# define __NR_copy_file_range 326 +# elif defined(__i386__) +# define __NR_copy_file_range 377 +# elif defined(__s390__) +# define __NR_copy_file_range 375 +# elif defined(__arm__) +# define __NR_copy_file_range (UV_SYSCALL_BASE + 391) +# elif defined(__aarch64__) +# define __NR_copy_file_range 285 +# elif defined(__powerpc__) +# define __NR_copy_file_range 379 +# elif defined(__arc__) +# define __NR_copy_file_range 285 +# endif +#endif /* __NR_copy_file_range */ + +#ifndef __NR_statx +# if defined(__x86_64__) +# define __NR_statx 332 +# elif defined(__i386__) +# define __NR_statx 383 +# elif defined(__aarch64__) +# define __NR_statx 397 +# elif defined(__arm__) +# define __NR_statx (UV_SYSCALL_BASE + 397) +# elif defined(__ppc__) +# define __NR_statx 383 +# elif defined(__s390__) +# define __NR_statx 379 +# endif +#endif /* __NR_statx */ + +#ifndef __NR_getrandom +# if defined(__x86_64__) +# define __NR_getrandom 318 +# elif defined(__i386__) +# define __NR_getrandom 355 +# elif defined(__aarch64__) +# define __NR_getrandom 384 +# elif defined(__arm__) +# define __NR_getrandom (UV_SYSCALL_BASE + 384) +# elif defined(__ppc__) +# define __NR_getrandom 359 +# elif defined(__s390__) +# define __NR_getrandom 349 +# endif +#endif /* __NR_getrandom */ + #define HAVE_IFADDRS_H 1 # if defined(__ANDROID_API__) && __ANDROID_API__ < 24 @@ -75,6 +151,27 @@ # define CLOCK_BOOTTIME 7 #endif +#define CAST(p) ((struct watcher_root*)(p)) + +struct watcher_list { + RB_ENTRY(watcher_list) entry; + QUEUE watchers; + int iterating; + char* path; + int wd; +}; + +struct watcher_root { + struct watcher_list* rbh_root; +}; + +static void uv__inotify_read(uv_loop_t* loop, + uv__io_t* w, + unsigned int revents); +static int compare_watchers(const struct watcher_list* a, + const struct watcher_list* b); +static void maybe_free_watcher_list(struct watcher_list* w, + uv_loop_t* loop); static int read_models(unsigned int numcpus, uv_cpu_info_t* ci); static int read_times(FILE* statfile_fp, unsigned int numcpus, @@ -82,6 +179,52 @@ static int read_times(FILE* statfile_fp, static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); static uint64_t read_cpufreq(unsigned int cpunum); +RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers) + + +ssize_t +uv__fs_copy_file_range(int fd_in, + off_t* off_in, + int fd_out, + off_t* off_out, + size_t len, + unsigned int flags) +{ +#ifdef __NR_copy_file_range + return syscall(__NR_copy_file_range, + fd_in, + off_in, + fd_out, + off_out, + len, + flags); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__statx(int dirfd, + const char* path, + int flags, + unsigned int mask, + struct uv__statx* statxbuf) { +#if !defined(__NR_statx) || defined(__ANDROID_API__) && __ANDROID_API__ < 30 + return errno = ENOSYS, -1; +#else + return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf); +#endif +} + + +ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) { +#if !defined(__NR_getrandom) || defined(__ANDROID_API__) && __ANDROID_API__ < 28 + return errno = ENOSYS, -1; +#else + return syscall(__NR_getrandom, buf, buflen, flags); +#endif +} + int uv__platform_loop_init(uv_loop_t* loop) { loop->inotify_watchers = NULL; @@ -1243,3 +1386,326 @@ void uv_loadavg(double avg[3]) { avg[1] = (double) info.loads[1] / 65536.0; avg[2] = (double) info.loads[2] / 65536.0; } + + +static int compare_watchers(const struct watcher_list* a, + const struct watcher_list* b) { + if (a->wd < b->wd) return -1; + if (a->wd > b->wd) return 1; + return 0; +} + + +static int init_inotify(uv_loop_t* loop) { + int fd; + + if (loop->inotify_fd != -1) + return 0; + + fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (fd < 0) + return UV__ERR(errno); + + loop->inotify_fd = fd; + uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); + uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); + + return 0; +} + + +int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) { + /* Open the inotify_fd, and re-arm all the inotify watchers. */ + int err; + struct watcher_list* tmp_watcher_list_iter; + struct watcher_list* watcher_list; + struct watcher_list tmp_watcher_list; + QUEUE queue; + QUEUE* q; + uv_fs_event_t* handle; + char* tmp_path; + + if (old_watchers != NULL) { + /* We must restore the old watcher list to be able to close items + * out of it. + */ + loop->inotify_watchers = old_watchers; + + QUEUE_INIT(&tmp_watcher_list.watchers); + /* Note that the queue we use is shared with the start and stop() + * functions, making QUEUE_FOREACH unsafe to use. So we use the + * QUEUE_MOVE trick to safely iterate. Also don't free the watcher + * list until we're done iterating. c.f. uv__inotify_read. + */ + RB_FOREACH_SAFE(watcher_list, watcher_root, + CAST(&old_watchers), tmp_watcher_list_iter) { + watcher_list->iterating = 1; + QUEUE_MOVE(&watcher_list->watchers, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + handle = QUEUE_DATA(q, uv_fs_event_t, watchers); + /* It's critical to keep a copy of path here, because it + * will be set to NULL by stop() and then deallocated by + * maybe_free_watcher_list + */ + tmp_path = uv__strdup(handle->path); + assert(tmp_path != NULL); + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&watcher_list->watchers, q); + uv_fs_event_stop(handle); + + QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers); + handle->path = tmp_path; + } + watcher_list->iterating = 0; + maybe_free_watcher_list(watcher_list, loop); + } + + QUEUE_MOVE(&tmp_watcher_list.watchers, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + QUEUE_REMOVE(q); + handle = QUEUE_DATA(q, uv_fs_event_t, watchers); + tmp_path = handle->path; + handle->path = NULL; + err = uv_fs_event_start(handle, handle->cb, tmp_path, 0); + uv__free(tmp_path); + if (err) + return err; + } + } + + return 0; +} + + +static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) { + struct watcher_list w; + w.wd = wd; + return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w); +} + + +static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) { + /* if the watcher_list->watchers is being iterated over, we can't free it. */ + if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) { + /* No watchers left for this path. Clean up. */ + RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w); + inotify_rm_watch(loop->inotify_fd, w->wd); + uv__free(w); + } +} + + +static void uv__inotify_read(uv_loop_t* loop, + uv__io_t* dummy, + unsigned int events) { + const struct inotify_event* e; + struct watcher_list* w; + uv_fs_event_t* h; + QUEUE queue; + QUEUE* q; + const char* path; + ssize_t size; + const char *p; + /* needs to be large enough for sizeof(inotify_event) + strlen(path) */ + char buf[4096]; + + for (;;) { + do + size = read(loop->inotify_fd, buf, sizeof(buf)); + while (size == -1 && errno == EINTR); + + if (size == -1) { + assert(errno == EAGAIN || errno == EWOULDBLOCK); + break; + } + + assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */ + + /* Now we have one or more inotify_event structs. */ + for (p = buf; p < buf + size; p += sizeof(*e) + e->len) { + e = (const struct inotify_event*) p; + + events = 0; + if (e->mask & (IN_ATTRIB|IN_MODIFY)) + events |= UV_CHANGE; + if (e->mask & ~(IN_ATTRIB|IN_MODIFY)) + events |= UV_RENAME; + + w = find_watcher(loop, e->wd); + if (w == NULL) + continue; /* Stale event, no watchers left. */ + + /* inotify does not return the filename when monitoring a single file + * for modifications. Repurpose the filename for API compatibility. + * I'm not convinced this is a good thing, maybe it should go. + */ + path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path); + + /* We're about to iterate over the queue and call user's callbacks. + * What can go wrong? + * A callback could call uv_fs_event_stop() + * and the queue can change under our feet. + * So, we use QUEUE_MOVE() trick to safely iterate over the queue. + * And we don't free the watcher_list until we're done iterating. + * + * First, + * tell uv_fs_event_stop() (that could be called from a user's callback) + * not to free watcher_list. + */ + w->iterating = 1; + QUEUE_MOVE(&w->watchers, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + h = QUEUE_DATA(q, uv_fs_event_t, watchers); + + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&w->watchers, q); + + h->cb(h, path, events, 0); + } + /* done iterating, time to (maybe) free empty watcher_list */ + w->iterating = 0; + maybe_free_watcher_list(w, loop); + } + } +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, + uv_fs_event_cb cb, + const char* path, + unsigned int flags) { + struct watcher_list* w; + size_t len; + int events; + int err; + int wd; + + if (uv__is_active(handle)) + return UV_EINVAL; + + err = init_inotify(handle->loop); + if (err) + return err; + + events = IN_ATTRIB + | IN_CREATE + | IN_MODIFY + | IN_DELETE + | IN_DELETE_SELF + | IN_MOVE_SELF + | IN_MOVED_FROM + | IN_MOVED_TO; + + wd = inotify_add_watch(handle->loop->inotify_fd, path, events); + if (wd == -1) + return UV__ERR(errno); + + w = find_watcher(handle->loop, wd); + if (w) + goto no_insert; + + len = strlen(path) + 1; + w = uv__malloc(sizeof(*w) + len); + if (w == NULL) + return UV_ENOMEM; + + w->wd = wd; + w->path = memcpy(w + 1, path, len); + QUEUE_INIT(&w->watchers); + w->iterating = 0; + RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w); + +no_insert: + uv__handle_start(handle); + QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers); + handle->path = w->path; + handle->cb = cb; + handle->wd = wd; + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + struct watcher_list* w; + + if (!uv__is_active(handle)) + return 0; + + w = find_watcher(handle->loop, handle->wd); + assert(w != NULL); + + handle->wd = -1; + handle->path = NULL; + uv__handle_stop(handle); + QUEUE_REMOVE(&handle->watchers); + + maybe_free_watcher_list(w, handle->loop); + + return 0; +} + + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} + + +int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { +#if defined(__i386__) + unsigned long args[4]; + int rc; + + args[0] = (unsigned long) fd; + args[1] = (unsigned long) mmsg; + args[2] = (unsigned long) vlen; + args[3] = /* flags */ 0; + + /* socketcall() raises EINVAL when SYS_SENDMMSG is not supported. */ + rc = syscall(/* __NR_socketcall */ 102, 20 /* SYS_SENDMMSG */, args); + if (rc == -1) + if (errno == EINVAL) + errno = ENOSYS; + + return rc; +#elif defined(__NR_sendmmsg) + return syscall(__NR_sendmmsg, fd, mmsg, vlen, /* flags */ 0); +#else + return errno = ENOSYS, -1; +#endif +} + + +int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { +#if defined(__i386__) + unsigned long args[5]; + int rc; + + args[0] = (unsigned long) fd; + args[1] = (unsigned long) mmsg; + args[2] = (unsigned long) vlen; + args[3] = /* flags */ 0; + args[4] = /* timeout */ 0; + + /* socketcall() raises EINVAL when SYS_RECVMMSG is not supported. */ + rc = syscall(/* __NR_socketcall */ 102, 19 /* SYS_RECVMMSG */, args); + if (rc == -1) + if (errno == EINVAL) + errno = ENOSYS; + + return rc; +#elif defined(__NR_recvmmsg) + return syscall(__NR_recvmmsg, fd, mmsg, vlen, /* flags */ 0, /* timeout */ 0); +#else + return errno = ENOSYS, -1; +#endif +} diff --git a/src/unix/random-getrandom.c b/src/unix/random-getrandom.c index bcc94089bcb..054eccf1664 100644 --- a/src/unix/random-getrandom.c +++ b/src/unix/random-getrandom.c @@ -24,8 +24,6 @@ #ifdef __linux__ -#include "linux-syscalls.h" - #define uv__random_getrandom_init() 0 #else /* !__linux__ */ From 3e7d2a649275cce3c2d43c67205e627931bda55e Mon Sep 17 00:00:00 2001 From: ywave620 Date: Sat, 8 Oct 2022 16:23:01 +0800 Subject: [PATCH 248/713] stream: process more than one write req per loop tick (#3728) Fixes: https://github.com/libuv/libuv/issues/3668 --- CMakeLists.txt | 1 + Makefile.am | 1 + src/unix/stream.c | 15 +++- test/test-list.h | 2 + test/test-tcp-write-in-a-row.c | 141 +++++++++++++++++++++++++++++++++ 5 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 test/test-tcp-write-in-a-row.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d5e37592e7..640f8a19e0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -584,6 +584,7 @@ if(LIBUV_BUILD_TESTS) test/test-tcp-rst.c test/test-tcp-shutdown-after-write.c test/test-tcp-try-write.c + test/test-tcp-write-in-a-row.c test/test-tcp-try-write-error.c test/test-tcp-unexpected-read.c test/test-tcp-write-after-connect.c diff --git a/Makefile.am b/Makefile.am index 66e18b1dca5..b0b4f2529a0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -277,6 +277,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-tcp-writealot.c \ test/test-tcp-write-fail.c \ test/test-tcp-try-write.c \ + test/test-tcp-write-in-a-row.c \ test/test-tcp-try-write-error.c \ test/test-tcp-write-queue-order.c \ test/test-test-macros.c \ diff --git a/src/unix/stream.c b/src/unix/stream.c index 95ca92d564c..0b755de6bce 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -841,9 +841,16 @@ static void uv__write(uv_stream_t* stream) { QUEUE* q; uv_write_t* req; ssize_t n; + int count; assert(uv__stream_fd(stream) >= 0); + /* Prevent loop starvation when the consumer of this stream read as fast as + * (or faster than) we can write it. This `count` mechanism does not need to + * change even if we switch to edge-triggered I/O. + */ + count = 32; + for (;;) { if (QUEUE_EMPTY(&stream->write_queue)) return; @@ -862,10 +869,13 @@ static void uv__write(uv_stream_t* stream) { req->send_handle = NULL; if (uv__write_req_update(stream, req, n)) { uv__write_req_finish(req); - return; /* TODO(bnoordhuis) Start trying to write the next request. */ + if (count-- > 0) + continue; /* Start trying to write the next request. */ + + return; } } else if (n != UV_EAGAIN) - break; + goto error; /* If this is a blocking stream, try again. */ if (stream->flags & UV_HANDLE_BLOCKING_WRITES) @@ -880,6 +890,7 @@ static void uv__write(uv_stream_t* stream) { return; } +error: req->error = n; uv__write_req_finish(req); uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); diff --git a/test/test-list.h b/test/test-list.h index ce4d4920cb6..8983cbc3f29 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -105,6 +105,7 @@ TEST_DECLARE (tcp_write_after_connect) TEST_DECLARE (tcp_writealot) TEST_DECLARE (tcp_write_fail) TEST_DECLARE (tcp_try_write) +TEST_DECLARE (tcp_write_in_a_row) TEST_DECLARE (tcp_try_write_error) TEST_DECLARE (tcp_write_queue_order) TEST_DECLARE (tcp_open) @@ -670,6 +671,7 @@ TASK_LIST_START TEST_HELPER (tcp_write_fail, tcp4_echo_server) TEST_ENTRY (tcp_try_write) + TEST_ENTRY (tcp_write_in_a_row) TEST_ENTRY (tcp_try_write_error) TEST_ENTRY (tcp_write_queue_order) diff --git a/test/test-tcp-write-in-a-row.c b/test/test-tcp-write-in-a-row.c new file mode 100644 index 00000000000..f04d48fcd68 --- /dev/null +++ b/test/test-tcp-write-in-a-row.c @@ -0,0 +1,141 @@ +/* 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 +#include +#include + +#include "task.h" +#include "uv.h" + +static uv_tcp_t server; +static uv_tcp_t client; +static uv_tcp_t incoming; +static int connect_cb_called; +static int close_cb_called; +static int connection_cb_called; +static int write_cb_called; +static uv_write_t small_write; +static uv_write_t big_write; + +/* 10 MB, which is large than the send buffer size and the recv buffer */ +static char data[1024 * 1024 * 10]; + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + +static void write_cb(uv_write_t* w, int status) { + /* the small write should finish immediately after the big write */ + ASSERT_EQ(0, uv_stream_get_write_queue_size((uv_stream_t*) &client)); + + write_cb_called++; + + if (write_cb_called == 2) { + /* we are done */ + uv_close((uv_handle_t*) &client, close_cb); + uv_close((uv_handle_t*) &incoming, close_cb); + uv_close((uv_handle_t*) &server, close_cb); + } +} + +static void connect_cb(uv_connect_t* _, int status) { + int r; + uv_buf_t buf; + size_t write_queue_size0, write_queue_size1; + + ASSERT_EQ(0, status); + connect_cb_called++; + + /* fire a big write */ + buf = uv_buf_init(data, sizeof(data)); + r = uv_write(&small_write, (uv_stream_t*) &client, &buf, 1, write_cb); + ASSERT_EQ(0, r); + + /* check that the write process gets stuck */ + write_queue_size0 = uv_stream_get_write_queue_size((uv_stream_t*) &client); + ASSERT_GT(write_queue_size0, 0); + + /* fire a small write, which should be queued */ + buf = uv_buf_init("A", 1); + r = uv_write(&big_write, (uv_stream_t*) &client, &buf, 1, write_cb); + ASSERT_EQ(0, r); + + write_queue_size1 = uv_stream_get_write_queue_size((uv_stream_t*) &client); + ASSERT_EQ(write_queue_size1, write_queue_size0 + 1); +} + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + static char base[1024]; + + buf->base = base; + buf->len = sizeof(base); +} + +static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {} + +static void connection_cb(uv_stream_t* tcp, int status) { + ASSERT_EQ(0, status); + connection_cb_called++; + + ASSERT_EQ(0, uv_tcp_init(tcp->loop, &incoming)); + ASSERT_EQ(0, uv_accept(tcp, (uv_stream_t*) &incoming)); + ASSERT_EQ(0, uv_read_start((uv_stream_t*) &incoming, alloc_cb, read_cb)); +} + +static void start_server(void) { + struct sockaddr_in addr; + + ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + ASSERT_EQ(0, uv_tcp_init(uv_default_loop(), &server)); + ASSERT_EQ(0, uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); + ASSERT_EQ(0, uv_listen((uv_stream_t*) &server, 128, connection_cb)); +} + +TEST_IMPL(tcp_write_in_a_row) { +#if defined(_WIN32) + RETURN_SKIP("tcp_write_in_a_row does not work on Windows"); +#endif + + uv_connect_t connect_req; + struct sockaddr_in addr; + + start_server(); + + ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT_EQ(0, uv_tcp_init(uv_default_loop(), &client)); + ASSERT_EQ(0, uv_tcp_connect(&connect_req, + &client, + (struct sockaddr*) &addr, + connect_cb)); + + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(3, close_cb_called); + ASSERT_EQ(1, connection_cb_called); + ASSERT_EQ(2, write_cb_called); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From 73b0c1f947646545bc824f868559ca3437340656 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 18 Oct 2022 23:06:47 +0200 Subject: [PATCH 249/713] unix,win: give thread pool threads an 8 MB stack (#3787) Give the threads in the thread pool a stack size that is consistent across platforms and architectures. Fixes: https://github.com/libuv/libuv/issues/3786 --- docs/src/threadpool.rst | 3 +++ src/threadpool.c | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/src/threadpool.rst b/docs/src/threadpool.rst index cf6cdc1be0f..7cfa797314c 100644 --- a/docs/src/threadpool.rst +++ b/docs/src/threadpool.rst @@ -14,6 +14,9 @@ is 1024). .. versionchanged:: 1.30.0 the maximum UV_THREADPOOL_SIZE allowed was increased from 128 to 1024. +.. versionchanged:: 1.45.0 threads now have an 8 MB stack instead of the + (sometimes too low) platform default. + The threadpool is global and shared across all event loops. When a particular function makes use of the threadpool (i.e. when using :c:func:`uv_queue_work`) libuv preallocates and initializes the maximum number of threads allowed by diff --git a/src/threadpool.c b/src/threadpool.c index e804c7c4b6f..a3da53026f9 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -191,6 +191,7 @@ void uv__threadpool_cleanup(void) { static void init_threads(void) { + uv_thread_options_t config; unsigned int i; const char* val; uv_sem_t sem; @@ -226,8 +227,11 @@ static void init_threads(void) { if (uv_sem_init(&sem, 0)) abort(); + config.flags = UV_THREAD_HAS_STACK_SIZE; + config.stack_size = 8u << 20; /* 8 MB */ + for (i = 0; i < nthreads; i++) - if (uv_thread_create(threads + i, worker, &sem)) + if (uv_thread_create_ex(threads + i, &config, worker, &sem)) abort(); for (i = 0; i < nthreads; i++) From acfe668ecbb008755ded4c2a7b2639e6b17a6f11 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 18 Oct 2022 23:21:42 +0200 Subject: [PATCH 250/713] build: add MemorySanitizer (MSAN) support (#3788) - unpoison results from linux system call wrappers - unpoison results from stat/fstat/lstat to pacify clang 14 (fixed in later versions) - add MSAN build option - turn on MSAN CI build --- .github/workflows/sanitizer.yml | 29 +++++++++++----- CMakeLists.txt | 13 ++++++++ src/unix/aix.c | 2 +- src/unix/fs.c | 14 ++++---- src/unix/internal.h | 46 +++++++++++++++++++++++++ src/unix/kqueue.c | 2 +- src/unix/linux.c | 59 ++++++++++++++++++++++++++++++--- src/unix/pipe.c | 2 +- src/unix/random-devurandom.c | 2 +- src/unix/tty.c | 4 +-- test/runner-unix.c | 1 + test/test-fs.c | 7 ++-- test/test-pipe-set-fchmod.c | 4 ++- 13 files changed, 155 insertions(+), 30 deletions(-) diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 3c39117faa3..d4b04aa1c24 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -14,7 +14,7 @@ on: jobs: sanitizers: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - name: Setup @@ -22,6 +22,25 @@ jobs: sudo apt-get install ninja-build - name: Envinfo run: npx envinfo + + - name: ASAN Build + run: | + mkdir build-asan + (cd build-asan && cmake .. -G Ninja -DBUILD_TESTING=ON -DASAN=ON -DCMAKE_BUILD_TYPE=Debug) + cmake --build build-asan + - name: ASAN Test + run: | + ./build-asan/uv_run_tests_a + + - name: MSAN Build + run: | + mkdir build-msan + (cd build-msan && cmake .. -G Ninja -DBUILD_TESTING=ON -DMSAN=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang) + cmake --build build-msan + - name: MSAN Test + run: | + ./build-msan/uv_run_tests_a + - name: TSAN Build run: | mkdir build-tsan @@ -31,11 +50,3 @@ jobs: continue-on-error: true # currently permit failures run: | ./build-tsan/uv_run_tests_a - - name: ASAN Build - run: | - mkdir build-asan - (cd build-asan && cmake .. -G Ninja -DBUILD_TESTING=ON -DASAN=ON -DCMAKE_BUILD_TYPE=Debug) - cmake --build build-asan - - name: ASAN Test - run: | - ./build-asan/uv_run_tests_a diff --git a/CMakeLists.txt b/CMakeLists.txt index 640f8a19e0a..358bcd6d3dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,13 +36,19 @@ if(QEMU) add_definitions(-D__QEMU__=1) endif() +# Note: these are mutually exclusive. option(ASAN "Enable AddressSanitizer (ASan)" OFF) +option(MSAN "Enable MemorySanitizer (MSan)" OFF) option(TSAN "Enable ThreadSanitizer (TSan)" OFF) if((ASAN OR TSAN) AND NOT (CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang")) message(SEND_ERROR "Sanitizer support requires clang or gcc. Try again with -DCMAKE_C_COMPILER.") endif() +if(MSAN AND NOT CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang") + message(SEND_ERROR "MemorySanitizer requires clang. Try again with -DCMAKE_C_COMPILER=clang") +endif() + if(ASAN) add_definitions(-D__ASAN__=1) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=address") @@ -50,6 +56,13 @@ if(ASAN) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address") endif() +if(MSAN) + add_definitions(-D__MSAN__=1) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=memory") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=memory") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=memory") +endif() + if(TSAN) add_definitions(-D__TSAN__=1) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=thread") diff --git a/src/unix/aix.c b/src/unix/aix.c index 6a013d43e3a..f413f108c54 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -425,7 +425,7 @@ static char* uv__rawname(const char* cp, char (*dst)[FILENAME_MAX+1]) { static int uv__path_is_a_directory(char* filename) { struct stat statbuf; - if (stat(filename, &statbuf) < 0) + if (uv__stat(filename, &statbuf) < 0) return -1; /* failed: not a directory, assume it is a file */ if (statbuf.st_type == VDIR) diff --git a/src/unix/fs.c b/src/unix/fs.c index 62e88f42374..3ec4b6ae85e 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -516,7 +516,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) { if (result == -1 && errno == EOPNOTSUPP) { struct stat buf; ssize_t rc; - rc = fstat(req->file, &buf); + rc = uv__fstat(req->file, &buf); if (rc == 0 && S_ISDIR(buf.st_mode)) { errno = EISDIR; } @@ -708,7 +708,7 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) { /* We may not have a real PATH_MAX. Read size of link. */ struct stat st; int ret; - ret = lstat(req->path, &st); + ret = uv__lstat(req->path, &st); if (ret != 0) return -1; if (!S_ISLNK(st.st_mode)) { @@ -1281,7 +1281,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { return srcfd; /* Get the source file's mode. */ - if (fstat(srcfd, &src_statsbuf)) { + if (uv__fstat(srcfd, &src_statsbuf)) { err = UV__ERR(errno); goto out; } @@ -1309,7 +1309,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { destination are not the same file. If they are the same, bail out early. */ if ((req->flags & UV_FS_COPYFILE_EXCL) == 0) { /* Get the destination file's mode. */ - if (fstat(dstfd, &dst_statsbuf)) { + if (uv__fstat(dstfd, &dst_statsbuf)) { err = UV__ERR(errno); goto out; } @@ -1588,7 +1588,7 @@ static int uv__fs_stat(const char *path, uv_stat_t *buf) { if (ret != UV_ENOSYS) return ret; - ret = stat(path, &pbuf); + ret = uv__stat(path, &pbuf); if (ret == 0) uv__to_stat(&pbuf, buf); @@ -1604,7 +1604,7 @@ static int uv__fs_lstat(const char *path, uv_stat_t *buf) { if (ret != UV_ENOSYS) return ret; - ret = lstat(path, &pbuf); + ret = uv__lstat(path, &pbuf); if (ret == 0) uv__to_stat(&pbuf, buf); @@ -1620,7 +1620,7 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) { if (ret != UV_ENOSYS) return ret; - ret = fstat(fd, &pbuf); + ret = uv__fstat(fd, &pbuf); if (ret == 0) uv__to_stat(&pbuf, buf); diff --git a/src/unix/internal.h b/src/unix/internal.h index 806bd672125..9f32ebb062e 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -33,6 +33,22 @@ #include #include #include +#include +#include + +#define uv__msan_unpoison(p, n) \ + do { \ + (void) (p); \ + (void) (n); \ + } while (0) + +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) +# include +# undef uv__msan_unpoison +# define uv__msan_unpoison __msan_unpoison +# endif +#endif #if defined(__STRICT_ANSI__) # define inline __inline @@ -341,6 +357,36 @@ UV_UNUSED(static char* uv__basename_r(const char* path)) { return s + 1; } +UV_UNUSED(static int uv__fstat(int fd, struct stat* s)) { + int rc; + + rc = fstat(fd, s); + if (rc >= 0) + uv__msan_unpoison(s, sizeof(*s)); + + return rc; +} + +UV_UNUSED(static int uv__lstat(const char* path, struct stat* s)) { + int rc; + + rc = lstat(path, s); + if (rc >= 0) + uv__msan_unpoison(s, sizeof(*s)); + + return rc; +} + +UV_UNUSED(static int uv__stat(const char* path, struct stat* s)) { + int rc; + + rc = stat(path, s); + if (rc >= 0) + uv__msan_unpoison(s, sizeof(*s)); + + return rc; +} + #if defined(__linux__) int uv__inotify_fork(uv_loop_t* loop, void* old_watchers); ssize_t diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index c7fbba94065..9e34a684efa 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -529,7 +529,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, handle->realpath_len = 0; handle->cf_flags = flags; - if (fstat(fd, &statbuf)) + if (uv__fstat(fd, &statbuf)) goto fallback; /* FSEvents works only with directories */ if (!(statbuf.st_mode & S_IFDIR)) diff --git a/src/unix/linux.c b/src/unix/linux.c index 22c06feffa3..13e7661f7cd 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -34,16 +34,18 @@ #include #include +#include #include #include #include #include #include +#include #include #include -#include -#include +#include #include +#include #if defined(__arm__) # if defined(__thumb__) || defined(__ARM_EABI__) @@ -212,7 +214,13 @@ int uv__statx(int dirfd, #if !defined(__NR_statx) || defined(__ANDROID_API__) && __ANDROID_API__ < 30 return errno = ENOSYS, -1; #else - return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf); + int rc; + + rc = syscall(__NR_statx, dirfd, path, flags, mask, statxbuf); + if (rc >= 0) + uv__msan_unpoison(statxbuf, sizeof(*statxbuf)); + + return rc; #endif } @@ -221,7 +229,13 @@ ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) { #if !defined(__NR_getrandom) || defined(__ANDROID_API__) && __ANDROID_API__ < 28 return errno = ENOSYS, -1; #else - return syscall(__NR_getrandom, buf, buflen, flags); + ssize_t rc; + + rc = syscall(__NR_getrandom, buf, buflen, flags); + if (rc >= 0) + uv__msan_unpoison(buf, buflen); + + return rc; #endif } @@ -1685,6 +1699,35 @@ int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { } +static void uv__recvmmsg_unpoison(struct uv__mmsghdr* mmsg, int rc) { + struct uv__mmsghdr* m; + struct msghdr* h; + struct iovec* v; + size_t j; + int i; + + for (i = 0; i < rc; i++) { + m = mmsg + i; + uv__msan_unpoison(m, sizeof(*m)); + + h = &m->msg_hdr; + if (h->msg_name != NULL) + uv__msan_unpoison(h->msg_name, h->msg_namelen); + + if (h->msg_iov != NULL) + uv__msan_unpoison(h->msg_iov, h->msg_iovlen * sizeof(*h->msg_iov)); + + for (j = 0; j < h->msg_iovlen; j++) { + v = h->msg_iov + j; + uv__msan_unpoison(v->iov_base, v->iov_len); + } + + if (h->msg_control != NULL) + uv__msan_unpoison(h->msg_control, h->msg_controllen); + } +} + + int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { #if defined(__i386__) unsigned long args[5]; @@ -1698,13 +1741,19 @@ int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { /* socketcall() raises EINVAL when SYS_RECVMMSG is not supported. */ rc = syscall(/* __NR_socketcall */ 102, 19 /* SYS_RECVMMSG */, args); + uv__recvmmsg_unpoison(mmsg, rc); if (rc == -1) if (errno == EINVAL) errno = ENOSYS; return rc; #elif defined(__NR_recvmmsg) - return syscall(__NR_recvmmsg, fd, mmsg, vlen, /* flags */ 0, /* timeout */ 0); + int rc; + + rc = syscall(__NR_recvmmsg, fd, mmsg, vlen, /* flags */ 0, /* timeout */ 0); + uv__recvmmsg_unpoison(mmsg, rc); + + return rc; #else return errno = ENOSYS, -1; #endif diff --git a/src/unix/pipe.c b/src/unix/pipe.c index e8cfa1481c3..610b09b37f3 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -357,7 +357,7 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { } /* stat must be used as fstat has a bug on Darwin */ - if (stat(name_buffer, &pipe_stat) == -1) { + if (uv__stat(name_buffer, &pipe_stat) == -1) { uv__free(name_buffer); return -errno; } diff --git a/src/unix/random-devurandom.c b/src/unix/random-devurandom.c index 05e52a56a36..d6336f2c98c 100644 --- a/src/unix/random-devurandom.c +++ b/src/unix/random-devurandom.c @@ -40,7 +40,7 @@ int uv__random_readpath(const char* path, void* buf, size_t buflen) { if (fd < 0) return fd; - if (fstat(fd, &s)) { + if (uv__fstat(fd, &s)) { uv__close(fd); return UV__ERR(errno); } diff --git a/src/unix/tty.c b/src/unix/tty.c index 4c220e56521..623280872fc 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -113,7 +113,7 @@ static int uv__tty_is_slave(const int fd) { } /* Lookup stat structure behind the file descriptor. */ - if (fstat(fd, &sb) != 0) + if (uv__fstat(fd, &sb) != 0) abort(); /* Assert character device. */ @@ -365,7 +365,7 @@ uv_handle_type uv_guess_handle(uv_file file) { if (isatty(file)) return UV_TTY; - if (fstat(file, &s)) { + if (uv__fstat(file, &s)) { #if defined(__PASE__) /* On ibmi receiving RST from TCP instead of FIN immediately puts fd into * an error state. fstat will return EINVAL, getsockname will also return diff --git a/test/runner-unix.c b/test/runner-unix.c index c165aab9305..09191dbdaa1 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -344,6 +344,7 @@ long int process_output_size(process_info_t *p) { /* Size of the p->stdout_file */ struct stat buf; + memset(&buf, 0, sizeof(buf)); int r = fstat(fileno(p->stdout_file), &buf); if (r < 0) { return -1; diff --git a/test/test-fs.c b/test/test-fs.c index e49eaa9b30f..8d3a388c94d 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1239,6 +1239,8 @@ static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) { ASSERT(r == 0); uv_fs_req_cleanup(&close_req); + memset(&s1, 0, sizeof(s1)); + memset(&s2, 0, sizeof(s2)); ASSERT(0 == stat("test_file", &s1)); ASSERT(0 == stat("test_file2", &s2)); ASSERT(s2.st_size == expected_size); @@ -1413,6 +1415,7 @@ TEST_IMPL(fs_fstat) { uv_fs_req_cleanup(&req); #ifndef _WIN32 + memset(&t, 0, sizeof(t)); ASSERT(0 == fstat(file, &t)); ASSERT(0 == uv_fs_fstat(NULL, &req, file, NULL)); ASSERT(req.result == 0); @@ -3707,9 +3710,9 @@ static void test_fs_partial(int doread) { ctx.doread = doread; ctx.interval = 1000; ctx.size = sizeof(test_buf) * iovcount; - ctx.data = malloc(ctx.size); + ctx.data = calloc(ctx.size, 1); ASSERT_NOT_NULL(ctx.data); - buffer = malloc(ctx.size); + buffer = calloc(ctx.size, 1); ASSERT_NOT_NULL(buffer); for (index = 0; index < iovcount; ++index) diff --git a/test/test-pipe-set-fchmod.c b/test/test-pipe-set-fchmod.c index 91e476652e0..985f4ba2eba 100644 --- a/test/test-pipe-set-fchmod.c +++ b/test/test-pipe-set-fchmod.c @@ -22,6 +22,7 @@ #include "uv.h" #include "task.h" +#include TEST_IMPL(pipe_set_chmod) { uv_pipe_t pipe_handle; @@ -48,7 +49,8 @@ TEST_IMPL(pipe_set_chmod) { } ASSERT(r == 0); #ifndef _WIN32 - stat(TEST_PIPENAME, &stat_buf); + memset(&stat_buf, 0, sizeof(stat_buf)); + ASSERT_EQ(0, stat(TEST_PIPENAME, &stat_buf)); ASSERT(stat_buf.st_mode & S_IRUSR); ASSERT(stat_buf.st_mode & S_IRGRP); ASSERT(stat_buf.st_mode & S_IROTH); From 821b0ba8cb44c8804aa9f9e1f3591cd408840d9a Mon Sep 17 00:00:00 2001 From: jensbjorgensen Date: Fri, 21 Oct 2022 04:02:43 -0500 Subject: [PATCH 251/713] doc: add uv_poll_cb status==UV_EBADF note (#3797) --- docs/src/poll.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/src/poll.rst b/docs/src/poll.rst index 93a101ec686..f501089279d 100644 --- a/docs/src/poll.rst +++ b/docs/src/poll.rst @@ -101,7 +101,9 @@ API with one of the `UV_E*` error codes (see :ref:`errors`). The user should not close the socket while the handle is active. If the user does that anyway, the callback *may* be called reporting an error status, but this is - **not** guaranteed. + **not** guaranteed. If `status == UV_EBADF` polling is discontinued for the + file handle and no further events will be reported. The user should + then call :c:func:`uv_close` on the handle. .. note:: Calling :c:func:`uv_poll_start` on a handle that is already active is From 1de43a1a171c2df65988fdc2fdd8e2c1fcb93536 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 21 Oct 2022 09:10:19 -0400 Subject: [PATCH 252/713] build: support AddressSanitizer on MSVC (#3692) Fixes: https://github.com/libuv/libuv/issues/3682 --- .github/workflows/CI-win.yml | 37 ++++++++++++++++++++++++------------ CMakeLists.txt | 37 ++++++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index 9b9aa7721eb..ca6741df280 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -16,7 +16,7 @@ on: jobs: build-windows: runs-on: windows-${{ matrix.config.server }} - name: build-${{ matrix.config.toolchain}}-${{ matrix.config.arch}} + name: build-${{ join(matrix.config.*, '-') }} strategy: fail-fast: false matrix: @@ -25,27 +25,40 @@ jobs: - {toolchain: Visual Studio 16 2019, arch: x64, server: 2019} - {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022} + - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN} steps: - uses: actions/checkout@v2 - name: Envinfo run: npx envinfo - name: Build shell: cmd - run: | - mkdir -p build - cd build - cmake .. -DBUILD_TESTING=ON -G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }} - cmake --build . + run: + cmake -S . -B build -DBUILD_TESTING=ON + -G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }} + ${{ matrix.config.config == 'ASAN' && '-DASAN=on -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded' || '' }} + + cmake --build build --config RelWithDebInfo + + ls -l build - name: platform_output shell: cmd - run: | - build\\Debug\\uv_run_tests.exe platform_output + run: + build\\RelWithDebInfo\\uv_run_tests.exe platform_output - name: platform_output_a shell: cmd - run: | - build\\Debug\\uv_run_tests_a.exe platform_output + run: + build\\RelWithDebInfo\\uv_run_tests_a.exe platform_output - name: Test + # only valid with libuv-master with the fix for + # https://github.com/libuv/leps/blob/master/005-windows-handles-not-fd.md + if: ${{ matrix.config.config != 'ASAN' }} shell: cmd - run: | + run: cd build - ctest -C Debug -V + + ctest -C RelWithDebInfo -V + - name: Test only static + if: ${{ matrix.config.config == 'ASAN' }} + shell: cmd + run: + build\\RelWithDebInfo\\uv_run_tests_a.exe diff --git a/CMakeLists.txt b/CMakeLists.txt index 358bcd6d3dc..74ee79362c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,9 @@ cmake_policy(SET CMP0064 NEW) # Support if (TEST) operator if(POLICY CMP0091) cmake_policy(SET CMP0091 NEW) # Enable MSVC_RUNTIME_LIBRARY setting endif() +if(POLICY CMP0092) + cmake_policy(SET CMP0092 NEW) # disable /W3 warning, if possible +endif() project(libuv LANGUAGES C) @@ -33,7 +36,7 @@ cmake_dependent_option(LIBUV_BUILD_BENCH # Qemu Build option(QEMU "build for qemu" OFF) if(QEMU) - add_definitions(-D__QEMU__=1) + list(APPEND uv_defines __QEMU__=1) endif() # Note: these are mutually exclusive. @@ -41,33 +44,39 @@ option(ASAN "Enable AddressSanitizer (ASan)" OFF) option(MSAN "Enable MemorySanitizer (MSan)" OFF) option(TSAN "Enable ThreadSanitizer (TSan)" OFF) -if((ASAN OR TSAN) AND NOT (CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang")) - message(SEND_ERROR "Sanitizer support requires clang or gcc. Try again with -DCMAKE_C_COMPILER.") -endif() - if(MSAN AND NOT CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang") message(SEND_ERROR "MemorySanitizer requires clang. Try again with -DCMAKE_C_COMPILER=clang") endif() if(ASAN) - add_definitions(-D__ASAN__=1) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=address") - set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address") - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address") + list(APPEND uv_defines __ASAN__=1) + if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=address") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address") + elseif(MSVC) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address") + else() + message(SEND_ERROR "AddressSanitizer support requires clang, gcc, or msvc. Try again with -DCMAKE_C_COMPILER.") + endif() endif() if(MSAN) - add_definitions(-D__MSAN__=1) + list(APPEND uv_defines __MSAN__=1) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=memory") set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=memory") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=memory") endif() if(TSAN) - add_definitions(-D__TSAN__=1) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=thread") - set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=thread") - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=thread") + list(APPEND uv_defines __TSAN__=1) + if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=thread") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=thread") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=thread") + else() + message(SEND_ERROR "ThreadSanitizer support requires clang or gcc. Try again with -DCMAKE_C_COMPILER.") + endif() endif() # Compiler check From 357d28a256bfe11d9a4a9b2cf4f28d97b42ba68d Mon Sep 17 00:00:00 2001 From: number201724 Date: Fri, 21 Oct 2022 21:14:48 +0800 Subject: [PATCH 253/713] win,pipe: improve method of obtaining pid for ipc (#3765) In the old version of uv_pipe_open, the parent process ID is used always. If the open pipe is used in the same process, the parent process will be obtained incorrectly. Now we first get the client pid and compare it with its own pid. If it is the same, then get the server pid. If the two are the same, then the pipe is from the same process. Fixes: https://github.com/libuv/libuv/issues/3766 --- src/win/pipe.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index 1babe05c24c..b9fa986e368 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1639,9 +1639,13 @@ static DWORD uv__pipe_get_ipc_remote_pid(uv_pipe_t* handle) { /* If the both ends of the IPC pipe are owned by the same process, * the remote end pid may not yet be set. If so, do it here. * TODO: this is weird; it'd probably better to use a handshake. */ - if (*pid == 0) - *pid = GetCurrentProcessId(); - + if (*pid == 0) { + GetNamedPipeClientProcessId(handle->handle, pid); + if (*pid == GetCurrentProcessId()) { + GetNamedPipeServerProcessId(handle->handle, pid); + } + } + return *pid; } @@ -2342,7 +2346,10 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { if (pipe->ipc) { assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); - pipe->pipe.conn.ipc_remote_pid = uv_os_getppid(); + GetNamedPipeClientProcessId(os_handle, &pipe->pipe.conn.ipc_remote_pid); + if (pipe->pipe.conn.ipc_remote_pid == GetCurrentProcessId()) { + GetNamedPipeServerProcessId(os_handle, &pipe->pipe.conn.ipc_remote_pid); + } assert(pipe->pipe.conn.ipc_remote_pid != (DWORD)(uv_pid_t) -1); } return 0; From e900006642a5e8d4ab27a8760afcc03136f0dd8f Mon Sep 17 00:00:00 2001 From: daomingq Date: Fri, 21 Oct 2022 21:18:10 +0800 Subject: [PATCH 254/713] thread: add support for affinity (#3774) Backported thread affinity feature and related dependency commits from master. It will add support for those APIs: uv_cpumask_size, uv_thread_setaffinity, uv_thread_getaffinity. The supported platforms are Linux, Freebsd, and Windows. Empty implementations (returning UV_ENOTSUP) on non-supported platforms (such as OS X and AIX). --- CMakeLists.txt | 1 + Makefile.am | 1 + docs/src/misc.rst | 7 +++ docs/src/threading.rst | 31 ++++++++++ include/uv.h | 8 +++ src/unix/core.c | 9 +++ src/unix/thread.c | 98 ++++++++++++++++++++++++++++++ src/win/thread.c | 72 ++++++++++++++++++++++ test/task.h | 7 +++ test/test-list.h | 2 + test/test-thread-affinity.c | 116 ++++++++++++++++++++++++++++++++++++ 11 files changed, 352 insertions(+) create mode 100644 test/test-thread-affinity.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 74ee79362c3..d2dfdc5f516 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -615,6 +615,7 @@ if(LIBUV_BUILD_TESTS) test/test-tcp-write-to-half-open-connection.c test/test-tcp-writealot.c test/test-test-macros.c + test/test-thread-affinity.c test/test-thread-equal.c test/test-thread.c test/test-threadpool-cancel.c diff --git a/Makefile.am b/Makefile.am index b0b4f2529a0..0e45172ede9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -283,6 +283,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-test-macros.c \ test/test-thread-equal.c \ test/test-thread.c \ + test/test-thread-affinity.c \ test/test-threadpool-cancel.c \ test/test-threadpool.c \ test/test-timer-again.c \ diff --git a/docs/src/misc.rst b/docs/src/misc.rst index f6d26efc287..423ef84cbb8 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -365,6 +365,13 @@ API Frees the `cpu_infos` array previously allocated with :c:func:`uv_cpu_info`. +.. c:function:: int uv_cpumask_size(void) + + Returns the maximum size of the mask used for process/thread affinities, + or ``UV_ENOTSUP`` if affinities are not supported on the current platform. + + .. versionadded:: 1.45.0 + .. c:function:: int uv_interface_addresses(uv_interface_address_t** addresses, int* count) Gets address information about the network interfaces on the system. An diff --git a/docs/src/threading.rst b/docs/src/threading.rst index 7ca1d4b7a58..ca9fb0cea5d 100644 --- a/docs/src/threading.rst +++ b/docs/src/threading.rst @@ -88,6 +88,37 @@ Threads .. versionadded:: 1.26.0 +.. c:function:: int uv_thread_setaffinity(uv_thread_t* tid, char* cpumask, char* oldmask, size_t mask_size) + + Sets the specified thread's affinity to cpumask, which is specified in + bytes. Optionally returning the previous affinity setting in oldmask. + On Unix, uses :man:`pthread_getaffinity_np(3)` to get the affinity setting + and maps the cpu_set_t to bytes in oldmask. Then maps the bytes in cpumask + to a cpu_set_t and uses :man:`pthread_setaffinity_np(3)`. On Windows, maps + the bytes in cpumask to a bitmask and uses SetThreadAffinityMask() which + returns the previous affinity setting. + + The mask_size specifies the number of entries (bytes) in cpumask / oldmask, + and must be greater-than-or-equal-to :c:func:`uv_cpumask_size`. + + .. note:: + Thread affinity setting is not atomic on Windows. Unsupported on macOS. + + .. versionadded:: 1.45.0 + +.. c:function:: int uv_thread_getaffinity(uv_thread_t* tid, char* cpumask, size_t mask_size) + + Gets the specified thread's affinity setting. On Unix, this maps the + cpu_set_t returned by :man:`pthread_getaffinity_np(3)` to bytes in cpumask. + + The mask_size specifies the number of entries (bytes) in cpumask, + and must be greater-than-or-equal-to :c:func:`uv_cpumask_size`. + + .. note:: + Thread affinity getting is not atomic on Windows. Unsupported on macOS. + + .. versionadded:: 1.45.0 + .. c:function:: uv_thread_t uv_thread_self(void) .. 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) diff --git a/include/uv.h b/include/uv.h index d68c5c84e8a..383974243e1 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1240,6 +1240,7 @@ UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority); UV_EXTERN unsigned int uv_available_parallelism(void); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); +UV_EXTERN int uv_cpumask_size(void); UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses, int* count); @@ -1782,6 +1783,13 @@ UV_EXTERN int uv_thread_create_ex(uv_thread_t* tid, const uv_thread_options_t* params, uv_thread_cb entry, void* arg); +UV_EXTERN int uv_thread_setaffinity(uv_thread_t* tid, + char* cpumask, + char* oldmask, + size_t mask_size); +UV_EXTERN int uv_thread_getaffinity(uv_thread_t* tid, + char* cpumask, + size_t mask_size); 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); diff --git a/src/unix/core.c b/src/unix/core.c index aaa980b86ef..fc8559ba614 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -72,6 +72,8 @@ extern char** environ; # include # include # include +# include +# include # if defined(__FreeBSD__) # define uv__accept4 accept4 # endif @@ -1420,6 +1422,13 @@ uv_pid_t uv_os_getppid(void) { return getppid(); } +int uv_cpumask_size(void) { +#if defined(__linux__) || defined(__FreeBSD__) + return CPU_SETSIZE; +#else + return UV_ENOTSUP; +#endif +} int uv_os_getpriority(uv_pid_t pid, int* priority) { int r; diff --git a/src/unix/thread.c b/src/unix/thread.c index d89e5cd13ba..77159511b19 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -41,6 +41,17 @@ #include /* gnu_get_libc_version() */ #endif +#if defined(__linux__) +# include +# define uv__cpu_set_t cpu_set_t +#elif defined(__FreeBSD__) +# include +# include +# include +# define uv__cpu_set_t cpuset_t +#endif + + #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) @@ -284,6 +295,93 @@ int uv_thread_create_ex(uv_thread_t* tid, return UV__ERR(err); } +#if defined(__linux__) || defined(__FreeBSD__) + +int uv_thread_setaffinity(uv_thread_t* tid, + char* cpumask, + char* oldmask, + size_t mask_size) { + int i; + int r; + uv__cpu_set_t cpuset; + int cpumasksize; + + cpumasksize = uv_cpumask_size(); + if (cpumasksize < 0) + return cpumasksize; + if (mask_size < (size_t)cpumasksize) + return UV_EINVAL; + + if (oldmask != NULL) { + r = uv_thread_getaffinity(tid, oldmask, mask_size); + if (r < 0) + return r; + } + + CPU_ZERO(&cpuset); + for (i = 0; i < cpumasksize; i++) + if (cpumask[i]) + CPU_SET(i, &cpuset); + +#if defined(__ANDROID__) + if (sched_setaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset)) + r = errno; + else + r = 0; +#else + r = pthread_setaffinity_np(*tid, sizeof(cpuset), &cpuset); +#endif + + return UV__ERR(r); +} + + +int uv_thread_getaffinity(uv_thread_t* tid, + char* cpumask, + size_t mask_size) { + int r; + int i; + uv__cpu_set_t cpuset; + int cpumasksize; + + cpumasksize = uv_cpumask_size(); + if (cpumasksize < 0) + return cpumasksize; + if (mask_size < (size_t)cpumasksize) + return UV_EINVAL; + + CPU_ZERO(&cpuset); +#if defined(__ANDROID__) + if (sched_getaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset)) + r = errno; + else + r = 0; +#else + r = pthread_getaffinity_np(*tid, sizeof(cpuset), &cpuset); +#endif + if (r) + return UV__ERR(r); + for (i = 0; i < cpumasksize; i++) + cpumask[i] = !!CPU_ISSET(i, &cpuset); + + return 0; +} +#else +int uv_thread_setaffinity(uv_thread_t* tid, + char* cpumask, + char* oldmask, + size_t mask_size) { + return UV_ENOTSUP; +} + + +int uv_thread_getaffinity(uv_thread_t* tid, + char* cpumask, + size_t mask_size) { + return UV_ENOTSUP; +} +#endif /* defined(__linux__) || defined(UV_BSD_H) */ + uv_thread_t uv_thread_self(void) { return pthread_self(); diff --git a/src/win/thread.c b/src/win/thread.c index d3b1c96b619..da150e45369 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -180,6 +180,78 @@ int uv_thread_create_ex(uv_thread_t* tid, return UV_EIO; } +int uv_thread_setaffinity(uv_thread_t* tid, + char* cpumask, + char* oldmask, + size_t mask_size) { + int i; + HANDLE hproc; + DWORD_PTR procmask; + DWORD_PTR sysmask; + DWORD_PTR threadmask; + DWORD_PTR oldthreadmask; + int cpumasksize; + + cpumasksize = uv_cpumask_size(); + assert(cpumasksize > 0); + if (mask_size < (size_t)cpumasksize) + return UV_EINVAL; + + hproc = GetCurrentProcess(); + if (!GetProcessAffinityMask(hproc, &procmask, &sysmask)) + return uv_translate_sys_error(GetLastError()); + + threadmask = 0; + for (i = 0; i < cpumasksize; i++) { + if (cpumask[i]) { + if (procmask & (1 << i)) + threadmask |= 1 << i; + else + return UV_EINVAL; + } + } + + oldthreadmask = SetThreadAffinityMask(*tid, threadmask); + if (oldthreadmask == 0) + return uv_translate_sys_error(GetLastError()); + + if (oldmask != NULL) { + for (i = 0; i < cpumasksize; i++) + oldmask[i] = (oldthreadmask >> i) & 1; + } + + return 0; +} + +int uv_thread_getaffinity(uv_thread_t* tid, + char* cpumask, + size_t mask_size) { + int i; + HANDLE hproc; + DWORD_PTR procmask; + DWORD_PTR sysmask; + DWORD_PTR threadmask; + int cpumasksize; + + cpumasksize = uv_cpumask_size(); + assert(cpumasksize > 0); + if (mask_size < (size_t)cpumasksize) + return UV_EINVAL; + + hproc = GetCurrentProcess(); + if (!GetProcessAffinityMask(hproc, &procmask, &sysmask)) + return uv_translate_sys_error(GetLastError()); + + threadmask = SetThreadAffinityMask(*tid, procmask); + if (threadmask == 0 || SetThreadAffinityMask(*tid, threadmask) == 0) + return uv_translate_sys_error(GetLastError()); + + for (i = 0; i < cpumasksize; i++) + cpumask[i] = (threadmask >> i) & 1; + + return 0; +} + uv_thread_t uv_thread_self(void) { uv_thread_t key; diff --git a/test/task.h b/test/task.h index 44fa25bfbff..91ccb59a470 100644 --- a/test/task.h +++ b/test/task.h @@ -370,4 +370,11 @@ UNUSED static int can_ipv6(void) { "Cygwin runtime hangs on listen+connect in same process." #endif +#if !defined(__linux__) && \ + !defined(__FreeBSD__) && \ + !defined(_WIN32) +# define NO_CPU_AFFINITY \ + "affinity not supported on this platform." +#endif + #endif /* TASK_H_ */ diff --git a/test/test-list.h b/test/test-list.h index 8983cbc3f29..b2e8a75f430 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -450,6 +450,7 @@ TEST_DECLARE (thread_rwlock) TEST_DECLARE (thread_rwlock_trylock) TEST_DECLARE (thread_create) TEST_DECLARE (thread_equal) +TEST_DECLARE (thread_affinity) TEST_DECLARE (dlerror) #if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ !defined(__sun) @@ -1122,6 +1123,7 @@ TASK_LIST_START TEST_ENTRY (thread_rwlock_trylock) TEST_ENTRY (thread_create) TEST_ENTRY (thread_equal) + TEST_ENTRY (thread_affinity) TEST_ENTRY (dlerror) TEST_ENTRY (ip4_addr) TEST_ENTRY (ip6_addr_link_local) diff --git a/test/test-thread-affinity.c b/test/test-thread-affinity.c new file mode 100644 index 00000000000..43783bc4b3f --- /dev/null +++ b/test/test-thread-affinity.c @@ -0,0 +1,116 @@ +/* Copyright libuv project contributors. All rights reserved. + */ + +#include "uv.h" +#include "task.h" + +#include + +#ifndef NO_CPU_AFFINITY + +static void check_affinity(void* arg) { + int r; + char* cpumask; + int cpumasksize; + uv_thread_t tid; + + cpumask = (char*)arg; + cpumasksize = uv_cpumask_size(); + ASSERT(cpumasksize > 0); + tid = uv_thread_self(); + r = uv_thread_setaffinity(&tid, cpumask, NULL, cpumasksize); + ASSERT(r == 0); + r = uv_thread_setaffinity(&tid, cpumask + cpumasksize, cpumask, cpumasksize); + ASSERT(r == 0); +} + + +TEST_IMPL(thread_affinity) { + int t1first; + int t1second; + int t2first; + int t2second; + int cpumasksize; + char* cpumask; + int ncpus; + int r; + uv_thread_t threads[3]; + +#ifdef _WIN32 + /* uv_thread_self isn't defined for the main thread on Windows */ + threads[0] = GetCurrentThread(); +#else + threads[0] = uv_thread_self(); +#endif + cpumasksize = uv_cpumask_size(); + ASSERT(cpumasksize > 0); + + cpumask = calloc(4 * cpumasksize, 1); + ASSERT(cpumask); + + r = uv_thread_getaffinity(&threads[0], cpumask, cpumasksize); + ASSERT(r == 0); + ASSERT(cpumask[0] && "test must be run with cpu 0 affinity"); + ncpus = 0; + while (cpumask[++ncpus]) { } + memset(cpumask, 0, 4 * cpumasksize); + + t1first = cpumasksize * 0; + t1second = cpumasksize * 1; + t2first = cpumasksize * 2; + t2second = cpumasksize * 3; + + cpumask[t1second + 0] = 1; + cpumask[t2first + 0] = 1; + cpumask[t1first + (ncpus >= 2)] = 1; + cpumask[t2second + (ncpus >= 2)] = 1; +#ifdef __linux__ + cpumask[t1second + 2] = 1; + cpumask[t2first + 2] = 1; + cpumask[t1first + 3] = 1; + cpumask[t2second + 3] = 1; +#else + if (ncpus >= 3) { + cpumask[t1second + 2] = 1; + cpumask[t2first + 2] = 1; + } + if (ncpus >= 4) { + cpumask[t1first + 3] = 1; + cpumask[t2second + 3] = 1; + } +#endif + + ASSERT(0 == uv_thread_create(threads + 1, + check_affinity, + &cpumask[t1first])); + ASSERT(0 == uv_thread_create(threads + 2, + check_affinity, + &cpumask[t2first])); + ASSERT(0 == uv_thread_join(threads + 1)); + ASSERT(0 == uv_thread_join(threads + 2)); + + ASSERT(cpumask[t1first + 0] == (ncpus == 1)); + ASSERT(cpumask[t1first + 1] == (ncpus >= 2)); + ASSERT(cpumask[t1first + 2] == 0); + ASSERT(cpumask[t1first + 3] == (ncpus >= 4)); + + ASSERT(cpumask[t2first + 0] == 1); + ASSERT(cpumask[t2first + 1] == 0); + ASSERT(cpumask[t2first + 2] == (ncpus >= 3)); + ASSERT(cpumask[t2first + 3] == 0); + + free(cpumask); + + return 0; +} + +#else + +TEST_IMPL(thread_affinity) { + int cpumasksize; + cpumasksize = uv_cpumask_size(); + ASSERT(cpumasksize == UV_ENOTSUP); + return 0; +} + +#endif From c83b9bd9c6876c0b6b605f38c92a92c2f630e0bd Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 25 Oct 2022 13:00:45 +0200 Subject: [PATCH 255/713] include: map ENODATA error code (#3802) Fixes: https://github.com/libuv/libuv/issues/3795 --- include/uv.h | 1 + include/uv/errno.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/uv.h b/include/uv.h index 383974243e1..d788bc1782d 100644 --- a/include/uv.h +++ b/include/uv.h @@ -147,6 +147,7 @@ extern "C" { XX(EFTYPE, "inappropriate file type or format") \ XX(EILSEQ, "illegal byte sequence") \ XX(ESOCKTNOSUPPORT, "socket type not supported") \ + XX(ENODATA, "no data available") \ #define UV_HANDLE_TYPE_MAP(XX) \ XX(ASYNC, async) \ diff --git a/include/uv/errno.h b/include/uv/errno.h index 71906b3f5e6..0bc429bc6c7 100644 --- a/include/uv/errno.h +++ b/include/uv/errno.h @@ -457,4 +457,10 @@ # define UV__ESOCKTNOSUPPORT (-4025) #endif +#if defined(ENODATA) && !defined(_WIN32) +# define UV__ENODATA UV__ERR(ENODATA) +#else +# define UV__ENODATA (-4024) +#endif + #endif /* UV_ERRNO_H_ */ From c880de3004ac31fde42129ff069a58d67013b8bd Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Thu, 27 Oct 2022 13:33:02 +0200 Subject: [PATCH 256/713] build: remove bashism from autogen.sh --- autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index bfd8f3e6df0..cf82cc634d4 100755 --- a/autogen.sh +++ b/autogen.sh @@ -17,7 +17,7 @@ set -eu cd `dirname "$0"` -if [ "${1:-dev}" == "release" ]; then +if [ "${1:-dev}" = "release" ]; then export LIBUV_RELEASE=true else export LIBUV_RELEASE=false From 2b4b293ebb2e876fe61df37c00d522ce55f2e34d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 4 Nov 2022 10:25:08 +0100 Subject: [PATCH 257/713] win,tcp,udp: remove "active streams" optimization It has been disabled for 11 years, I guess it should remain that way. --- include/uv/win.h | 4 +- src/win/core.c | 3 -- src/win/tcp.c | 36 ++-------------- src/win/udp.c | 106 +++++++++++------------------------------------ 4 files changed, 30 insertions(+), 119 deletions(-) diff --git a/include/uv/win.h b/include/uv/win.h index 582d2e877e0..d2f69ccff14 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -343,9 +343,9 @@ typedef struct { uv_idle_t* next_idle_handle; \ /* This handle holds the peer sockets for the fast variant of uv_poll_t */ \ SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \ - /* Counter to keep track of active tcp streams */ \ + /* No longer used. */ \ unsigned int active_tcp_streams; \ - /* Counter to keep track of active udp streams */ \ + /* No longer used. */ \ unsigned int active_udp_streams; \ /* Counter to started timer */ \ uint64_t timer_counter; \ diff --git a/src/win/core.c b/src/win/core.c index 67af93e6571..8d4bbefddb9 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -279,9 +279,6 @@ int uv_loop_init(uv_loop_t* loop) { memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); - loop->active_tcp_streams = 0; - loop->active_udp_streams = 0; - loop->timer_counter = 0; loop->stop_flag = 0; diff --git a/src/win/tcp.c b/src/win/tcp.c index f061ed76caf..20b03947fed 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -29,14 +29,6 @@ #include "req-inl.h" -/* - * Threshold of active tcp streams for which to preallocate tcp read buffers. - * (Due to node slab allocator performing poorly under this pattern, - * the optimization is temporarily disabled (threshold=0). This will be - * revisited once node allocator is improved.) - */ -const unsigned int uv_active_tcp_streams_threshold = 0; - /* * Number of simultaneous pending AcceptEx calls. */ @@ -273,7 +265,6 @@ void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { } uv__handle_close(handle); - loop->active_tcp_streams--; } @@ -483,26 +474,9 @@ static void uv__tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { req = &handle->read_req; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); - /* - * Preallocate a read buffer if the number of active streams is below - * the threshold. - */ - if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) { - handle->flags &= ~UV_HANDLE_ZERO_READ; - handle->tcp.conn.read_buffer = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer); - if (handle->tcp.conn.read_buffer.base == NULL || - handle->tcp.conn.read_buffer.len == 0) { - handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer); - return; - } - assert(handle->tcp.conn.read_buffer.base != NULL); - buf = handle->tcp.conn.read_buffer; - } else { - handle->flags |= UV_HANDLE_ZERO_READ; - buf.base = (char*) &uv_zero_; - buf.len = 0; - } + handle->flags |= UV_HANDLE_ZERO_READ; + buf.base = (char*) &uv_zero_; + buf.len = 0; /* Prepare the overlapped structure. */ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped)); @@ -715,8 +689,6 @@ int uv__tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { } } - loop->active_tcp_streams++; - return err; } @@ -1247,7 +1219,6 @@ void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, 0) == 0) { uv__connection_init((uv_stream_t*)handle); handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; - loop->active_tcp_streams++; } else { err = WSAGetLastError(); } @@ -1330,7 +1301,6 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp, tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; } - tcp->loop->active_tcp_streams++; return 0; } diff --git a/src/win/udp.c b/src/win/udp.c index eaebc1eda8f..1edb7f62279 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -29,11 +29,6 @@ #include "req-inl.h" -/* - * Threshold of active udp streams for which to preallocate udp read buffers. - */ -const unsigned int uv_active_udp_streams_threshold = 0; - /* A zero-size buffer for use by uv_udp_read */ static char uv_zero_[] = ""; int uv_udp_getpeername(const uv_udp_t* handle, @@ -276,84 +271,35 @@ static void uv__udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { req = &handle->recv_req; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); - /* - * Preallocate a read buffer if the number of active streams is below - * the threshold. - */ - if (loop->active_udp_streams < uv_active_udp_streams_threshold) { - handle->flags &= ~UV_HANDLE_ZERO_READ; - - handle->recv_buffer = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &handle->recv_buffer); - if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) { - handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0); - return; - } - assert(handle->recv_buffer.base != NULL); + handle->flags |= UV_HANDLE_ZERO_READ; - buf = handle->recv_buffer; - memset(&handle->recv_from, 0, sizeof handle->recv_from); - handle->recv_from_len = sizeof handle->recv_from; - flags = 0; + buf.base = (char*) uv_zero_; + buf.len = 0; + flags = MSG_PEEK; - result = handle->func_wsarecvfrom(handle->socket, - (WSABUF*) &buf, - 1, - &bytes, - &flags, - (struct sockaddr*) &handle->recv_from, - &handle->recv_from_len, - &req->u.io.overlapped, - NULL); - - if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { - /* Process the req without IOCP. */ - handle->flags |= UV_HANDLE_READ_PENDING; - req->u.io.overlapped.InternalHigh = bytes; - handle->reqs_pending++; - uv__insert_pending_req(loop, req); - } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { - /* The req will be processed with IOCP. */ - handle->flags |= UV_HANDLE_READ_PENDING; - handle->reqs_pending++; - } else { - /* Make this req pending reporting an error. */ - SET_REQ_ERROR(req, WSAGetLastError()); - uv__insert_pending_req(loop, req); - handle->reqs_pending++; - } + result = handle->func_wsarecv(handle->socket, + (WSABUF*) &buf, + 1, + &bytes, + &flags, + &req->u.io.overlapped, + NULL); + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Process the req without IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + req->u.io.overlapped.InternalHigh = bytes; + handle->reqs_pending++; + uv__insert_pending_req(loop, req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* The req will be processed with IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; } else { - handle->flags |= UV_HANDLE_ZERO_READ; - - buf.base = (char*) uv_zero_; - buf.len = 0; - flags = MSG_PEEK; - - result = handle->func_wsarecv(handle->socket, - (WSABUF*) &buf, - 1, - &bytes, - &flags, - &req->u.io.overlapped, - NULL); - - if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { - /* Process the req without IOCP. */ - handle->flags |= UV_HANDLE_READ_PENDING; - req->u.io.overlapped.InternalHigh = bytes; - handle->reqs_pending++; - uv__insert_pending_req(loop, req); - } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { - /* The req will be processed with IOCP. */ - handle->flags |= UV_HANDLE_READ_PENDING; - handle->reqs_pending++; - } else { - /* Make this req pending reporting an error. */ - SET_REQ_ERROR(req, WSAGetLastError()); - uv__insert_pending_req(loop, req); - handle->reqs_pending++; - } + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv__insert_pending_req(loop, req); + handle->reqs_pending++; } } @@ -376,7 +322,6 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, handle->flags |= UV_HANDLE_READING; INCREASE_ACTIVE_COUNT(loop, handle); - loop->active_udp_streams++; handle->recv_cb = recv_cb; handle->alloc_cb = alloc_cb; @@ -393,7 +338,6 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, int uv__udp_recv_stop(uv_udp_t* handle) { if (handle->flags & UV_HANDLE_READING) { handle->flags &= ~UV_HANDLE_READING; - handle->loop->active_udp_streams--; DECREASE_ACTIVE_COUNT(loop, handle); } From a7b16bfb332f6aa2bf25bdcbc4ddf624f44b6ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 7 Nov 2022 14:10:35 +0100 Subject: [PATCH 258/713] win: drop code checking for Windows XP / Server 2k3 Our minimum requirements are Windows 8 now. --- docs/src/fs.rst | 4 -- docs/src/guide/networking.rst | 3 +- src/win/poll.c | 5 +-- src/win/tcp.c | 2 +- src/win/util.c | 81 ++--------------------------------- test/test-fs.c | 51 +--------------------- 6 files changed, 10 insertions(+), 136 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index e6e7088e573..86d77c7948b 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -465,10 +465,6 @@ API The background story and some more details on these issues can be checked `here `_. - .. note:: - This function is not implemented on Windows XP and Windows Server 2003. - On these systems, UV_ENOSYS is returned. - .. versionadded:: 1.8.0 .. c:function:: int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) diff --git a/docs/src/guide/networking.rst b/docs/src/guide/networking.rst index dcb5643137c..892ade0023e 100644 --- a/docs/src/guide/networking.rst +++ b/docs/src/guide/networking.rst @@ -164,7 +164,7 @@ IPv6 stack only IPv6 sockets can be used for both IPv4 and IPv6 communication. If you want to restrict the socket to IPv6 only, pass the ``UV_UDP_IPV6ONLY`` flag to -``uv_udp_bind`` [#]_. +``uv_udp_bind``. Multicast ~~~~~~~~~ @@ -250,7 +250,6 @@ times, with each address being reported once. ---- .. [#] https://beej.us/guide/bgnet/html/#broadcast-packetshello-world -.. [#] on Windows only supported on Windows Vista and later. .. [#] https://www.tldp.org/HOWTO/Multicast-HOWTO-6.html#ss6.1 .. [#] libuv use the system ``getaddrinfo`` in the libuv threadpool. libuv v0.8.0 and earlier also included c-ares_ as an alternative, but this has been diff --git a/src/win/poll.c b/src/win/poll.c index bd531b06792..7fec2b99650 100644 --- a/src/win/poll.c +++ b/src/win/poll.c @@ -425,9 +425,8 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, return uv_translate_sys_error(WSAGetLastError()); /* Try to obtain a base handle for the socket. This increases this chances that - * we find an AFD handle and are able to use the fast poll mechanism. This will - * always fail on windows XP/2k3, since they don't support the. SIO_BASE_HANDLE - * ioctl. */ + * we find an AFD handle and are able to use the fast poll mechanism. + */ #ifndef NDEBUG base_socket = INVALID_SOCKET; #endif diff --git a/src/win/tcp.c b/src/win/tcp.c index 20b03947fed..62e0917fe64 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -1401,7 +1401,7 @@ static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) { uv_tcp_non_ifs_lsp_ipv4; /* If there are non-ifs LSPs then try to obtain a base handle for the socket. - * This will always fail on Windows XP/3k. */ + */ if (non_ifs_lsp) { DWORD bytes; if (WSAIoctl(socket, diff --git a/src/win/util.c b/src/win/util.c index 695f849441e..3dd9d96a841 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -686,37 +686,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { } -static int is_windows_version_or_greater(DWORD os_major, - DWORD os_minor, - WORD service_pack_major, - WORD service_pack_minor) { - OSVERSIONINFOEX osvi; - DWORDLONG condition_mask = 0; - int op = VER_GREATER_EQUAL; - - /* Initialize the OSVERSIONINFOEX structure. */ - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - osvi.dwMajorVersion = os_major; - osvi.dwMinorVersion = os_minor; - osvi.wServicePackMajor = service_pack_major; - osvi.wServicePackMinor = service_pack_minor; - - /* Initialize the condition mask. */ - VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op); - VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op); - VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op); - VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op); - - /* Perform the test. */ - return (int) VerifyVersionInfo( - &osvi, - VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR, - condition_mask); -} - - static int address_prefix_match(int family, struct sockaddr* address, struct sockaddr* prefix_address, @@ -763,26 +732,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, uv_interface_address_t* uv_address; int count; - - int is_vista_or_greater; ULONG flags; *addresses_ptr = NULL; *count_ptr = 0; - is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0); - if (is_vista_or_greater) { - flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | - GAA_FLAG_SKIP_DNS_SERVER; - } else { - /* We need at least XP SP1. */ - if (!is_windows_version_or_greater(5, 1, 1, 0)) - return UV_ENOTSUP; - - flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | - GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX; - } - + flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_DNS_SERVER; /* Fetch the size of the adapters reported by windows, and then get the list * itself. */ @@ -946,37 +902,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, sa = unicast_address->Address.lpSockaddr; - /* XP has no OnLinkPrefixLength field. */ - if (is_vista_or_greater) { - prefix_len = - ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength; - } else { - /* Prior to Windows Vista the FirstPrefix pointed to the list with - * single prefix for each IP address assigned to the adapter. - * Order of FirstPrefix does not match order of FirstUnicastAddress, - * so we need to find corresponding prefix. - */ - IP_ADAPTER_PREFIX* prefix; - prefix_len = 0; - - for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) { - /* We want the longest matching prefix. */ - if (prefix->Address.lpSockaddr->sa_family != sa->sa_family || - prefix->PrefixLength <= prefix_len) - continue; - - if (address_prefix_match(sa->sa_family, sa, - prefix->Address.lpSockaddr, prefix->PrefixLength)) { - prefix_len = prefix->PrefixLength; - } - } - - /* If there is no matching prefix information, return a single-host - * subnet mask (e.g. 255.255.255.255 for IPv4). - */ - if (!prefix_len) - prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32; - } + prefix_len = + ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength; memset(uv_address, 0, sizeof *uv_address); diff --git a/test/test-fs.c b/test/test-fs.c index 8d3a388c94d..78ee499917f 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -219,16 +219,6 @@ static void realpath_cb(uv_fs_t* req) { char test_file_abs_buf[PATHMAX]; size_t test_file_abs_size = sizeof(test_file_abs_buf); ASSERT(req->fs_type == UV_FS_REALPATH); -#ifdef _WIN32 - /* - * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() - */ - if (req->result == UV_ENOSYS) { - realpath_cb_count++; - uv_fs_req_cleanup(req); - return; - } -#endif ASSERT(req->result == 0); uv_cwd(test_file_abs_buf, &test_file_abs_size); @@ -770,11 +760,10 @@ TEST_IMPL(fs_file_loop) { r = uv_fs_symlink(NULL, &req, "test_symlink", "test_symlink", 0, NULL); #ifdef _WIN32 /* - * Windows XP and Server 2003 don't support symlinks; we'll get UV_ENOTSUP. - * Starting with vista they are supported, but only when elevated, otherwise + * Symlinks are only suported but only when elevated, otherwise * we'll see UV_EPERM. */ - if (r == UV_ENOTSUP || r == UV_EPERM) + if (r == UV_EPERM) return 0; #elif defined(__MSYS__) /* MSYS2's approximation of symlinks with copies does not work for broken @@ -2049,15 +2038,6 @@ TEST_IMPL(fs_realpath) { ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(dummy_cb_count == 1); ASSERT_NULL(req.ptr); -#ifdef _WIN32 - /* - * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() - */ - if (req.result == UV_ENOSYS) { - uv_fs_req_cleanup(&req); - RETURN_SKIP("realpath is not supported on Windows XP"); - } -#endif ASSERT(req.result == UV_ENOENT); uv_fs_req_cleanup(&req); @@ -2168,15 +2148,6 @@ TEST_IMPL(fs_symlink) { uv_fs_req_cleanup(&req); r = uv_fs_realpath(NULL, &req, "test_file_symlink_symlink", NULL); -#ifdef _WIN32 - /* - * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() - */ - if (r == UV_ENOSYS) { - uv_fs_req_cleanup(&req); - RETURN_SKIP("realpath is not supported on Windows XP"); - } -#endif ASSERT(r == 0); #ifdef _WIN32 ASSERT(stricmp(req.ptr, test_file_abs_buf) == 0); @@ -2226,15 +2197,6 @@ TEST_IMPL(fs_symlink) { ASSERT(readlink_cb_count == 1); r = uv_fs_realpath(loop, &req, "test_file", realpath_cb); -#ifdef _WIN32 - /* - * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() - */ - if (r == UV_ENOSYS) { - uv_fs_req_cleanup(&req); - RETURN_SKIP("realpath is not supported on Windows XP"); - } -#endif ASSERT(r == 0); uv_run(loop, UV_RUN_DEFAULT); ASSERT(realpath_cb_count == 1); @@ -2335,15 +2297,6 @@ int test_symlink_dir_impl(int type) { uv_fs_req_cleanup(&req); r = uv_fs_realpath(NULL, &req, "test_dir_symlink", NULL); -#ifdef _WIN32 - /* - * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() - */ - if (r == UV_ENOSYS) { - uv_fs_req_cleanup(&req); - RETURN_SKIP("realpath is not supported on Windows XP"); - } -#endif ASSERT(r == 0); #ifdef _WIN32 ASSERT(strlen(req.ptr) == test_dir_abs_size - 5); From ec5130c3f966e76fe11df22fe8a04c8fe862187d Mon Sep 17 00:00:00 2001 From: twosee Date: Tue, 8 Nov 2022 16:56:14 +0800 Subject: [PATCH 259/713] unix,win: fix 'sprintf' is deprecated warning (#3813) --- src/inet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/inet.c b/src/inet.c index 4b630f53bb8..cd77496846e 100644 --- a/src/inet.c +++ b/src/inet.c @@ -130,7 +130,7 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) { tp += strlen(tp); break; } - tp += sprintf(tp, "%x", words[i]); + tp += snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]); } /* Was it a trailing run of 0x00's? */ if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words)) From 8a1f378f05eacd1ea7ae4bf2950b7494417fd22b Mon Sep 17 00:00:00 2001 From: Qix Date: Tue, 8 Nov 2022 09:57:54 +0100 Subject: [PATCH 260/713] doc: mention close_cb can be NULL (#3810) --- docs/src/handle.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/handle.rst b/docs/src/handle.rst index 0edb7d7adf2..e91d6e8fb2d 100644 --- a/docs/src/handle.rst +++ b/docs/src/handle.rst @@ -153,6 +153,9 @@ API In-progress requests, like uv_connect_t or uv_write_t, are cancelled and have their callbacks called asynchronously with status=UV_ECANCELED. + `close_cb` can be `NULL` in cases where no cleanup or deallocation is + necessary. + .. c:function:: void uv_ref(uv_handle_t* handle) Reference the given handle. References are idempotent, that is, if a handle From dff3f8ccabee15b1545523329e39e7acd2e77563 Mon Sep 17 00:00:00 2001 From: ywave620 <60539365+ywave620@users.noreply.github.com> Date: Tue, 8 Nov 2022 17:23:40 +0800 Subject: [PATCH 261/713] win: optimize udp receive performance (#3807) Do at most 32 nonblocking udp receive in a row. Fixes: https://github.com/libuv/libuv/issues/3704 --- CMakeLists.txt | 1 + Makefile.am | 1 + src/win/udp.c | 99 +++++++++++++++------------- test/test-list.h | 2 + test/test-udp-recv-in-a-row.c | 121 ++++++++++++++++++++++++++++++++++ 5 files changed, 180 insertions(+), 44 deletions(-) create mode 100644 test/test-udp-recv-in-a-row.c diff --git a/CMakeLists.txt b/CMakeLists.txt index d2dfdc5f516..d2b4e44c7c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -648,6 +648,7 @@ if(LIBUV_BUILD_TESTS) test/test-udp-sendmmsg-error.c test/test-udp-send-unreachable.c test/test-udp-try-send.c + test/test-udp-recv-in-a-row.c test/test-uname.c test/test-walk-handles.c test/test-watcher-cross-stop.c) diff --git a/Makefile.am b/Makefile.am index 0e45172ede9..7545ee0c274 100644 --- a/Makefile.am +++ b/Makefile.am @@ -314,6 +314,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-udp-sendmmsg-error.c \ test/test-udp-send-unreachable.c \ test/test-udp-try-send.c \ + test/test-udp-recv-in-a-row.c \ test/test-uname.c \ test/test-walk-handles.c \ test/test-watcher-cross-stop.c diff --git a/src/win/udp.c b/src/win/udp.c index 1edb7f62279..8a982d1907d 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -441,57 +441,68 @@ void uv__process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, DWORD bytes, err, flags; struct sockaddr_storage from; int from_len; + int count; + + /* Prevent loop starvation when the data comes in as fast as + * (or faster than) we can read it. */ + count = 32; + + do { + /* Do at most `count` nonblocking receive. */ + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); + goto done; + } - /* Do a nonblocking receive. - * TODO: try to read multiple datagrams at once. FIONREAD maybe? */ - buf = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf); - if (buf.base == NULL || buf.len == 0) { - handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); - goto done; - } - assert(buf.base != NULL); - - memset(&from, 0, sizeof from); - from_len = sizeof from; + memset(&from, 0, sizeof from); + from_len = sizeof from; - flags = 0; + flags = 0; - if (WSARecvFrom(handle->socket, - (WSABUF*)&buf, - 1, - &bytes, - &flags, - (struct sockaddr*) &from, - &from_len, - NULL, - NULL) != SOCKET_ERROR) { + if (WSARecvFrom(handle->socket, + (WSABUF*)&buf, + 1, + &bytes, + &flags, + (struct sockaddr*) &from, + &from_len, + NULL, + NULL) != SOCKET_ERROR) { - /* Message received */ - handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0); - } else { - err = WSAGetLastError(); - if (err == WSAEMSGSIZE) { - /* Message truncated */ - handle->recv_cb(handle, - bytes, - &buf, - (const struct sockaddr*) &from, - UV_UDP_PARTIAL); - } else if (err == WSAEWOULDBLOCK) { - /* Kernel buffer empty */ - handle->recv_cb(handle, 0, &buf, NULL, 0); - } else if (err == WSAECONNRESET || err == WSAENETRESET) { - /* WSAECONNRESET/WSANETRESET is ignored because this just indicates - * that a previous sendto operation failed. - */ - handle->recv_cb(handle, 0, &buf, NULL, 0); + /* Message received */ + err = ERROR_SUCCESS; + handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0); } else { - /* Any other error that we want to report back to the user. */ - uv_udp_recv_stop(handle); - handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0); + err = WSAGetLastError(); + if (err == WSAEMSGSIZE) { + /* Message truncated */ + handle->recv_cb(handle, + bytes, + &buf, + (const struct sockaddr*) &from, + UV_UDP_PARTIAL); + } else if (err == WSAEWOULDBLOCK) { + /* Kernel buffer empty */ + handle->recv_cb(handle, 0, &buf, NULL, 0); + } else if (err == WSAECONNRESET || err == WSAENETRESET) { + /* WSAECONNRESET/WSANETRESET is ignored because this just indicates + * that a previous sendto operation failed. + */ + handle->recv_cb(handle, 0, &buf, NULL, 0); + } else { + /* Any other error that we want to report back to the user. */ + uv_udp_recv_stop(handle); + handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0); + } } } + while (err == ERROR_SUCCESS && + count-- > 0 && + /* The recv_cb callback may decide to pause or close the handle. */ + (handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)); } done: diff --git a/test/test-list.h b/test/test-list.h index b2e8a75f430..5a6d09fc02e 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -185,6 +185,7 @@ TEST_DECLARE (udp_open) TEST_DECLARE (udp_open_twice) TEST_DECLARE (udp_open_bound) TEST_DECLARE (udp_open_connect) +TEST_DECLARE (udp_recv_in_a_row) #ifndef _WIN32 TEST_DECLARE (udp_send_unix) #endif @@ -770,6 +771,7 @@ TASK_LIST_START TEST_ENTRY (udp_multicast_ttl) TEST_ENTRY (udp_sendmmsg_error) TEST_ENTRY (udp_try_send) + TEST_ENTRY (udp_recv_in_a_row) TEST_ENTRY (udp_open) TEST_ENTRY (udp_open_twice) diff --git a/test/test-udp-recv-in-a-row.c b/test/test-udp-recv-in-a-row.c new file mode 100644 index 00000000000..531fd1fac0f --- /dev/null +++ b/test/test-udp-recv-in-a-row.c @@ -0,0 +1,121 @@ +/* Copyright The libuv project and contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +static uv_udp_t server; +static uv_udp_t client; +static uv_check_t check_handle; +static uv_buf_t buf; +static struct sockaddr_in addr; +static char send_data[10]; +static int check_cb_called; + +#define N 5 +static int recv_cnt; + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[sizeof(send_data)]; + buf->base = slab; + buf->len = sizeof(slab); +} + +static void sv_recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* rcvbuf, + const struct sockaddr* addr, + unsigned flags) { + if (++ recv_cnt < N) { + ASSERT_EQ(sizeof(send_data), nread); + } else { + ASSERT_EQ(0, nread); + } +} + +static void check_cb(uv_check_t* handle) { + ASSERT_PTR_EQ(&check_handle, handle); + + /** + * sv_recv_cb() is called with nread set to zero to indicate + * there is no more udp packet in the kernel, so the actual + * recv_cnt is one larger than N. + */ + ASSERT_EQ(N+1, recv_cnt); + check_cb_called = 1; + + /* we are done */ + ASSERT_EQ(0, uv_check_stop(handle)); + uv_close((uv_handle_t*) &client, NULL); + uv_close((uv_handle_t*) &check_handle, NULL); + uv_close((uv_handle_t*) &server, NULL); +} + + +TEST_IMPL(udp_recv_in_a_row) { + int i, r; + + ASSERT_EQ(0, uv_check_init(uv_default_loop(), &check_handle)); + ASSERT_EQ(0, uv_check_start(&check_handle, check_cb)); + + ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT_EQ(0, uv_udp_init(uv_default_loop(), &server)); + ASSERT_EQ(0, uv_udp_bind(&server, (const struct sockaddr*) &addr, 0)); + ASSERT_EQ(0, uv_udp_recv_start(&server, alloc_cb, sv_recv_cb)); + + ASSERT_EQ(0, uv_udp_init(uv_default_loop(), &client)); + + /* send N-1 udp packets */ + buf = uv_buf_init(send_data, sizeof(send_data)); + for (i = 0; i < N - 1; i ++) { + r = uv_udp_try_send(&client, + &buf, + 1, + (const struct sockaddr*) &addr); + ASSERT_EQ(sizeof(send_data), r); + } + + /* send an empty udp packet */ + buf = uv_buf_init(NULL, 0); + r = uv_udp_try_send(&client, + &buf, + 1, + (const struct sockaddr*) &addr); + ASSERT_EQ(0, r); + + /* check_cb() asserts that the N packets can be received + * before it gets called. + */ + + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT(check_cb_called); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From 07949ce2aea6028ef597faf193b2fddf4a889036 Mon Sep 17 00:00:00 2001 From: twosee Date: Tue, 8 Nov 2022 17:24:45 +0800 Subject: [PATCH 262/713] win: fix an incompatible types warning (#3798) --- src/win/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/util.c b/src/win/util.c index 3dd9d96a841..79ab61b7c69 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -247,7 +247,7 @@ int uv_cwd(char* buffer, size_t* size) { int uv_chdir(const char* dir) { WCHAR *utf16_buffer; - size_t utf16_len; + DWORD utf16_len; WCHAR drive_letter, env_var[4]; int r; From 8975c05d199558b0cc2e98f26ce33c6090d1d7a1 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 8 Nov 2022 17:33:19 +0100 Subject: [PATCH 263/713] doc: document 0 return value for free/total memory (#3817) Refs: https://github.com/libuv/libuv/discussions/3809 --- docs/src/misc.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 423ef84cbb8..a18040e2eb5 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -551,11 +551,13 @@ API .. c:function:: uint64_t uv_get_free_memory(void) - Gets the amount of free memory available in the system, as reported by the kernel (in bytes). + Gets the amount of free memory available in the system, as reported by + the kernel (in bytes). Returns 0 when unknown. .. c:function:: uint64_t uv_get_total_memory(void) Gets the total amount of physical memory in the system (in bytes). + Returns 0 when unknown. .. c:function:: uint64_t uv_get_constrained_memory(void) From 3300502231b58227d8d3e7c16c762224757da48d Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 8 Nov 2022 12:40:17 -0500 Subject: [PATCH 264/713] darwin: use hw.cpufrequency again for frequency info (#3679) This reverts commit 87f076515937345fda1a1dbc598f34e65e1b81c7 and implements a work-around instead. This has been reported to be unnecessary, and also returns the wrong answer (off by exactly 100x), so it is not particularly useful. This also reverts the bugfixes to the original PR: Revert "darwin: fix iOS compilation and functionality" This reverts commit 1addf9b88a17bc32d009d377a14d540ccddd06db. Revert "macos: fix the cfdata length in uv__get_cpu_speed (#3356)" This reverts commit 1e7074913e1d2a1be72b62ba807325c14b0b317a. Revert "darwin: fix -Wsometimes-uninitialized warning" This reverts commit 6085bcef8dea1eaa21a92e2b6e6f03a0476b6c54. Revert "macos: fix memleaks in uv__get_cpu_speed" This reverts commit d2482ae121e0ae5d0cf0934b2e93cee81a4ac5ed. The expected behavior on failure to read this info is to report 0 (for example https://github.com/libuv/libuv/blob/8975c05d199558b0cc2e98f26ce33c6090d1 d7a1/src/unix/linux.c#L834), which is which was not the case before this PR for macos. However hw.cpufrequency sysctl seems to be missing on darwin/arm64 (Apple Silicon), so we instead hardcode a plausible value. This value matches what the mach kernel will report when running Rosetta apps. Fixes: https://github.com/libuv/libuv/issues/3642 Fixes: https://github.com/libuv/libuv/issues/2911 Refs: https://github.com/libuv/libuv/pull/2912 --- src/unix/darwin-stub.h | 16 ----- src/unix/darwin.c | 157 +++-------------------------------------- 2 files changed, 8 insertions(+), 165 deletions(-) diff --git a/src/unix/darwin-stub.h b/src/unix/darwin-stub.h index 433e3efa730..b93cf67c596 100644 --- a/src/unix/darwin-stub.h +++ b/src/unix/darwin-stub.h @@ -27,7 +27,6 @@ struct CFArrayCallBacks; struct CFRunLoopSourceContext; struct FSEventStreamContext; -struct CFRange; typedef double CFAbsoluteTime; typedef double CFTimeInterval; @@ -43,23 +42,13 @@ typedef unsigned CFStringEncoding; typedef void* CFAllocatorRef; typedef void* CFArrayRef; typedef void* CFBundleRef; -typedef void* CFDataRef; typedef void* CFDictionaryRef; -typedef void* CFMutableDictionaryRef; -typedef struct CFRange CFRange; typedef void* CFRunLoopRef; typedef void* CFRunLoopSourceRef; typedef void* CFStringRef; typedef void* CFTypeRef; typedef void* FSEventStreamRef; -typedef uint32_t IOOptionBits; -typedef unsigned int io_iterator_t; -typedef unsigned int io_object_t; -typedef unsigned int io_service_t; -typedef unsigned int io_registry_entry_t; - - typedef void (*FSEventStreamCallback)(const FSEventStreamRef, void*, size_t, @@ -80,11 +69,6 @@ struct FSEventStreamContext { void* pad[3]; }; -struct CFRange { - CFIndex location; - CFIndex length; -}; - static const CFStringEncoding kCFStringEncodingUTF8 = 0x8000100; static const OSStatus noErr = 0; diff --git a/src/unix/darwin.c b/src/unix/darwin.c index 62f04d31542..7d2cacb60da 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -33,13 +33,10 @@ #include #include /* sysconf */ -#include "darwin-stub.h" - static uv_once_t once = UV_ONCE_INIT; static uint64_t (*time_func)(void); static mach_timebase_info_data_t timebase; -typedef unsigned char UInt8; int uv__platform_loop_init(uv_loop_t* loop) { loop->cf_state = NULL; @@ -183,159 +180,17 @@ int uv_uptime(double* uptime) { return 0; } -static int uv__get_cpu_speed(uint64_t* speed) { - /* IOKit */ - void (*pIOObjectRelease)(io_object_t); - kern_return_t (*pIOMasterPort)(mach_port_t, mach_port_t*); - CFMutableDictionaryRef (*pIOServiceMatching)(const char*); - kern_return_t (*pIOServiceGetMatchingServices)(mach_port_t, - CFMutableDictionaryRef, - io_iterator_t*); - io_service_t (*pIOIteratorNext)(io_iterator_t); - CFTypeRef (*pIORegistryEntryCreateCFProperty)(io_registry_entry_t, - CFStringRef, - CFAllocatorRef, - IOOptionBits); - - /* CoreFoundation */ - CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, - const char*, - CFStringEncoding); - CFStringEncoding (*pCFStringGetSystemEncoding)(void); - UInt8 *(*pCFDataGetBytePtr)(CFDataRef); - CFIndex (*pCFDataGetLength)(CFDataRef); - void (*pCFDataGetBytes)(CFDataRef, CFRange, UInt8*); - void (*pCFRelease)(CFTypeRef); - - void* core_foundation_handle; - void* iokit_handle; - int err; - - kern_return_t kr; - mach_port_t mach_port; - io_iterator_t it; - io_object_t service; - - mach_port = 0; - - err = UV_ENOENT; - core_foundation_handle = dlopen("/System/Library/Frameworks/" - "CoreFoundation.framework/" - "CoreFoundation", - RTLD_LAZY | RTLD_LOCAL); - iokit_handle = dlopen("/System/Library/Frameworks/IOKit.framework/" - "IOKit", - RTLD_LAZY | RTLD_LOCAL); - - if (core_foundation_handle == NULL || iokit_handle == NULL) - goto out; - -#define V(handle, symbol) \ - do { \ - *(void **)(&p ## symbol) = dlsym((handle), #symbol); \ - if (p ## symbol == NULL) \ - goto out; \ - } \ - while (0) - V(iokit_handle, IOMasterPort); - V(iokit_handle, IOServiceMatching); - V(iokit_handle, IOServiceGetMatchingServices); - V(iokit_handle, IOIteratorNext); - V(iokit_handle, IOObjectRelease); - V(iokit_handle, IORegistryEntryCreateCFProperty); - V(core_foundation_handle, CFStringCreateWithCString); - V(core_foundation_handle, CFStringGetSystemEncoding); - V(core_foundation_handle, CFDataGetBytePtr); - V(core_foundation_handle, CFDataGetLength); - V(core_foundation_handle, CFDataGetBytes); - V(core_foundation_handle, CFRelease); -#undef V - -#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8) - - kr = pIOMasterPort(MACH_PORT_NULL, &mach_port); - assert(kr == KERN_SUCCESS); - CFMutableDictionaryRef classes_to_match - = pIOServiceMatching("IOPlatformDevice"); - kr = pIOServiceGetMatchingServices(mach_port, classes_to_match, &it); - assert(kr == KERN_SUCCESS); - service = pIOIteratorNext(it); - - CFStringRef device_type_str = S("device_type"); - CFStringRef clock_frequency_str = S("clock-frequency"); - - while (service != 0) { - CFDataRef data; - data = pIORegistryEntryCreateCFProperty(service, - device_type_str, - NULL, - 0); - if (data) { - const UInt8* raw = pCFDataGetBytePtr(data); - if (strncmp((char*)raw, "cpu", 3) == 0 || - strncmp((char*)raw, "processor", 9) == 0) { - CFDataRef freq_ref; - freq_ref = pIORegistryEntryCreateCFProperty(service, - clock_frequency_str, - NULL, - 0); - if (freq_ref) { - const UInt8* freq_ref_ptr = pCFDataGetBytePtr(freq_ref); - CFIndex len = pCFDataGetLength(freq_ref); - if (len == 8) - memcpy(speed, freq_ref_ptr, 8); - else if (len == 4) { - uint32_t v; - memcpy(&v, freq_ref_ptr, 4); - *speed = v; - } else { - *speed = 0; - } - - pCFRelease(freq_ref); - pCFRelease(data); - break; - } - } - pCFRelease(data); - } - - service = pIOIteratorNext(it); - } - - pIOObjectRelease(it); - - err = 0; - - if (device_type_str != NULL) - pCFRelease(device_type_str); - if (clock_frequency_str != NULL) - pCFRelease(clock_frequency_str); - -out: - if (core_foundation_handle != NULL) - dlclose(core_foundation_handle); - - if (iokit_handle != NULL) - dlclose(iokit_handle); - - mach_port_deallocate(mach_task_self(), mach_port); - - return err; -} - int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK), multiplier = ((uint64_t)1000L / ticks); char model[512]; + uint64_t cpuspeed; size_t size; unsigned int i; natural_t numcpus; mach_msg_type_number_t msg_type; processor_cpu_load_info_data_t *info; uv_cpu_info_t* cpu_info; - uint64_t cpuspeed; - int err; size = sizeof(model); if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) && @@ -343,9 +198,13 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { return UV__ERR(errno); } - err = uv__get_cpu_speed(&cpuspeed); - if (err < 0) - return err; + cpuspeed = 0; + size = sizeof(cpuspeed); + sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0); + if (cpuspeed == 0) + /* If sysctl hw.cputype == CPU_TYPE_ARM64, the correct value is unavailable + * from Apple, but we can hard-code it here to a plausible value. */ + cpuspeed = 2400000000; if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus, (processor_info_array_t*)&info, From 96637d032f8f861a24026f49a460047a62d3550f Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 9 Nov 2022 15:54:52 +0100 Subject: [PATCH 265/713] win,test: change format of TEST_PIPENAME's So `WaitNamedPipe()` doesn't fail. Increase the number of clients in `pipe_connect_multiple` so `CreateFile()` returns `ERROR_PIPE_BUSY` and the codepath leading to `WaitNamedPipe()` is exercised. --- test/task.h | 6 +++--- test/test-pipe-connect-multiple.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/task.h b/test/task.h index 91ccb59a470..4ee81662be0 100644 --- a/test/task.h +++ b/test/task.h @@ -50,9 +50,9 @@ #define TEST_PORT_3 9125 #ifdef _WIN32 -# define TEST_PIPENAME "\\\\?\\pipe\\uv-test" -# define TEST_PIPENAME_2 "\\\\?\\pipe\\uv-test2" -# define TEST_PIPENAME_3 "\\\\?\\pipe\\uv-test3" +# define TEST_PIPENAME "\\\\.\\pipe\\uv-test" +# define TEST_PIPENAME_2 "\\\\.\\pipe\\uv-test2" +# define TEST_PIPENAME_3 "\\\\.\\pipe\\uv-test3" #else # define TEST_PIPENAME "/tmp/uv-test-sock" # define TEST_PIPENAME_2 "/tmp/uv-test-sock2" diff --git a/test/test-pipe-connect-multiple.c b/test/test-pipe-connect-multiple.c index 0a60d4a9642..c75eae6cca0 100644 --- a/test/test-pipe-connect-multiple.c +++ b/test/test-pipe-connect-multiple.c @@ -29,7 +29,7 @@ static int connection_cb_called = 0; static int connect_cb_called = 0; -#define NUM_CLIENTS 4 +#define NUM_CLIENTS 10 typedef struct { uv_pipe_t pipe_handle; From 3706c4f85505714b217591f2eefae5afe8d87946 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 9 Nov 2022 16:02:02 +0100 Subject: [PATCH 266/713] win,pipe: fixes in uv_pipe_connect() Make unices and windows consistent when closing a pipe while it's connecting so they all return `UV_ECANCELED`. Avoid race condition between `pipe_connect_thread_proc()` and `uv_close()` when accessing `handle->name`. Fixes: https://github.com/libuv/libuv/issues/3578 --- include/uv/win.h | 1 + src/win/pipe.c | 21 +++++++-- test/test-list.h | 2 + test/test-pipe-connect-multiple.c | 71 +++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 3 deletions(-) diff --git a/include/uv/win.h b/include/uv/win.h index d2f69ccff14..5d08d637f03 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -377,6 +377,7 @@ typedef struct { ULONG_PTR result; /* overlapped.Internal is reused to hold the result */\ HANDLE pipeHandle; \ DWORD duplex_flags; \ + WCHAR* name; \ } connect; \ } u; \ struct uv_req_s* next_req; diff --git a/src/win/pipe.c b/src/win/pipe.c index b9fa986e368..787ba105c93 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -792,15 +792,17 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait * up to 30 seconds for the pipe to become available with WaitNamedPipe. */ - while (WaitNamedPipeW(handle->name, 30000)) { + while (WaitNamedPipeW(req->u.connect.name, 30000)) { /* The pipe is now available, try to connect. */ - pipeHandle = open_named_pipe(handle->name, &duplex_flags); + pipeHandle = open_named_pipe(req->u.connect.name, &duplex_flags); if (pipeHandle != INVALID_HANDLE_VALUE) break; SwitchToThread(); } + uv__free(req->u.connect.name); + req->u.connect.name = NULL; if (pipeHandle != INVALID_HANDLE_VALUE) { SET_REQ_SUCCESS(req); req->u.connect.pipeHandle = pipeHandle; @@ -828,6 +830,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, req->cb = cb; req->u.connect.pipeHandle = INVALID_HANDLE_VALUE; req->u.connect.duplex_flags = 0; + req->u.connect.name = NULL; if (handle->flags & UV_HANDLE_PIPESERVER) { err = ERROR_INVALID_PARAMETER; @@ -859,10 +862,19 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, pipeHandle = open_named_pipe(handle->name, &duplex_flags); if (pipeHandle == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_PIPE_BUSY) { + req->u.connect.name = uv__malloc(nameSize); + if (!req->u.connect.name) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + + memcpy(req->u.connect.name, handle->name, nameSize); + /* Wait for the server to make a pipe instance available. */ if (!QueueUserWorkItem(&pipe_connect_thread_proc, req, WT_EXECUTELONGFUNCTION)) { + uv__free(req->u.connect.name); + req->u.connect.name = NULL; err = GetLastError(); goto error; } @@ -2131,7 +2143,10 @@ void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, if (REQ_SUCCESS(req)) { pipeHandle = req->u.connect.pipeHandle; duplex_flags = req->u.connect.duplex_flags; - err = uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags); + if (handle->flags & UV_HANDLE_CLOSING) + err = UV_ECANCELED; + else + err = uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags); if (err) CloseHandle(pipeHandle); } else { diff --git a/test/test-list.h b/test/test-list.h index 5a6d09fc02e..ca24ba5eba6 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -194,6 +194,7 @@ TEST_DECLARE (udp_try_send) TEST_DECLARE (pipe_bind_error_addrinuse) TEST_DECLARE (pipe_bind_error_addrnotavail) TEST_DECLARE (pipe_bind_error_inval) +TEST_DECLARE (pipe_connect_close_multiple) TEST_DECLARE (pipe_connect_multiple) TEST_DECLARE (pipe_listen_without_bind) TEST_DECLARE (pipe_bind_or_listen_error_after_close) @@ -784,6 +785,7 @@ TASK_LIST_START TEST_ENTRY (pipe_bind_error_addrinuse) TEST_ENTRY (pipe_bind_error_addrnotavail) TEST_ENTRY (pipe_bind_error_inval) + TEST_ENTRY (pipe_connect_close_multiple) TEST_ENTRY (pipe_connect_multiple) TEST_ENTRY (pipe_listen_without_bind) TEST_ENTRY (pipe_bind_or_listen_error_after_close) diff --git a/test/test-pipe-connect-multiple.c b/test/test-pipe-connect-multiple.c index c75eae6cca0..977ce488f14 100644 --- a/test/test-pipe-connect-multiple.c +++ b/test/test-pipe-connect-multiple.c @@ -105,3 +105,74 @@ TEST_IMPL(pipe_connect_multiple) { MAKE_VALGRIND_HAPPY(); return 0; } + + +static void connection_cb2(uv_stream_t* server, int status) { + int r; + uv_pipe_t* conn; + ASSERT_EQ(status, 0); + + conn = &connections[connection_cb_called]; + r = uv_pipe_init(server->loop, conn, 0); + ASSERT_EQ(r, 0); + + r = uv_accept(server, (uv_stream_t*)conn); + ASSERT_EQ(r, 0); + + uv_close((uv_handle_t*)conn, NULL); + if (++connection_cb_called == NUM_CLIENTS && + connect_cb_called == NUM_CLIENTS) { + uv_close((uv_handle_t*)&server_handle, NULL); + } +} + +static void connect_cb2(uv_connect_t* connect_req, int status) { + ASSERT_EQ(status, UV_ECANCELED); + if (++connect_cb_called == NUM_CLIENTS && + connection_cb_called == NUM_CLIENTS) { + uv_close((uv_handle_t*)&server_handle, NULL); + } +} + + +TEST_IMPL(pipe_connect_close_multiple) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif + int i; + int r; + uv_loop_t* loop; + + loop = uv_default_loop(); + + r = uv_pipe_init(loop, &server_handle, 0); + ASSERT_EQ(r, 0); + + r = uv_pipe_bind(&server_handle, TEST_PIPENAME); + ASSERT_EQ(r, 0); + + r = uv_listen((uv_stream_t*)&server_handle, 128, connection_cb2); + ASSERT_EQ(r, 0); + + for (i = 0; i < NUM_CLIENTS; i++) { + r = uv_pipe_init(loop, &clients[i].pipe_handle, 0); + ASSERT_EQ(r, 0); + uv_pipe_connect(&clients[i].conn_req, + &clients[i].pipe_handle, + TEST_PIPENAME, + connect_cb2); + } + + for (i = 0; i < NUM_CLIENTS; i++) { + uv_close((uv_handle_t*)&clients[i].pipe_handle, NULL); + } + + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT_EQ(connection_cb_called, NUM_CLIENTS); + ASSERT_EQ(connect_cb_called, NUM_CLIENTS); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From 6f6965429424f8c34bda9d60e72351eb825b3488 Mon Sep 17 00:00:00 2001 From: theanarkh Date: Fri, 11 Nov 2022 17:56:06 +0800 Subject: [PATCH 267/713] misc: fix return value of memory functions (#3818) Specifically uv_get_free_memory and uv_get_total_memory. --- src/unix/darwin.c | 4 ++-- src/unix/freebsd.c | 4 ++-- src/unix/netbsd.c | 4 ++-- src/unix/openbsd.c | 4 ++-- src/win/util.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/unix/darwin.c b/src/unix/darwin.c index 7d2cacb60da..1216770d86e 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -107,7 +107,7 @@ uint64_t uv_get_free_memory(void) { if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&info, &count) != KERN_SUCCESS) { - return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */ + return 0; } return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE); @@ -120,7 +120,7 @@ uint64_t uv_get_total_memory(void) { size_t size = sizeof(info); if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) - return UV__ERR(errno); + return 0; return (uint64_t) info; } diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index 658ff262d37..33a49878c91 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -91,7 +91,7 @@ uint64_t uv_get_free_memory(void) { size_t size = sizeof(freecount); if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0)) - return UV__ERR(errno); + return 0; return (uint64_t) freecount * sysconf(_SC_PAGESIZE); @@ -105,7 +105,7 @@ uint64_t uv_get_total_memory(void) { size_t size = sizeof(info); if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) - return UV__ERR(errno); + return 0; return (uint64_t) info; } diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index c66333f522c..a19f5a01ad4 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -103,7 +103,7 @@ uint64_t uv_get_free_memory(void) { int which[] = {CTL_VM, VM_UVMEXP}; if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) - return UV__ERR(errno); + return 0; return (uint64_t) info.free * sysconf(_SC_PAGESIZE); } @@ -120,7 +120,7 @@ uint64_t uv_get_total_memory(void) { size_t size = sizeof(info); if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) - return UV__ERR(errno); + return 0; return (uint64_t) info; } diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index f32a94df387..3674052f200 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -116,7 +116,7 @@ uint64_t uv_get_free_memory(void) { int which[] = {CTL_VM, VM_UVMEXP}; if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) - return UV__ERR(errno); + return 0; return (uint64_t) info.free * sysconf(_SC_PAGESIZE); } @@ -128,7 +128,7 @@ uint64_t uv_get_total_memory(void) { size_t size = sizeof(info); if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0)) - return UV__ERR(errno); + return 0; return (uint64_t) info; } diff --git a/src/win/util.c b/src/win/util.c index 79ab61b7c69..23dd4136894 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -338,7 +338,7 @@ uint64_t uv_get_free_memory(void) { memory_status.dwLength = sizeof(memory_status); if (!GlobalMemoryStatusEx(&memory_status)) { - return -1; + return 0; } return (uint64_t)memory_status.ullAvailPhys; @@ -350,7 +350,7 @@ uint64_t uv_get_total_memory(void) { memory_status.dwLength = sizeof(memory_status); if (!GlobalMemoryStatusEx(&memory_status)) { - return -1; + return 0; } return (uint64_t)memory_status.ullTotalPhys; From e14158605336d2852dc5489204d2eb7fbe38a97d Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Fri, 11 Nov 2022 08:21:58 -0700 Subject: [PATCH 268/713] src: add new metrics APIs (#3749) The following metrics are now always recorded and available via the new uv_metrics_info() API. * loop_count: Number of event loop iterations. * events: Total number of events processed by the event handler. * events_waiting: Total number of events waiting in the event queue when the event provider request was made. Benchmarking has shown no noticeable impact recording these metrics. PR-URL: https://github.com/libuv/libuv/pull/3749 --- docs/src/metrics.rst | 48 +++++++++++++++++++- include/uv.h | 11 +++++ src/unix/aix.c | 2 + src/unix/core.c | 2 + src/unix/kqueue.c | 2 + src/unix/linux.c | 2 + src/unix/loop.c | 3 ++ src/unix/os390.c | 2 + src/unix/posix-poll.c | 2 + src/unix/sunos.c | 2 + src/uv-common.c | 9 ++++ src/uv-common.h | 16 +++++++ src/win/core.c | 22 +++++++-- test/test-list.h | 2 + test/test-metrics.c | 103 ++++++++++++++++++++++++++++++++++++++++++ 15 files changed, 223 insertions(+), 5 deletions(-) diff --git a/docs/src/metrics.rst b/docs/src/metrics.rst index 696c620d192..0141d03286b 100644 --- a/docs/src/metrics.rst +++ b/docs/src/metrics.rst @@ -4,8 +4,46 @@ Metrics operations ====================== -libuv provides a metrics API to track the amount of time the event loop has -spent idle in the kernel's event provider. +libuv provides a metrics API to track various internal operations of the event +loop. + + +Data types +---------- + +.. c:type:: uv_metrics_t + + The struct that contains event loop metrics. It is recommended to retrieve + these metrics in a :c:type:`uv_prepare_cb` in order to make sure there are + no inconsistencies with the metrics counters. + + :: + + typedef struct { + uint64_t loop_count; + uint64_t events; + uint64_t events_waiting; + /* private */ + uint64_t* reserved[13]; + } uv_metrics_t; + + +Public members +^^^^^^^^^^^^^^ + +.. c:member:: uint64_t uv_metrics_t.loop_count + + Number of event loop iterations. + +.. c:member:: uint64_t uv_metrics_t.events + + Number of events that have been processed by the event handler. + +.. c:member:: uint64_t uv_metrics_t.events_waiting + + Number of events that were waiting to be processed when the event provider + was called. + API --- @@ -25,3 +63,9 @@ API :c:type:`UV_METRICS_IDLE_TIME`. .. versionadded:: 1.39.0 + +.. c:function:: int uv_metrics_info(uv_loop_t* loop, uv_metrics_t* metrics) + + Copy the current set of event loop metrics to the ``metrics`` pointer. + + .. versionadded:: 1.45.0 diff --git a/include/uv.h b/include/uv.h index d788bc1782d..68128db1ad9 100644 --- a/include/uv.h +++ b/include/uv.h @@ -246,6 +246,8 @@ typedef struct uv_passwd_s uv_passwd_t; typedef struct uv_utsname_s uv_utsname_t; typedef struct uv_statfs_s uv_statfs_t; +typedef struct uv_metrics_s uv_metrics_t; + typedef enum { UV_LOOP_BLOCK_SIGNAL = 0, UV_METRICS_IDLE_TIME @@ -1274,6 +1276,15 @@ UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size); UV_EXTERN int uv_os_uname(uv_utsname_t* buffer); +struct uv_metrics_s { + uint64_t loop_count; + uint64_t events; + uint64_t events_waiting; + /* private */ + uint64_t* reserved[13]; +}; + +UV_EXTERN int uv_metrics_info(uv_loop_t* loop, uv_metrics_t* metrics); UV_EXTERN uint64_t uv_metrics_idle_time(uv_loop_t* loop); typedef enum { diff --git a/src/unix/aix.c b/src/unix/aix.c index f413f108c54..656869f7acf 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -321,9 +321,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { nevents++; } + uv__metrics_inc_events(loop, nevents); if (reset_timeout != 0) { timeout = user_timeout; reset_timeout = 0; + uv__metrics_inc_events_waiting(loop, nevents); } if (have_signals != 0) { diff --git a/src/unix/core.c b/src/unix/core.c index fc8559ba614..b77be274f40 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -405,6 +405,8 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT) timeout = uv__backend_timeout(loop); + uv__metrics_inc_loop_count(loop); + uv__io_poll(loop, timeout); /* Process immediate callbacks (e.g. write_cb) a small fixed number of diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 9e34a684efa..abb147851f1 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -386,9 +386,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { uv__wait_children(loop); } + uv__metrics_inc_events(loop, nevents); if (reset_timeout != 0) { timeout = user_timeout; reset_timeout = 0; + uv__metrics_inc_events_waiting(loop, nevents); } if (have_signals != 0) { diff --git a/src/unix/linux.c b/src/unix/linux.c index 13e7661f7cd..d2db848b3a8 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -610,9 +610,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } } + uv__metrics_inc_events(loop, nevents); if (reset_timeout != 0) { timeout = user_timeout; reset_timeout = 0; + uv__metrics_inc_events_waiting(loop, nevents); } if (have_signals != 0) { diff --git a/src/unix/loop.c b/src/unix/loop.c index a88e71c3393..816ac179c65 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -45,6 +45,9 @@ int uv_loop_init(uv_loop_t* loop) { err = uv_mutex_init(&lfields->loop_metrics.lock); if (err) goto fail_metrics_mutex_init; + memset(&lfields->loop_metrics.metrics, + 0, + sizeof(lfields->loop_metrics.metrics)); heap_init((struct heap*) &loop->timer_heap); QUEUE_INIT(&loop->wq); diff --git a/src/unix/os390.c b/src/unix/os390.c index 3b16318ce28..315b8cd9949 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -998,9 +998,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } } + uv__metrics_inc_events(loop, nevents); if (reset_timeout != 0) { timeout = user_timeout; reset_timeout = 0; + uv__metrics_inc_events_waiting(loop, nevents); } if (have_signals != 0) { diff --git a/src/unix/posix-poll.c b/src/unix/posix-poll.c index 0f4bf93874b..711780ece8d 100644 --- a/src/unix/posix-poll.c +++ b/src/unix/posix-poll.c @@ -292,9 +292,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } } + uv__metrics_inc_events(loop, nevents); if (reset_timeout != 0) { timeout = user_timeout; reset_timeout = 0; + uv__metrics_inc_events_waiting(loop, nevents); } if (have_signals != 0) { diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 7835bed75e0..afbc3532e35 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -320,9 +320,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); } + uv__metrics_inc_events(loop, nevents); if (reset_timeout != 0) { timeout = user_timeout; reset_timeout = 0; + uv__metrics_inc_events_waiting(loop, nevents); } if (have_signals != 0) { diff --git a/src/uv-common.c b/src/uv-common.c index 6bb574738c0..df8b8b714d4 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -963,6 +963,15 @@ void uv__metrics_set_provider_entry_time(uv_loop_t* loop) { } +int uv_metrics_info(uv_loop_t* loop, uv_metrics_t* metrics) { + memcpy(metrics, + &uv__get_loop_metrics(loop)->metrics, + sizeof(*metrics)); + + return 0; +} + + uint64_t uv_metrics_idle_time(uv_loop_t* loop) { uv__loop_metrics_t* loop_metrics; uint64_t entry_time; diff --git a/src/uv-common.h b/src/uv-common.h index bbfaaf708aa..3b0370c7d29 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -349,6 +349,21 @@ void uv__threadpool_cleanup(void); #define uv__get_loop_metrics(loop) \ (&uv__get_internal_fields(loop)->loop_metrics) +#define uv__metrics_inc_loop_count(loop) \ + do { \ + uv__get_loop_metrics(loop)->metrics.loop_count++; \ + } while (0) + +#define uv__metrics_inc_events(loop, e) \ + do { \ + uv__get_loop_metrics(loop)->metrics.events += (e); \ + } while (0) + +#define uv__metrics_inc_events_waiting(loop, e) \ + do { \ + uv__get_loop_metrics(loop)->metrics.events_waiting += (e); \ + } while (0) + /* Allocator prototypes */ void *uv__calloc(size_t count, size_t size); char *uv__strdup(const char* s); @@ -362,6 +377,7 @@ typedef struct uv__loop_metrics_s uv__loop_metrics_t; typedef struct uv__loop_internal_fields_s uv__loop_internal_fields_t; struct uv__loop_metrics_s { + uv_metrics_t metrics; uint64_t provider_entry_time; uint64_t provider_idle_time; uv_mutex_t lock; diff --git a/src/win/core.c b/src/win/core.c index 8d4bbefddb9..09a3c7b1865 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -245,6 +245,9 @@ int uv_loop_init(uv_loop_t* loop) { err = uv_mutex_init(&lfields->loop_metrics.lock); if (err) goto fail_metrics_mutex_init; + memset(&lfields->loop_metrics.metrics, + 0, + sizeof(lfields->loop_metrics.metrics)); /* To prevent uninitialized memory access, loop->time must be initialized * to zero before calling uv_update_time for the first time. @@ -454,6 +457,8 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { timeout); if (reset_timeout != 0) { + if (overlapped && timeout == 0) + uv__metrics_inc_events_waiting(loop, 1); timeout = user_timeout; reset_timeout = 0; } @@ -466,6 +471,8 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { 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); @@ -508,6 +515,7 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { int repeat; uint64_t timeout_time; uint64_t user_timeout; + uint64_t actual_timeout; int reset_timeout; timeout_time = loop->time + timeout; @@ -521,6 +529,8 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { } for (repeat = 0; ; repeat++) { + actual_timeout = timeout; + /* 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. */ @@ -540,9 +550,9 @@ 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 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. + * empty package or not, or if pGetQueuedCompletionStatusEx 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); @@ -552,6 +562,10 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { * meant only to wake us up. */ if (overlappeds[i].lpOverlapped) { + uv__metrics_inc_events(loop, 1); + if (actual_timeout == 0) + uv__metrics_inc_events_waiting(loop, 1); + req = uv__overlapped_to_req(overlappeds[i].lpOverlapped); uv__insert_pending_req(loop, req); } @@ -609,6 +623,8 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT) timeout = uv_backend_timeout(loop); + uv__metrics_inc_loop_count(loop); + if (pGetQueuedCompletionStatusEx) uv__poll(loop, timeout); else diff --git a/test/test-list.h b/test/test-list.h index ca24ba5eba6..45261be28a8 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -547,6 +547,7 @@ TEST_DECLARE (utf8_decode1) TEST_DECLARE (utf8_decode1_overrun) TEST_DECLARE (uname) +TEST_DECLARE (metrics_info_check) TEST_DECLARE (metrics_idle_time) TEST_DECLARE (metrics_idle_time_thread) TEST_DECLARE (metrics_idle_time_zero) @@ -1174,6 +1175,7 @@ TASK_LIST_START TEST_ENTRY (readable_on_eof) TEST_HELPER (readable_on_eof, tcp4_echo_server) + TEST_ENTRY (metrics_info_check) TEST_ENTRY (metrics_idle_time) TEST_ENTRY (metrics_idle_time_thread) TEST_ENTRY (metrics_idle_time_zero) diff --git a/test/test-metrics.c b/test/test-metrics.c index f527494470e..bfc09251028 100644 --- a/test/test-metrics.c +++ b/test/test-metrics.c @@ -25,6 +25,16 @@ #define UV_NS_TO_MS 1000000 +typedef struct { + uv_fs_t open_req; + uv_fs_t write_req; + uv_fs_t close_req; +} fs_reqs_t; + +static uint64_t last_events_count; +static char test_buf[] = "test-buffer\n"; +static fs_reqs_t fs_reqs; + static void timer_spin_cb(uv_timer_t* handle) { uint64_t t; @@ -116,6 +126,7 @@ static void timer_noop_cb(uv_timer_t* handle) { TEST_IMPL(metrics_idle_time_zero) { + uv_metrics_t metrics; uv_timer_t timer; int cntr; @@ -130,6 +141,98 @@ TEST_IMPL(metrics_idle_time_zero) { ASSERT_GT(cntr, 0); ASSERT_EQ(0, uv_metrics_idle_time(uv_default_loop())); + ASSERT_EQ(0, uv_metrics_info(uv_default_loop(), &metrics)); + ASSERT_UINT64_EQ(cntr, metrics.loop_count); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static void close_cb(uv_fs_t* req) { + uv_metrics_t metrics; + + ASSERT_EQ(0, uv_metrics_info(uv_default_loop(), &metrics)); + ASSERT_UINT64_EQ(3, metrics.loop_count); + ASSERT_UINT64_GT(metrics.events, last_events_count); + + uv_fs_req_cleanup(req); + last_events_count = metrics.events; +} + + +static void write_cb(uv_fs_t* req) { + uv_metrics_t metrics; + + ASSERT_EQ(0, uv_metrics_info(uv_default_loop(), &metrics)); + ASSERT_UINT64_EQ(2, metrics.loop_count); + ASSERT_UINT64_GT(metrics.events, last_events_count); + ASSERT_EQ(req->result, sizeof(test_buf)); + + uv_fs_req_cleanup(req); + last_events_count = metrics.events; + + ASSERT_EQ(0, uv_fs_close(uv_default_loop(), + &fs_reqs.close_req, + fs_reqs.open_req.result, + close_cb)); +} + + +static void create_cb(uv_fs_t* req) { + uv_metrics_t metrics; + + ASSERT_EQ(0, uv_metrics_info(uv_default_loop(), &metrics)); + /* Event count here is still 0 so not going to check. */ + ASSERT_UINT64_EQ(1, metrics.loop_count); + ASSERT_GE(req->result, 0); + + uv_fs_req_cleanup(req); + last_events_count = metrics.events; + + uv_buf_t iov = uv_buf_init(test_buf, sizeof(test_buf)); + ASSERT_EQ(0, uv_fs_write(uv_default_loop(), + &fs_reqs.write_req, + req->result, + &iov, + 1, + 0, + write_cb)); +} + + +static void prepare_cb(uv_prepare_t* handle) { + uv_metrics_t metrics; + + uv_prepare_stop(handle); + + ASSERT_EQ(0, uv_metrics_info(uv_default_loop(), &metrics)); + ASSERT_UINT64_EQ(0, metrics.loop_count); + ASSERT_UINT64_EQ(0, metrics.events); + + ASSERT_EQ(0, uv_fs_open(uv_default_loop(), + &fs_reqs.open_req, + "test_file", + O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR, + create_cb)); +} + + +TEST_IMPL(metrics_info_check) { + uv_fs_t unlink_req; + uv_prepare_t prepare; + + uv_fs_unlink(NULL, &unlink_req, "test_file", NULL); + uv_fs_req_cleanup(&unlink_req); + + ASSERT_EQ(0, uv_prepare_init(uv_default_loop(), &prepare)); + ASSERT_EQ(0, uv_prepare_start(&prepare, prepare_cb)); + + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + uv_fs_unlink(NULL, &unlink_req, "test_file", NULL); + uv_fs_req_cleanup(&unlink_req); + MAKE_VALGRIND_HAPPY(); return 0; } From 64669fdd8de8fce478e6ce1f7c954905f682c75b Mon Sep 17 00:00:00 2001 From: daomingq Date: Wed, 16 Nov 2022 01:01:29 +0800 Subject: [PATCH 269/713] thread: add uv_thread_getcpu() (#3803) Add uv_thread_getcpu() api to get the cpu number on which the calling thread is running. --- docs/src/threading.rst | 9 +++++++++ include/uv.h | 1 + src/unix/thread.c | 13 +++++++++++++ src/win/thread.c | 3 +++ test/test-thread-affinity.c | 20 ++++++++++++++++++++ 5 files changed, 46 insertions(+) diff --git a/docs/src/threading.rst b/docs/src/threading.rst index ca9fb0cea5d..d379677a211 100644 --- a/docs/src/threading.rst +++ b/docs/src/threading.rst @@ -119,6 +119,15 @@ Threads .. versionadded:: 1.45.0 +.. c:function:: int uv_thread_getcpu(void) + + Gets the CPU number on which the calling thread is running. + + .. note:: + Currently only implemented on Windows, Linux and FreeBSD. + + .. versionadded:: 1.45.0 + .. c:function:: uv_thread_t uv_thread_self(void) .. 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) diff --git a/include/uv.h b/include/uv.h index 68128db1ad9..30e09c618e6 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1802,6 +1802,7 @@ UV_EXTERN int uv_thread_setaffinity(uv_thread_t* tid, UV_EXTERN int uv_thread_getaffinity(uv_thread_t* tid, char* cpumask, size_t mask_size); +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); diff --git a/src/unix/thread.c b/src/unix/thread.c index 77159511b19..f75fe82aa20 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -382,6 +382,19 @@ int uv_thread_getaffinity(uv_thread_t* tid, } #endif /* defined(__linux__) || defined(UV_BSD_H) */ +int uv_thread_getcpu(void) { +#if defined(__linux__) || defined(__FreeBSD__) + int cpu; + + cpu = sched_getcpu(); + if (cpu < 0) + return UV__ERR(errno); + + return cpu; +#else + return UV_ENOTSUP; +#endif +} uv_thread_t uv_thread_self(void) { return pthread_self(); diff --git a/src/win/thread.c b/src/win/thread.c index da150e45369..5e86999c28d 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -252,6 +252,9 @@ int uv_thread_getaffinity(uv_thread_t* tid, return 0; } +int uv_thread_getcpu(void) { + return GetCurrentProcessorNumber(); +} uv_thread_t uv_thread_self(void) { uv_thread_t key; diff --git a/test/test-thread-affinity.c b/test/test-thread-affinity.c index 43783bc4b3f..2c9b696ec7a 100644 --- a/test/test-thread-affinity.c +++ b/test/test-thread-affinity.c @@ -34,6 +34,8 @@ TEST_IMPL(thread_affinity) { char* cpumask; int ncpus; int r; + int c; + int i; uv_thread_t threads[3]; #ifdef _WIN32 @@ -99,6 +101,24 @@ TEST_IMPL(thread_affinity) { ASSERT(cpumask[t2first + 2] == (ncpus >= 3)); ASSERT(cpumask[t2first + 3] == 0); + c = uv_thread_getcpu(); + ASSERT_GE(c, 0); + + memset(cpumask, 0, cpumasksize); + cpumask[c] = 1; + r = uv_thread_setaffinity(&threads[0], cpumask, NULL, cpumasksize); + ASSERT_EQ(r, 0); + + memset(cpumask, 0, cpumasksize); + r = uv_thread_getaffinity(&threads[0], cpumask, cpumasksize); + ASSERT_EQ(r, 0); + for (i = 0; i < cpumasksize; i++) { + if (i == c) + ASSERT_EQ(1, cpumask[i]); + else + ASSERT_EQ(0, cpumask[i]); + } + free(cpumask); return 0; From a73725579107e374eb8358a3999d03b822df6c89 Mon Sep 17 00:00:00 2001 From: Edward Humes <29870961+aurxenon@users.noreply.github.com> Date: Tue, 22 Nov 2022 15:46:55 -0500 Subject: [PATCH 270/713] build: don't use ifaddrs.h on solaris 10 (#3826) Disable usage of ifaddrs.h on Solaris 10 at configuration time. --- CMakeLists.txt | 4 ++++ configure.ac | 3 +++ 2 files changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2b4e44c7c7..a8d8d3b3427 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -374,6 +374,10 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OS400") endif() if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") + if(CMAKE_SYSTEM_VERSION STREQUAL "5.10") + list(APPEND uv_defines SUNOS_NO_IFADDRS) + list(APPEND uv_libraries rt) + endif() list(APPEND uv_defines __EXTENSIONS__ _XOPEN_SOURCE=500 _REENTRANT) list(APPEND uv_libraries kstat nsl sendfile socket) list(APPEND uv_sources diff --git a/configure.ac b/configure.ac index 0f272561e71..a380cd9715b 100644 --- a/configure.ac +++ b/configure.ac @@ -76,6 +76,9 @@ AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false]) AS_CASE([$host_os],[mingw*], [ LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32" ]) +AS_CASE([$host_os], [solaris2.10], [ + CFLAGS="$CFLAGS -DSUNOS_NO_IFADDRS" +]) AS_CASE([$host_os], [netbsd*], [AC_CHECK_LIB([kvm], [kvm_open])]) AS_CASE([$host_os], [kfreebsd*], [ LIBS="$LIBS -lfreebsd-glue" From 988d225cf01be202293634cc440f750a7bc53261 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Thu, 24 Nov 2022 22:09:32 +0100 Subject: [PATCH 271/713] unix,win: add uv_get_available_memory() (#3754) --- docs/src/misc.rst | 16 +++- include/uv.h | 1 + src/unix/aix.c | 5 ++ src/unix/cygwin.c | 4 + src/unix/darwin.c | 5 ++ src/unix/freebsd.c | 5 ++ src/unix/haiku.c | 5 ++ src/unix/hurd.c | 5 ++ src/unix/ibmi.c | 5 ++ src/unix/linux.c | 172 +++++++++++++++++++++++++++++++++++------ src/unix/netbsd.c | 5 ++ src/unix/openbsd.c | 5 ++ src/unix/os390.c | 5 ++ src/unix/qnx.c | 5 ++ src/unix/sunos.c | 5 ++ src/win/util.c | 5 ++ test/test-get-memory.c | 13 +++- 17 files changed, 238 insertions(+), 28 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index a18040e2eb5..39241df8cbc 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -561,7 +561,7 @@ API .. c:function:: uint64_t uv_get_constrained_memory(void) - Gets the amount of memory available to the process (in bytes) based on + Gets the total amount of memory available to the process (in bytes) based on limits imposed by the OS. If there is no such constraint, or the constraint is unknown, `0` is returned. Note that it is not unusual for this value to be less than or greater than :c:func:`uv_get_total_memory`. @@ -572,6 +572,20 @@ API .. versionadded:: 1.29.0 +.. c:function:: uint64_t uv_get_available_memory(void) + + Gets the amount of free memory that is still available to the process (in bytes). + This differs from :c:func:`uv_get_free_memory` in that it takes into account any + limits imposed by the OS. If there is no such constraint, or the constraint + is unknown, the amount returned will be identical to :c:func:`uv_get_free_memory`. + + .. note:: + This function currently only returns a value that is different from + what :c:func:`uv_get_free_memory` reports on Linux, based + on cgroups if it is present. + + .. versionadded:: 1.45.0 + .. c:function:: uint64_t uv_hrtime(void) Returns the current high-resolution real time. This is expressed in diff --git a/include/uv.h b/include/uv.h index 30e09c618e6..7189951f3e4 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1718,6 +1718,7 @@ UV_EXTERN int uv_chdir(const char* dir); UV_EXTERN uint64_t uv_get_free_memory(void); UV_EXTERN uint64_t uv_get_total_memory(void); UV_EXTERN uint64_t uv_get_constrained_memory(void); +UV_EXTERN uint64_t uv_get_available_memory(void); UV_EXTERN uint64_t uv_hrtime(void); UV_EXTERN void uv_sleep(unsigned int msec); diff --git a/src/unix/aix.c b/src/unix/aix.c index 656869f7acf..b855282ebc8 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -391,6 +391,11 @@ uint64_t uv_get_constrained_memory(void) { } +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} + + void uv_loadavg(double avg[3]) { perfstat_cpu_total_t ps_total; int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1); diff --git a/src/unix/cygwin.c b/src/unix/cygwin.c index 169958d55f2..4e5413963d6 100644 --- a/src/unix/cygwin.c +++ b/src/unix/cygwin.c @@ -51,3 +51,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { uint64_t uv_get_constrained_memory(void) { return 0; /* Memory constraints are unknown. */ } + +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} diff --git a/src/unix/darwin.c b/src/unix/darwin.c index 1216770d86e..90790d701c4 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -131,6 +131,11 @@ uint64_t uv_get_constrained_memory(void) { } +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} + + void uv_loadavg(double avg[3]) { struct loadavg info; size_t size = sizeof(info); diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index 33a49878c91..b254b9501d8 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -116,6 +116,11 @@ uint64_t uv_get_constrained_memory(void) { } +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} + + void uv_loadavg(double avg[3]) { struct loadavg info; size_t size = sizeof(info); diff --git a/src/unix/haiku.c b/src/unix/haiku.c index cf17d836b4c..31284b66dc3 100644 --- a/src/unix/haiku.c +++ b/src/unix/haiku.c @@ -84,6 +84,11 @@ uint64_t uv_get_constrained_memory(void) { } +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} + + int uv_resident_set_memory(size_t* rss) { area_info area; ssize_t cookie; diff --git a/src/unix/hurd.c b/src/unix/hurd.c index d19ea634790..63c878123f1 100644 --- a/src/unix/hurd.c +++ b/src/unix/hurd.c @@ -165,3 +165,8 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { uint64_t uv_get_constrained_memory(void) { return 0; /* Memory constraints are unknown. */ } + + +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} diff --git a/src/unix/ibmi.c b/src/unix/ibmi.c index 8c6ae636329..837bba6e2fe 100644 --- a/src/unix/ibmi.c +++ b/src/unix/ibmi.c @@ -249,6 +249,11 @@ uint64_t uv_get_constrained_memory(void) { } +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} + + void uv_loadavg(double avg[3]) { SSTS0200 rcvr; diff --git a/src/unix/linux.c b/src/unix/linux.c index d2db848b3a8..18dd5029b8f 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1343,47 +1343,169 @@ static uint64_t uv__read_uint64(const char* filename) { } -/* This might return 0 if there was a problem getting the memory limit from - * cgroups. This is OK because a return value of 0 signifies that the memory - * limit is unknown. - */ -static uint64_t uv__get_constrained_memory_fallback(void) { - return uv__read_uint64("/sys/fs/cgroup/memory/memory.limit_in_bytes"); +/* Given a buffer with the contents of a cgroup1 /proc/self/cgroups, + * finds the location and length of the memory controller mount path. + * This disregards the leading / for easy concatenation of paths. + * Returns NULL if the memory controller wasn't found. */ +static char* uv__cgroup1_find_memory_controller(char buf[static 1024], + int* n) { + char* p; + + /* Seek to the memory controller line. */ + p = strchr(buf, ':'); + while (p != NULL && strncmp(p, ":memory:", 8)) { + p = strchr(p, '\n'); + if (p != NULL) + p = strchr(p, ':'); + } + + if (p != NULL) { + /* Determine the length of the mount path. */ + p = p + strlen(":memory:/"); + *n = (int) strcspn(p, "\n"); + } + + return p; } +static void uv__get_cgroup1_memory_limits(char buf[static 1024], uint64_t* high, + uint64_t* max) { + char filename[4097]; + char* p; + int n; -uint64_t uv_get_constrained_memory(void) { + /* Find out where the controller is mounted. */ + p = uv__cgroup1_find_memory_controller(buf, &n); + if (p != NULL) { + snprintf(filename, sizeof(filename), + "/sys/fs/cgroup/memory/%.*s/memory.soft_limit_in_bytes", n, p); + *high = uv__read_uint64(filename); + + snprintf(filename, sizeof(filename), + "/sys/fs/cgroup/memory/%.*s/memory.limit_in_bytes", n, p); + *max = uv__read_uint64(filename); + + /* If the controller wasn't mounted, the reads above will have failed, + * as indicated by uv__read_uint64 returning 0. + */ + if (*high != 0 && *max != 0) + return; + } + + /* Fall back to the limits of the global memory controller. */ + *high = uv__read_uint64("/sys/fs/cgroup/memory/memory.soft_limit_in_bytes"); + *max = uv__read_uint64("/sys/fs/cgroup/memory/memory.limit_in_bytes"); +} + +static void uv__get_cgroup2_memory_limits(char buf[static 1024], uint64_t* high, + uint64_t* max) { char filename[4097]; - char buf[1024]; + char* p; + int n; + + /* Find out where the controller is mounted. */ + p = buf + strlen("0::/"); + n = (int) strcspn(p, "\n"); + + /* Read the memory limits of the controller. */ + snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%.*s/memory.max", n, p); + *max = uv__read_uint64(filename); + snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%.*s/memory.high", n, p); + *high = uv__read_uint64(filename); +} + +static uint64_t uv__get_cgroup_constrained_memory(char buf[static 1024]) { uint64_t high; uint64_t max; - char* p; + + /* In the case of cgroupv2, we'll only have a single entry. */ + if (strncmp(buf, "0::/", 4)) + uv__get_cgroup1_memory_limits(buf, &high, &max); + else + uv__get_cgroup2_memory_limits(buf, &high, &max); + + if (high == 0 || max == 0) + return 0; + + return high < max ? high : max; +} + +uint64_t uv_get_constrained_memory(void) { + char buf[1024]; if (uv__slurp("/proc/self/cgroup", buf, sizeof(buf))) - return uv__get_constrained_memory_fallback(); + return 0; + + return uv__get_cgroup_constrained_memory(buf); +} + + +static uint64_t uv__get_cgroup1_current_memory(char buf[static 1024]) { + char filename[4097]; + uint64_t current; + char* p; + int n; + + /* Find out where the controller is mounted. */ + p = uv__cgroup1_find_memory_controller(buf, &n); + if (p != NULL) { + snprintf(filename, sizeof(filename), + "/sys/fs/cgroup/memory/%.*s/memory.usage_in_bytes", n, p); + current = uv__read_uint64(filename); + + /* If the controller wasn't mounted, the reads above will have failed, + * as indicated by uv__read_uint64 returning 0. + */ + if (current != 0) + return current; + } + + /* Fall back to the usage of the global memory controller. */ + return uv__read_uint64("/sys/fs/cgroup/memory/memory.usage_in_bytes"); +} + +static uint64_t uv__get_cgroup2_current_memory(char buf[static 1024]) { + char filename[4097]; + char* p; + int n; - if (memcmp(buf, "0::/", 4)) - return uv__get_constrained_memory_fallback(); + /* Find out where the controller is mounted. */ + p = buf + strlen("0::/"); + n = (int) strcspn(p, "\n"); - p = strchr(buf, '\n'); - if (p != NULL) - *p = '\0'; + snprintf(filename, sizeof(filename), + "/sys/fs/cgroup/%.*s/memory.current", n, p); + return uv__read_uint64(filename); +} - p = buf + 4; +uint64_t uv_get_available_memory(void) { + char buf[1024]; + uint64_t constrained; + uint64_t current; + uint64_t total; - snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%s/memory.max", p); - max = uv__read_uint64(filename); + if (uv__slurp("/proc/self/cgroup", buf, sizeof(buf))) + return 0; - if (max == 0) - return uv__get_constrained_memory_fallback(); + constrained = uv__get_cgroup_constrained_memory(buf); + if (constrained == 0) + return uv_get_free_memory(); - snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%s/memory.high", p); - high = uv__read_uint64(filename); + total = uv_get_total_memory(); + if (constrained > total) + return uv_get_free_memory(); - if (high == 0) - return uv__get_constrained_memory_fallback(); + /* In the case of cgroupv2, we'll only have a single entry. */ + if (strncmp(buf, "0::/", 4)) + current = uv__get_cgroup1_current_memory(buf); + else + current = uv__get_cgroup2_current_memory(buf); - return high < max ? high : max; + /* memory usage can be higher than the limit (for short bursts of time) */ + if (constrained < current) + return 0; + + return constrained - current; } diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index a19f5a01ad4..fa21e98e41a 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -131,6 +131,11 @@ uint64_t uv_get_constrained_memory(void) { } +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} + + int uv_resident_set_memory(size_t* rss) { kvm_t *kd = NULL; struct kinfo_proc2 *kinfo = NULL; diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index 3674052f200..9c863b6c90d 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -139,6 +139,11 @@ uint64_t uv_get_constrained_memory(void) { } +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} + + int uv_resident_set_memory(size_t* rss) { struct kinfo_proc kinfo; size_t page_size = getpagesize(); diff --git a/src/unix/os390.c b/src/unix/os390.c index 315b8cd9949..3954b2c2753 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -198,6 +198,11 @@ uint64_t uv_get_constrained_memory(void) { } +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} + + int uv_resident_set_memory(size_t* rss) { char* ascb; char* rax; diff --git a/src/unix/qnx.c b/src/unix/qnx.c index ca148d349f8..57ea9dfd9cc 100644 --- a/src/unix/qnx.c +++ b/src/unix/qnx.c @@ -88,6 +88,11 @@ uint64_t uv_get_constrained_memory(void) { } +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} + + int uv_resident_set_memory(size_t* rss) { int fd; procfs_asinfo asinfo; diff --git a/src/unix/sunos.c b/src/unix/sunos.c index afbc3532e35..75b6fbad493 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -417,6 +417,11 @@ uint64_t uv_get_constrained_memory(void) { } +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} + + void uv_loadavg(double avg[3]) { (void) getloadavg(avg, 3); } diff --git a/src/win/util.c b/src/win/util.c index 23dd4136894..a3bc1b980af 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -362,6 +362,11 @@ uint64_t uv_get_constrained_memory(void) { } +uint64_t uv_get_available_memory(void) { + return uv_get_free_memory(); +} + + uv_pid_t uv_os_getpid(void) { return GetCurrentProcessId(); } diff --git a/test/test-get-memory.c b/test/test-get-memory.c index 4555ba08895..9ac42c383c9 100644 --- a/test/test-get-memory.c +++ b/test/test-get-memory.c @@ -26,11 +26,14 @@ TEST_IMPL(get_memory) { uint64_t free_mem = uv_get_free_memory(); uint64_t total_mem = uv_get_total_memory(); uint64_t constrained_mem = uv_get_constrained_memory(); + uint64_t available_mem = uv_get_available_memory(); - printf("free_mem=%llu, total_mem=%llu, constrained_mem=%llu\n", + printf("free_mem=%llu, total_mem=%llu, constrained_mem=%llu, " + "available_mem=%llu\n", (unsigned long long) free_mem, (unsigned long long) total_mem, - (unsigned long long) constrained_mem); + (unsigned long long) constrained_mem, + (unsigned long long) available_mem); ASSERT(free_mem > 0); ASSERT(total_mem > 0); @@ -40,5 +43,11 @@ TEST_IMPL(get_memory) { #else ASSERT(total_mem > free_mem); #endif + ASSERT_LE(available_mem, total_mem); + /* we'd really want to test if available <= free, but that is fragile: + * with no limit set, get_available calls and returns get_free; so if + * any memory was freed between our calls to get_free and get_available + * we would fail such a test test (as observed on CI). + */ return 0; } From 238ba3b625417405ea6c819ad4831d642c52a653 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 26 Nov 2022 22:30:04 +0100 Subject: [PATCH 272/713] test: fix -Wunused-but-set-variable warnings (#3829) --- test/runner.c | 8 ++------ test/test-env-vars.c | 5 ++++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/test/runner.c b/test/runner.c index 789108275cd..00f2dea2179 100644 --- a/test/runner.c +++ b/test/runner.c @@ -77,9 +77,7 @@ const char* fmt(double d) { int run_tests(int benchmark_output) { int actual; int total; - int passed; int failed; - int skipped; int current; int test_result; int skip; @@ -102,9 +100,7 @@ int run_tests(int benchmark_output) { fflush(stdout); /* Run all tests. */ - passed = 0; failed = 0; - skipped = 0; current = 1; for (task = TASKS; task->main; task++) { if (task->is_helper) { @@ -113,8 +109,8 @@ int run_tests(int benchmark_output) { test_result = run_test(task->task_name, benchmark_output, current); switch (test_result) { - case TEST_OK: passed++; break; - case TEST_SKIP: skipped++; break; + case TEST_OK: break; + case TEST_SKIP: break; default: failed++; } current++; diff --git a/test/test-env-vars.c b/test/test-env-vars.c index ecaba337ca1..8118e3da5d7 100644 --- a/test/test-env-vars.c +++ b/test/test-env-vars.c @@ -131,7 +131,10 @@ TEST_IMPL(env_vars) { ASSERT(found == 2); #ifdef _WIN32 - ASSERT(found_win_special > 0); + ASSERT_GT(found_win_special, 0); +#else + /* There's no rule saying a key can't start with '='. */ + (void) &found_win_special; #endif uv_os_free_environ(envitems, envcount); From 8ddffeeea3ae83958e54fd814755cd63d4262a5c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 28 Nov 2022 12:00:27 +0100 Subject: [PATCH 273/713] doc: bump min supported linux and freebsd versions (#3830) The old Linux baseline was essentially RHEL 6 but that distro has been out of support for two years now. Move to RHEL 7. This commit also moves FreeBSD to tier 2 because it isn't actually part of libuv's CI matrix, only Node's. Fixes: https://github.com/libuv/libuv/issues/3822 --- SUPPORTED_PLATFORMS.md | 4 +- src/unix/freebsd.c | 24 ---------- src/unix/internal.h | 16 ------- src/unix/linux.c | 102 ----------------------------------------- src/unix/udp.c | 81 ++++++++------------------------ 5 files changed, 21 insertions(+), 206 deletions(-) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 0c1dd4e29fa..014ffd1da98 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -2,10 +2,10 @@ | System | Support type | Supported versions | Notes | |---|---|---|---| -| GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | | +| GNU/Linux | Tier 1 | Linux >= 3.10 with glibc >= 2.17 | | | macOS | Tier 1 | macOS >= 10.15 | Current and previous macOS release | | Windows | Tier 1 | >= Windows 8 | VS 2015 and later are supported | -| FreeBSD | Tier 1 | >= 10 | | +| 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 | diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index b254b9501d8..191bc8bc213 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -269,30 +269,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { } -int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { -#if __FreeBSD__ >= 11 && !defined(__DragonFly__) - return sendmmsg(fd, - (struct mmsghdr*) mmsg, - vlen, - 0 /* flags */); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { -#if __FreeBSD__ >= 11 && !defined(__DragonFly__) - return recvmmsg(fd, - (struct mmsghdr*) mmsg, - vlen, - 0 /* flags */, - NULL /* timeout */); -#else - return errno = ENOSYS, -1; -#endif -} - ssize_t uv__fs_copy_file_range(int fd_in, off_t* off_in, diff --git a/src/unix/internal.h b/src/unix/internal.h index 9f32ebb062e..395ba89b31b 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -411,22 +411,6 @@ int uv__getsockpeername(const uv_handle_t* handle, struct sockaddr* name, int* namelen); -#if defined(__linux__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ - defined(__DragonFly__) -#define HAVE_MMSG 1 -struct uv__mmsghdr { - struct msghdr msg_hdr; - unsigned int msg_len; -}; - -int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen); -int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen); -#else -#define HAVE_MMSG 0 -#endif - #if defined(__sun) #if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L size_t strnlen(const char* s, size_t maxlen); diff --git a/src/unix/linux.c b/src/unix/linux.c index 18dd5029b8f..bbeb283d0de 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -55,22 +55,6 @@ # endif #endif /* __arm__ */ -#ifndef __NR_recvmmsg -# if defined(__x86_64__) -# define __NR_recvmmsg 299 -# elif defined(__arm__) -# define __NR_recvmmsg (UV_SYSCALL_BASE + 365) -# endif -#endif /* __NR_recvmsg */ - -#ifndef __NR_sendmmsg -# if defined(__x86_64__) -# define __NR_sendmmsg 307 -# elif defined(__arm__) -# define __NR_sendmmsg (UV_SYSCALL_BASE + 374) -# endif -#endif /* __NR_sendmmsg */ - #ifndef __NR_copy_file_range # if defined(__x86_64__) # define __NR_copy_file_range 326 @@ -1796,89 +1780,3 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { void uv__fs_event_close(uv_fs_event_t* handle) { uv_fs_event_stop(handle); } - - -int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { -#if defined(__i386__) - unsigned long args[4]; - int rc; - - args[0] = (unsigned long) fd; - args[1] = (unsigned long) mmsg; - args[2] = (unsigned long) vlen; - args[3] = /* flags */ 0; - - /* socketcall() raises EINVAL when SYS_SENDMMSG is not supported. */ - rc = syscall(/* __NR_socketcall */ 102, 20 /* SYS_SENDMMSG */, args); - if (rc == -1) - if (errno == EINVAL) - errno = ENOSYS; - - return rc; -#elif defined(__NR_sendmmsg) - return syscall(__NR_sendmmsg, fd, mmsg, vlen, /* flags */ 0); -#else - return errno = ENOSYS, -1; -#endif -} - - -static void uv__recvmmsg_unpoison(struct uv__mmsghdr* mmsg, int rc) { - struct uv__mmsghdr* m; - struct msghdr* h; - struct iovec* v; - size_t j; - int i; - - for (i = 0; i < rc; i++) { - m = mmsg + i; - uv__msan_unpoison(m, sizeof(*m)); - - h = &m->msg_hdr; - if (h->msg_name != NULL) - uv__msan_unpoison(h->msg_name, h->msg_namelen); - - if (h->msg_iov != NULL) - uv__msan_unpoison(h->msg_iov, h->msg_iovlen * sizeof(*h->msg_iov)); - - for (j = 0; j < h->msg_iovlen; j++) { - v = h->msg_iov + j; - uv__msan_unpoison(v->iov_base, v->iov_len); - } - - if (h->msg_control != NULL) - uv__msan_unpoison(h->msg_control, h->msg_controllen); - } -} - - -int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) { -#if defined(__i386__) - unsigned long args[5]; - int rc; - - args[0] = (unsigned long) fd; - args[1] = (unsigned long) mmsg; - args[2] = (unsigned long) vlen; - args[3] = /* flags */ 0; - args[4] = /* timeout */ 0; - - /* socketcall() raises EINVAL when SYS_RECVMMSG is not supported. */ - rc = syscall(/* __NR_socketcall */ 102, 19 /* SYS_RECVMMSG */, args); - uv__recvmmsg_unpoison(mmsg, rc); - if (rc == -1) - if (errno == EINVAL) - errno = ENOSYS; - - return rc; -#elif defined(__NR_recvmmsg) - int rc; - - rc = syscall(__NR_recvmmsg, fd, mmsg, vlen, /* flags */ 0, /* timeout */ 0); - uv__recvmmsg_unpoison(mmsg, rc); - - return rc; -#else - return errno = ENOSYS, -1; -#endif -} diff --git a/src/unix/udp.c b/src/unix/udp.c index 4d985b88ba9..74a60131054 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -54,36 +54,6 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain, unsigned int flags); -#if HAVE_MMSG - -#define UV__MMSG_MAXWIDTH 20 - -static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf); -static void uv__udp_sendmmsg(uv_udp_t* handle); - -static int uv__recvmmsg_avail; -static int uv__sendmmsg_avail; -static uv_once_t once = UV_ONCE_INIT; - -static void uv__udp_mmsg_init(void) { - int ret; - int s; - s = uv__socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) - return; - ret = uv__sendmmsg(s, NULL, 0); - if (ret == 0 || errno != ENOSYS) { - uv__sendmmsg_avail = 1; - uv__recvmmsg_avail = 1; - } else { - ret = uv__recvmmsg(s, NULL, 0); - if (ret == 0 || errno != ENOSYS) - uv__recvmmsg_avail = 1; - } - uv__close(s); -} - -#endif void uv__udp_close(uv_udp_t* handle) { uv__io_close(handle->loop, &handle->io_watcher); @@ -183,11 +153,11 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { } } -#if HAVE_MMSG static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { - struct sockaddr_in6 peers[UV__MMSG_MAXWIDTH]; - struct iovec iov[UV__MMSG_MAXWIDTH]; - struct uv__mmsghdr msgs[UV__MMSG_MAXWIDTH]; +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + struct sockaddr_in6 peers[20]; + struct iovec iov[ARRAY_SIZE(peers)]; + struct mmsghdr msgs[ARRAY_SIZE(peers)]; ssize_t nread; uv_buf_t chunk_buf; size_t chunks; @@ -212,7 +182,7 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { } do - nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks); + nread = recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL); while (nread == -1 && errno == EINTR); if (nread < 1) { @@ -240,8 +210,10 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE); } return nread; +#else /* __linux__ || ____FreeBSD__ || __FreeBSD_kernel__ */ + return UV_ENOSYS; +#endif /* __linux__ || ____FreeBSD__ || __FreeBSD_kernel__ */ } -#endif static void uv__udp_recvmsg(uv_udp_t* handle) { struct sockaddr_storage peer; @@ -268,14 +240,12 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { } assert(buf.base != NULL); -#if HAVE_MMSG if (uv_udp_using_recvmmsg(handle)) { nread = uv__udp_recvmmsg(handle, &buf); if (nread > 0) count -= nread; continue; } -#endif memset(&h, 0, sizeof(h)); memset(&peer, 0, sizeof(peer)); @@ -311,11 +281,11 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { && handle->recv_cb != NULL); } -#if HAVE_MMSG -static void uv__udp_sendmmsg(uv_udp_t* handle) { +static void uv__udp_sendmsg(uv_udp_t* handle) { +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) uv_udp_send_t* req; - struct uv__mmsghdr h[UV__MMSG_MAXWIDTH]; - struct uv__mmsghdr *p; + struct mmsghdr h[20]; + struct mmsghdr* p; QUEUE* q; ssize_t npkts; size_t pkts; @@ -326,7 +296,7 @@ static void uv__udp_sendmmsg(uv_udp_t* handle) { write_queue_drain: for (pkts = 0, q = QUEUE_HEAD(&handle->write_queue); - pkts < UV__MMSG_MAXWIDTH && q != &handle->write_queue; + pkts < ARRAY_SIZE(h) && q != &handle->write_queue; ++pkts, q = QUEUE_HEAD(q)) { assert(q != NULL); req = QUEUE_DATA(q, uv_udp_send_t, queue); @@ -355,7 +325,7 @@ static void uv__udp_sendmmsg(uv_udp_t* handle) { } do - npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts); + npkts = sendmmsg(handle->io_watcher.fd, h, pkts, 0); while (npkts == -1 && errno == EINTR); if (npkts < 1) { @@ -401,24 +371,12 @@ static void uv__udp_sendmmsg(uv_udp_t* handle) { if (!QUEUE_EMPTY(&handle->write_queue)) goto write_queue_drain; uv__io_feed(handle->loop, &handle->io_watcher); - return; -} -#endif - -static void uv__udp_sendmsg(uv_udp_t* handle) { +#else /* __linux__ || ____FreeBSD__ || __FreeBSD_kernel__ */ uv_udp_send_t* req; struct msghdr h; QUEUE* q; ssize_t size; -#if HAVE_MMSG - uv_once(&once, uv__udp_mmsg_init); - if (uv__sendmmsg_avail) { - uv__udp_sendmmsg(handle); - return; - } -#endif - while (!QUEUE_EMPTY(&handle->write_queue)) { q = QUEUE_HEAD(&handle->write_queue); assert(q != NULL); @@ -466,6 +424,7 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); uv__io_feed(handle->loop, &handle->io_watcher); } +#endif /* __linux__ || ____FreeBSD__ || __FreeBSD_kernel__ */ } /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional @@ -1061,11 +1020,9 @@ int uv__udp_init_ex(uv_loop_t* loop, int uv_udp_using_recvmmsg(const uv_udp_t* handle) { -#if HAVE_MMSG - if (handle->flags & UV_HANDLE_UDP_RECVMMSG) { - uv_once(&once, uv__udp_mmsg_init); - return uv__recvmmsg_avail; - } +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + if (handle->flags & UV_HANDLE_UDP_RECVMMSG) + return 1; #endif return 0; } From 2c6858a018a0e23c0a576335e899680f22cbbcde Mon Sep 17 00:00:00 2001 From: Sergey Rubanov Date: Mon, 28 Nov 2022 18:51:45 +0400 Subject: [PATCH 274/713] Add Socket Runtime to the LINKS.md PR-URL: https://github.com/libuv/libuv/pull/3834 --- LINKS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/LINKS.md b/LINKS.md index 6f91d08a274..253e584b23d 100644 --- a/LINKS.md +++ b/LINKS.md @@ -32,6 +32,7 @@ * [pixie](https://github.com/pixie-lang/pixie): clojure-inspired lisp with a tracing JIT * [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 +* [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 * [Swish](https://github.com/becls/swish/): Concurrency engine with Erlang-like concepts. Includes a web server. From 5102b2c093681dae2a90ea2196f868de78ec9957 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 28 Nov 2022 22:45:28 +0100 Subject: [PATCH 275/713] unix: drop kfreebsd support (#3835) Because kFreeBSD is dead. RIP. Fixes: https://github.com/libuv/libuv/issues/3833 --- CMakeLists.txt | 5 ----- Makefile.am | 4 ---- configure.ac | 6 +----- include/uv/errno.h | 1 - include/uv/unix.h | 1 - src/unix/core.c | 1 - src/unix/fs.c | 19 +------------------ src/unix/internal.h | 1 - src/unix/process.c | 2 +- src/unix/tty.c | 2 +- src/unix/udp.c | 14 +++++++------- test/test-fs-event.c | 1 - test/test-poll.c | 2 +- test/test-tty.c | 3 +-- test/test-udp-ipv6.c | 6 +++--- test/test-udp-multicast-interface6.c | 2 +- test/test-udp-multicast-join6.c | 1 - 17 files changed, 17 insertions(+), 54 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a8d8d3b3427..650d6ca0cf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -294,11 +294,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "GNU") src/unix/hurd.c) endif() -if(CMAKE_SYSTEM_NAME STREQUAL "kFreeBSD") - list(APPEND uv_defines _GNU_SOURCE) - list(APPEND uv_libraries dl freebsd-glue) -endif() - if(CMAKE_SYSTEM_NAME STREQUAL "Linux") list(APPEND uv_defines _GNU_SOURCE _POSIX_C_SOURCE=200112) list(APPEND uv_libraries dl rt) diff --git a/Makefile.am b/Makefile.am index 7545ee0c274..e0c9414a1c2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -468,10 +468,6 @@ libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/hurd.c endif -if KFREEBSD -libuv_la_CFLAGS += -D_GNU_SOURCE -endif - if LINUX uvinclude_HEADERS += include/uv/linux.h libuv_la_CFLAGS += -D_GNU_SOURCE diff --git a/configure.ac b/configure.ac index a380cd9715b..d3417f5ea45 100644 --- a/configure.ac +++ b/configure.ac @@ -61,8 +61,7 @@ AM_CONDITIONAL([ANDROID], [AS_CASE([$host_os],[linux-android*],[true], [false]) AM_CONDITIONAL([CYGWIN], [AS_CASE([$host_os],[cygwin*], [true], [false])]) AM_CONDITIONAL([DARWIN], [AS_CASE([$host_os],[darwin*], [true], [false])]) AM_CONDITIONAL([DRAGONFLY],[AS_CASE([$host_os],[dragonfly*], [true], [false])]) -AM_CONDITIONAL([FREEBSD], [AS_CASE([$host_os],[*freebsd*], [true], [false])]) -AM_CONDITIONAL([KFREEBSD], [AS_CASE([$host_os],[kfreebsd*], [true], [false])]) +AM_CONDITIONAL([FREEBSD], [AS_CASE([$host_os],[freebsd*], [true], [false])]) AM_CONDITIONAL([HAIKU], [AS_CASE([$host_os],[haiku], [true], [false])]) AM_CONDITIONAL([HURD], [AS_CASE([$host_os],[gnu*], [true], [false])]) AM_CONDITIONAL([LINUX], [AS_CASE([$host_os],[linux*], [true], [false])]) @@ -80,9 +79,6 @@ AS_CASE([$host_os], [solaris2.10], [ CFLAGS="$CFLAGS -DSUNOS_NO_IFADDRS" ]) AS_CASE([$host_os], [netbsd*], [AC_CHECK_LIB([kvm], [kvm_open])]) -AS_CASE([$host_os], [kfreebsd*], [ - LIBS="$LIBS -lfreebsd-glue" -]) AS_CASE([$host_os], [haiku], [ LIBS="$LIBS -lnetwork" ]) diff --git a/include/uv/errno.h b/include/uv/errno.h index 0bc429bc6c7..82d84bfdb56 100644 --- a/include/uv/errno.h +++ b/include/uv/errno.h @@ -413,7 +413,6 @@ #elif defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ defined(__NetBSD__) || \ defined(__OpenBSD__) # define UV__EHOSTDOWN (-64) diff --git a/include/uv/unix.h b/include/uv/unix.h index ea37d787686..0b1fdac2b25 100644 --- a/include/uv/unix.h +++ b/include/uv/unix.h @@ -59,7 +59,6 @@ # include "uv/darwin.h" #elif defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) # include "uv/bsd.h" diff --git a/src/unix/core.c b/src/unix/core.c index b77be274f40..bb9226afc8d 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -66,7 +66,6 @@ extern char** environ; #if defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ defined(__NetBSD__) || \ defined(__OpenBSD__) # include diff --git a/src/unix/fs.c b/src/unix/fs.c index 3ec4b6ae85e..e1120cd775b 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -48,7 +48,6 @@ #if defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) # define HAVE_PREADV 1 @@ -79,7 +78,6 @@ #if defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) # include @@ -256,7 +254,6 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { #elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ - || defined(__FreeBSD_kernel__) \ || defined(__NetBSD__) \ || defined(__OpenBSD__) \ || defined(__sun) @@ -1054,10 +1051,7 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { return -1; } -#elif defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) +#elif defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) { off_t len; ssize_t r; @@ -1081,15 +1075,6 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { #endif len = 0; r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0); -#elif defined(__FreeBSD_kernel__) - len = 0; - r = bsd_sendfile(in_fd, - out_fd, - req->off, - req->bufsml[0].len, - NULL, - &len, - 0); #else /* The darwin sendfile takes len as an input for the length to send, * so make sure to initialize it with the caller's value. */ @@ -1141,7 +1126,6 @@ static ssize_t uv__fs_utime(uv_fs_t* req) { #elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ - || defined(__FreeBSD_kernel__) \ || defined(__NetBSD__) \ || defined(__OpenBSD__) struct timeval tv[2]; @@ -1183,7 +1167,6 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) { #elif defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ defined(__NetBSD__) struct timeval tv[2]; tv[0] = uv__fs_to_timeval(req->atime); diff --git a/src/unix/internal.h b/src/unix/internal.h index 395ba89b31b..e83526db0a9 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -207,7 +207,6 @@ struct uv__statx { defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ defined(__linux__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) diff --git a/src/unix/process.c b/src/unix/process.c index f84153687f7..fff6192eea4 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -55,7 +55,7 @@ extern char **environ; #endif -#if defined(__linux__) || defined(__GLIBC__) +#if defined(__linux__) # include #endif diff --git a/src/unix/tty.c b/src/unix/tty.c index 623280872fc..7a5390c1a8b 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -81,7 +81,7 @@ int uv__tcsetattr(int fd, int how, const struct termios *term) { static int uv__tty_is_slave(const int fd) { int result; -#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__linux__) || defined(__FreeBSD__) int dummy; result = ioctl(fd, TIOCGPTN, &dummy) != 0; diff --git a/src/unix/udp.c b/src/unix/udp.c index 74a60131054..42ce0ca77f9 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -154,7 +154,7 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { } static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { -#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__linux__) || defined(__FreeBSD__) struct sockaddr_in6 peers[20]; struct iovec iov[ARRAY_SIZE(peers)]; struct mmsghdr msgs[ARRAY_SIZE(peers)]; @@ -210,9 +210,9 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE); } return nread; -#else /* __linux__ || ____FreeBSD__ || __FreeBSD_kernel__ */ +#else /* __linux__ || ____FreeBSD__ */ return UV_ENOSYS; -#endif /* __linux__ || ____FreeBSD__ || __FreeBSD_kernel__ */ +#endif /* __linux__ || ____FreeBSD__ */ } static void uv__udp_recvmsg(uv_udp_t* handle) { @@ -282,7 +282,7 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { } static void uv__udp_sendmsg(uv_udp_t* handle) { -#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__linux__) || defined(__FreeBSD__) uv_udp_send_t* req; struct mmsghdr h[20]; struct mmsghdr* p; @@ -371,7 +371,7 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { if (!QUEUE_EMPTY(&handle->write_queue)) goto write_queue_drain; uv__io_feed(handle->loop, &handle->io_watcher); -#else /* __linux__ || ____FreeBSD__ || __FreeBSD_kernel__ */ +#else /* __linux__ || ____FreeBSD__ */ uv_udp_send_t* req; struct msghdr h; QUEUE* q; @@ -424,7 +424,7 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); uv__io_feed(handle->loop, &handle->io_watcher); } -#endif /* __linux__ || ____FreeBSD__ || __FreeBSD_kernel__ */ +#endif /* __linux__ || ____FreeBSD__ */ } /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional @@ -1020,7 +1020,7 @@ int uv__udp_init_ex(uv_loop_t* loop, int uv_udp_using_recvmmsg(const uv_udp_t* handle) { -#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__linux__) || defined(__FreeBSD__) if (handle->flags & UV_HANDLE_UDP_RECVMMSG) return 1; #endif diff --git a/test/test-fs-event.c b/test/test-fs-event.c index a08bfb9100c..03a29a7e8fb 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -33,7 +33,6 @@ # if defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) # define HAVE_KQUEUE 1 diff --git a/test/test-poll.c b/test/test-poll.c index 3bc422d2795..0ee0fd8cf08 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -631,7 +631,7 @@ TEST_IMPL(poll_unidirectional) { */ TEST_IMPL(poll_bad_fdtype) { #if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \ - !defined(_AIX) && !defined(__MVS__) && !defined(__FreeBSD_kernel__) && \ + !defined(_AIX) && !defined(__MVS__) && \ !defined(__OpenBSD__) && !defined(__CYGWIN__) && !defined(__MSYS__) && \ !defined(__NetBSD__) uv_poll_t poll_handle; diff --git a/test/test-tty.c b/test/test-tty.c index ff7d388d7c0..2c7ec4ec564 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -28,7 +28,7 @@ #else /* Unix */ # include # include -# if (defined(__linux__) || defined(__GLIBC__)) && !defined(__ANDROID__) +# if defined(__linux__) && !defined(__ANDROID__) # include # elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) # include @@ -433,7 +433,6 @@ TEST_IMPL(tty_pty) { #if defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ (defined(__linux__) && !defined(__ANDROID__)) || \ defined(__NetBSD__) || \ defined(__OpenBSD__) diff --git a/test/test-udp-ipv6.c b/test/test-udp-ipv6.c index 7099953097c..6f491fbb7dc 100644 --- a/test/test-udp-ipv6.c +++ b/test/test-udp-ipv6.c @@ -26,7 +26,7 @@ #include #include -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) #include #endif @@ -49,7 +49,7 @@ static int recv_cb_called; static int close_cb_called; static uint16_t client_port; -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) static int can_ipv6_ipv4_dual(void) { int v6only; size_t size = sizeof(int); @@ -220,7 +220,7 @@ TEST_IMPL(udp_dual_stack) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) if (!can_ipv6_ipv4_dual()) RETURN_SKIP("IPv6-IPv4 dual stack not supported"); #elif defined(__OpenBSD__) diff --git a/test/test-udp-multicast-interface6.c b/test/test-udp-multicast-interface6.c index be11514c805..d69b3419727 100644 --- a/test/test-udp-multicast-interface6.c +++ b/test/test-udp-multicast-interface6.c @@ -77,7 +77,7 @@ TEST_IMPL(udp_multicast_interface6) { r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0); ASSERT(r == 0); -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__APPLE__) || defined(__FreeBSD__) r = uv_udp_set_multicast_interface(&server, "::1%lo0"); #else r = uv_udp_set_multicast_interface(&server, NULL); diff --git a/test/test-udp-multicast-join6.c b/test/test-udp-multicast-join6.c index e67c5ee59bb..f7ac113d471 100644 --- a/test/test-udp-multicast-join6.c +++ b/test/test-udp-multicast-join6.c @@ -33,7 +33,6 @@ #if defined(__APPLE__) || \ defined(_AIX) || \ defined(__MVS__) || \ - defined(__FreeBSD_kernel__) || \ defined(__NetBSD__) || \ defined(__OpenBSD__) #define MULTICAST_ADDR "ff02::1%lo0" From c17bd99f1ccf236698e5bda3edbbe82843710ef9 Mon Sep 17 00:00:00 2001 From: Stefan Stojanovic Date: Tue, 29 Nov 2022 23:46:09 +0100 Subject: [PATCH 276/713] win: fix fstat for pipes and character files (#3811) Calling uv_fs_fstat for file types other then disk type was resulting in error on Windows while it was retrieving data on Linux. This change enables getting fstat for pipes and character files on Windows with data fetched being as reasonable as possible. A simple test is also added to check this behavior on all platforms. It uses stdin, stdout and stderr. uv_fs_fstat needs to pass with disk files pipes and character files (eg. console). Refs: https://github.com/nodejs/node/issues/40006 Co-authored-by: Jameson Nash --- include/uv/win.h | 5 ++++ src/win/fs.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++- test/test-fs.c | 37 +++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 4 files changed, 103 insertions(+), 1 deletion(-) diff --git a/include/uv/win.h b/include/uv/win.h index 5d08d637f03..1c69c022cde 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -70,6 +70,11 @@ typedef struct pollfd { # define S_IFLNK 0xA000 #endif +// Define missing in Windows Kit Include\{VERSION}\ucrt\sys\stat.h +#if defined(_CRT_INTERNAL_NONSTDC_NAMES) && _CRT_INTERNAL_NONSTDC_NAMES && !defined(S_IFIFO) +# define S_IFIFO _S_IFIFO +#endif + /* Additional signals supported by uv_signal and or uv_kill. The CRT defines * the following signals already: * diff --git a/src/win/fs.c b/src/win/fs.c index 792307995f6..efc2393424a 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -36,6 +36,8 @@ #include "handle-inl.h" #include "fs-fd-hash-inl.h" +#include + #define UV_FS_FREE_PATHS 0x0002 #define UV_FS_FREE_PTR 0x0008 @@ -1706,11 +1708,36 @@ void fs__closedir(uv_fs_t* req) { INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, int do_lstat) { + FILE_FS_DEVICE_INFORMATION device_info; FILE_ALL_INFORMATION file_info; FILE_FS_VOLUME_INFORMATION volume_info; NTSTATUS nt_status; IO_STATUS_BLOCK io_status; + 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)) { + SetLastError(pRtlNtStatusToDosError(nt_status)); + return -1; + } + + /* If it's NUL device set fields as reasonable as possible and return. */ + if (device_info.DeviceType == FILE_DEVICE_NULL) { + memset(statbuf, 0, sizeof(uv_stat_t)); + statbuf->st_mode = _S_IFCHR; + statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | + ((_S_IREAD | _S_IWRITE) >> 6); + statbuf->st_nlink = 1; + statbuf->st_blksize = 4096; + statbuf->st_rdev = FILE_DEVICE_NULL << 16; + return 0; + } + nt_status = pNtQueryInformationFile(handle, &io_status, &file_info, @@ -1915,6 +1942,37 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) { } +INLINE static int fs__fstat_handle(int fd, HANDLE handle, uv_stat_t* statbuf) { + DWORD file_type; + + /* Each file type is processed differently. */ + file_type = uv_guess_handle(fd); + switch (file_type) { + /* Disk files use the existing logic from fs__stat_handle. */ + case UV_FILE: + return fs__stat_handle(handle, statbuf, 0); + + /* Devices and pipes are processed identically. There is no more information + * for them from any API. Fields are set as reasonably as possible and the + * function returns. */ + case UV_TTY: + case UV_NAMED_PIPE: + memset(statbuf, 0, sizeof(uv_stat_t)); + statbuf->st_mode = file_type == UV_TTY ? _S_IFCHR : _S_IFIFO; + statbuf->st_nlink = 1; + statbuf->st_rdev = (file_type == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE) << 16; + statbuf->st_ino = (uint64_t) handle; + return 0; + + /* If file type is unknown it is an error. */ + case UV_UNKNOWN_HANDLE: + default: + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } +} + + static void fs__stat(uv_fs_t* req) { fs__stat_prepare_path(req->file.pathw); fs__stat_impl(req, 0); @@ -1940,7 +1998,7 @@ static void fs__fstat(uv_fs_t* req) { return; } - if (fs__stat_handle(handle, &req->statbuf, 0) != 0) { + if (fs__fstat_handle(fd, handle, &req->statbuf) != 0) { SET_REQ_WIN32_ERROR(req, GetLastError()); return; } diff --git a/test/test-fs.c b/test/test-fs.c index 78ee499917f..ebf410504da 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1539,6 +1539,43 @@ TEST_IMPL(fs_fstat) { } +TEST_IMPL(fs_fstat_stdio) { + int fd; + int res; + uv_fs_t req; +#ifdef _WIN32 + uv_stat_t* st; + DWORD ft; +#endif + + for (fd = 0; fd <= 2; ++fd) { + res = uv_fs_fstat(NULL, &req, fd, NULL); + ASSERT(res == 0); + ASSERT(req.result == 0); + +#ifdef _WIN32 + st = req.ptr; + ft = uv_guess_handle(fd); + switch (ft) { + case UV_TTY: + case UV_NAMED_PIPE: + ASSERT(st->st_mode == ft == UV_TTY ? S_IFCHR : S_IFIFO); + ASSERT(st->st_nlink == 1); + ASSERT(st->st_rdev == (ft == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE) << 16); + break; + default: + break; + } +#endif + + uv_fs_req_cleanup(&req); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + TEST_IMPL(fs_access) { int r; uv_fs_t req; diff --git a/test/test-list.h b/test/test-list.h index 45261be28a8..ec23b344a1e 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -347,6 +347,7 @@ TEST_DECLARE (fs_async_sendfile_nodata) TEST_DECLARE (fs_mkdtemp) TEST_DECLARE (fs_mkstemp) TEST_DECLARE (fs_fstat) +TEST_DECLARE (fs_fstat_stdio) TEST_DECLARE (fs_access) TEST_DECLARE (fs_chmod) TEST_DECLARE (fs_copyfile) @@ -1024,6 +1025,7 @@ TASK_LIST_START TEST_ENTRY (fs_mkdtemp) TEST_ENTRY (fs_mkstemp) TEST_ENTRY (fs_fstat) + TEST_ENTRY (fs_fstat_stdio) TEST_ENTRY (fs_access) TEST_ENTRY (fs_chmod) TEST_ENTRY (fs_copyfile) From a138041c59ecd9402c524e8c7839e148f5d0af3c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 1 Dec 2022 09:34:33 +0100 Subject: [PATCH 277/713] win: fix -Wunused-variable warning --- src/win/tcp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/win/tcp.c b/src/win/tcp.c index 62e0917fe64..6b282e0b501 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -627,7 +627,6 @@ int uv__tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { int uv__tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { - uv_loop_t* loop = server->loop; int err = 0; int family; From 1a9150885767ab81b6d176734f95382571b67bd9 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 1 Dec 2022 09:34:33 +0100 Subject: [PATCH 278/713] win: fix -Wunused-function warning --- src/win/util.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/src/win/util.c b/src/win/util.c index a3bc1b980af..094a414c055 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -691,40 +691,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { } -static int address_prefix_match(int family, - struct sockaddr* address, - struct sockaddr* prefix_address, - int prefix_len) { - uint8_t* address_data; - uint8_t* prefix_address_data; - int i; - - assert(address->sa_family == family); - assert(prefix_address->sa_family == family); - - if (family == AF_INET6) { - address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr); - prefix_address_data = - (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr); - } else { - address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr); - prefix_address_data = - (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr); - } - - for (i = 0; i < prefix_len >> 3; i++) { - if (address_data[i] != prefix_address_data[i]) - return 0; - } - - if (prefix_len % 8) - return prefix_address_data[i] == - (address_data[i] & (0xff << (8 - prefix_len % 8))); - - return 1; -} - - int uv_interface_addresses(uv_interface_address_t** addresses_ptr, int* count_ptr) { IP_ADAPTER_ADDRESSES* win_address_buf; From 244e0e20592f40fce87d573c9f7b6ff7f189c382 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 25 May 2016 13:53:56 +0200 Subject: [PATCH 279/713] win: implement uv_try_write() for pipes(#3825 1/2) --- Makefile.am | 1 + src/win/internal.h | 2 + src/win/pipe.c | 72 +++++++++++++++++++++ src/win/stream.c | 2 +- test/test-list.h | 6 ++ test/test-pipe-try-write.c | 125 +++++++++++++++++++++++++++++++++++++ 6 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 test/test-pipe-try-write.c diff --git a/Makefile.am b/Makefile.am index e0c9414a1c2..9a33f7e6344 100644 --- a/Makefile.am +++ b/Makefile.am @@ -222,6 +222,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-pipe-close-stdout-read-stdin.c \ test/test-pipe-set-non-blocking.c \ test/test-pipe-set-fchmod.c \ + test/test-pipe-try-write.c \ test/test-platform-output.c \ test/test-poll.c \ test/test-poll-close.c \ diff --git a/src/win/internal.h b/src/win/internal.h index 89c72b8a1a6..8a87743b352 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -134,6 +134,8 @@ int uv__pipe_write(uv_loop_t* loop, uv_stream_t* send_handle, uv_write_cb cb); void uv__pipe_shutdown(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req); +int uv__pipe_try_write(uv_pipe_t* handle, const uv_buf_t bufs[], + unsigned int nbufs); void uv__process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, uv_req_t* req); diff --git a/src/win/pipe.c b/src/win/pipe.c index 787ba105c93..94233455388 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1782,6 +1782,78 @@ int uv__pipe_write(uv_loop_t* loop, } +int uv__pipe_try_write(uv_pipe_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs) { + OVERLAPPED overlapped; + const uv_buf_t* buf; + int bytes_written; + unsigned int idx; + DWORD timeout; + DWORD err; + + if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + return UV_EAGAIN; + } + + if (handle->stream.conn.write_reqs_pending > 0) { + return UV_EAGAIN; + } + + timeout = 0; + if (handle->flags & UV_HANDLE_BLOCKING_WRITES) { + timeout = INFINITE; + } + + memset(&overlapped, 0, sizeof(overlapped)); + + overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (overlapped.hEvent == NULL) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + + bytes_written = 0; + for (err = 0, idx = 0; idx < nbufs; err = 0, idx += 1) { + buf = &bufs[idx]; + + if (WriteFile(handle->handle, buf->base, buf->len, NULL, &overlapped)) { + bytes_written += buf->len; + continue; + } + + err = GetLastError(); + if (err != ERROR_IO_PENDING) { + break; + } + + err = WaitForSingleObject(overlapped.hEvent, timeout); + if (err == WAIT_OBJECT_0) { + bytes_written += buf->len; + continue; + } + + if (err == WAIT_TIMEOUT && + CancelIo(handle->handle) && + GetOverlappedResult(handle->handle, &overlapped, &err, TRUE)) { + bytes_written += err; + err = WSAEWOULDBLOCK; /* Translates to UV_EAGAIN. */ + } else { + err = GetLastError(); + } + + break; + } + + CloseHandle(overlapped.hEvent); + + if (bytes_written == 0 && err != 0) { + return uv_translate_sys_error(err); + } + + return bytes_written; +} + + static void uv__pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, uv_buf_t buf) { /* If there is an eof timer running, we don't need it any more, so discard diff --git a/src/win/stream.c b/src/win/stream.c index 7bf9ca388cb..7ccc79be421 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -182,7 +182,7 @@ int uv_try_write(uv_stream_t* stream, case UV_TTY: return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs); case UV_NAMED_PIPE: - return UV_EAGAIN; + return uv__pipe_try_write((uv_pipe_t*) stream, bufs, nbufs); default: assert(0); return UV_ENOSYS; diff --git a/test/test-list.h b/test/test-list.h index ec23b344a1e..00eda659a3c 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -207,6 +207,9 @@ TEST_DECLARE (pipe_getsockname_blocking) TEST_DECLARE (pipe_pending_instances) TEST_DECLARE (pipe_sendmsg) TEST_DECLARE (pipe_server_close) +TEST_DECLARE (pipe_try_write_0) +TEST_DECLARE (pipe_try_write_1) +TEST_DECLARE (pipe_try_write_2) TEST_DECLARE (connection_fail) TEST_DECLARE (connection_fail_doesnt_auto_close) TEST_DECLARE (shutdown_close_tcp) @@ -587,6 +590,9 @@ TASK_LIST_START TEST_ENTRY (pipe_connect_on_prepare) TEST_ENTRY (pipe_server_close) + TEST_ENTRY (pipe_try_write_0) + TEST_ENTRY (pipe_try_write_1) + TEST_ENTRY (pipe_try_write_2) #ifndef _WIN32 TEST_ENTRY (pipe_close_stdout_read_stdin) #endif diff --git a/test/test-pipe-try-write.c b/test/test-pipe-try-write.c new file mode 100644 index 00000000000..346a1c3910d --- /dev/null +++ b/test/test-pipe-try-write.c @@ -0,0 +1,125 @@ +#include "uv.h" +#include "task.h" + +static void (*spam)(uv_pipe_t* handle); +static uv_pipe_t client_handle; +static uv_pipe_t peer_handle; +static uv_pipe_t server_handle; +static uv_write_t write_req; + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(0 == status); +} + + +static void spam_0(uv_pipe_t* handle) { + uv_buf_t buf; + + buf = uv_buf_init("", 0); + ASSERT(0 == uv_try_write((uv_stream_t*) handle, &buf, 1)); + + /* Non-empty write to start the event loop moving. */ + buf = uv_buf_init("hello, world", sizeof("hello, world") - 1); + ASSERT(0 == uv_write(&write_req, (uv_stream_t*) handle, &buf, 1, write_cb)); +} + + +static void spam_1(uv_pipe_t* handle) { + uv_buf_t buf; + int rc; + + buf = uv_buf_init("hello, world", sizeof("hello, world") - 1); + do + rc = uv_try_write((uv_stream_t*) handle, &buf, 1); + while (rc > 0); + + ASSERT(rc == UV_EAGAIN); +} + + +static void spam_2(uv_pipe_t* handle) { + uv_buf_t bufs[2]; + int rc; + + bufs[0] = uv_buf_init("hello,", sizeof("hello,") - 1); + bufs[1] = uv_buf_init(" world", sizeof(" world") - 1); + + do + rc = uv_try_write((uv_stream_t*) handle, bufs, ARRAY_SIZE(bufs)); + while (rc > 0); + + ASSERT(rc == UV_EAGAIN); +} + + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + static char base[256]; + + buf->base = base; + buf->len = sizeof(base); +} + + +static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { + if (spam == spam_0) { + ASSERT(nread > 0); /* Expect some bytes. */ + } else { + ASSERT(nread == (ssize_t) buf->len); /* Expect saturation. */ + } + + if (handle == (uv_stream_t*) &peer_handle) { + spam(&client_handle); + } else { + uv_close((uv_handle_t*) &peer_handle, NULL); + uv_close((uv_handle_t*) &client_handle, NULL); + uv_close((uv_handle_t*) &server_handle, NULL); + } +} + + +static void connection_cb(uv_stream_t* handle, int status) { + ASSERT(0 == status); + ASSERT(0 == uv_pipe_init(uv_default_loop(), &peer_handle, 0)); + ASSERT(0 == uv_accept((uv_stream_t*) &server_handle, + (uv_stream_t*) &peer_handle)); + ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb)); + spam(&peer_handle); +} + + +static void connect_cb(uv_connect_t* req, int status) { + ASSERT(0 == status); + ASSERT(0 == uv_read_start((uv_stream_t*) &client_handle, alloc_cb, read_cb)); +} + + +static int pipe_try_write(void (*spammer)(uv_pipe_t*)) { + uv_connect_t connect_req; + + spam = spammer; + ASSERT(0 == uv_pipe_init(uv_default_loop(), &client_handle, 0)); + ASSERT(0 == uv_pipe_init(uv_default_loop(), &server_handle, 0)); + ASSERT(0 == uv_pipe_bind(&server_handle, TEST_PIPENAME)); + ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); + uv_pipe_connect(&connect_req, &client_handle, TEST_PIPENAME, connect_cb); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(pipe_try_write_0) { + return pipe_try_write(spam_0); +} + + +TEST_IMPL(pipe_try_write_1) { + return pipe_try_write(spam_1); +} + + +TEST_IMPL(pipe_try_write_2) { + return pipe_try_write(spam_2); +} From e1143f12657444c750e47ab3e1fb70ae6a030620 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sun, 20 Nov 2022 20:51:29 +0100 Subject: [PATCH 280/713] win: fixes in uv__pipe_try_write() (#3825 2/2) Return `UV_EAGAIN` on `ERROR_OPERATION_ABORTED`. Use the correct format for `overlapped.hEvent`. Some refactoring to always wait for the overlapped result. Modernize tests and some improvements. --- CMakeLists.txt | 1 + src/win/pipe.c | 46 ++++++++-------- test/test-pipe-try-write.c | 107 ++++++++++++++++++++++++------------- 3 files changed, 95 insertions(+), 59 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 650d6ca0cf9..6502f6e65b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -555,6 +555,7 @@ if(LIBUV_BUILD_TESTS) test/test-pipe-server-close.c test/test-pipe-set-fchmod.c test/test-pipe-set-non-blocking.c + test/test-pipe-try-write.c test/test-platform-output.c test/test-poll-close-doesnt-corrupt-stack.c test/test-poll-close.c diff --git a/src/win/pipe.c b/src/win/pipe.c index 94233455388..85b3e7da47e 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1786,6 +1786,7 @@ int uv__pipe_try_write(uv_pipe_t* handle, const uv_buf_t bufs[], unsigned int nbufs) { OVERLAPPED overlapped; + HANDLE event; const uv_buf_t* buf; int bytes_written; unsigned int idx; @@ -1807,44 +1808,47 @@ int uv__pipe_try_write(uv_pipe_t* handle, memset(&overlapped, 0, sizeof(overlapped)); - overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (overlapped.hEvent == NULL) { + event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (event == NULL) { uv_fatal_error(GetLastError(), "CreateEvent"); } + overlapped.hEvent = (HANDLE)((uintptr_t)event | 1); + bytes_written = 0; for (err = 0, idx = 0; idx < nbufs; err = 0, idx += 1) { buf = &bufs[idx]; - if (WriteFile(handle->handle, buf->base, buf->len, NULL, &overlapped)) { - bytes_written += buf->len; - continue; - } - - err = GetLastError(); - if (err != ERROR_IO_PENDING) { - break; - } + if (!WriteFile(handle->handle, buf->base, buf->len, NULL, &overlapped)) { + err = GetLastError(); + if (err != ERROR_IO_PENDING) { + break; + } - err = WaitForSingleObject(overlapped.hEvent, timeout); - if (err == WAIT_OBJECT_0) { - bytes_written += buf->len; - continue; + err = WaitForSingleObject(event, timeout); + if (err != WAIT_OBJECT_0) { + CancelIoEx(handle->handle, &overlapped); + } } - - if (err == WAIT_TIMEOUT && - CancelIo(handle->handle) && - GetOverlappedResult(handle->handle, &overlapped, &err, TRUE)) { + + if (GetOverlappedResult(handle->handle, &overlapped, &err, TRUE)) { bytes_written += err; - err = WSAEWOULDBLOCK; /* Translates to UV_EAGAIN. */ + if (err == buf->len) + continue; + err = WSAEWOULDBLOCK; /* Ignored later. */ } else { err = GetLastError(); + if (err == ERROR_OPERATION_ABORTED) { + err = WSAEWOULDBLOCK; /* Translates to UV_EAGAIN. */ + } } break; } - CloseHandle(overlapped.hEvent); + if (!CloseHandle(event)) { + uv_fatal_error(GetLastError(), "CloseHandle"); + } if (bytes_written == 0 && err != 0) { return uv_translate_sys_error(err); diff --git a/test/test-pipe-try-write.c b/test/test-pipe-try-write.c index 346a1c3910d..cacc12448f2 100644 --- a/test/test-pipe-try-write.c +++ b/test/test-pipe-try-write.c @@ -1,27 +1,64 @@ #include "uv.h" #include "task.h" +typedef struct pipe_ctx_s { + uv_pipe_t handle; + uv_write_t write_req; + ssize_t read; + ssize_t written; +} pipe_ctx_t; + static void (*spam)(uv_pipe_t* handle); -static uv_pipe_t client_handle; -static uv_pipe_t peer_handle; +static pipe_ctx_t client; +static pipe_ctx_t peer; static uv_pipe_t server_handle; -static uv_write_t write_req; - static void write_cb(uv_write_t* req, int status) { - ASSERT(0 == status); + ASSERT_EQ(0, status); +} + + +static int do_try_write(uv_pipe_t* handle, uv_buf_t* buf, size_t size) { + int rc; + pipe_ctx_t* pc; + pc = container_of(handle, struct pipe_ctx_s, handle); + rc = 0; + do { + pc->written += rc; + rc = uv_try_write((uv_stream_t*)handle, buf, size); + } while (rc > 0); + + return rc; +}; + + +static void handle_read(uv_stream_t* handle, + ssize_t nread, + const uv_buf_t* buf) { + pipe_ctx_t* send_ctx; + pipe_ctx_t* recv_ctx; + recv_ctx = container_of(handle, struct pipe_ctx_s, handle); + send_ctx = recv_ctx == &client ? &peer : &client; + ASSERT_UINT64_GT(nread, 0); + if (send_ctx->written >= recv_ctx->read + (ssize_t)buf->len) { + ASSERT_UINT64_EQ(nread, (ssize_t)buf->len); /* Expect saturation. */ + } + recv_ctx->read += nread; } static void spam_0(uv_pipe_t* handle) { uv_buf_t buf; + pipe_ctx_t* pc; buf = uv_buf_init("", 0); - ASSERT(0 == uv_try_write((uv_stream_t*) handle, &buf, 1)); + ASSERT_EQ(0, uv_try_write((uv_stream_t*) handle, &buf, 1)); /* Non-empty write to start the event loop moving. */ + pc = container_of(handle, struct pipe_ctx_s, handle); buf = uv_buf_init("hello, world", sizeof("hello, world") - 1); - ASSERT(0 == uv_write(&write_req, (uv_stream_t*) handle, &buf, 1, write_cb)); + ASSERT_EQ(0, + uv_write(&pc->write_req,(uv_stream_t*) handle, &buf, 1, write_cb)); } @@ -30,11 +67,9 @@ static void spam_1(uv_pipe_t* handle) { int rc; buf = uv_buf_init("hello, world", sizeof("hello, world") - 1); - do - rc = uv_try_write((uv_stream_t*) handle, &buf, 1); - while (rc > 0); + rc = do_try_write(handle, &buf, 1); - ASSERT(rc == UV_EAGAIN); + ASSERT_EQ(rc, UV_EAGAIN); } @@ -44,12 +79,9 @@ static void spam_2(uv_pipe_t* handle) { bufs[0] = uv_buf_init("hello,", sizeof("hello,") - 1); bufs[1] = uv_buf_init(" world", sizeof(" world") - 1); + rc = do_try_write(handle, bufs, ARRAY_SIZE(bufs)); - do - rc = uv_try_write((uv_stream_t*) handle, bufs, ARRAY_SIZE(bufs)); - while (rc > 0); - - ASSERT(rc == UV_EAGAIN); + ASSERT_EQ(rc, UV_EAGAIN); } @@ -62,35 +94,34 @@ static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { - if (spam == spam_0) { - ASSERT(nread > 0); /* Expect some bytes. */ - } else { - ASSERT(nread == (ssize_t) buf->len); /* Expect saturation. */ + ASSERT_UINT64_GT(nread, 0); /* Expect some bytes. */ + if (spam != spam_0) { + handle_read(handle, nread, buf); } - if (handle == (uv_stream_t*) &peer_handle) { - spam(&client_handle); + if (handle == (uv_stream_t*) &client.handle) { + spam(&client.handle); } else { - uv_close((uv_handle_t*) &peer_handle, NULL); - uv_close((uv_handle_t*) &client_handle, NULL); + uv_close((uv_handle_t*) &peer.handle, NULL); + uv_close((uv_handle_t*) &client.handle, NULL); uv_close((uv_handle_t*) &server_handle, NULL); } } static void connection_cb(uv_stream_t* handle, int status) { - ASSERT(0 == status); - ASSERT(0 == uv_pipe_init(uv_default_loop(), &peer_handle, 0)); - ASSERT(0 == uv_accept((uv_stream_t*) &server_handle, - (uv_stream_t*) &peer_handle)); - ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb)); - spam(&peer_handle); + ASSERT_EQ(0, status); + ASSERT_EQ(0, uv_pipe_init(uv_default_loop(), &peer.handle, 0)); + ASSERT_EQ(0, uv_accept((uv_stream_t*) &server_handle, + (uv_stream_t*) &peer.handle)); + ASSERT_EQ(0, uv_read_start((uv_stream_t*) &peer.handle, alloc_cb, read_cb)); + spam(&peer.handle); } static void connect_cb(uv_connect_t* req, int status) { - ASSERT(0 == status); - ASSERT(0 == uv_read_start((uv_stream_t*) &client_handle, alloc_cb, read_cb)); + ASSERT_EQ(0, status); + ASSERT_EQ(0, uv_read_start((uv_stream_t*) &client.handle, alloc_cb, read_cb)); } @@ -98,12 +129,12 @@ static int pipe_try_write(void (*spammer)(uv_pipe_t*)) { uv_connect_t connect_req; spam = spammer; - ASSERT(0 == uv_pipe_init(uv_default_loop(), &client_handle, 0)); - ASSERT(0 == uv_pipe_init(uv_default_loop(), &server_handle, 0)); - ASSERT(0 == uv_pipe_bind(&server_handle, TEST_PIPENAME)); - ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); - uv_pipe_connect(&connect_req, &client_handle, TEST_PIPENAME, connect_cb); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(0, uv_pipe_init(uv_default_loop(), &client.handle, 0)); + ASSERT_EQ(0, uv_pipe_init(uv_default_loop(), &server_handle, 0)); + ASSERT_EQ(0, uv_pipe_bind(&server_handle, TEST_PIPENAME)); + ASSERT_EQ(0, uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); + uv_pipe_connect(&connect_req, &client.handle, TEST_PIPENAME, connect_cb); + ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(); return 0; From cc000cfb5e92d2730ee0c8ee1d586133d7b6ae17 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 6 Dec 2022 22:57:52 +0100 Subject: [PATCH 281/713] build: drop qemu-alpha from ci matrix (#3848) As of recent, the fs_partial_read and fs_partial_write tests reliably fail on that architecture. An upgrade from Ubuntu 20.04 to 22.04 on the CI machines is suspected, not any changes in libuv itself. Perhaps it's possible to work around it in the tests but as Alpha is a dead architecture, it doesn't seem worthwhile to sink time in that. Let's remove it from the CI matrix instead. Fixes: https://github.com/libuv/libuv/issues/3843 --- .github/workflows/CI-unix.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 7ef80a623ce..748fd6a5e89 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -94,7 +94,6 @@ jobs: - {target: mips64, toolchain: gcc-mips64-linux-gnuabi64, cc: mips64-linux-gnuabi64-gcc, qemu: qemu-mips64-static } - {target: mipsel, toolchain: gcc-mipsel-linux-gnu, cc: mipsel-linux-gnu-gcc, qemu: qemu-mipsel-static } - {target: mips64el,toolchain: gcc-mips64el-linux-gnuabi64, cc: mips64el-linux-gnuabi64-gcc,qemu: qemu-mips64el-static } - - {target: alpha, toolchain: gcc-alpha-linux-gnu, cc: alpha-linux-gnu-gcc, qemu: qemu-alpha-static } - {target: arm (u64 slots), toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm-static} - {target: aarch64 (u64 slots), toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64-static} - {target: ppc (u64 slots), toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc-static} From 75d9411e803dea5363bfdc223f1f284b8cf3dec3 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 9 Dec 2022 13:27:52 +0100 Subject: [PATCH 282/713] win: move child_stdio_buffer out of uv_process_t (#3850) --- include/uv/win.h | 2 +- src/win/process.c | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/uv/win.h b/include/uv/win.h index 1c69c022cde..3c3fa016490 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -606,7 +606,7 @@ typedef struct { struct uv_process_exit_s { \ UV_REQ_FIELDS \ } exit_req; \ - BYTE* child_stdio_buffer; \ + void* unused; /* TODO: retained for ABI compat; remove this in v2.x. */ \ int exit_signal; \ HANDLE wait_handle; \ HANDLE process_handle; \ diff --git a/src/win/process.c b/src/win/process.c index 24c633393fd..ed44adc67c6 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -144,7 +144,6 @@ static void uv__process_init(uv_loop_t* loop, uv_process_t* handle) { handle->exit_signal = 0; handle->wait_handle = INVALID_HANDLE_VALUE; handle->process_handle = INVALID_HANDLE_VALUE; - handle->child_stdio_buffer = NULL; handle->exit_cb_pending = 0; UV_REQ_INIT(&handle->exit_req, UV_PROCESS_EXIT); @@ -947,9 +946,11 @@ int uv_spawn(uv_loop_t* loop, STARTUPINFOW startup; PROCESS_INFORMATION info; DWORD process_flags; + BYTE* child_stdio_buffer; uv__process_init(loop, process); process->exit_cb = options->exit_cb; + child_stdio_buffer = NULL; if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { return UV_ENOTSUP; @@ -1040,7 +1041,7 @@ int uv_spawn(uv_loop_t* loop, } } - err = uv__stdio_create(loop, options, &process->child_stdio_buffer); + err = uv__stdio_create(loop, options, &child_stdio_buffer); if (err) goto done; @@ -1059,12 +1060,12 @@ int uv_spawn(uv_loop_t* loop, startup.lpTitle = NULL; startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer); - startup.lpReserved2 = (BYTE*) process->child_stdio_buffer; + startup.cbReserved2 = uv__stdio_size(child_stdio_buffer); + startup.lpReserved2 = (BYTE*) child_stdio_buffer; - startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0); - startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1); - startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2); + startup.hStdInput = uv__stdio_handle(child_stdio_buffer, 0); + startup.hStdOutput = uv__stdio_handle(child_stdio_buffer, 1); + startup.hStdError = uv__stdio_handle(child_stdio_buffer, 2); process_flags = CREATE_UNICODE_ENVIRONMENT; @@ -1178,10 +1179,10 @@ int uv_spawn(uv_loop_t* loop, uv__free(env); uv__free(alloc_path); - if (process->child_stdio_buffer != NULL) { + if (child_stdio_buffer != NULL) { /* Clean up child stdio handles. */ - uv__stdio_destroy(process->child_stdio_buffer); - process->child_stdio_buffer = NULL; + uv__stdio_destroy(child_stdio_buffer); + child_stdio_buffer = NULL; } return uv_translate_sys_error(err); From abf77a9eda3c83e74d8d0f60d77fe00cb888908b Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sat, 10 Dec 2022 19:36:46 +0100 Subject: [PATCH 283/713] test: fix some unreachable code warnings (#3851) --- test/run-tests.c | 4 ---- test/test-tcp-connect-error-after-write.c | 12 ++++++------ test/test-tcp-write-in-a-row.c | 3 ++- test/test-tty-escape-sequence-processing.c | 21 +++++++++++---------- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/test/run-tests.c b/test/run-tests.c index 86b0359949b..d8cfe297c49 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -85,10 +85,6 @@ int main(int argc, char **argv) { fflush(stderr); return EXIT_FAILURE; } - -#ifndef __SUNPRO_C - return EXIT_SUCCESS; -#endif } diff --git a/test/test-tcp-connect-error-after-write.c b/test/test-tcp-connect-error-after-write.c index 3f2e3572da9..ad214b9396b 100644 --- a/test/test-tcp-connect-error-after-write.c +++ b/test/test-tcp-connect-error-after-write.c @@ -55,6 +55,11 @@ static void write_cb(uv_write_t* req, int status) { * Related issue: https://github.com/joyent/libuv/issues/443 */ TEST_IMPL(tcp_connect_error_after_write) { +#ifdef _WIN32 + RETURN_SKIP("This test is disabled on Windows for now. " + "See https://github.com/joyent/libuv/issues/444\n"); +#else + uv_connect_t connect_req; struct sockaddr_in addr; uv_write_t write_req; @@ -62,12 +67,6 @@ TEST_IMPL(tcp_connect_error_after_write) { uv_buf_t buf; int r; -#ifdef _WIN32 - fprintf(stderr, "This test is disabled on Windows for now.\n"); - fprintf(stderr, "See https://github.com/joyent/libuv/issues/444\n"); - return 0; /* windows slackers... */ -#endif - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); buf = uv_buf_init("TEST", 4); @@ -95,4 +94,5 @@ TEST_IMPL(tcp_connect_error_after_write) { MAKE_VALGRIND_HAPPY(); return 0; +#endif } diff --git a/test/test-tcp-write-in-a-row.c b/test/test-tcp-write-in-a-row.c index f04d48fcd68..f50e5186c09 100644 --- a/test/test-tcp-write-in-a-row.c +++ b/test/test-tcp-write-in-a-row.c @@ -114,7 +114,7 @@ static void start_server(void) { TEST_IMPL(tcp_write_in_a_row) { #if defined(_WIN32) RETURN_SKIP("tcp_write_in_a_row does not work on Windows"); -#endif +#else uv_connect_t connect_req; struct sockaddr_in addr; @@ -138,4 +138,5 @@ TEST_IMPL(tcp_write_in_a_row) { MAKE_VALGRIND_HAPPY(); return 0; +#endif } diff --git a/test/test-tty-escape-sequence-processing.c b/test/test-tty-escape-sequence-processing.c index 5f04291d244..e311c0f02d4 100644 --- a/test/test-tty-escape-sequence-processing.c +++ b/test/test-tty-escape-sequence-processing.c @@ -1043,6 +1043,11 @@ TEST_IMPL(tty_set_cursor_shape) { TEST_IMPL(tty_set_style) { +#if _MSC_VER >= 1920 && _MSC_VER <= 1929 + RETURN_SKIP("Broken on Microsoft Visual Studio 2019, to be investigated. " + "See: https://github.com/libuv/libuv/issues/3304"); +#else + uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos; @@ -1070,11 +1075,6 @@ TEST_IMPL(tty_set_style) { WORD attr; int i, length; -#if _MSC_VER >= 1920 && _MSC_VER <= 1929 - RETURN_SKIP("Broken on Microsoft Visual Studio 2019, to be investigated. " - "See: https://github.com/libuv/libuv/issues/3304"); -#endif - loop = uv_default_loop(); initialize_tty(&tty_out); @@ -1239,6 +1239,7 @@ TEST_IMPL(tty_set_style) { MAKE_VALGRIND_HAPPY(); return 0; +#endif } @@ -1345,6 +1346,10 @@ TEST_IMPL(tty_full_reset) { TEST_IMPL(tty_escape_sequence_processing) { +#if _MSC_VER >= 1920 && _MSC_VER <= 1929 + RETURN_SKIP("Broken on Microsoft Visual Studio 2019, to be investigated. " + "See: https://github.com/libuv/libuv/issues/3304"); +#else uv_tty_t tty_out; uv_loop_t* loop; COORD cursor_pos, cursor_pos_old; @@ -1353,11 +1358,6 @@ TEST_IMPL(tty_escape_sequence_processing) { struct captured_screen actual = {0}, expect = {0}; int dir; -#if _MSC_VER >= 1920 && _MSC_VER <= 1929 - RETURN_SKIP("Broken on Microsoft Visual Studio 2019, to be investigated. " - "See: https://github.com/libuv/libuv/issues/3304"); -#endif - loop = uv_default_loop(); initialize_tty(&tty_out); @@ -1622,6 +1622,7 @@ TEST_IMPL(tty_escape_sequence_processing) { MAKE_VALGRIND_HAPPY(); return 0; +#endif } #else From a3de1384c304553886c4e74dc82d9356df732cf8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 15 Dec 2022 12:57:14 +0100 Subject: [PATCH 284/713] linux: simplify uv_uptime() (#3859) Drop support for old kernels. Assume support for CLOCK_BOOTTIME. --- src/unix/linux.c | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index bbeb283d0de..11704b62bda 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -124,19 +124,6 @@ # include #endif /* HAVE_IFADDRS_H */ -/* Available from 2.6.32 onwards. */ -#ifndef CLOCK_MONOTONIC_COARSE -# define CLOCK_MONOTONIC_COARSE 6 -#endif - -/* This is rather annoying: CLOCK_BOOTTIME lives in but we can't - * include that file because it conflicts with . We'll just have to - * define it ourselves. - */ -#ifndef CLOCK_BOOTTIME -# define CLOCK_BOOTTIME 7 -#endif - #define CAST(p) ((struct watcher_root*)(p)) struct watcher_list { @@ -732,30 +719,18 @@ int uv_resident_set_memory(size_t* rss) { } int uv_uptime(double* uptime) { - static volatile int no_clock_boottime; - char buf[128]; struct timespec now; - int r; - - /* Try /proc/uptime first, then fallback to clock_gettime(). */ + char buf[128]; + /* Consult /proc/uptime when present (common case), or fall back to + * clock_gettime. Why not always clock_gettime? It doesn't always return the + * right result under OpenVZ and possibly other containerized environments. + */ if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf))) if (1 == sscanf(buf, "%lf", uptime)) return 0; - /* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available - * (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system - * is suspended. - */ - if (no_clock_boottime) { - retry_clock_gettime: r = clock_gettime(CLOCK_MONOTONIC, &now); - } - else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) { - no_clock_boottime = 1; - goto retry_clock_gettime; - } - - if (r) + if (clock_gettime(CLOCK_BOOTTIME, &now)) return UV__ERR(errno); *uptime = now.tv_sec; From d5cfb8995939bad0bd24c47f469f3b4f294305a0 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 21 Dec 2022 07:51:50 +0100 Subject: [PATCH 285/713] test: unflake fs_event_watch_dir test (#3863) Increase the timer interval. That hopefully ameliorates the problem of FSEvents.framework missing events on the macOS CI buildbot. Not really a fix, more a mitigation. Fixes: https://github.com/libuv/libuv/issues/3862 --- test/test-fs-event.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 03a29a7e8fb..db2966e178c 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -39,12 +39,6 @@ # endif #endif -#if defined(__arm__)/* Increase the timeout so the test passes on arm CI bots */ -# define CREATE_TIMEOUT 100 -#else -# define CREATE_TIMEOUT 1 -#endif - static uv_fs_event_t fs_event; static const char file_prefix[] = "fsevent-"; static const int fs_event_file_count = 16; @@ -162,10 +156,7 @@ static void fs_event_create_files(uv_timer_t* handle) { if (++fs_event_created < fs_event_file_count) { /* Create another file on a different event loop tick. We do it this way * to avoid fs events coalescing into one fs event. */ - ASSERT(0 == uv_timer_start(&timer, - fs_event_create_files, - CREATE_TIMEOUT, - 0)); + ASSERT_EQ(0, uv_timer_start(&timer, fs_event_create_files, 100, 0)); } } @@ -241,7 +232,8 @@ static void fs_event_create_files_in_subdir(uv_timer_t* handle) { if (++fs_event_created < fs_event_file_count) { /* Create another file on a different event loop tick. We do it this way * to avoid fs events coalescing into one fs event. */ - ASSERT(0 == uv_timer_start(&timer, fs_event_create_files_in_subdir, 1, 0)); + ASSERT_EQ(0, + uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0)); } } From e9d91fccfc3e5ff772d5da90e1c4a24061198ca0 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 22 Dec 2022 00:51:19 +0100 Subject: [PATCH 286/713] darwin: remove unused fsevents symbol lookups (#3867) One hasn't been in use since 2017, the other since 2013. --- src/unix/fsevents.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c index bf4f1f6a518..8b5b3d5b160 100644 --- a/src/unix/fsevents.c +++ b/src/unix/fsevents.c @@ -132,7 +132,6 @@ static void (*pCFRunLoopWakeUp)(CFRunLoopRef); static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)( CFAllocatorRef, const char*); -static CFStringEncoding (*pCFStringGetSystemEncoding)(void); static CFStringRef (*pkCFRunLoopDefaultMode); static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef, FSEventStreamCallback, @@ -141,7 +140,6 @@ static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef, FSEventStreamEventId, CFTimeInterval, FSEventStreamCreateFlags); -static void (*pFSEventStreamFlushSync)(FSEventStreamRef); static void (*pFSEventStreamInvalidate)(FSEventStreamRef); static void (*pFSEventStreamRelease)(FSEventStreamRef); static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef, @@ -563,10 +561,8 @@ static int uv__fsevents_global_init(void) { V(core_foundation_handle, CFRunLoopStop); V(core_foundation_handle, CFRunLoopWakeUp); V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation); - V(core_foundation_handle, CFStringGetSystemEncoding); V(core_foundation_handle, kCFRunLoopDefaultMode); V(core_services_handle, FSEventStreamCreate); - V(core_services_handle, FSEventStreamFlushSync); V(core_services_handle, FSEventStreamInvalidate); V(core_services_handle, FSEventStreamRelease); V(core_services_handle, FSEventStreamScheduleWithRunLoop); From 12b8c116a42eb0619d32329e8246e78d844fe0f4 Mon Sep 17 00:00:00 2001 From: Zvicii Date: Wed, 4 Jan 2023 05:03:37 +0800 Subject: [PATCH 287/713] build: add define guard around UV_EXTERN (#3855) Incidentally lets users control the definition of UV_EXTERN. --- include/uv.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uv.h b/include/uv.h index 7189951f3e4..045371aa916 100644 --- a/include/uv.h +++ b/include/uv.h @@ -31,6 +31,7 @@ extern "C" { #error "Define either BUILDING_UV_SHARED or USING_UV_SHARED, not both." #endif +#ifndef UV_EXTERN #ifdef _WIN32 /* Windows - set up dll import/export decorators. */ # if defined(BUILDING_UV_SHARED) @@ -50,6 +51,7 @@ extern "C" { #else # define UV_EXTERN /* nothing */ #endif +#endif /* UV_EXTERN */ #include "uv/errno.h" #include "uv/version.h" From e972c6705f197e12d211b598fc514bbea051425d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 4 Jan 2023 23:43:50 +0100 Subject: [PATCH 288/713] build: add UndefinedBehaviorSanitizer support (#3870) - add UBSAN build option - turn on UBSAN CI build Fixes: https://github.com/libuv/libuv/issues/3869 --- .github/workflows/sanitizer.yml | 9 +++++++++ CMakeLists.txt | 14 ++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index d4b04aa1c24..2ebb8e1709f 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -50,3 +50,12 @@ jobs: continue-on-error: true # currently permit failures run: | ./build-tsan/uv_run_tests_a + + - name: UBSAN Build + run: | + mkdir build-ubsan + (cd build-ubsan && cmake .. -G Ninja -DBUILD_TESTING=ON -DUBSAN=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang) + cmake --build build-ubsan + - name: UBSAN Test + run: | + ./build-ubsan/uv_run_tests_a diff --git a/CMakeLists.txt b/CMakeLists.txt index 6502f6e65b7..f53b1a966cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ endif() option(ASAN "Enable AddressSanitizer (ASan)" OFF) option(MSAN "Enable MemorySanitizer (MSan)" OFF) option(TSAN "Enable ThreadSanitizer (TSan)" OFF) +option(UBSAN "Enable UndefinedBehaviorSanitizer (UBSan)" OFF) if(MSAN AND NOT CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang") message(SEND_ERROR "MemorySanitizer requires clang. Try again with -DCMAKE_C_COMPILER=clang") @@ -79,6 +80,19 @@ if(TSAN) endif() endif() +if(UBSAN) + list(APPEND uv_defines __UBSAN__=1) + if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=undefined") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=undefined") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=undefined") + elseif(MSVC) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=undefined") + else() + message(SEND_ERROR "UndefinedBehaviorSanitizer support requires clang, gcc, or msvc. Try again with -DCMAKE_C_COMPILER.") + endif() +endif() + # Compiler check string(CONCAT is-msvc $, From 5ee455ffc296e8afbe1e253b44e4f9436f9e9b08 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 12 Jan 2023 15:22:19 +0100 Subject: [PATCH 289/713] build: enable platform_output test on qemu (#3878) The test was disabled because of a qemu bug that is presumed to have since been fixed. Refs: https://github.com/libuv/libuv/pull/3861 --- test/test-platform-output.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/test-platform-output.c b/test/test-platform-output.c index 5827dca1cb2..4c2d77c9500 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -25,11 +25,6 @@ TEST_IMPL(platform_output) { -/* TODO(gengjiawen): Fix test on QEMU. */ -#if defined(__QEMU__) - RETURN_SKIP("Test does not currently work in QEMU"); -#endif - char buffer[512]; size_t rss; size_t size; From 434eb4b0ac29e853e85562119fda3fa681642f17 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 14 Jan 2023 05:08:15 +0100 Subject: [PATCH 290/713] linux: handle cpu hotplugging in uv_cpu_info() (#3861) On Linux, CPUs can come online or go offline while uv_cpu_info() is busy gathering data. Change uv_cpu_info() in the following ways: 1. Learn online CPUs from /proc/stat 2. Get the model name from /proc/cpuinfo when it has a matching CPU, or default to "unknown" 3. Get speed from /sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq when it exists, or default to 0 Before this commit, libuv read the speed from /proc/cpuinfo but that reports the base frequency, not the actual frequency. My system has two cores running permanently at 3.6 GHz but libuv thought all 12 ran at 2.2 GHz. Fixes: https://github.com/libuv/libuv/issues/2351 Fixes: https://github.com/libuv/libuv/issues/3858 --- src/unix/linux.c | 503 ++++++++++++++++------------------------------- src/uv-common.c | 5 + src/uv-common.h | 1 + 3 files changed, 173 insertions(+), 336 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 11704b62bda..049ef1f9cd7 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -145,12 +145,6 @@ static int compare_watchers(const struct watcher_list* a, const struct watcher_list* b); static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop); -static int read_models(unsigned int numcpus, uv_cpu_info_t* ci); -static int read_times(FILE* statfile_fp, - unsigned int numcpus, - uv_cpu_info_t* ci); -static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); -static uint64_t read_cpufreq(unsigned int cpunum); RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers) @@ -738,376 +732,213 @@ int uv_uptime(double* uptime) { } -static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { - unsigned int num; +int uv_cpu_info(uv_cpu_info_t** ci, int* count) { +#if defined(__PPC__) + static const char model_marker[] = "cpu\t\t: "; +#elif defined(__arm__) + static const char model_marker[] = "Processor\t: "; +#elif defined(__aarch64__) + static const char model_marker[] = "CPU part\t: "; +#elif defined(__mips__) + static const char model_marker[] = "cpu model\t\t: "; +#else + static const char model_marker[] = "model name\t: "; +#endif + static const char parts[] = +#ifdef __aarch64__ + "0x811\nARM810\n" "0x920\nARM920\n" "0x922\nARM922\n" + "0x926\nARM926\n" "0x940\nARM940\n" "0x946\nARM946\n" + "0x966\nARM966\n" "0xa20\nARM1020\n" "0xa22\nARM1022\n" + "0xa26\nARM1026\n" "0xb02\nARM11 MPCore\n" "0xb36\nARM1136\n" + "0xb56\nARM1156\n" "0xb76\nARM1176\n" "0xc05\nCortex-A5\n" + "0xc07\nCortex-A7\n" "0xc08\nCortex-A8\n" "0xc09\nCortex-A9\n" + "0xc0d\nCortex-A17\n" /* Originally A12 */ + "0xc0f\nCortex-A15\n" "0xc0e\nCortex-A17\n" "0xc14\nCortex-R4\n" + "0xc15\nCortex-R5\n" "0xc17\nCortex-R7\n" "0xc18\nCortex-R8\n" + "0xc20\nCortex-M0\n" "0xc21\nCortex-M1\n" "0xc23\nCortex-M3\n" + "0xc24\nCortex-M4\n" "0xc27\nCortex-M7\n" "0xc60\nCortex-M0+\n" + "0xd01\nCortex-A32\n" "0xd03\nCortex-A53\n" "0xd04\nCortex-A35\n" + "0xd05\nCortex-A55\n" "0xd06\nCortex-A65\n" "0xd07\nCortex-A57\n" + "0xd08\nCortex-A72\n" "0xd09\nCortex-A73\n" "0xd0a\nCortex-A75\n" + "0xd0b\nCortex-A76\n" "0xd0c\nNeoverse-N1\n" "0xd0d\nCortex-A77\n" + "0xd0e\nCortex-A76AE\n" "0xd13\nCortex-R52\n" "0xd20\nCortex-M23\n" + "0xd21\nCortex-M33\n" "0xd41\nCortex-A78\n" "0xd42\nCortex-A78AE\n" + "0xd4a\nNeoverse-E1\n" "0xd4b\nCortex-A78C\n" +#endif + ""; + struct cpu { + unsigned long long freq, user, nice, sys, idle, irq; + unsigned model; + }; + FILE* fp; + char* p; + int found; + int n; + unsigned i; + unsigned cpu; + unsigned maxcpu; + unsigned size; + unsigned long long skip; + struct cpu (*cpus)[8192]; /* Kernel maximum. */ + struct cpu* c; + struct cpu t; + char (*model)[64]; + unsigned char bitmap[ARRAY_SIZE(*cpus) / 8]; + /* Assumption: even big.LITTLE systems will have only a handful + * of different CPU models. Most systems will just have one. + */ + char models[8][64]; char buf[1024]; - if (!fgets(buf, sizeof(buf), statfile_fp)) - return UV_EIO; + memset(bitmap, 0, sizeof(bitmap)); + memset(models, 0, sizeof(models)); + snprintf(*models, sizeof(*models), "unknown"); + maxcpu = 0; - num = 0; - while (fgets(buf, sizeof(buf), statfile_fp)) { - if (strncmp(buf, "cpu", 3)) - break; - num++; - } - - if (num == 0) - return UV_EIO; - - *numcpus = num; - return 0; -} - - -int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { - unsigned int numcpus; - uv_cpu_info_t* ci; - int err; - FILE* statfile_fp; - - *cpu_infos = NULL; - *count = 0; + cpus = uv__calloc(ARRAY_SIZE(*cpus), sizeof(**cpus)); + if (cpus == NULL) + return UV_ENOMEM; - statfile_fp = uv__open_file("/proc/stat"); - if (statfile_fp == NULL) + fp = uv__open_file("/proc/stat"); + if (fp == NULL) { + uv__free(cpus); return UV__ERR(errno); - - err = uv__cpu_num(statfile_fp, &numcpus); - if (err < 0) - goto out; - - err = UV_ENOMEM; - ci = uv__calloc(numcpus, sizeof(*ci)); - if (ci == NULL) - goto out; - - err = read_models(numcpus, ci); - if (err == 0) - err = read_times(statfile_fp, numcpus, ci); - - if (err) { - uv_free_cpu_info(ci, numcpus); - goto out; } - /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo. - * We don't check for errors here. Worst case, the field is left zero. - */ - if (ci[0].speed == 0) - read_speeds(numcpus, ci); - - *cpu_infos = ci; - *count = numcpus; - err = 0; + fgets(buf, sizeof(buf), fp); /* Skip first line. */ -out: + for (;;) { + memset(&t, 0, sizeof(t)); - if (fclose(statfile_fp)) - if (errno != EINTR && errno != EINPROGRESS) - abort(); + n = fscanf(fp, "cpu%u %llu %llu %llu %llu %llu %llu", + &cpu, &t.user, &t.nice, &t.sys, &t.idle, &skip, &t.irq); - return err; -} + if (n != 7) + break; + fgets(buf, sizeof(buf), fp); /* Skip rest of line. */ -static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) { - unsigned int num; + if (cpu >= ARRAY_SIZE(*cpus)) + continue; - for (num = 0; num < numcpus; num++) - ci[num].speed = read_cpufreq(num) / 1000; -} + (*cpus)[cpu] = t; + bitmap[cpu >> 3] |= 1 << (cpu & 7); -/* Also reads the CPU frequency on ppc and x86. The other architectures only - * have a BogoMIPS field, which may not be very accurate. - * - * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup. - */ -static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { -#if defined(__PPC__) - static const char model_marker[] = "cpu\t\t: "; - static const char speed_marker[] = "clock\t\t: "; -#else - static const char model_marker[] = "model name\t: "; - static const char speed_marker[] = "cpu MHz\t\t: "; -#endif - const char* inferred_model; - unsigned int model_idx; - unsigned int speed_idx; - unsigned int part_idx; - char buf[1024]; - char* model; - FILE* fp; - int model_id; - - /* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */ - (void) &model_marker; - (void) &speed_marker; - (void) &speed_idx; - (void) &part_idx; - (void) &model; - (void) &buf; - (void) &fp; - (void) &model_id; - - model_idx = 0; - speed_idx = 0; - part_idx = 0; - -#if defined(__arm__) || \ - defined(__i386__) || \ - defined(__mips__) || \ - defined(__aarch64__) || \ - defined(__PPC__) || \ - defined(__x86_64__) - fp = uv__open_file("/proc/cpuinfo"); - if (fp == NULL) - return UV__ERR(errno); - - while (fgets(buf, sizeof(buf), fp)) { - if (model_idx < numcpus) { - if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) { - model = buf + sizeof(model_marker) - 1; - model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */ - if (model == NULL) { - fclose(fp); - return UV_ENOMEM; - } - ci[model_idx++].model = model; - continue; - } - } -#if defined(__arm__) || defined(__mips__) || defined(__aarch64__) - if (model_idx < numcpus) { -#if defined(__arm__) - /* Fallback for pre-3.8 kernels. */ - static const char model_marker[] = "Processor\t: "; -#elif defined(__aarch64__) - static const char part_marker[] = "CPU part\t: "; - - /* Adapted from: https://github.com/karelzak/util-linux */ - struct vendor_part { - const int id; - const char* name; - }; - - static const struct vendor_part arm_chips[] = { - { 0x811, "ARM810" }, - { 0x920, "ARM920" }, - { 0x922, "ARM922" }, - { 0x926, "ARM926" }, - { 0x940, "ARM940" }, - { 0x946, "ARM946" }, - { 0x966, "ARM966" }, - { 0xa20, "ARM1020" }, - { 0xa22, "ARM1022" }, - { 0xa26, "ARM1026" }, - { 0xb02, "ARM11 MPCore" }, - { 0xb36, "ARM1136" }, - { 0xb56, "ARM1156" }, - { 0xb76, "ARM1176" }, - { 0xc05, "Cortex-A5" }, - { 0xc07, "Cortex-A7" }, - { 0xc08, "Cortex-A8" }, - { 0xc09, "Cortex-A9" }, - { 0xc0d, "Cortex-A17" }, /* Originally A12 */ - { 0xc0f, "Cortex-A15" }, - { 0xc0e, "Cortex-A17" }, - { 0xc14, "Cortex-R4" }, - { 0xc15, "Cortex-R5" }, - { 0xc17, "Cortex-R7" }, - { 0xc18, "Cortex-R8" }, - { 0xc20, "Cortex-M0" }, - { 0xc21, "Cortex-M1" }, - { 0xc23, "Cortex-M3" }, - { 0xc24, "Cortex-M4" }, - { 0xc27, "Cortex-M7" }, - { 0xc60, "Cortex-M0+" }, - { 0xd01, "Cortex-A32" }, - { 0xd03, "Cortex-A53" }, - { 0xd04, "Cortex-A35" }, - { 0xd05, "Cortex-A55" }, - { 0xd06, "Cortex-A65" }, - { 0xd07, "Cortex-A57" }, - { 0xd08, "Cortex-A72" }, - { 0xd09, "Cortex-A73" }, - { 0xd0a, "Cortex-A75" }, - { 0xd0b, "Cortex-A76" }, - { 0xd0c, "Neoverse-N1" }, - { 0xd0d, "Cortex-A77" }, - { 0xd0e, "Cortex-A76AE" }, - { 0xd13, "Cortex-R52" }, - { 0xd20, "Cortex-M23" }, - { 0xd21, "Cortex-M33" }, - { 0xd41, "Cortex-A78" }, - { 0xd42, "Cortex-A78AE" }, - { 0xd4a, "Neoverse-E1" }, - { 0xd4b, "Cortex-A78C" }, - }; - - if (strncmp(buf, part_marker, sizeof(part_marker) - 1) == 0) { - model = buf + sizeof(part_marker) - 1; - - errno = 0; - model_id = strtol(model, NULL, 16); - if ((errno != 0) || model_id < 0) { - fclose(fp); - return UV_EINVAL; - } - - for (part_idx = 0; part_idx < ARRAY_SIZE(arm_chips); part_idx++) { - if (model_id == arm_chips[part_idx].id) { - model = uv__strdup(arm_chips[part_idx].name); - if (model == NULL) { - fclose(fp); - return UV_ENOMEM; - } - ci[model_idx++].model = model; - break; - } - } - } -#else /* defined(__mips__) */ - static const char model_marker[] = "cpu model\t\t: "; -#endif - if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) { - model = buf + sizeof(model_marker) - 1; - model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */ - if (model == NULL) { - fclose(fp); - return UV_ENOMEM; - } - ci[model_idx++].model = model; - continue; - } - } -#else /* !__arm__ && !__mips__ && !__aarch64__ */ - if (speed_idx < numcpus) { - if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) { - ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1); - continue; - } - } -#endif /* __arm__ || __mips__ || __aarch64__ */ + if (cpu >= maxcpu) + maxcpu = cpu + 1; } fclose(fp); -#endif /* __arm__ || __i386__ || __mips__ || __PPC__ || __x86_64__ || __aarch__ */ - /* Now we want to make sure that all the models contain *something* because - * it's not safe to leave them as null. Copy the last entry unless there - * isn't one, in that case we simply put "unknown" into everything. - */ - inferred_model = "unknown"; - if (model_idx > 0) - inferred_model = ci[model_idx - 1].model; - - while (model_idx < numcpus) { - model = uv__strndup(inferred_model, strlen(inferred_model)); - if (model == NULL) - return UV_ENOMEM; - ci[model_idx++].model = model; - } + fp = uv__open_file("/proc/cpuinfo"); + if (fp == NULL) + goto nocpuinfo; - return 0; -} + for (;;) { + 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); + + if (!found) + goto next; + + p = buf + sizeof(model_marker) - 1; + n = (int) strcspn(p, "\n"); + + /* arm64: translate CPU part code to model name. */ + if (*parts) { + p = memmem(parts, sizeof(parts) - 1, p, n + 1); + if (p == NULL) + p = "unknown"; + else + p += n + 1; + n = (int) strcspn(p, "\n"); + } + found = 0; + for (model = models; !found && model < ARRAY_END(models); model++) + found = !strncmp(p, *model, strlen(*model)); -static int read_times(FILE* statfile_fp, - unsigned int numcpus, - uv_cpu_info_t* ci) { - struct uv_cpu_times_s ts; - unsigned int ticks; - unsigned int multiplier; - uint64_t user; - uint64_t nice; - uint64_t sys; - uint64_t idle; - uint64_t dummy; - uint64_t irq; - uint64_t num; - uint64_t len; - char buf[1024]; + if (!found) + goto next; - ticks = (unsigned int)sysconf(_SC_CLK_TCK); - assert(ticks != (unsigned int) -1); - assert(ticks != 0); - multiplier = ((uint64_t)1000L / ticks); + if (**model == '\0') + snprintf(*model, sizeof(*model), "%.*s", n, p); - rewind(statfile_fp); + if (cpu < maxcpu) + (*cpus)[cpu].model = model - models; - if (!fgets(buf, sizeof(buf), statfile_fp)) - abort(); +next: + while (fgets(buf, sizeof(buf), fp)) + if (*buf == '\n') + break; + } - num = 0; + fclose(fp); + fp = NULL; - while (fgets(buf, sizeof(buf), statfile_fp)) { - if (num >= numcpus) - break; +nocpuinfo: - if (strncmp(buf, "cpu", 3)) - break; + n = 0; + for (cpu = 0; cpu < maxcpu; cpu++) { + if (!(bitmap[cpu >> 3] & (1 << (cpu & 7)))) + continue; - /* skip "cpu " marker */ - { - unsigned int n; - int r = sscanf(buf, "cpu%u ", &n); - assert(r == 1); - (void) r; /* silence build warning */ - for (len = sizeof("cpu0"); n /= 10; len++); - } + n++; + snprintf(buf, sizeof(buf), + "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", cpu); - /* Line contains user, nice, system, idle, iowait, irq, softirq, steal, - * guest, guest_nice but we're only interested in the first four + irq. - * - * Don't use %*s to skip fields or %ll to read straight into the uint64_t - * fields, they're not allowed in C89 mode. - */ - if (6 != sscanf(buf + len, - "%" PRIu64 " %" PRIu64 " %" PRIu64 - "%" PRIu64 " %" PRIu64 " %" PRIu64, - &user, - &nice, - &sys, - &idle, - &dummy, - &irq)) - abort(); + fp = uv__open_file(buf); + if (fp == NULL) + continue; - ts.user = user * multiplier; - ts.nice = nice * multiplier; - ts.sys = sys * multiplier; - ts.idle = idle * multiplier; - ts.irq = irq * multiplier; - ci[num++].cpu_times = ts; + fscanf(fp, "%llu", &(*cpus)[cpu].freq); + fclose(fp); + fp = NULL; } - assert(num == numcpus); - return 0; -} + size = n * sizeof(**ci) + sizeof(models); + *ci = uv__malloc(size); + *count = 0; + if (*ci == NULL) { + uv__free(cpus); + return UV_ENOMEM; + } -static uint64_t read_cpufreq(unsigned int cpunum) { - uint64_t val; - char buf[1024]; - FILE* fp; + *count = n; + p = memcpy(*ci + n, models, sizeof(models)); - snprintf(buf, - sizeof(buf), - "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", - cpunum); + i = 0; + for (cpu = 0; cpu < maxcpu; cpu++) { + if (!(bitmap[cpu >> 3] & (1 << (cpu & 7)))) + continue; - fp = uv__open_file(buf); - if (fp == NULL) - return 0; + c = *cpus + cpu; - if (fscanf(fp, "%" PRIu64, &val) != 1) - val = 0; + (*ci)[i++] = (uv_cpu_info_t) { + .model = p + c->model * sizeof(*model), + .speed = c->freq / 1000, + /* Note: sysconf(_SC_CLK_TCK) is fixed at 100 Hz, + * therefore the multiplier is always 1000/100 = 10. + */ + .cpu_times = (struct uv_cpu_times_s) { + .user = 10 * c->user, + .nice = 10 * c->nice, + .sys = 10 * c->sys, + .idle = 10 * c->idle, + .irq = 10 * c->irq, + }, + }; + } - fclose(fp); + uv__free(cpus); - return val; + return 0; } diff --git a/src/uv-common.c b/src/uv-common.c index df8b8b714d4..c87bd2e8748 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -887,12 +887,17 @@ void uv_os_free_environ(uv_env_item_t* envitems, int count) { void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { +#ifdef __linux__ + (void) &count; + uv__free(cpu_infos); +#else int i; for (i = 0; i < count; i++) uv__free(cpu_infos[i].model); uv__free(cpu_infos); +#endif /* __linux__ */ } diff --git a/src/uv-common.h b/src/uv-common.h index 3b0370c7d29..6c537e9e8eb 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -48,6 +48,7 @@ extern int snprintf(char*, size_t, const char*, ...); #endif #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define ARRAY_END(a) ((a) + ARRAY_SIZE(a)) #define container_of(ptr, type, member) \ ((type *) ((char *) (ptr) - offsetof(type, member))) From 39f9189f345d0661af64d6f29b47d19f3cd70c0c Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 14 Jan 2023 11:12:51 +0100 Subject: [PATCH 291/713] build: remove unnecessary policy setting (#3873) All cmake policies up to CMP0065 are set to NEW by default since the minimum required version is 3.4. --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f53b1a966cd..1e20b42bc3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,5 @@ cmake_minimum_required(VERSION 3.4) -cmake_policy(SET CMP0057 NEW) # Enable IN_LIST operator -cmake_policy(SET CMP0064 NEW) # Support if (TEST) operator if(POLICY CMP0091) cmake_policy(SET CMP0091 NEW) # Enable MSVC_RUNTIME_LIBRARY setting endif() From 1279a20c03651f56847b8467827170ae0c4776cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jack=C2=B7Boos=C2=B7Yu?= <47264268+JackBoosY@users.noreply.github.com> Date: Wed, 18 Jan 2023 10:54:36 +0800 Subject: [PATCH 292/713] docs: add vcpkg instruction step (#3747) Co-authored-by: JackBoosY --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 06486febc28..eb126f7b3c9 100644 --- a/README.md +++ b/README.md @@ -220,6 +220,15 @@ Make sure that you specify the architecture you wish to build for in the "ARCHS" flag. You can specify more than one by delimiting with a space (e.g. "x86_64 i386"). +### Install with vcpkg + +```bash +$ git clone https://github.com/microsoft/vcpkg.git +$ ./bootstrap-vcpkg.bat # for powershell +$ ./bootstrap-vcpkg.sh # for bash +$ ./vcpkg install libuv +``` + ### Running tests Some tests are timing sensitive. Relaxing test timeouts may be necessary From 7fd7e8264f4430e642ac21dc386aed2f99f5f567 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Wed, 18 Jan 2023 08:34:52 +0530 Subject: [PATCH 293/713] win,fs: fix readlink errno for a non-symlink file (#3719) In Node.js, fs.readlink() on a non-symlink file used to throw an UNKNOWN error on Windows. This change maps ERROR_NOT_A_REPARSE_POINT to UV_EINVAL, so that now it throws EINVAL just like other platforms. This is handled explicitly in `fs__readlink`, since elsewhere it might map to EPERM instead (such as in `link`). --- src/win/fs.c | 5 ++++- test/test-fs.c | 57 +++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index efc2393424a..1f813c3e2bb 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -2662,7 +2662,10 @@ static void fs__readlink(uv_fs_t* req) { } if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) { - SET_REQ_WIN32_ERROR(req, GetLastError()); + DWORD error = GetLastError(); + SET_REQ_WIN32_ERROR(req, error); + if (error == ERROR_NOT_A_REPARSE_POINT) + req->result = UV_EINVAL; CloseHandle(handle); return; } diff --git a/test/test-fs.c b/test/test-fs.c index ebf410504da..3d7b700845c 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2047,20 +2047,53 @@ TEST_IMPL(fs_link) { TEST_IMPL(fs_readlink) { - uv_fs_t req; + /* Must return UV_ENOENT on an inexistent file */ + { + uv_fs_t req; - loop = uv_default_loop(); - ASSERT(0 == uv_fs_readlink(loop, &req, "no_such_file", dummy_cb)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(dummy_cb_count == 1); - ASSERT_NULL(req.ptr); - ASSERT(req.result == UV_ENOENT); - uv_fs_req_cleanup(&req); + loop = uv_default_loop(); + ASSERT(0 == uv_fs_readlink(loop, &req, "no_such_file", dummy_cb)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(dummy_cb_count == 1); + ASSERT_NULL(req.ptr); + ASSERT(req.result == UV_ENOENT); + uv_fs_req_cleanup(&req); - ASSERT(UV_ENOENT == uv_fs_readlink(NULL, &req, "no_such_file", NULL)); - ASSERT_NULL(req.ptr); - ASSERT(req.result == UV_ENOENT); - uv_fs_req_cleanup(&req); + ASSERT(UV_ENOENT == uv_fs_readlink(NULL, &req, "no_such_file", NULL)); + ASSERT_NULL(req.ptr); + ASSERT(req.result == UV_ENOENT); + uv_fs_req_cleanup(&req); + } + + /* Must return UV_EINVAL on a non-symlink file */ + { + int r; + uv_fs_t req; + uv_file file; + + /* Setup */ + + /* Create a non-symlink file */ + r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); + file = req.result; + uv_fs_req_cleanup(&req); + + r = uv_fs_close(NULL, &req, file, NULL); + ASSERT_EQ(r, 0); + ASSERT_EQ(req.result, 0); + uv_fs_req_cleanup(&req); + + /* Test */ + r = uv_fs_readlink(NULL, &req, "test_file", NULL); + ASSERT_EQ(r, UV_EINVAL); + uv_fs_req_cleanup(&req); + + /* Cleanup */ + unlink("test_file"); + } MAKE_VALGRIND_HAPPY(); return 0; From 2f110a50dfc7cfa60b9b8345473aba7a0bba5a19 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 17 Jan 2023 21:51:28 -0600 Subject: [PATCH 294/713] misc: extend getpw to take uid as an argument (#3523) File system operations may return uid and gid values, which we may want to pretty-print. We already have the code for getting information for the current user, so just need to add a parameter to make it exposed for every user. We expose information about groups in a similar manner also. --- include/uv.h | 10 +++ src/unix/core.c | 106 +++++++++++++++++++++++++------ src/unix/internal.h | 1 - src/uv-common.c | 33 ++++++++++ src/win/internal.h | 1 - src/win/util.c | 27 ++++---- test/test-get-passwd.c | 121 +++++++++++++++++++++++++++++++++--- test/test-list.h | 4 ++ test/test-platform-output.c | 31 ++++++++- 9 files changed, 286 insertions(+), 48 deletions(-) diff --git a/include/uv.h b/include/uv.h index 045371aa916..e6724deffdf 100644 --- a/include/uv.h +++ b/include/uv.h @@ -245,6 +245,7 @@ typedef struct uv_cpu_info_s uv_cpu_info_t; typedef struct uv_interface_address_s uv_interface_address_t; typedef struct uv_dirent_s uv_dirent_t; typedef struct uv_passwd_s uv_passwd_t; +typedef struct uv_group_s uv_group_t; typedef struct uv_utsname_s uv_utsname_t; typedef struct uv_statfs_s uv_statfs_t; @@ -1139,6 +1140,12 @@ struct uv_passwd_s { char* homedir; }; +struct uv_group_s { + char* groupname; + unsigned long gid; + char** members; +}; + struct uv_utsname_s { char sysname[256]; char release[256]; @@ -1219,6 +1226,9 @@ UV_EXTERN int uv_os_homedir(char* buffer, size_t* size); UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size); UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd); UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); +UV_EXTERN int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid); +UV_EXTERN int uv_os_get_group(uv_group_t* grp, uv_uid_t gid); +UV_EXTERN void uv_os_free_group(uv_group_t* grp); UV_EXTERN uv_pid_t uv_os_getpid(void); UV_EXTERN uv_pid_t uv_os_getppid(void); diff --git a/src/unix/core.c b/src/unix/core.c index bb9226afc8d..706dcccb647 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -41,12 +41,12 @@ #include /* writev */ #include /* getrusage */ #include +#include #include #include #ifdef __sun # include -# include # include #endif @@ -1097,8 +1097,8 @@ int uv_os_homedir(char* buffer, size_t* size) { if (r != UV_ENOENT) return r; - /* HOME is not set, so call uv__getpwuid_r() */ - r = uv__getpwuid_r(&pwd); + /* HOME is not set, so call uv_os_get_passwd() */ + r = uv_os_get_passwd(&pwd); if (r != 0) { return r; @@ -1171,11 +1171,10 @@ int uv_os_tmpdir(char* buffer, size_t* size) { } -int uv__getpwuid_r(uv_passwd_t* pwd) { +static int uv__getpwuid_r(uv_passwd_t *pwd, uid_t uid) { struct passwd pw; struct passwd* result; char* buf; - uid_t uid; size_t bufsize; size_t name_size; size_t homedir_size; @@ -1185,8 +1184,6 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { if (pwd == NULL) return UV_EINVAL; - uid = geteuid(); - /* Calling sysconf(_SC_GETPW_R_SIZE_MAX) would get the suggested size, but it * is frequently 1024 or 4096, so we can just use that directly. The pwent * will not usually be large. */ @@ -1245,24 +1242,93 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { } -void uv_os_free_passwd(uv_passwd_t* pwd) { - if (pwd == NULL) - return; +int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) { + struct group gp; + struct group* result; + char* buf; + char* gr_mem; + size_t bufsize; + size_t name_size; + long members; + size_t mem_size; + int r; - /* - The memory for name, shell, and homedir are allocated in a single - uv__malloc() call. The base of the pointer is stored in pwd->username, so - that is the field that needs to be freed. - */ - uv__free(pwd->username); - pwd->username = NULL; - pwd->shell = NULL; - pwd->homedir = NULL; + if (grp == NULL) + return UV_EINVAL; + + /* Calling sysconf(_SC_GETGR_R_SIZE_MAX) would get the suggested size, but it + * is frequently 1024 or 4096, so we can just use that directly. The pwent + * will not usually be large. */ + for (bufsize = 2000;; bufsize *= 2) { + buf = uv__malloc(bufsize); + + if (buf == NULL) + return UV_ENOMEM; + + do + r = getgrgid_r(gid, &gp, buf, bufsize, &result); + while (r == EINTR); + + if (r != 0 || result == NULL) + uv__free(buf); + + if (r != ERANGE) + break; + } + + if (r != 0) + return UV__ERR(r); + + if (result == NULL) + return UV_ENOENT; + + /* Allocate memory for the groupname and members. */ + name_size = strlen(gp.gr_name) + 1; + members = 0; + mem_size = sizeof(char*); + for (r = 0; gp.gr_mem[r] != NULL; r++) { + mem_size += strlen(gp.gr_mem[r]) + 1 + sizeof(char*); + members++; + } + + gr_mem = uv__malloc(name_size + mem_size); + if (gr_mem == NULL) { + uv__free(buf); + return UV_ENOMEM; + } + + /* Copy the members */ + grp->members = (char**) gr_mem; + grp->members[members] = NULL; + gr_mem = (char*) &grp->members[members + 1]; + for (r = 0; r < members; r++) { + grp->members[r] = gr_mem; + strcpy(gr_mem, gp.gr_mem[r]); + gr_mem += strlen(gr_mem) + 1; + } + assert(gr_mem == (char*)grp->members + mem_size); + + /* Copy the groupname */ + grp->groupname = gr_mem; + memcpy(grp->groupname, gp.gr_name, name_size); + gr_mem += name_size; + + /* Copy the gid */ + grp->gid = gp.gr_gid; + + uv__free(buf); + + return 0; } int uv_os_get_passwd(uv_passwd_t* pwd) { - return uv__getpwuid_r(pwd); + return uv__getpwuid_r(pwd, geteuid()); +} + + +int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid) { + return uv__getpwuid_r(pwd, uid); } diff --git a/src/unix/internal.h b/src/unix/internal.h index e83526db0a9..5497ee369dd 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -312,7 +312,6 @@ size_t uv__thread_stack_size(void); void uv__udp_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle); FILE* uv__open_file(const char* path); -int uv__getpwuid_r(uv_passwd_t* pwd); int uv__search_path(const char* prog, char* buf, size_t* buflen); void uv__wait_children(uv_loop_t* loop); diff --git a/src/uv-common.c b/src/uv-common.c index c87bd2e8748..1031be4a118 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -128,6 +128,39 @@ int uv_replace_allocator(uv_malloc_func malloc_func, return 0; } + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + /* On unix, the memory for name, shell, and homedir are allocated in a single + * uv__malloc() call. The base of the pointer is stored in pwd->username, so + * that is the field that needs to be freed. + */ + uv__free(pwd->username); +#ifdef _WIN32 + uv__free(pwd->homedir); +#endif + pwd->username = NULL; + pwd->shell = NULL; + pwd->homedir = NULL; +} + + +void uv_os_free_group(uv_group_t *grp) { + if (grp == NULL) + return; + + /* The memory for is allocated in a single uv__malloc() call. The base of the + * pointer is stored in grp->members, so that is the only field that needs to + * be freed. + */ + uv__free(grp->members); + grp->members = NULL; + grp->groupname = NULL; +} + + #define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t); size_t uv_handle_size(uv_handle_type type) { diff --git a/src/win/internal.h b/src/win/internal.h index 8a87743b352..1b524b5cd92 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -269,7 +269,6 @@ void uv__util_init(void); uint64_t uv__hrtime(unsigned int scale); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); -int uv__getpwuid_r(uv_passwd_t* pwd); int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16); diff --git a/src/win/util.c b/src/win/util.c index 094a414c055..647d6e66572 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -999,8 +999,8 @@ int uv_os_homedir(char* buffer, size_t* size) { if (r != UV_ENOENT) return r; - /* USERPROFILE is not set, so call uv__getpwuid_r() */ - r = uv__getpwuid_r(&pwd); + /* USERPROFILE is not set, so call uv_os_get_passwd() */ + r = uv_os_get_passwd(&pwd); if (r != 0) { return r; @@ -1087,17 +1087,6 @@ int uv_os_tmpdir(char* buffer, size_t* size) { } -void uv_os_free_passwd(uv_passwd_t* pwd) { - if (pwd == NULL) - return; - - uv__free(pwd->username); - uv__free(pwd->homedir); - pwd->username = NULL; - pwd->homedir = NULL; -} - - /* * Converts a UTF-16 string into a UTF-8 one. The resulting string is * null-terminated. @@ -1194,7 +1183,7 @@ int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) { } -int uv__getpwuid_r(uv_passwd_t* pwd) { +static int uv__getpwuid_r(uv_passwd_t* pwd) { HANDLE token; wchar_t username[UNLEN + 1]; wchar_t *path; @@ -1272,6 +1261,16 @@ int uv_os_get_passwd(uv_passwd_t* pwd) { } +int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid) { + return UV_ENOTSUP; +} + + +int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) { + return UV_ENOTSUP; +} + + int uv_os_environ(uv_env_item_t** envitems, int* count) { wchar_t* env; wchar_t* penv; diff --git a/test/test-get-passwd.c b/test/test-get-passwd.c index d2c7431fe7f..d046e40c6e8 100644 --- a/test/test-get-passwd.c +++ b/test/test-get-passwd.c @@ -39,32 +39,32 @@ TEST_IMPL(get_passwd) { /* Test the normal case */ r = uv_os_get_passwd(&pwd); - ASSERT(r == 0); + ASSERT_EQ(r, 0); len = strlen(pwd.username); - ASSERT(len > 0); + ASSERT_GT(len, 0); #ifdef _WIN32 ASSERT_NULL(pwd.shell); #else len = strlen(pwd.shell); # ifndef __PASE__ - ASSERT(len > 0); + ASSERT_GT(len, 0); # endif #endif len = strlen(pwd.homedir); - ASSERT(len > 0); + ASSERT_GT(len, 0); #ifdef _WIN32 if (len == 3 && pwd.homedir[1] == ':') - ASSERT(pwd.homedir[2] == '\\'); + ASSERT_EQ(pwd.homedir[2], '\\'); else - ASSERT(pwd.homedir[len - 1] != '\\'); + ASSERT_NE(pwd.homedir[len - 1], '\\'); #else if (len == 1) - ASSERT(pwd.homedir[0] == '/'); + ASSERT_EQ(pwd.homedir[0], '/'); else - ASSERT(pwd.homedir[len - 1] != '/'); + ASSERT_NE(pwd.homedir[len - 1], '/'); #endif #ifdef _WIN32 @@ -95,7 +95,110 @@ TEST_IMPL(get_passwd) { /* Test invalid input */ r = uv_os_get_passwd(NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); + + return 0; +} + + +TEST_IMPL(get_passwd2) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + + uv_passwd_t pwd; + uv_passwd_t pwd2; + size_t len; + int r; + + /* Test the normal case */ + r = uv_os_get_passwd(&pwd); + ASSERT_EQ(r, 0); + + r = uv_os_get_passwd2(&pwd2, pwd.uid); + +#ifdef _WIN32 + ASSERT_EQ(r, UV_ENOTSUP); + +#else + ASSERT_EQ(r, 0); + ASSERT_EQ(pwd.uid, pwd2.uid); + ASSERT_STR_EQ(pwd.username, pwd2.username); + ASSERT_STR_EQ(pwd.shell, pwd2.shell); + ASSERT_STR_EQ(pwd.homedir, pwd2.homedir); + uv_os_free_passwd(&pwd2); + + r = uv_os_get_passwd2(&pwd2, 0); + ASSERT_EQ(r, 0); + + len = strlen(pwd2.username); + ASSERT_GT(len, 0); + ASSERT_STR_EQ(pwd2.username, "root"); + + len = strlen(pwd2.homedir); + ASSERT_GT(len, 0); + + len = strlen(pwd2.shell); +# ifndef __PASE__ + ASSERT_GT(len, 0); +# endif + + uv_os_free_passwd(&pwd2); +#endif + + uv_os_free_passwd(&pwd); + + /* Test invalid input */ + r = uv_os_get_passwd2(NULL, pwd.uid); +#ifdef _WIN32 + ASSERT_EQ(r, UV_ENOTSUP); +#else + ASSERT_EQ(r, UV_EINVAL); +#endif + + return 0; +} + + +TEST_IMPL(get_group) { +/* TODO(gengjiawen): Fix test on QEMU. */ +#if defined(__QEMU__) + RETURN_SKIP("Test does not currently work in QEMU"); +#endif + + uv_passwd_t pwd; + uv_group_t grp; + size_t len; + int r; + + r = uv_os_get_passwd(&pwd); + ASSERT_EQ(r, 0); + + r = uv_os_get_group(&grp, pwd.gid); + +#ifdef _WIN32 + ASSERT_EQ(r, UV_ENOTSUP); + +#else + ASSERT_EQ(r, 0); + ASSERT_EQ(pwd.gid, grp.gid); + + len = strlen(grp.groupname); + ASSERT_GT(len, 0); + + uv_os_free_group(&grp); +#endif + + uv_os_free_passwd(&pwd); + + /* Test invalid input */ + r = uv_os_get_group(NULL, pwd.gid); +#ifdef _WIN32 + ASSERT_EQ(r, UV_ENOTSUP); +#else + ASSERT_EQ(r, UV_EINVAL); +#endif return 0; } diff --git a/test/test-list.h b/test/test-list.h index 00eda659a3c..4cd06356ee9 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -281,6 +281,8 @@ TEST_DECLARE (process_title_threadsafe) TEST_DECLARE (cwd_and_chdir) TEST_DECLARE (get_memory) TEST_DECLARE (get_passwd) +TEST_DECLARE (get_passwd2) +TEST_DECLARE (get_group) TEST_DECLARE (handle_fileno) TEST_DECLARE (homedir) TEST_DECLARE (tmpdir) @@ -899,6 +901,8 @@ TASK_LIST_START TEST_ENTRY (get_memory) TEST_ENTRY (get_passwd) + TEST_ENTRY (get_passwd2) + TEST_ENTRY (get_group) TEST_ENTRY (get_loadavg) diff --git a/test/test-platform-output.c b/test/test-platform-output.c index 4c2d77c9500..5839f52dfe5 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -35,8 +35,10 @@ TEST_IMPL(platform_output) { uv_cpu_info_t* cpus; uv_interface_address_t* interfaces; uv_passwd_t pwd; + uv_group_t grp; uv_utsname_t uname; unsigned par; + char* const* member; int count; int i; int err; @@ -147,15 +149,38 @@ TEST_IMPL(platform_output) { uv_free_interface_addresses(interfaces, count); err = uv_os_get_passwd(&pwd); - ASSERT(err == 0); + ASSERT_EQ(err, 0); + + err = uv_os_get_group(&grp, pwd.gid); +#if defined(_WIN32) + ASSERT_EQ(err, UV_ENOTSUP); + ASSERT_EQ(pwd.uid, (unsigned long) -1); + ASSERT_EQ(pwd.gid, (unsigned long) -1); + (void) member; + grp.groupname = "ENOTSUP"; +#else + ASSERT_EQ(err, 0); + ASSERT_EQ(pwd.gid, grp.gid); +#endif printf("uv_os_get_passwd:\n"); printf(" euid: %ld\n", pwd.uid); - printf(" gid: %ld\n", pwd.gid); + printf(" gid: %ld (%s)\n", pwd.gid, grp.groupname); +#if !defined(_WIN32) + printf(" members: ["); + for (member = grp.members; *member != NULL; member++) { + printf(" %s", *member); + } + printf(" ]\n"); +#endif printf(" username: %s\n", pwd.username); - printf(" shell: %s\n", pwd.shell); + if (pwd.shell != NULL) /* Not set on Windows */ + printf(" shell: %s\n", pwd.shell); printf(" home directory: %s\n", pwd.homedir); uv_os_free_passwd(&pwd); +#if !defined(_WIN32) + uv_os_free_group(&grp); +#endif pid = uv_os_getpid(); ASSERT(pid > 0); From 55b5d88b01ef9e1101df62ee49b3f34e58877faa Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 18 Jan 2023 05:26:41 +0100 Subject: [PATCH 295/713] unix,win: use static_assert when available (#3189) Fixes: https://github.com/libuv/libuv/issues/3131 --- src/uv-common.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/uv-common.h b/src/uv-common.h index 6c537e9e8eb..26d0e49b805 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -53,8 +53,13 @@ extern int snprintf(char*, size_t, const char*, ...); #define container_of(ptr, type, member) \ ((type *) ((char *) (ptr) - offsetof(type, member))) +/* C11 defines static_assert to be a macro which calls _Static_assert. */ +#if defined(static_assert) +#define STATIC_ASSERT(expr) static_assert(expr, #expr) +#else #define STATIC_ASSERT(expr) \ void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)]) +#endif #if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 7) #define uv__load_relaxed(p) __atomic_load_n(p, __ATOMIC_RELAXED) From 4155405e605b24c67bb533af0692c0182c39f296 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 18 Jan 2023 10:16:29 -0600 Subject: [PATCH 296/713] docs: delete code Makefile (#3883) This Makefile was a fairly poor sample, while now we have CMake for these to use for testing. --- docs/code/Makefile | 82 ---------------------------------------------- 1 file changed, 82 deletions(-) delete mode 100644 docs/code/Makefile diff --git a/docs/code/Makefile b/docs/code/Makefile deleted file mode 100644 index 0526e8c2eea..00000000000 --- a/docs/code/Makefile +++ /dev/null @@ -1,82 +0,0 @@ -examples=\ - helloworld\ - default-loop\ - idle-basic\ - uvcat\ - uvtee\ - onchange\ - thread-create\ - queue-work\ - progress\ - tcp-echo-server\ - dns\ - udp-dhcp\ - idle-compute\ - ref-timer\ - spawn\ - detach\ - proc-streams\ - cgi\ - pipe-echo-server\ - multi-echo-server\ - tty\ - tty-gravity\ - interfaces\ - locks \ - signal \ - uvstop \ - queue-cancel - -UV_PATH=$(shell pwd)/../.. -UV_LIB=$(UV_PATH)/.libs/libuv.a -CFLAGS=-g -Wall -I$(UV_PATH)/include -LIBS= - -uname_S=$(shell uname -s) - -ifeq (Darwin, $(uname_S)) -CFLAGS+=-framework CoreServices -SHARED_LIB_FLAGS=-bundle -undefined dynamic_lookup -o plugin/libhello.dylib -endif - -ifeq (Linux, $(uname_S)) -LIBS=-lrt -ldl -lm -pthread -lcurl -SHARED_LIB_FLAGS=-shared -Wl,-soname,libhello.so -o plugin/libhello.so -PLUGIN_EXE_FLAGS=-Wl,-export-dynamic -endif - - -all: $(examples) plugin/plugin proc-streams/test cgi/tick multi-echo-server/worker uvwget/uvwget - -$(examples): % : %/main.c - gcc $(CFLAGS) -o $@/$@ $< $(UV_LIB) $(LIBS) - -plugin: plugin/plugin -plugin/plugin: plugin/*.c - gcc $(CFLAGS) $(PLUGIN_EXE_FLAGS) -o plugin/plugin plugin/main.c $(UV_LIB) $(LIBS) - gcc -g -Wall -c -fPIC -o plugin/hello.o plugin/hello.c - gcc $(SHARED_LIB_FLAGS) plugin/hello.o - -proc-streams/test: proc-streams/test.c - gcc -g -Wall -o proc-streams/test proc-streams/test.c - -cgi/tick: cgi/tick.c - gcc -g -Wall -o cgi/tick cgi/tick.c - -multi-echo-server/worker: multi-echo-server/worker.c - gcc $(CFLAGS) -o multi-echo-server/worker multi-echo-server/worker.c $(UV_LIB) $(LIBS) - -uvwget: uvwget/uvwget -uvwget/uvwget: uvwget/main.c - gcc $(CFLAGS) `curl-config --cflags --libs` -o uvwget/uvwget uvwget/main.c $(UV_LIB) $(LIBS) - -clean: - for dir in $(examples); do cd $$dir; rm -f $$dir; rm -rf $$dir.dSYM; cd ..; done - rm -rf plugin/*.o plugin/libhello.* - rm -rf plugin/plugin plugin/plugin.dSYM - rm -rf proc-streams/test proc-streams/test.dSYM - rm -rf cgi/tick cgi/tick.dSYM - rm -rf multi-echo-server/worker multi-echo-server/worker.dSYM - rm -rf uvwget/uvwget uvwget/uvwget.dSYM - -.PHONY: clean all $(examples) plugin uvwget From 975f685d6966a3a731987a5941dc9ef197a9bd2e Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 18 Jan 2023 11:29:10 -0600 Subject: [PATCH 297/713] docs: add CI for docs PRs (#3884) --- .github/workflows/CI-docs.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/CI-docs.yml diff --git a/.github/workflows/CI-docs.yml b/.github/workflows/CI-docs.yml new file mode 100644 index 00000000000..d112a98e476 --- /dev/null +++ b/.github/workflows/CI-docs.yml @@ -0,0 +1,25 @@ +name: CI-docs + +on: + pull_request: + paths: + - 'docs/**' + - '!docs/code/**' + - '.github/workflows/CI-docs.yml' + +jobs: + docs-src: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: '3.9' + cache: 'pip' # caching pip dependencies + - run: pip install -r docs/requirements.txt + - name: html + run: | + make -C docs html + - name: linkcheck + run: | + make -C docs linkcheck From a38c4dfa99f55bba46f720471f1baa50e6e324bf Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 18 Jan 2023 12:15:48 -0600 Subject: [PATCH 298/713] docs: update Sphinx version on RTD (#3882) python3.9 -mvirtualenv sphinx . sphinx/bin/activate pip install Sphinx pip freeze > requirements.txt --- .readthedocs.yaml | 5 +++- docs/requirements.txt | 57 ++++++++++++++++--------------------------- 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index e53b9f3e84b..c1c9ab238cd 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -5,7 +5,10 @@ sphinx: configuration: null fail_on_warning: false +build: + tools: + python: "3.9" + python: - version: 3.8 install: - requirements: docs/requirements.txt diff --git a/docs/requirements.txt b/docs/requirements.txt index 8386e0178fa..b037de46595 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,42 +1,27 @@ # primary -Sphinx==3.5.4 +sphinx==6.1.3 # dependencies -alabaster==0.7.12 -appdirs==1.4.3 -Babel==2.9.0 -CacheControl==0.12.6 -certifi==2019.11.28 -chardet==3.0.4 -colorama==0.4.3 -contextlib2==0.6.0 -distlib==0.3.0 -distro==1.4.0 -docutils==0.16 -html5lib==1.0.1 -idna==2.8 -imagesize==1.2.0 -ipaddr==2.2.0 -Jinja2==2.11.3 -lockfile==0.12.2 -MarkupSafe==1.1.1 -msgpack==0.6.2 -packaging==20.3 -pep517==0.8.2 -progress==1.5 -Pygments==2.8.1 -pyparsing==2.4.6 -pytoml==0.1.21 -pytz==2021.1 -requests==2.22.0 -retrying==1.3.3 -six==1.14.0 -snowballstemmer==2.1.0 -sphinxcontrib-applehelp==1.0.2 +alabaster==0.7.13 +Babel==2.11.0 +certifi==2022.12.7 +charset-normalizer==3.0.1 +docutils==0.19 +idna==3.4 +imagesize==1.4.1 +importlib-metadata==6.0.0 +Jinja2==3.1.2 +MarkupSafe==2.1.2 +packaging==23.0 +Pygments==2.14.0 +pytz==2022.7.1 +requests==2.28.2 +snowballstemmer==2.2.0 +sphinxcontrib-applehelp==1.0.3 sphinxcontrib-devhelp==1.0.2 -sphinxcontrib-htmlhelp==1.0.3 +sphinxcontrib-htmlhelp==2.0.0 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 -sphinxcontrib-serializinghtml==1.1.4 -urllib3==1.25.8 -webencodings==0.5.1 +sphinxcontrib-serializinghtml==1.1.5 +urllib3==1.26.14 +zipp==3.11.0 From 61e0bbda6bf2416210b54ad80bb3f19e4876a896 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 19 Jan 2023 17:46:25 +0100 Subject: [PATCH 299/713] doc: clean up license file (#3876) GitHub gets confused by the non-standard format of the LICENSE file. Move the extra bits into the creatively named LICENSE-extra file. Fixes: https://github.com/libuv/libuv/issues/3875 --- CMakeLists.txt | 1 + LICENSE | 41 ----------------------------------------- LICENSE-extra | 36 ++++++++++++++++++++++++++++++++++++ Makefile.am | 1 + README.md | 7 +++++-- 5 files changed, 43 insertions(+), 43 deletions(-) create mode 100644 LICENSE-extra diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e20b42bc3b..2dcccc2c4c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -712,6 +712,7 @@ configure_file(libuv-static.pc.in libuv-static.pc @ONLY) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) +install(FILES LICENSE-extra DESTINATION ${CMAKE_INSTALL_DOCDIR}) install(FILES ${PROJECT_BINARY_DIR}/libuv-static.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(TARGETS uv_a EXPORT libuvConfig diff --git a/LICENSE b/LICENSE index 3d7f8f80f9b..6566365d4f2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,3 @@ -libuv is licensed for use as follows: - -==== Copyright (c) 2015-present libuv project contributors. Permission is hereby granted, free of charge, to any person obtaining a copy @@ -20,41 +17,3 @@ 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. -==== - -This license applies to parts of libuv originating from the -https://github.com/joyent/libuv repository: - -==== - -Copyright Joyent, Inc. and other Node contributors. All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. - -==== - -This license applies to all parts of libuv that are not externally -maintained libraries. - -The externally maintained libraries used by libuv are: - - - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license. - - - inet_pton and inet_ntop implementations, contained in src/inet.c, are - copyright the Internet Systems Consortium, Inc., and licensed under the ISC - license. diff --git a/LICENSE-extra b/LICENSE-extra new file mode 100644 index 00000000000..7d8ee65fce6 --- /dev/null +++ b/LICENSE-extra @@ -0,0 +1,36 @@ +This license applies to parts of libuv originating from the +https://github.com/joyent/libuv repository: + +==== + +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +==== + +This license applies to all parts of libuv that are not externally +maintained libraries. + +The externally maintained libraries used by libuv are: + + - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license. + + - inet_pton and inet_ntop implementations, contained in src/inet.c, are + copyright the Internet Systems Consortium, Inc., and licensed under the ISC + license. diff --git a/Makefile.am b/Makefile.am index 9a33f7e6344..c2c9970d715 100644 --- a/Makefile.am +++ b/Makefile.am @@ -126,6 +126,7 @@ EXTRA_DIST = test/fixtures/empty_file \ img \ CONTRIBUTING.md \ LICENSE \ + LICENSE-extra \ README.md diff --git a/README.md b/README.md index eb126f7b3c9..09e9bf10b6d 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,11 @@ The ABI/API changes can be tracked [here](http://abi-laboratory.pro/tracker/time ## Licensing -libuv is licensed under the MIT license. Check the [LICENSE file](LICENSE). -The documentation is licensed under the CC BY 4.0 license. Check the [LICENSE-docs file](LICENSE-docs). +libuv is licensed under the MIT license. Check the [LICENSE](LICENSE) and +[LICENSE-extra](LICENSE-extra) files. + +The documentation is licensed under the CC BY 4.0 license. Check the +[LICENSE-docs file](LICENSE-docs). ## Community From a4ba1bd73e50eaaa92fec53df6e3362b54eb71d0 Mon Sep 17 00:00:00 2001 From: panran <310762957@qq.com> Date: Fri, 20 Jan 2023 00:48:13 +0800 Subject: [PATCH 300/713] test: fix some warnings when compiling tests (#3816) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] note: in expansion of macro 'ASSERT_BASE' #define ASSERT_EQ(a, b) ASSERT_BASE(a, ==, b, int64_t, PRId64) warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 3 has type ‘uint32_t’ {aka ‘unsigned int’} ``` Co-authored-by: Jameson Nash --- test/test-idna.c | 4 ++-- test/test-ip6-addr.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test-idna.c b/test/test-idna.c index f4fad9653df..9b7002819fa 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -104,13 +104,13 @@ TEST_IMPL(utf8_decode1_overrun) { p = b; b[0] = 0x7F; ASSERT_EQ(0x7F, uv__utf8_decode1(&p, b + 1)); - ASSERT_EQ(p, b + 1); + ASSERT_PTR_EQ(p, b + 1); /* Multi-byte. */ p = b; b[0] = 0xC0; ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + 1)); - ASSERT_EQ(p, b + 1); + ASSERT_PTR_EQ(p, b + 1); return 0; } diff --git a/test/test-ip6-addr.c b/test/test-ip6-addr.c index 8036c4b1712..4c1e1019fe3 100644 --- a/test/test-ip6-addr.c +++ b/test/test-ip6-addr.c @@ -103,7 +103,7 @@ TEST_IMPL(ip6_addr_link_local) { fflush(stderr); ASSERT(0 == uv_ip6_addr(scoped_addr, TEST_PORT, &addr)); - fprintf(stderr, "Got scope_id 0x%02x\n", addr.sin6_scope_id); + fprintf(stderr, "Got scope_id 0x%2x\n", (unsigned)addr.sin6_scope_id); fflush(stderr); ASSERT(iface_index == addr.sin6_scope_id); } From c70cc5832b6bcd70c5917350d5805af8ce03b2e4 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 19 Jan 2023 14:00:15 -0600 Subject: [PATCH 301/713] build,win: add mingw-w64 CI configuration (#3885) Co-authored-by: Nicolas Noble --- .github/workflows/CI-win.yml | 58 ++++++++++++++++++++++++++++ cmake-toolchains/cross-mingw32.cmake | 17 ++++++++ 2 files changed, 75 insertions(+) create mode 100644 cmake-toolchains/cross-mingw32.cmake diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index ca6741df280..a8810eade49 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -62,3 +62,61 @@ jobs: shell: cmd run: build\\RelWithDebInfo\\uv_run_tests_a.exe + + build-mingw: + runs-on: ubuntu-latest + name: build-mingw-${{ matrix.config.arch }} + strategy: + fail-fast: false + matrix: + config: + - {arch: i686, server: 2022, libgcc: dw2 } + - {arch: x86_64, server: 2022, libgcc: seh } + steps: + - uses: actions/checkout@v3 + - name: Install mingw32 environment + run: | + sudo apt update + sudo apt install mingw-w64 ninja-build -y + - name: Build + run: | + cmake -S . -B build -G Ninja -DHOST_ARCH=${{ matrix.config.arch }} -DBUILD_TESTING=ON -DCMAKE_TOOLCHAIN_FILE=cmake-toolchains/cross-mingw32.cmake + cmake --build build + cmake --install build --prefix "`pwd`/build/usr" + mkdir -p build/usr/test build/usr/bin + cp -av test/fixtures build/usr/test + cp -av build/uv_run_tests_a.exe build/uv_run_tests.exe \ + `${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libgcc_s_${{ matrix.config.libgcc }}-1.dll` \ + `${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libwinpthread-1.dll` \ + `${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libatomic-1.dll` \ + build/usr/bin + - name: Upload build artifacts + uses: actions/upload-artifact@v3 + with: + name: mingw-${{ matrix.config.arch }} + path: build/usr/**/* + retention-days: 2 + + test-mingw: + runs-on: windows-${{ matrix.config.server }} + name: test-mingw-${{ matrix.config.arch }} + needs: build-mingw + strategy: + fail-fast: false + matrix: + config: + - {arch: i686, server: 2022} + - {arch: x86_64, server: 2022} + steps: + - name: Download build artifacts + uses: actions/download-artifact@v2 + with: + name: mingw-${{ matrix.config.arch }} + - name: Test + shell: cmd + run: | + bin\uv_run_tests_a.exe + - name: Test + shell: cmd + run: | + bin\uv_run_tests.exe diff --git a/cmake-toolchains/cross-mingw32.cmake b/cmake-toolchains/cross-mingw32.cmake new file mode 100644 index 00000000000..3fe1dd69ec5 --- /dev/null +++ b/cmake-toolchains/cross-mingw32.cmake @@ -0,0 +1,17 @@ +if(NOT HOST_ARCH) + message(SEND_ERROR "-DHOST_ARCH required to be specified") +endif() + +list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + HOST_ARCH + ) + +SET(CMAKE_SYSTEM_NAME Windows) +set(COMPILER_PREFIX "${HOST_ARCH}-w64-mingw32") +find_program(CMAKE_RC_COMPILER NAMES ${COMPILER_PREFIX}-windres) +find_program(CMAKE_C_COMPILER NAMES ${COMPILER_PREFIX}-gcc) +find_program(CMAKE_CXX_COMPILER NAMES ${COMPILER_PREFIX}-g++) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) From a40058dbd12fbcd92b571f656f10a35d2ebf206b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 19 Jan 2023 14:00:45 -0600 Subject: [PATCH 302/713] build: add CI for distcheck (#3571) Refs: https://github.com/libuv/libuv/issues/2190#issuecomment-465974240 Refs: https://github.com/libuv/libuv/issues/2199 Co-authored-by: Richard Lau --- .github/workflows/CI-unix.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 748fd6a5e89..e2859e4e242 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -14,6 +14,23 @@ on: - master jobs: + build-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: configure + run: | + ./autogen.sh + mkdir build + (cd build && ../configure) + - name: distcheck + continue-on-error: true # XXX: allow failure + run: | + make -C build distcheck + - name: dist + run: | + make -C build dist + build-android: runs-on: ubuntu-latest container: reactnativecommunity/react-native-android:2020-5-20 @@ -40,7 +57,7 @@ jobs: run: npx envinfo - name: Setup run: | - brew install ninja + brew install ninja automake libtool - name: Configure run: | mkdir build @@ -59,6 +76,13 @@ jobs: - name: Test run: | cd build && ctest -V + - name: Autotools configure + if: always() + run: | + ./autogen.sh + mkdir build-auto + (cd build-auto && ../configure) + make -C build-auto -j4 build-ios: runs-on: macos-11 From fe7ee4a624e69063e2f9b4b4c39861ed63368303 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 19 Jan 2023 14:03:59 -0600 Subject: [PATCH 303/713] unix: remove busy loop from uv_async_send (#3879) The current fix (libuv#2231) was found to be slow in certain cases. This change should improve scalabaility a bit by only incurring the spin loop delay while closing an UV_ASYNC. It also is intended to slightly improve the behavior after uv_loop_close is called, by parking all of the pending flags as set, so that it will not access the loop at all (until the uv_async_t memory is freed, which we leave still to the responsibility of the user). Note that this bug appears to still exist on Win32, though it's harder to address without the refactoring done to this code on libuv master. Takes some inspiration from https://github.com/libuv/libuv/pull/2654 Takes some inspiration from https://github.com/libuv/libuv/pull/2656 Refs: https://github.com/libuv/libuv/pull/2231 --- src/unix/async.c | 117 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 33 deletions(-) diff --git a/src/unix/async.c b/src/unix/async.c index 1f4a3061310..5751b6d02be 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -53,6 +53,7 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC); handle->async_cb = async_cb; handle->pending = 0; + handle->u.fd = 0; /* This will be used as a busy flag. */ QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue); uv__handle_start(handle); @@ -63,53 +64,50 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { int uv_async_send(uv_async_t* handle) { _Atomic int* pending; - int expected; + _Atomic int* busy; pending = (_Atomic int*) &handle->pending; + busy = (_Atomic int*) &handle->u.fd; /* Do a cheap read first. */ if (atomic_load_explicit(pending, memory_order_relaxed) != 0) return 0; - /* Tell the other thread we're busy with the handle. */ - expected = 0; - if (!atomic_compare_exchange_strong(pending, &expected, 1)) - return 0; + /* Set the loop to busy. */ + atomic_fetch_add(busy, 1); /* Wake up the other thread's event loop. */ - uv__async_send(handle->loop); + if (atomic_exchange(pending, 1) == 0) + uv__async_send(handle->loop); - /* Tell the other thread we're done. */ - expected = 1; - if (!atomic_compare_exchange_strong(pending, &expected, 2)) - abort(); + /* Set the loop to not-busy. */ + atomic_fetch_add(busy, -1); return 0; } -/* Only call this from the event loop thread. */ -static int uv__async_spin(uv_async_t* handle) { +/* Wait for the busy flag to clear before closing. + * Only call this from the event loop thread. */ +static void uv__async_spin(uv_async_t* handle) { _Atomic int* pending; - int expected; + _Atomic int* busy; int i; pending = (_Atomic int*) &handle->pending; + busy = (_Atomic int*) &handle->u.fd; + + /* Set the pending flag first, so no new events will be added by other + * threads after this function returns. */ + atomic_store(pending, 1); for (;;) { - /* 997 is not completely chosen at random. It's a prime number, acyclical - * by nature, and should therefore hopefully dampen sympathetic resonance. + /* 997 is not completely chosen at random. It's a prime number, acyclic by + * nature, and should therefore hopefully dampen sympathetic resonance. */ for (i = 0; i < 997; i++) { - /* rc=0 -- handle is not pending. - * rc=1 -- handle is pending, other thread is still working with it. - * rc=2 -- handle is pending, other thread is done. - */ - expected = 2; - atomic_compare_exchange_strong(pending, &expected, 0); - - if (expected != 1) - return expected; + if (atomic_load(busy) == 0) + return; /* Other thread is busy with this handle, spin until it's done. */ uv__cpu_relax(); @@ -137,6 +135,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { QUEUE queue; QUEUE* q; uv_async_t* h; + _Atomic int *pending; assert(w == &loop->async_io_watcher); @@ -166,8 +165,10 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { QUEUE_REMOVE(q); QUEUE_INSERT_TAIL(&loop->async_handles, q); - if (0 == uv__async_spin(h)) - continue; /* Not pending. */ + /* Atomically fetch and clear pending flag */ + pending = (_Atomic int*) &h->pending; + if (atomic_exchange(pending, 0) == 0) + continue; if (h->async_cb == NULL) continue; @@ -239,20 +240,68 @@ static int uv__async_start(uv_loop_t* loop) { } +void uv__async_stop(uv_loop_t* loop) { + QUEUE queue; + QUEUE* q; + uv_async_t* h; + + if (loop->async_io_watcher.fd == -1) + return; + + /* Make sure no other thread is accessing the async handle fd after the loop + * cleanup. + */ + QUEUE_MOVE(&loop->async_handles, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + h = QUEUE_DATA(q, uv_async_t, queue); + + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&loop->async_handles, q); + + uv__async_spin(h); + } + + if (loop->async_wfd != -1) { + if (loop->async_wfd != loop->async_io_watcher.fd) + uv__close(loop->async_wfd); + loop->async_wfd = -1; + } + + uv__io_stop(loop, &loop->async_io_watcher, POLLIN); + uv__close(loop->async_io_watcher.fd); + loop->async_io_watcher.fd = -1; +} + + int uv__async_fork(uv_loop_t* loop) { + QUEUE queue; + QUEUE* q; + uv_async_t* h; + if (loop->async_io_watcher.fd == -1) /* never started */ return 0; - uv__async_stop(loop); - - return uv__async_start(loop); -} + QUEUE_MOVE(&loop->async_handles, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + h = QUEUE_DATA(q, uv_async_t, queue); + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&loop->async_handles, q); -void uv__async_stop(uv_loop_t* loop) { - if (loop->async_io_watcher.fd == -1) - return; + /* The state of any thread that set pending is now likely corrupt in this + * child because the user called fork, so just clear these flags and move + * on. Calling most libc functions after `fork` is declared to be undefined + * behavior anyways, unless async-signal-safe, for multithreaded programs + * like libuv, and nothing interesting in pthreads is async-signal-safe. + */ + h->pending = 0; + /* This is the busy flag, and we just abruptly lost all other threads. */ + h->u.fd = 0; + } + /* Recreate these, since they still exist, but belong to the wrong pid now. */ if (loop->async_wfd != -1) { if (loop->async_wfd != loop->async_io_watcher.fd) uv__close(loop->async_wfd); @@ -262,6 +311,8 @@ void uv__async_stop(uv_loop_t* loop) { uv__io_stop(loop, &loop->async_io_watcher, POLLIN); uv__close(loop->async_io_watcher.fd); loop->async_io_watcher.fd = -1; + + return uv__async_start(loop); } From b4440f5aa21a6f9e4b3623e3e75e8e9fab1c95a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Thu, 19 Jan 2023 21:05:07 +0100 Subject: [PATCH 304/713] doc: document uv_fs_cb type (#3517) --- docs/src/fs.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 86d77c7948b..fb27a3b9654 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -160,6 +160,10 @@ Data types size_t nentries; } uv_dir_t; +.. c:type:: void (*uv_fs_cb)(uv_fs_t* req) + + Callback called when a request is completed asynchronously. + Public members ^^^^^^^^^^^^^^ From 17ea56ee737b66b434f31c7731b6629a3b7c83ab Mon Sep 17 00:00:00 2001 From: erw7 Date: Fri, 20 Jan 2023 06:33:07 +0900 Subject: [PATCH 305/713] build: Improve build by cmake for Cygwin (#2085) - Fix build on Cygwin. - Simplify file name of static library. Co-authored-by: Jameson Nash --- CMakeLists.txt | 19 +++++++++++++++++++ libuv-static.pc.in | 2 +- libuv.pc.in | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2dcccc2c4c1..cecd901d531 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -419,6 +419,20 @@ if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|Linux|NetBSD|OpenBSD") list(APPEND uv_test_libraries util) endif() +if(CYGWIN OR MSYS) + list(APPEND uv_defines _GNU_SOURCE) + list(APPEND uv_sources + src/unix/cygwin.c + src/unix/bsd-ifaddrs.c + src/unix/no-fsevents.c + src/unix/no-proctitle.c + src/unix/posix-hrtime.c + src/unix/posix-poll.c + src/unix/procfs-exepath.c + src/unix/sysinfo-loadavg.c + src/unix/sysinfo-memory.c) +endif() + if(LIBUV_BUILD_SHARED) add_library(uv SHARED ${uv_sources}) target_compile_definitions(uv @@ -439,6 +453,7 @@ if(LIBUV_BUILD_SHARED) set_target_properties(uv PROPERTIES LINKER_LANGUAGE CXX) endif() target_link_libraries(uv ${uv_libraries}) + set_target_properties(uv PROPERTIES OUTPUT_NAME "uv") endif() add_library(uv_a STATIC ${uv_sources}) @@ -455,6 +470,10 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OS390") set_target_properties(uv_a PROPERTIES LINKER_LANGUAGE CXX) endif() target_link_libraries(uv_a ${uv_libraries}) +set_target_properties(uv_a PROPERTIES OUTPUT_NAME "uv") +if(MSVC) + set_target_properties(uv_a PROPERTIES PREFIX "lib") +endif() if(LIBUV_BUILD_TESTS) # Small hack: use ${uv_test_sources} now to get the runner skeleton, diff --git a/libuv-static.pc.in b/libuv-static.pc.in index ea625482d5e..639058c8e08 100644 --- a/libuv-static.pc.in +++ b/libuv-static.pc.in @@ -8,5 +8,5 @@ Version: @PACKAGE_VERSION@ Description: multi-platform support library with a focus on asynchronous I/O. URL: http://libuv.org/ -Libs: -L${libdir} -luv_a @LIBS@ +Libs: -L${libdir} -l:libuv.a @LIBS@ Cflags: -I${includedir} diff --git a/libuv.pc.in b/libuv.pc.in index 1d7b86f7517..0f569146697 100644 --- a/libuv.pc.in +++ b/libuv.pc.in @@ -2,6 +2,7 @@ prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ +LIBUV_STATIC=-L${libdir} -l:libuv.a @LIBS@ Name: libuv Version: @PACKAGE_VERSION@ From 0235e150e2a071d81610cb19996dd2c3ec7efcb6 Mon Sep 17 00:00:00 2001 From: AJ Heller Date: Thu, 19 Jan 2023 14:07:29 -0800 Subject: [PATCH 306/713] build: add libuv:: namespace to libuvConfig.cmake (#3596) This may be breaking, but is still quite new, and seems to follow cmake best practices. --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cecd901d531..58163f69af0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -736,7 +736,9 @@ install(FILES ${PROJECT_BINARY_DIR}/libuv-static.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(TARGETS uv_a EXPORT libuvConfig ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(EXPORT libuvConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libuv) +install(EXPORT libuvConfig + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libuv + NAMESPACE libuv::) if(LIBUV_BUILD_SHARED) # The version in the filename is mirroring the behaviour of autotools. From 679d679f25a47e88b2a46de192972491655e7237 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 19 Jan 2023 14:09:15 +0100 Subject: [PATCH 307/713] test: fix ThreadSanitizer thread leak warning Refs: https://github.com/libuv/libuv/issues/3681 --- test/test-eintr-handling.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test-eintr-handling.c b/test/test-eintr-handling.c index 1aaf623b789..3cd55a03593 100644 --- a/test/test-eintr-handling.c +++ b/test/test-eintr-handling.c @@ -87,6 +87,8 @@ TEST_IMPL(eintr_handling) { ASSERT(0 == close(pipe_fds[1])); uv_close((uv_handle_t*) &signal, NULL); + ASSERT_EQ(0, uv_thread_join(&thread)); + MAKE_VALGRIND_HAPPY(); return 0; } From 895a1c03be41c3f021f021062246f7ccb3fa6631 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 19 Jan 2023 14:09:15 +0100 Subject: [PATCH 308/713] test: fix ThreadSanitizer data race warning Refs: https://github.com/libuv/libuv/issues/3681 --- test/test-ipc-send-recv.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/test-ipc-send-recv.c b/test/test-ipc-send-recv.c index 8a0e9708f02..1eba6dfa71f 100644 --- a/test/test-ipc-send-recv.c +++ b/test/test-ipc-send-recv.c @@ -76,10 +76,12 @@ static int write2_cb_called; static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { - /* we're not actually reading anything so a small buffer is okay */ - static char slab[8]; - buf->base = slab; - buf->len = sizeof(slab); + /* We're not actually reading anything so a small buffer is okay + * but it needs to be heap-allocated to appease TSan. + */ + buf->len = 8; + buf->base = malloc(buf->len); + ASSERT_NOT_NULL(buf->base); } @@ -91,6 +93,8 @@ static void recv_cb(uv_stream_t* handle, int r; union handles* recv; + free(buf->base); + pipe = (uv_pipe_t*) handle; ASSERT(pipe == &ctx.channel); @@ -304,6 +308,8 @@ static void read_cb(uv_stream_t* handle, union handles* recv; uv_write_t* write_req; + free(rdbuf->base); + if (nread == UV_EOF || nread == UV_ECONNABORTED) { return; } From 7b5a21deaaf914d221e57d3666e1fe48ab56127e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 19 Jan 2023 14:09:15 +0100 Subject: [PATCH 309/713] test: fix ThreadSanitizer data race warning Refs: https://github.com/libuv/libuv/issues/3681 --- test/test-fs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/test-fs.c b/test/test-fs.c index 3d7b700845c..f4fdd8687ec 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -3778,9 +3778,10 @@ static void test_fs_partial(int doread) { uv_fs_req_cleanup(&write_req); } - ASSERT(0 == memcmp(buffer, ctx.data, ctx.size)); - ASSERT(0 == uv_thread_join(&thread)); + + ASSERT_MEM_EQ(buffer, ctx.data, ctx.size); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(0 == close(pipe_fds[1])); From f328457cb1d06b0dc328fe0136f1d7466432b0c5 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 19 Jan 2023 14:09:15 +0100 Subject: [PATCH 310/713] test: fix ThreadSanitizer data race warning Legitimate if fairly benign warning: the `stop` global variable was read and written without proper synchronization; `volatile` isn't sufficient. Refs: https://github.com/libuv/libuv/issues/3681 --- test/test-signal-multiple-loops.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/test/test-signal-multiple-loops.c b/test/test-signal-multiple-loops.c index 7d61ff61e0d..43e0a12253e 100644 --- a/test/test-signal-multiple-loops.c +++ b/test/test-signal-multiple-loops.c @@ -50,18 +50,18 @@ enum signal_action { }; static uv_sem_t sem; -static uv_mutex_t counter_lock; -static volatile int stop = 0; +static uv_mutex_t lock; +static int stop = 0; -static volatile int signal1_cb_counter = 0; -static volatile int signal2_cb_counter = 0; -static volatile int loop_creation_counter = 0; +static int signal1_cb_counter = 0; +static int signal2_cb_counter = 0; +static int loop_creation_counter = 0; -static void increment_counter(volatile int* counter) { - uv_mutex_lock(&counter_lock); +static void increment_counter(int* counter) { + uv_mutex_lock(&lock); ++(*counter); - uv_mutex_unlock(&counter_lock); + uv_mutex_unlock(&lock); } @@ -162,6 +162,8 @@ static void signal_unexpected_cb(uv_signal_t* handle, int signum) { static void loop_creating_worker(void* context) { + int done; + (void) context; do { @@ -188,7 +190,11 @@ static void loop_creating_worker(void* context) { free(loop); increment_counter(&loop_creation_counter); - } while (!stop); + + uv_mutex_lock(&lock); + done = stop; + uv_mutex_unlock(&lock); + } while (!done); } @@ -215,7 +221,7 @@ TEST_IMPL(signal_multiple_loops) { r = uv_sem_init(&sem, 0); ASSERT(r == 0); - r = uv_mutex_init(&counter_lock); + r = uv_mutex_init(&lock); ASSERT(r == 0); /* Create a couple of threads that create a destroy loops continuously. */ @@ -272,7 +278,9 @@ TEST_IMPL(signal_multiple_loops) { } /* Tell all loop creating threads to stop. */ + uv_mutex_lock(&lock); stop = 1; + uv_mutex_unlock(&lock); /* Wait for all loop creating threads to exit. */ for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) { From c58cd282794018a883ad899fdda4e05046f9e060 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 19 Jan 2023 14:09:15 +0100 Subject: [PATCH 311/713] test: cond-skip fork_threadpool_queue_work_simple Skip the test when ThreadSanitizer is active because the latter doesn't support forking in multi-threaded processes. Refs: https://github.com/libuv/libuv/issues/3681 --- test/test-fork.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test-fork.c b/test/test-fork.c index 9e4684f0e15..0cb04423548 100644 --- a/test/test-fork.c +++ b/test/test-fork.c @@ -646,6 +646,10 @@ TEST_IMPL(fork_threadpool_queue_work_simple) { pid_t child_pid; uv_loop_t loop; +#ifdef __TSAN__ + RETURN_SKIP("ThreadSanitizer doesn't support multi-threaded fork"); +#endif + /* Prime the pool and default loop. */ assert_run_work(uv_default_loop()); From bcbaf671a9572b7381ec2e15f1528643eacc3955 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 19 Jan 2023 14:09:15 +0100 Subject: [PATCH 312/713] test: cond-skip signal_multiple_loops ThreadSanitizer's complaints about data races are likely legitimate but they are pre-existing and not straightforward to fix with the current design. Something for later. Refs: https://github.com/libuv/libuv/issues/3681 --- test/test-signal-multiple-loops.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/test-signal-multiple-loops.c b/test/test-signal-multiple-loops.c index 43e0a12253e..0879b7bca12 100644 --- a/test/test-signal-multiple-loops.c +++ b/test/test-signal-multiple-loops.c @@ -210,6 +210,12 @@ TEST_IMPL(signal_multiple_loops) { #if defined(__QEMU__) // See https://github.com/libuv/libuv/issues/2859 RETURN_SKIP("QEMU's signal emulation code is notoriously tricky"); +#endif +#if defined(__TSAN__) + /* ThreadSanitizer complains - likely legitimately - about data races + * in uv__signal_compare() in src/unix/signal.c but that's pre-existing. + */ + RETURN_SKIP("Fix test under ThreadSanitizer"); #endif uv_thread_t loop_creating_threads[NUM_LOOP_CREATING_THREADS]; uv_thread_t signal_handling_threads[NUM_SIGNAL_HANDLING_THREADS]; From a3b7dfcfca285aee530caf5511cbe16c3a4b43cf Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 19 Jan 2023 14:09:15 +0100 Subject: [PATCH 313/713] test: cond-skip tcp_writealot Too slow to run under ThreadSanitizer. Refs: https://github.com/libuv/libuv/issues/3681 --- test/test-tcp-writealot.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test-tcp-writealot.c b/test/test-tcp-writealot.c index 40dce96e8d8..382c2712ed8 100644 --- a/test/test-tcp-writealot.c +++ b/test/test-tcp-writealot.c @@ -149,6 +149,10 @@ TEST_IMPL(tcp_writealot) { uv_tcp_t client; int r; +#ifdef __TSAN__ + RETURN_SKIP("Test is too slow to run under ThreadSanitizer"); +#endif + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); send_buffer = calloc(1, TOTAL_BYTES); From 67063ead6092657725d74b595a8763ebb0bdd659 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 19 Jan 2023 14:09:15 +0100 Subject: [PATCH 314/713] build: promote tsan ci to must-pass Refs: https://github.com/libuv/libuv/issues/3681 --- .github/workflows/sanitizer.yml | 5 +++-- tsansupp.txt | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 tsansupp.txt diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 2ebb8e1709f..8173c8222c5 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -47,9 +47,10 @@ jobs: (cd build-tsan && cmake .. -G Ninja -DBUILD_TESTING=ON -DTSAN=ON -DCMAKE_BUILD_TYPE=Release) cmake --build build-tsan - name: TSAN Test - continue-on-error: true # currently permit failures + # Note: path must be absolute because some tests chdir. + # TSan exits with an error when it can't find the file. run: | - ./build-tsan/uv_run_tests_a + env TSAN_OPTIONS="suppressions=$PWD/tsansupp.txt" ./build-tsan/uv_run_tests_a - name: UBSAN Build run: | diff --git a/tsansupp.txt b/tsansupp.txt new file mode 100644 index 00000000000..bde4060803e --- /dev/null +++ b/tsansupp.txt @@ -0,0 +1,2 @@ +# glibc reads `count` field unsynchronized, not a libuv bug +race:pthread_barrier_destroy From 2638237e1fd6643ae8e7e4e2faa75b647e6f7248 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sat, 21 Jan 2023 07:52:36 -0500 Subject: [PATCH 315/713] build: add CI for OpenBSD and FreeBSD (#3548) Fixes: https://github.com/libuv/libuv/issues/3510 --- .github/workflows/CI-unix.yml | 33 +++++++++++++++++++++++++++++++++ src/unix/core.c | 4 ++-- src/unix/internal.h | 5 +++++ src/unix/thread.c | 4 ++-- test/task.h | 2 +- test/test-fs.c | 18 +++++++++--------- test/test-get-currentexe.c | 3 +++ test/test-gethostname.c | 2 +- test/test-metrics.c | 7 +++++-- test/test-tcp-rst.c | 3 +++ test/test-udp-connect.c | 3 +++ test/test-udp-connect6.c | 3 +++ test/test-udp-multicast-join.c | 3 +++ 13 files changed, 73 insertions(+), 17 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index e2859e4e242..52a8bf595de 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -150,3 +150,36 @@ jobs: - name: Test run: | ${{ matrix.config.qemu }} build/uv_run_tests_a + + build-bsd: + timeout-minutes: 30 + runs-on: ${{ matrix.config.runner }} + name: build-${{ matrix.config.os }}-${{ matrix.config.version }} + + strategy: + fail-fast: false + matrix: + config: + # The OS versions supported are specific to the version of the action + # https://github.com/cross-platform-actions/action/blob/master/changelog.md + - { os: freebsd, version: '13.1', runner: 'ubuntu-latest', install: 'pkg install -y' } + - { os: openbsd, version: '7.2', runner: 'macos-11', install: 'pkg_add -I' } + + steps: + - uses: actions/checkout@v2 + + - uses: cross-platform-actions/action@v0.9.0 + with: + operating_system: ${{ matrix.config.os }} + version: ${{ matrix.config.version }} + run: | + sudo ${{ matrix.config.install }} cmake ninja + sudo hostname -s ci-host + mkdir build + cd build + cmake .. -DBUILD_TESTING=ON -G Ninja + cmake --build . + ls -lh + ./uv_run_tests platform_output + ./uv_run_tests_a platform_output + ctest -V diff --git a/src/unix/core.c b/src/unix/core.c index 706dcccb647..0ef6ae8a3e5 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -72,8 +72,8 @@ extern char** environ; # include # include # include -# include # if defined(__FreeBSD__) +# include # define uv__accept4 accept4 # endif # if defined(__NetBSD__) @@ -1490,7 +1490,7 @@ uv_pid_t uv_os_getppid(void) { } int uv_cpumask_size(void) { -#if defined(__linux__) || defined(__FreeBSD__) +#if UV__CPU_AFFINITY_SUPPORTED return CPU_SETSIZE; #else return UV_ENOTSUP; diff --git a/src/unix/internal.h b/src/unix/internal.h index 5497ee369dd..97823a91794 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -425,5 +425,10 @@ uv__fs_copy_file_range(int fd_in, unsigned int flags); #endif +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 1301000) +#define UV__CPU_AFFINITY_SUPPORTED 1 +#else +#define UV__CPU_AFFINITY_SUPPORTED 0 +#endif #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/src/unix/thread.c b/src/unix/thread.c index f75fe82aa20..8e3652f10e9 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -295,7 +295,7 @@ int uv_thread_create_ex(uv_thread_t* tid, return UV__ERR(err); } -#if defined(__linux__) || defined(__FreeBSD__) +#if UV__CPU_AFFINITY_SUPPORTED int uv_thread_setaffinity(uv_thread_t* tid, char* cpumask, @@ -383,7 +383,7 @@ int uv_thread_getaffinity(uv_thread_t* tid, #endif /* defined(__linux__) || defined(UV_BSD_H) */ int uv_thread_getcpu(void) { -#if defined(__linux__) || defined(__FreeBSD__) +#if UV__CPU_AFFINITY_SUPPORTED int cpu; cpu = sched_getcpu(); diff --git a/test/task.h b/test/task.h index 4ee81662be0..7f7ed015998 100644 --- a/test/task.h +++ b/test/task.h @@ -371,7 +371,7 @@ UNUSED static int can_ipv6(void) { #endif #if !defined(__linux__) && \ - !defined(__FreeBSD__) && \ + !(defined(__FreeBSD__) && __FreeBSD_version >= 1301000) && \ !defined(_WIN32) # define NO_CPU_AFFINITY \ "affinity not supported on this platform." diff --git a/test/test-fs.c b/test/test-fs.c index f4fdd8687ec..fd2b651c1be 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2788,8 +2788,8 @@ TEST_IMPL(fs_lutime) { loop = uv_default_loop(); unlink(path); r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); uv_fs_req_cleanup(&req); uv_fs_close(loop, &req, r, NULL); @@ -2805,8 +2805,8 @@ TEST_IMPL(fs_lutime) { "Symlink creation requires elevated console (with admin rights)"); } #endif - ASSERT(s == 0); - ASSERT(req.result == 0); + ASSERT_EQ(s, 0); + ASSERT_EQ(req.result, 0); uv_fs_req_cleanup(&req); /* Test the synchronous version. */ @@ -2820,12 +2820,12 @@ TEST_IMPL(fs_lutime) { r = uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL); #if (defined(_AIX) && !defined(_AIX71)) || \ defined(__MVS__) - ASSERT(r == UV_ENOSYS); + ASSERT_EQ(r, UV_ENOSYS); RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1"); #endif - ASSERT(r == 0); + ASSERT_EQ(r, 0); lutime_cb(&req); - ASSERT(lutime_cb_count == 1); + ASSERT_EQ(lutime_cb_count, 1); /* Test the asynchronous version. */ atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */ @@ -2835,9 +2835,9 @@ TEST_IMPL(fs_lutime) { checkme.path = symlink_path; r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb); - ASSERT(r == 0); + ASSERT_EQ(r, 0); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(lutime_cb_count == 2); + ASSERT_EQ(lutime_cb_count, 2); /* Cleanup. */ unlink(path); diff --git a/test/test-get-currentexe.c b/test/test-get-currentexe.c index dc239cc89d1..becaf5c1bb8 100644 --- a/test/test-get-currentexe.c +++ b/test/test-get-currentexe.c @@ -35,6 +35,9 @@ TEST_IMPL(get_currentexe) { #if defined(__QEMU__) RETURN_SKIP("Test does not currently work in QEMU"); #endif +#if defined(__OpenBSD__) + RETURN_SKIP("Test does not currently work in OpenBSD"); +#endif char buffer[PATHMAX]; char path[PATHMAX]; diff --git a/test/test-gethostname.c b/test/test-gethostname.c index 1a9816d43c6..dc29cd69234 100644 --- a/test/test-gethostname.c +++ b/test/test-gethostname.c @@ -43,7 +43,7 @@ TEST_IMPL(gethostname) { enobufs_size = 1; buf[0] = '\0'; r = uv_os_gethostname(buf, &enobufs_size); - ASSERT(r == UV_ENOBUFS); + ASSERT_EQ(r, UV_ENOBUFS); ASSERT(buf[0] == '\0'); ASSERT(enobufs_size > 1); diff --git a/test/test-metrics.c b/test/test-metrics.c index bfc09251028..1f887857030 100644 --- a/test/test-metrics.c +++ b/test/test-metrics.c @@ -47,6 +47,9 @@ static void timer_spin_cb(uv_timer_t* handle) { TEST_IMPL(metrics_idle_time) { +#if defined(__OpenBSD__) + RETURN_SKIP("Test does not currently work in OpenBSD"); +#endif const uint64_t timeout = 1000; uv_timer_t timer; uint64_t idle_time; @@ -65,8 +68,8 @@ TEST_IMPL(metrics_idle_time) { idle_time = uv_metrics_idle_time(uv_default_loop()); /* Permissive check that the idle time matches within the timeout ±500 ms. */ - ASSERT((idle_time <= (timeout + 500) * UV_NS_TO_MS) && - (idle_time >= (timeout - 500) * UV_NS_TO_MS)); + ASSERT_LE(idle_time, (timeout + 500) * UV_NS_TO_MS); + ASSERT_GE(idle_time, (timeout - 500) * UV_NS_TO_MS); MAKE_VALGRIND_HAPPY(); return 0; diff --git a/test/test-tcp-rst.c b/test/test-tcp-rst.c index ed48e741908..16bc9ce4a82 100644 --- a/test/test-tcp-rst.c +++ b/test/test-tcp-rst.c @@ -76,6 +76,9 @@ static void connect_cb(uv_connect_t *req, int status) { * RST. Test checks that uv_guess_handle still works on a reset TCP handle. */ TEST_IMPL(tcp_rst) { +#if defined(__OpenBSD__) + RETURN_SKIP("Test does not currently work in OpenBSD"); +#endif #ifndef _WIN32 struct sockaddr_in server_addr; int r; diff --git a/test/test-udp-connect.c b/test/test-udp-connect.c index 0be702efef4..d78e62e3551 100644 --- a/test/test-udp-connect.c +++ b/test/test-udp-connect.c @@ -98,6 +98,9 @@ static void sv_recv_cb(uv_udp_t* handle, TEST_IMPL(udp_connect) { +#if defined(__OpenBSD__) + RETURN_SKIP("Test does not currently work in OpenBSD"); +#endif uv_udp_send_t req; struct sockaddr_in ext_addr; struct sockaddr_in tmp_addr; diff --git a/test/test-udp-connect6.c b/test/test-udp-connect6.c index d000daf17fb..9195ef90105 100644 --- a/test/test-udp-connect6.c +++ b/test/test-udp-connect6.c @@ -98,6 +98,9 @@ static void sv_recv_cb(uv_udp_t* handle, TEST_IMPL(udp_connect6) { +#if defined(__OpenBSD__) + RETURN_SKIP("Test does not currently work in OpenBSD"); +#endif uv_udp_send_t req; struct sockaddr_in6 ext_addr; struct sockaddr_in6 tmp_addr; diff --git a/test/test-udp-multicast-join.c b/test/test-udp-multicast-join.c index 9e603a8455f..2c375cc0196 100644 --- a/test/test-udp-multicast-join.c +++ b/test/test-udp-multicast-join.c @@ -138,6 +138,9 @@ static void cl_recv_cb(uv_udp_t* handle, TEST_IMPL(udp_multicast_join) { +#if defined(__OpenBSD__) + RETURN_SKIP("Test does not currently work in OpenBSD"); +#endif int r; struct sockaddr_in addr; From ee206367d4e8ebb70455665de78b8309220fd7d0 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 22 Jan 2023 15:26:22 -0600 Subject: [PATCH 316/713] build,test: fix distcheck errors (#3886) When run under distcheck, the libuv source permissions are read-only, which makes this test copyfile fail without explicit correction to the permissions. --- .github/workflows/CI-unix.yml | 4 ---- configure.ac | 1 + test/test-fs-copyfile.c | 9 ++++++++- test/test-pipe-connect-error.c | 22 ++++++++++++---------- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 52a8bf595de..858235e7651 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -24,12 +24,8 @@ jobs: mkdir build (cd build && ../configure) - name: distcheck - continue-on-error: true # XXX: allow failure run: | make -C build distcheck - - name: dist - run: | - make -C build dist build-android: runs-on: ubuntu-latest diff --git a/configure.ac b/configure.ac index d3417f5ea45..a64a3dd9017 100644 --- a/configure.ac +++ b/configure.ac @@ -87,4 +87,5 @@ AC_CONFIG_FILES([Makefile libuv.pc]) AC_CONFIG_LINKS([test/fixtures/empty_file:test/fixtures/empty_file]) AC_CONFIG_LINKS([test/fixtures/load_error.node:test/fixtures/load_error.node]) AC_CONFIG_LINKS([test/fixtures/lorem_ipsum.txt:test/fixtures/lorem_ipsum.txt]) +AC_CONFIG_LINKS([test/fixtures/one_file/one_file:test/fixtures/one_file/one_file]) AC_OUTPUT diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index c785a4b51fb..6781ee7f71d 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -151,14 +151,18 @@ TEST_IMPL(fs_copyfile) { handle_result(&req); /* Fails to overwrites existing file. */ + ASSERT_EQ(uv_fs_chmod(NULL, &req, dst, 0644, NULL), 0); + uv_fs_req_cleanup(&req); r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_EXCL, NULL); ASSERT(r == UV_EEXIST); uv_fs_req_cleanup(&req); /* Truncates when an existing destination is larger than the source file. */ + ASSERT_EQ(uv_fs_chmod(NULL, &req, dst, 0644, NULL), 0); + uv_fs_req_cleanup(&req); touch_file(src, 1); r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); - ASSERT(r == 0); + ASSERT_EQ(r, 0); handle_result(&req); /* Copies a larger file. */ @@ -176,6 +180,9 @@ TEST_IMPL(fs_copyfile) { ASSERT(result_check_count == 5); uv_run(loop, UV_RUN_DEFAULT); ASSERT(result_check_count == 6); + /* Ensure file is user-writable (not copied from src). */ + ASSERT_EQ(uv_fs_chmod(NULL, &req, dst, 0644, NULL), 0); + uv_fs_req_cleanup(&req); /* If the flags are invalid, the loop should not be kept open */ unlink(dst); diff --git a/test/test-pipe-connect-error.c b/test/test-pipe-connect-error.c index 0f1e2b1c1ed..ba28a5922c3 100644 --- a/test/test-pipe-connect-error.c +++ b/test/test-pipe-connect-error.c @@ -43,15 +43,17 @@ static void close_cb(uv_handle_t* handle) { static void connect_cb(uv_connect_t* connect_req, int status) { - ASSERT(status == UV_ENOENT); - uv_close((uv_handle_t*)connect_req->handle, close_cb); + ASSERT_EQ(status, UV_ENOENT); + uv_close((uv_handle_t*) connect_req->handle, close_cb); connect_cb_called++; } static void connect_cb_file(uv_connect_t* connect_req, int status) { - ASSERT(status == UV_ENOTSOCK || status == UV_ECONNREFUSED); - uv_close((uv_handle_t*)connect_req->handle, close_cb); + if (status != UV_ENOTSOCK) + if (status != UV_EACCES) + ASSERT_EQ(status, UV_ECONNREFUSED); + uv_close((uv_handle_t*) connect_req->handle, close_cb); connect_cb_called++; } @@ -62,13 +64,13 @@ TEST_IMPL(pipe_connect_bad_name) { int r; r = uv_pipe_init(uv_default_loop(), &client, 0); - ASSERT(r == 0); + ASSERT_EQ(r, 0); uv_pipe_connect(&req, &client, BAD_PIPENAME, connect_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); - ASSERT(connect_cb_called == 1); + ASSERT_EQ(close_cb_called, 1); + ASSERT_EQ(connect_cb_called, 1); MAKE_VALGRIND_HAPPY(); return 0; @@ -82,13 +84,13 @@ TEST_IMPL(pipe_connect_to_file) { int r; r = uv_pipe_init(uv_default_loop(), &client, 0); - ASSERT(r == 0); + ASSERT_EQ(r, 0); uv_pipe_connect(&req, &client, path, connect_cb_file); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); - ASSERT(connect_cb_called == 1); + ASSERT_EQ(close_cb_called, 1); + ASSERT_EQ(connect_cb_called, 1); MAKE_VALGRIND_HAPPY(); return 0; From f1b4c7664868358e32d5cb6c1d0a9dced7d7ae0f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 31 Jan 2023 18:35:18 +0100 Subject: [PATCH 317/713] test: remove bad tty window size assumption (#3895) Fixes: https://github.com/libuv/libuv/issues/3894 --- test/test-tty.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/test-tty.c b/test/test-tty.c index 2c7ec4ec564..f53a701fce7 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -116,12 +116,8 @@ TEST_IMPL(tty) { return TEST_SKIP; } - /* - * Is it a safe assumption that most people have terminals larger than - * 10x10? - */ - ASSERT(width > 10); - ASSERT(height > 10); + ASSERT_GT(width, 0); + ASSERT_GT(height, 0); /* Turn on raw mode. */ r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); From 42cc412c4aca0ff17ad40ad3e35b5386ae171dd5 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 1 Feb 2023 13:42:26 -0500 Subject: [PATCH 318/713] darwin,process: feed kevent the signal to reap children (#3893) Since we are emulating this event, but are not using the pending_queue, we need to make sure it is accounted for properly. Also DRY some of the reset_timeout code here. This was observed to cause a hang in certain rare cases, particularly on M1 machines. Do a bit of code cleanup too, since we do not need to initialize the internal signal handling pipe if it will not be used. --- src/unix/core.c | 1 + src/unix/internal.h | 1 + src/unix/kqueue.c | 43 ++++++++++++++++++------------------------- src/unix/loop.c | 5 +---- src/unix/process.c | 27 +++++++++++++++++++++++++++ src/unix/signal.c | 2 ++ 6 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 0ef6ae8a3e5..8f7ff943499 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -361,6 +361,7 @@ static int uv__backend_timeout(const uv_loop_t* loop) { (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) && QUEUE_EMPTY(&loop->pending_queue) && QUEUE_EMPTY(&loop->idle_handles) && + (loop->flags & UV_LOOP_REAP_CHILDREN) == 0 && loop->closing_handles == NULL) return uv__next_timeout(loop); return 0; diff --git a/src/unix/internal.h b/src/unix/internal.h index 97823a91794..d9892fcf9ed 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -296,6 +296,7 @@ int uv__kqueue_init(uv_loop_t* loop); int uv__platform_loop_init(uv_loop_t* loop); void uv__platform_loop_delete(uv_loop_t* loop); void uv__platform_invalidate_fd(uv_loop_t* loop, int fd); +int uv__process_init(uv_loop_t* loop); /* various */ void uv__async_close(uv_async_t* handle); diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index abb147851f1..c68cd451b88 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -250,6 +250,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { ARRAY_SIZE(events), timeout == -1 ? NULL : &spec); + if (nfds == -1) + assert(errno == EINTR); + if (pset != NULL) pthread_sigmask(SIG_UNBLOCK, pset, NULL); @@ -257,36 +260,26 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the * operating system didn't reschedule our process while in the syscall. */ - SAVE_ERRNO(uv__update_time(loop)); - - if (nfds == 0) { - if (reset_timeout != 0) { - timeout = user_timeout; - reset_timeout = 0; - if (timeout == -1) - continue; - if (timeout > 0) - goto update_timeout; + uv__update_time(loop); + + if (nfds == 0 || nfds == -1) { + /* If kqueue is empty or interrupted, we might still have children ready + * to reap immediately. */ + if (loop->flags & UV_LOOP_REAP_CHILDREN) { + loop->flags &= ~UV_LOOP_REAP_CHILDREN; + uv__wait_children(loop); + assert((reset_timeout == 0 ? timeout : user_timeout) == 0); + return; /* Equivalent to fall-through behavior. */ } - assert(timeout != -1); - return; - } - - if (nfds == -1) { - if (errno != EINTR) - abort(); - if (reset_timeout != 0) { timeout = user_timeout; reset_timeout = 0; - } - - if (timeout == 0) + } else if (nfds == 0) { + /* Reached the user timeout value. */ + assert(timeout != -1); return; - - if (timeout == -1) - continue; + } /* Interrupted by a signal. Update timeout and poll again. */ goto update_timeout; @@ -413,13 +406,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { return; } +update_timeout: if (timeout == 0) return; if (timeout == -1) continue; -update_timeout: assert(timeout > 0); diff = loop->time - base; diff --git a/src/unix/loop.c b/src/unix/loop.c index 816ac179c65..90a51b339de 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -82,12 +82,9 @@ int uv_loop_init(uv_loop_t* loop) { goto fail_platform_init; uv__signal_global_once_init(); - err = uv_signal_init(loop, &loop->child_watcher); + err = uv__process_init(loop); if (err) goto fail_signal_init; - - uv__handle_unref(&loop->child_watcher); - loop->child_watcher.flags |= UV_HANDLE_INTERNAL; QUEUE_INIT(&loop->process_handles); err = uv_rwlock_init(&loop->cloexec_lock); diff --git a/src/unix/process.c b/src/unix/process.c index fff6192eea4..ab717404826 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -79,8 +79,28 @@ static void uv__chld(uv_signal_t* handle, int signum) { assert(signum == SIGCHLD); uv__wait_children(handle->loop); } + + +int uv__process_init(uv_loop_t* loop) { + int err; + + err = uv_signal_init(loop, &loop->child_watcher); + if (err) + return err; + uv__handle_unref(&loop->child_watcher); + loop->child_watcher.flags |= UV_HANDLE_INTERNAL; + return 0; +} + + +#else +int uv__process_init(uv_loop_t* loop) { + memset(&loop->child_watcher, 0, sizeof(loop->child_watcher)); + return 0; +} #endif + void uv__wait_children(uv_loop_t* loop) { uv_process_t* process; int exit_status; @@ -105,6 +125,7 @@ void uv__wait_children(uv_loop_t* loop) { continue; options = 0; process->flags &= ~UV_HANDLE_REAP; + loop->nfds--; #else options = WNOHANG; #endif @@ -1012,6 +1033,10 @@ int uv_spawn(uv_loop_t* loop, process->flags |= UV_HANDLE_REAP; loop->flags |= UV_LOOP_REAP_CHILDREN; } + /* This prevents uv__io_poll() from bailing out prematurely, being unaware + * that we added an event here for it to react to. We will decrement this + * again after the waitpid call succeeds. */ + loop->nfds++; #endif process->pid = pid; @@ -1080,6 +1105,8 @@ int uv_kill(int pid, int signum) { void uv__process_close(uv_process_t* handle) { QUEUE_REMOVE(&handle->queue); uv__handle_stop(handle); +#ifdef UV_USE_SIGCHLD if (QUEUE_EMPTY(&handle->loop->process_handles)) uv_signal_stop(&handle->loop->child_watcher); +#endif } diff --git a/src/unix/signal.c b/src/unix/signal.c index 1133c73a955..bb70523f561 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -279,6 +279,8 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) { int uv__signal_loop_fork(uv_loop_t* loop) { + if (loop->signal_pipefd[0] == -1) + return 0; uv__io_stop(loop, &loop->signal_io_watcher, POLLIN); uv__close(loop->signal_pipefd[0]); uv__close(loop->signal_pipefd[1]); From be2ddacb906939d989a422e5b44f121bcf720f0d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 1 Feb 2023 22:10:36 +0100 Subject: [PATCH 319/713] unix: abort on clock_gettime() error (#3898) Per standard libuv operating procedures, abort on unexpected failure. Don't silently ignore the error and return garbage. --- src/unix/posix-hrtime.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/unix/posix-hrtime.c b/src/unix/posix-hrtime.c index 323dfc20392..7b45c01a4d0 100644 --- a/src/unix/posix-hrtime.c +++ b/src/unix/posix-hrtime.c @@ -23,13 +23,14 @@ #include "internal.h" #include +#include #include -#undef NANOSEC -#define NANOSEC ((uint64_t) 1e9) - uint64_t uv__hrtime(uv_clocktype_t type) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); + struct timespec t; + + if (clock_gettime(CLOCK_MONOTONIC, &t)) + abort(); + + return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec; } From 84525b26fe614b01d13d39741fd322ee4fadfa50 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 7 Feb 2023 17:15:59 +0100 Subject: [PATCH 320/713] test: remove timing-sensitive check (#3899) Remove expectations around uv_cond_timedwait() maximum sleep time. The OpenBSD buildbot sleeps more than 5x longer than requested. It no longer makes sense to expect some reasonable upper bound because at that point we've moved well beyond reasonable. Fixes: https://github.com/libuv/libuv/issues/3896 --- test/test-condvar.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/test/test-condvar.c b/test/test-condvar.c index 32abccc2e76..61592d0e2d1 100644 --- a/test/test-condvar.c +++ b/test/test-condvar.c @@ -228,11 +228,6 @@ TEST_IMPL(condvar_4) { /* uv_cond_timedwait: One thread waits, no signal. Timeout should be delivered. */ TEST_IMPL(condvar_5) { worker_config wc; - int r; - /* ns */ - uint64_t before; - uint64_t after; - uint64_t elapsed; uint64_t timeout; timeout = 100 * 1000 * 1000; /* 100 ms in ns */ @@ -242,25 +237,11 @@ TEST_IMPL(condvar_5) { uv_mutex_lock(&wc.mutex); - /* We wait. - * No signaler, so this will only return if timeout is delivered. */ - before = uv_hrtime(); - r = uv_cond_timedwait(&wc.cond, &wc.mutex, timeout); - after = uv_hrtime(); + /* We wait. No signaler, so this will only return if timeout is delivered. */ + ASSERT_EQ(UV_ETIMEDOUT, uv_cond_timedwait(&wc.cond, &wc.mutex, timeout)); uv_mutex_unlock(&wc.mutex); - /* It timed out. */ - ASSERT(r == UV_ETIMEDOUT); - - /* It must have taken at least timeout, modulo system timer ticks. - * But it should not take too much longer. - * cf. MSDN docs: - * https://msdn.microsoft.com/en-us/library/ms687069(VS.85).aspx */ - elapsed = after - before; - ASSERT(0.75 * timeout <= elapsed); /* 1.0 too large for Windows. */ - ASSERT(elapsed <= 5.0 * timeout); /* MacOS has reported failures up to 1.75. */ - worker_config_destroy(&wc); return 0; From 62c2374a8c005ce9e42088965f8f8af2532c177b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 7 Feb 2023 14:59:39 -0500 Subject: [PATCH 321/713] unix: DRY and fix tcp bind error path (#3904) The conditional bind-to-port logic in tcp.c had an error path that closed the socket file descriptor while it was still owned by the uv_tcp_t handle. Fix that by not closing the file descriptor and refactoring the code so it is hopefully harder to get wrong in the future. The refactoring also makes the code a little flatter, removes duplicated code, and, arguably, is in a more idiomatic libuv style. Fixes: https://github.com/libuv/libuv/issues/3461 Replaces: https://github.com/libuv/libuv/pull/3462 Co-authored-by: Ben Noordhuis --- src/unix/internal.h | 6 +++ src/unix/tcp.c | 118 +++++++++++++++++++++----------------------- src/unix/udp.c | 6 --- 3 files changed, 63 insertions(+), 67 deletions(-) diff --git a/src/unix/internal.h b/src/unix/internal.h index d9892fcf9ed..150f30a2ad5 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -92,6 +92,12 @@ # define UV__PATH_MAX 8192 #endif +union uv__sockaddr { + struct sockaddr_in6 in6; + struct sockaddr_in in; + struct sockaddr addr; +}; + #define ACCESS_ONCE(type, var) \ (*(volatile type*) &(var)) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 881f392b821..ab4e06c2f67 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -28,16 +28,39 @@ #include -static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { - struct sockaddr_storage saddr; +static int maybe_bind_socket(int fd) { + union uv__sockaddr s; socklen_t slen; + + slen = sizeof(s); + memset(&s, 0, sizeof(s)); + + if (getsockname(fd, &s.addr, &slen)) + return UV__ERR(errno); + + if (s.addr.sa_family == AF_INET) + if (s.in.sin_port != 0) + return 0; /* Already bound to a port. */ + + if (s.addr.sa_family == AF_INET6) + if (s.in6.sin6_port != 0) + return 0; /* Already bound to a port. */ + + /* Bind to an arbitrary port. */ + if (bind(fd, &s.addr, slen)) + return UV__ERR(errno); + + return 0; +} + + +static int new_socket(uv_tcp_t* handle, int domain, unsigned int flags) { int sockfd; int err; - err = uv__socket(domain, SOCK_STREAM, 0); - if (err < 0) - return err; - sockfd = err; + sockfd = uv__socket(domain, SOCK_STREAM, 0); + if (sockfd < 0) + return sockfd; err = uv__stream_open((uv_stream_t*) handle, sockfd, flags); if (err) { @@ -45,74 +68,44 @@ static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { return err; } - if (flags & UV_HANDLE_BOUND) { - /* Bind this new socket to an arbitrary port */ - slen = sizeof(saddr); - memset(&saddr, 0, sizeof(saddr)); - if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) { - uv__close(sockfd); - return UV__ERR(errno); - } - - if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) { - uv__close(sockfd); - return UV__ERR(errno); - } - } + if (flags & UV_HANDLE_BOUND) + return maybe_bind_socket(sockfd); return 0; } -static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { - struct sockaddr_storage saddr; - socklen_t slen; +static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned int flags) { + int sockfd; + int err; - if (domain == AF_UNSPEC) { - handle->flags |= flags; - return 0; - } + if (domain == AF_UNSPEC) + goto out; - if (uv__stream_fd(handle) != -1) { + sockfd = uv__stream_fd(handle); + if (sockfd == -1) + return new_socket(handle, domain, flags); - if (flags & UV_HANDLE_BOUND) { - - if (handle->flags & UV_HANDLE_BOUND) { - /* It is already bound to a port. */ - handle->flags |= flags; - return 0; - } - - /* Query to see if tcp socket is bound. */ - slen = sizeof(saddr); - memset(&saddr, 0, sizeof(saddr)); - if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) - return UV__ERR(errno); - - if ((saddr.ss_family == AF_INET6 && - ((struct sockaddr_in6*) &saddr)->sin6_port != 0) || - (saddr.ss_family == AF_INET && - ((struct sockaddr_in*) &saddr)->sin_port != 0)) { - /* Handle is already bound to a port. */ - handle->flags |= flags; - return 0; - } - - /* Bind to arbitrary port */ - if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) - return UV__ERR(errno); - } + if (!(flags & UV_HANDLE_BOUND)) + goto out; - handle->flags |= flags; - return 0; - } + if (handle->flags & UV_HANDLE_BOUND) + goto out; /* Already bound to a port. */ + + err = maybe_bind_socket(sockfd); + if (err) + return err; - return new_socket(handle, domain, flags); +out: + + handle->flags |= flags; + return 0; } int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) { int domain; + int err; /* Use the lower 8 bits for the domain */ domain = flags & 0xFF; @@ -129,9 +122,12 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) { */ if (domain != AF_UNSPEC) { - int err = maybe_new_socket(tcp, domain, 0); + err = new_socket(tcp, domain, 0); if (err) { QUEUE_REMOVE(&tcp->handle_queue); + if (tcp->io_watcher.fd != -1) + uv__close(tcp->io_watcher.fd); + tcp->io_watcher.fd = -1; return err; } } @@ -338,7 +334,7 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) { int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { - unsigned long flags; + unsigned int flags; int err; if (tcp->delayed_error) diff --git a/src/unix/udp.c b/src/unix/udp.c index 42ce0ca77f9..110467ae5fc 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -40,12 +40,6 @@ # define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP #endif -union uv__sockaddr { - struct sockaddr_in6 in6; - struct sockaddr_in in; - struct sockaddr addr; -}; - static void uv__udp_run_completed(uv_udp_t* handle); static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents); static void uv__udp_recvmsg(uv_udp_t* handle); From e613fdd83cb1fb448ac0ebace7ade055d0068829 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 17 Feb 2023 13:59:02 +0100 Subject: [PATCH 322/713] macos: fix fsevents thread race conditions (#3909) ThreadSanitizer complains about unsynchronized access to the handle->loop->cf_state pointer. The warning is probably benign but the fsevents thread already knows the pointer. It doesn't have to read it, it just needs to propagate it. Refs: https://github.com/libuv/libuv/issues/3880 --- src/unix/fsevents.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c index 8b5b3d5b160..0535b4547aa 100644 --- a/src/unix/fsevents.c +++ b/src/unix/fsevents.c @@ -329,8 +329,9 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef, /* Runs in CF thread */ -static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { - uv__cf_loop_state_t* state; +static int uv__fsevents_create_stream(uv__cf_loop_state_t* state, + uv_loop_t* loop, + CFArrayRef paths) { FSEventStreamContext ctx; FSEventStreamRef ref; CFAbsoluteTime latency; @@ -371,10 +372,7 @@ static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { flags); assert(ref != NULL); - state = loop->cf_state; - pFSEventStreamScheduleWithRunLoop(ref, - state->loop, - *pkCFRunLoopDefaultMode); + pFSEventStreamScheduleWithRunLoop(ref, state->loop, *pkCFRunLoopDefaultMode); if (!pFSEventStreamStart(ref)) { pFSEventStreamInvalidate(ref); pFSEventStreamRelease(ref); @@ -387,11 +385,7 @@ static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { /* Runs in CF thread */ -static void uv__fsevents_destroy_stream(uv_loop_t* loop) { - uv__cf_loop_state_t* state; - - state = loop->cf_state; - +static void uv__fsevents_destroy_stream(uv__cf_loop_state_t* state) { if (state->fsevent_stream == NULL) return; @@ -406,9 +400,9 @@ static void uv__fsevents_destroy_stream(uv_loop_t* loop) { /* Runs in CF thread, when there're new fsevent handles to add to stream */ -static void uv__fsevents_reschedule(uv_fs_event_t* handle, +static void uv__fsevents_reschedule(uv__cf_loop_state_t* state, + uv_loop_t* loop, uv__cf_loop_signal_type_t type) { - uv__cf_loop_state_t* state; QUEUE* q; uv_fs_event_t* curr; CFArrayRef cf_paths; @@ -417,7 +411,6 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle, int err; unsigned int path_count; - state = handle->loop->cf_state; paths = NULL; cf_paths = NULL; err = 0; @@ -436,7 +429,7 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle, uv_mutex_unlock(&state->fsevent_mutex); /* Destroy previous FSEventStream */ - uv__fsevents_destroy_stream(handle->loop); + uv__fsevents_destroy_stream(state); /* Any failure below will be a memory failure */ err = UV_ENOMEM; @@ -476,7 +469,7 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle, err = UV_ENOMEM; goto final; } - err = uv__fsevents_create_stream(handle->loop, cf_paths); + err = uv__fsevents_create_stream(state, loop, cf_paths); } final: @@ -763,7 +756,7 @@ static void uv__cf_loop_cb(void* arg) { if (s->handle == NULL) pCFRunLoopStop(state->loop); else - uv__fsevents_reschedule(s->handle, s->type); + uv__fsevents_reschedule(state, loop, s->type); uv__free(s); } From 780b40ea7ba5773a41109108276e1eed207818c8 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Mon, 27 Feb 2023 11:58:12 -0700 Subject: [PATCH 323/713] win: fix leak in uv_chdir (#3912) The call to uv__cwd() always returns a new allocation. The previously allocated utf16_buffer needs to be free'd before passing it in to receive the next allocation. --- src/win/util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/win/util.c b/src/win/util.c index 647d6e66572..6232ce1505a 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -284,6 +284,10 @@ int uv_chdir(const char* dir) { return uv_translate_sys_error(GetLastError()); } + /* uv__cwd() will return a new buffer. */ + uv__free(utf16_buffer); + utf16_buffer = NULL; + /* Windows stores the drive-local path in an "hidden" environment variable, * which has the form "=C:=C:\Windows". SetCurrentDirectory does not update * this, so we'll have to do it. */ From 460accf9be077f376baebd93a39c214644442674 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Fri, 3 Mar 2023 13:52:31 -0700 Subject: [PATCH 324/713] test: make valgrind happy (#3916) Missing a call to MAKE_VALGRIND_HAPPY() to silence valgrind output. --- test/test-fs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test-fs.c b/test/test-fs.c index fd2b651c1be..ec823f111e4 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -4513,6 +4513,7 @@ TEST_IMPL(fs_statfs) { uv_run(loop, UV_RUN_DEFAULT); ASSERT(statfs_cb_count == 2); + MAKE_VALGRIND_HAPPY(); return 0; } From 964f79f7c81f4457e7750601ea961cd0299797f7 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 6 Mar 2023 17:57:25 -0500 Subject: [PATCH 325/713] barrier: wait for prior out before next in (#3905) This code would previously get confused between rounds of the barrier being called and a thread might incorrectly get stuck (deadlock) if the next round started before that thread had exited the current round. Avoid that by not starting the next round in++ before out-- has reached zero indicating that all threads have left the prior round. And fix it that on Windows by replacing the implementation with the one from unix. There are some awkward platform-specific redirection here with an extra malloc that is not needed on Win32, but that will be fixed in libuv v2. Fixes: https://github.com/libuv/libuv/issue/3872 --- CMakeLists.txt | 1 + Makefile.am | 1 + include/uv/win.h | 9 ++- src/thread-common.c | 175 ++++++++++++++++++++++++++++++++++++++++++++ src/unix/thread.c | 120 +----------------------------- src/win/thread.c | 64 +--------------- test/test-barrier.c | 58 +++++++++------ 7 files changed, 219 insertions(+), 209 deletions(-) create mode 100644 src/thread-common.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 58163f69af0..1fb05a921a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -166,6 +166,7 @@ set(uv_sources src/random.c src/strscpy.c src/strtok.c + src/thread-common.c src/threadpool.c src/timer.c src/uv-common.c diff --git a/Makefile.am b/Makefile.am index c2c9970d715..be2661580fa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,6 +38,7 @@ libuv_la_SOURCES = src/fs-poll.c \ src/random.c \ src/strscpy.c \ src/strscpy.h \ + src/thread-common.c \ src/threadpool.c \ src/timer.c \ src/uv-data-getter-setters.c \ diff --git a/include/uv/win.h b/include/uv/win.h index 3c3fa016490..1dee8ac5cb3 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -274,11 +274,12 @@ typedef struct { } uv_rwlock_t; typedef struct { - unsigned int n; - unsigned int count; + unsigned threshold; + unsigned in; uv_mutex_t mutex; - uv_sem_t turnstile1; - uv_sem_t turnstile2; + /* TODO: in v2 make this a uv_cond_t, without unused_ */ + CONDITION_VARIABLE cond; + unsigned out; } uv_barrier_t; typedef struct { diff --git a/src/thread-common.c b/src/thread-common.c new file mode 100644 index 00000000000..c67c0a7dd72 --- /dev/null +++ b/src/thread-common.c @@ -0,0 +1,175 @@ +/* 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 "uv-common.h" + +#include +#ifndef _WIN32 +#include +#endif + +#if defined(PTHREAD_BARRIER_SERIAL_THREAD) +STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t)); +#endif + +/* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */ +#if defined(_AIX) || \ + defined(__OpenBSD__) || \ + !defined(PTHREAD_BARRIER_SERIAL_THREAD) +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + int rc; +#ifdef _WIN32 + uv_barrier_t* b; + b = barrier; + + if (barrier == NULL || count == 0) + return UV_EINVAL; +#else + struct _uv_barrier* b; + + if (barrier == NULL || count == 0) + return UV_EINVAL; + + b = uv__malloc(sizeof(*b)); + if (b == NULL) + return UV_ENOMEM; +#endif + + b->in = 0; + b->out = 0; + b->threshold = count; + + rc = uv_mutex_init(&b->mutex); + if (rc != 0) + goto error2; + + /* TODO(vjnash): remove these uv_cond_t casts in v2. */ + rc = uv_cond_init((uv_cond_t*) &b->cond); + if (rc != 0) + goto error; + +#ifndef _WIN32 + barrier->b = b; +#endif + return 0; + +error: + uv_mutex_destroy(&b->mutex); +error2: +#ifndef _WIN32 + uv__free(b); +#endif + return rc; +} + + +int uv_barrier_wait(uv_barrier_t* barrier) { + int last; +#ifdef _WIN32 + uv_barrier_t* b; + b = barrier; +#else + struct _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return UV_EINVAL; + + b = barrier->b; +#endif + + uv_mutex_lock(&b->mutex); + + while (b->out != 0) + uv_cond_wait((uv_cond_t*) &b->cond, &b->mutex); + + if (++b->in == b->threshold) { + b->in = 0; + b->out = b->threshold; + uv_cond_broadcast((uv_cond_t*) &b->cond); + } else { + do + uv_cond_wait((uv_cond_t*) &b->cond, &b->mutex); + while (b->in != 0); + } + + last = (--b->out == 0); + if (last) + uv_cond_broadcast((uv_cond_t*) &b->cond); + + uv_mutex_unlock(&b->mutex); + return last; +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { +#ifdef _WIN32 + uv_barrier_t* b; + b = barrier; +#else + struct _uv_barrier* b; + b = barrier->b; +#endif + + uv_mutex_lock(&b->mutex); + + assert(b->in == 0); + while (b->out != 0) + uv_cond_wait((uv_cond_t*) &b->cond, &b->mutex); + + if (b->in != 0) + abort(); + + uv_mutex_unlock(&b->mutex); + uv_mutex_destroy(&b->mutex); + uv_cond_destroy((uv_cond_t*) &b->cond); + +#ifndef _WIN32 + uv__free(barrier->b); + barrier->b = NULL; +#endif +} + +#else + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + return UV__ERR(pthread_barrier_init(barrier, NULL, count)); +} + + +int uv_barrier_wait(uv_barrier_t* barrier) { + int rc; + + rc = pthread_barrier_wait(barrier); + if (rc != 0) + if (rc != PTHREAD_BARRIER_SERIAL_THREAD) + abort(); + + return rc == PTHREAD_BARRIER_SERIAL_THREAD; +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { + if (pthread_barrier_destroy(barrier)) + abort(); +} + +#endif diff --git a/src/unix/thread.c b/src/unix/thread.c index 8e3652f10e9..4d6f4b8232e 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -55,124 +55,6 @@ #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) -#if defined(PTHREAD_BARRIER_SERIAL_THREAD) -STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t)); -#endif - -/* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */ -#if defined(_AIX) || \ - defined(__OpenBSD__) || \ - !defined(PTHREAD_BARRIER_SERIAL_THREAD) -int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { - struct _uv_barrier* b; - int rc; - - if (barrier == NULL || count == 0) - return UV_EINVAL; - - b = uv__malloc(sizeof(*b)); - if (b == NULL) - return UV_ENOMEM; - - b->in = 0; - b->out = 0; - b->threshold = count; - - rc = uv_mutex_init(&b->mutex); - if (rc != 0) - goto error2; - - rc = uv_cond_init(&b->cond); - if (rc != 0) - goto error; - - barrier->b = b; - return 0; - -error: - uv_mutex_destroy(&b->mutex); -error2: - uv__free(b); - return rc; -} - - -int uv_barrier_wait(uv_barrier_t* barrier) { - struct _uv_barrier* b; - int last; - - if (barrier == NULL || barrier->b == NULL) - return UV_EINVAL; - - b = barrier->b; - uv_mutex_lock(&b->mutex); - - if (++b->in == b->threshold) { - b->in = 0; - b->out = b->threshold; - uv_cond_signal(&b->cond); - } else { - do - uv_cond_wait(&b->cond, &b->mutex); - while (b->in != 0); - } - - last = (--b->out == 0); - uv_cond_signal(&b->cond); - - uv_mutex_unlock(&b->mutex); - return last; -} - - -void uv_barrier_destroy(uv_barrier_t* barrier) { - struct _uv_barrier* b; - - b = barrier->b; - uv_mutex_lock(&b->mutex); - - assert(b->in == 0); - while (b->out != 0) - uv_cond_wait(&b->cond, &b->mutex); - - if (b->in != 0) - abort(); - - uv_mutex_unlock(&b->mutex); - uv_mutex_destroy(&b->mutex); - uv_cond_destroy(&b->cond); - - uv__free(barrier->b); - barrier->b = NULL; -} - -#else - -int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { - return UV__ERR(pthread_barrier_init(barrier, NULL, count)); -} - - -int uv_barrier_wait(uv_barrier_t* barrier) { - int rc; - - rc = pthread_barrier_wait(barrier); - if (rc != 0) - if (rc != PTHREAD_BARRIER_SERIAL_THREAD) - abort(); - - return rc == PTHREAD_BARRIER_SERIAL_THREAD; -} - - -void uv_barrier_destroy(uv_barrier_t* barrier) { - if (pthread_barrier_destroy(barrier)) - abort(); -} - -#endif - - /* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is * too small to safely receive signals on. * @@ -696,7 +578,7 @@ static void uv__custom_sem_post(uv_sem_t* sem_) { uv_mutex_lock(&sem->mutex); sem->value++; if (sem->value == 1) - uv_cond_signal(&sem->cond); + uv_cond_signal(&sem->cond); /* Release one to replace us. */ uv_mutex_unlock(&sem->mutex); } diff --git a/src/win/thread.c b/src/win/thread.c index 5e86999c28d..57c25e8f5a8 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -449,6 +449,7 @@ void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { abort(); } + int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { if (SleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6))) return 0; @@ -458,69 +459,6 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { } -int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { - int err; - - barrier->n = count; - barrier->count = 0; - - err = uv_mutex_init(&barrier->mutex); - if (err) - return err; - - err = uv_sem_init(&barrier->turnstile1, 0); - if (err) - goto error2; - - err = uv_sem_init(&barrier->turnstile2, 1); - if (err) - goto error; - - return 0; - -error: - uv_sem_destroy(&barrier->turnstile1); -error2: - uv_mutex_destroy(&barrier->mutex); - return err; - -} - - -void uv_barrier_destroy(uv_barrier_t* barrier) { - uv_sem_destroy(&barrier->turnstile2); - uv_sem_destroy(&barrier->turnstile1); - uv_mutex_destroy(&barrier->mutex); -} - - -int uv_barrier_wait(uv_barrier_t* barrier) { - int serial_thread; - - uv_mutex_lock(&barrier->mutex); - if (++barrier->count == barrier->n) { - uv_sem_wait(&barrier->turnstile2); - uv_sem_post(&barrier->turnstile1); - } - uv_mutex_unlock(&barrier->mutex); - - uv_sem_wait(&barrier->turnstile1); - uv_sem_post(&barrier->turnstile1); - - uv_mutex_lock(&barrier->mutex); - serial_thread = (--barrier->count == 0); - if (serial_thread) { - uv_sem_wait(&barrier->turnstile1); - uv_sem_post(&barrier->turnstile2); - } - uv_mutex_unlock(&barrier->mutex); - - uv_sem_wait(&barrier->turnstile2); - uv_sem_post(&barrier->turnstile2); - return serial_thread; -} - - int uv_key_create(uv_key_t* key) { key->tls_index = TlsAlloc(); if (key->tls_index == TLS_OUT_OF_INDEXES) diff --git a/test/test-barrier.c b/test/test-barrier.c index 89858db5711..c780f0cf2dd 100644 --- a/test/test-barrier.c +++ b/test/test-barrier.c @@ -27,20 +27,22 @@ typedef struct { uv_barrier_t barrier; - int delay; - volatile int posted; - int main_barrier_wait_rval; - int worker_barrier_wait_rval; + unsigned delay; + unsigned niter; + unsigned main_barrier_wait_rval; + unsigned worker_barrier_wait_rval; } worker_config; static void worker(void* arg) { worker_config* c = arg; + unsigned i; if (c->delay) uv_sleep(c->delay); - c->worker_barrier_wait_rval = uv_barrier_wait(&c->barrier); + for (i = 0; i < c->niter; i++) + c->worker_barrier_wait_rval += uv_barrier_wait(&c->barrier); } @@ -49,17 +51,18 @@ TEST_IMPL(barrier_1) { worker_config wc; memset(&wc, 0, sizeof(wc)); + wc.niter = 1; - ASSERT(0 == uv_barrier_init(&wc.barrier, 2)); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + ASSERT_EQ(0, uv_barrier_init(&wc.barrier, 2)); + ASSERT_EQ(0, uv_thread_create(&thread, worker, &wc)); uv_sleep(100); wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_EQ(0, uv_thread_join(&thread)); uv_barrier_destroy(&wc.barrier); - ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval)); + ASSERT_EQ(1, (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval)); return 0; } @@ -71,16 +74,17 @@ TEST_IMPL(barrier_2) { memset(&wc, 0, sizeof(wc)); wc.delay = 100; + wc.niter = 1; - ASSERT(0 == uv_barrier_init(&wc.barrier, 2)); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + ASSERT_EQ(0, uv_barrier_init(&wc.barrier, 2)); + ASSERT_EQ(0, uv_thread_create(&thread, worker, &wc)); wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_EQ(0, uv_thread_join(&thread)); uv_barrier_destroy(&wc.barrier); - ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval)); + ASSERT_EQ(1, (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval)); return 0; } @@ -89,26 +93,32 @@ TEST_IMPL(barrier_2) { TEST_IMPL(barrier_3) { uv_thread_t thread; worker_config wc; + unsigned i; memset(&wc, 0, sizeof(wc)); + wc.niter = 5; - ASSERT(0 == uv_barrier_init(&wc.barrier, 2)); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + ASSERT_EQ(0, uv_barrier_init(&wc.barrier, 2)); + ASSERT_EQ(0, uv_thread_create(&thread, worker, &wc)); - wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier); + for (i = 0; i < wc.niter; i++) + wc.main_barrier_wait_rval += uv_barrier_wait(&wc.barrier); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_EQ(0, uv_thread_join(&thread)); uv_barrier_destroy(&wc.barrier); - ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval)); + ASSERT_EQ(wc.niter, wc.main_barrier_wait_rval + wc.worker_barrier_wait_rval); return 0; } static void serial_worker(void* data) { uv_barrier_t* barrier; + unsigned i; barrier = data; + for (i = 0; i < 5; i++) + uv_barrier_wait(barrier); if (uv_barrier_wait(barrier) > 0) uv_barrier_destroy(barrier); @@ -123,16 +133,18 @@ TEST_IMPL(barrier_serial_thread) { uv_barrier_t barrier; unsigned i; - ASSERT(0 == uv_barrier_init(&barrier, ARRAY_SIZE(threads) + 1)); + ASSERT_EQ(0, uv_barrier_init(&barrier, ARRAY_SIZE(threads) + 1)); for (i = 0; i < ARRAY_SIZE(threads); ++i) - ASSERT(0 == uv_thread_create(&threads[i], serial_worker, &barrier)); + ASSERT_EQ(0, uv_thread_create(&threads[i], serial_worker, &barrier)); + for (i = 0; i < 5; i++) + uv_barrier_wait(&barrier); if (uv_barrier_wait(&barrier) > 0) uv_barrier_destroy(&barrier); for (i = 0; i < ARRAY_SIZE(threads); ++i) - ASSERT(0 == uv_thread_join(&threads[i])); + ASSERT_EQ(0, uv_thread_join(&threads[i])); return 0; } @@ -141,8 +153,8 @@ TEST_IMPL(barrier_serial_thread) { TEST_IMPL(barrier_serial_thread_single) { uv_barrier_t barrier; - ASSERT(0 == uv_barrier_init(&barrier, 1)); - ASSERT(0 < uv_barrier_wait(&barrier)); + ASSERT_EQ(0, uv_barrier_init(&barrier, 1)); + ASSERT_LT(0, uv_barrier_wait(&barrier)); uv_barrier_destroy(&barrier); return 0; } From 9581e3df0cb3529372d731710d70c94e0c0fe8e7 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 10 Mar 2023 11:41:35 +0100 Subject: [PATCH 326/713] test: fix visual studio 2015 build error (#3918) --- test/test-fs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test-fs.c b/test/test-fs.c index ec823f111e4..ea672d367f2 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -37,6 +37,9 @@ # ifndef ERROR_SYMLINK_NOT_SUPPORTED # define ERROR_SYMLINK_NOT_SUPPORTED 1464 # endif +# ifndef S_IFIFO +# define S_IFIFO _S_IFIFO +# endif # define unlink _unlink # define rmdir _rmdir # define open _open From dfb206c8b06d9581dbbc52e2013dc18681694683 Mon Sep 17 00:00:00 2001 From: Bruno Passeri Date: Sun, 12 Mar 2023 12:05:45 +0100 Subject: [PATCH 327/713] linux: fix ceph copy error truncating readonly files (#3920) Trying to copy a read-only file onto a ceph-fuse filesystem fails, returning an `EACCES` error. This happens when the destination doesn't exist yet, and a new file is created. By checking that the error matches, and that the destination file is empty, we can fix this issue while waiting for a proper Ceph fix to be upstreamed. Fixes: https://github.com/libuv/libuv/issues/3919 Refs: https://github.com/nodejs/node/issues/37284 Refs: https://github.com/libuv/libuv/issues/3117 Refs: https://github.com/libuv/libuv/issues/3322 --- src/unix/fs.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index e1120cd775b..ea1d305f31d 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1306,7 +1306,19 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { /* Truncate the file in case the destination already existed. */ if (ftruncate(dstfd, 0) != 0) { err = UV__ERR(errno); - goto out; + + /* ftruncate() on ceph-fuse fails with EACCES when the file is created + * with read only permissions. Since ftruncate() on a newly created + * file is a meaningless operation anyway, detect that condition + * and squelch the error. + */ + if (err != UV_EACCES) + goto out; + + if (dst_statsbuf.st_size > 0) + goto out; + + err = 0; } } From 91a7e49846f8786132da08e48cfd92bdd12f8cf7 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Sun, 12 Mar 2023 07:59:00 -0600 Subject: [PATCH 328/713] test: silence more valgrind warnings (#3917) Pass the loop to MAKE_VALGRIND_HAPPY() so it's explicit on which loop needs to be cleaned up. Since it asserts on uv_loop_close(), need to remove a couple of those that were being done before the call. Cleanup where loop was assigned, so the entire test either uses loop or uv_default_loop(). Not both. Also take care of any reqs that may have been left uncleaned. --- test/benchmark-async-pummel.c | 2 +- test/benchmark-async.c | 2 +- test/benchmark-fs-stat.c | 2 +- test/benchmark-getaddrinfo.c | 2 +- test/benchmark-loop-count.c | 4 +- test/benchmark-million-async.c | 2 +- test/benchmark-million-timers.c | 2 +- test/benchmark-multi-accept.c | 2 +- test/benchmark-ping-pongs.c | 2 +- test/benchmark-ping-udp.c | 2 +- test/benchmark-pound.c | 2 +- test/benchmark-pump.c | 6 +- test/benchmark-queue-work.c | 2 +- test/benchmark-spawn.c | 2 +- test/benchmark-tcp-write-batch.c | 2 +- test/benchmark-udp-pummel.c | 2 +- test/task.h | 10 +- test/test-active.c | 2 +- test/test-async-null-cb.c | 2 +- test/test-async.c | 2 +- test/test-callback-stack.c | 2 +- test/test-close-fd.c | 2 +- test/test-close-order.c | 2 +- test/test-connect-unspecified.c | 1 + test/test-connection-fail.c | 4 +- test/test-default-loop-close.c | 3 +- test/test-delayed-accept.c | 2 +- test/test-eintr-handling.c | 2 +- test/test-embed.c | 2 +- test/test-emfile.c | 2 +- test/test-fork.c | 25 ++-- test/test-fs-copyfile.c | 1 + test/test-fs-event.c | 40 +++--- test/test-fs-open-flags.c | 2 +- test/test-fs-poll.c | 20 +-- test/test-fs-readdir.c | 8 +- test/test-fs.c | 115 +++++++++--------- test/test-getaddrinfo.c | 10 +- test/test-getnameinfo.c | 6 +- test/test-getsockname.c | 4 +- test/test-handle-fileno.c | 2 +- test/test-idle.c | 4 +- test/test-ip-name.c | 4 +- test/test-ip4-addr.c | 2 +- test/test-ip6-addr.c | 4 +- test/test-ipc-heavy-traffic-deadlock-bug.c | 4 +- test/test-ipc-send-recv.c | 6 +- test/test-ipc.c | 14 +-- test/test-loop-alive.c | 1 + test/test-loop-close.c | 4 +- test/test-loop-handles.c | 2 +- test/test-loop-stop.c | 1 + test/test-loop-time.c | 4 +- test/test-metrics.c | 6 +- test/test-multiple-listen.c | 2 +- ...-not-readable-nor-writable-on-read-error.c | 2 +- test/test-not-writable-after-shutdown.c | 4 +- test/test-osx-select.c | 4 +- test/test-ping-pong.c | 2 +- test/test-pipe-bind-error.c | 10 +- test/test-pipe-close-stdout-read-stdin.c | 2 +- test/test-pipe-connect-error.c | 4 +- test/test-pipe-connect-multiple.c | 4 +- test/test-pipe-connect-prepare.c | 2 +- test/test-pipe-getsockname.c | 8 +- test/test-pipe-pending-instances.c | 2 +- test/test-pipe-sendmsg.c | 4 +- test/test-pipe-server-close.c | 2 +- test/test-pipe-set-fchmod.c | 4 +- test/test-pipe-set-non-blocking.c | 2 +- test/test-pipe-try-write.c | 2 +- test/test-poll-close-doesnt-corrupt-stack.c | 2 +- test/test-poll-close.c | 2 +- test/test-poll-closesocket.c | 2 +- test/test-poll-multiple-handles.c | 2 +- test/test-poll-oob.c | 2 +- test/test-poll.c | 8 +- test/test-process-title.c | 2 +- test/test-queue-foreach-delete.c | 2 +- test/test-random.c | 4 +- test/test-readable-on-eof.c | 2 +- test/test-ref.c | 48 ++++---- test/test-run-nowait.c | 1 + test/test-run-once.c | 2 +- test/test-shutdown-close.c | 4 +- test/test-shutdown-eof.c | 2 +- test/test-shutdown-simultaneous.c | 2 +- test/test-shutdown-twice.c | 4 +- test/test-signal-multiple-loops.c | 2 +- test/test-signal-pending-on-close.c | 7 +- test/test-signal.c | 12 +- test/test-socket-buffer-size.c | 2 +- test/test-spawn.c | 72 +++++------ test/test-stdio-over-pipes.c | 6 +- test/test-tcp-alloc-cb-fail.c | 2 +- test/test-tcp-bind-error.c | 22 ++-- test/test-tcp-bind6-error.c | 10 +- test/test-tcp-close-accept.c | 2 +- test/test-tcp-close-after-read-timeout.c | 2 +- test/test-tcp-close-reset.c | 10 +- test/test-tcp-close-while-connecting.c | 2 +- test/test-tcp-close.c | 2 +- test/test-tcp-connect-error-after-write.c | 2 +- test/test-tcp-connect-error.c | 2 +- test/test-tcp-connect-timeout.c | 6 +- test/test-tcp-connect6-error.c | 2 +- test/test-tcp-create-socket-early.c | 8 +- test/test-tcp-flags.c | 2 +- test/test-tcp-oob.c | 2 +- test/test-tcp-open.c | 10 +- test/test-tcp-read-stop-start.c | 2 +- test/test-tcp-read-stop.c | 2 +- test/test-tcp-rst.c | 2 +- test/test-tcp-shutdown-after-write.c | 2 +- test/test-tcp-try-write-error.c | 2 +- test/test-tcp-try-write.c | 2 +- test/test-tcp-unexpected-read.c | 2 +- test/test-tcp-write-after-connect.c | 2 +- test/test-tcp-write-fail.c | 2 +- test/test-tcp-write-in-a-row.c | 2 +- test/test-tcp-write-queue-order.c | 2 +- test/test-tcp-write-to-half-open-connection.c | 2 +- test/test-tcp-writealot.c | 2 +- test/test-threadpool-cancel.c | 12 +- test/test-threadpool.c | 4 +- test/test-timer-again.c | 2 +- test/test-timer-from-check.c | 2 +- test/test-timer.c | 20 +-- test/test-tty-duplicate-key.c | 6 +- test/test-tty-escape-sequence-processing.c | 32 ++--- test/test-tty.c | 27 ++-- test/test-udp-alloc-cb-fail.c | 2 +- test/test-udp-bind.c | 4 +- test/test-udp-connect.c | 2 +- test/test-udp-connect6.c | 2 +- test/test-udp-create-socket-early.c | 6 +- test/test-udp-dgram-too-big.c | 2 +- test/test-udp-ipv6.c | 2 +- test/test-udp-mmsg.c | 2 +- test/test-udp-multicast-interface.c | 2 +- test/test-udp-multicast-interface6.c | 2 +- test/test-udp-multicast-join.c | 2 +- test/test-udp-multicast-join6.c | 4 +- test/test-udp-multicast-ttl.c | 2 +- test/test-udp-open.c | 10 +- test/test-udp-options.c | 4 +- test/test-udp-recv-in-a-row.c | 2 +- test/test-udp-send-and-recv.c | 2 +- test/test-udp-send-hang-loop.c | 2 +- test/test-udp-send-immediate.c | 2 +- test/test-udp-send-unreachable.c | 2 +- test/test-udp-sendmmsg-error.c | 2 +- test/test-udp-try-send.c | 2 +- test/test-walk-handles.c | 2 +- test/test-watcher-cross-stop.c | 2 +- 155 files changed, 449 insertions(+), 451 deletions(-) diff --git a/test/benchmark-async-pummel.c b/test/benchmark-async-pummel.c index 49660a6f575..93f9b1aa996 100644 --- a/test/benchmark-async-pummel.c +++ b/test/benchmark-async-pummel.c @@ -94,7 +94,7 @@ static int test_async_pummel(int nthreads) { free(tids); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/benchmark-async.c b/test/benchmark-async.c index 5167ecbd758..59aed6f7bf5 100644 --- a/test/benchmark-async.c +++ b/test/benchmark-async.c @@ -116,7 +116,7 @@ static int test_async(int nthreads) { free(threads); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/benchmark-fs-stat.c b/test/benchmark-fs-stat.c index 32d2589586c..195f5052b8b 100644 --- a/test/benchmark-fs-stat.c +++ b/test/benchmark-fs-stat.c @@ -131,6 +131,6 @@ BENCHMARK_IMPL(fs_stat) { warmup(path); sync_bench(path); async_bench(path); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/benchmark-getaddrinfo.c b/test/benchmark-getaddrinfo.c index 1dbc23ddba0..1ef7b1ef095 100644 --- a/test/benchmark-getaddrinfo.c +++ b/test/benchmark-getaddrinfo.c @@ -87,6 +87,6 @@ BENCHMARK_IMPL(getaddrinfo) { (double) calls_completed / (double) (end_time - start_time) * 1000.0); fflush(stderr); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/benchmark-loop-count.c b/test/benchmark-loop-count.c index 970a94c2fec..4aa39867bb1 100644 --- a/test/benchmark-loop-count.c +++ b/test/benchmark-loop-count.c @@ -68,7 +68,7 @@ BENCHMARK_IMPL(loop_count) { NUM_TICKS / (ns / 1e9)); fflush(stderr); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -87,6 +87,6 @@ BENCHMARK_IMPL(loop_count_timed) { fprintf(stderr, "loop_count: %lu ticks (%.0f ticks/s)\n", ticks, ticks / 5.0); fflush(stderr); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/benchmark-million-async.c b/test/benchmark-million-async.c index 937a12f81e6..d398332ed20 100644 --- a/test/benchmark-million-async.c +++ b/test/benchmark-million-async.c @@ -107,6 +107,6 @@ BENCHMARK_IMPL(million_async) { fmt(container->handles_seen)); free(container); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/benchmark-million-timers.c b/test/benchmark-million-timers.c index ef25c2052d6..b35fd5e7882 100644 --- a/test/benchmark-million-timers.c +++ b/test/benchmark-million-timers.c @@ -81,6 +81,6 @@ BENCHMARK_IMPL(million_timers) { fprintf(stderr, "%.2f seconds cleanup\n", (after_all - after_run) / 1e9); fflush(stderr); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/benchmark-multi-accept.c b/test/benchmark-multi-accept.c index 86b7da5acd1..e2026276721 100644 --- a/test/benchmark-multi-accept.c +++ b/test/benchmark-multi-accept.c @@ -431,7 +431,7 @@ static int test_tcp(unsigned int num_servers, unsigned int num_clients) { free(clients); free(servers); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/benchmark-ping-pongs.c b/test/benchmark-ping-pongs.c index 646a7df9447..0357704e66e 100644 --- a/test/benchmark-ping-pongs.c +++ b/test/benchmark-ping-pongs.c @@ -216,6 +216,6 @@ BENCHMARK_IMPL(ping_pongs) { ASSERT(completed_pingers == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/benchmark-ping-udp.c b/test/benchmark-ping-udp.c index cf9ca9811f7..3db8765bf9c 100644 --- a/test/benchmark-ping-udp.c +++ b/test/benchmark-ping-udp.c @@ -153,7 +153,7 @@ static int ping_udp(unsigned pingers) { fprintf(stderr, "ping_pongs: %d pingers, ~ %lu roundtrips/s\n", completed_pingers, completed_pings / (TIME/1000)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/benchmark-pound.c b/test/benchmark-pound.c index 830bc554b34..acfe4497a2e 100644 --- a/test/benchmark-pound.c +++ b/test/benchmark-pound.c @@ -306,7 +306,7 @@ static int pound_it(int concurrency, conns_failed); fflush(stderr); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/benchmark-pump.c b/test/benchmark-pump.c index 7d3977dfc32..316c6809960 100644 --- a/test/benchmark-pump.c +++ b/test/benchmark-pump.c @@ -415,7 +415,7 @@ HELPER_IMPL(pipe_pump_server) { notify_parent_process(); uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -434,7 +434,7 @@ static void tcp_pump(int n) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); } @@ -450,7 +450,7 @@ static void pipe_pump(int n) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); } diff --git a/test/benchmark-queue-work.c b/test/benchmark-queue-work.c index 2dd5cb66561..439be16a9f5 100644 --- a/test/benchmark-queue-work.c +++ b/test/benchmark-queue-work.c @@ -63,6 +63,6 @@ BENCHMARK_IMPL(queue_work) { printf("%s async jobs in %.1f seconds (%s/s)\n", fmt(events), timeout / 1000., fmt(events / (timeout / 1000.))); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/benchmark-spawn.c b/test/benchmark-spawn.c index ed9ad608f37..bdaf6c1a254 100644 --- a/test/benchmark-spawn.c +++ b/test/benchmark-spawn.c @@ -159,6 +159,6 @@ BENCHMARK_IMPL(spawn) { (double) N / (double) (end_time - start_time) * 1000.0); fflush(stderr); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/benchmark-tcp-write-batch.c b/test/benchmark-tcp-write-batch.c index 16aa72f6bf7..aedefb74255 100644 --- a/test/benchmark-tcp-write-batch.c +++ b/test/benchmark-tcp-write-batch.c @@ -139,6 +139,6 @@ BENCHMARK_IMPL(tcp_write_batch) { (long)NUM_WRITE_REQS, (stop - start) / 1e9); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/benchmark-udp-pummel.c b/test/benchmark-udp-pummel.c index 1a220570260..f89913b6ceb 100644 --- a/test/benchmark-udp-pummel.c +++ b/test/benchmark-udp-pummel.c @@ -215,7 +215,7 @@ static int pummel(unsigned int n_senders, send_cb_called, duration / 1000.0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/task.h b/test/task.h index 7f7ed015998..0bf69927dd8 100644 --- a/test/task.h +++ b/test/task.h @@ -243,13 +243,13 @@ typedef enum { #define ASSERT_PTR_NE(a, b) \ ASSERT_BASE(a, !=, b, void*, "p") -/* This macro cleans up the main loop. This is used to avoid valgrind - * warnings about memory being "leaked" by the main event loop. +/* This macro cleans up the event loop. This is used to avoid valgrind + * warnings about memory being "leaked" by the event loop. */ -#define MAKE_VALGRIND_HAPPY() \ +#define MAKE_VALGRIND_HAPPY(loop) \ do { \ - close_loop(uv_default_loop()); \ - ASSERT(0 == uv_loop_close(uv_default_loop())); \ + close_loop(loop); \ + ASSERT(0 == uv_loop_close(loop)); \ uv_library_shutdown(); \ } while (0) diff --git a/test/test-active.c b/test/test-active.c index 384389561a7..aaff97087b1 100644 --- a/test/test-active.c +++ b/test/test-active.c @@ -79,6 +79,6 @@ TEST_IMPL(active) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-async-null-cb.c b/test/test-async-null-cb.c index 52652d91ebf..1bdd0e03249 100644 --- a/test/test-async-null-cb.c +++ b/test/test-async-null-cb.c @@ -59,6 +59,6 @@ TEST_IMPL(async_null_cb) { ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT(0 == uv_thread_join(&thread)); ASSERT(1 == check_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-async.c b/test/test-async.c index 619be620e3e..73664ea5d67 100644 --- a/test/test-async.c +++ b/test/test-async.c @@ -129,6 +129,6 @@ TEST_IMPL(async) { ASSERT(0 == uv_thread_join(&thread)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-callback-stack.c b/test/test-callback-stack.c index a5195c7b7f3..5dad8d75d2a 100644 --- a/test/test-callback-stack.c +++ b/test/test-callback-stack.c @@ -199,6 +199,6 @@ TEST_IMPL(callback_stack) { ASSERT(shutdown_cb_called == 1 && "shutdown_cb must be called exactly once"); ASSERT(close_cb_called == 2 && "close_cb must be called exactly twice"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-close-fd.c b/test/test-close-fd.c index 0d3927f652e..d8e12653f77 100644 --- a/test/test-close-fd.c +++ b/test/test-close-fd.c @@ -79,6 +79,6 @@ TEST_IMPL(close_fd) { ASSERT(2 == read_cb_called); ASSERT(0 != uv_is_closing((const uv_handle_t *) &pipe_handle)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-close-order.c b/test/test-close-order.c index c2fd6c3d0de..768e1ceedbe 100644 --- a/test/test-close-order.c +++ b/test/test-close-order.c @@ -75,6 +75,6 @@ TEST_IMPL(close_order) { ASSERT(close_cb_called == 3); ASSERT(timer_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-connect-unspecified.c b/test/test-connect-unspecified.c index 5f32b67a6a4..ecbe98538ed 100644 --- a/test/test-connect-unspecified.c +++ b/test/test-connect-unspecified.c @@ -59,5 +59,6 @@ TEST_IMPL(connect_unspecified) { ASSERT(uv_run(loop, UV_RUN_DEFAULT) == 0); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-connection-fail.c b/test/test-connection-fail.c index 59048102529..aa7db30d85a 100644 --- a/test/test-connection-fail.c +++ b/test/test-connection-fail.c @@ -130,7 +130,7 @@ TEST_IMPL(connection_fail) { ASSERT(timer_close_cb_calls == 0); ASSERT(timer_cb_calls == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -156,6 +156,6 @@ TEST_IMPL(connection_fail_doesnt_auto_close) { ASSERT(timer_close_cb_calls == 1); ASSERT(timer_cb_calls == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-default-loop-close.c b/test/test-default-loop-close.c index 51e1e7dc23b..8d960e1130a 100644 --- a/test/test-default-loop-close.c +++ b/test/test-default-loop-close.c @@ -52,8 +52,7 @@ TEST_IMPL(default_loop_close) { ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0)); ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(2 == timer_cb_called); - ASSERT(0 == uv_loop_close(loop)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-delayed-accept.c b/test/test-delayed-accept.c index 88b31e26903..c1d6ce0b45b 100644 --- a/test/test-delayed-accept.c +++ b/test/test-delayed-accept.c @@ -184,6 +184,6 @@ TEST_IMPL(delayed_accept) { ASSERT(connect_cb_called == 2); ASSERT(close_cb_called == 7); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-eintr-handling.c b/test/test-eintr-handling.c index 3cd55a03593..d37aba4aa52 100644 --- a/test/test-eintr-handling.c +++ b/test/test-eintr-handling.c @@ -89,7 +89,7 @@ TEST_IMPL(eintr_handling) { ASSERT_EQ(0, uv_thread_join(&thread)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-embed.c b/test/test-embed.c index 1d3355fdc67..bbe56e176db 100644 --- a/test/test-embed.c +++ b/test/test-embed.c @@ -74,6 +74,6 @@ TEST_IMPL(embed) { ASSERT_EQ(0, uv_thread_join(&thread)); uv_barrier_destroy(&barrier); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-emfile.c b/test/test-emfile.c index bc1fce5f559..343c9521dc7 100644 --- a/test/test-emfile.c +++ b/test/test-emfile.c @@ -94,7 +94,7 @@ TEST_IMPL(emfile) { first_fd += 1; } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-fork.c b/test/test-fork.c index 0cb04423548..7a6eb9c411b 100644 --- a/test/test-fork.c +++ b/test/test-fork.c @@ -59,17 +59,18 @@ static void socket_cb(uv_poll_t* poll, int status, int events) { static void run_timer_loop_once(void) { - uv_loop_t* loop; + uv_loop_t loop; uv_timer_t timer_handle; - loop = uv_default_loop(); + ASSERT_EQ(0, uv_loop_init(&loop)); timer_cb_called = 0; /* Reset for the child. */ - ASSERT(0 == uv_timer_init(loop, &timer_handle)); + ASSERT(0 == uv_timer_init(&loop, &timer_handle)); ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); ASSERT(1 == timer_cb_called); + ASSERT_EQ(0, uv_loop_close(&loop)); } @@ -111,7 +112,7 @@ TEST_IMPL(fork_timer) { run_timer_loop_once(); } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -148,7 +149,7 @@ TEST_IMPL(fork_socketpair) { ASSERT(1 == socket_cb_called); } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -212,7 +213,7 @@ TEST_IMPL(fork_socketpair_started) { ASSERT(0 == strcmp("hi\n", socket_cb_read_buf)); } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -269,7 +270,7 @@ TEST_IMPL(fork_signal_to_child) { ASSERT(SIGUSR1 == fork_signal_cb_called); } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -342,7 +343,7 @@ TEST_IMPL(fork_signal_to_child_closed) { exit(0); } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -500,7 +501,7 @@ static int _do_fork_fs_events_child(int file_or_dir) { printf("Exiting child \n"); } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -597,7 +598,7 @@ TEST_IMPL(fork_fs_events_file_parent_child) { } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; #endif } @@ -675,7 +676,7 @@ TEST_IMPL(fork_threadpool_queue_work_simple) { } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif /* !__MVS__ */ diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index 6781ee7f71d..d7f04cf4cdd 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -220,5 +220,6 @@ TEST_IMPL(fs_copyfile) { #endif unlink(dst); /* Cleanup */ + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-fs-event.c b/test/test-fs-event.c index db2966e178c..017aed2654f 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -432,7 +432,7 @@ TEST_IMPL(fs_event_watch_dir) { remove("watch_dir/file1"); remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -494,7 +494,7 @@ TEST_IMPL(fs_event_watch_dir_recursive) { remove("watch_dir/subdir"); remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; #else RETURN_SKIP("Recursive directory watching not supported on this platform."); @@ -541,7 +541,7 @@ TEST_IMPL(fs_event_watch_dir_short_path) { remove("watch_dir/file1"); remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); if (!has_shortnames) RETURN_SKIP("Was not able to address files with 8.3 short name."); @@ -587,7 +587,7 @@ TEST_IMPL(fs_event_watch_file) { remove("watch_dir/file1"); remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -640,7 +640,7 @@ TEST_IMPL(fs_event_watch_file_exact_path) { remove("watch_dir/file.jsx"); remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -664,7 +664,7 @@ TEST_IMPL(fs_event_watch_file_twice) { ASSERT(0 == uv_timer_start(&timer, timer_cb_watch_twice, 10, 0)); ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -719,7 +719,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) { /* Cleanup */ remove("watch_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -745,7 +745,7 @@ TEST_IMPL(fs_event_watch_file_root_dir) { uv_close((uv_handle_t*) &fs_event, NULL); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } #endif @@ -784,7 +784,7 @@ TEST_IMPL(fs_event_no_callback_after_close) { remove("watch_dir/file1"); remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -821,7 +821,7 @@ TEST_IMPL(fs_event_no_callback_on_close) { remove("watch_dir/file1"); remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -859,7 +859,7 @@ TEST_IMPL(fs_event_immediate_close) { ASSERT(close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -894,7 +894,7 @@ TEST_IMPL(fs_event_close_with_pending_event) { remove("watch_dir/file"); remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -932,7 +932,7 @@ TEST_IMPL(fs_event_close_with_pending_delete_event) { /* Clean up */ remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -973,7 +973,7 @@ TEST_IMPL(fs_event_close_in_callback) { fs_event_unlink_files(NULL); remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1008,7 +1008,7 @@ TEST_IMPL(fs_event_start_and_close) { ASSERT(close_cb_called == 2); remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1061,7 +1061,7 @@ TEST_IMPL(fs_event_getpath) { } remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1150,7 +1150,7 @@ TEST_IMPL(fs_event_error_reporting) { } while (i-- != 0); remove("watch_dir/"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1159,7 +1159,7 @@ TEST_IMPL(fs_event_error_reporting) { TEST_IMPL(fs_event_error_reporting) { /* No-op, needed only for FSEvents backend */ - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1182,7 +1182,7 @@ TEST_IMPL(fs_event_watch_invalid_path) { r = uv_fs_event_start(&fs_event, fs_event_cb_file, "", 0); ASSERT(r != 0); ASSERT(uv_is_active((uv_handle_t*) &fs_event) == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1228,6 +1228,6 @@ TEST_IMPL(fs_event_stop_in_cb) { remove(path); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-fs-open-flags.c b/test/test-fs-open-flags.c index 372afe13975..ea9be25afc1 100644 --- a/test/test-fs-open-flags.c +++ b/test/test-fs-open-flags.c @@ -424,7 +424,7 @@ TEST_IMPL(fs_open_flags) { /* Cleanup. */ rmdir(empty_dir); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-fs-poll.c b/test/test-fs-poll.c index 76fe6fc3957..af486023d10 100644 --- a/test/test-fs-poll.c +++ b/test/test-fs-poll.c @@ -164,7 +164,7 @@ TEST_IMPL(fs_poll) { ASSERT(timer_cb_called == 2); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -192,7 +192,7 @@ TEST_IMPL(fs_poll_getpath) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -212,9 +212,7 @@ TEST_IMPL(fs_poll_close_request) { uv_run(&loop, UV_RUN_ONCE); ASSERT(close_cb_called == 1); - ASSERT(0 == uv_loop_close(&loop)); - - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(&loop); return 0; } @@ -238,9 +236,7 @@ TEST_IMPL(fs_poll_close_request_multi_start_stop) { uv_run(&loop, UV_RUN_ONCE); ASSERT(close_cb_called == 1); - ASSERT(0 == uv_loop_close(&loop)); - - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(&loop); return 0; } @@ -264,9 +260,7 @@ TEST_IMPL(fs_poll_close_request_multi_stop_start) { uv_run(&loop, UV_RUN_ONCE); ASSERT(close_cb_called == 1); - ASSERT(0 == uv_loop_close(&loop)); - - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(&loop); return 0; } @@ -293,8 +287,6 @@ TEST_IMPL(fs_poll_close_request_stop_when_active) { uv_run(&loop, UV_RUN_ONCE); ASSERT(close_cb_called == 1); - ASSERT(0 == uv_loop_close(&loop)); - - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(&loop); return 0; } diff --git a/test/test-fs-readdir.c b/test/test-fs-readdir.c index 6bb69178415..43c9edf178b 100644 --- a/test/test-fs-readdir.c +++ b/test/test-fs-readdir.c @@ -156,7 +156,7 @@ TEST_IMPL(fs_readdir_empty_dir) { ASSERT(empty_closedir_cb_count == 1); uv_fs_rmdir(uv_default_loop(), &rmdir_req, path, NULL); uv_fs_req_cleanup(&rmdir_req); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -208,7 +208,7 @@ TEST_IMPL(fs_readdir_non_existing_dir) { ASSERT(r == 0); ASSERT(non_existing_opendir_cb_count == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -258,7 +258,7 @@ TEST_IMPL(fs_readdir_file) { r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); ASSERT(file_opendir_cb_count == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -457,6 +457,6 @@ TEST_IMPL(fs_readdir_non_empty_dir) { uv_fs_req_cleanup(&rmdir_req); cleanup_test_files(); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-fs.c b/test/test-fs.c index ea672d367f2..51b4144ec3a 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -723,7 +723,7 @@ TEST_IMPL(fs_file_noent) { /* TODO add EACCES test */ - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -749,7 +749,7 @@ TEST_IMPL(fs_file_nametoolong) { uv_run(loop, UV_RUN_DEFAULT); ASSERT(open_cb_count == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -791,7 +791,7 @@ TEST_IMPL(fs_file_loop) { unlink("test_symlink"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -958,7 +958,7 @@ TEST_IMPL(fs_file_async) { unlink("test_file"); unlink("test_file2"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1048,7 +1048,7 @@ TEST_IMPL(fs_file_sync) { fs_file_sync(0); fs_file_sync(UV_FS_O_FILEMAP); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1084,7 +1084,7 @@ TEST_IMPL(fs_file_write_null_buffer) { fs_file_write_null_buffer(0); fs_file_write_null_buffer(UV_FS_O_FILEMAP); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1179,7 +1179,7 @@ TEST_IMPL(fs_async_dir) { unlink("test_dir/file2"); rmdir("test_dir"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1259,7 +1259,7 @@ static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) { unlink("test_file"); unlink("test_file2"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1307,7 +1307,7 @@ TEST_IMPL(fs_mkdtemp) { uv_fs_req_cleanup(&mkdtemp_req1); uv_fs_req_cleanup(&mkdtemp_req2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1340,6 +1340,8 @@ TEST_IMPL(fs_mkstemp) { /* Make sure that path is empty string */ ASSERT_EQ(0, strlen(mkstemp_req3.path)); + uv_fs_req_cleanup(&mkstemp_req3); + /* We can write to the opened file */ iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &req, mkstemp_req1.result, &iov, 1, -1, NULL); @@ -1373,7 +1375,7 @@ TEST_IMPL(fs_mkstemp) { uv_fs_req_cleanup(&mkstemp_req1); uv_fs_req_cleanup(&mkstemp_req2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1537,7 +1539,7 @@ TEST_IMPL(fs_fstat) { /* Cleanup. */ unlink("test_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1574,7 +1576,7 @@ TEST_IMPL(fs_fstat_stdio) { uv_fs_req_cleanup(&req); } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1650,7 +1652,7 @@ TEST_IMPL(fs_access) { unlink("test_file"); rmdir("test_dir"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1748,7 +1750,7 @@ TEST_IMPL(fs_chmod) { /* Cleanup. */ unlink("test_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1807,7 +1809,7 @@ TEST_IMPL(fs_unlink_readonly) { uv_fs_req_cleanup(&req); unlink("test_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1865,7 +1867,7 @@ TEST_IMPL(fs_unlink_archive_readonly) { uv_fs_req_cleanup(&req); unlink("test_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } #endif @@ -1958,7 +1960,7 @@ TEST_IMPL(fs_chown) { unlink("test_file"); unlink("test_file_link"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2044,7 +2046,7 @@ TEST_IMPL(fs_link) { unlink("test_file_link"); unlink("test_file_link2"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2098,7 +2100,7 @@ TEST_IMPL(fs_readlink) { unlink("test_file"); } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2119,7 +2121,7 @@ TEST_IMPL(fs_realpath) { ASSERT(req.result == UV_ENOENT); uv_fs_req_cleanup(&req); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2287,7 +2289,7 @@ TEST_IMPL(fs_symlink) { unlink("test_file_symlink2"); unlink("test_file_symlink2_symlink"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2432,7 +2434,7 @@ int test_symlink_dir_impl(int type) { rmdir("test_dir"); rmdir("test_dir_symlink"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2541,7 +2543,7 @@ TEST_IMPL(fs_non_symlink_reparse_point) { unlink("test_dir/test_file"); rmdir("test_dir"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2561,7 +2563,7 @@ TEST_IMPL(fs_lstat_windows_store_apps) { len = sizeof(localappdata); r = uv_os_getenv("LOCALAPPDATA", localappdata, &len); if (r == UV_ENOENT) { - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return TEST_SKIP; } ASSERT_EQ(r, 0); @@ -2572,11 +2574,11 @@ TEST_IMPL(fs_lstat_windows_store_apps) { ASSERT_GT(r, 0); if (uv_fs_opendir(loop, &req, windowsapps_path, NULL) != 0) { /* If we cannot read the directory, skip the test. */ - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return TEST_SKIP; } if (uv_fs_scandir(loop, &req, windowsapps_path, 0, NULL) <= 0) { - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return TEST_SKIP; } while (uv_fs_scandir_next(&req, &dirent) != UV_EOF) { @@ -2592,7 +2594,7 @@ TEST_IMPL(fs_lstat_windows_store_apps) { } ASSERT_EQ(uv_fs_lstat(loop, &stat_req, file_path, NULL), 0); } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } #endif @@ -2639,7 +2641,7 @@ TEST_IMPL(fs_utime) { /* Cleanup. */ unlink(path); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2678,7 +2680,7 @@ TEST_IMPL(fs_utime_round) { check_utime(path, atime, mtime, /* test_lutime */ 0); unlink(path); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2709,7 +2711,7 @@ TEST_IMPL(fs_stat_root) { r = uv_fs_stat(NULL, &stat_req, "\\\\?\\C:\\", NULL); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif @@ -2772,7 +2774,7 @@ TEST_IMPL(fs_futime) { /* Cleanup. */ unlink(path); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2846,7 +2848,7 @@ TEST_IMPL(fs_lutime) { unlink(path); unlink(symlink_path); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2862,7 +2864,7 @@ TEST_IMPL(fs_stat_missing_path) { ASSERT(req.result == UV_ENOENT); uv_fs_req_cleanup(&req); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2899,7 +2901,7 @@ TEST_IMPL(fs_scandir_empty_dir) { uv_fs_rmdir(NULL, &req, path, NULL); uv_fs_req_cleanup(&req); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2933,7 +2935,7 @@ TEST_IMPL(fs_scandir_non_existent_dir) { uv_run(loop, UV_RUN_DEFAULT); ASSERT(scandir_cb_count == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2955,7 +2957,7 @@ TEST_IMPL(fs_scandir_file) { uv_run(loop, UV_RUN_DEFAULT); ASSERT(scandir_cb_count == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -2973,7 +2975,7 @@ TEST_IMPL(fs_scandir_early_exit) { ASSERT_NE(UV_EOF, uv_fs_scandir_next(&req, &d)); uv_fs_req_cleanup(&req); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -3003,7 +3005,7 @@ TEST_IMPL(fs_open_dir) { uv_run(loop, UV_RUN_DEFAULT); ASSERT(open_cb_count == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -3078,7 +3080,7 @@ TEST_IMPL(fs_file_open_append) { fs_file_open_append(0); fs_file_open_append(UV_FS_O_FILEMAP); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -3147,7 +3149,7 @@ TEST_IMPL(fs_rename_to_existing_file) { unlink("test_file"); unlink("test_file2"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -3205,7 +3207,7 @@ TEST_IMPL(fs_read_bufs) { fs_read_bufs(0); fs_read_bufs(UV_FS_O_FILEMAP); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -3271,7 +3273,7 @@ TEST_IMPL(fs_read_file_eof) { fs_read_file_eof(0); fs_read_file_eof(UV_FS_O_FILEMAP); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -3365,7 +3367,7 @@ TEST_IMPL(fs_write_multiple_bufs) { fs_write_multiple_bufs(0); fs_write_multiple_bufs(UV_FS_O_FILEMAP); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -3472,7 +3474,7 @@ TEST_IMPL(fs_write_alotof_bufs) { fs_write_alotof_bufs(0); fs_write_alotof_bufs(UV_FS_O_FILEMAP); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -3588,7 +3590,7 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) { fs_write_alotof_bufs_with_offset(0); fs_write_alotof_bufs_with_offset(UV_FS_O_FILEMAP); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -3643,7 +3645,7 @@ TEST_IMPL(fs_read_dir) { /* Cleanup */ rmdir("test_dir"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -3802,7 +3804,7 @@ static void test_fs_partial(int doread) { free(buffer); free(ctx.data); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); } TEST_IMPL(fs_partial_read) { @@ -3875,6 +3877,7 @@ TEST_IMPL(fs_read_write_null_arguments) { uv_run(loop, UV_RUN_DEFAULT); uv_fs_req_cleanup(&write_req); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -3913,7 +3916,7 @@ TEST_IMPL(get_osfhandle_valid_handle) { /* Cleanup. */ unlink("test_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -3959,7 +3962,7 @@ TEST_IMPL(open_osfhandle_valid_handle) { /* Cleanup. */ unlink("test_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -3999,7 +4002,7 @@ TEST_IMPL(fs_file_pos_after_op_with_offset) { /* Cleanup */ unlink("test_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -4098,7 +4101,7 @@ TEST_IMPL(fs_file_pos_write) { fs_file_pos_write(0); fs_file_pos_write(UV_FS_O_FILEMAP); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -4138,7 +4141,7 @@ TEST_IMPL(fs_file_pos_append) { fs_file_pos_append(0); fs_file_pos_append(UV_FS_O_FILEMAP); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif @@ -4298,7 +4301,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) { /* Cleanup */ unlink("test_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif @@ -4345,7 +4348,7 @@ TEST_IMPL(fs_file_flag_no_buffering) { /* Cleanup */ unlink("test_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif @@ -4431,7 +4434,7 @@ TEST_IMPL(fs_open_readonly_acl) { unlink("test_file_icacls"); uv_os_free_passwd(&pwd); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } #endif @@ -4516,7 +4519,7 @@ TEST_IMPL(fs_statfs) { uv_run(loop, UV_RUN_DEFAULT); ASSERT(statfs_cb_count == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-getaddrinfo.c b/test/test-getaddrinfo.c index d0b6a505016..1032537ad56 100644 --- a/test/test-getaddrinfo.c +++ b/test/test-getaddrinfo.c @@ -106,7 +106,7 @@ TEST_IMPL(getaddrinfo_fail) { ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT(fail_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -127,7 +127,7 @@ TEST_IMPL(getaddrinfo_fail_sync) { NULL)); uv_freeaddrinfo(req.addrinfo); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -153,7 +153,7 @@ TEST_IMPL(getaddrinfo_basic) { ASSERT(getaddrinfo_cbs == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -173,7 +173,7 @@ TEST_IMPL(getaddrinfo_basic_sync) { NULL)); uv_freeaddrinfo(req.addrinfo); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -210,6 +210,6 @@ TEST_IMPL(getaddrinfo_concurrent) { ASSERT(callback_counts[i] == 1); } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-getnameinfo.c b/test/test-getnameinfo.c index 2bfedd3a39b..cea57b012f1 100644 --- a/test/test-getnameinfo.c +++ b/test/test-getnameinfo.c @@ -65,7 +65,7 @@ TEST_IMPL(getnameinfo_basic_ip4) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -86,7 +86,7 @@ TEST_IMPL(getnameinfo_basic_ip4_sync) { ASSERT(req.host[0] != '\0'); ASSERT(req.service[0] != '\0'); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -111,6 +111,6 @@ TEST_IMPL(getnameinfo_basic_ip6) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-getsockname.c b/test/test-getsockname.c index 6e0f8c18982..1d4d9f12bda 100644 --- a/test/test-getsockname.c +++ b/test/test-getsockname.c @@ -337,7 +337,7 @@ TEST_IMPL(getsockname_tcp) { ASSERT(getsocknamecount_tcp == 3); ASSERT(getpeernamecount == 3); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -357,6 +357,6 @@ TEST_IMPL(getsockname_udp) { ASSERT(udp.send_queue_size == 0); ASSERT(udpServer.send_queue_size == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-handle-fileno.c b/test/test-handle-fileno.c index 8a093e2ea46..6c4c2b6601d 100644 --- a/test/test-handle-fileno.c +++ b/test/test-handle-fileno.c @@ -120,6 +120,6 @@ TEST_IMPL(handle_fileno) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-idle.c b/test/test-idle.c index 427cf545beb..e3f4c2bcb65 100644 --- a/test/test-idle.c +++ b/test/test-idle.c @@ -94,7 +94,7 @@ TEST_IMPL(idle_starvation) { ASSERT(timer_cb_called == 1); ASSERT(close_cb_called == 3); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -120,6 +120,6 @@ TEST_IMPL(idle_check) { ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_ONCE)); ASSERT_EQ(2, close_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-ip-name.c b/test/test-ip-name.c index 1cb1b605834..006095f5f97 100644 --- a/test/test-ip-name.c +++ b/test/test-ip-name.c @@ -51,7 +51,7 @@ TEST_IMPL(ip_name) { ASSERT_EQ(0, uv_ip6_addr("fe80::2acf:daff:fedd:342a", TEST_PORT, addr6)); ASSERT_EQ(0, uv_ip6_name(addr6, dst, INET6_ADDRSTRLEN)); ASSERT_EQ(0, strcmp("fe80::2acf:daff:fedd:342a", dst)); - + ASSERT_EQ(0, uv_ip_name(addr, dst, INET6_ADDRSTRLEN)); ASSERT_EQ(0, strcmp("fe80::2acf:daff:fedd:342a", dst)); @@ -60,6 +60,6 @@ TEST_IMPL(ip_name) { /* size is not a concern here */ ASSERT_EQ(UV_EAFNOSUPPORT, uv_ip_name(addr, dst, INET6_ADDRSTRLEN)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-ip4-addr.c b/test/test-ip4-addr.c index dfefb0f914a..722ffb390a9 100644 --- a/test/test-ip4-addr.c +++ b/test/test-ip4-addr.c @@ -50,6 +50,6 @@ TEST_IMPL(ip4_addr) { ASSERT(UV_EAFNOSUPPORT == uv_inet_pton(42, "127.0.0.1", &addr.sin_addr.s_addr)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-ip6-addr.c b/test/test-ip6-addr.c index 4c1e1019fe3..8f0c18601ba 100644 --- a/test/test-ip6-addr.c +++ b/test/test-ip6-addr.c @@ -113,7 +113,7 @@ TEST_IMPL(ip6_addr_link_local) { scoped_addr_len = sizeof(scoped_addr); ASSERT(0 != uv_if_indextoname((unsigned int)-1, scoped_addr, &scoped_addr_len)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -154,7 +154,7 @@ TEST_IMPL(ip6_pton) { GOOD_ADDR_LIST(TEST_GOOD) BAD_ADDR_LIST(TEST_BAD) - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-ipc-heavy-traffic-deadlock-bug.c b/test/test-ipc-heavy-traffic-deadlock-bug.c index 89b977d2c34..f239d1fc01f 100644 --- a/test/test-ipc-heavy-traffic-deadlock-bug.c +++ b/test/test-ipc-heavy-traffic-deadlock-bug.c @@ -137,7 +137,7 @@ TEST_IMPL(ipc_heavy_traffic_deadlock_bug) { spawn_helper(&pipe, &process, "ipc_helper_heavy_traffic_deadlock_bug"); do_writes_and_reads((uv_stream_t*) &pipe); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(pipe.loop); return 0; } @@ -154,6 +154,6 @@ int ipc_helper_heavy_traffic_deadlock_bug(void) { do_writes_and_reads((uv_stream_t*) &pipe); uv_sleep(100); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-ipc-send-recv.c b/test/test-ipc-send-recv.c index 1eba6dfa71f..48eea7286b8 100644 --- a/test/test-ipc-send-recv.c +++ b/test/test-ipc-send-recv.c @@ -223,7 +223,7 @@ static int run_ipc_send_recv_pipe(int inprocess) { r = run_test(inprocess); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -264,7 +264,7 @@ static int run_ipc_send_recv_tcp(int inprocess) { r = run_test(inprocess); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -416,7 +416,7 @@ int ipc_send_recv_helper(void) { r = run_ipc_send_recv_helper(uv_default_loop(), 0); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-ipc.c b/test/test-ipc.c index cf131ffd193..7ec6ec9ce3a 100644 --- a/test/test-ipc.c +++ b/test/test-ipc.c @@ -424,7 +424,7 @@ static int run_ipc_test(const char* helper, uv_read_cb read_cb) { r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT_EQ(r, 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -489,7 +489,7 @@ TEST_IMPL(listen_with_simultaneous_accepts) { ASSERT_EQ(r, 0); ASSERT_EQ(server.reqs_pending, 32); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -514,7 +514,7 @@ TEST_IMPL(listen_no_simultaneous_accepts) { ASSERT_EQ(r, 0); ASSERT_EQ(server.reqs_pending, 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -721,7 +721,7 @@ int ipc_helper(int listen_after_write) { ASSERT_EQ(connection_accepted, 1); ASSERT_EQ(close_cb_called, 3); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -774,7 +774,7 @@ int ipc_helper_tcp_connection(void) { ASSERT_EQ(tcp_conn_write_cb_called, 1); ASSERT_EQ(close_cb_called, 4); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -820,7 +820,7 @@ int ipc_helper_bind_twice(void) { r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT_EQ(r, 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -852,6 +852,6 @@ int ipc_helper_send_zero(void) { ASSERT_EQ(send_zero_write, 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-loop-alive.c b/test/test-loop-alive.c index cf4d301930c..76a2b04cc9d 100644 --- a/test/test-loop-alive.c +++ b/test/test-loop-alive.c @@ -63,5 +63,6 @@ TEST_IMPL(loop_alive) { ASSERT(r == 0); ASSERT(!uv_loop_alive(uv_default_loop())); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-loop-close.c b/test/test-loop-close.c index f0f3e627f97..f5814796e8f 100644 --- a/test/test-loop-close.c +++ b/test/test-loop-close.c @@ -62,6 +62,8 @@ static void loop_instant_close_work_cb(uv_work_t* req) { static void loop_instant_close_after_work_cb(uv_work_t* req, int status) { } +/* It's impossible to properly cleanup after this test because loop can't be + * closed while work has been queued. */ TEST_IMPL(loop_instant_close) { static uv_loop_t loop; static uv_work_t req; @@ -70,6 +72,6 @@ TEST_IMPL(loop_instant_close) { &req, loop_instant_close_work_cb, loop_instant_close_after_work_cb)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-loop-handles.c b/test/test-loop-handles.c index 05cb8466ca6..5d3df0245aa 100644 --- a/test/test-loop-handles.c +++ b/test/test-loop-handles.c @@ -332,6 +332,6 @@ TEST_IMPL(loop_handles) { ASSERT(idle_2_close_cb_called == idle_2_cb_started); ASSERT(idle_2_is_active == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-loop-stop.c b/test/test-loop-stop.c index 14b8c11186c..02aa12f1a83 100644 --- a/test/test-loop-stop.c +++ b/test/test-loop-stop.c @@ -67,5 +67,6 @@ TEST_IMPL(loop_stop) { ASSERT(timer_called == 10); ASSERT(prepare_called == 10); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-loop-time.c b/test/test-loop-time.c index 087720b9e9e..5d083064ae3 100644 --- a/test/test-loop-time.c +++ b/test/test-loop-time.c @@ -30,7 +30,7 @@ TEST_IMPL(loop_update_time) { while (uv_now(uv_default_loop()) - start < 1000) ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_NOWAIT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -64,6 +64,6 @@ TEST_IMPL(loop_backend_timeout) { ASSERT_EQ(r, 0); ASSERT_EQ(uv_backend_timeout(loop), 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-metrics.c b/test/test-metrics.c index 1f887857030..c6fa432a55d 100644 --- a/test/test-metrics.c +++ b/test/test-metrics.c @@ -71,7 +71,7 @@ TEST_IMPL(metrics_idle_time) { ASSERT_LE(idle_time, (timeout + 500) * UV_NS_TO_MS); ASSERT_GE(idle_time, (timeout - 500) * UV_NS_TO_MS); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -147,7 +147,7 @@ TEST_IMPL(metrics_idle_time_zero) { ASSERT_EQ(0, uv_metrics_info(uv_default_loop(), &metrics)); ASSERT_UINT64_EQ(cntr, metrics.loop_count); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -236,6 +236,6 @@ TEST_IMPL(metrics_info_check) { uv_fs_unlink(NULL, &unlink_req, "test_file", NULL); uv_fs_req_cleanup(&unlink_req); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-multiple-listen.c b/test/test-multiple-listen.c index 0b2851411a8..bbaa9bc1ef1 100644 --- a/test/test-multiple-listen.c +++ b/test/test-multiple-listen.c @@ -104,6 +104,6 @@ TEST_IMPL(multiple_listen) { ASSERT(connect_cb_called == 1); ASSERT(close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-not-readable-nor-writable-on-read-error.c b/test/test-not-readable-nor-writable-on-read-error.c index ae951e39893..823a4e91e29 100644 --- a/test/test-not-readable-nor-writable-on-read-error.c +++ b/test/test-not-readable-nor-writable-on-read-error.c @@ -99,6 +99,6 @@ TEST_IMPL(not_readable_nor_writable_on_read_error) { ASSERT(write_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(&loop); return 0; } diff --git a/test/test-not-writable-after-shutdown.c b/test/test-not-writable-after-shutdown.c index 9cd93703cea..84e09177bd3 100644 --- a/test/test-not-writable-after-shutdown.c +++ b/test/test-not-writable-after-shutdown.c @@ -61,9 +61,9 @@ TEST_IMPL(not_writable_after_shutdown) { connect_cb); ASSERT(r == 0); - r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + r = uv_run(loop, UV_RUN_DEFAULT); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-osx-select.c b/test/test-osx-select.c index a0afda9181e..00ae540b405 100644 --- a/test/test-osx-select.c +++ b/test/test-osx-select.c @@ -79,7 +79,7 @@ TEST_IMPL(osx_select) { ASSERT(read_count == 3); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -133,7 +133,7 @@ TEST_IMPL(osx_select_many_fds) { ASSERT(read_count == 3); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-ping-pong.c b/test/test-ping-pong.c index c598587d112..f54f2ad22e5 100644 --- a/test/test-ping-pong.c +++ b/test/test-ping-pong.c @@ -378,7 +378,7 @@ static int run_ping_pong_test(void) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT_EQ(completed_pingers, 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-pipe-bind-error.c b/test/test-pipe-bind-error.c index aacde456543..88ece6ba5d8 100644 --- a/test/test-pipe-bind-error.c +++ b/test/test-pipe-bind-error.c @@ -67,7 +67,7 @@ TEST_IMPL(pipe_bind_error_addrinuse) { ASSERT(close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -88,7 +88,7 @@ TEST_IMPL(pipe_bind_error_addrnotavail) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -110,7 +110,7 @@ TEST_IMPL(pipe_bind_error_inval) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -134,7 +134,7 @@ TEST_IMPL(pipe_listen_without_bind) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -150,6 +150,6 @@ TEST_IMPL(pipe_bind_or_listen_error_after_close) { ASSERT_EQ(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-pipe-close-stdout-read-stdin.c b/test/test-pipe-close-stdout-read-stdin.c index 126be2cc46f..e0f864e9cdf 100644 --- a/test/test-pipe-close-stdout-read-stdin.c +++ b/test/test-pipe-close-stdout-read-stdin.c @@ -101,7 +101,7 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { ASSERT(WIFEXITED(status) && WEXITSTATUS(status) == 0); } - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-pipe-connect-error.c b/test/test-pipe-connect-error.c index ba28a5922c3..140e7d32daf 100644 --- a/test/test-pipe-connect-error.c +++ b/test/test-pipe-connect-error.c @@ -72,7 +72,7 @@ TEST_IMPL(pipe_connect_bad_name) { ASSERT_EQ(close_cb_called, 1); ASSERT_EQ(connect_cb_called, 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -92,6 +92,6 @@ TEST_IMPL(pipe_connect_to_file) { ASSERT_EQ(close_cb_called, 1); ASSERT_EQ(connect_cb_called, 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-pipe-connect-multiple.c b/test/test-pipe-connect-multiple.c index 977ce488f14..b8f417e81ca 100644 --- a/test/test-pipe-connect-multiple.c +++ b/test/test-pipe-connect-multiple.c @@ -102,7 +102,7 @@ TEST_IMPL(pipe_connect_multiple) { ASSERT(connection_cb_called == NUM_CLIENTS); ASSERT(connect_cb_called == NUM_CLIENTS); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -173,6 +173,6 @@ TEST_IMPL(pipe_connect_close_multiple) { ASSERT_EQ(connection_cb_called, NUM_CLIENTS); ASSERT_EQ(connect_cb_called, NUM_CLIENTS); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-pipe-connect-prepare.c b/test/test-pipe-connect-prepare.c index 08b57cbf510..f7a79404048 100644 --- a/test/test-pipe-connect-prepare.c +++ b/test/test-pipe-connect-prepare.c @@ -78,6 +78,6 @@ TEST_IMPL(pipe_connect_on_prepare) { ASSERT(close_cb_called == 2); ASSERT(connect_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index 79db8eba717..4b0aa53b927 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -156,7 +156,7 @@ TEST_IMPL(pipe_getsockname) { ASSERT(pipe_client_connect_cb_called == 1); ASSERT(pipe_close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -200,10 +200,10 @@ TEST_IMPL(pipe_getsockname_abstract) { close(sock); ASSERT(pipe_close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; #else - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; #endif } @@ -265,6 +265,6 @@ TEST_IMPL(pipe_getsockname_blocking) { CloseHandle(writeh); #endif - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-pipe-pending-instances.c b/test/test-pipe-pending-instances.c index b6ff911a0f2..9b1bfbc9aac 100644 --- a/test/test-pipe-pending-instances.c +++ b/test/test-pipe-pending-instances.c @@ -54,6 +54,6 @@ TEST_IMPL(pipe_pending_instances) { r = uv_run(loop, UV_RUN_DEFAULT); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-pipe-sendmsg.c b/test/test-pipe-sendmsg.c index 3bf427f8aa0..7758b65b05c 100644 --- a/test/test-pipe-sendmsg.c +++ b/test/test-pipe-sendmsg.c @@ -158,14 +158,14 @@ TEST_IMPL(pipe_sendmsg) { ASSERT(ARRAY_SIZE(incoming) + 1 == close_called); close(fds[0]); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #else /* !_WIN32 */ TEST_IMPL(pipe_sendmsg) { - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-pipe-server-close.c b/test/test-pipe-server-close.c index 25305b397b2..dc20661916d 100644 --- a/test/test-pipe-server-close.c +++ b/test/test-pipe-server-close.c @@ -89,6 +89,6 @@ TEST_IMPL(pipe_server_close) { ASSERT(pipe_client_connect_cb_called == 1); ASSERT(pipe_close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-pipe-set-fchmod.c b/test/test-pipe-set-fchmod.c index 985f4ba2eba..402970e3da9 100644 --- a/test/test-pipe-set-fchmod.c +++ b/test/test-pipe-set-fchmod.c @@ -44,7 +44,7 @@ TEST_IMPL(pipe_set_chmod) { * successful. */ r = uv_pipe_chmod(&pipe_handle, UV_READABLE); if (r == UV_EPERM) { - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); RETURN_SKIP("Insufficient privileges to alter pipe fmode"); } ASSERT(r == 0); @@ -87,6 +87,6 @@ TEST_IMPL(pipe_set_chmod) { r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); ASSERT(r == UV_EBADF); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-pipe-set-non-blocking.c b/test/test-pipe-set-non-blocking.c index c780460950e..1b90bca3d2a 100644 --- a/test/test-pipe-set-non-blocking.c +++ b/test/test-pipe-set-non-blocking.c @@ -122,6 +122,6 @@ TEST_IMPL(pipe_set_non_blocking) { fd[0] = -1; uv_barrier_destroy(&ctx.barrier); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-pipe-try-write.c b/test/test-pipe-try-write.c index cacc12448f2..2dccd4b5c47 100644 --- a/test/test-pipe-try-write.c +++ b/test/test-pipe-try-write.c @@ -136,7 +136,7 @@ static int pipe_try_write(void (*spammer)(uv_pipe_t*)) { uv_pipe_connect(&connect_req, &client.handle, TEST_PIPENAME, connect_cb); ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-poll-close-doesnt-corrupt-stack.c b/test/test-poll-close-doesnt-corrupt-stack.c index 1d7e84f6039..a19f42769b5 100644 --- a/test/test-poll-close-doesnt-corrupt-stack.c +++ b/test/test-poll-close-doesnt-corrupt-stack.c @@ -108,7 +108,7 @@ TEST_IMPL(poll_close_doesnt_corrupt_stack) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; #endif } diff --git a/test/test-poll-close.c b/test/test-poll-close.c index 2eccddf5b0b..b4ad4c78346 100644 --- a/test/test-poll-close.c +++ b/test/test-poll-close.c @@ -68,6 +68,6 @@ TEST_IMPL(poll_close) { ASSERT(close_cb_called == NUM_SOCKETS); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-poll-closesocket.c b/test/test-poll-closesocket.c index 1a1c364112a..a81d0b09ff8 100644 --- a/test/test-poll-closesocket.c +++ b/test/test-poll-closesocket.c @@ -86,7 +86,7 @@ TEST_IMPL(poll_closesocket) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; #endif } diff --git a/test/test-poll-multiple-handles.c b/test/test-poll-multiple-handles.c index fc2205ddec7..1aad1ef2106 100644 --- a/test/test-poll-multiple-handles.c +++ b/test/test-poll-multiple-handles.c @@ -94,6 +94,6 @@ TEST_IMPL(poll_multiple_handles) { ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT(close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-poll-oob.c b/test/test-poll-oob.c index 77ffe31e962..b1ff41f5b8a 100644 --- a/test/test-poll-oob.c +++ b/test/test-poll-oob.c @@ -199,7 +199,7 @@ TEST_IMPL(poll_oob) { */ ASSERT(srv_rd_check == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-poll.c b/test/test-poll.c index 0ee0fd8cf08..a0f28324e2f 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -589,7 +589,7 @@ static void start_poll_test(void) { #if !defined(__sun) && !defined(_AIX) && !defined(__MVS__) ASSERT(disconnects == NUM_CLIENTS * 2); #endif - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); } @@ -647,7 +647,7 @@ TEST_IMPL(poll_bad_fdtype) { ASSERT(0 == close(fd)); #endif - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -668,7 +668,7 @@ TEST_IMPL(poll_nested_epoll) { ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT(0 == close(fd)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif /* __linux__ */ @@ -690,7 +690,7 @@ TEST_IMPL(poll_nested_kqueue) { ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT(0 == close(fd)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif /* UV_HAVE_KQUEUE */ diff --git a/test/test-process-title.c b/test/test-process-title.c index 35a14809fb3..c5cff9723da 100644 --- a/test/test-process-title.c +++ b/test/test-process-title.c @@ -120,7 +120,7 @@ TEST_IMPL(process_title_big_argv) { ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-queue-foreach-delete.c b/test/test-queue-foreach-delete.c index 049ea776e34..75d63f5cf17 100644 --- a/test/test-queue-foreach-delete.c +++ b/test/test-queue-foreach-delete.c @@ -198,7 +198,7 @@ TEST_IMPL(queue_foreach_delete) { ASSERT(helper_timer_cb_calls == 1); #endif - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-random.c b/test/test-random.c index 2e3ce4424d2..3ff3fa8b364 100644 --- a/test/test-random.c +++ b/test/test-random.c @@ -70,7 +70,7 @@ TEST_IMPL(random_async) { ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(2 == random_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -89,6 +89,6 @@ TEST_IMPL(random_sync) { memset(zero, 0, sizeof(zero)); ASSERT(0 != memcmp(buf, zero, sizeof(zero))); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-readable-on-eof.c b/test/test-readable-on-eof.c index 68e84542477..1162f8db1d0 100644 --- a/test/test-readable-on-eof.c +++ b/test/test-readable-on-eof.c @@ -106,6 +106,6 @@ TEST_IMPL(readable_on_eof) { ASSERT_EQ(write_cb_called, 1); ASSERT_EQ(close_cb_called, 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(&loop); return 0; } diff --git a/test/test-ref.c b/test/test-ref.c index d24ea4a01e8..7a9a0b9315b 100644 --- a/test/test-ref.c +++ b/test/test-ref.c @@ -101,7 +101,7 @@ static void connect_and_shutdown(uv_connect_t* req, int status) { TEST_IMPL(ref) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -113,7 +113,7 @@ TEST_IMPL(idle_ref) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -124,7 +124,7 @@ TEST_IMPL(async_ref) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -136,7 +136,7 @@ TEST_IMPL(prepare_ref) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -148,7 +148,7 @@ TEST_IMPL(check_ref) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -165,7 +165,7 @@ TEST_IMPL(unref_in_prepare_cb) { uv_prepare_start(&h, prepare_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -176,7 +176,7 @@ TEST_IMPL(timer_ref) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -188,7 +188,7 @@ TEST_IMPL(timer_ref2) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -203,7 +203,7 @@ TEST_IMPL(fs_event_ref) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -215,7 +215,7 @@ TEST_IMPL(fs_poll_ref) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -226,7 +226,7 @@ TEST_IMPL(tcp_ref) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -238,7 +238,7 @@ TEST_IMPL(tcp_ref2) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -251,7 +251,7 @@ TEST_IMPL(tcp_ref2b) { uv_close((uv_handle_t*)&h, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -270,7 +270,7 @@ TEST_IMPL(tcp_ref3) { ASSERT(connect_cb_called == 1); ASSERT(shutdown_cb_called == 1); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -290,7 +290,7 @@ TEST_IMPL(tcp_ref4) { ASSERT(write_cb_called == 1); ASSERT(shutdown_cb_called == 1); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -301,7 +301,7 @@ TEST_IMPL(udp_ref) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -316,7 +316,7 @@ TEST_IMPL(udp_ref2) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -340,7 +340,7 @@ TEST_IMPL(udp_ref3) { ASSERT(req_cb_called == 1); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -351,7 +351,7 @@ TEST_IMPL(pipe_ref) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -363,7 +363,7 @@ TEST_IMPL(pipe_ref2) { uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -377,7 +377,7 @@ TEST_IMPL(pipe_ref3) { ASSERT(connect_cb_called == 1); ASSERT(shutdown_cb_called == 1); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -392,7 +392,7 @@ TEST_IMPL(pipe_ref4) { ASSERT(write_cb_called == 1); ASSERT(shutdown_cb_called == 1); do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -428,7 +428,7 @@ TEST_IMPL(process_ref) { do_close(&h); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -440,6 +440,6 @@ TEST_IMPL(has_ref) { ASSERT(uv_has_ref((uv_handle_t*)&h) == 1); uv_unref((uv_handle_t*)&h); ASSERT(uv_has_ref((uv_handle_t*)&h) == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-run-nowait.c b/test/test-run-nowait.c index 43524f636d8..704105376fa 100644 --- a/test/test-run-nowait.c +++ b/test/test-run-nowait.c @@ -41,5 +41,6 @@ TEST_IMPL(run_nowait) { ASSERT(r != 0); ASSERT(timer_called == 0); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-run-once.c b/test/test-run-once.c index 10cbf95e4ad..ee332fa1a05 100644 --- a/test/test-run-once.c +++ b/test/test-run-once.c @@ -43,6 +43,6 @@ TEST_IMPL(run_once) { while (uv_run(uv_default_loop(), UV_RUN_ONCE)); ASSERT(idle_counter == NUM_TICKS); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-shutdown-close.c b/test/test-shutdown-close.c index 78c369be2d9..cb478b5fdd2 100644 --- a/test/test-shutdown-close.c +++ b/test/test-shutdown-close.c @@ -84,7 +84,7 @@ TEST_IMPL(shutdown_close_tcp) { ASSERT(shutdown_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -103,6 +103,6 @@ TEST_IMPL(shutdown_close_pipe) { ASSERT(shutdown_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-shutdown-eof.c b/test/test-shutdown-eof.c index 0abab9175e9..9c0b85652ae 100644 --- a/test/test-shutdown-eof.c +++ b/test/test-shutdown-eof.c @@ -182,7 +182,7 @@ TEST_IMPL(shutdown_eof) { ASSERT(called_timer_close_cb == 1); ASSERT(called_timer_cb == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-shutdown-simultaneous.c b/test/test-shutdown-simultaneous.c index 7de3bd42252..14cc443730d 100644 --- a/test/test-shutdown-simultaneous.c +++ b/test/test-shutdown-simultaneous.c @@ -130,6 +130,6 @@ TEST_IMPL(shutdown_simultaneous) { ASSERT_EQ(got_eof, 1); ASSERT_EQ(got_q, 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-shutdown-twice.c b/test/test-shutdown-twice.c index d7aae89914d..d936a70cb7d 100644 --- a/test/test-shutdown-twice.c +++ b/test/test-shutdown-twice.c @@ -75,11 +75,11 @@ TEST_IMPL(shutdown_twice) { connect_cb); ASSERT(r == 0); - r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + r = uv_run(loop, UV_RUN_DEFAULT); ASSERT(r == 0); ASSERT(shutdown_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-signal-multiple-loops.c b/test/test-signal-multiple-loops.c index 0879b7bca12..483f59f2006 100644 --- a/test/test-signal-multiple-loops.c +++ b/test/test-signal-multiple-loops.c @@ -310,7 +310,7 @@ TEST_IMPL(signal_multiple_loops) { */ ASSERT(loop_creation_counter >= NUM_LOOP_CREATING_THREADS); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-signal-pending-on-close.c b/test/test-signal-pending-on-close.c index 428a97ef5ae..e0b9bc300b1 100644 --- a/test/test-signal-pending-on-close.c +++ b/test/test-signal-pending-on-close.c @@ -88,11 +88,9 @@ TEST_IMPL(signal_pending_on_close) { ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); - ASSERT(0 == uv_loop_close(&loop)); - ASSERT(2 == close_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(&loop); return 0; } @@ -109,10 +107,9 @@ TEST_IMPL(signal_close_loop_alive) { ASSERT(1 == uv_loop_alive(&loop)); ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); - ASSERT(0 == uv_loop_close(&loop)); ASSERT(1 == close_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(&loop); return 0; } diff --git a/test/test-signal.c b/test/test-signal.c index c2ce5ec0e0a..f8222d14b4e 100644 --- a/test/test-signal.c +++ b/test/test-signal.c @@ -38,7 +38,7 @@ TEST_IMPL(kill_invalid_signum) { #endif ASSERT(uv_kill(pid, 4096) == UV_EINVAL); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -69,7 +69,7 @@ TEST_IMPL(win32_signum_number) { ASSERT(uv_signal_start(&signal, signum_test_cb, -1) == UV_EINVAL); ASSERT(uv_signal_start(&signal, signum_test_cb, NSIG) == UV_EINVAL); ASSERT(uv_signal_start(&signal, signum_test_cb, 1024) == UV_EINVAL); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } #else @@ -180,7 +180,7 @@ TEST_IMPL(we_get_signal) { ASSERT(tc.ncalls == NSIGNALS); ASSERT(sc.ncalls == NSIGNALS); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -206,7 +206,7 @@ TEST_IMPL(we_get_signals) { for (i = 0; i < ARRAY_SIZE(tc); i++) ASSERT(tc[i].ncalls == NSIGNALS); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -235,7 +235,7 @@ TEST_IMPL(we_get_signal_one_shot) { ASSERT(tc.ncalls == NSIGNALS); ASSERT(sc.ncalls == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -318,7 +318,7 @@ TEST_IMPL(we_get_signals_mixed) { ASSERT(sc[2].ncalls == 0); ASSERT(sc[3].ncalls == NSIGNALS); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-socket-buffer-size.c b/test/test-socket-buffer-size.c index 72f8c2524c0..5f072cb02be 100644 --- a/test/test-socket-buffer-size.c +++ b/test/test-socket-buffer-size.c @@ -72,6 +72,6 @@ TEST_IMPL(socket_buffer_size) { ASSERT(close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-spawn.c b/test/test-spawn.c index 7a07482b1c9..182cf5ec3eb 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -193,7 +193,7 @@ TEST_IMPL(spawn_fails) { uv_close((uv_handle_t*) &process, NULL); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -223,7 +223,7 @@ TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) { uv_close((uv_handle_t*) &process, NULL); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif @@ -253,7 +253,7 @@ TEST_IMPL(spawn_empty_env) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -272,7 +272,7 @@ TEST_IMPL(spawn_exit_code) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -305,7 +305,7 @@ TEST_IMPL(spawn_stdout) { printf("output is: %s", output); ASSERT(strcmp("hello world\n", output) == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -359,7 +359,7 @@ TEST_IMPL(spawn_stdout_to_file) { /* Cleanup. */ unlink("stdout_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -415,7 +415,7 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) { /* Cleanup. */ unlink("stdout_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -477,7 +477,7 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file2) { /* Cleanup. */ unlink("stdout_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; #else RETURN_SKIP("Unix only test"); @@ -569,7 +569,7 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) { unlink("stdout_file"); unlink("stderr_file"); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; #else RETURN_SKIP("Unix only test"); @@ -615,7 +615,7 @@ TEST_IMPL(spawn_stdin) { ASSERT(close_cb_called == 3); /* Once for process twice for the pipe. */ ASSERT(strcmp(buffer, output) == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -650,7 +650,7 @@ TEST_IMPL(spawn_stdio_greater_than_3) { printf("output from stdio[3] is: %s", output); ASSERT(strcmp("fourth stdio!\n", output) == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -728,7 +728,7 @@ TEST_IMPL(spawn_tcp_server) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -750,7 +750,7 @@ TEST_IMPL(spawn_ignored_stdio) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -775,7 +775,7 @@ TEST_IMPL(spawn_and_kill) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 2); /* Once for process and once for timer. */ - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -815,7 +815,7 @@ TEST_IMPL(spawn_preserve_env) { printf("output is: %s", output); ASSERT(strcmp("testval", output) == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -845,7 +845,7 @@ TEST_IMPL(spawn_detached) { r = uv_kill(process.pid, SIGTERM); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -903,7 +903,7 @@ TEST_IMPL(spawn_and_kill_with_std) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 5); /* process x 1, timer x 1, stdio x 3. */ - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -950,7 +950,7 @@ TEST_IMPL(spawn_and_ping) { ASSERT(exit_cb_called == 1); ASSERT(strcmp(output, "TEST") == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -997,7 +997,7 @@ TEST_IMPL(spawn_same_stdout_stderr) { ASSERT(exit_cb_called == 1); ASSERT(strcmp(output, "TEST") == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1029,7 +1029,7 @@ TEST_IMPL(spawn_closed_process_io) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 2); /* process, child stdin */ - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1083,7 +1083,7 @@ TEST_IMPL(kill) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1135,7 +1135,7 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) { printf("output is: %s", output); ASSERT(strcmp("hello world\n", output) == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1363,7 +1363,7 @@ TEST_IMPL(spawn_with_an_odd_path) { uv_close((uv_handle_t*) &process, NULL); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif @@ -1406,7 +1406,7 @@ TEST_IMPL(spawn_setuid_setgid) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif @@ -1459,7 +1459,7 @@ TEST_IMPL(spawn_setuid_fails) { ASSERT(close_cb_called == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1504,7 +1504,7 @@ TEST_IMPL(spawn_setgid_fails) { ASSERT(close_cb_called == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif @@ -1535,7 +1535,7 @@ TEST_IMPL(spawn_setuid_fails) { ASSERT(close_cb_called == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1556,7 +1556,7 @@ TEST_IMPL(spawn_setgid_fails) { ASSERT(close_cb_called == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif @@ -1570,7 +1570,7 @@ TEST_IMPL(spawn_auto_unref) { uv_close((uv_handle_t*) &process, NULL); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT(1 == uv_is_closing((uv_handle_t*) &process)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1633,7 +1633,7 @@ TEST_IMPL(spawn_fs_open) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 2); /* One for `in`, one for process */ - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1705,7 +1705,7 @@ TEST_IMPL(closed_fd_events) { ASSERT(0 == close(fd[1])); #endif - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1775,7 +1775,7 @@ TEST_IMPL(spawn_reads_child_path) { ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1859,7 +1859,7 @@ TEST_IMPL(spawn_inherit_streams) { r = memcmp(ubuf, output, sizeof ubuf); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1883,7 +1883,7 @@ TEST_IMPL(spawn_quoted_path) { /* We test if libuv will not segfault. */ uv_spawn(uv_default_loop(), &process, &options); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; #endif } @@ -1922,7 +1922,7 @@ TEST_IMPL(spawn_exercise_sigchld_issue) { ASSERT_EQ(exit_cb_called, 1); ASSERT_EQ(close_cb_called, 101); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -2009,6 +2009,6 @@ TEST_IMPL(spawn_relative_path) { ASSERT_EQ(1, exit_cb_called); ASSERT_EQ(1, close_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-stdio-over-pipes.c b/test/test-stdio-over-pipes.c index 1aed4712277..1b7f17297ca 100644 --- a/test/test-stdio-over-pipes.c +++ b/test/test-stdio-over-pipes.c @@ -145,7 +145,7 @@ static void test_stdio_over_pipes(int overlapped) { r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); ASSERT(r == 0); - r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + r = uv_run(loop, UV_RUN_DEFAULT); ASSERT(r == 0); ASSERT(on_read_cb_called > 1); @@ -155,7 +155,7 @@ static void test_stdio_over_pipes(int overlapped) { ASSERT(memcmp("hello world\nhello world\n", output, 24) == 0); ASSERT(output_used == 24); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); } TEST_IMPL(stdio_over_pipes) { @@ -294,6 +294,6 @@ int stdio_over_pipes_helper(void) { ASSERT(on_pipe_read_called == 2); ASSERT(close_cb_called == 4); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-tcp-alloc-cb-fail.c b/test/test-tcp-alloc-cb-fail.c index b6f4ca38850..a1b5e84d3b1 100644 --- a/test/test-tcp-alloc-cb-fail.c +++ b/test/test-tcp-alloc-cb-fail.c @@ -118,6 +118,6 @@ TEST_IMPL(tcp_alloc_cb_fail) { ASSERT(connection_cb_called == 1); ASSERT(close_cb_called == 3); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-bind-error.c b/test/test-tcp-bind-error.c index c3ca6ec824a..edb44c21459 100644 --- a/test/test-tcp-bind-error.c +++ b/test/test-tcp-bind-error.c @@ -72,7 +72,7 @@ TEST_IMPL(tcp_bind_error_addrinuse_connect) { ASSERT(connect_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -105,7 +105,7 @@ TEST_IMPL(tcp_bind_error_addrinuse_listen) { ASSERT(close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -130,7 +130,7 @@ TEST_IMPL(tcp_bind_error_addrnotavail_1) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -153,7 +153,7 @@ TEST_IMPL(tcp_bind_error_addrnotavail_2) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -178,7 +178,7 @@ TEST_IMPL(tcp_bind_error_fault) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -206,7 +206,7 @@ TEST_IMPL(tcp_bind_error_inval) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -223,7 +223,7 @@ TEST_IMPL(tcp_bind_localhost_ok) { r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -240,7 +240,7 @@ TEST_IMPL(tcp_bind_invalid_flags) { r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, UV_TCP_IPV6ONLY); ASSERT(r == UV_EINVAL); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -254,7 +254,7 @@ TEST_IMPL(tcp_listen_without_bind) { r = uv_listen((uv_stream_t*)&server, 128, NULL); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -294,7 +294,7 @@ TEST_IMPL(tcp_bind_writable_flags) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -312,6 +312,6 @@ TEST_IMPL(tcp_bind_or_listen_error_after_close) { ASSERT_EQ(uv_tcp_bind(&tcp, (struct sockaddr*) &addr, 0), UV_EINVAL); ASSERT_EQ(uv_listen((uv_stream_t*) &tcp, 5, NULL), UV_EINVAL); ASSERT_EQ(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-bind6-error.c b/test/test-tcp-bind6-error.c index 86181b708e3..656ebe34e29 100644 --- a/test/test-tcp-bind6-error.c +++ b/test/test-tcp-bind6-error.c @@ -66,7 +66,7 @@ TEST_IMPL(tcp_bind6_error_addrinuse) { ASSERT(close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -92,7 +92,7 @@ TEST_IMPL(tcp_bind6_error_addrnotavail) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -120,7 +120,7 @@ TEST_IMPL(tcp_bind6_error_fault) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -151,7 +151,7 @@ TEST_IMPL(tcp_bind6_error_inval) { ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -171,6 +171,6 @@ TEST_IMPL(tcp_bind6_localhost_ok) { r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-close-accept.c b/test/test-tcp-close-accept.c index 624262bcfe9..b255cfbd9f3 100644 --- a/test/test-tcp-close-accept.c +++ b/test/test-tcp-close-accept.c @@ -187,7 +187,7 @@ TEST_IMPL(tcp_close_accept) { ASSERT(ARRAY_SIZE(tcp_outgoing) == write_cb_called); ASSERT(1 == read_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-tcp-close-after-read-timeout.c b/test/test-tcp-close-after-read-timeout.c index 493492dba6a..098e405a875 100644 --- a/test/test-tcp-close-after-read-timeout.c +++ b/test/test-tcp-close-after-read-timeout.c @@ -178,6 +178,6 @@ TEST_IMPL(tcp_close_after_read_timeout) { ASSERT_EQ(read_cb_called, 1); ASSERT_EQ(on_close_called, 3); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-tcp-close-reset.c b/test/test-tcp-close-reset.c index 66dfc82eb47..7415646996c 100644 --- a/test/test-tcp-close-reset.c +++ b/test/test-tcp-close-reset.c @@ -223,7 +223,7 @@ TEST_IMPL(tcp_close_reset_client) { ASSERT(close_cb_called == 1); ASSERT(shutdown_cb_called == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -250,7 +250,7 @@ TEST_IMPL(tcp_close_reset_client_after_shutdown) { ASSERT(close_cb_called == 0); ASSERT(shutdown_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -277,7 +277,7 @@ TEST_IMPL(tcp_close_reset_accepted) { ASSERT(close_cb_called == 1); ASSERT(shutdown_cb_called == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -304,7 +304,7 @@ TEST_IMPL(tcp_close_reset_accepted_after_shutdown) { ASSERT(close_cb_called == 0); ASSERT(shutdown_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -331,6 +331,6 @@ TEST_IMPL(tcp_close_reset_accepted_after_socket_shutdown) { ASSERT_EQ(close_cb_called, 1); ASSERT_EQ(shutdown_cb_called, 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-tcp-close-while-connecting.c b/test/test-tcp-close-while-connecting.c index 8d0b8270645..490413891bb 100644 --- a/test/test-tcp-close-while-connecting.c +++ b/test/test-tcp-close-while-connecting.c @@ -88,7 +88,7 @@ TEST_IMPL(tcp_close_while_connecting) { ASSERT(timer1_cb_called == 1); ASSERT(close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); if (netunreach_errors > 0) RETURN_SKIP("Network unreachable."); diff --git a/test/test-tcp-close.c b/test/test-tcp-close.c index 5a7bd6893bf..6879bae20f8 100644 --- a/test/test-tcp-close.c +++ b/test/test-tcp-close.c @@ -131,6 +131,6 @@ TEST_IMPL(tcp_close) { ASSERT(write_cb_called == NUM_WRITE_REQS); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-tcp-connect-error-after-write.c b/test/test-tcp-connect-error-after-write.c index ad214b9396b..1800b4d6ed0 100644 --- a/test/test-tcp-connect-error-after-write.c +++ b/test/test-tcp-connect-error-after-write.c @@ -92,7 +92,7 @@ TEST_IMPL(tcp_connect_error_after_write) { ASSERT(write_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; #endif } diff --git a/test/test-tcp-connect-error.c b/test/test-tcp-connect-error.c index dda30a58064..9384ebce57c 100644 --- a/test/test-tcp-connect-error.c +++ b/test/test-tcp-connect-error.c @@ -68,6 +68,6 @@ TEST_IMPL(tcp_connect_error_fault) { ASSERT(connect_cb_called == 0); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-connect-timeout.c b/test/test-tcp-connect-timeout.c index 0f968157127..4cd83e1d38b 100644 --- a/test/test-tcp-connect-timeout.c +++ b/test/test-tcp-connect-timeout.c @@ -86,7 +86,7 @@ TEST_IMPL(tcp_connect_timeout) { r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -153,7 +153,7 @@ TEST_IMPL(tcp_local_connect_timeout) { r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -191,6 +191,6 @@ TEST_IMPL(tcp6_local_connect_timeout) { r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT_EQ(r, 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-connect6-error.c b/test/test-tcp-connect6-error.c index 2f6e9cbce14..8646dd56496 100644 --- a/test/test-tcp-connect6-error.c +++ b/test/test-tcp-connect6-error.c @@ -66,6 +66,6 @@ TEST_IMPL(tcp_connect6_error_fault) { ASSERT(connect_cb_called == 0); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-create-socket-early.c b/test/test-tcp-create-socket-early.c index f2bc60d7c7c..c84882dad21 100644 --- a/test/test-tcp-create-socket-early.c +++ b/test/test-tcp-create-socket-early.c @@ -128,7 +128,7 @@ TEST_IMPL(tcp_create_early) { uv_close((uv_handle_t*) &client, NULL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -173,7 +173,7 @@ TEST_IMPL(tcp_create_early_bad_bind) { uv_close((uv_handle_t*) &client, NULL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -190,7 +190,7 @@ TEST_IMPL(tcp_create_early_bad_domain) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -204,6 +204,6 @@ TEST_IMPL(tcp_create_early_accept) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-flags.c b/test/test-tcp-flags.c index 68afb39f456..6856429aa1d 100644 --- a/test/test-tcp-flags.c +++ b/test/test-tcp-flags.c @@ -47,6 +47,6 @@ TEST_IMPL(tcp_flags) { r = uv_run(loop, UV_RUN_DEFAULT); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-tcp-oob.c b/test/test-tcp-oob.c index 53f8231e83e..989454ed878 100644 --- a/test/test-tcp-oob.c +++ b/test/test-tcp-oob.c @@ -135,7 +135,7 @@ TEST_IMPL(tcp_oob) { ASSERT(ticks == kMaxTicks); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-tcp-open.c b/test/test-tcp-open.c index 7e49139cd81..b5c5621a793 100644 --- a/test/test-tcp-open.c +++ b/test/test-tcp-open.c @@ -277,7 +277,7 @@ TEST_IMPL(tcp_open) { ASSERT(write_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -304,7 +304,7 @@ TEST_IMPL(tcp_open_twice) { uv_close((uv_handle_t*) &client, NULL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -327,7 +327,7 @@ TEST_IMPL(tcp_open_bound) { ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, NULL)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -361,7 +361,7 @@ TEST_IMPL(tcp_open_connected) { ASSERT(write_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -396,6 +396,6 @@ TEST_IMPL(tcp_write_ready) { ASSERT(write_cb_called > 0); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-read-stop-start.c b/test/test-tcp-read-stop-start.c index 9bccbc12fc5..9be12bb75b0 100644 --- a/test/test-tcp-read-stop-start.c +++ b/test/test-tcp-read-stop-start.c @@ -131,6 +131,6 @@ TEST_IMPL(tcp_read_stop_start) { ASSERT(read_cb_called >= 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-tcp-read-stop.c b/test/test-tcp-read-stop.c index 488e8fb49a9..1754876d4f1 100644 --- a/test/test-tcp-read-stop.c +++ b/test/test-tcp-read-stop.c @@ -70,7 +70,7 @@ TEST_IMPL(tcp_read_stop) { (const struct sockaddr*) &addr, connect_cb)); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-rst.c b/test/test-tcp-rst.c index 16bc9ce4a82..b5d216ce7e8 100644 --- a/test/test-tcp-rst.c +++ b/test/test-tcp-rst.c @@ -102,7 +102,7 @@ TEST_IMPL(tcp_rst) { ASSERT_EQ(called_connect_cb, 1); ASSERT_EQ(called_close_cb, 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; #else RETURN_SKIP("Unix only test"); diff --git a/test/test-tcp-shutdown-after-write.c b/test/test-tcp-shutdown-after-write.c index 463b4b0d79c..d2401e8fdb3 100644 --- a/test/test-tcp-shutdown-after-write.c +++ b/test/test-tcp-shutdown-after-write.c @@ -133,6 +133,6 @@ TEST_IMPL(tcp_shutdown_after_write) { ASSERT(conn_close_cb_called == 1); ASSERT(timer_close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-tcp-try-write-error.c b/test/test-tcp-try-write-error.c index 2201d0ea61a..97deccaa0dd 100644 --- a/test/test-tcp-try-write-error.c +++ b/test/test-tcp-try-write-error.c @@ -104,6 +104,6 @@ TEST_IMPL(tcp_try_write_error) { ASSERT(close_cb_called == 3); ASSERT(connection_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-try-write.c b/test/test-tcp-try-write.c index 97a1d6e3d57..6458857a85c 100644 --- a/test/test-tcp-try-write.c +++ b/test/test-tcp-try-write.c @@ -130,6 +130,6 @@ TEST_IMPL(tcp_try_write) { ASSERT(bytes_read == bytes_written); ASSERT(bytes_written > 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-unexpected-read.c b/test/test-tcp-unexpected-read.c index c7b981456be..e11f77473f4 100644 --- a/test/test-tcp-unexpected-read.c +++ b/test/test-tcp-unexpected-read.c @@ -112,6 +112,6 @@ TEST_IMPL(tcp_unexpected_read) { */ ASSERT(ticks <= 20); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-tcp-write-after-connect.c b/test/test-tcp-write-after-connect.c index 8a698f44bd5..4a786995ff1 100644 --- a/test/test-tcp-write-after-connect.c +++ b/test/test-tcp-write-after-connect.c @@ -66,7 +66,7 @@ TEST_IMPL(tcp_write_after_connect) { uv_run(&loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(&loop); return 0; } diff --git a/test/test-tcp-write-fail.c b/test/test-tcp-write-fail.c index 58ee00faedb..2912e7c5068 100644 --- a/test/test-tcp-write-fail.c +++ b/test/test-tcp-write-fail.c @@ -110,6 +110,6 @@ TEST_IMPL(tcp_write_fail) { ASSERT(write_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-write-in-a-row.c b/test/test-tcp-write-in-a-row.c index f50e5186c09..99f4dee125e 100644 --- a/test/test-tcp-write-in-a-row.c +++ b/test/test-tcp-write-in-a-row.c @@ -136,7 +136,7 @@ TEST_IMPL(tcp_write_in_a_row) { ASSERT_EQ(1, connection_cb_called); ASSERT_EQ(2, write_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; #endif } diff --git a/test/test-tcp-write-queue-order.c b/test/test-tcp-write-queue-order.c index 1ff9c517cec..7562c41d3de 100644 --- a/test/test-tcp-write-queue-order.c +++ b/test/test-tcp-write-queue-order.c @@ -134,6 +134,6 @@ TEST_IMPL(tcp_write_queue_order) { write_cancelled_callbacks == REQ_COUNT); ASSERT(close_cb_called == 3); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-write-to-half-open-connection.c b/test/test-tcp-write-to-half-open-connection.c index ae4251317d8..8978211d2b7 100644 --- a/test/test-tcp-write-to-half-open-connection.c +++ b/test/test-tcp-write-to-half-open-connection.c @@ -136,6 +136,6 @@ TEST_IMPL(tcp_write_to_half_open_connection) { ASSERT(write_cb_called > 0); ASSERT(read_cb_called > 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-tcp-writealot.c b/test/test-tcp-writealot.c index 382c2712ed8..3c6c149e92c 100644 --- a/test/test-tcp-writealot.c +++ b/test/test-tcp-writealot.c @@ -179,6 +179,6 @@ TEST_IMPL(tcp_writealot) { free(send_buffer); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index 1e867c51cf9..a6c9d3465d6 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -189,7 +189,7 @@ TEST_IMPL(threadpool_cancel_getaddrinfo) { ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(1 == timer_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -225,7 +225,7 @@ TEST_IMPL(threadpool_cancel_getnameinfo) { ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(1 == timer_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -248,7 +248,7 @@ TEST_IMPL(threadpool_cancel_random) { ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(1 == done_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -272,7 +272,7 @@ TEST_IMPL(threadpool_cancel_work) { ASSERT(1 == timer_cb_called); ASSERT(ARRAY_SIZE(reqs) == done2_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -326,7 +326,7 @@ TEST_IMPL(threadpool_cancel_fs) { ASSERT(1 == timer_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -344,6 +344,6 @@ TEST_IMPL(threadpool_cancel_single) { ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(1 == done_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-threadpool.c b/test/test-threadpool.c index e3d17d7546f..5254131bce3 100644 --- a/test/test-threadpool.c +++ b/test/test-threadpool.c @@ -54,7 +54,7 @@ TEST_IMPL(threadpool_queue_work_simple) { ASSERT(work_cb_count == 1); ASSERT(after_work_cb_count == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -71,6 +71,6 @@ TEST_IMPL(threadpool_queue_work_einval) { ASSERT(work_cb_count == 0); ASSERT(after_work_cb_count == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-timer-again.c b/test/test-timer-again.c index 834b59d718c..cb298956aa9 100644 --- a/test/test-timer-again.c +++ b/test/test-timer-again.c @@ -136,6 +136,6 @@ TEST_IMPL(timer_again) { (long int)(uv_now(uv_default_loop()) - start_time)); fflush(stderr); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-timer-from-check.c b/test/test-timer-from-check.c index a18c7e1fb99..e1a002d8121 100644 --- a/test/test-timer-from-check.c +++ b/test/test-timer-from-check.c @@ -75,6 +75,6 @@ TEST_IMPL(timer_from_check) { uv_close((uv_handle_t*) &check_handle, NULL); uv_close((uv_handle_t*) &timer_handle, NULL); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-timer.c b/test/test-timer.c index a9fa534f5ad..1753fbccc07 100644 --- a/test/test-timer.c +++ b/test/test-timer.c @@ -154,7 +154,7 @@ TEST_IMPL(timer) { ASSERT(500 <= uv_now(uv_default_loop()) - start_time); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -174,7 +174,7 @@ TEST_IMPL(timer_start_twice) { ASSERT(twice_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -187,7 +187,7 @@ TEST_IMPL(timer_init) { ASSERT_UINT64_LE(0, uv_timer_get_due_in(&handle)); ASSERT(0 == uv_is_active((uv_handle_t*) &handle)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -236,7 +236,7 @@ TEST_IMPL(timer_order) { ASSERT(order_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -260,7 +260,7 @@ TEST_IMPL(timer_huge_timeout) { ASSERT_UINT64_EQ(281474976710655, uv_timer_get_due_in(&huge_timer1)); ASSERT_UINT64_LE(0, uv_timer_get_due_in(&huge_timer2)); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -286,7 +286,7 @@ TEST_IMPL(timer_huge_repeat) { ASSERT(0 == uv_timer_start(&tiny_timer, huge_repeat_cb, 2, 2)); ASSERT(0 == uv_timer_start(&huge_timer1, huge_repeat_cb, 1, (uint64_t) -1)); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -314,7 +314,7 @@ TEST_IMPL(timer_run_once) { uv_close((uv_handle_t*) &timer_handle, NULL); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -327,7 +327,7 @@ TEST_IMPL(timer_is_closing) { ASSERT(UV_EINVAL == uv_timer_start(&handle, never_cb, 100, 100)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -338,7 +338,7 @@ TEST_IMPL(timer_null_callback) { ASSERT(0 == uv_timer_init(uv_default_loop(), &handle)); ASSERT(UV_EINVAL == uv_timer_start(&handle, NULL, 100, 100)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -365,6 +365,6 @@ TEST_IMPL(timer_early_check) { uv_close((uv_handle_t*) &timer_handle, NULL); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tty-duplicate-key.c b/test/test-tty-duplicate-key.c index efd79e14786..6ba96c81352 100644 --- a/test/test-tty-duplicate-key.c +++ b/test/test-tty-duplicate-key.c @@ -180,7 +180,7 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -246,7 +246,7 @@ TEST_IMPL(tty_duplicate_alt_modifier_key) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -310,7 +310,7 @@ TEST_IMPL(tty_composing_character) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-tty-escape-sequence-processing.c b/test/test-tty-escape-sequence-processing.c index e311c0f02d4..d40dca4974b 100644 --- a/test/test-tty-escape-sequence-processing.c +++ b/test/test-tty-escape-sequence-processing.c @@ -420,7 +420,7 @@ TEST_IMPL(tty_cursor_up) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -471,7 +471,7 @@ TEST_IMPL(tty_cursor_down) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -532,7 +532,7 @@ TEST_IMPL(tty_cursor_forward) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -593,7 +593,7 @@ TEST_IMPL(tty_cursor_back) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -644,7 +644,7 @@ TEST_IMPL(tty_cursor_next_line) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -695,7 +695,7 @@ TEST_IMPL(tty_cursor_previous_line) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -741,7 +741,7 @@ TEST_IMPL(tty_cursor_horizontal_move_absolute) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -797,7 +797,7 @@ TEST_IMPL(tty_cursor_move_absolute) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -831,7 +831,7 @@ TEST_IMPL(tty_hide_show_cursor) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -905,7 +905,7 @@ TEST_IMPL(tty_erase) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -979,7 +979,7 @@ TEST_IMPL(tty_erase_line) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1037,7 +1037,7 @@ TEST_IMPL(tty_set_cursor_shape) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1237,7 +1237,7 @@ TEST_IMPL(tty_set_style) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; #endif } @@ -1297,7 +1297,7 @@ TEST_IMPL(tty_save_restore_cursor_position) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1340,7 +1340,7 @@ TEST_IMPL(tty_full_reset) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1620,7 +1620,7 @@ TEST_IMPL(tty_escape_sequence_processing) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; #endif } diff --git a/test/test-tty.c b/test/test-tty.c index f53a701fce7..418ec31e4b5 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -94,12 +94,12 @@ TEST_IMPL(tty) { ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); - r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ + r = uv_tty_init(loop, &tty_in, ttyin_fd, 1); /* Readable. */ ASSERT(r == 0); ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); - r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + r = uv_tty_init(loop, &tty_out, ttyout_fd, 0); /* Writable. */ ASSERT(r == 0); ASSERT(!uv_is_readable((uv_stream_t*) &tty_out)); ASSERT(uv_is_writable((uv_stream_t*) &tty_out)); @@ -112,7 +112,7 @@ TEST_IMPL(tty) { if (width == 0 && height == 0) { /* Some environments such as containers or Jenkins behave like this * sometimes */ - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return TEST_SKIP; } @@ -141,7 +141,7 @@ TEST_IMPL(tty) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -184,7 +184,7 @@ TEST_IMPL(tty_raw) { ASSERT(ttyin_fd >= 0); ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); - r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ + r = uv_tty_init(loop, &tty_in, ttyin_fd, 1); /* Readable. */ ASSERT(r == 0); ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); @@ -211,7 +211,7 @@ TEST_IMPL(tty_raw) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -242,7 +242,7 @@ TEST_IMPL(tty_empty_write) { ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); - r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + r = uv_tty_init(loop, &tty_out, ttyout_fd, 0); /* Writable. */ ASSERT(r == 0); ASSERT(!uv_is_readable((uv_stream_t*) &tty_out)); ASSERT(uv_is_writable((uv_stream_t*) &tty_out)); @@ -257,7 +257,7 @@ TEST_IMPL(tty_empty_write) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -288,7 +288,7 @@ TEST_IMPL(tty_large_write) { ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); - r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + r = uv_tty_init(loop, &tty_out, ttyout_fd, 0); /* Writable. */ ASSERT(r == 0); memset(dummy, '.', sizeof(dummy) - 1); @@ -303,7 +303,7 @@ TEST_IMPL(tty_large_write) { uv_run(loop, UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -336,7 +336,7 @@ TEST_IMPL(tty_raw_cancel) { r = uv_read_stop((uv_stream_t*) &tty_in); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } #endif @@ -410,9 +410,8 @@ TEST_IMPL(tty_file) { ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); - ASSERT(0 == uv_loop_close(&loop)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(&loop); #endif return 0; } @@ -463,7 +462,7 @@ TEST_IMPL(tty_pty) { ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(&loop); #endif return 0; } diff --git a/test/test-udp-alloc-cb-fail.c b/test/test-udp-alloc-cb-fail.c index 6b0980163a5..073dea97782 100644 --- a/test/test-udp-alloc-cb-fail.c +++ b/test/test-udp-alloc-cb-fail.c @@ -191,6 +191,6 @@ TEST_IMPL(udp_alloc_cb_fail) { ASSERT(sv_recv_cb_called == 1); ASSERT(close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-bind.c b/test/test-udp-bind.c index a1e080ee70c..200cdc7c927 100644 --- a/test/test-udp-bind.c +++ b/test/test-udp-bind.c @@ -55,7 +55,7 @@ TEST_IMPL(udp_bind) { r = uv_run(loop, UV_RUN_DEFAULT); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -88,6 +88,6 @@ TEST_IMPL(udp_bind_reuseaddr) { r = uv_run(loop, UV_RUN_DEFAULT); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-udp-connect.c b/test/test-udp-connect.c index d78e62e3551..c1e4064b94e 100644 --- a/test/test-udp-connect.c +++ b/test/test-udp-connect.c @@ -191,6 +191,6 @@ TEST_IMPL(udp_connect) { ASSERT(client.send_queue_size == 0); ASSERT(server.send_queue_size == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-connect6.c b/test/test-udp-connect6.c index 9195ef90105..076d8d77b92 100644 --- a/test/test-udp-connect6.c +++ b/test/test-udp-connect6.c @@ -194,6 +194,6 @@ TEST_IMPL(udp_connect6) { ASSERT_EQ(client.send_queue_size, 0); ASSERT_EQ(server.send_queue_size, 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-create-socket-early.c b/test/test-udp-create-socket-early.c index f7e46abc98d..f51e275ba1e 100644 --- a/test/test-udp-create-socket-early.c +++ b/test/test-udp-create-socket-early.c @@ -68,7 +68,7 @@ TEST_IMPL(udp_create_early) { uv_close((uv_handle_t*) &client, NULL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -113,7 +113,7 @@ TEST_IMPL(udp_create_early_bad_bind) { uv_close((uv_handle_t*) &client, NULL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -130,6 +130,6 @@ TEST_IMPL(udp_create_early_bad_domain) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-dgram-too-big.c b/test/test-udp-dgram-too-big.c index bd44c425287..9db8b47be18 100644 --- a/test/test-udp-dgram-too-big.c +++ b/test/test-udp-dgram-too-big.c @@ -86,6 +86,6 @@ TEST_IMPL(udp_dgram_too_big) { ASSERT(send_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-ipv6.c b/test/test-udp-ipv6.c index 6f491fbb7dc..ae55cd01b0b 100644 --- a/test/test-udp-ipv6.c +++ b/test/test-udp-ipv6.c @@ -207,7 +207,7 @@ static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) { ASSERT(close_cb_called == 3); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); } diff --git a/test/test-udp-mmsg.c b/test/test-udp-mmsg.c index f722608a185..c37343f8c9f 100644 --- a/test/test-udp-mmsg.c +++ b/test/test-udp-mmsg.c @@ -144,6 +144,6 @@ TEST_IMPL(udp_mmsg) { else ASSERT_EQ(alloc_cb_called, recv_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-multicast-interface.c b/test/test-udp-multicast-interface.c index bd9a61c98aa..447d3487f5c 100644 --- a/test/test-udp-multicast-interface.c +++ b/test/test-udp-multicast-interface.c @@ -99,6 +99,6 @@ TEST_IMPL(udp_multicast_interface) { ASSERT(client.send_queue_size == 0); ASSERT(server.send_queue_size == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-multicast-interface6.c b/test/test-udp-multicast-interface6.c index d69b3419727..1d40aefa8cb 100644 --- a/test/test-udp-multicast-interface6.c +++ b/test/test-udp-multicast-interface6.c @@ -103,6 +103,6 @@ TEST_IMPL(udp_multicast_interface6) { ASSERT(sv_send_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-multicast-join.c b/test/test-udp-multicast-join.c index 2c375cc0196..dddcea4662f 100644 --- a/test/test-udp-multicast-join.c +++ b/test/test-udp-multicast-join.c @@ -179,6 +179,6 @@ TEST_IMPL(udp_multicast_join) { ASSERT(sv_send_cb_called == 2); ASSERT(close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-multicast-join6.c b/test/test-udp-multicast-join6.c index f7ac113d471..d5262b6a9a0 100644 --- a/test/test-udp-multicast-join6.c +++ b/test/test-udp-multicast-join6.c @@ -186,7 +186,7 @@ TEST_IMPL(udp_multicast_join6) { r = uv_udp_set_membership(&server, MULTICAST_ADDR, INTERFACE_ADDR, UV_JOIN_GROUP); if (r == UV_ENODEV) { - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); RETURN_SKIP("No ipv6 multicast route"); } @@ -213,6 +213,6 @@ TEST_IMPL(udp_multicast_join6) { ASSERT(sv_send_cb_called == 2); ASSERT(close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-multicast-ttl.c b/test/test-udp-multicast-ttl.c index fbddd90914c..9aa5bb9147f 100644 --- a/test/test-udp-multicast-ttl.c +++ b/test/test-udp-multicast-ttl.c @@ -89,6 +89,6 @@ TEST_IMPL(udp_multicast_ttl) { ASSERT(sv_send_cb_called == 1); ASSERT(close_cb_called == 1); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-open.c b/test/test-udp-open.c index f5136b6d4f2..0e09f56a49f 100644 --- a/test/test-udp-open.c +++ b/test/test-udp-open.c @@ -188,7 +188,7 @@ TEST_IMPL(udp_open) { ASSERT(client.send_queue_size == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -215,7 +215,7 @@ TEST_IMPL(udp_open_twice) { uv_close((uv_handle_t*) &client, NULL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -245,7 +245,7 @@ TEST_IMPL(udp_open_bound) { uv_close((uv_handle_t*) &client, NULL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -295,7 +295,7 @@ TEST_IMPL(udp_open_connect) { ASSERT(client.send_queue_size == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -344,7 +344,7 @@ TEST_IMPL(udp_send_unix) { close(fd); unlink(TEST_PIPENAME); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } #endif diff --git a/test/test-udp-options.c b/test/test-udp-options.c index 3ea51baf40b..11e58b996a1 100644 --- a/test/test-udp-options.c +++ b/test/test-udp-options.c @@ -87,7 +87,7 @@ static int udp_options_test(const struct sockaddr* addr) { r = uv_run(loop, UV_RUN_DEFAULT); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -155,6 +155,6 @@ TEST_IMPL(udp_no_autobind) { ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-udp-recv-in-a-row.c b/test/test-udp-recv-in-a-row.c index 531fd1fac0f..98aca28e193 100644 --- a/test/test-udp-recv-in-a-row.c +++ b/test/test-udp-recv-in-a-row.c @@ -116,6 +116,6 @@ TEST_IMPL(udp_recv_in_a_row) { ASSERT(check_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-send-and-recv.c b/test/test-udp-send-and-recv.c index d60209059b9..ab60e84a138 100644 --- a/test/test-udp-send-and-recv.c +++ b/test/test-udp-send-and-recv.c @@ -207,6 +207,6 @@ TEST_IMPL(udp_send_and_recv) { ASSERT(client.send_queue_size == 0); ASSERT(server.send_queue_size == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-send-hang-loop.c b/test/test-udp-send-hang-loop.c index 072070b60e5..b1e02263d3c 100644 --- a/test/test-udp-send-hang-loop.c +++ b/test/test-udp-send-hang-loop.c @@ -94,6 +94,6 @@ TEST_IMPL(udp_send_hang_loop) { ASSERT(loop_hang_called > 1000); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-send-immediate.c b/test/test-udp-send-immediate.c index a1c95d34384..ee70a6165a2 100644 --- a/test/test-udp-send-immediate.c +++ b/test/test-udp-send-immediate.c @@ -143,6 +143,6 @@ TEST_IMPL(udp_send_immediate) { ASSERT(sv_recv_cb_called == 2); ASSERT(close_cb_called == 2); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-send-unreachable.c b/test/test-udp-send-unreachable.c index c67a23b3852..7075deb1896 100644 --- a/test/test-udp-send-unreachable.c +++ b/test/test-udp-send-unreachable.c @@ -196,6 +196,6 @@ TEST_IMPL(udp_send_unreachable) { ASSERT_EQ(timer_cb_called, 1); ASSERT_EQ(close_cb_called, (long)(can_recverr ? 3 : 2)); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-sendmmsg-error.c b/test/test-udp-sendmmsg-error.c index c8a411b2dee..7b1741a3e04 100644 --- a/test/test-udp-sendmmsg-error.c +++ b/test/test-udp-sendmmsg-error.c @@ -70,6 +70,6 @@ TEST_IMPL(udp_sendmmsg_error) { ASSERT_EQ(0, client.send_queue_size); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-udp-try-send.c b/test/test-udp-try-send.c index 85caaaca41d..b81506cc39f 100644 --- a/test/test-udp-try-send.c +++ b/test/test-udp-try-send.c @@ -116,6 +116,6 @@ TEST_IMPL(udp_try_send) { ASSERT(client.send_queue_size == 0); ASSERT(server.send_queue_size == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-walk-handles.c b/test/test-walk-handles.c index 4b0ca6ebc55..50f0ce84f1e 100644 --- a/test/test-walk-handles.c +++ b/test/test-walk-handles.c @@ -72,6 +72,6 @@ TEST_IMPL(walk_handles) { uv_walk(loop, walk_cb, magic_cookie); ASSERT(seen_timer_handle == 0); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } diff --git a/test/test-watcher-cross-stop.c b/test/test-watcher-cross-stop.c index b26deb8d88c..bbc0c30574a 100644 --- a/test/test-watcher-cross-stop.c +++ b/test/test-watcher-cross-stop.c @@ -107,6 +107,6 @@ TEST_IMPL(watcher_cross_stop) { ASSERT(ARRAY_SIZE(sockets) == send_cb_called); ASSERT(ARRAY_SIZE(sockets) == close_cb_called); - MAKE_VALGRIND_HAPPY(); + MAKE_VALGRIND_HAPPY(loop); return 0; } From d4eb276eea7cb19a888fe97d7759d97c7092ad02 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Mon, 13 Mar 2023 11:54:31 +0100 Subject: [PATCH 329/713] darwin: bring back macos-specific copyfile(3) (#3654) Co-authored-by: Mingye Wang --- src/unix/fs.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index ea1d305f31d..9c8ef6cc066 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -65,6 +65,7 @@ #endif #if defined(__APPLE__) +# include # include #elif defined(__linux__) && !defined(FICLONE) # include @@ -1240,6 +1241,32 @@ static ssize_t uv__fs_write(uv_fs_t* req) { } static ssize_t uv__fs_copyfile(uv_fs_t* req) { +#if defined(__APPLE__) && !TARGET_OS_IPHONE + /* On macOS, use the native copyfile(3). */ + copyfile_flags_t flags; + + /* Don't overwrite the destination if its permissions disallow it. */ + if (faccessat(AT_FDCWD, req->new_path, R_OK | W_OK, AT_EACCESS)) { + if (errno != ENOENT) + return UV__ERR(errno); + } + + flags = COPYFILE_ALL; + + if (req->flags & UV_FS_COPYFILE_FICLONE) + flags |= COPYFILE_CLONE; + + if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) + flags |= COPYFILE_CLONE_FORCE; + + if (req->flags & UV_FS_COPYFILE_EXCL) + flags |= COPYFILE_EXCL; + + if (copyfile(req->path, req->new_path, NULL, flags)) + return UV__ERR(errno); + + return 0; +#else /* defined(__APPLE__) && !TARGET_OS_IPHONE */ uv_fs_t fs_req; uv_file srcfd; uv_file dstfd; @@ -1415,6 +1442,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { errno = UV__ERR(result); return -1; +#endif /* defined(__APPLE__) && !TARGET_OS_IPHONE */ } static void uv__to_stat(struct stat* src, uv_stat_t* dst) { From 4a65e10f5e372ba7cc9b21dd21b18fe0eedc0054 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Wed, 15 Mar 2023 22:35:18 -0600 Subject: [PATCH 330/713] doc: add entries to LINKS.md (#3925) Add the libuv wrapper nsuv to the list, along with other C++ apps that were found to use libuv extensively and have been maintained recently. --- LINKS.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/LINKS.md b/LINKS.md index 253e584b23d..c2d79f8bb7a 100644 --- a/LINKS.md +++ b/LINKS.md @@ -1,8 +1,11 @@ ### Apps / VM +* [AliceO2](https://github.com/AliceO2Group/AliceO2): The framework and detector specific code for the reconstruction, calibration and simulation for the ALICE experiment at CERN. +* [Beam](https://github.com/BeamMW/beam): A scalable, confidential cryptocurrency based on the Mimblewimble protocol. * [BIND 9](https://bind.isc.org/): DNS software system including an authoritative server, a recursive resolver and related utilities. * [cjdns](https://github.com/cjdelisle/cjdns): Encrypted self-configuring network/VPN routing engine * [clearskies_core](https://github.com/larroy/clearskies_core): Clearskies file synchronization program. (C++11) * [CMake](https://cmake.org) open-source, cross-platform family of tools designed to build, test and package software +* [Cocos-Engine](https://github.com/cocos/cocos-engine): The runtime framework for Cocos Creator editor. * [Coherence](https://github.com/liesware/coherence/): Cryptographic server for modern web apps. * [DPS-For-IoT](https://github.com/intel/dps-for-iot/wiki): Fully distributed publish/subscribe protocol. * [HashLink](https://github.com/HaxeFoundation/hashlink): Haxe run-time with libuv support included. @@ -30,6 +33,7 @@ * [phastlight](https://github.com/phastlight/phastlight): Command line tool and web server written in PHP 5.3+ inspired by Node.js * [pilight](https://www.pilight.org/): home automation ("domotica") * [pixie](https://github.com/pixie-lang/pixie): clojure-inspired lisp with a tracing JIT +* [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 * [Socket Runtime](https://sockets.sh): A runtime for creating native cross-platform software on mobile and desktop using HTML, CSS, and JavaScript @@ -40,6 +44,7 @@ * [Urbit](http://urbit.org): runtime * [uv_callback](https://github.com/litesync/uv_callback) libuv thread communication * [uvloop](https://github.com/MagicStack/uvloop): Ultra fast implementation of python's asyncio event loop on top of libuv +* [WPILib](https://github.com/wpilibsuite/allwpilib): Libraries for creating robot programs for the roboRIO. * [Wren CLI](https://github.com/wren-lang/wren-cli): For io, process, scheduler and timer modules ### Other @@ -60,6 +65,7 @@ * [lluv](https://github.com/moteus/lua-lluv) * C++11 * [uvpp](https://github.com/larroy/uvpp) - Not complete, exposes very few aspects of `libuv` + * [nsuv](https://github.com/nodesource/nsuv) - Template wrapper focused on enforcing compile-time type safety when propagating data * C++17 * [uvw](https://github.com/skypjack/uvw) - Header-only, event based, tiny and easy to use *libuv* wrapper in modern C++. * Python From 66009549067cab59d697cd8df8091a179d1a15fc Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Mon, 20 Mar 2023 10:04:57 -0600 Subject: [PATCH 331/713] win,unix: change execution order of timers (#3927) The maximum number of times timers should run when uv_run() is called with UV_RUN_ONCE and UV_RUN_NOWAIT is 1. Do that by conditionally calling timers before entering the while loop when called with UV_RUN_DEFAULT. The reason to always run timers at the end of the while loop, instead of at the beginning, is to help enforce the conceptual event loop model. Which starts when entering the event provider (e.g. calling poll). Other than only allowing timers to be processed once per uv_run() execution, the only other noticeable change this will show is if all the following are true: * uv_run() is called with UV_RUN_NOWAIT or UV_RUN_ONCE. * An event is waiting to be received when poll is called. * Execution time between the call to uv_timer_start() and entering the while loop is longer than the timeout. If all these are true, then timers that would have executed before entering the event provider will now be executed afterward. Fixes: https://github.com/libuv/libuv/issues/3686 Co-authored-by: Momtchil Momtchev --- docs/src/design.rst | 17 +++++++------ docs/src/static/loop_iteration.png | Bin 80528 -> 65186 bytes src/unix/core.c | 25 ++++++++---------- src/win/core.c | 25 ++++++++---------- test/test-list.h | 4 +++ test/test-timer.c | 39 +++++++++++++++++++++++++++++ 6 files changed, 74 insertions(+), 36 deletions(-) diff --git a/docs/src/design.rst b/docs/src/design.rst index 0f5580c7e95..5a20595c3b4 100644 --- a/docs/src/design.rst +++ b/docs/src/design.rst @@ -60,16 +60,15 @@ stages of a loop iteration: :align: center -#. The loop concept of 'now' is updated. The event loop caches the current time at the start of - the event loop tick in order to reduce the number of time-related system calls. +#. The loop concept of 'now' is initially set. + +#. Due timers are run if the loop was run with ``UV_RUN_DEFAULT``. All active timers scheduled + for a time before the loop's concept of *now* get their callbacks called. #. If the loop is *alive* an iteration is started, otherwise the loop will exit immediately. So, when is a loop considered to be *alive*? If a loop has active and ref'd handles, active requests or closing handles it's considered to be *alive*. -#. Due timers are run. All active timers scheduled for a time before the loop's concept of *now* - get their callbacks called. - #. Pending callbacks are called. All I/O callbacks are called right after polling for I/O, for the most part. There are cases, however, in which calling such a callback is deferred for the next loop iteration. If the previous iteration deferred any I/O callback it will be run at this point. @@ -101,9 +100,11 @@ stages of a loop iteration: #. Close callbacks are called. If a handle was closed by calling :c:func:`uv_close` it will get the close callback called. -#. Special case in case the loop was run with ``UV_RUN_ONCE``, as it implies forward progress. - It's possible that no I/O callbacks were fired after blocking for I/O, but some time has passed - so there might be timers which are due, those timers get their callbacks called. +#. The loop concept of 'now' is updated. + +#. Due timers are run. Note that 'now' is not updated again until the next loop iteration. + So if a timer became due while other timers were being processed, it won't be run until + the following event loop iteration. #. Iteration ends. If the loop was run with ``UV_RUN_NOWAIT`` or ``UV_RUN_ONCE`` modes the iteration ends and :c:func:`uv_run` will return. If the loop was run with ``UV_RUN_DEFAULT`` diff --git a/docs/src/static/loop_iteration.png b/docs/src/static/loop_iteration.png index e769cf338b4456ea688b0abf888b646a4253e0eb..1545f84a8dcd1cf7b5035f467fea69321e230302 100644 GIT binary patch literal 65186 zcmagF2Ut@}+xLqQDIyYzBGOABfOH5=dO`^`^p2DS2mwMbQltn0q=-QUq!>j}dT#=v zpnzaOiZnqK6)7qT2nc+W?S9_xdC$4db+-E=Yt5Q9Yu1!|=KkIPm2PQn$a3t=F&Y{g z7Goo%6%EaiAsQMw2S$33f~>CY0zXGWtqk>OYF_Xz)6g(XgrOY50-|t!1S}0qQUC7| zOhL{!C^QVFh=eI9co2y)-hLiFAszvtGJ)7IkOZy=1bO@6{IK4C^C-wEC`!vIO3Nc` zz*R+EWo7V3NmWKwP1Wgdeh(jP;J*bb%gBKO;12TgFhxCZWa<|f9tD1*R1xk7B?)k( zOC%Do_E=97KkzgIWknSkMFjO06C)clQ<#E2I41b{W5JIh*2_PLdW*hqNKgPsF_4#+ zllkW#NVN9Ad4%}=R}s{jW5Yar{?m96wbl@x=J9?~Y>F-}zln*P(amY`Xr<^L9S<1;a*Cej zC{?vcqEncurzs)Y53P$+ls5_sh(;<~M~3P<+RN!e*Tm)f|zC03)x6NJ5mNN{FGk6V5wam)ce)Q6|3D;T~346MsDmkYI}rkXIslsz#!M ziE2T1F-qa)p^gXxAG~g`wWnW@8o|%T5fv4Rh(Z!PJ@u7L4bA0L&24Rc<$bLcje<=O zYC$SW#sm{ZC!Ad{D9+k8z|qbc>uDN{bo6sFRJKRUqvZooI8!G_TeZMIBZml-p_Qe9 zi2=gG3~din&@-V{D%xAc9ucH$;Y96DBarF{ejUAWRx03F4I7AvR*ukDu*8E@PZL78 z57r!IX`)8-#o8i+0xbz4h;Wp?u}M&rIV#%3(1NIE9D}mAB2Nmv*M;Yj2YQk1e+KIhg+*r-&@}y%qrAOF4V-zKFrJ{ z(#+Jv(Zq;=_4lyS^9eFC4~+`6Q^2dJsfCB&m9dK9W;kP9kTu@V(@9Ux9_eix1Ih@n z_KNli_jYvj3W)KS)3q_viwMMl^ay+~)=xHHEiNC79gA)ogzrM9fl)in#&oZENuM2yXl#PTN8Zkae9IF7AAT| zfsW?pj)p;DL_}nykC!bd-^jqs$2%g>R?$#Rk7yQc?&pP-$A{Ugf=d_$IXQE~U`Lda zAId%;IKazJ%~nmtR#n~_VeX-dv5Hhxj#N>$(KS)V_+gQ1XkSNV1!I(Bc%Z66l!|^B z!Aw6C*b6-~#~?Jp(_76C>yI=DwL+RY`Wwdh$k{~O5_AnC%oR|e+0nWLJ+FWWqOF{Y zoVmQ5nl8qkIw{amwz}a#o+?&Rj@EKWH9|xT-pDTmTtFZl^ew$r6m%^E&28oN!og!4 zod~x2K~d4R-q=W_zOAP&GC*Ng*BJKP!p<&8l{!u~ZPL{#O$^nt)1lw>Ylp#jR(cC{8p=57pjth-Z zQZfzFlgHug>_FirYL=E3VYW)dKx;)?b6-y@Yg@dT1u-aufVc69#Cu?^jlx54fk^6z zu(MZE)>8_wa3X|Qns}?=Ok<)w%TBbTuti1d zIeDl?7%EY_1)(fw=x?fEPf$_}4^fP9LKp@p830qOXK95*I4J26F}gt(HW(ZR6|CZA z7!=~47@RF7!@qS3S%W76l9Kw#2I)|tx|}-nMn*1p%xvE z1%wh_AWriu#s_SV6kSS6bXuMqzzFI|KM(oxyT zkQk=mp%7__RWVoau(vX>QZuyjiwLu~(+v&@jkfjk^E8VHRq%=-T6(DI+S)kjdItsC zg`icvgTXSVCud_A6X@+3Vu?{OwL~j;+AA0$iIMuMI9qHCUf0e~-Xc;DjW$z>REzRJ zg_=63=%SqT33!uG2Y*vPGi8ET7@p{%6o~dvmA8)yQBl@c#F&7E(ZIyc*vH-y9C$_H z!N>tdin@AG|EIqFe^#D=*V~o_biE>*lKH4;kXuXtw=LUJ^ z&TQ(;-S0!g|NYBAYl8Xv3-ApV8)WmU zjl!9Z2nj+`E<&NS>5O6Qml}q3$zS>PbpD=$W4iwwf7RE? zXwaJdMFwSnv?eB6;UR>dudVgptl%=zQ6Mk|{r7Yla)b?Aq}234;_p*8g#;;8tSXwY zzo!977fB6fXPm}4sbw)H?n0rMiL{~;_P?hHT^;0<7)$ZpLiH^b7IcRpsxG7fy+)E+{cm_7B#b>7(<92vdBLzYgG3>vqQ%WgXRyyfsq$;9tn0%6Oeurv%sGZTtw z@#z$w*ey*sU^@fq2g!JJ+Uqh~#nM5MH04)MR!E~IvVdny(uh%s54`3ZA!#g}GJIlY zA>?51TTgPMBR%sGA-Q9T^3Qm!Exl7Nk`zSF>kr!@xjicfaiAfFJ6K8ZMg!HdKZm<3 zwXdtP4EOtkUTtR27^YYlLdLW=Rs_7VlpOgfIq?4npR(epPak@#eDv@2G%`< zbL*{FPVw^ZS1$@O;WO=$4)DH@T1Sc(!E2 zi`N3nUL6_=37#{M;NE1=-b*GabYkq01$-^NOMgJM8GIU#pQ6<}&q@0sTcf6IfDycz z!K2h0)g*;JyQ?F5I>>@>0VoESMbz1070@~-=#PB>h5`oC5wRwzqd>jRRwsm$q8zUu z_iluqz64&ovjn^>wO#lTgc}sMlba9p7w9x02@iifWeyx>>Oaqhg-hor7Yn1~V8|KI z$8)DdD8qrdoEThM08#C5YbK~bYRFI^Zmg$UyaT<)>2&o+-);U3(-s~`~jUH8q;ATf{P zh-tr1bx%$xu2i>{w11&wo_X9^5HX$ZKD|NR~}7e1*BY84vH_j&&u1}6Evq3R;pFQ{92!fczCmY1U@uw?>=|!=Un8xauxhJ+Y+a>sfTRb z?(#i8PHdwjBSxliSOGUAac{K@UX-7p_%jinqq@kr5`+4YT5^LCJJ&7b$?59J_&UBc z;1p(eR$Xmo0!`_QYkx$`e53!A^YCo!&yi2ViZ7K^W{JtY;b^6K;mot1TXT`_if>F6 z!*$9N4i6%-@|rCs;M-F^0z7r>78aVDKM6HRQ=&HHDS7YocWN)ow0~sJJn26(*BRNm{sOee zoR)xDu3|vz;lW;!@`S^aj>OUn>uNv0^&A#*<8Jg4x;7_T&Lv%VP>x^gT)O65=p58F z&Ko|4!CiNasGn-zVDj~B&?#fRv8cN|SzFp1UEMs<;6L-L*hIE#EcVZjXE;i_n1WPQ zT~e{P=oQPx>3dGaZ``;rcTo?v_K@UeFT1zm@t_}uZ$mKTg?+r!5;eJcR}5wJ2`29bYAXE+n%S zc7E%g(R!lu?0mwchPDQ?p_A$v59Xm#+y`=Y8l>7lqhJZB>oisRj2gkig zLgY^0PoI5qZ>LMhopZ}~t`<(ZC(MPdOpJW8h(pW}6gv;lV={E=DUgCIr)Rl;zd^c| z1V81DsB`xz4j(?s^%wW;b8*%ZJizi!Eu8VL(SpJr-MX2rv98*9u)E?cj0)J$m^pI# zV!`Hh5wU|8G^;M5=G-%!KpaOw9*UM$6h%fyH9!6dqcwW0CQpue_5uXM1Os+4*@meGGjhJDx>Y zR5vx3E`9BI#r-cn)xg%NCx3l%a`!1u5P7vP{4*!4#@>(&*JMXOYriufyL_;}HS@A# z1{iR0lhhwEA;rD?kNaS&q>%QdYmFHjYpwGw*!<_(Oad*{Wkwif@tedXzFgP#3fbAh zHv1s3=vZloOzzB_&{#eHmLo&BGF96dOGN1zfu*Bcnqiav{pQ#4=jVP7E5azmwH)+Q zmh9;#)tWPe#)5={ooDRFXJUw-M-6_w4Aiv&Go#ZnerIWaYB~}yP{W3+5da3;ihRc=RLkaVxPP_W5^9d8$s;7m2|V=nno|%>Dyn# z+z=U>@+qCuO41mq-bAH0%HyE_*4-!!3RX%OO65-Z5NxoRXp= zI94Mv|0UdL`MGRQllL-hDPRcZ@Y{rh<5S9P;SP2y&rHY znSpg3O1cu(Bb9mN^d=3H+`!M(qM&X+*IS|k{YQ_yKAGzK4^EoB1aPvjK`1O$?`<>Gw6dPH%&;lK%f$Qvp)5XEraHcOF zYgO#>wr7m4l8(co-$j3RY?Z{6$<&)K4P@x{a3j+dys|DIDY%&HD=NJd4>lqQb(H|U z_v)A2)(b=_eE}xObe&}5f$x@2UZ9vOpTx^fGio|+{&GBU7ev;MyswAR&K5v(Ey?b2oB6inrIy0)$6t1Qwj?8GC~$$Og+%04L8E(H4%*=v zc`-pf`&)KXVld&7;CB0lXPVED6)t;vgsLkI6TG%$vc(10=%swV3`0!E<_oY+iC=-= z-od`s%4!PuH8m(!RORR>QF@wI7#*I@PP=AAZj%*4x!`kQM|ggu9P`#diXaCei33jb zIAQ&rE|;V-%yye`aglnw>`G?tQUCn$7thUv(Hk&UPT`N&$v2eh0uA?>&PTt$#6{pd zdzHaR+AoWJscSJqYTCc8c4t|P(d2ABGHpTBUTh`Bl+l;jWj=7Ej#sN%6ivWK>?!#( zvSSd;gRg(G{oN4X9v)qNZo*Sj5+;z+dxnn*^`V7sx=Th^dDUS!nIt z35)ww;M0=9e(3|njhk4!xG-z+_>*h=k3C0mm})X47;41cTqJ#locWw3Pw-LdN*j|9 zWXwqEn93kOBi*F%Oi;^QgmdM(I*uz`9JWAUSV; zd5cIwr_SDf`91^3a&@<1!lgRF7Vplv#1}d1v3-LAzrFN^-rgk`mG)=wxy1Pi_>?=h zw6;VKuGOM>_ih(|BoBiMO*Em7H2UG`;EYmhyVmm%ZZaQ+-E?sb>b^ikrWYxf{4Nqf zlb*pQ9`Rz-C#5C@(e%15S;uqXJVRiA(sHiOEV&vimXF7FI>FhMq!Mn*gYT99#M=IOxzq4FD3ju; ztA2k(xArYp==qe77c);F+reLF)SwQh1vE=! z$hVG_u2uv+G3VmBLXUn4W6WNI8E-58ZoG@~r1`|jOClv+l|D^=exNZXmT?1uX|Sb5 z?SPF{{!seo9F6PB=Io+b>W{{ax__jc39WG_(WCkb1;qOo_)~{5Z$!;Ab;HF1e9}KN z-%_I>F&z-C*zlt&vUt|(!YM~5L{EsGHdBqEKU?n^$heh-3L>(0}8`Wv6V{+P{PEIwTIO8UqSef1UDED<@gj$Y5A?V ztaV47cWB-V*VF_6;+Mn8gBQYVFz@HnXS`_&7GjWt*F@}+5(U}FQgm8hkJ-yeaRr!?Pc@vCRha?Qiv(H776)Yo6 zUEXHvai70bDBXH6IH-{e_s@W8V;(}h-aokfE%`G0N$&wBEy%9Ui}S;f-hf?;WR7jJ z|NKJ|J5S;GKeg0i!z!nI?UA8W33NWz96Vno3MtH@K^nh;W@K*~l@p+(Z%0P%lDCF! zky9mWB@X^<=7{p&i5)#)2ED)Ah#5zWX8M@bCfZtuCr2WtC9 zz?y-$cxHc`ntITmwaTtjncelKf#v4MiB@<2t8~-kUA}j3{SY$$^v!J2Rgwy%n zd1z{?e)(K&gKai&`Lh7RARO;OTV%o;pCH<9PVtwCLQ-^YFt+WNc{qJ*9T!IT%!u2s zAj$2Is~@N6SOXstaq`890^lf8^UpWMf2#s{`DXOUUb5*joUz*w2EhAbv(VXE;Tzw$>w}DS#=qJ4u z92f!E!r&&k|HVhIS%n#V9s(i)Zm4zZn*RU2A-3Gj7?3PEwlBcfyOGLpzL}(O(O~E~ zlGIS(uJ|Z$$$oDV@hhAq&b6=WXY)gC&?N@wf4$~~-eeR(1Vs@3Dwp12QL5FOrFQG| zS<3P9@{l@3G zy=O`oeK-SGVMdYLb*qz7bly-qfN#_)_3uvnb0QrB{r}LO{k?52PHrldVsyYtLH=Qc z{W<{VU5>Dk{^v|j@GnQIBwV5bM7^@pV3=mU&VF#|FADsZaOGG3J>{eW@iX>hGKO?`THcEt-L4TY9|(omG&|5EL)$v5~;rNB1hyKXmpl>e{07kVnF&G zHc`p;V@Ef(*&GR6mH!8|yWi**K2iAsH?l>Tzwl1 zsJwiUMc$bWOR5$tqT;L-EznA5-e24}T&e9bXhd}Hi^M0_M9%UH$EpjL9b9ogJndgq zPkScdv4Sm<+wKAuFO9tKYme$gXq>U$S>n*t03Mf*x>i%@C*h%pzrB$N>H6ojRKg z`sMVcM{OUnrQrWB5C;bJ90QWg)g=CsvHB`mrTJ-8wMNKPu{%41U6*;z04PGdTl2*xzQU+N z$hmO)+SNcVFEB=%oBkay*WKfPOyEc%GXbs2nlZoRlIdB{O&q9Luxj4`aB1@U9spE6 z{D3(It&qJ>BisLMJaAG4@eKdby6xC~|==kK0oe*y{fXdt>IqvoIu8t5jLj@nC5aLfA#ZSsBWR_OOI&WMPISe92YkBWl`YRhs7qA)_VDNGCV0n}XX_r(;_CZPDXPrJ zHmU(1o8?Z{$`!aiZ5na&h0+^SW#!*#0`b1)nwvI1`#3CafEoGj*SGokRWPdW0;e(^ z**@XqUtq`|-FK}A>_fBdCh(QjxS#6Vv!NrYJb`cDtG8H1mK*}Vr)n5Ot*Ug7_IGc;T6W3E17fpsPJc+Bj}^8*W=FVt6VFw3-^Z`x0~ zcQXW?4j)YZJRi61+W1P3xd5QCSC{3Vp8f=On@X|ULBR7u%*XFl2Y68e1Y*7jDV~3H z(dM@%80puBExU71tz0>NU}|%EOi18h>uY80wT)y;MsvyuDE8q&Wo>r{YzPd|8A8)* zgYp&V8!(A+bj2jAOJ$7HdTe=uQlzTsNh`}wRom~th~H8p5r*ZTHF+z7(w!*}*IH&) z4~5VhonSL6jR|ZR6iZb$6@xSh^z|M2lWlsR3p2v|)l6sT)h+$CX22EZwYakEs++ZP zg|FU(U2}LG3mn@|U{@^Lb)Cv;LE||NH$0c|7e|ukJ0pXf`8l`=NL?=h?YNx6atldp zGBD3PF3H2n-jozZun%Ug#9LY<9PYQ;O2JR6JW|#pE5YwX%mzOz*qn5q2a%rs6E%Nc zM5F_JGjq*0izsL~#w*(S<0(%Ohq-DmyL7Sw{&Ep~Zu_q;wdOnRyLQ6pugRX>R7$oXCP1EZjhw>{@?5a|36E~s z(P?{Y@~+}sQu6Pvl3i8Goi2E$@e%(C*@xegbYY#wC+`eTBk-p#_?Ci4y@Wjyuy@>8`b%Sw+}2E_^_L$^3LJdE92xXfD8SonDb4wbL;3D6qdn& ziayx+oU=7`mUF588NWXRfm~os&Shb;m-u=%gDzQWU2Ou%ZBzOFv&{rR=!C&zo}@(v zj~|hwjeL7IiMWYlMHmF(B}och;ts-4Rnz@}W0DbNpQtE%#qDTM)SjB@-mhh^jl~K? zM=Eb!_)6WCF!-Y4J_1Yey#?<_%1caYhR^06Z~6flESu)VJgwEBAYtm*G(3oHJdYeT z7GL{*`Xi%6qZTCE#-t4ej7oecKv&l%HYhJ=0WMC}OouK33g*(m2}8RS`~ZJRB}!D{ zC)@L9G!J&8kE2(ut$ZpO?MQZ%xD|7+5dVN3V=&oAK@RpM_T8bOT%Nq-e^YAsW701G zQyraer!z4Hx``pcI%hq%>5( zNHt_9k}TBXWPnK1Bj?(mt3QO=_S0PUXTR>Mn4YJJH_mv?23xrd`3U;O#qm&2ZE-YH zeEOntlRV!yP-0mPEMX^X2!zq@ zhjF9QGxOBNB+xBtMC}MKZMG(J7Ws7FRD~pX@k(CBtBRGAo}IvwSDUCkfIB9nz^CqV zh@)HI?Yz+VCd!Ug>WNvQ!?6E2hDo|m-nT2deR~-5?d7?jm%~js#+g%*JG(cq2h*#N#$gkD+ynMbelVUd92UpFS6#vx zlX>~$Uutf@rMU(;V5kz0puUm3IT`Y$?&ziPraMpG3)ve@u)(-rf)H_p3H?=CF$QBM ztBZdeD!uni%E!=@s#dLWQpiBA(8NitXS|`8w=@kWl+?^~Q2mB68ql{ zV2@qE1^vpJ+i)QT607i8ABHQG3aOgLQ_EZW8wp#UA?H;BmCPTd8%Q)Bw&5YxcQib~JOxSpxOnopwq`FPdh!J=VGd1GP)+6Fy#!YEgln4@3~#-SkHaG2z&e`^bd=Q@=EQhN`JWh{W!)V`qh^vOxZ zBNjha2tFPSz1J}gm4UX07S@5YaeT8hAM1OC(K$TgL2quj?iH$@e8vW&^Dl3jbh}Uh z7R%{(dKc5JX{+SfP4zu1kCY}SofB-++;b$52;pquvf3f9e}F_LF^qE76!Ot|&L_W?QzlI^NsFed^H z-4M+kjPpo(n0^*(0@YS)7BfqN-=`Dj(!B`jxhTXiq5mDqBNM_N!4J47jB@!?4jNFc zf_{dbJAc03XN~J;!~Uu};=_EzWsFZnZry_`F7tW*mQHUYOKP=bx8aiv_?uq~yX$N~ zjNvR)n!%v(+s2s0u17NL5}O+6Wy%$qaaB!E-4tu>PLb^GLMJJyA}@N)spcOYe_EEl z!hu>Qx7z(0EGq9ErofxtqEdzb% z*8x9;w~usKF%*)kr?oc6@hu%I!=XiQUNHty#Pn@-p#`P%HI>&d6Y6uwYx0DlG&rl~ zuUG6C3Y-t~)O8M8Zha5=?kV;C>S`x;b;t{;6w_n0bX-X{TvFs$uC%SCCt=xpMQNJT zuRq@Y*uA>gSu8XyP8BIAG_=E!Oy>xZIr-O{QTl4zNX@ zd$z#pv521q+tVsZ)1n(^i4+!ZrgnB-)GHe|q@#b_12))B@B1*OyJKND{!?_P5xR* z#on{){?OCkwwl{Bz8n^(yd1bv9$$U1V4pyo2}t6JqLl;gm5#^~)^qgMd~|+w2w(!f z$AOFQ_1iYa>92ldI4vh1Br|d({ub|hTy?3`E)%{_xPHw6Mjv=1Kf|W-RH!5M#<=3(y_n0$vhTvI0EDn^9JpXK##-PrVe0^@xefg?-_!FSp^v1q&;m0p;2Pb^OTbOt?iZaBf+PV|54TO|po5U52EZZH z@^3iw1T%nOY+sj=lNYpMFOS3cbLzn-XeEu%D<^QY1`E4_!uX~DDYmRdt!NsB_Q{&hl$=LP+v|^=xxTYI}xB(Q|p>K zo3iIXQ$1Fxm%JfQMMy{Nw)D!z!E>DFXeG6&;OSOt*(w*UEg&xsG8q$}f?q^xX~`+t zcho|=)4j_+gWQ@yf(7CbNg+AHTRFwp-^4dv7q%N(%Y}x3VxthCo5H}k4kjX?Yn~wU zI4nhHfsr@3kL|8u4nJ#7oeFrcE4lLzV!4oqtQ-Lg`0lZWJOU;lifOtvNW39+9x6%ra(9wUyH6CN96#`J``2A+@N+>*; z=D|kS_B$!pEOs0j{sA&b2i)GPV|QY%K`SnTkuj&w$Vrn}@!+x@!{e|A^1By)@!ub$ z4WqFYvIehS@VIjLl1@BhpDng9uUza+*_{j1|I;gSjHz2+_%1$u^F;$WOnNA zj_sA>phIwsH4Ud|qeUz;ACL=&JHu_z#E!qr0=dtuU5agYy?zf$9(J9LVr4lk_%FqZl z(3>2+HgQzyRQO${chP%4JU!wUtmVU_Un}1`(#VJYR~AE*t3q z`oX|E^jgtbU$0810;)0Lbi>L(oHBK6!1G#Kq-|o_K<+028jdoM2f|QIIy-!Wq)Ue` zqbSI1^9)LR)R4y3cywEg`Q57rZa9!vG1-or`G_`D$2RX*m$CM=zFkThm{kuESNrwK za1bCSk=+}1@XE6N*%$-lnAG_h@$JZigj;N<g+pnB?fsh{44!mm5pw0CeF|EE8MFfQH&78)SB}FzhnW3LATI$1@8WIApPA0yp7W^A<lx9=>_9~dl(9}+cD2@jqz9w~+X z29AyfuV8L-KuA9>t8Rn!NMcz!`-a!T!o5ANqnhTIf6(8LDAs+vzcN~$IT4`u<@M1P zHhU>_!^!k;6I6c-ZFK%J9c?d|I)dh!soC;O4JpnpH=9{Ih#9v_5KHelJm}=|ztY_8 z12>7|>}c7Vn0qhyDui-;e59}?-Lc1;=JhVtsc-tH7GuLWraDVl)}8Y(} za=c6ZuW*plKrnjorJq-gA60Zh;>rw%a)PL<~->&#!p=>el+X23S7GQ1ht}~ z)h(GH;2FY*ksQyt=u*Gwbx*tzRdyelKC=u00V5NOh`~6ZQM4yo&;+beI*P(a$AE6p z8{k+q#U-+JAy8!8TT5CX_Dcc}F?${-hRBCAy<^&EX6$a#{`?ri_4g_tZcY2+9$h?w z?JXfR3=V@iAC!865C6N1ly2;Cs>Y5qDltSAb&+0`*KpK0n4PkIQqH4@ER#SEp2~HP z-$A7vQ)<8E(0KEF64S%C3X7yXN#M^v`~7I4o}p#6dVlWF#>Z!Kp3sQZHu} z2C%%1iOmekm@eP#cdX=cil;yKba;>=o9_)c(}J#RihW&;7jAjRAumeR2D9UF2@3K2PAyKo2v6)x~-gdrs~AhD+fc`-H36HXCj zT_6;)c5xT@`q_6$&q3%u6bMd>Kv?PZasG2}G1J=lcxtl1r=&f(0LT)Hr$7K8AeZms zM5Vp#&k>dRx0_z0ROW9E^x~t6&?Tx^7>oyymFb8p=${RF zE{#oBGr2i?i&vdT&4ipE$(xu;%HvAsa*((Hp+<+UJs5&x++u(9N9a&V*f6)xO^*m5 z;XXkl3b?>eu${u?Lnpahh`KY8K#s|+@#Jj_L^6PGRK-m$_r|z`=e4$YU5c8}l0Eu?W>dg%I^*SEjTj&IlGKX#0x(kUK z+G#vu3

rQxP)(0rA=J9lqKl9F+2FPD5_DS-^aYTQR=a^pCi8#W{$+&9lH)f+_JF z)RzP=a6JH_u7a8=-z?nN8M8`TEE&GD5A>G`)Ub}LhTcw@jSE^By}rav?=YLT{_7Tq z+PpdO$vt7eS$AI!x|jQ%tRuX%TiRGZHR*WU#pBY+)ibcRJZ=AcplC`dhTmH7x#5w@ zj&%9V*Jry6=12ihPmfY#Ia^e9Ct)3c*kmpmtIV3}kbS`Q8$YH$zZOxJb4!rRH4L+N z4$?7#mWL_6by2F;lj??G|4i`_Mtf?d*p2?=wL?b24ea zz!wPdXZL}Kv-!%`nHyB2m+I531PCFAVUT5THA-@?AX zCD9p3`FNBtS=-$D;DVfQ^VcV>#sK;lZ&|YoCV2`CBy$41z)bg*8f$hg-8V zreyT5WzqHnTXGW!@~UFY&3nxwXss}W3DcquV}o%Vw|Sq)!0$^H7$Z66LYwFkt#}jCXv<$NOvqfHaE)~R39d|i zu@h6zh6mTOuN9KpxQ=$dPX&7HZc&m|jf1<>ZHI_46d5WSI2khk^3AQ!#p+c7?K0MZ zhpy6-LPK`QKlvhPg5e;sxcTYcdS{Rl#rwP_h?Whr8S-N6*hT=|`~=j_bt{D20Jrq+ zg3Md2r#Xnd2`%1$=J z37aQ$lm1d#Pi)iS!Ci|<{U@K(4Cz8%i>#7Hy2P{LyzKdW-^dyjB8A!7GIhDT}Dej*2CqwAvG3Q;cUKG3s zU-qiPgnS~NQ;S@4^eJ94`))gH(C+zD{HpME2QCcwJS1lq9-0|*^hyqg#kt`1a(iL) zWuc0+1%BFWpg%WlZ*&X3$F4Mb+mMxKn8V#Cy!RaBDpAReKfQML_X0j^@?`jDpubDi z72eI4KGUSBs}ww`^tydD4&pr9NH{7K0OA#huO}yegHfk(rpn$mJf9k(MhAwvTyN`f z9g}+bouH(9r!B1h=yssguIKcDuJ%VDzY49be)bkGEH&N0cYuhS#3G8rrkOo9)62)?kGimO8Mh2q&|9K@vV*t^G#S3TSqny9`!l%|u8gS|FyGsk?d z;_H-#VJM;k)5pq<7m0KO+n~1_wtwFI#>92D*CV8V_nlSzjJ+ae!?Rgk;Z=}PV{5i! z$h+6IekAsW4}!F<0dO=KLM}s|Ca9rOd#~SSEsa`aS`qWEd#Nr5Il8>JZ3ULLt8b{G zyobP5Ye~NKs+bnp+lUxE7z5_8OP>L`te=+)TbXI|QoHl$=x->z55d}+{e{H7trAVK z!qh>}PQE?$w2!{wgv3zO$#14xB8lh$=ETDEyu`bs1_VB+9DYRJg!gpW#yh<$sqp0{ z!r@!6><|vK5^$MDe%W;*wK>`cZDF6_;?K)s8%(=9oIZrh0D&8WP|`QBj^gP`zj)p3 zITiuFFlpAr$w<5xUaGP;*Y#XGodbC`T8|s%f9o5994!0+J}x@X$|tD9Y_I$qo^+>Q)@b$L1N`Ecz9iw zH=B3=KC4xl^7I&z+!jB*|5n}TC@Nh_il6O<&l?Wk_q2+5=}9)xmE_|Y8mo2s)s9gK z+K}ZIx#*xOL;6#$7=v4>@SiS^1&LYd65pKJ#P9Nlf4Ey@#eu=6z8mD1TO;LVZB-Wr zbKJCCi64UNc9itFwF!4MwK*}dkKV^@W}RF^k_E|WQWI>V+L`L|)wQjce%hEJ2hSFx z_N$U@V_(cm{1a9$F}jL5ube^v*HOZ5&iSgdJ0Nh|bfKRy*wFSzd4%x6@8cMy_5yjH`kh#gUX`2p z$83J*p4p%JT_$aKub<-rDms;A3Zev+Zv8cCGBYxZ^xa*EfyMSrx7RK)HjrecA%j~v zc4jU%fm^TNIa-wcc%}5@WDznKb@N6`27?nO&+7t z$2{bUCPt~G4BZ!vMJ4vhdlFvYtTpeCBaJmlu~~POAj@P6wh6H%y!15jqeUD(xZh4> zK-kQ5-|tqe^!;?W+MhycVVV9X%OCEltfZBw>3YLe%(TpJA-}m*-$uCugvJq^>Zw(r>rtqzYCxx*=UaCUAGg(jVwG-)SMG|3 zGug--yG~9OydBNy5x{O=*_~GS?fmP&a(V7Fx##7eY9-Q-`eR8?(#C2%eKyjl$Ra-+P}@IR+1Th ztfY6Jy;fHA$$hvvriGR@a`v?MplD(Mzh7QsI8gmCZg}Tgo2&JA90(c5lk}V(kS^xQXyXoZ) zQJ{3i%BGT4`gJ^_>@2t8jT?Gobi5!D$Ui=N8kr%NIk7U=_G_U71)&me#3pzg?}Z_a z8PY6=*kJ1?yBRGys9#KJ?X7zCEJp%?nCL0vk5c~E!ADm^xhWJ={Ttb$n9=7lodhSN zuJ)X8FX7t!6rFdBs+5nKPn=Q5qDKo<;vMrp!!UYI`4b--Xy}f5?Hd zuX}ei)8RYoC3`y3lixa4WO#lIsbkepgV)&4q$#J_Nup=%vf-|CqwHegPY<9uuOIu< zIJQXcs+-OGZ)utisouQ#NHJdg{n7O8dE9kpY3&ovKAyYa^TDax(#!UZFVrhFmEtzX z?Q6H9pp%aALZg~zj%HG-F3Dv=IToC~eza@lT?Zd&irx_a)_l}W%MF>Gr7ta(&zioW z+3k0)cp?Iii_3=3T|Y&6S>OMJMG1};qdE74Atd(u#^za=@TcjMS6zh7D3em|T<8i!$}TGGDjy^H#gg##az)R+EA zPgwli%OKEHdOYc^pu9`iCLCRuv?fR}R0BJlHN(`~=~vMX+aIxnW(tIkYtyNQ*-m&k z*S5S;7E`;nkYQ#;CZu`Zzi2GvmV1uFKfFTJh&}%TQ10X-zIt)&6|}biNmIdG#Ei7X zn?k!&kb*7JfKrNt?Nrmee_dngm-fOSD)_Py>*Y$k8 zE*x=EWAD;&wYq98KM}4PrOg+7`e&A*hIjpSdDGsivoj0?2rKSYz&(W9XVyB9U7!BP z)vMliT&4S4MitmJ0w182^vCxHX`R13N*jC}B_fMOU6Q$_C0BPhhgz656)4Q-*5biue1)7v0>i}wpzZ;ypkkQD*Tq$;y}3uo0c9VFIdU=6}HRGAp*Z6 z$+QQ5&{~Z3!*=D`t9fG19do=e2WCObsY1I|M$b9uCEKTuvsbyfd(*}mTrNJz)aIN? zc;sYAf9?;@zbrs(Pf>F1)nD>t~R_gdFhW*rVWwK+ZqN?;Q zGR(xnGo{U6&nfZfDTb+VvVPDWh5fswC9i8n$N0*p>YoK>3QUr(CYetg{7N)&V%r*> z{Un2tWVsP-T|wuLh0SY35bVv@Eo#7Z=`(oLmvmTe*oK1{Mtz$3H)P zUh4PbDYI3USp~K}HS4@ywx&@=wTe2fg@0E0(xL4)jk#|*m#tmupO++GrL&-LvAL^D z@m#W=q!awDnR}8ub+X?hgShopvKU_W?HwT11{KocjnG_u{#{heo0l<^rPudeP;%%X z`=g$a*X0*0=NmW%J%@b)H#sHMoJQmJRg&f0Ghoku)2)|nw(%o*``fKMmey5n&%5}0 zagPiVY?t=i1@&|!I|WU|(3bDCIhbt3#}lZdsK3o?(M1o~z3OIjAoehxz425%v&x)T z=PeU^-wQLB$zKWjX>(FKbele0InEsHyuL!Z7~y|e_`@snnmwF~I)Se86RD+l8?mLdf{jaSI(Zj4f6ZT8ny%i?U(cQB zMA_?^KF}1i!#gIWe7RIQ!PlMmu{GyZ(}TDx*4LYU6bPWG zC+i6Wrk}FKh=dd(aL% z;khMFon_Iggj1fLC7-_K_tXax518+gXg;la@~utQoYL$Ihz-{1_{HTroWU==GI)8n zQ?)sT)ROZ!>aTYE01f1ExXZoNOJzFwq4^A&>jhUGo=sHvVACr>%Q4gMObPzOM_lE) zUn2R_yJ^oDoKf>in0l`f@lzeAFjN+=OIRJHu9)vzO~NxITq`egjFRjFIr%y%`ldd_kNWx@~irM@mP z)c!3pb57SYrcu^oi2{1s=&@qPX~sBjfyfLZX>Oh@^Ar5WxGKh5iR^gCE42y1No}@4 zf>@MI=wx$`B~P_kWJp}S(>k3%g5}a%pAv99SD|y=rnccLS*>ke9{kizJyThU^-<5f zG+5RBcxH#YL(0ukK0l=Ww4Sv^%ashvJIB1QgiQ#c}--3P*sD{*PXbKH6iPJT&g+nNlVdS_O8RCB5uNA-5h&ovw0 z@H$JN;Bj((mAU!@JCmv%HKum$W+gLq=j`AVzg5x&5X9PkmOuWZHyj~UIQe!z?chm< z3)u&H0XtP(XY9w%@6D@F3Cy;u=}CMa$<0LL6Tg=)tT>8|v}zVN_1ufMtbDh9exuMX|D^0>kqJAo{ss+p`*}&&@eAzY-LjeG4|0WR10$o19@5;DK6++VUdO(8 z&6854u#hSeWs%Sw1L6{0;rzMop;v$WLKz6%Hs(w2JLhvQ{M1j$@@#Ri5P2!`qvP$p zn;+f_vzuH|tb6PO@KIy9;5A$kJDod@oebQ~;ZX+n@CJK{?Cv?xbj91`@v~)M#oX~* zTvpFHq8fwX_tIt8$@-+Q6e}~Jf*cAK7S%l>TOYN^TSL+wK zedKA8W9C`>b9c%tlKnlF&=%DbJAqwM+_20a;C#B4r-fLF7d{rfd>6Tp8CxH1RG)Y` zRy9u2>8G+A2=F_k@;WDDUi|L(leDc)HK(%orMOBdbVzt5SK^X?s*PwTm<%|xf=sXvF)72yISm9x!#X? z3627HaBYh`dHpWK)p)Gr>U86dm@9C60?vyUz!|y^)XfRLe@*sdjv9vVy_q8DSl*Aw=UBU z6aIbo*bq%hNhaT)>lMzHER+~yH!3c>>z6C6#nw&4rEYOZzIka@hQLOVYs^1;dof!-an0hVjBZJ^nj@qU3oz-{Mxy6*BY%kr3T>8^2Nd^w461!SF@yGkT zrw)QIyq?v4DnlDl6qgq4Ym#|UJ4&WbtbKr7X5gJVZc|&edh*ZN8WX&ARaldDMI~7> zidARVsKPjav`DatB%Pzv%_m@p((T*0(tGaPkz<=0vXily?%rs!Zc1Ks&z@g1UjSnd z=Six=_FjychnTyY<<+&ZjpkFWmIp!9w`%!y@ce|Cp=OkvY^qwaVl7xwGtIWW4a-9p zB2EUu*!cKY4{bI|ig=eW11G*4>5-+O2$(eoj^W1?iCMTCuh$0!%1WJXb;!dy``B(i zaJ+k?On_J)ckFdt0AgTa45?XL{&Mz$CuWnGz`BmOq1A-gEWCBtWT^wEwvmgsJXqha zY8G|H`%P>5k*ZyteZe7Kbdg9V_A2Ma=Qeek@5AP6hn^_=G%b&~_nqN`pA$ECem~MQ zxSRMSlrSS}m>agvJRlN1_M{Ix@hYq8;b?Ml$brFmZ@rMz7{E=;=O1 z+9ov9>Gie^{o~}i!jEKTls}RWQE1?938)n==zWZtIo&86I?og8)z&ahDsSd7(?|Qb z;$F?r_|%Fmo7e9c9=+V#7BYir)Lp_E+P5zX-RFlcfJcuBH?etGoYqsOvTG;Jjx(0~ z@5b7DOjD9;;u;qKeD=yHrQ+35jysmP%kmQz`swC-oi7;gwmBqN4>$VvJso6ghl+{z zZKy6OLo%wIKSYE_zciVY=3wYV@O!Cp6Axl&U?`kooPJIJj7%_F6;t)}+j8r8bqe|` zZV5VPB64d-ZFJu*>lo`vKE7G8biAoSia3MnNM z{L?ke8&oZ2lL2KNzDJ>_sloGtv&yez4qGV>3 z)9!1NJf2w>s`+WkQ&&C=n0Q2{be^@uYL{OB|>{mnVzYOpjg@MKts39rK_6 z2|d^$qK`8}UnZ*ZE^rQTY;TZ9i)#F;m7v8{$h3Dd!#b~xt4Y&{bcam}MMiQ+H>4{;XM0?_FZcRk(zn&*2HNn^F8St_+`JJWLHq zH-9Jz!nPuwDK9xodz>)onLn6q6fBprP|LH15?LX^jVi(c5c$4$A}AY_ss zZ{X@;T~EpOvNrUFu39`whlHZleEQRpho;!q?-XHG#1&RoO_=fBlkQ zkBQl{z{N#98C|y-#NEjOXKYiw`%dWdsT28T?iKmh08^>pVQ8ho_{^PO9O!c9N_vj* zrQto2Z?V3jSa$!0pZi-{*HYv%cp&#s(&HFV97Jd0jfZQNn)2t&QU=DZ9GN=1QrQOGdcmnSA@@5aZC3Hy~73b-9e@4mR2XP_oVY z@N=~4DV{m&x{*s&gB&rR?aH^$6I?s*Qv|AyGQw@;=FW z)yqM$h(A%v$b?h9$dJah896%HuksOQm(Z+%M1!{w0>&sa>6@GuQf5K38yJ(XAru43 zJaa;X5T0N$j9e|-jTooPyhu<0B`{bkTF1=R;2y|3FFX;dWBpKX{A4Sq2LT{COt-6f zV^l|IbUwvrR5ZC(eNf(}#WY{Es(7HzeTmrnDPBB%6k4IxWfKM?X3G``IYei(Bt|?% zNpPW3-DWerNx#){x{`>Yv5j{yQnvDu0I?7r6uqr!(r;XBAbfwTB=xgHInm?rmkwbIfI(|OMb z)eoUyF=3k3%kXd^W@9yJ{t)c$J0OsiZQBu?^Y}yXP}toj>tMJNk!%{buI`_ZVwD4~ zzN&lnX0y;EPgSxQfng=$vh>3KfV?be zgeyM>CU_!sod>b8s(hhs1#R)DRW-w5(g?sy{ft_{GxkbPq{>sRix3pAdk@6_p1s3N4%!NFN%n68rNq<^>Bnaknc45^89M$ zGHg}qzL{nrNhngV<)6NLuM2ef2appL!Nc#Xp;5#d+Ln1f0p+fy|BF207%jZOCOCZ% z1}+<__-E`vi>b>g8dP;Uf1osRu5MkHM2h=!04cqM#;K)xoUhC9`BhP0kaP0DU~B1f zFXUV6E2NCNY;GSjl7en6fZ(NNutmy3MotuBetd;EnyBRGj=gPg89tVpHDJN>CQ;cY z!IO8;^37<6I=3ouu1whsm}s1nWF{mK9tu1wHx0gj==f_@#CpKKTMn@`DjnRB22fDn z2XRv7xZ<&u3+zCF1%U%>En*#M5{JGnMbeBaJ9efr4VWz)X+zpMSNt~SdYnP+kgDm} z$<1-jbt6Py5p;=AZP@d(oJQl^Qb$A8xs8Z(&y{)9_K++C7b*u*X1r+v!u+vqx-#g{dy-ZB?m#KQ^=`&dq34NuApcd20kvm^iNB_r+-cZ=e`B zhU(q}T&+h6eX@(rh;MO)PE&r|Xb!ml9JA#81x zEJMw|=R2n9u5}^CL|XttmR=E2E86Ytth>w3`d!-plkfZ5!e>bq0?t^Z315ACJKmjw zuLLp+u14Ay4n{mJ%SbaDEQlrpp(}Q68@&{-pl_c=-ZbBLC-25{j(2S~h{W<8gT45fCc+5Oy~enD8XJua8p3U!e}3ur&R^Hi zK+-|_+MPr}D$#C19E!FIa`qyi8|nWNPzQyn;M2oDZsHwpY+r!deLJG)A$g1{6Fh7z z%Ea-5q!CjzaAwNUIP=Gd^Ul4x^_kc4R`?<)SCjZn=HV&h3A*A*#IcpvN2Tx*i7Awo z%ydWhR7161O0Eq3<()8P`2*;9ue!ER<#yKIbQyt1T+F)oqimY8WL2gpJsCWIy+2kU zvo>13hnRj+%I=)O?T&P4>E;P^A?am_;L>O&Y;k`t-uwB+dlL29H-JufQj6N<4S>ha z6-=j9D;eV)@RURj{5_M6b_N6C0IB2IG7~;M(Rn}4{O+HE+m}Eg^T5>!TGNxviJb7Y8ooW*{siYk~$&>x;|ZK;>(k=FC-XgP3j1M zv!r`;Mi-5%6!9jf$rPon>Eq+bL%Zp2{qdwqSV$UZx;q9Qgffe!i0-+qE?YG zSp*HBm$7g3>M^8&(Z^1t|4h;u{SOCxQaG9W_Zs8ZHyYGUck)I4KR+7#9|G8dQQ+m5 zBD&K$oO72fjMEEb%3hYo0RhZ`2C6?7nApKDeKZd)C5?P629$S#@-e3?0z@;(-HvA_ zyw6Kxmf^O-Ba=fSF#G8gETkVT(L1COsx;n@(%yQ?zj|Pd0Kg=pEs_mH$TCa%cbP3> z0{YfM?qzW8Q>Z!?AqI?sfV-8YEJ z0uc}}1Nqx8RU-SPsPPkslY#u7zq-VISx^iO38yi06|Ou+41eKYM~tP}HoPJ=@{0fY zt4l?uf?`^LdM}U|{ZKDLk)lln{2i{B?ieza`cFUM1Tx<%eB72)nh_vqpo)bX2Pp#Uhxho{Z1yTfRgknuSa(ldM{q;$SS4eh2J475W?P3YmaY%&zq)DbE7l!A700 z%0!qp!^ORGD{qZ^)#S^#q(3WtnQ3i!TwED9I{o0sa4nLuz;gI&U6Zzi)R_1^d!(Oy z0Jvhi)V_x^VNo5PY)6#z7}=Y4Z&XDTW#;#;_d?d>^_SnJjVWvn&)VrF06$!aySX9@ zUkk!rBevrvrIb&z#<+8l9Ko1>3zKkwxAic4(+cjjYw+Z(p7)xC^nu$nI(NH4oXj~~ z&i{_XzhvD=NubBX&IH%nknX}=U>raCoilf|4VLH%hV2#38$G0ZM=0Xx=Vf!0+b6c~ zSbn@y_l!+sNe6f2X$-y$P7f>wZ_-%Mtc|*6hI#Ue{lqia5nX?-MO*sV@Kd2Z0E`bI zV}Yxb%JPjGeNG|~vXq8LeK-=O!vs%DAF?jT)#p21u>TS)N!aUxBfNBEbfg2`hjJOc zBl8-n1O#(AUogt|H>-AqG!Y)T%l~558oXQPg(r%a-Gla z#(YfK9bq2$u;HYB>r>+@#fL7b4F4Pt_rirksmBNnXu3 z7acMC7c?T43#$-H@)*!Ir{#L-$VaO zGE`+@I^ogw5%^lBZhpa@E|37oNV}XP)Uyk;*{)=aP@#4S>Ss?YP3a#fK61uCf$S|s zd7j3kwLkGEthi?(Z$qmu0F50zdCPGMEE04W^*5RqfnvLcMe&dr=c5vm)!KoL11iwQ z7pkS{p{2bc@K+l14npG8h)CH2`fJ7wGGN$CQK8?9%h&dovaT4-1gJw~-}iHK=*(ZQcsnp24}3qrUWU>`0%KHsz~05pUB$0+BJ2pf{`O~WaTC#kXmSx{k63TZZpSi z0$eH$X%hKAl2H5Gt1gTJoJ0(z-`yg~1UDwoLSRCArqWl>t@rva@?EUYDFPjr1ETlP zqqe|>P5>>36n`(KPaKe^%G7_?L!Tp`=f`i=d|q--jg!36ZsW$QCp0**)h?J7-{u~0 z9tz@D5G8Vbx1VY;CSEj4`C#jk)H`cmR%PzcZ>^tmPs+{IdikO##>u~GF)qP=#fwqE zy=1)zg-JvWLL5O+32K$3iJMv-hpafJIF#o@RQle~gFG)wV;myYnUNw{4#I;_iHeeH zo|})R501Gq#`53KF{sI8(f?=wwAk)^fPhU!UfouPXx}^}>s9sIh##z*IY@Z`B#+24 zTupMf&W0kHt!gY!)|;*F?B{9XQocfW!|q7!14sd_zoAI4q6mUzUm|3^DJusmZ~E1z zZK6?||E9S1v8^F7u2Gq_=W@A!9%nM|p4bOAOBOJ&2mWg5Cx#w43v(9nQc(%_T_c}*(UCNtg@1e za`%CKgd7;rldxf}cw2lv6nHP;2606SqQ2Hr1d4p`lx6c$ok9#}US+vgF?72bVVu`h zrqXo$_Lx_9wtjrE?e{?=;Uc+7vQsZMLM{0cTm zZg~%@At3gsXTr^~^it|-q#5;6%rW=4S2N$A-9A2&a$1eP!P)I0UB6o3zAN~a2(!6~`paL?_?Fp<>$_|EOj zyL&F&f@wKpKmxBS72R69;y0pM^$KDM3IztG*TW$IpI8tvtPE95(^59eE9$hb)WDcnCPDiuj?Hg*CZp*h(|vg%|w*z-|#$m z1!)#lNtHDk&ql&7xrZNTPELuQ%eHQ5E>WDK&d+hIvmHdo?bk&e9(^gkn+w~Z*~}x@ z8NUx6c@CR6*C*90YrTS`*+*~hl2!kP=dD<5BWq~Hz?IAUCSQj-!Et`Y>Y2t92(^1V z7*p}EBbiP0eTr@1{P8|Y`SW-6@{W)V38N4Z@gO!Ur~fAnc@%|}73rHv|93X)GI4Kc zmw;El)TV+(iHw7J`Bza2H_Kp5(GKJz`;MEMy;s|ZBWensY4@Md^5S5L~MkkkneAx_QG!J(5Q9kr%{jh>xF0Q)^AZqb)P7N6zYDH@~$~XRZOIUla>mjW;p&HH|O35*y1@2 z)jaHyq%Bfz(TB<|3{hkJT*IwL3?3OxZn=y}Io^2`gTj1Y%W9 zAe6lAN=Z%0PoF}F7n*2Vjg&IN-N2WKHYdpA(PWqPTMT-RzgvK6LwRZ)$nJX6@Dv8e z3%Q=n?<>=yM04h!(>DZ8yyvD_>!%{|)yB0Lg4)SKIrP)#bu&enR%m8L+`0|BSZ?wKex`cTJDS7VN<=lB}aO$pgX!L zOwh~g9)yF0a$Y}Cf_)zK@zX#@!WL~DL*A#e$HqUzXw@X3jx>zo>qkC}^?oKxadUQ1 zErgZPGqaLw(?KrHx>2~Kdx~6K=mlXGKlb*C$7iSr)eY}+v)WllqFDQltRNi4LK%%c zujj)tFYG8G01m@fMeDpF7W$%(pB{gLp?cAVeLP9X)Z?1? zr$`qb4A0}E*K(}q1bEKgzkg5XwNw0KzDGzYz+~lNkEOd#culkbX|ySvC@R8_`R*HnW^8nwG^h zEkqnVZ-qAi2ut`&P=%*f`t&!6?)#1Sk$W#6uztBwfj@7pt|l)Txm(Y#M|jQrOyX%m zq3nANvd`FP36z`A)OZr_@^g5{nw(3CBlVCaB4|z|P$w7{sVallNuv{{a>~m@xeIaK zT)uyY^O{WoF_vFo<^}4TG+H->%Dt}4Q|F9fF9!vy#_pC>R<^gqZWJT&1PUW5WY0@` zk+^qG{q+4v%#-acGr}k4?xlwYqNDsk-6l+rANLz!CM8ceok?zvw^NdAbBf>3o}nE{ zc*k48kN-n$Av9PSY(e!~OSjD8X&v+E$=hBBwZpU1wAakM7)~I@Mr?4#IB1QDs7Kl#?;GZYhmh1;w&TD(~{>LjCk$tbW=piv&i4L zo9cbD^<%~SK(}Tz3cW;VhaXnOjhzBVL0Z#UUfZMZM~5|)c>W?Hx~MUHe3~jhLn&WN z@Zjk=VyAeUrMTQ~dXligiU+74=Oy0Tt0r+On3E}dwtOm(l&fy@R<8S=&ILgp;<7j4 z@VjwF45icc(Yb~zXHa^iasEm;GsRFSze|-80}0JPRy^#YJ4caIjLMlT(KVpM;E2y* zxF!VZ=og#~rQC9QmlBv`L%b7;CCQHU1_*|2{T8K5C%ux+P+BAQ>AsBxjet}rFD8f# zODXpFGmSips}TVWE0HL{nU>S6yWVbEC!U~gQTDdbH}DT4qYX&R``^M?hO6(|14r`d zZg*oow``ji>+7Lc>1N}C9cIfo@w{xAp;;|AZ)iW^PIL{TJWNq#LJwH7>BTlZ^l`_{ z^`5t7!=sZFqXvOT@kzx$LkSH=!T%~Diu-b)5^f~dBCgV`lU4L;r zo5enMA*$l8zXmC%94hMMyBwCH*c&}~NggCjC8;NaRfV>4j2R!X#X`!{5vVYi_MiZQ zbmnIKn-z{Xg;rrCA@#Qjk_yymmoKczN)K_-g>f{FsMk8 zHM(N^%uHV8MRfxj?X9pq(rqWZ=c~6B@@32?l6i&$73yVQ{jMqjlk$Xc_~uphPYePr zCM#!%CyP*S`m&p!#^W+I_|Lk(rI8Don7$H}{ENr{6NqCLJMmaKol{V=kx>Pb)tC~L z0_IKU!gwE9$UPWNrT%7dNOjmqOJHcgwy=IoHW1~#^l?030o z=^dkm<;WuMP|0KJ!o(A*el4(i=lqbQnIHANgO~E&sHayRE{cit9Z4cKR@L(&xnLLR zD18dl&dWuMg+p#(pz6<9* zHy@`U5!qZk?RB1xsDn?>JMQ%1a$H(Ymp*0UWX}iv358j#%1o5V=+beXma6k}6mIju z{#M6V#0n*6l`ljZ8AvPaaP0it(ep88x5uD_eUQb&+D z(`h~RqE$6VeqQ#0Sb6%iHiWofndzCb%9y=84oPfLUYP_NEviLp9ZNTv+oRYXo}r^b zt1R0^iKc;2BbgAE5mNAtI9rt5ncM!DA0|%MNn(!X*~=}rYb-f>Px1D7K0q?Vn6RS+T>@9S3QY{~lMGD#;i(0Or? zSD5zKSx4%K6mABShgRCW*P9EAP&`wC4z+%0R_dLer^^#fwRiljOirxOJ4FuV^_&G; z#&6YS48HQ=t&P*0nFKk+RAX7^RZ%G?x-N0LySmX`8?EBlRIIjH89vnA=z`6=K7lmK zS0^3KaQfX3TS#=;kkd(N($Yzeh5;!9#CYRydxvOzbZt4`I?*$nT369Q_Xi=f%|{Qr zHreBIWJ23HQdmM`#l#!s)0t36+3BQ3L@4~`q> ze6GM=c6jc&2WKgr%_Wa$R8MA4zN#SeD^l8G{O&37$CYtu^{o9ERRb1oRHSQM|B?wi zgH&@}v-!~dg-UmjzPjjKdzCfE_#R2NO~lk+y@DFd)s6dUDN$}W2eu9Kx zo@h9hVFYyzw7ltkduct{E;j9${ZibX=eV!j&iALVn_uvpfll{CDLnc738QwOJ7N#- zoQ6Oh?cZw6s8H|H@9Omi@-y=c7AK>42ai(5*_G3u%F_;ZxV^JnQW1&nLXko zSJmQgy`vpNt_nsX4teZ-joo!bA$aI;Vu&2ASo^(5y(+KNJeeIWRG+Tt@M+ zCi-g-(SRZkjRdIqRTz?)&?70OJ+(P?6CG$Osdt|u9=&zcWco}G(@g&R*bsE@CtW2i z;8hScSTd#B^1VT4Ni}@@+cYl-36$S_b5Fx>H909Z>Z8Bf7r)@=F`@w|z!(?vWf0~; zh@+MMe$+o2MG&Wa$hxhPQ1XwC8ii_7G1@0;QmJh|i0BpJunpbc*}ndU9&}*A4{Wla zBwY7Qw}<18PErLwb$iwA|AS^b#^%Jcx7i&*M1i6HdyCWpBe#$q(w^U zQf}H^(1Ifyt+XI)drpNAc9sQ?wcx5mG;hKG91P?wAZnoc))HdxrP($TK#rX{0uX{Qtw^}XL@4yLU9&(~rHGqJXY zQ6Ke81?oz{Wx;h%;> zCya+WU$FTz716`2!6M?6grtwm>r^2~M#g2!0VD|6xw7urX0;@Q4@**r*53XKm&)(8 zhGFArInaLdApP`RJIpgf#-G&>--8KC%V1!Z1TDJx90$!h z-kiCiUGW{RAt%IoI{FcEcLRK(cb^CE{Jf$Wl8mR>A@*v62?Hs`t2XDB|Gt!p9WpU-nn&!?^cu_q_pVZx+M$}el zi(C&(W&M(nvLZ03wQ8G$I`v9r_45_5WTmajAckKrXmVKOVP5>v{QEGP)VM<>hE^); z=L}iH7~_y2g{Q$vyK_;cJ>Q|>vJu>6Hbs&PEJzg|iM-X1-$bUGUBCeH((2am=xZkg zRdki0kf}5t^NK6F+Ksb&DuU5I_;~6j$?~EaEzUF%mdqEohCBY(|VWb)z1P!Y^ z;AO{Tui{V@v=m+~z_NUhh(i)UcY?GTh#QNHhtGXx_eJJ%sOCfWeOR=8qt_WY5J^xo zuRikXV_O1g*)b{zq7~AqhP~59Azj!G90F87q4Sr=sT6E(W%L$quuwzvZ%~5Yw|{H@ zdBKXR=K?t4fi?y24wUn6HoOI2GVP^Z&Pf4e^>L-^*7S8mp!%$AM>o@ z&@apr|5fKb$dtWo<8RskHQ7zlmR`@WZh{lpkOBO$P2-~C5A;uHMzbpN5ldA;fJH#B z^ZbxuS1MamNF?`p)1=uE;_46m+WB4g-?q?pXkhgO@N?>}saD19oJP z6S$aGBnKPuz|OvHi!}M(%nqvZt6ZdENkq1!Ku;7$}o2S&Vk(jnkYlm~D=ZW^kzQIH-?HVSJ0 zzHzDmnyhv6CG@?luNA_4s6iU+fWHo<@l~atkhs?DRGi3?as?U{RPmDK%9LA+nz(CV zd-dd(kcGUqH_HUAXKPO%*La%V|;-|b? z?hDW!#!dx%h34erz#>i_4TiI1`{Es2#=eNed{lh+Ir}Qr{u4gEu+OcC8}b634qBp^ zrYE9H;igdZGbIDd+9k*=XbSM*@?2_uRl=k9g7K-&l_>ycUh&*vcNn-AZLCR9%rxK& zs8((G>6U9CdCQ=0e}IOob1bWKZMe2!abnKQNfwFjG@p^QxXmu6b!o}q_OKDlwz=&a z@efJIp&_NTUX(6)-wsKt9<^I5h>*@FOrTo%c0QhtS2anKvGfvA3*kNecS^nxanHhV z+>v4Sq1o#T6TkEEe*1JhfxPD_ja2t z9wD~CqcE9eo{vvAJzdcko*9g~md{T9;Y=~E2FS|xJe)L`Dk2lo;e0n6ckn{bl zdi52E^~Fs(#pr=Sl=DvAB%Q=^5m!MJV;nn%u zS>Kh$%GiNOxr9>yD~--E3CD?KH-r-R-W9aIkCGG=A0gH)RxO0VWWL}s$}oYUIwq`( zOczmOe97_)NADFVxX*bBk`K+Z^uA2yc{#x4?0iA^e}?VmPf|%m@#O#69{BpC^~c(` znGfG=zt5}+XMOi_DVa#ux>z%wdlEk0Et6Rm3g+I<6I{2vt=UUY3dGaB)WE^iK^Jb~ z3nr0DV~sa1WSxx_4ub(r4mx>H38o3qEZjl8uL{UYMt41iA;3cj?{V>Bzz=s%>T*(v z6p3EpLb8`*+&xsiL-`esK73yz<;Ev9(!Au*1A_$;ZkhPSKczx?ChV~*JnYZIOwa$0 z9p+JHVDtYxK;E>QE%5H8hOqzc$L3l2`OIt zol!A-t9GY202wPvYh5g=-d?KwkkdqBC1;=P9bGklG&bUKxnEq`fy%~fn0H5fnMO+G zsvY%%wN`PsP6Q63P&{%{3`fI+2FL7+A!gP1qeg z8B@86QD3{h4rvo-qhLgasd2afKDseYSAFT0eWdnCh7{kR@%kA}+}h7NZ5`LNgY!~M z?C>fVXWlJdVZzWolYW}L^$Nmlqst_A{IL18S?>Ee10jJQ&-O!7N6=-D8tLI;1Ig_5 zONa238@cj=qdiTlBXNjV@F&naA(kPypaQms?^4cMFhr^9kgH*wX$4l&O!;-0%LsNV zUZ@(d5yul=jT|z@8Mu~R*m=3Ou555?%|eagt8Pj?kMa&PCN7B4X)jnkVC{NprLi7H zoe))z1WIdSEJMs0Hl#?fG`umlul=BUtGBN0l!rGE_5xDiRJ7u1Wy3QATlK89@rbjm z{n2*}G3v4?y|h$4T7mtz#t{YqV)Tn&fRZNYNqI&aWBh5D?%PVyg&SZtrE*#V`tO{L zE*xheQ=1v)6cJ8$(@y|jB9dK_EsqSgl|Pqukb5hX zBg8t|`TZx}K1omhgxaomuK0dtNm1QR9t#0aSQ8S`LpU+~!|0;+flUt@vUu|KM)YcjE%u6RYj9Y;Y%daygee-HSv)c+)gC1J0E#g zbhh7Rk&rf&DieKKeP!a9<0)6))*TJPxo4cEF}JS6r-wRRpot@1| zO2w}kY~@vctJcAliKn5~k`$wR*77EEUSK>~`t={FJi47CSP`l)_7T24uH>%TLhV4R z7&pfO$JdS&sh@fDIyGaA&U!i>C3i?G^zA}Tc7ow_d|E%_2gUT)I)>CguEnKoVvJer zeQbGLVtJh}W;Q%zxqo@+a#bu!w~~iph%oy6z@igI!&%Jp@l~0ixHKAZ;@1VjId2^& zjhUXUewVkx>KUZ*YF~Ka=fs|R>=|d9=2`PHZ|e8;DKgi838i7-&bky|kJXl?zlup5 zZxI^Q`z{l+k=-uA;3P>554a8CXZ)_$v*%Y^jMU1E;?krtSfbtIg;$TS8oY@P!FYfD zL~Ajb)mA{m8RDPs8QuP(-7%cvsg@+U%O*FovYe)F91SnGfopu)`5#12(O>S>i{_<^ zS~1Z@lacBFY|huaTz;_oe1S+H>rba1j(OjQ#f5#K`)T+T^~9ef8nNf*qJ+mVbdg#Z z=a^?0T>C=uq20w%N=a=-eCF2^Q$xI|X7a`pU~gq+rWimG?y5Q_COM7~Y-^Ji96u3O z?@bUgv^QdrJmM^fSk27K&Ev zCi=L>te0j?R4Gy_Z!f<{*Cf^xKZ7x5lK)v?ji+_&!!z+*8RMn6?H8DZmSnmT-Jx6J z5Yg9aNtdnT7+IO%$~!n=n}PROp!J%s67-6+W(E~Ui16#8z(p@m7?8(G9O~Z9lo@(L z!$d^HsmI>AUa?B!)M~a(mpS(ND09tyzWB%e&&69mduUl}1U3Jz0~vyYTm3a3r|BX# zXgGBp#sX0)oXB3B%B|)={71Y*4kDfuagr_$jQd`{|ai2TM@Cgr!5VB6^0T9ECLKO5V## z+I-5|e}#|@(GwjFY4oG?T{6uKJYRm!ladyC^p5R*$^8`dYc*I#NUuie)0;DVdP2O& zf0|6!lwh8FDT-s%cHd?}DPLACv(2iIx==OdqAVdB7aLb;0jM-_^#_%U8_A2zU(fqp z6bESYO+Os8CeBdtmX*!ticAKdOE0P>c;qr38Y%zO+Y7m*WSBcuyft>}btsIbTMicD z9sk@%OQZar;$#wa(%laoAy4l8@QW(>mjxiu#Cbh=R(N&b`-!d3_Y~>iEalLq;7z_X z`WfTM7AX1x71Od1<+H(&$;@ixt|2!Qt5j;qIydcNEBH9&u@xwx2$WOx2O zg^5dGfndUOTtk$}Lz*uzs#@jY;ZL3a+fRebg5iID8e*wc9+rST70XVKC}pGs+N7wh zl`^Tt_r60WiFn*Oa2Dja+*1)SSm%i+NN&jSdVpu_ zFh5QEA0Z7kvn`%?{`r^x{gVt%6s+x>`DiWTu16e8$vTP)8*+o!`os4Iw2{Xb^e}Df zY~jgR)WJ3u&bKBcD+_5_#MLRn91ZnGjU+g>ZZ5)(;O))NW8s{-|CgWs16AYye0F4j z*q?I(nqQkQ&YTwn3!{vW0jV?+YArPQfU95n9~Dhu48fuQ@JIjvzwZm0n`dE*KOA|p z`(ieYYw%wo)KDeP5F>cECt!6#?8~o-t3ACMpVWpmwuk#58tqd+fyqS0boGzVAfmbR zN<^YG8TM|;gNWwAJHGp7ckcIJ5$$S+up&ec6ryohX8qFBe?>Hk0a`|<4>51RLTL50 zaxB}b1a&IPm*?79yr?G4UWkcYZ%lT5 zMw&ORIC<+bMGqizyI!Al*Z)1GKb1CeSz^+ebk?tMW8pmy>TDS~LqP*EoiRNS0}F~~ zHV7a3OviYVl=r^agDZv#0Zk{tcF_ldnQdrHTSGZ5f@b!CT5&29h<$IcYfIZ$T>x(1 z8wMLi0|F_5=tN?N7iHf&&chLq!sH%xWZ2)^CXt#xUYOAQX?KQt%XN6Zus@AnA z>WUpm>y8Eb`1Iku;bFk9Y9X%X$urFB@e|-d3-$IiDMx;<_?e~6>Tk#hvD`uFn>zA5 zw7iv!&j)tJ0R!-*W4g!$lT(Z@Vw>2ndAqO+8NA>e6rvPm|w$ z8eUCbj&>F(FyBD=z+k}aw3H(r_^lAOedmM+5vO|+9&t|<<8J}K-3Pm@w{E+Hu1Y`h zK)hW!AMRh`y^aYW?hp?+gMP0w#5-ub9S+-LdstPH=?6g&<^mn1L96Xi8{{S5L2Vc|iaW=NgVmVqJNR6hsAMQM>_^IE_|`)QbV0Aqe?Gy}pao36B{fiif$eC#BHkqxSHfmhpC!jE0> z=PR+GRfv5H?F3`Y*)>i1KnN{8iSWALF5neyCpX5;uEfCpTTU?V7F_c7kRwT+Al7V- z&~tqzmkh@rD6S}i=FtmK2%9s6Te8@Kf2^htG-j?L34gV75a|*e2u_txpJ5;zDM*=S zlVDQn1tjUigO^a)$%)p#;I)r9&J^e91Jq#*2tx{CF>Kp4K(gBdE={#Y_HZ54K5Ae= zomy6_pY(#N#_{8RwQ}fQwCQCF0dXUUQ)tYDW=r_F?sPQb?TQ77gJ%YW-iVIBQ<5qn zM8O^;S89uoA-e$Z9cTCoSQh>M7nqDkZZHGVZur`&pYeMDT{%Ind+iN`aWoSBof6k) z&ISy6e-xHcQH#|HM{6Ahuip!p7o#o6&pNla7y)cj+A)8EP4hhQjL_aexouRtX^kXlaGISR8h@VEHQ96q}1Z>cOO~)wKU3o6QD}I&bD$aKF#Cu z8cZn@tw81Y8PToX&j*p%9+G<9cm^3SoAb~KymN&7JVi8Fd9Iok4FNq>MF?FCw~V08 zj^>uTfiaWVjvQ-??M+ZL8H3APibn zQustR<}7joGT0))U5@=IlTd!`)>p+uGYU zf+Vg{qjbiE=+|IR$AMU~BMly27m260}YtE3=1& zowi+4!5aRTla7gOX|d@IF*p?j=dhEV6#OL#*R+{+UCh|%QW2h1;XVo$q^Fs8$^6xE zAh25U=a#4$AwtC;dY5VQA7+vwcXde}blKA7=FNH?qKynsYDgn;QagjggTxZG7SIgb z^2^fGTWq4pfq}obfPTe!h6H2G9I%+Gt;MUuriZH)6{b||K3+`4FkotC!>G&WiPL?* zz0<}1dX5~U&LUc1bXQlyrWl7M{9o+7`8(7P-~L}HV~H6%*@hX7r5H<*eazS^Bb6zU zJ*3b^L>P>nF+^E1mMCQjZM4|8Qc{*yq9Q7aMC$W=>FT=f`?&7w{(k>}`*{EI?%=?@ zW?swld_Kd`Y$m zQIy~MqeTk$l5$JAt{7PIwk8P0!hox-#i68jsMsP{6wiC}Xt=IF!9z?tO|d1p&@q0M z0W3R+zG>QRy36Za>%DCXog!+#Ydtgz{rlldC3ng`((G0fwj6Vf*eGew*_0xLzkGDQ zzHjXhbp0tPq8P>P>r5i>6bdcct`}Aux;1syIpF@98F$65Z#e(&K$7QD_Xo*f>uNEV zT6Z`UY^yP6*-pV~%Q=x_+pF8);G^tHu^)mI?0rU3njV%7MyK;dMVk%FHq5WtGJLS; z)(;l}Z$)bqbNNoK=~{w&Q@WZ)&lfpLPMvx;2j}qzxcnDyH?w;b47=8F_CJSwSqu+z zt6Hug*1J(6nv4_K57sCEx|Og&Ua>AK7V z&}DV7%}6|fi9Y)yt>NsL014@)bQ!wNUDEBoL*pZ#uT>c~x81scM=V-{%0jCy9khzB zwbe6gqEoL;fr*hZV$O`q+Ur|hwul-C66`dl#ad&Ntn5>#FAg0)z>zZLhorL4OsR0W zg`T0y^Y9IH{|ss;lIvf6DPfGY@9<5$ z(ks@W!W`f+}h_EPfH zPAO`QdOJDaQ~C;)XHA3}SBDXyaIXk4qe_xDUqjo~{Ff)jbK`Qa87qm0MH>c5jk>xf z0^3%MvA0-L6QE3CLELe$Lz0gc+oQ1gmtu=e4Zo{vn_m{DtE9r390Ia=oXm+q?05eA zugc1GhAo4oYwC&>c}X-9`&*z`{QIjFoZ<+fL?=1DguwGSP%bpE(~!`CnQOu2fVoAHd>VWvV+z))f-xj} zyWzudM=LXsH)bVZ@CjV(>VS%u?fGIEx@`(g{U=I(MG~lJ!XBk=$ioVTJw$6U-lnhm zk%|iaw7M8CEa+0_gxWk^o;KB4QD}a@yXypl$RmX*H4Nryr=6_&i;2BuYuW_Uc~XQP zZ)&EX~=hZd=MoS71+HfVK9yGEj-kk?;UOeW-%AVkNwO`+Br{s@-`c%zLWK{ zXEcc{%XF#Hys4VJ+UWY0Mw!IT?QKl_5^&nmKTN43b~0Ciz?VGZwD>&Dkv@o9A7 ze$1u&456p1WIJ&pU*lrd@bRa}nViYJsTh_lWbS$~!{bKk7!yX<*3%E*S@p{AIwk9x zFe{eA&y>mScf)(dG-UABLSc?-7`9SmM@?YHv}tEX`M!7p?a#BRaD|0l8SPFL;iT!bt?pcN&m}|8f)4Uno-&cP>gz2B6%W?;U-Qn~#EgJ5g+KcW z_o${;$qVbW?{N&&ni<0IDRJ9`$zN7q)?gmH?<_-(Kc!(7SV*AmrzJ2w_(kxci6NxQ z-LkGaLe5O{zIDG~a(GYWNzbL5vZk8Z1gk--^%k}rhe{6pw2V78ljkAaR8*UHjcJ>o zRmV%rSe2=59iu#ymSPZe;pT+FM8u0P{`YkKN6n=nzJ2EBaR6szJ@io%%{`}%Ln$W`A$d0)Hd z-aukym3O_LvSF{XQgaJ4yOkz0P*b^WVT=F5nqNuV+SbMgt37f=RiUiqTIHj~W=mcV zJ?YtNQuqCb|K~aMtvwm+Z^K#w%d^%jlh$9w_+3am1QmadXj*mA!b?q9WRm#^PmdAu ztb0jdd$1LpEIuR^gq-J%d&U!iIpG;pSJ7upZXR1}O6+8ll?R$`(bLO0YrKhP`kI+! z9svT+P6;{}cI`t!&6`CU8YtnKwhn1Z;5p)i5Zm*!sN%QI&yI#aD|M*Dr1%)YrOK=y zUB6^#9b&WZruESbnhu%gs+#==^_2ND!YwVNRH7gDyEQppkW9J}w}hqGd~#L0hLZ1U z>Mir=*KCu;Sp`gGvYnFE$^ijhzq;n(R^NWcge7?>p+>}0(cCF-(qu-v&yID%Io;zd z3`k*7YL3T?l&J9)cZffo)W7V~;({$&3TFw3i^DbaZ||-bK@%`0y)n zW~f?n(yQj($;tOy=OypAY8w2=9q6UzOLF-R-M}f07>`-r$o#ml9=kUsPk zHm0)FR`r=X%EJ99n@#^f4fcqt3Aj+OAUWPMBlqR4)Wb}nw(C81451S9-^IObdv#m~ zn>)rYfq560N3KEDS$S?T0$MAbt6!Czle86SEvSy*DSDn=s>Ui#<`YqO-7R)){*qN# zmAFQLVdrkOV2J^OIZFk*8}$>O;FCjZ7S2`_rT6OZ<8t1X(C62y`>k7_s_9cCmGgm_ zfwd#$mSOFG^6bZ4#pPOdWW*Oz$??AO#CWUo0TLOU-ts)JiPQ}n1*t)X*4%E2<#B6P zWw?}oKMA)9gPh<_`#OG0F$LUY)f>yWz??zqYx*hd9;L%dA^n{&&kAois3bh!t?L!7 zay1UQI&`^La}bG}KL|VE`J_-HY725PDJtA@6?@rZ&XcB(BZb?;EV~pgts-hEeHFrc z60fJVr z`GpIDx3>NYd6n~mCR{G!>5Y9&pDT^mTt4vedp%zaPL@U_)aMj4x)pOhA36W1N)Y8SMnGO@$7Hd*{oCZVfBD?M-g?4&5ig!-oMbcRUD z#a98J5*d9V+?|Ghq|Fk-`QU~6TLM%em22p9P+@&V|DnQ~&hl4Z=h>Oiw=Y$9-h!-5 zLSv8RqHC+V!c!2bH)TTouAj7auk{^E(j4JxS@@jF$9W4(?!40C$uA6U0R&h z)OV&<17xlwLY+cZ4GaFOm@`1|F*UBIvkyLl2Bxe-KTX2X=+eq8U+E5PBT3jK= zVjWcx6wCmq)3PT|9Jbs27X4cDLfU!K;W~kvOyA9_UD<9LuBT;AnA)*2)NUEHZ*t1T3CwVBKV^<;igXW6F8zV6l zW?BV2ACzbbaslVEGu6${zLZp{6ItyiqQIV#TCUj58~G6Wjg=`wl5elRJ1!ulUG~oN zk_pIs^i`;D)6WMsqV4|(yb9J4rxjA^CR7MJu%?Q+sR1KWg`T!UUelL21X}#5H&S{o7YZpB1?_$KIUV zmV)ToFHpxmzk2D0rxX>JdGX*2zKJ~m{CmhwKmMiWG*4Otdw$n|X ztN@FL7EKQ&Xom3D@4J53^zL<8J~3G-!BeuAB4pbny``^zEv|81k*@4mG~q}LS(*Ll zeKQYv!9%#bEv}8bHx3cc<7@};Gnj%$0)b3uCVBd0n`p1 z7Zehgd{TdhZ|XnZfSk{f11*HyS`**j99HlB`YfFYS3F5soShOBRK~VM9dL#&zr#?FM&u)0?{|2#hwn&)w+;FpzKiAo7(~ePAbgi5Y?q zK1R7TTj2#rZi->Q5LFLEJ~e}HkIY7ZffH!BgqZ?s=({R#l5_XBz})7ndUn@#9?;C; z5EuZVIDEogk8L|p3uAfr4sO`Dxeadi52sfjAOeXAWK!~ z0|e}dg7>vxGrmScce1Rg3524(HA*N%oLmP|QK;GTXHQjxfqmp7zPk%ZT$W*%{kod8 z45MCi`S{+7YY(MF$B`HycFWXP_~dDYfk$}+_)9^A8B{w2o8fgJ8HR=hn$|6lSgFw3 z=)fv-*vYbx4e@YbA+Y7uS!_P&zWRp%(4i(nuVcr?-&;prLfZw&dSJ+HJMjWSx?R&L zVv_fNgDj{e4KDT(P@M%p_B`4B{%3M;707eyu)E&u3M2ozhTJ9i!}$>VtnT~VqfH>x zV8mAn+a1C8espA~|L@xC%M+*0{rClefcK^i$_?SPc-u>4*zeYd>oU?XE%8d#6NJ|N zxJUqmbdf3ySCGap4aY+}C2@?{uYtAcK;Dkdqc;1mS_ymZ{*W2)1yZV|*78fBJEd=f zSlbM%Z?Om?2>Wb;psjNga^7(?eghCpT;X-{?J)Y`ksZ*)^RX}Ms&g5m<~Y}}r7b@u z6RsL*o~u|UNYkd#*`TDe*#?jn)h&e2_$uXBfl&)L25nhzyi}~P$Ikd zS24S1r*3F?68F6RQ1?f*Xu^i`hiV)fmAi`7=?;*@AfEXK5q^vp0cU1MA#=aN+5^;w z^4$<2AYWzY1W3SW{?&?kRIu|IOX{;bclq|Q88!9$&z~hw0jR9CtH_0sC0BB(jc#LQ zkHvU`7Q7B7GC_g`^Z0_Hj|{#Gbn;CNkSeXXs`~!g^(_HchX8_IUGpy}+{oGVQs+(1@!U(ow)% zvG^Km_INGD10K59ChI+vbzwf6O{8HGgOJ>jCODNP*4tQq1I;%4MWoE9VyoK{{!Sf2)MxcOXNAUL@{y5+Xhn_b+9z#|n#eYgDBZ!e zy>z1dV!o6WkGt_1+eG)0Qo^25+1gyF>q4$3BT8nKgnJO`fJ@SQm;HD{ zN`2akuW$iuSEDf`YCKXO)mSDIsKGn8>FgSWS8WDqUhYE4<@fA6_9%1#M61Dkj#$_2 zxh^fjkx91JDvwf~`y_p|2Xk5>#0NG3SC8E^ILee0dOPg~UTh7jo-1h_Q;s=1j&_yTBkGFKOnzU47~JbG+G zhG)91M}kmEW;;QUO-`4jGRtkEgg$dA_4}yk(qy@g!qp}Y;5#L+Z*J&ui0_wzB(_g=p zp}C_R?PR}vK@+NR;;SIEKL+~x@Yhg^6jC9CURyMj=97N_@<>@@)gi*({yEkDH~;!lwVZ+k4gLm4nCo?rD3AA%MdRm!$W{vjP4_zOChToCiX!`;?1`@Q^9`|Ey?aIL zw$El%)Wg%(z8My~VtUZ`pb!0rN1fR!wpxsGp-ta7&kj<;gkd#k^{TO}hoYU_;_;e! z3jLko@{-p|MX=UQDFmaP7YWu5{k32jcZABlib=Fd=^~7L&ZQID z?0m8hottL5wF6f4WR zMsg=^M?_jA&6>&<3i--!{rHuM8AqbBb$HuCk4VY>Jv?S9^*}WJwpFnvHK?tEq_(R) z3i6ioyNDuqWAO2blRJB-iHtrGm9d`7zcgx`AUP;ATcY-DihjK^^UJ2tCY)fpbmsfu z4!AGN%)^^6v0dqTwyg`zA5*nO?P-1gFiVL-TQ7Z^tc=`N&!X(lK9yY=qoyr(ZD4ieXIDV(F)vVcVbjEp7|un4=Bt#9 zUnls4Jk>tVK{RyYP=Uk}lhB1M+hkMk*`)*fZR?O9Vs)l*rwE?xk-%KG=qRXkk1ms+ ztS$Tm$xB%`&UWN0dHI`Cg@pW53klQPC{styv7MmPYIH^-rOTr+R7{8OU7C`0b$`C% zk$EJ}&~5XkrM3h9y!D3Rlfzx8!S&$g8d^|=?Rsj+lV=2Wh5x{DI)PhIRvOO1YRlR( znUv7M>*^QYWxud87|}|}&VHIfDCcCq^?aKf?eST3wppGkBCEdT%{U64Q2h8GKZ_=W zj7x`R(D!s>jIl>hGH-1s;nl7G9vZSF;2n##_+()vREo#)>Zn~7M6Nzgbr!S&;r|zFx)Bxf*<4a4CEIju+qW2}Lobnnmn^BaW9`);&F|Mxhy=*#BueTxxDN z6p`b%q=~A_$(P4+&eOR=GG$zHC{cEc-T7439M0Md#W60eSlA0AO6$OzqXHGm#F2&@bC&;xdHAd%TM;@*gvE&9 zgH&A+Ba595oPnRcs(8V5f&0Lm70Es+%m!%h@yPRpAJQLin ztvBlY19O_<+4;7}FGVo4*?tKI4yTQO2ab~6E%sT+e|7oXf2>i~&NcqR9_4E%zK#f& zed#ned29BzsQ)V#p*dm+e2>v9fBDIk0r=BePaT07%5~nG%454frk(HFNhk>Mgyq#0 zuf4t#nRNhd^VVJBe|3_Upk!+9t=Ae_6_2kr(t3O5ayTkTm3bj2o4l^ zN?x8){>aa;ZC7)*2z9e`&@KYkEq<6xF`n49`YyhzE7(v!XC&;-`-=w8vEZAx9hj1e zVGwSc8(+>OUC>$?o=>#hxEzuP{;5kLIVyI@e7=eU{D8;#=n!83a7;F%&!wP45y=Bw zdC?Nxa9>g*|HW?}K^IcQ_T~2w>-HbMdo4fVU*CNLg3r*kZ97y0Km0(!Y0OrWrk2VbT7H#f<(mdN6+;04-9!?fr?i$WYSVZlOO+7+k{eq`iamhm%L znJv@~$ii}817@Zz7uv#h@k{G!^uR^EF!cK;BnqkX)xG&`POf!NNxO5Os>=qy@Vi$220#!1Q5XLSJ;9Fhe+ztqsrBaOmJfKqRzyH$SUUy3_NgT>p8DGKr^um6d&Ug{wJJ1Ye1jJCZ zFdA!~Qkn8i@OwV+P*mz+$TuDV^gRAo5y3|=VHO^FKckIg=6buAg>5w=pG(?>{!z2g zB^EY9o&F;9jb{QZRG!lFi636;jRUMIe1M7QUWEiFSDu$uxX*nLRHWR#0@9T?FavYE2s&| zi947C@C>$qFtC9Rvzc*~w-G2sba2ipPXXeG{kX(`pM$apCOA6y@l<}o`yEJ9dd#?E zwIR|Uvc*ThR>Y4uTEWFgvfN^zI;vr-3!UR z3y7%D?kCSXDGNYFq8r^r-ZaTieDA?R%SkXjyV~e21ObiGcGm^OI#)QJml=HIo8aGz zgQ9HWsP%JsfiGun5XJZrap_Q^WMVQ>=%y4n(=-kKVzv788IH{dj)TXI+^5Yc%m_NW z{{#;raZQ;`vRxM9h+YRR{*qDb-xJY*54QwvhC|-I99ZR^bRenF{%!J%8=vl-Q@%j9 z@TmC?CYGKC#U@<3*$W886Vm5vlTU1i)YEF0A+HPJVrp9;R}p1(STyp;mo;zR{l)Rm zWfEvFi(>Ui_qkenZIu9vsu)+=bc-!bB{>X2#id;4HmJ!PEpGda78+aXQmtfdBUOJg z0$Qm^1>r24Tg6>o2-$n}y>+FuQa^!DQ0NGeJ?7o7*kZDb?f`3`_)`Tg(`7H)TWD2b zRo+PmjP#|Jmnoo9m#ErVlKj19oj z<1cxdsKp*T$y$Iro_IU2zu5!!u*Q57H9LFb9lL>~N@&)_&FdK1sb{-|FlIq{OPG#q z*%o6j=8>vd`dac@(q-UJ+k^gaQLFyRMa4)Dn)T#wgLRia(CY^Fstaw_uZl49+LWAj zW2Jpc-^QGk$Tvq5RO{3B-jZf8HN+B_NffQ76!bU@L1OWEA2c&Y6fsn50Nj>!Je9}4 zG{-9;!|2jlJhK)qum+bTQM{vOjeD2rG1x)-IbmkB2C-uju5!ubG#t-u@yt3%9;YZA z=oJq|*df{V%0J5#J9K?)Cka>$g`c((gCcm`4u)uE8?KjTDRgO8if^q5o_^nrdoEkM zUwyo2cw6;La93BadlLc>QHq`D0x9b+6s6{H@M5|^LD9o^a6XrnVQondB)BMLS*=mZ zrmCq%lxj8|Yb_L71)sk!D%K)F8+!6Li;)O{9hlKJi4BPT(5b4pw@*_^vJ&kTdVSUG z{EjPEuf^=S(skKW&z@CBzV^mbM+-8^pi42Q>;ybEC2z*w3KBkh+y~G0sOxp64a=`@ zI)Gl6aYE0%#akQTJIWI_{v*5yzNj-mCmf39$-#2kxC5LQfpjz@3Tw$PQV>327;WfjlEA3u%e+^Y0i3L~RnVxJAlEeS7trDw-iK{ieg)h%^|o=#(& z$;so}etizM8L6Fnv!Avr2(%uQ$mr*qC-d8-=L^nmc;0^P{Xefbk%S>ZQaV1llfN!9 z;T$M(Zkqg(XRSU$zSv-mND&6_Thu@19WEWdFp}QEGcgo$+q(H4^1l19iv^zxmwKr) zPg{R63&8}{a+L+$k)#H#XjFVF6$L})?wJbTJ zt87p2xx^=miX~Xr1gT1rJHyxe3LQ^U!B0K-wSM_tasB}OFxg2$B7x`qIgk?ekkZRm zEuOdJh_`I0j{mX|yUjs@ZxusR@>I+tJC;XPmV$Lk8+w#Z7z*{6iAlf5ay~P2Qgi!| z#kLgv^+(d8Wwy9sO%(*KHqvqiLcS;@G%XY_Ct2;op}n?yPrg&GOdmjRpZ|-iJ+Nin zvm!C3T`^7jfFa&z=T+mOiI*|HVse8~wAP~*5f#m{rLDB($EWAv0=8~{wiB)K%aEl0ZNTczjCqfxdmt;trpgAXf(e)SGtE6PXs zb0utgZY$|bF|q&9Y!L+vV8dhM)HXpJtIPQewu@^U=Qik^QTskH=-W4ok8L zchx9XFL8Ajf^^?C4QVUc>oXpBxW|il@RZ8!W$NnsuBK{^oKN>;uyJFVB?PNaCe&A8 zh7%RVho|Gaf0*>gD2rZB?95oUnHL?}6HSLEEr5!ALd#%-=4W8s(YVl>@7Q;ck8T;O z;+O=tV5(<&TJ$g$qtqzQJwZa*J|hr1(qm8qg|$6k4oJQ6;Q*Vv*FLn^Dnj16#)QhE zyFOVP`56X*z*Oe4Ns{4KMr4}%vwW3^qCEPUp=Rx(tnxu$XzGKz7zZoE$SpD| zE^NYmUOR)|-TmJ6uNAQWPc8ZG+2f zNSO^hYw=x^jrrtwxrW-jB2~0r@c|2L_86+$)Wr6UZMLHhfY+Vjav8cyg>=d38{Dq? zlaW7Z(g9PP(G44qSxbmMJ-C#FmNiP>$XA}e-zkBhe72SMy=}%c;d_|_ObAu3g-z>I z)V^je>%W@u>$GpUvHFlciIv;!At+|hDex{=wWXygiMV#gEtA3Yb0h}{et*)Q^`d#u z9b@7^FQ9goc_tZJGM^2qQf^Ao?2U2T2ju``;vMrz5Te%4#{$-oKD6D%2n4_ruO4T2 zQxTS_rw8`c4Uy7zlrk%&5KA6+k|(oiA&IBmIn;b1L2)%2A9~!Y%t$GsX74o-e7sgE zq5HIVX=Xe5AuiRIf=??<=rfTCbc#M2hAvmGww^1h_2E<@Ndv}wpj+i_Xs#JagkbVR z-DdYsi-y=P5_}djVmK#7*&dH$3JH4WqS?0j-Q!v;oW)5EF~zbYV&(I^R$*r}9_S8q zN*-v#CZxYLpgUr}z}TYmsdKa-`D>d&=5%F@-QB5AQu#2hHRJWoE1;d=RpoR2$`3o!LE3 zq-HcY@CE6-8I`+KEm-}@yrW4<77lg>?p2HwzeZc6(MHf1DDyVXWa-mA^d8G>_}eGAsaj@;8$OuD086~j&4(4X!{&H0A! zRZc{=sZ16G1ZqiRpsQ;B(w{2>Q#r0-;Nwhsr+f9Fb+|pArzucvQ8Nx*gzB76D!4D;Y0-BATat~ zUZ`lp-bpsWZi#u}D-*Ocgm+x45`p5L+S;tUX%Wg=7kN`6lci|w=lb7moq~5{doDx$ z2I2)?*iQZ{I9pOxzU@s7eELO`0(&DTQQpW+(FnXmW88lzzTCA!>dcv(QQz?0m$&iM zv}9a(JVE9}f|C%(ntzxQ3k?oFy6`VkA`*J`znKyZ0^Z#F*LN>3&VBvQa@>W~aR}?;3gt6p z@md%2PVCi%VWbI04bg}2IO&MgzDs0*bwC4D%vgB7C{mik@s*$ap>y&^2A^8Y0Q4RR z%fgd%K$r4GI&>ruPK5v$5)02TTh#9UoE=F}z52nU_xbL-uyl_>EC>iP;|jok!1%r^ zc^FWa{R~UDmKao$k+}XiaMEl=+RE^ONS9g@GN{L2D^g-l5u)bqx{zrRNq+lRT&*98 zPnE|_$zt{@<0eJMcSmB^H$k?V$S)9wG@ALfRoU@ZRki0onnD@F@#0%W(>h zLT;EuX|`Jeb76euHz+=We-I#KQc8r~zTIbFrCt@z^1Lifj=!5fzVCF%aKU)N^(C8; z7DIol^P4#jffGmTR<-J^-vhNL4R0U1*B=#B87Pf2L=gQNp94~i( z@DsZ}=#vdfxS}P$2(Psn+?!Id0y0v_gc<T*i0#etclVdYa`@yL1VUh@me;MSR%D#+{PkI9gMm1zR599$2QiqaNC1Vi9lT zw}~ekkPed^oX;<|0WG~q45|)dG@#~f*GpD0o1R;}5}q;xx})E&v->C8PMvi*8mE8r zo_#RV{!OI{d1_EX9#h2E09W7hiox8tW+w}Avu!Ba`+9OiZa~xG?njY*B?SFd&UtP^(A`i_#tF<43PZ^%1lzoJG)@okd0b@KD8AZ6>X@c#_q4-hpc5)N@G z_fEb=`ZI_l?j@PKeRm$(7|*;eL!<)lFugj4KV6ul^n+pbvgu4FV;0_C!Lv?5R>8o> zamH`6-HPx){5FVmt#}XlDmRNbfH){!!HFjbS6x1&$OaLVn_$%5++>IVDJ|zbvVkqz z3M8fCX#6A%)cEJiy8Kewgj}!-V7^1=qUL54Kl?8WkhKMZ`RPCq5_>>aRAik5O(Pb# zw#`VFO62k^Xqouf$7dlMEw~qIN&AC#z#~W>|KljAq*g$1!fJI1&ZJ5Z^nJJrUV$!> z&HoK#(-ynm@Z2L>4YK@?W<(2ax67g$EpOk)=nv?H7BMm8fgO=>>R;F=5GMHA@Hf&c zphD+;otlUo;2$4^t^B_UyNAF>CzX#=K?QPvhK98eA07W=ztql3TP}GKb@LOd2||k9 z+Im*??d|Z_YkkroHF&fRJ0KL)}l(!q)ZKP2Uo)4Mvrwt(#Ol7pg(){%L&+RAq!|o|pVt7oj z)dZ}5PT4AKkY#l1YT?sCku_jBjzPpZF=J4lxtfk8S**`^lahMkV538XNpLA)%iw`% zM_GCuD5LFb*0eNr|DH&MPtL|shNL9EQ>d@45;2dD>JE8iP;4RGE%C+~&QJx(G_SrC zFtQJBkT~6HEVk)D;_swsM2+jkb|EHb>7WiQMxCG3CMUKV62RS@4rzo}fu^psNH!i7 zd>i@kM;sEP6xa}4>sv5lUP}RRoFHB-u!9@|z-mjT@nyS?t9#u)GwqZ!G z$4Ya%e%aCy6EApq4OKIpX+U~OFh-r_5mp>Q?TTY#cbO{l{NGr{ZnOk zl=<%3Wg)ZGX%7qGa2?TCZV23PFsa3CFx9%ueu{v6>7Yt)f@oPzuapU6iuz51g0 zh7&kN_o4Ea4n@YfUA&^!_d#7F4&|e|j1&-g3gNwTCf>rs4jqiTo0$!Ba@33*?|i-a zHDjH}y^<9BRR*FiTg)l351l?%OieBbwL|GBPFGEgdoGcF0Tp=e zlFcjkoc1yj<1$kQk&W(Q4IF60b~bQ<3)6)}M+IWxd|83rJD|P{n&!g7VXxT!g^*2) z@SJOh^IcpN?;5<5^}hVM-AWc5dEpo3VU+4CY# zstF_GMDa8v5inZf&egr$N(&Bj(PQJtT_eA03za0fYd=Fyh5#tf{ta9ab}V|zleXZ< z{_LL{ZzfjFu6W9MYr5@^zacqF;*%w*LYu}LG)`~lidtiHN-l@M!KWYQ=4LVOHNE5H z7_Iz$Bj7j3N(dkI`X-&~r;qmEJm=K~fwnQqV3J`IvTXZxc!@=q z@D~-J*7UZd!>th)*8PhnOX;L13zbSYRb(c`8}Bz-q9XJ#bnfZ7%^%4!)yNv@#tFs~ zhu9K7_}$Y@2qLYF1Y6mkO2t-8!8V-jf>!svgxTP0>wGWf7WUlBoWJg^@Lsmc(>T>= zG-5Kwk!U&aip7dKi^0#a?`0$~zo-`;>_41k%I=R>*&vdyO{z!|H}Wp{4k~&4U9;k} z!o15m1;bii)Wg@)1$B?gwCAPf^mb zJ^<|8(L=CelD5iL6wl;mdMlVw_s$=_8Cuh2L1kW8oes;_{W;go(g?cz6d&W~tzi#~ zw-K`9Un-q$iY0h|sWa3U<1-J+9Nsf|baAyU)|e&ZxJR?;($8p#2}KlVW}*~+%2r5h zWDiQMoN#S1TFo7-oJrLK?b-4@RzW+ns2ix<8s0AJ8|)-&8Vf6(3QbNa0zLA+~xmFlvmuW`3`)At3dyQcZ|$2qdd+6|IROaC-^ z2~#-)t$1)u4O-PL_3OQD9`33>O6%qm><9#oru3g18wXlsv7MrhSK^sf#3ft${%MqD zO*hY5B9`s~_SL=C$C*BS}a>BTRHOuM(GSl(6JgANRXw(+*n1 zGt+#Z?K>|o9d<^9##Jq$aLC3Uts*9x7e1Yrd>uz+KOFkpD&JLc^1RR@{!lknS}f3< z^^GSqMdH05*0@8sqT;Za;WtS>{X}Vr-D+wyX#{S=MAY1D%mLIIstp^HAD&of9-Hj6 z3_B3yE_7gYE3ET0Uq5WVqbO|9(r&b_e0C6S0m2dW*A7n9W9}%ZC7QOBR@kNY$Ec8x zyV_nTJs^M4I+g>cn8^xena{34z2H+W+>F&ys;ihC680D!?^qRjn5MG225%bkMJ<7A zS7eP>P;2ioYoqKa482QMp6fR7?`>;%c=PR!E$T$lk6^>*@1i32Lf{a;-4T!KzLP%- zHrME5v7|)0%EoW!r#NqOb5KT1NuA+pPvw$?Mew{3W2ZNIAF2Y=1y=X9r)iIw?IX?~ z!{SN(w9uZP$$om`IRrt^In`~2q2=Sxp@2W&@ z%j}p7r|YD%uUVe)kQ|WqpYZ~`L^hrMZS&UWBZBV*45bRyl{R!-WMP~=**2fzG4|2) zgW_HBR;lqZqQ>fb&e;9XcO@}(ljzw!fSUKit>jxfJ?2uEJDo%;XU7g6b&KF@s#e>s zq_4lFqorV%QRr#hg$rUtrC^3&9p_EEO=Fq15^j~r^>*UZoa-40RwA=ex!I30mU7f^ zx^Zy{s}%#djFk@XXL3}(dvM8PHK(hIN$!&32qR6yXoT;yue!kj;(?(u-0!LjBX)+? z>w;pwP@@*OLR?F}M5zV0u21L_(M`mNtWV@*$Q3YT?c(Ovc;ti?t@F)w-~7&atgUx} z%QcdFKtpM$$TpUS4Q&%{lW>pZ%84>O9e1u)kw5@;J7G%>-E6;F)s0kQ56v!VBUjVY zB)*RGM#WBT8jeHG-dFCN*Xh;m4Ncy7;H&fNj*kG~#-GR-7|$d`W?JQIs948aMP?da z_ODSG;x^;)+$KQ3Y3F8}Z`+UN&fsguWd~$GvJ`Vu?@Ed4Paw>!cQYAcAIo83H$!wy znQbHM{DQwF(Ue`P8a!KuO@ECwdL%^&C-R}Be%p1F*^)Zx6l~xkMgcMzvH1Bg8drKc z-_RElH;Q*n?&hCy0eZhoE!VrbRdYsazFLqQ^( zI?9*xI;&;vX8JFpP<-$jdGdn=^TwKiZO>6pb`P6&FsevV&^<&8}VcRwa>CW5ph>V zkTke4vwN>%Ge1wZIRnV<*l_;VW{l^~lLfir99LIp-CMF3faxUg;AtqU--3d89`2C~ zfsbb1pSf21_qJp6Z=TaX@q%Jm6=U>o(MRxS&!PXsl+Dx2XCCXcTP&XUA2v37`dL7^ zYtePz4QBGcyH0&(eRa>v+vr&S57B=bAl1gM(2X}Bx(;yGEriQ~4DnRevC_1CSIiEp z>?jO-C%V+e@_ko&>UEJ}*C|D(3$xvr5}j)z>62fP1j4D9Si~*p^8MXY@}H25u=c{g zI(acc^wgF18@|Cg3SF^gSD|J7EF%1})mjd`PYnGF&E69~9I6xJyrM3XSpxc$P5&$i zX|a>lK4|wZw<91wi$^DoQ~wdVMP~h4B+LG@u(-uh76Qor_1)pii~lR#2@3JQP-dhF z_K%U0jMzmH4Oo$j)${h>0{kFP@UJ8F|Kk1rFW&EejQ1P=oCQjTei#U5BZx)w{NYCw5mu77`CcFZH?Wz!>~^2_&N~Hz*>D>$s&+XinKa!{klb>dNmklWV)D5EmzsfrB_7n{@`9o*X>O>r$|?f-&91J|xQ? z>-mV7(mFqar|Zh|1yuzqVtI1~jUyp33nI--$+YW_pVS|K^-zte*_As_5utcvD67O5 zJfQD;e}BLGn?eZzTruea;mNPhfHP95SD|%)N_}?iG$Q`y<|1MdGePsnGJu}}ju6Jw zY^(L4KbG+IRl)V&@?8kGt5OMR3XNA6-t4@xyyJSttWPgusoDg<>t-^5o=0NAKubUt zQLfOg`H)_Q`GpzoeQr#f{(9;+m$0qfYn}?u62H_M&Ns*F_F=me24VKt$%L$M8(~kw z=LKK*8u7-`~D=LfCSw&LqbT%H;4GbeD*p?O&n5IJp!tH>f|X9)&-DcoiS_8$AqFJ zreF3R1?%~xO;BKBY0w|vi)g(ER&&JC<^e6G1D>sqsM{le*6GA)TwKENtW-? zZkW{9i_tvNtL|~|(LpLVkVXhsaO$SG@NoY^D$fT&mvNWOoPsuW6u5y}QDw#qHwQx7uR`swTgPuK&clp*)Kxg=M}M? zz}fwr&;{CukO&v6-nKZ=AYaZ0RMQm-oC8&%KM%|kD*?a${0g4NzO+iYiEU3Q? zgW)xM5Wn)EMJAJSFcG6&=~rwluP-JD2~9UajcG5a1YKQ>T^!C>M2Ii!zB`)|=AVn_ z9RbWYP#Q_Q!5mrq2^*S}fq;(un4L_V?~t*m{-eih3X+wb;&_yT zm7X9XGMw$&fkM*$wU6D7kZ|<58!5#ymgfqvk<<0hH#sLlhDR?-RB-)fHLvQRymCWJ zZ}6}tjWvK(y>06QRO3~!ff2uT^?IQ{LRkFzYpyvju)T;?KD=kt6@usz65=}Z-fCr5 zh)~%zf_h_Vmi1+7Vp6rDnvoymaUDn_eNv0pg2}Cg8=%vX-6X+Mpjh|NgG2=~$1+9(Vda>OE<0t61l541Rom@~LVrbh6LL4*Mo5 zbYNN^Qj5XkY`kf&{5R;XSFQRS@d#=yQ?Raep9&17=Yo=9T;2fVa#EMd&jX@PT#93B zl%?S+e^UhSOOMaDD;eU~>OqU*h4nLz_Q~5cRU(bVxw_ON5*hjX>tI;^)+Ijja4Ix2_Wfg{Aaz=rCM6q zTy-7n=rt%Z&oc=wUNNgBaCMDFt*WycP2b4dRTpm*L*S9T7#{>=X#B|QVs`D~#LmTM z{C#EB>ERy3jQ2+rbJRvnz2#1f;WVsI~9iS$G>nVvh$*>P0U6^ZfI(?$g&@P~Fd9J=6 z)y`mU9Xw09QnGHmEqufDm2XizpRQyPXat;#oe8b%%_So81&+ zUp@X?Hy4upaetEhbIcES?U_$VIDjNnz9?`Xt*Eu=Y&j0BIwiAt^7SFuNhBr2qxU`& zf5@~WxuKTa5o(;Db8pi+Yb`(022=X79z%#}y&k)}W7X5R-~A6hqm`k(!1h7MF&)Z} zH_?LiKV{Zf42pX0Qt78yo~_5c^Spaah)SxM8qZ;mUC}|5(HCbqng8WI?^K6{M;n-OnicgEz zobcXdxKx-Ep8fQk(uied?Q({SKA8J+TkZ1sV4Xgh=G1N}6f4&~@TXEu(X z2QyA2l{T;n8_Dreu?MUaNP%ZHtFRvj7`frDzcW3u?AMka2!&i)i;ASO!S+VDR%jm4 z2fNT)XSMHpEpI=AWuL>=C)ryeVDU;&OBqKVwQhanCD2@NkG@h|+9gqF-o*4##93!; z6uzZwO^U7Xq9#urt@bu&FpET`A1U>8%8HY7_#69-hItA%h~hoI!A-P%nI?2%t1sP- zM_sG4ut@{hG2LhL6e zTXzVNnk?Bh!w6&S6%9(1WJ$7Q4U?#D*`*1s64Katf5+YP-p}(s@AG;8dGQCIImbCO z=gj%d?>g7@y+&ZBg;DajtJacUMK8)iwj6xQ?)Lq8#@D9lcm0KMJkoMi&XN6t!j&TG z1+*KKJL*DrpB*Z93B~2|=&83`;w9Sb>6}B1CTAI>}=~FJ>ZJ()(t@m8Z5KS2jZS zx_43XRTeWQ($T@>KGq@AGWS?kn%Zz}=E-BT_-|IU`{13DZ#VJ;>bx*Ztc2bvgLd+5 z-o9`lJyjmFx?vy9alZaNXV8>CYe!1v(oL({8^Vs6IR}4>t51qHe-Zn)FD2H7wS`?C;e!m9X5kg_a z9(3y^OEBnMg`)|+JjOq<;=L@D0T!PHL)!HYlN(L<9J5H{$~utKeB}zuZ5*olBn8Qp zLMcLJ?p=$>T)~O%b*y2&bxq~4M0tBYIG`D9Sej)?%;&lSFKrj2d$OHCz%F|->%DAJe zw$4cuS<G$7|njUbmdMpx6Y`#zg|09faE$&iz3I}=OadQ zO}LnLPBq8z&EGb_U$g4JV~0P4v~`d~n>4Ol=6a_N>fXA|=M3A!Xqbw-z=IWxyVboDb4v3uNW5FMbkHHie)6hTjm1e` zvTf&H9^D<50~Zbp)7j!N>{kokU(w?4r0h*2$M2B$`Nm&ycAhnj(FTGVQUG)%^rDvR zW~6-4#b-ime5>TLOSaqdm;_B0Jn9Cu^OmyrFVI8OeLTFEjR#{n;G0Ra%IY+%naTGK zb%CZlwX?qw`ywQysn{=~4}zU|Kz@cuKVxS;9e5G3!uQrQMI29K!^;Y=2_5FwZ#Tty zukL>~-lxgORLC(I4p1~m42@X^rk!ht(C37d+q)zBqYuOt$lEeaR`LT6w5J=4**sQ{ zj5W}0ZPgTOQsDM@NWI({#G7wsB_$EfJ}3VpOy`JTaZQGy8;ql-%bn$bq6$fDM=F)- zHRFqNK&+&)W1a~Ass|~^+6JfQ*&}cfk_|%T(NKZ9iwaD}jhd0;^pz{NOMX9U;C&@9 z9GD0B1Li|zXb5O*s)9J47fQsU=8BA;>`*;*$vxW8c;U5M%?_S3kR@XzHlAV`Kp>9 z>=zedf~viPthZaM;_x_IElZoaU#3DYKd{;GK7X;WaKq-n&3}wZI3cgqme06npXBM~ zahz>6S|cxj(}gy}6G=foSRGZrp~irMvllJGzF#HAFs7jUs5~sGPM}k*+(DSgH6qU_WLt&{vKlkE^Suay6UI1r{=D51bn|Z)wcuO%D~<2A2g~3mWjel!#cam zBkZMpRlxe$#)So`b;V@JOF3+W4GKMoR{0$rhkTrsGLxkYuZ0lIzvR|CT!tp*Nc+s= zM+$pbDe4l}P4sBmWZb{z*5@*OfTLx*(WK)t*FPMZCW&^p2Sdqa30a`zOLwZ&7IsnM zFYpu(6U-K#{WqHo>f_j^xN$fBhmMJVw{!l-y!4+@|4SJM5cZg))145B4SSs{`i}WF zdu}l{8-SPoPe5F!nN&!ElOUwVLU01&?*@$RKh43P(*O48>68TC-5&>Zpyazru;Q!6 zu*4@Jb)<&$nN&0KtBg+^a%!{@U-qANl8Mjp32>@y+QxU$3L2=2UsJ+&2Mw z`+#&9$sWp_`7&S$Fm4cfO0f8uQJOib0J$9&-=&!efEj-W%L{;$V)MpopW=U7Iubau z{`S3kBp=NDT}1M~zEbNT+5C4R{yCt7{m%E-f>IDbd;{$zM^nJLm00cgkrZ@3+H%Eeb=ku*KVZvLw7m?8oD$98b_R*d{$xcoBk)lB@&{u1vMl*f+|LNh|aEbQx*shC;&%l6SlV!6a^|>1)!oq zA@(OQ9ojfarEZ0OARyh6g7R zEAJ&Zs-FdMcDmD!jx`K$r#Qcm@ltW!H`PCrUx);NwYB|>IH3gaOMS6kH*+2{0A!J~ zLtv)GX50t3Y78hVsUiADCes+WQ1&G*#EZEEzJ2y=YctGYW~jh4Rsk=$38aDm0&wEB zLaNe7U`6TK?EV@{BlmerxSlh9!7y%N7kYA&t;QU5x~%JQ;4g`&VW^JZpMfEy4YG$VIBS~xN+smqICGwk7zh1I;o7gREkyRz@3%9-Jlp(k^8&^!Pg0OSvrs*$`4F7t; z)NB|c?k|Hffk}OA7H|Ov0&T*Jav^M_&E+d3b7Z=Net|k-(Bugqvx%dOrc%w^4ar#$ zV{erS^x$})iK(f>GJ(5nD3i1&7b%9t)B{ZLNa42M@zEcK&T~v~{^{%tIOF>hq|@vd z<_@f6Q~`sMvh~o+QHq|=nonv6h|P;Af8YC8MGA=XBqKpl^6UM;aSNGm^&mO%3`COy zhuZ}qP4*iFN|~~bBb*Opo0BJvR6UbIJr_PHEqTr?=tY`2=bB!{Qg{1Rw7_0oTL*Qf zI+oP2DyUHfeHZMrAzT=}^R)-)tO?cy=snfzg^&bg0HV#?LgXN%DGPE2COF7#TMj88 za1TbXt-oM%`}KO!Td#XTOOIlvnJZ%wr0ZqDomevQ+If{8@Gl|BG+^>{*l63y=s5^y zGzY}%=MfHC^n|GsfVlQVj@}i{C;b2z$a5HS;-%yyYBe0>yC9rsb`!E zzF`R5#~LYV3_^GRLVg5dg-P;wiw#Dqdb@t94zR5MNa2D?F@5ORxdF~nu?S5{qMs_aTP7(RnZvYc4oCRM{ zuy9HNWqR?Hh|Set<0^gq-dVl+uuDIFF0ARKd@>5|?RC=9AFSKdsA|7&Nj-dd)=6C7 zlV4>546DmY65+K3`IR|_neDrtqZ3v%sh3X@D?7@JRdYr8ZwC$HsdsJi%g1D5+&mJ- zXbkJ*M7WrbKayT{;$Z@>{xNEa;LJ#kuPN6Z<{YD~B}eOQjL!qRC1RMM&c|}+`WTeQ z4jW#vZ$Cfv#nOr#5F_)Gov{l~FHB;GnuB8-3Taak;`wc#7@=svj|saZmXzn69Q<-j zsQ``2`_k6?+!a_mM~m~*i|0y^7w*!Kj{tHeS;hZA))%o$^B+2FmvTqa6wNsTCYpGQ zk;>LLvcn7nra_5P>qY~0t~FIMQSxBe%EEL(qJ3K!OPY)UAyD_u0rJy}jol$#s&w@S z)k-NCniOYtl?uPCk%8`|nV~=->(hI2RKM9LPWEOO=5kW8UkCEEe+hg~SGIW$Q#ya- z$}ZePK3b90WM_(OEGRJIzb<3AYLj(!Yg5{SBH0f%}`rYC1C7ntcR2(BQrL%k4$xK978}o-8pr3kE$yt>x$uo)f#ZSDX1r zZ$wT>MCThv9`_$*CZxz1awk&62lI3S653iaNcAFv;(0&1)0JZncV$TGm{3c&$BHnC z3m;$RnPDvN^DAD8KiqNNoM!IdUTLv-CU|DEP*v&*ka#a} zxzqq?P&Z*E4--6mt9_irm~C%7?TL8&o_VuBe^G`=xq7BS*l(oz96{oQj{`Mr$d=k} zETL7puO@qc+l1})b~gJL`8q!cU8z_++$QpN$PuTcc1JvwYS2y*p?XWxVKj0a zt7sh!kwlHVU4oPck!FcX3|c}c7F@wjSWv(G{3y+j=IRyja@^S0ZC1^y@u3A7I`*dB z%e8?Z*zcWxKP9Ir{o@Im-#k4F*{RHbkQ8dFS3#;`6xXOQZ7WW!0A;6q-cDb1+T37m;;{jzQuGVU05k3)35Tz zaeHsiTvX~J>s!hu8|M=3xvgDEwgWzhe+gdJE|M)tX#ew?9F8cHv}CJhvEd<8t90*k z|2=#8P26+;TP4(#_>tmaro*=O_Fab*>sjGv+E=M$SYmb{`6OH+Gj{EnS8l{!lE37qyY``3?qj zh61;yDl6Pe*OF5|ax*+|nnnXA2T|+6+s#{j`Nl_-a9s&ga0i|#Y#k?}=M!AHeIsca z-Axb|E5Z)%no4HK6dCON!PaL%f{STz?^Yt}XXZC2K5J;5Cs1+gtH0E!uC|>gJ3fmc zuI=8<7WcU&Pz0^lN1zko4TO2Q9HL!rc0|&Pj1?9!7g%#yz;Fe8`txpi{PAIF$&rt1 zOFwwOJ8q0CtSA9$M3;6UQKs00!jY3tl||Pol(H|h%kh5QYbnfd5VhVs^Cuc#8SRdk zLu0yGchs2@+NJSSzo}z9UWs8MwX#dE&0RuuDFO?OPc3pq4!`W^tY12Gk@Vb`H#Ffo z=J`GOscxL}eRP!;iz26&8RipIzU`c+Q_|6=# zM|(Wz&f}@)9q#s=z3O!8_0NwI{OImag~;x?m%L8d0UzqcFW3{)+IR^hw{hDeT+E27 z2I`%FNt;eJ{9^)BiQb)VKB8MHSU6`SbG(`3CD&f3&S?&O+Ax998ec#UJg=UI{30}* z(atA-Ve@75&Q#?`=-x9gNt7@GYjcJbStzK}*|I_8Ao*LWuO2=~cCsPl+i~J>kZhju zlvSfj`QX@w{&%&O7c2x+=9qbpu-H;5F=$|(DyY;~*bd9!DP_GJEOGT%B9fTv-#0467E(n~sUK#jC^KW8d8p@@kr2+nPkn$$UtI z7k)dl8k&kcM%~>VP!n9Xw;TR_=3brU2O$f4kXu2FZr%D%n$VRH{NIyG>DPX`X zsH*e?jn_WovB(Qb7%|G0^JOJctnL#&(Jh(w^z_p2*m3`2aIsj&QQ* zDPSA>?sVb@^_+{5dh%NzI`#LQhq<_#n}jFoSPhyR51Je3-TUVql_9;+anC5G+j%)I z8Oh;GkvfzKpS78XuFv>9g3@Iqb!;DsDasjrW1n0NjF zgAHDct|N!kESwFBs#4c+_7ABa3%^w!&djK(smb_p?&yYz2leR99PW)=EOnk~iT?U4 zguVUlGN$bpWA*)~(drO(1bFIk-~wCyWa*MKJG!77R)P#^Jai@E_-r29Q9^ZhVic^0 z7=>2B_dfB=9ljwu^%f0OBsU3|-{|A>5-I1WwL%&n2aOEq?*r%A!pu{cwiGML4l_Kb zbm~DE7;4K0UL6OAP+`9!8yMO1=daHmIsumSSE7sB+;SF+PEdrN`R*okS;&t+@7lbT z9Ko@JEqJ5dIy?Z_W5geVq2jEK5UG+`jRp9oi(3bT_&1}T_@}pB`r@^5lHj`m9 zV|BsL^`DM9VTQ-+LOh{O%CQ}klfw_N&{Dvw1%5uOv%$SCe;P=GR*8c3M@69>cMy$G z(Du*;_22~_zj@kx5456!?GCUkuiPpOT2UZ+RzVJb>9W6c4zwcCgcmG(FzT}+w4w?7 h)1)Z$|JO#hSTzskPU)K35a literal 80528 zcmc$^^;;WJ*EWh3*V5uvoECSd6o(e6;qLA(fl{mlD-t|7rFbcY;_eWvxCeKFCImR) z`Ofpc-*x_h^TT8&bM4uC&ziN@TKm557;Q}zB77QrG&D3KHC4s;XlNLyYm7}?Y}6f> z1o~1mG<WDWV{)Vy)v(nVHxwXaewaLD?L#>(@x!bkbJ!c*ONz7sjtk`JyO8-QqL)a;|Fj79$^->Ey zU=3ZQatTHX2vX$Z6;v=od#atTO1ED%52l0IH}h%q$EaI`bAip;E17KTg+Q!)qja`4 z+rl6m>(-BInP^+roKsUb*>BPKpJkYi?6BuM#Rw`rqdty-VW8or^hmUL5XZtL>~hik zN^Cd3Va2Ffl#tD)+i&d-*dWg8KEN#mUZr%uTaWg83%U4B7|%}`TJ4&qgwCe#oMD%A zR7rPqq(8H52XCKWWeE9jCo>Rm`{|7R5Rxko%++6YI;`Mpr9iu4HOQi`YfJrv_S+fz z_11cY)(I0D>)FC;J&+NQS(Sjo+v>VlM23%#(6j(4>UE~5Vf)5Ny1@H&j zTI?#5sy!0~1MYVaj08sCT-M*pGk@5=B22LIU@PFJE?oWU)QRyl5yvYJUpS1HAA{SB zh%Qvf4ReJF?Q5tiDP|fbuPTQ9Yph@LvU4aG6qrNz33qTqn+^*Y$I|>F>V|EErQ1Q| zMnD*<@)|#~Q-dFUCCnc8%PHye0{Neb6h$N%Z)Qko4RHMxcoJkn_4n6oQSvtm)Inf;2pV0XlDLP!0uHiLBzvtOF zlpTxf>Wvh##0_1P>$In6+!3Z-$+)iva4{#8^>As=6yGH3v7(c`a735i6OzZtjZ^|*yYE=wY59U)z z76P4vpo5jkm}$m-Ey4r`9yT1G|H{!@R@oKi={?hM?(zMY~(|n=<3HOOmXS!q#W^QHf2>1WCGa#tPGT1WM zsW;(I%{U(UXv0<)E0JGWbyUhTAzQRuE>mgwqfXDZP_u4~-1s}Mp_qJwQNst{H(DBe zdVHqUIw$$EI^arhQM*dJAz-LuoN2)@ISJH-Sx(?GawX) zBaowZO09G?M}LfKjA*QofROT(a+-(AW5RvCkgSd}{b?~3YH)xUc{dxk z_n$y|eiXBj2Pc ztI;$C#v7!9PlPm{2%+(FgeMg*w{Qjfp?~8izYsrPEFKFbMTMSb)r5h`0hQP|3JnTh zcaG|?-tfl4&D{93V9u?7$6 zjF4?#Y-Vn{4AT#u58j4|*ogRg+qU`KMJ52H!Q+-}_uY&gnU=wF;|Uv&mdp~qqN z;>a>QqiX>STx&a4$~*U(FRfQ}LkzTp5zir&-;H1{<+6-2fq3bNLw(0lgWKLC0)yi-fsM_T0uSeNp>n-vVsNA+n!dNOeC%E+}@-A+Mp*c6r^f1JJ zul~fjbCp{7D~sfCX)cf^_oqh*>%`GO{Ow@=C0#V{6w(Q^R!)E~^G8r5^=qlQIBv4Qz!kOP9OWW=iC(ff5&({ z<)9uJ$9t#zpF#i6eHwf?;s5oQ1NDg4n`E;89k&KmQs7?DV$iV_9Dn_SSAa=Q-=e86_d4uPh;yX%42 z_Sklz4x4mv`=V=mtA4;O5dYC|_CfCK{O`byZCe--d+b68|0YNeRS|GTJ5Sy#F%d=FxB4pR zdr0yUMr66R{jDcwVc>Yq+Wj5}s|!(>>+$$PeyY9PXTv-FwlDsG4P9Hko%$f6DZc?^ zstWmlljZTWr7avBp0d!Mc!FGWu9hFIbct?Xk=| z|Jag|_irAp)MTo^5Za+gPkGkzr2g;OMhc^rO-ti6qmr34urF2viH#|DVmW!Q^4PXL zO2H7*=D9Fd6E?$5lL7lBd3#WZGSOa>bB`$b-NqAF!6TLBqPsZMYPbu2h-|y4e?cnM zvP;S7my}>SOF=26yt!cY9`Gzo)ahya6WiYl{4~=${Q+!80IW&v-G@N&-y&;q?2IreAzN!#Z_@GHwKbxA7Ja^a`CcIR}I$6=5ET_QD!CV3#J<~xcN+uQ;Vxe$(V8Td5LYdSL?2a4-AIay@b{$ z&oNA`wm&Y{_G_12jpIcptS_3wVst;Mw#m~<2|wmei+3mO>!Pe92gWOdM6Rn|z7kS} zXjObb+%kpT5ltxW9z)`bY$t{0)+D$TnhKmh`7G)st0DJ z&&y5E3&=>f=&+bc0Q-D?qDmWLtI^*e>aud@ATTqp_ic>(-iayJ@k+ZAH4U+ZwEJE6&WUJ?3L?4eF=54NkkGh6T z8F~NvWGO^cA4CZD9FtJWZJ+aYi`!dIfH|)lv=KM#Js@V=UH&XMls}ntNp>9O8(Kz% z#Zj#gSn~Ed3Ba#zJJT`KJAX(muAWYC`Q}KHNq-)ghY+cnyAuQ@w&(O6@$5-b%nQPs20h%5~ed z$U#M2{3mX&hGic|m&Wx-53q$qGm?N)H;gxDp!y>PuJT{r2MqjAc^VwBSE+(!I%HCp6eRbZrUzvy9QU5Bl;BFd+MAz2(dmK78Po~^^^{t($S*1^v5h+I^Q03 zOw+Rn(T(8NP5HzaupU7vT3*%UP*y6~*B=xY-v6sp?g6gVVp)d{O>O4^oV|(xBDufG zTASJzr)J)wY)`OPcdaDN8OYs!87plg?l(4L5_t5O%WCzWH2;CIkY1J=+#3M6yOmDu zn6d*F_O||NDVUSJKFl9N&dhcz3Y96EiIV=1vN``f1vHm@4Mz~Y;;4jwZB5*p)J^cv z|5IMw*5tn}1fHk!8kZmKX1J<}wBKVyuHjglF;|Mr=oR{3)q#ygo0g#r*P$Yx$DUHb z&4X!WIQuX>vRs<%&zojjs}A33k0Fb9z<`i*lO+&Z5`CS{S@TArEFAjHI&^m#so$O_qmWZyAyV8WA%ipa`6gH{-L{u33tp=|k)?8Xd$q9k zbs|^0G?Rcmn3J1a2x?3*vG^8wD8oe_jtC=SJSvk&bk1xu4pFpS(@pF+CJqI9kc{V> zIALFAaH;#=We33qiLy94u`r_%-^Zj@;bYqZ3H~E`_q9l!_HC__d+1(&V+^uBj6W%; z4?>JuQ6t1-8N-B3W;iyJUs?DfsS|hk-4TV{NKRL(Zyz`ij(5ydA<^x3SBtcwN+wB;%!fZ!HUg%dq>~kY}-}+D0%MbS6JUz2T%Y8w3RM| zPlDQ}D;ib;EXDg_(>HO?CH<(T`LS=lKzsQ@-0L3hZ^h1)ZOF%DZx6Roui;aN3d_Q- zDBO>B=C(8XBHt`}MS%g9xZQdZ>?$z8+m3_@c7&ij%2iWhE9J`>Y?#l~qmbK7HDvm_ zhg{2P<)%+eG{LWjWhhwoa{9wC(_MwFOgVhSR`vrhvI!{wc)A>Xy-W-1K|?11mZs{O z_#gf?SEz`Lw%5U?Q|`lmRWTlPQOL-1okpZPGMY5Prg_di78 z(%@Z57{5d|1?VFUek=ie#CHLAP9TFchcP~$TXNG2;iw)|SxvaNcT!M7qO>B&30ZuB zNrE}Qd?JhZBn~G=z-%Pj#wW9d+vl8Iv z$^<8|rbr8F?X?ebZ8m0qF9lnJPi z=GA?pq^Hx}+$$Y0b|0EXc#CjMa?oe*QAeuu59Vpv(m~IJ24wej5**UgZ0tMzR>t*9 z`=i(5>c+sGBkw$Rdti0IjuA9vba(Mf0scA0vxfFNXKudBBq0D-AQ=@Z@fAB| zlZCFkAOGFqeU?BshWr;^3T_B2*%Nr*q0shB-{y0gvClkgn+L2xsO1k%NS-@^xcm!U^l(Sc+aCJ2r8TS{i$W8a7`q?z}8QAM) zBzG)-bEgS`HFrabm@nP05y9QW>T@w-hXC%>nv6tyKmWe+grw6=4!OVUOx)I|mV`B( zbr2aqXuMO8K(6K zS{5ZV_|1wZ_m8Z-USwRq_Ba(16@YZoWah-aaBI?YDr3~?F0nvkwb^u`w(xfvIjV8V zeT`?xSHRzRqAy+A;Dtl8L@p*3-T`nQqf!~W^^EjjH3jqW-0v@bY8l$9TsGf0yOZ%= zIt(qkjK&5alDc1%x454xm&Ce@wDYTk9HVAR$rsM%+9=-UW=3v09TQ?TN1i97i4VTe z^R$f&lOa3&X-h;$U2On%d)xgkVuZ>p#Y+O)q@=yjCFip)op*282N2;I6;{Qi5N!vD zaaU%GOY4Qh+v*u#?JWW{8%3|8-Zr8w$8YBSw31Xa?j>aQDHB>jAh7sVA{ArV{io0R z*4(ls*3yAyr$PteXE+Rp@_QcK_WYQIAt}imBD|4>tA1tf@8QY$$s$zj$)ATV7*KnV zfCT#zaShxX3L76E?KX7pR%+@56CRd?-+oiw0{j`2NZw%43IRQsGUb+9c%1F7&)zMZ zF{jld=*xh?FZ1)%Ox|bIupTl9_Ukqb@uS~U>KW3`Nf`t)ZP2qpCHu`NVYd<`$wriM zRwD#)2VVjAqgpYEor=h;iB!IU33l#r`9Z5C5Wy%I;Rg5Ujk2@B?z%3xm0oZ-H-QpHD zeHRCU1(fFkIg)^`A?1ur+a)V|8p32H2cNA;?R4W7p#}zKGh4R$a3O*lqoitXK}4}m zyr0%Al;b?($cf23i@BJ#m0!^P!&_^nL)MW8tF24a#aXd_><;S0l_(=fnR8S zv6tb$Y`eTHGudjJLx8q&nDKGJK^QTz@qSaR6{{E1plafer9eF)mQK(MacF_;^_L7R z!l!h8Ve)jL8a)FE2=4kdqg>9gBt~1g#O~f8-0uDxOXWAzWoJnn{alz^%*HwHk@>PL z-uFEjkpb^Fymrqc@Q?Sj00D4=F7eHGV(&NJX*dK;$02k$5X~3wY<29M`MK3;%BG~S zJcKMyYDQ9QsL>@krSy>|r!AaM?>QZfHp^a-P-Ck~YPBVRTm!r_E7m<-&@prO6ug6! z?dERM+0VqW*`U-|`hrY!)^Sn&0QOy6&%29KIUXElctofvMqX67gW14`S-*3p!)cki zX95iLmlBHK?lA7b^3(l{)AcERkvL-)+#G__pt9gLn#6>PJ(XNUNih(nZ46W(DQ&Z7F6`!GG?~_ow|;7)Irr9~ z#a;Wd^NW7T0L$nf3%FnnTvk%4ovbqz?ay0eV7EZVAG4TeuJq9JeiGh`Rd$ z5k$Ym7Z;K@seC|{tyL+^+r8IFacuFeLRn?JsXa;Syon5U+WqvB9VS-mLON;L2P+n4 z4czTw*^ee5*{Su-ZV9wQxsHDb!X+o}%}V`-%NavZc*fj~J$#g4sEtgP%=!aosp<^; ze7>y3fKeump^>DdtOBmE^$+0K@*oKyKHLB+&(BdWzfF_d zMxg-z1++{(B*mp9I-=U0xAG%E?WJ#SU$t4KYvwEM`o+?5-VmxsxnO_kd;Z zKblO9FDqoV7bg9V+#gkj@1PH;Bv9iKKfqB{$|qSNVIHf-`_m}76!d%dgg_(sn{Ge5 z7K_YH@-5u+2=rUrJSt-yPzL_cC^re%K2r=F`b8>`cYmHzR%B~xGFEv^eeJ&Y;T%XqEW=AYSS4&Bn&LK#RhGDep{E|SJvw!vyp zQG)Y2GnraoKwK9?f^WlJdn&n4m|4r%zdl5bAApS=wp7T^-{5ic(gH_iv=AW8y6>%L z-F!ivF0LAV38!pXd$QFdRZ=sr+P^3}wG#BHV-}AtD>l}CZzmfa`y=uAI;|hJSR1=p zNmxUm&rjFi6Uqd;7I|i&{I3PYVOKzgTWawiQDYCuV5AkiR0Sr$H)%UwGQy3Mr@%nB zH%tph$Dz~KWML(e9ki0eY(AOi99SF7S3d;W`g8-5SOF^^C1gmuqZK93tPj((*%NI>B2Z^0wCmop{Uwt+xZV z_9I>Sh=b0*$gweA2vrU6LtX~H7k@y<{I(Nnn~HF&7O+Z($K0A#gzr%w7i^pMYkh8? z8Fm9Oxg{ixZRXu`I;07bQ3Z!@#Kno7m5ECU?tS#i_*DY6rpc-g#%7AY+ah>^jXfr4 zc4{5a=F>tgWDWU+p>p<%u46&mb*HFbr@7@w@br%a;nTKD+ws2FX5VsxGKhD0GKmrn zkvo7VRA_Eq+dYNDf|y&@Xq)^jD>F%3o^P>3hWgirve@J2aob$h5?`RcOwEjY8d|C1 zcM41{O!3S7d%`}a^h1vgUh5eQBd!l#RCI*nR4=LCQ|Y!$)D;(kxm~kSI8iDXs>`2Hs<`KjeOH&;X`o+ z1Dd@V)n3fTK-T>P9gaxyJ*yyB(wl#-A-YckkZI?O$6g=W76;-Ob9^&h)XTuQBN!Nj zXf5>3)Cv8dFfz(J=ySFqZ+Kua+-p_u%957w|ZcrY0gWW8vY za`3-@I6bIvTP}rIgg{_$6|5oE|K%mvJ{TyLHp*{d^xeK(0~U}Fio<&eOZ>?eU^?{h12B5As}1G zUUbP1*8tvG0Q-qtdddGh>?Km`S^bIu$7*9={(UYoV_J;Fj+@UMY9k0ZpeegIA2S_+ z$|UKo(z<_V4=Hqhx$(lsg1me0XLu}&P}P1skBVn zqQ1+QfGNje7TCorxm|djL~4`4s(E?)Wo4P)+w1$;J)6e%N0|RV_~D8s&li3Z9LlXG zWb2IWwHTOUV`0b;R5%Nt-P3x;kcI?b6mdM~+z%AwzB~ya4*2v?b&UR{Muq_Or)@ zDw*taguszrv~OxF=OUS_%kMa|{!5t{rv+h!&FLt$=gjyq{Sz#cdx(vq$r7b=%;@1e za}3n{KKt-!w1;aqJIA#Je_Av`10zBkV_ssX`nUh-l{?_JZ1F?nE$t&petS=3y+@6N z9~g*zM*k8X;!LHOf%}=qG%EGo-4ik3H;p)5`p>*)w3ks*{Lgk1)8Bz@i~UXLRg8Py zdSYakV)Ug-5Q>m-2meYzM~{oJ<1FeVMN@ZWuAw3w=S<{{WVT8Z`id&0gs`00rKE7J zN` zyVjP5E7bl=gpPYYGCLAQ8D{^z!!Q15CGl%P$M65;LNDkZcO=C2?CJl#L->f75stNv zWd0BTDf7rc%pFNfI|}X=zh&kR zd>l7W&sG!FTKffQT!b*`OE)8Yj!qiI2z z##jdqzS$0jy^4#-5BU1)mnZIHl@{fqOu-xV{Nr^4a0rBLLwXXbCl zCF}*hIdlsZ^U;p%56=-}Z3xU#Gz;KVP zkuL+R@33qb!cb0F@Zxp9k{*pzp7p(e z3gn7273-Mly^2_MD?REq{Wb0%pc~Lf%SW1@Un%Ld@ z0i+rh0vA2knAhg%Tw`=nX!+uMLc>-&z2RhK|GV+sri-nqK08w*)N3i`iQ$gyQ9qF) zkYvNw<6Y?sHpIb@dTO=Hy*ckr#Y@H_S06v}cvF-_PS+r^1Jh)(=th2E%hkJC8hnLaOF{Wfe7+ z6vk$uDd!qlRP6l#i;L)m0O0_RWmp3Ph}A>li&UZuFAHh~Q8kM%>KI?m%@oM}smmBI z%|6UnBY%e=tnxxdv6@}nk-x<_l4Me>D};@9yTnB_q#x&r@qfzoy_$Mnt*MKAyZ?c4 zNc~QjhMNRlqJg#j6yuK?h?d{Yz4mB&D-PnxqY@xgT&?q^wj)-VS7F+hy*s93nl$}` z5WW|?7n87yB&*S)AZC!%3;RuP_@dRKUtO_QR9|s^hXEh3)TV<3&)ak z%*U#6o2;7H9g%ucFT3~N1sGusGEU?6w8_s)ltcAPmM$cOFYLe#zZHf)Yy zL>FmbmBe>gh&|g?JOrjk+SXW6bczv`TSZxwVlo0+HkH0Hip^e@@#*p^0avP##z@>b zUZ_X-QQYJ|=UQF?h-ZqficA?YW1QpNep26?IG0HButAm@JrKj8V$B6LlfFl^BiQ+0 zbPmCpkMabgzc-DiG5D7ycdcXAsKtnAhXx3DgdL+ksY5n@&SwD$E2?b~;fuVS{jH1m z%@`M96dC=aM2;+-4kOlCIZQK*0E*@aX2ZE=8UL}E9VGS4>LQEb<6lW4`2NVJU?3(T z$I2#u0k^L)n2-ZQC=3lkO9@#+F`UAGZ2NpH4TVlb@2&ic1oY=c{|@e3a*wBZ*mO3d zmPEQVMy$1R7&as#sbf)yNROqnV3CU|Z3r|JrEGH1F!;My#pHsII5_Uf(0Z8YDN5BO z6ceh9q5M+$jZAm{`9N=n;VlnkP_{6_k-n?sQ_2^U>dV5~L?MEL98~92Vfu{zhn)Kv zSg{T*If}G#(s$uMAYRo%1U_psLiWt#j#zdY(zaB1Vk>@@2f7&EfpvsQ39G|?_9@9Y zaY5cJTJxeSA1{*XPu8DAyfQ|me_%pK#Te%t`ndS=Iz$rb7q=>2_Ah3ASBwE4b#*2{ zch?7b9&AI_@vY%S%@>bi4Xl6|H0MwseOf$dJ<++Y@=L~rzH<1Gs;vR|>OT`DJG$V& zIKmxi%Fj#c$nrpHEL?5y4Aisa=R-lfod4+eb%RR)`i8waJJR-5w+yx;(`0$Z zHrAPL#&5PbtTbA>#&<%0d2f{1*{yZ1MUC^c~WsPW>o zlrb|uJ(it9eUe$gAHK36`%M)9{VGM&+f9`Rr-P{yJ(ocrHkcZDSOi)68TAuMbZn6s zENJQHXA$Bw4i^divGn)>(7`{&^CyUDJi3fjGBI1KXq3yor9fZ!qTEF!wp26z_RU+4 zKUusXAVQe2J4)XrkT5?!tH;Eb_Cjxe*yqz~1R;qKhLCLGYn<0nMZL!d4BHksqNlw-c-6>@s2ni+S;)=#FAz>qQuss^kdn$Q%$OhX6#B5R7NAR|~a= z&cms6qdowh84~hK-J6F**BvJ-bl67B|2U{_4?$;JNI4>EcYgcR4W$#2pTJ?Xp-A^$ zS4Y)eQW!!GoZ|!1e4Qe4QZ#lKo-CV#u7L^yn);VTNpb^-wG0i?rAx15c_tb>clH;5 zC?{XMZH@`C1{(S3`ZH}q`pm~#GYF*Wl9c+JCdIN z8frl=)0Q*0Yl&k9#SYrA%r@U(ZoeW=_^=X0NUnRpiD_Ee;vTv4Q+Cb*=-&Iw04$&P zC{)QRjFD+QTHaAxEtuxrnHIx-6qS8S91ffQwMm)v4b z5Qk6j@eTbsE6_xRoB#JT(~`kYp(%4Y4Ff((V4m5&=^t4yMN#(K>6Y;s+M-XMhGo3Y z+lj;=ii;nd$9fpY4arJ2oidoY;cYvceALwh{C|EkAvUi-zD-_^IU)D}STfkjMJL1KM6i@yjt>vY=3)I^`lTQ8+QaBL&$=YpGOU9;gGFa zaLh@lV&Kcv(;5B}hZ%M{tV@xr$?#EP1N+^o{u43L8S!r_?NjY2rgpRwhjHoTUwS?4 zcFD5FbAuTY0g1d<<7@GabqA&Dy~=6Egsz? zOsKOpeZ4r%k}vJXY6PfnVfN3!wrF-_T2Pf1R0| zfmoEd$RtHX7FJMkmPBbCm(arL7__OR4@EVhVf5EY8>5FhC0@U5IWRtPm_dn%wzv2I z{{DR(%*$Q4r$%mP+-9t&R|n^qy}fRm83vp6gERJ|_b8>ztn}TU79R&K0|0qut%c{> zjS>q%vi_r2A(lEE4?53U<rGb?n)}5RBh-8m`03)WiNdPwr-2o3Me0VtsC3kV0EB%EMvWYx$%NR|@ zm(1^=1*;y)>Z=rTIlzEj%^CCYN9_nN1a@HhfcRVw2|o5D(y+Tdtka_Duf%2Z{6o4s z55ypfB>sjT+wk?KI6SqC_Brg57T98tChU;=tAr#~clfF9c?z2*M|B!o+csA@??)3J z4WrQyY2rDkMmL!#y>E+i4U+#y9X{QRQvct7pAA#@7BGp$Lmjl{jZw0^(Z`4>*m{SO z1hsl~Bm_(sW^%}$#cb`aaB+x7J@aE|7=%j120`na2X+o!eqtJc{0qgHHlM z)R@P!$+;Ir-;3de!)S;|v6lQ(F0nn?9SMlN=!zfIX3@EUM_ECpzB9d|+hh4vj z?9T}04$VnulgnhNEKF|~W;4$ra_u9NBUxhAhj->S?5ON+tM`n% z&K5mr$?en!>; z$Ldxee`xkli6FKRFsy#Yp!}_xrJWf!fB7j&Hd7#RJ|d){LM!D6uKueTypp44Mq0I~ zSb^zYpIn;zJI#>*?A}Kmare7a#+iH7033`tLK-UN{&3ST_bvbGQSY?d)m>&wrBE=+ zxnz^&JVYC;)1<+-?^@eSu@w;^U+Yss4~JRY!wTp^;8X+`zV7~|X*rxg^N7xiYQSB& z`Dbk3E<6t5#{i$D+q(a0G|kXO-|wFP7ItVW*E}C^P?`0}m0R0?(TavMfB6$8A9_Yc zKTKH^$KdgpS+bI~WdGjGGk$q-Rm>O6^|MHhOb;zAmkM8)PV&`?jlK9;^1$5bfJEe_ zVL_GK=0Sq+r3#rFyfa?I2s`Fi67T~$oZ>DVCAcdpznW=it8e)$5O>5bmdbeD*e~Ms z$7`k{^*Z@L@aYdsXGMbsP*n{~aQw=DMq<*!e#3)A0>E0eVQzf z(TalaR`%E*5;)|No@yS>FT_v9j@q;HVg)#G-o!9u^kRp%6Tc#dIuz9O>NN;3?=+&3C3vd+`D1-ta)082SAC;h6BV7cAVq6^j6*{h;Kxd1i|L(M1-#2;~izh@=2(OwKGm0(`n@ zN^{-$Q{rY6rK7cF9w<2_5Yx)=!1yb2?!DUrVzmggHl^f3JXxDZx;F^Fcsr`{H56tVOKbD5Sh?A

IlG||>&m()vh!j1bs%Xt$;1BU+W z)iGl9GvI77$4O39ztw3wP%$ae!I2Xpm=d6nHVmWIPs2^O{y~3B_Swk2H_|$lw||6K z$mWdo132(1(M?mySz4g*s*AF%=GEXP2gc}cq9-&Y^l6b8w60FtYq9MvA5XoYgC+OV zXS9)9IJpEi*mJwR1_z46Pj+&AP5iNQwy);Pxu)jD+lIlznk?whQ1qdOqq#IrIdiK; zqh;*WYPc~%;2lmd_AlOGY~GoEftPNFLgs%$yHlsb_EoSSszWZz1qv~8kHy;I?=p@# zDm15UV`BcS$$ZlKsfm(PS0Nhqw0vzk?{JNGzSf{81&)@O03)hmt!ZS5{+VZ^REn!F zg@{JzDt-;U?4>eiah0R$onhJAP%!I+cPVk=5JmR&U;=CNbkKU|^YTs;Q=e8FIVBD~ zzEPp)rb(j>eq{LmT=u|Ud{8TrV)E@R2p}B{RizA0`;xwF{=p<@QN)xJhu3@wj>i;`UD*M`qpSED!cE}MKWAxX zhMNhp|Am*D%&4Z2i=bldNuqRJ^KS9joY>;flqvg#^2uYo_*P+A*MaM*0~CahG!%i7zOxVV&5$mv{Vf_y)SWV^Rdn%Ho|^OH@K zbWS1?o|5`5m?U^tVR(@bUKRz`dMTk1t{;Oco8gx3gptjMzcl=hxkw~is{q_lAzao_ zBTS>}xCsCA?NlMsx%6gEVud(sToAKfZfBz4Q>c7A zt#6|*>6SJQOYFe^#4<2RCF62-8lfmF4NFqd0~DRQ>!fM1NQmQFhC(zYdZO+_KT!A+ z!<|l00=Bbs28LsL93uC(LUjsM_}pr4{G{PjU`>ynT3%Ubi^z$jVBDCYfYkM1!n@Ez z<27fR?yt90!}PMwnxS6(6|I;3M9Qu!KSL+(gZHO{k=7JzZ6lIt_H7d36O7Z)0VsaoCluRzBlE&8x zV$WbKe2Bd@j)UFkrM03luXER_9f;d5x8M0hub>JbD+CDsDXS;R<}4}FRw99$QW!45 z2Y9%yv@AX#{;Vdj|CFzcO?j+8ZBdm6;+CC@M!mxr>KQ4Fi z?#Y4J5NQ74!0gSpAknqjkTEATTSl`A7)cDbig*o|)7$yx za^<+{(g{L)$>ehH$D~fA^JVSV=HSC+w)I(>_eGx$gi;Zxtw>u%-BURe_~OO7lGyWL ztG^tCyeYA#c~UdAaFcAYqJ=Xf*gQ)gmdgD`f-(GW{ z>v1!RBR5tf4Ey%_l6d1T@8UOfOO7;OukKO5Z%MKk>%3A|r#_TDN08D* z)#eG6%Pmb0@d4#3jLO^;xw5ft75vR*8eO4XALQ* zqwWyrmj}9NDYC$pktum{*Jhfgo{d9UxN|-XvF@OGeS!I8?_IVyB?h{Gb0QM4ru%3r z(ikHpo!Ho4^k|ldTDArBP*E=667Vtopcz|CI-t##qHN<0% z$^KiC%y&QJsC$WTs!)*uc{}^T6ZaDP4{u2mKOOH8{1_0X*k&|a+FZGio=6T@{=C-g zJfVdc5wb&k{d-=rj4C}U_ye@KsM(5-Ll%`v8()CisF@V$>AhY>a9x(YktP_cGE|-n zA%x!U(y*Fz!WI<6-(M&Ys$#;!yU?0X=xC#KlG_n#S_!?d^ACFM_#tCe4Fl)79Z!$c z+`LP4W=ui?=~AD2PF-Y?S4hFEkK`Uah2pmkzrNDB_0_J4enqoxb@JA{`q*%{MW8(Q zrxfL24+ikkU8}&$KejZsG#3?z_dy4x|XLfUyyCE=>i?xHR!$I;qy(cAshe@%cPpsp}U z54Bwk7i6fL|H?Gvthhhz)THnQe$}rsstX%5%6q7nnh@YV73*wf-`cvfD>i>%EKB#S zd!QYWdj@OIOmrC>X2qJ&vQf7E+_}~1PO7uI7pnnFWS|b&?WCmy(U7{wPYOo;zFsdQ z(ZP+J*V~Etj?9$?&u@jx#B?+`QNK&Tew~{ZnddV**N4E+ZXN;GDgv+AF77vHFbZNh z>%bpuTHft;9)Ukl9;P3NJ<64i&9k8{=&zkQsGxGLDDJL`$b2=XJF8^pDl=k!pYCaF zxc8(s%tcS(=ZPp^!^o`p3_D%k9USpn((s-voVwG`wUEQ>uH(kn zUqsYmZ0KZL*0uG!>^!!ehaamW^N}4=BdP;jNvZ0 z=p==NaaqM~Q>i-rr*Mkn`#1X>9U*IWgm6C)V%qloqaeYrE`-|i-vv{`biTr6rbN+A zhbiQQ>e1eoaQ9WT@)!v&o`G!knUj&KVgG`RdgzJ1F^h~M-CD=1L&n^iVD@q)W=w|T zzgi1u-&U0;v~u|4^JE2yq<4`pbYwu9bmVM}?mXUCMDVECTEUgc`JBUA=`Y7-xDsg; z*0-FCRYl)+X)QtyOrYY~x&q6@;D8|cg+_5B*tMul&qvZq$sa{){UOeHgxD!xX`{43 zszZ2=BD1luqnk;HZ~k<=yV7!f=DKB~Cul0A|8EatNiiApYOv98)c)DmsfJhG@KU(_ z7#10`23GRau=gi2c_)rDi+JAk?V_s7fy%3ZbNfq&lQ;d!AOfMsU~Xs7REG9Bj0_&| zvmVTb{CJdzjYlFWBq}gc?%V44oZMan;d2gE>%J$0G;04kM#*yUgz;>m+}mfI^4vUc z!9DWgcT)yjXHw0^0;kM_C$ojTg^4ORGt{x=9eQm2a`F@%Tz(=Lb7k%x1b)Dq@900v ze*HPg$1v8u2yK9b@AS&Mfw^9{GQGOn1NBKaW=j%l*^4o4LFD>jX6ji>V)PkQ4Q4J7 zqG)FUj>S{lzVb(g=52RereTTYkx;S6&0W_Jx5YgaNR_js9jZTWQ7d3UKQd+R?$XD) zrLLwH2LT`+GT1-*^gT+1d}?p7J7~zM?ICgk{@kx-`9Cax(UY}4b!3te{&Qe^Vz7KC zic_Q%QyiM1o7N9ElHBcYD!Hxkp=AV`Yf%I=LNcG#t!hNIMtP(4)KJ7pHb50+Q4LhsnVni{r_T-b+VoJ-d z`J)OOb=C;xTAygjxK29@hi=KOn6=%*QZ4&ywz#Uye#%m-MgS{2^5Rn((t#R}B;eI& zrNxVy{#tN}te0_Hy}G}+@^5*Gl3x$qRh{qiz>bPdu$Akd$iywbp;2dHn#!+gJ4$0q zcb30Ghd$T4+owH1xQPbF7UIlo$2`GuoPGb=Njjy?H&8i>+fDdgwtpZ6f?33`qoC85 zR>ziK)dDC;HsG(NzpRXS{;7}uIQAy=_h+bUVs-GecpsIq20hY^`G_P!aH?W#soq&d zw}b^b0~haW+F(J7G)RwTt7Piu%G5zPSc;>CZ-T=nI$*GA*A%_sCV{q1HWsk%!zWIr z+`=)qroxVVC2FYgCxIJ=9>@N@kb=3SG2Y*|?HCWmr5y>7MTtHhq*P|-X8}eNCfpDI z*e{~4=H#zyZ>eIoIf|2($ppI{RN|lQW;fP(pbYyO%HQjwcHd@*lj5ahGNfHZv2|o! zwL1D%yXqT^u5MZ1mZ0IO9lLj;X(i6SdcnxUkxLqKZH`@B&L=d)uKtmBqn`p%iRC0Z z%Wxih|Jd5&)673Vks}qGHP<1bcw}JpF+3C5A14b8jf1d}nsw#8ef!b6nDE}q%4nuZ7rCLo*oSofp4pU&UeazP3H5Pk z#&#?a1yaw>wUQLiRiexld0a)ms9qnkw=cR1x1P>?k;?Xxy!l<@_L*c%9&4Fzk#dNf zgq4Joga@ovuI_I_h?h+)T32F1e#CWGCx&j6^fCN;qqvjB9qb*k)*5_l1OJ1$N&04` z@=`msLE1I|ZK&0_H{5@Drc1Bb{NCPzzdaOLvfbm~&!;4Im!5E0|CfN6<|tP|rQ%LG zNc_`dP30LLu)#@V?=Qy1&4H<%hoRFo)dN`p0y(hsqQpyCp}Rt+uY~6>!@c;D*eQI(AGqD~XyrxO6k?+E1 z@;B%YBd(EXl9!O|#KfbP(KS!m@n*I299OSew1f)%b@|Ep_Y+P(~DVoqW z@ao_ZxBIB;8u2)ekUvQry1@k}_#UEz_m)oFa-ZNSkT9pSia1PaVWjw9z3gZp!M*!) z65FUuoJ96^4wEurl=n!rV^W5mMt&+4_nynRtP|eZi`C4GP#%~U6tz>HA*-Q?f;y=? zcV`cwJ++CPKWw(=z4sf9V{1Zrb)%!+P& zJ2Mt5Y6)FDWPY&^QY~~jQXt%06mfaj&$80`)5D7|8?&$_Grd)EaMfv_p~Jw&Rhjk= z+7*~#rnGd+2f_#vR#JnT-AsY=g(Pha3fFgYy2sAC!mlVi1j~~0+g%h_qp03~{rls^ zepMRC^-&_ZkeW(KQS`kef5otlw}feHX&^)-_aQ{B-xgmL{86Vt9wufabGtFtrKv>T zd3gR%)>;5|^7EDblQaA4ZTj@P9yKhdnBe7kF<9qD zWFP&nqQl0Vmhy1dGDEi%kx;G^oe(Dy)qqdQb>rwjEx(ko8$}Y%(T3N{^NdG7PK%ST z8&6j0^q)gzqC{B9-{%+4n`x{k;08nXh7n9bi0}EsVGAo5T8m4!On+te2VwgQ0l86Q4Qa^bU1+8jEv}CCzswIpZ_|v8079Rp(R;0 zkWrooG*>3G!jJNvPx2I7n{^um?`jt(hB}g}Zd7n5iK5;}ki7YCA2Rqwh@BW?n5GZA zVYOM>6{Q)KKOPpb4}a3@-1!7$kx0wpc(@|%`l#_n+yN)jZ!@Fu!nnt}>p zS~p+5L5Le=+!&T9Tj$fk4#4aTByB9|3=Wag&UnZizfsq-7l9VTbN-0Ej6t!>oGtnC z?YcxZ@=y*#o5=M(ww=Aeistab23D80Hr?Xwi*f91ASDGv4Wy8r{!Qkn20h>sWk%&b-GE+lO!Q z$^Kad9Zd$ga8ch&W1hAU30OVBy7<^Qs#4e54B2-@SmWe?`FU@>uj^lSuP^#s=ltT? zq>PJ0HMSmD`1Ua98*_wrr}-k;wMrQ{ampNdFrsoH8dwZ;waYR-B%0mGdm4*T7dDYE9&0I-v?8^qat(&3}QF7W?+&xmNsfL^)$$N881(C71OM=M^m2mZH}W z`I(^vd`!j2Wsp7YKN*or&)@ngnBWWD{Pu&WHkIWM#~9XtnEUw#RbMmPmG~_+-kkzA zVGmVIWtReaqU$?iP=+_x^Ua7Ic55Xdm2dCHC$5ce4oiiWMSP~6FnH&fqCb~U;4Orl zqxkXcX>qN=82_|Hl57uMdKX$DK%dOxj9lT$cE@tV?Ds1((kD_vy-B72=g-O_OvD}> zcE=UN0}6l_wBydFnElpmVi&@6&di4CS&hvL^U{u`2gTMhu1pykKqboLfK&EWGki3m zGrq#piMrtOf@xGjmp&s`=Y&D1BY;C(aaXPV5Rip1wwC-tu{6v*9Zo7B{O@a(t;?|-7vc(ACVRNWSKH39VN(2`#m62JVW44esnAbq^3i|7~d^j zEYSG=IM1DUglCcpI|!q5YCR*1jwi|QBqqpTde8#&QSfEZmrjE?&F%=>mQEnuDfCIM z?J&WrN^s*pu;%zwi-G0gLEh#;*?u$B;TM(Qvpv;#ZpYTAo^{J`=Ue6R)*k+;cx_sE zVc4oce)qja@SsCLy6&><^0B{p8yZwFq@tIDRZ*||@GRiEPkSbMFtsZIHKB#^>=))= z_C|$`i3dP8DTXyAN&QZq6bO4YA_|o`io$z|Wx9N5SS9aW?ebUy9nVSSt;6s&;ako4 z{s*leL|!>)O1vClz4nE1i_*C8NiP|c*kK6`){H88IlwWtXuNOPCxWdMzR0-+CCi^; zcS8~-5w8GKUqrp;HA8eM6$$=E#MAC9e3Bk?hJb<0#E8W{PK8H1z8bNmE!jTnIT5-?#uOefV^-qCncHGsKN7(c*Njzyu zgZs8J7zxpf8^BFcmM_tzJN`uI$%Wo^iJL|$C>9uF?!|JK#!!y{V7*}W z&4#0Lt5(Y7u#D1A%lnnV%)jU7JRIb>|wu4|V zpfq40ZnzBsKUD4j7h^A`+t5Crd?0p=F=J~1cJ@H%ZZgW%apqtahMj5g1L2i(UeBTE z_b5LL6Yu9XnkZ4{%)7~Oyfut7xvq607%Qm5m(L<&5KjufPLjLeIh#ak>p!2I=NfAi zAK!YUNs?zu=CHJDT^>%BEc7x{yMuL33qf2xzsa5)AWNr*gSs95B}qJD!dQ5Oe%x&Q zRZxAe7J@V?JOOF!BRMV$bZj4{K+F&*^JblPsxm`+rTvTx`((Q#6EJ>`Ne;9qjo~;` zjMKPsK!|-P5+eUN7*uTR9jLiZ9|Z(`+|%Uf+`vo3S)%{5x{Lqpz*aNO?pOPY)s?|A zKa!d{USN?PO*D;G6qxcO6j5+gsx!`R}4N}g)B)p zzwCkJ^*zCfgBVBFWcaw52=3rpc08=y$xm}uOEU9v9je9oCnWlPO2epDnYw8suQIGA z|L$n?-Nn_8?%y&xg<5HuJ5+?-c|YH%_O6nYm!TpwpfK`1IJVO*;Q^!-D@q}$JWdlu z6|Qoxz&Qr1VBF?X_jP!JBfisZZ-36V=;>>A;Ujx!N#OlY$)bI!F|ArjENUT&j>R1I zr+COjuTeUlI^TH0pao72FumTKni zB<)_94Z1r?3bZ#;)X?Gy0~_9mim~|}HG_@0hIA3dqr;(U*EEjNvjL!T$Ozn(%4tca zV;01Lw2IRRv*wCA2ddZ?dQu@j!DW+$gVjP$G#ggue4@5m6!U|=EK~gD9M5;h`uSYwqu<=2qVoKQl^;l+bZE&TL) zLd84UuCemuBu^p4^4z-F^?hV;1!8_xg!_xy4*?_8JPgPU(wB-FSlP7_HJNW}lWfDn z-9Q^<0(Fd&hDv>;9sRNyZlEoiSup~V;KlQhPpRRQS40D;gBgISH+SgaGXO4n%rQjP zb+n>j%2_g8|KZMMr=lf0D;7AfyEIOmkqb}h(8aot4_aOAQ>k`J%_v8^eLZpN@T$?A3F3^C*wVGoM-kjT;yD zo89sh1d}dsjl^{%(h;?mN>?gxMLCYXm1O`y{QXxv4@blp6ZrIH6Hz&8{i0++c2OJI zdeD25D={5GeOMmT)okORJhbhfA8@TP2>qlDL6zoc$35e_itm8pJa0R(nGDn;aUgNI z9N8O@TCtEMI8=~2vGIGF%Rn=cmi>YGj?BF>MM`aM;EfVbsjd0(eD5}0Uels0bq7ne z$E_71lq;uq6Oc(GIfU(Fuoh5dLt%X}tUuyJsORSgChA)0ko#e4HstLe>f`0Fx(mpi z_Rnp$WW5wUZ5ojH)&6M5)VML!X;D(zDrhyD6g-=`Qx`cgU1kWfQSMm04TQ`5)bstc ze7XKz{I&-A;_E)y``UBR$kTfD4@)*rOtANj;#uY}Js|1V8w>)nnxmfH8qr;4A3qUT z;$2zKL>wooHN3uwhg)9k!ofH}r(i1F9La8aRcn*I^HlSQH{PSpQ$Oa7$b+u>iZLDH zzGs3`VNlR>p*T*x1~#wk=OlC}Ab6%n7SJN~EoJ*8!9dZ2pBC#w2_V;RQBteA%N^3@ zU0`GmFj)zOh;QEhC!_N{E#*MYPJ-1CdzcuVpmBXigr2xop!X!#EUa8NF~ck8QC4qZ zzDC40Xg99djzk6`>PWqKm62-JZAR&R+`%Q$L-(K(stSDnN?UyU*6E<`hv$=_)6PhC z24$I0sl2RL8WGPVcKj&{J|sHx_c#(9$NwaT`3EqF2@VQ)hFBSZCnlE)MCpuJ^>#c4 z)GMLitHV+dy`nfVkwX;pBp#2IV@EaKC))bstK_#6Z0b-Z;V{TY()FUS3QyHY&wZ&Yy z;w2?%Jsv%wyH&~YX)Dg|D?!R_2`qUN2yq@l3ndS4ca8iQhv%BZ<9cKi??+cX;8Mn7zo!yG4p=G+A{a2bdc}LH|J5YM^?cD5+|F?9U zO7X3Tw)`YJ>YC|};g_*@gVpMXq-NQG2S5kMC05X_b~suru{Mk{q1NU_(oeiR+aU*r zL?6pmo++J>M4Z7qjfi(#573T{D$p@f^e|)Dz)EPei4II2mtUB~i1&~B7gExc`{7KF zOJ0sThFoJK-@1L|&85S`%6M@rM_Y@dQ!dM&i?Sfsh0%t8-uRmsJ#l*BkMaUGW$1UZ zJ!uE0hxrTIgNdEFumhY$pbS!1wW);=QO}S8KOEjYS)Q&|m3orSUk;-r9X2(ohC+e& z4ic;7m~F#Zj&q4o?ue4)v8*fYmZwR!xKcv{?en1DvxhN6AQ>O3o74WRCBNkv0 z5^bLPX>jQ!$Fu~Wl)vwlqROAZHuJI#1OPxZ+$sm@O=l1k8bVoJYGms5QKR?`HwD4!17`~FX_ zO9k+#`cffgF~GUz&T3=MDU`uBY+@ho7`N@NIoT*3JgBw0mvNT?xz5XxBs$C~%%}aO z=t1zhObE%9&gf{o9k_a50)AuFaP~=lm2G7vnN~eN3&)AW)ns_`L&M~K`@U!Ngax^RXyI+bcY~UNHian} zZxK^FX&e4=ZJ$HDP#{pIR4QOEWy_=h+0hx5H)Zc?`T|@6e0Y6Z-2}kmNy#TRrNn!ymu^7Q@32kebqky-3@B z&Sy=tzVb{=2tAITg-&H9Ujvtf!R&nz3Sj~sAu$5};)6!jg`I&MbyoB^Zvh@d-H2(} zSjR96UoCtfT)MFs6`brdogysyFnAVL2Ud6K$3-cx#Qcjg!LY@QlDfmeaXA70vfXN61Uv^}P&@ z1xc$9@RW|Dk|EL)+yXv5$4ZMC!$>F$Gc2eL>+HD3 zmE}t$#J86tkYlI_p0+(ZDhPa@Qtp}73-?hD{`lor%aO@q+8bX3<2mg^H&#=jK^H|4 zvxB`74S;)7djE5lP|U5RUMj5Ftt8qnPeZO@|a@(eXREnntph z&+!Z2z0x(uMY@5FY223Vp5Vts$yH*Q2F6b=*|XuhHvBbNn3~jVPy{D$3T*)^ zcZINO2A7n*0c*NPIPNgZKCFvqVVX25{3MJnR7&SqsZ!rm=z{R_DIupv@;^Hn;8?Xu zQnNGq^9O49Lr8u|lVHd)yR@z^h_EFn$;vVFxT@|AK}!vlK+_7d+I-1QtW{<(Qna&| z;}mRE-2l6Jmr}5*vBbgaGl;9{Rml$jp3MF5YFizqs|nL3XLem%lx@A00-TGl*lf%p zW2T7X-g#yYwe2ag&nHyyd^2UITW2_;e>v5rCjrBQ3=7+pXL@`gUVHBh`1s;GPAF?a z0_cb@@v$Sn#sm)6j%bB#>E5F!r2GJ0m->Vb0|-$)vFm0!0f`V+st8Ty?RUA)A^5V1 zIAp>gwyOr5#0mJol1xMXE6a^txQ0M_``HM8O=pTD!3IXem8wXNMpuU-vstYo+MKP} z>T0&GX7iB)QLy5OUO_oimOuz|n%{~M`dtY+pU2>WL&a?9IV(_wn`smbnRc)uPBapu zrRy>B{T@teWo|IMS-68mg*NcxU^oI?Ir_~6t-xysIdJyONeE*UBh1MJhf7F)_7wO> z!qLEh@TX;2px@dP_|p;76AiO^Gw!a1i&xSN_BBi%;BK--eZg$&9AcMImqW7 z=07Wcn$t8MxOr~{TV&|A^x;kDM2`Pp1@Xpnuw73)lw8?Q8Id&ilAzJkXQu$L4Ys0` zYqaOq5C?1~DTIkK4Q;%z#7M49h<#i+Pku?d1Mu5hBYnBAh~@OVK^&=I;dGDnM!l3c z3kX)@I}%yLYQxw%FnZgo?S#RiXQjbj`b^VZ?DaVXS4$T`BOH3BD(9xhDEd!@3@-d0 z*E#Ux3fmL7@Y_(^2nSIH&f4~gvUEjdiC`cXJBJpc=--gc0e8Fs$Lm#aVOltNB;g;; zqH`WVY8Vt$X8>|8CTzrkDqPLR4kuF~Zmx%(xAq;ubUl$wcFj92vV1FgqV8v7^?m5G zME%##g`>zj*^OmLqt$T)Xa2$Ix214$9uF);g?{l%Xlfq~~C{(q?WP7u(){_hX@!tW`qd}R~(0yC5^nHhV^jTI89%-sK7 zs_E%+L|LJ*pgf(72_?cSUIfy*`BbLf0@(Cf5ro;(8A@08Ic&Xu0c-`}JH!@oLGVB* z-1+l%qQC$Bo=*XKz_GYH_r_}|7_kb$#m^-l~#kLC0+AmqvEZhPDM(JViWme zWA9SPj2rXO!1_y%W@*ZdkN*M18>HtX$LejzFnIDXQRX(}Qib*CWeXn#8XH)ymtVj0 z!H|q!xl|#SU-NrCHnzSr_Mz#=lk3^%6{YD|ef}Y6h*?M|cI<~UlHF&^KAKsEE_*#c zhfCM&O?ShzOqJ^Tbbz4|^YGP6I@_ywYegkR76=ibsqUM;sAIbGQy<+FV;7RsrG2K& zKO2|&WZC4nRpPN}<+~rEv(Oy!`(D zaQN1z5;p2ml$;RsBVutm$Y&7FEoNl_T3nb}1KE2gG%`H@uZZgn2WaS5yxb8LQLH{&|mGAkif*@ z>j7{!FO?ZUQ$~nA@qm!-9@~F?eX0aTx04$M#zp!A4XWJ8*Iu&zgVMZ*D2{f5q|1`) z?Sk~Pq|t`6Dy`%5Ea*k;gF9&SfdM4(LOShJ0X97M+5Wf$`(n^GBp-DwcOzM~7=*qu zs!#ca`>*htCjkTHV1y~={ft-pv<#Uisx$z)D|B{hf#mR$|t}4-|!em z0cd4>q$y5O0$dl$_X_~W%R|u|qD!+khl|?oa5TUj^p}+vQYUx*dPrialy5MQJu*2a z95TYYtN%0yjj9JvCx0wz+PNEmE#AUR}Y#Q@?_d$F|`4HwMJ&K)7$Sc0Y6^ znA3>%+3oY*eFo#5j5eZW;itOkgkIY%X~SUX2M=3mFBA-6tjV>ElkbSHCnnPxR70}< zp|x_;zdSn6^1PtiC3_lnH$SEea-9grjo zuUcF$%f4~niKK-68L=klH_KWW%!kt8D*YN$_~ipX`rDsSq~F#uo!@@R$u-_`)zf_P z7maQ?`Tdmv^?J%oPR!uhGMUXmvBf&JP4!9j=gqfHfCjeH%00wiuUii`ZBl6QdG_~b zD__U0HkGpf+$@ZR&h7&<7O8(EsU*+YsM9sVDKzyfOzOM8Q9W3+N}-bv*}x5FGl<$0 zGa7^cImCQZ!eVW zvB!2p^V(9z^jr7u5FING!FX;uH_or)IT8r@mr(rAn zA=s$QmN>96e|`Jd#PZW;FmS(}(v$meK9zqxT?IPXNLjY$VinkK-4Qru3$wnu6--MG zt5Vuv`-(On2G4gh8&8^p*mM7&yX#-3DFPQ#|YI?Frt z!^^W-(YZ%>z^UBN2BTxN0VxN4?$b)oqBJZxc~FGqH3s*&_y&BJiq*;d3S?G zw{K#zoGJSqedEq}P=pp1>Go!;33(%<>&ika=4Ds0TALC`9F$4S22!S7+uf>bnGCR1x0*rqtgqcK* zWRm3Rus52nM5@t&_9u54G1D`-?r|A~;w?KX?3p8p3K}Lw(pNziFGhx+g`({BaIdT(S9^6}_us zUG8Q35XqE1(==7ekw_+!d;Rv764Oalt7%S~0-ZKo+ffs)lax*?Y~GJvO4ASS5X{as(XX(5%uh z{pSz{G(~;TsiUcNL!c(1zUpD-g#LW%N&k_Ui(QWJK^1r2j5|@LG)|9%&xF1G zdwj^VW`cY9tPFQ?;U@#M*js2Fob`+_Lu7rTNYbJ{y)w~C|QOaU$4=&&wB^R;KjnB>l_=TX1SSCj)~Bz!po!5zS^k6 z0ZqlaPoet)2tVCrhg~>Z+8-(id*U>IAHiune- z%3s4KO30|~W95TiI3bwFQa-wBD#?1B^CeJry;e;k7gK}~K})+jO#0FOU&jJTrgTQ( z!Aw{0&Ca8jD{jE?y@|#(9}ihy*9ET)xU2a??DoG2D+P;SPO6)lfxDKr-vGW_;mt3z^fN&myZ)H`QQf;*F@>n4glTDD;QaT6N>tPH z@}hW6{Qj0xbQ5f%%K(@eIk7qsnUyo{Y;%vwyX8GMC>xq^t5otTZ>`N16!l0x30`u< zMt}ic)Ho)y{Td8@jZ+4~EXM};gVCvV)tEN`j4@*t`eR?@W9G&@kV4Wz4o14gKeXE( zyCeCq9sOJxLdjbDQmuO6LFv@Pv8Y#Mc%<^j!myxP#c6Xom!3kk#LI$6wqvyKX&)Jc zWLS}I45y@X5)gLa#}-eYs5ulFl`k+998_z&epe27KbQZsLw6yC8 zw?#iM$A(1|Q2lix?xpd%D#F)Ca;3&3O|~ez&+H)~W5ln7?u_bL=cP3-)(T8Tr$6l^mz07tgaiGN1Byv2mu9vm-l8n61KLNa)-J*!)8n8mgJfCr;a$3xK z@ZA5*M>#7|k%4+dC%7wJ2hyYWBpM_j>9N3r!%i?(l$eeoGp(s*7HWs2eT90%Uo*-F+;dNHO=WC2LGQ-RV8E&5m@=w>wF1`KCWqEutt=g?0|XRVT%Qq zf^oi~rzA?Arbc&`?+TO*iQEBdVOSoX-_CiwP>tqZgHOtkBSy6I8o z%WE_n3F(XB^snCNTUZ_?>AXp3Syxwd-Qf7yr7veVdsNz(yLTVaN>CksYkVrSWK(^S z29DZ?9-Q_ASx&OcxhIYux16XZQ^2G1!SX*1Rquqz?;99Dz2frwQVko1Z%m^G?^vD@ z=rU7Uo&6l3A)&y;lg4*lyGER2)2tcJwhkDXo+N^hAMc>~osB$GSldp--IKbfo+loKN z$7z!qe|#f0DqUQa87yIFzS}RW9y0i-Px>71m|bXh?!4q%?2|nCAMXO8-&eMJnkPS{ZnKdOC?C`E!6hM^KWF9S zO^z=$H5`ktS7TWeA9Ejnz;<<9%@R^Ns)Dx|1P>g`Ujp`ztGo;3_?2VV8qz?7wR?`8 z(9Hm4!xFU-!x;HJgQRq!+OBR zy(jpXYnOKQ4QyR!#K_uwQ z$?T$b#p39l?h;>ISL3%W{T{r<)R>9JiXZVhD^3knCP7#7`!NAE$n<=WU2<^{e)>VP zWVfo~s@1c<2}9cDo7~NGc*}uS)MKRphe<`?lq=^_+3VR#3HFQ7zQttxWjddn?JH1j z3t2yZG~4nMy#xMo2dWe9{Cl5Kc)=d73Wd(T)i)YzyuO4JSe36w8p{(QX6^-Q+tpNQ zEgdAB_qkmnF1qoy1d;)i;i$r85!-m5sOJ=+Yiecw6~Lw-2YYYg{n zlROIe>^5m#Yo~6eeH@^~^-WeSgv%n3G&4%!q)h&&{o~P|u9qp_l7G_(2Omj?Y4yN9ekQj=#}oCeGZq=}dd*79S8U!06?|HI;QsoZ zL-#<_cC=tP0;S9qi`=d#^ydBQGpwk=v-W(r%gLjw<15zLL0K@qd_d??|Ki~_jb?dbt z8TyrDob##q;LYkB#;w-hslw9co3bnYDjyZka>aTvcDMgU$S; zJ>R~1N{@z-VFve=9@)vJV}jnDQFhH)MhWlnx{ZanRVyOMbnnJ2TBDB!8*7J$Kc-T8 zT(T$Jgkb%%xy>Tfg<%YO{1A2|k`xrDzm{=T{y~3U$!XAtYo|*UjB3%(M(XKiKKk~q1zZ?Uw4&B^ts?rFT)Iim)AZbaic{zj0k7+ushFy0Z;52pFhItyaAHX?FTl7i;8z?wU7F}e z0wcv=ig-S07xpnY45=*mKOx@>uokAypz0uUb*s6nV)x1D1aKL|e-|A`xGCbWA1BJW zjNm*3vDC^RLGNl^yKB?6FK@LshQ4l%hNC}tLr>O-t0?D%9j2YYl4@oWM`ivm@CtfI zJ8buYcj|vl{tiF0F3*E&h$wPS-1=Du)oK8$_JjMb{xwqI@YQV4jO)g&cH6Zrg{Mkd zEj5&&pV(TrtIURi=$eZpK$=Vja`S|omSC6wcQH@^iM2jHe7Cx9iM)X;F+DzB(f4a_-;|$&3aF?2al5Z+uM6 zJn6qY?Igr3=w5X#!T5-nF^DnI9U8);8;XX`ZsTMAeo$4KI!?YBVy3NGC{!{vn!|<& zac{ksEL@d9%>#&cr zU`gX$rdC{P8eQ31ncvqe)Zm=jOA5O=4F(OqVSVpKv8oUKqA^Yi3({C4?@^ohk$vl^ z*N`gLk-hvMZb}NOie@daNA4f!W2n)neg8}236eY?~S>sm_*%S5&-XC zBF#!?`sjm@oze_RfREpqX6?aHJBXR{33FanA)-faqNDOxTkXquMt^k^`(JSN(GFet zoo{4h1eO;Yv?zPQCJnbqcUK{HVRllhYY9T0=>q1)p6>Y14B{ebT-T8WcyNmI3MCnt zFr782&tkYVQS4KKB5>`PUQj=*wQ)(pqX4P>H>oaTyee(&v z558XoYgW1}+iS_>s&nA0Rs))KJB`I4a8do&Y?fMo$&;}X;3QYE9pHqIpu4`68-NauRPa^ zOTi~YS?Pg0->Nrsb>8e1eadll&B(iaGTQLy^Z)0+di#;LJ$>wCne|n2*D@lr)StDc zj3N8-`W=P;sa{uj$qRs+cE7;e-4R(Vp%6fTYEZANq?K-Xd#Tcw5B z=eSZ)sRRwSsb>#hv)^M3PxH?wV69}@7wTZ}4?SegkuVk)k>>q8X=}ix^-YTTT-{|& ze^+1cY5dB%UP6fa+bd_E6{TeC|MmxX2hu_Pn3mi{NwLZ2741(Cyt>~fWuWK9#J^(* zyz$^kgg^D>w`kMhnRh1b4H9~ueWd}RyZY7&b7yhc4Ws&Cs@Qg)yXp?*_;9>se^Z!D zheFTJ*EP%~ckt-$F-EadSVA4v-Zz8X2UsjvpXNXQa@X>&HZ81hS!r6VdmB9uoIuDI zBPvq}up(3W7~d6crv6v;W%((vT|ie~zKEJ`vz2{_9CWy$gWbf>u_LcQE8J6(CSN3q z^iV*&=F-9)Xm~_7`N_yOuSFym_1){G|LSxv{!ow7#R|0LW=$dgaDoFg+_ngFL$tK* zmoMo0%g<g)NquuK3Dg|_FG+a23WAA3t=O=e%hOxXfKYXfacckup1EYC){dp^I=@J$EGb(9!?@ zDl0nTW>xx~=O^JCWdI*2&Mj>>^XzJG?+6|C`n+9~@YejtQF`qY`>&xsu|7{qMMWOsNJ3n9 z%+3&$-Zhb;6o(vwEMdc9f-Z*1XLCSyyE*!-%?};VEd@YN)wk$cu;&2dv;f`Fv3`oi zwMvkT-~7J0Qkp4WnCM%acMdbj{~h}u765G6o_XpLM4$5BBSBi}VG!ClTDIWxsyDgt z;|;12wu}N0L-<=X%5VhidK3b#I#?1F0iQF&Noe!5n(zi)bPzY;cvQ}di1+{_9~4)8 z{^SN7Fkfi}m0~krXTz_y(3N1(7z@2hjz5W4Z*?a_X4)Td-JB#V|Kd3zJFg*`jlA!! z5G<0J{#Fz9xcd3yf2DF400;doU|n8~ka~JYI(>V6=cPDzKGfH*0~0?j+ylLkVFqA4 zy^WcTEW_gmbJLxaUo*E5rWxhBBT@qYDH#2q;?bH44rjGpOCU+{me1<&<%d*U*?{0$ zMx^1#^y;bIY3S5{%idjKK9wJw-FQvAF$^rM$dtfu0f)tchk~C6xS97LLvg;ft%9M` zNk>OBsX+FqeSuyMUW>4#se3*T^`z@N(^XdcoT?{VAx*f?g{Ggrecl?DxJuL1tiJFd z2#v(diMD+9{geCO*DOOXeFBzT__LdLq+JI0CcWImWRI3k*400MY_9WY09iZqH!?^A ztm!j!tT6`^kTklyWyWhSH^VK|_r{~x@FU-kvj4%_d&g7xKYrs@Br+?6Lu8aq_HnEv zk&&{uka4o*$V?I95ZSBj>{&*3X7s;gYdR@=SRSe$w_Xo7E#nF-kc&81yH zdMqhb(~Ha6Hk@C~2>vsmJ#`_dh!DZ+EM8bI&@26b0*$UF$$?O-=+d}nTyL3GcWAVn zzUe_TU3OPhfqN;MUp^^1uhY%g#%gvl4wYD+T{`^w+-a1am%Po`w$Y|U5Q*?6Nubq$ zmojk!#wATJ`4#s}HpGtBR09@g+-bWgHtSp3>F=DL6~un^GO+lnx`Jy(6iSFp0#(1$ zJ;py>=t7e&Oaz-V-AfR<&A7-o+|&jklFRDPYP8G2#TwW06iUeLGFPKeoL;>nZuisU zQ?00O?ZilEiUEs5tbpmX_m;h>J=ClFL0J<1q8cJTj^*q?c^4F_m&3cDaOkTZc8xKFNcSUdBITd#EV#Rp zEH2)b6=6-rr6WJp{@A)oA$3Q8gX9D|{zyV}!OCFT#jYvc>^;N-Ujg7!3Fssq>U zfKm7$(tG+Tt6=}PJ1h(^4Z!jhC+NVI8WuSOZ2v@)$vZ#^4mtf$>Zdrc!bK-S^w!W~ z<*TilB4l0B;jRv`J0Mtn2ccSTs~2v~kNsEVCLzNhQ$W=oh|FS#?Yv&b^?}N6aAXQ3 z#MDffrl$a>cvXEOpX8jt=C$r7#a^TlAra~OClTJ<_7?Lz0EI6e2zD;IlakN2M{q`xBW`MA$8}C zO$;qI#tNm$N!J?(hthK+WKR!-2b?geA~)66ZBpEIO50m+E^9Ru8gG9O_kz-1ldnz# z6YmSM#1=}~x{A0O1D)aaWpG9sf)qmm`)B1EZf}&K7OCO0uAKxO>#r)ISb-dx}MZgzM@iV5q-#nw3pkgz(Tu zn13?w;QYmj$#&>Zpf+fAd}_<39*QZAh$4abZDct_;zDW5&WO2dfe5S@L`gC6CQ~te z0Wr7kJ7L7U`-PQdlYZR+##C%YI>xl)msq5y2ZcwT=DAieaLPG?&vHJ%G4k z0{XyP*Sf}R-DercMuTOK=axY{^Fx&3Jjmw#6~l~Sh)*cd4-x6lGi4iLS+snO9pJ>Z zy|Z!2=Bs0N0!Q1k3qdGGcnXg5@3-xC4}3VynXXeHeZk1ZZ^O@vZaTEpcy8eA1Y(jk zVlXAPW^8R*o`#R3)4ii4`r}{!La;AXlUsHte+OAN6{;kgtUaJgqu)g z@tgQ)$K*P2)V8b!zv5fig!;>H8kKkg<%Y4xWs3$pZI64abh8%eaLx|s_b%;R=~b>M zHmVSy4CR$2P-pIiA&E&|#5aIMN96Qg)u(r3F4eKbZfW~m0uCM$N{4-LT^bL<;s@SSfTX*l3$lA0NJW(KK`GkDVO)PM zwPx^L(XCga>T_VYYA*{6VxCl(`H(Vv1US*-hbi0|@W{&|2W_2P0xh1@9n7zG<{MTE zT{B#Vj>?;|nYr(dIeU`B3xeYKjSaf=41Kml2FhObK9+mEm+(d$Xjk(1*7V}I$!5%| z-BZ|ST>9tamZ8S?`RkFR2s8^ky|a}8oAAW>dcS3J_};jQHOIG`QCq*CgkhZTm>kd3 z(QzpnZYPk_d-@pn9g67B$D2jB3zfp)uxn|*bm)0$C0{J%lAu*yS2>@=1oyemYLUBZ zqP$8})j$QK{>~DW+&w2m?cT86 zOqTQ8Ru;YBMB`(W#RpRq3JIi?mY4_@4sqT7{hB?38;w^$xqrDBS}ebsN0Mm(EDAompjnIjbR%pN`w>R(1g40^>_1$u*SGn>7f|kv2wM%87-L@&=LqkXKRkq?~dsBT*&7}+< z&rOQ$ip-lN_w4uPO zNc=n*s;tUBC&kIgb^`Y=ywbxS5Zujb23%6lJGXU%Ny2TMgs4oI&UcX z4(p~8zKs3B>H1~ExHv{N#q)Y&lVq=;phS6((c}Pe-$|ad)uCdn0Eb;Ix5n`Re;~Y; zWLad+dG+nPdiRH14=6Y>m+z3cVn8MQOwEXUKjPBLH>r-Ct+DD}_w2*F6@`4179UzP zeCbX%HB0PU)+eiM`!K(pf~8|@R!dKrbSfOUPhJsvCzsB86V>t*6cm!|4d}MlTyAS+ z85}^^CSRg>IO@IALcLf@i{`Ef)b5mg``yHYvoWHbY^Ozc6dw_=VJ|u1Pf1Bq>R~Xv z63JmB>;#++BCzE=4HQ$+*SvuF#S%k;pG3(#6QRjld|tDcqtPz6B5YV9nmnM;_Qmnr^M2ki znAL{@XIn$&Z}u4#KU`^>HY>Q1qI$$@MH1*D?--h;58jLI5{{PycLq(5C)lE|OY>}Y z-5yWq;(5Vyc3YA;Tu+_3U8tY>7TWj~)P!I~5~^61Nm@ax9NJFteIV8+?_%%=i5+GA zL7|B9u1vJZE0HF4ZYDhD$y~p&+UZJMe=uTrdqf2mw$sAtSTGAes9vAAlM=DVC%fhe zJuBB82zYHE^GU95U0^GM(X+Cp-6FggfFE@xG|Nh}6x!Izf|ca!C2ErU8cMF8`g|98 z4u-!?|3bH!J1HQ3HbAtigbCTH7_mn`F>z(%RVpTV3cYk&vdgkNuF;N#nNy!&h1}EE zp+sFP&1NVTiNH+U8BI^dEzbEaSf|mqLQ!2bj?QR+e46dx+p)jq=P^ z6=?FajX=3nmsh24ZN6lA8wUPh=zg2X(#@%X2u7foS{B$~WCNyp%&tWNjrw?te3US3 z)F>)Dqb`kD;2yY}hU#PLR#|tg@g3i9-;EF_^@KO~5=KiPmz*h9oX?N8Z-kZe^VlE!3Op$Cm+t2A(mz(n?VKbU; zBiCWj7aYF#rgbDX;Z6R)i9>V#fP%j3Zj||3Z?KX#Al~wPTcetmLZJS1_o=u#fmNw+ zt4gE3lmD~rYiViGA-3JY&946MDEr{^rN+w%lvawio)*5xEp6_x9bJr9#s7ZA6x1MiEQsaoi0*Wkfc?W=cgCoqUQ11sIVi^Y|07A zC)yM8l`PE1S97ENgSm!8p}Dz`$=| zoyW2|yHX>OlGD6hcz6WH5-`6*$kj@kd}oD07Ofhir7K-f&w|ZWewRXvj8ZP~wwhD& z!FB9(1O%k~y7DA{bY(mBS#hNUb!*V5069m^2=ruR4?Kc4*`Cz1+iFp)1t=R>7}Q@R_a@ z)9y*MG*wd|`0s!okH&Xpc`eSg#a+!Jrbn8%%6j2No4-?|ejy2gqZbKDF5K!|NZ`Zm z?-!kv@*IX&-ib|b6*W|>E_Qn$LH9-94VM>IqkCXR&vu+vJ9L=C99kwJNE#1x@V6dY zS)&TR$4lUT#bZ7o@^5iQc-{@Kp(*HoY}bQbasCE+LR#h{ZB>oA^X0ci^n5eh3Ny+y zyKiae=c4Lt8^t7xF}SH8!jV8TP>@NAJjC!)N+OI}7dT+br4vP43%ASOX7_F1!D}kN zTCjXEmUM}a)O6qt*0H=8f$HkABuhm!UAIS|zBlGA4lwX|F6Zv`& zZ*Vl}vLc^hsx8QFu8Rj?96+R-pX@MuuT9PFaH0tVy#a-5*mh0QqPd-QSaAyEk zwZw4Du(=PM8W>CL*LJ50MFzO(a-|$hMsP>iOh}@<>v2}g^_~z19c?&)+1m$cWKVv) zd9Gz?{4NB(frdK@Y?m^m{wlNhO1yW_i)X68SbA^j+o z95>sdWW?j4ol7#)Jj)X_9ES8OVnOqLXOJ7C+Mt=dS1MCP;&RGs2!b`JmWeINCd< zzZ2m0f;EfjnQkdM=N`;+eRtZE(|1}%QXxWLX)ByG5>KU`Y}&-_GQ;m>B1(<0_Nnf= z^|yG>-kbw+1HmibgDqo{W~df06HmOSZ4o@o9%Kh{6wy3^$}tP9bb&JY52~ax_^N*E zpZm})FNp1*qhhyVl~D5SxE37qj$?9iN0QI#D~r1@@`SC@dnw)fbr7ZWT!COZV|>S~ z$TdAj?E8v$lov}s?B}CaKLkfF?BnzHd3+k_gL-N7wmB41<#)AGpOCGDkp|c-ywvmH z9g@I`b!Znaw|isaSy37OA^nb=jW)Xel(ah%{_U#1hJkfbuhYCab$iWA2qH`+ucwvs zN+hI;`?r5&Za*I!ZEuBA`ygQrFV8_cHKN7w4j!l5N)RMQrM311M} zH#%oE3_0?W-7`G+CfX}ZTkqaNYS!Fdy(l%1=KS(|A)C|pC|9})QZA8cS+kZC{41km zSGOJn+0MgH&FC(Wq%u=_&^vXY6iM1$KvcT2!_C?4!B59UZ4d9Lwu+7D5BR3Utqrhk z%hJvkU+q-3=TT)jPf*mThb%3WoRrgj9I2;m_NXW4F-|CVw=R~?V8&^6(1z9ea)(^E zTpd`8-Y;*zKz;=KnUP#2Rk>61Sn{OjX6R*llG^hH>f>K$iDdFU*YB_19D~DZxA|qk zldw&`I59R$NB}%74eRB%V;5?VX9H3uY}W_1)5>ZcB5ht{w%2d*JV49_`f#!lnC@Gi z>m_=%ORreSviqi-N2#IdM#juRe890mT4&5ej zsN$lr$2lh>>kGfHtrIJy9yK0nJ04!Bt8)3wHIU`#LaFIDkyY=pA=QPxWN7gLu{5NC zGiTZKPPw%{>WsDbRU6uOrWqgUfBLP@bBM{azv*1i$^PWC-dV8NfwT>`S*0#KU6A(d zwH8cI2HJ)(6UHrI77&v`0idzSf$>prQ#@K`j=SV)%uF`ufhyvGEp2$lsV@Q-JTt%= zwdy0Dt=;x5Y+1NoRXz^0VRPIN*(~yQn(y{6i1C>=j#HGHSPT8HW$gdAAIz26n9ph1 z<@^y*C`ylZrmz!D&Br__a3&$l4d}dv3C}O5!WNcqRq$2aN4SKQo>X*-g(>||KS*Yr zJu`3;jPNrf;3)S70qcx-5s>blzzpiGv0-;6OOg?QS|JU>}`e~w^P2XY8 ziApfXyx@i7FKKW0f&uM&VlH!6RXxIefkBN)vqOac9oy-eTk0K*I z@HOv`eyu+wumu}-DYcImdB(E);)qdUfi0fLhV~u|5@Ah-#7qyD-f2;oM0EKY=ftPp zKgsYmZXY&%B^Mt4S!MFDB@tXukb;wv9vRWMznuMW5#QGHw0ZX7L64{*d3Q-Ttwcnn^yQLP{r|=>=_LWd_ZKD zjeoPt{j0VghDn*R$~a!>RG}ID%XE0l=q?uhnX&J%*!1jjd*;bCKoI%qQ4T(k=^#`9 zo$gGF^ba>85A!LCN4~eZ0fN*brhs_r;H`93Ys|_@ z)6GVw!D8k>Zd!SeCtp#PcQ&JAli!xF&gC0@{_&Z<-brx24*J^OQf3BpOa^A9Rv)<2 z9OyO?adFFE>!GZ^YYC?y+O}jh?ylMyRyk?ytH(ob@Bmpz*%?6G%O7{r2&fLipq0IH zN$_L4KUxx~0&KTO+!0uFk}*A}OWkpC@?Li(9veco+#l4lX?Z&gzY41+K0@Y-t4yyx zzt-D-tL=(}1Rco!d*k}-jZX>AuxLM8wPR5BjpT1Q#<*Rw4mZ01^cr{(0b~?cm?bE9 z6$bTJKRNz$a!T6nf4dlwA(wo)DfBW=XolcaQNS(0w=DYHkSH->Xas@jOIzc`G05c)9-Z^_s!YI|#zcZAJfW^93#D z1mM*1zRZttSNpfox9ugkLoEpqJ>WY*=HcrEWcc9BU1@&QCH40uO9gOJgz(d>|K&ZV z33%lXHY1z6X~q2aB_VLD0lrkD{9m6F(x@N@Hhbmtt}Np3OYu}4l>FhO2Vb97ZJF-! z?}^zQ0SmI3+xY{fJ8P@FR-K|?4~Jhr_EM*6)SBG~{-0-|y(&%mcfqcaU%+P~lqE?s z^=9tN(g1pz&jNP&5+uh5=%~{(&$9%wUd72!R*a=lIuyn5e^z+>?}Q*L(Fn`XfSv1# ze$d^+G8$Oc`bY8+>nF6;NXX&YvLM(Y0<*H5I{tH^tEtEDqzb}*CD4oey`PbdGxfy{ z`$cE+{k^SYE)#Qm(DDN%Qjnie59`t_1(kC@TevsV@GLc(ELOKLo2KCrh4l}ORgs`g z+5DgRUtP|4P3!B9#SPlYirokQy*PfnHq|O|0i<4yS9DIx*JZzWxSK*X$EaKtt9qhB zWM|aM3rK5AQ@z#yMdlGrEAB3XB9&wMJev^PtoI>JSW83;{$+%KvJy{3f&$!v(} zys|87YrUM*UUYoKG2p+nQYGYNZq(&kCZ|x(A4m4|LxA7!z}?vbC-&#spG2n_XTXLy zFHvJ{U%s@pYG`n%ZW2;mlQX+7E`~Ga z2~5D;5|93-hROrE4r=s0F>zpoWfjzBNx0!ybckNM{#U;f*IV==LT;=Pe@3%A6O!xL zxP*PF7oV4*U6?=TSo%Y@O62btTcIOO;M^GI+!R2EYrTj>Ih)-sy3Yx;Lr+>bcalyE zYAIc{0Dc;VKTD@1%4z;*#N*eg81LH+U!6$bNR{Gjc6`4hT|DE5-g z=xBZ99A`u)i-i=6`5upIen#`3DpdRB+64WTLY&iOrzRri(v{Fu?BU|mU;y=EsBCu8 zA~i?>N}A`>;+EO=uJcsn^pv((sqN@r(^kc0;z_SYj{A`pB5m`8GwpMl;qI1F*xH#( zYt4CKl(8Xxdkr|Zv#-w)3mFg*JzxocLgw7;@$4D~kLxGD#I+l=Bss&TC;HE!v+-oV zFP&sqNE88$G_se<)eofb)c2}nm%9~%X7TQV8&WG1uxb{Z>~FnnyD3eCty>&l$% z{as>E7?h5S3P|B=^{TL9UZWMy0P&;(>2%{h4r3>P2`wq#Xz6AT5ZjJH@;~j7!liHY z$|t2h%Lz7O4Y(f1M8KUDLanHUy|=g=LM5p~uxFqdRR0ut0FrW~Ui~TMgz)euPl298 z91>4lni2j`4_}?AID0|H{{$jsmt#NGS-Ar8sq|90*x^9Yj`M2Z5!4g942t@&50Cm} z_NSJC*UT2^FQ&4M&{bagD|aUsojy(;X!Us}O(_iIq%s`-CGI)No)NEyv?RfNW5T=} z6Dbc#n4IKxfyd3U&HmF|5Th6+szWi+M)qjDM_qdBmgqol@L}LDpdJ}nzFh37v>Wc| zoly-8lZH-N^5souDZjjJc7YSGCg$3Cu4E^LU8o3FZ4rcc_YAuyc5k#39YLmK93V?) zrhq|m%zUhfOZ5ItSH!hkXW^|wm z>+sZo#!%XRMbU-p!=tBOvx0n&a@3#gyo-h;3nS5YBt8Goguo-$o%$ip#LIRUXhtg4 zK0u$H1d-Q0LhVdLf+(7G%)|pK*;_m!u}~$JAl?kmf?A z_qQ-%tzJx~v5V-8u$`}NO<1w9Ex77I0Z81G+Ht%M(>l6r>Dl<&d_LFztiOO>iB7AK zh1P$R8}bJ8*(-Fqlx;QynLxU5G~7P=mP0jh3pDe5DH9FM@8G0NHljI8kXzVj649rUnHffgM&n{1 z>z5Qx^mUR_;aHVtUx7XXSes|ExdghXSCm&7WgSM{^^LVJ8 z{9~HMrbYcbb@|s@Kf7R<)E4`)5Mt!9`OF7xzg*LfZh2@#c@e1wvH`MYz3B4L>$P zE^5!8RA&QbNWmojhuw#$KaRAT=_USWwnZM5`IpBHOtL+)wnNgqF`YdjT&dst#bD1h zSB`*kpa)XtJjxj_#;SA&nm}b4-sk9(K?`UPw&>ZHW!U~_6|Y355i(Icn>@?z4?{t+&=)g9yEw(7QM1 zp8;yy@*}erV)Wf-q-Zbx!~$BjezqN3GZ6lCcoX+iA)Oo;mpA6CiO`ki0wjQmF|N8?9+{nQR-i2T)%QBy#E z>OT#*SWiH(PQqvLDY>f(&<}Ynufl4Xiotslq3<}f$+{mv>7D*ZMxyx>Dr`uOf=K-) z{^-lXJ2@AHgf1EbcZK3}=g0NOO9FA_SJf~OW7~DRoq=L;xHNUJBUo7iRBv2O&LyOT zmq?KRp{hZ~eG#ga9X8;-s>qUflPC7*qwbfF6(Nd&$#m7Dl|_$w-@+Fd`knyN^Vb87 z$(OK*CXhJ2OpJq)7bHQgStxsuqH`;?a!eT**D7qs9-TmXlq@9EVJ7AFl@3URBCO(y zyx28)=U`h+u_Qtv6c}5MtB2{p(;^$t1N@oH$zjgt6r?Z~iTI#4TIA9GNX!$ZA5nVM)JInCe56Fj}n1Cwb*bq{iuPqTVor}LSxn%Ox;6O$)Zg-#^;XcBt zP7u+~IK3TY4W^9bnrx;+@9}PvQTWmg4O=KOx=gt0L}Y}8u@BYjdR6BTs$#u&5~&<_ z2%+;&p8{q!mc_dn5?`>XGJhu({5}n8sF$p0tc8PYP_v=5J5X_KL0eBtwb$BWNbDQQI^|xCGokC>& zA4MAR6=EtsvFQpz$~7r|09wnN6lQ!$yxCB6xH^YdBGdB=oMCw!wauWbQg3VH%eK%< zNuz{5^TZp3eQCn$O*R}jC=fsbwtdmip;RfM0$67oVjLN6GcQEZtk?+NPnzC|cou`i z1X4)ls`+dEBGvFzK*>ZEp3=tzD9ha6%_ZV>GV^>i496tMC43&Ik^SATnBx``(DvEN zVu4uvvwS(I`Jm$ps6f@Fc4qecR2^O^j82+bXHc)<0OZKkB$)*lsCp;d7(K zt&q0+YF7Q$-3dy9>VF>dn;WSWQzB3WM)UxGTNrFF%I`{8Z_g|N+JGxjRW(IAXyZ&XNbx_y&A`+Zwa*f6w4{crz> z5g_yhZNR4YgZSKa+?lRF2jL6aRsJ$D^jN-zs%tFzoHT-LjVl)~=#+QeK0dCoI62lo zd2sh&;rh8Ocr&!ZQ8=++JvQ*mFRV(e>M49bq{ z&wzynP7U?#g=Kq&fJe&t--f=%2l`J9e@txhIHs;4epmk0iZ|(7Zoh7-7_N(taNf;Y zRvp%gy-_w!{UKsr`3eeQuyUD?BFwka@jBE}bSKK`ujX=bpe2f* z(^#B@8(xVCi5klm_W2akOez#r8F5XhpkdWx||U8chtLlWEXtZwv**q@Ao5iI%*-6 z(>qSIGE*{gwtS2$#qEJ}q=amf{GB3_;(K>|=H16fRqs_-zNvFwwUqu3(74)oJ)DqA zuJKu;)*U%u~^-;%i%LMeDL^< zV#@04ZkwYNuTrU{Nb}(kXPsX4vh^!-A+pZ%kC(oM#*5$q8!}^Xq6P}H^zK`T?8HZ| zc_|i2E1WN(Iswlg-Q-YL)p3|W{pU5Wuojn?ccE#v+y~U2nR5(5Vke&QLdzMd6D+;t z#WqEhzQ1cXj8>$UoE88Cr%hpwsUj`bIJ`sVK{{bfdpauF6|UIuPzsV;*JJyo7h8lo z@D}hk(y#Y5vD|*$EpEKqR;cl%AkaP7z!dYnnd_jCV6xS9=`iMt)wXvET*266(RNb! zJ@N0weC^$sM-kqz1gh`ZaT6-QSvPzyx zhsWP3I6sdV0rztesDp|fTldy^iqfRGTZR$QOSR3dt2tfN3Toh1ol38_-8wqKugb-J zYJbVyo!ON@Hmxp~(^HRGbQKG9#dAb;8+MU|SLA$y1nVxVt}7ucYelO)?UK8bNLorsls4k4Dgk(p@GfKDY54^!NP0gRAJJ@qIj8LB5 z&t9Z3y7h~4x9IYteBP#zP;h@}kyj~VuH`1O8o_E_|2zzILDNzRIF!Fvax4uhE63soi7)?f5;aK#UNroSf|2Chu~Vpo2wtkUR+JfY<+Z+BHn2U2mM)~| zWzy8$&gk3DQY*2F^B>c%>`S8D?B90gHF>qDng};AZx3im-jv&xIX8pR)cCkn^K|iu zy|3mY*Oqp}LpJCRNYz?p#+Wm>`M)0#LeO5ox@uar7s@7yZQk0^A&S0~c4Haz$|y8a z&&n|bZ%Vv+I;(%HxA{g+@`Kc^p|wdaW92?70BzV4xsd$&AQgI4{8Ms!kV1f2`|c+-Y&8~fRbps zSHk$vD)gJq-wtjG&p3Yu!p$Gs#Z5S~w};Nppa+l(SeotK!c_WK8Ifq1PP?R}>ubEp6baG?p<+Mr@I+Y|acv`i$P}{~;Fm5q zYAkvz)n%u%-Z*ZU}#x!(sMZ}?l2l{+p6eI18_>DPxGlc=-u)I z>FB4>`(+DAY&+#|i244D_G_4wUv1{a&^EN9kIJ^D-<)LfAby?>Jt|)O7x9FQg$Kw@ znhm$v6Ou_1XZ?4x_nUo<%>{;E|1uMn=)@N!m$03q0!2gH7E={ ziNzLjQTkdmlr(gR0|IbiUG{rVzbpiaqjBlH!k-WF8K>KVmHnm6Dm!mvcxxHt*_f;s zyIi+RZp~dz3gYw)G1Zk_o8KSz%T)~Wg}w|+GKoD$ef_!fSVJoHI~bLGS`-0ypBu2~ zSnavpHo8>L949Og@(w;&QtJ-E-Nxe#??W4_OF}FAMf4p{2l?A7HrWK<;_5Wf45YJz4Vc5TH-}n9}+qdkI$`A2H zWrOZFwP&q0R&{@|G0Zs1aDl73F4I(+Sc~(8PWPCt6(DL^97BRD0O!X8Vf0uTm6_Zl)fAZSS<_QPpF)knY6$bJ zZg<<}aG~8btZ^%QF4=gV+}5|__SFSvR(}@4HG`_~oPR`&c`94jRZSoqqbaM0ne5Bsv zRVI|DOnw#6QFKhaQcg^IFEh*g9Y29n3v`9%;Ysm~Ov(WgZorP5@8e)gW%igIq8wAG z8*lXMH=6fr>8%iGJEuUvUW%D&Rs!&X`@3Wa{KEpOc_l#E;URLj{e@bciGr^^qh*si z`8ouFlTCW_5E1AI(Ce=%^lA&`?;&oHhRE$Ilj$9c>tsksGoYjQwz~ejr*^TUWM0~z zPht}^0am?YTt(_XKSC_uE(3U~THYP$tO3UBe~3Rz$i66K>VNBBTScD#27-aL;`?;D zHe&z1ywME%iSNVF4 zvsNM$=!82>ZHS!6Pl0hz44^aux1=t#PAV+6e=fshVzPiE+}+m@CJg=te35_r-LFbl zaY805pO&uC;)H;&^Ze_OhenzIP#(#j!;aFa=2j-a~8&_)w2BmP^7&Uo0N zZl}#^{+SEOONq7UI|!-s+vlUw4x@YVKVSFFPwuTr>$f2v_tW{I8@6<69_O+)n1wsv ztUgV9U->;(dhp{Q{Hw}yZ&mpd#Kxsxk3Dp-tEXl2Ug#JFWpE*K;bHL{zTTmXo)nlfbNH4covHctfE!RO-+1}M*$ z3PeVnT+e2gU2pY_;ZoPsxFE1jzY>*=`i~7eQs;B^mnM5WyLww&KGPhC0yL;sA9Kmh zs`O4N0%mM`oRl%32S-84Bp?e5mp0t^Yzz##$JT&1y8_r7A*c5L{|(dDb|C$r=Z@*` z(J{A$=$T64_!}Ct)^8JT0L=zY_v~x^?Ac`Ku#etS`;RnYBtnj9+rr3cRte#(XlTMjA7vk{ z0?5~i5|!g@*^Q?y+(&)KtFk7+5QO;0W8Zs~Cy_om#%N8Dn>G{Re#dOLcDR71qq5b} zCFg5BThD3v=U*)C0smzKLQkf;1^*)2fi}hV<6%?LgHProZK{w0r0vMYiEtHe>m+qy zcTs_N*={)BbmA(P_`;x+EHHBE>uIMN;tU>c9%X)(OZ!q->dc7e*HjUgR3TW!QOfjsv ztMX5jaO&FK@IO()J_>d-g3Ni&R%K^z8qQknqjvs1^&nq0Rl%H8Xfp{O8+;^Ro5&N? z_z|yu@>5)?#%X;%&}u&I#1ZksZzr|y;IG|VA-UwopD^KCGWEM%txY$ux_+an(4;bP zBC?9_t`-hfRBDZsUkhmKDg2|qY@uNt4xgsIELxYE3a&*#aWOkN6^xyf~N?;RjQVX{g_S1>2E&*&|a zgb@bNc*R#ADDXpt+<PzVVh_ zPwMlZgy^|TGPHrujE58iv=u4|9e)utxe94#bc)s zovDD*gZ)5}uQ(L^y9>;HdQmsLAeSiwE+s-)oK5e)1K(iRbs-Kx>Vcx+I;kIDb=4=p zIoH+rzx~N|20}#b)e*SGp!$FauLn!(Zgik7^IuGwQO_ChjSd|H5GirOR`CpgHvIbp zXR+1O^10ZJ-xCuoarGY25il@A+(GZ8^9inQhvm~Ph~N)_#jf!o#Og^SPk}%431p%Y zXF2-bo(RP&_C%-t&K$M)kW%ECKYz~}X!de^#R;f$iabBknIZh@z^P{<~JVSoFLq{M*BLebM%A-x1KQ~kl^&cHh+ z!(4s-PvcHO;M4c1O>1#`-~wUk$@AGb119)teUM^R4#b?Is|Gv|EKurgwT?S8H2OTsgQ zu^OEg5lbuHnX(V3Ks2-efUY;xNu8+nrRT}S@6NNynbXltV0O=+Q#StN+1)({u{1g0 znWj6?z;vEyOQ8=yG|M15hp+a&Y8-zGXTH%ew5R$LO2$QABl%(wMf@nCR|5Z_t6Cs=ATi}Dzfv!XU&H^B3#e^s6r~~+~ z+jTnxj?IJ*S(Rv$96~kU)e!4eH-EV}{$m(!)d!%ZH%Qvl;XAFujV;p0+bv0y-m`=~ zf9k10E37@BBq`s8gu|KMaslUM4;iqG+tL!FN{xmpaNr<$>;mGu;Sc-0O@1O;jJm%Y zopwwVMH4TWhKb3!g+_g|e0=#Hs?U2_gpust9{rku-0xZ8$}B#=V|dluRZR~E zm%$3e7cwj6Y$sH(?0;?-J=!eSNH{PLJ%cQvgQHNC>ypzHwK9`dYB0Ov(NpIz!Z{k=dki;{OR4w=2mB4(EqiP9QVt($)U9xVlA-9u=;XVJMya z+!&k0&I*LO+Y+vj#luN;frIku`r#s%Y;|U#YPf4>@&VxtoEr;=c#iduz)$V4=eLRh z1=uaGhs}h79|$>(_UWGjyy#Ckby59GkuHFJ3jh!C3&IoAZ~b#M{c%n;bNPy?JKU5rn!95C7Uh_>Jf_aUk&!PAFk?+HN9=bFuj-yHqCpwGE1vU;dNq@Vy;TMc!5*bt5h0 z>M2yuz3fj&5g$a-OBuaio{BA4hEV<8l3@__W`eDGo|($TCs0{%%pWVAKu{ z|AO!}k*F{htFm=KMWz`tUE!2ZCggm=nFum9?)N|r=?4M_YE(qO6ZGOY^GLSZJ8|F~ z8z)~{j~K#$qv`fhHoZl(aT(B}#wBJLkZ|xzuWOM~{VD~1Ef26TOD8gdB#d)sfBgLf z)&w@qpH58-$#Qps(QtafwdrNCPdB2ukS!{ni|j1=6LY;(hnp6f#SreF^#jZ}*n72p z*nHE=%z_YMHst`C>$Q;?rYR`UIpsC~Z4Pd{A~kly{cLIlp_|O5c?cH&$D157;K z6cpO=t`jwMU!0F(7-DN(Qrr)Q<W|zrb=q2+b+c}X!#&c2Om>0nkpz{r zI`R`}DnE;-?D{|$5bn`$ruiCQGH@sHt!(rkM^Gq&kRxBD>rZ})RJzAnyGzV_wNE>; zz)^jxfFf!Vq`h{_s}MVL&O!1RE5Ve!)0nJ_OcW;1!W^AS3Von-6$y}d(4pKF`u0(Z z*J@c;Ti)yz#iyn`9+cWd9b1=tFSNj4jk0cTd2gn0HW*j`kkhyOrSOfC!c$NSQ01_j z)c)89^6Pb!hc&%4hwbIcN|Q*OBi1?HM3nF}+J_W8U9dd22$<;Ncchz8z(IxbC9_WX zVIbzq+MI@DNLhL?X~DUI%Zh3N@Qo?J66K$Jo-APv1A;r zZp;D%w0`SS%{G&%DjB_&jU0a*$5zF8r=x#(*xhsznJ1Np=?xH>sk{iOH7dNpWEP<4 zpFy*MCTzSHPnr_Ky-ZC)=0U8NHHO-BDM`%yR&(m@=N}TWS32?OB-zqTnsLe!wQd>K zcyr2ou+^5(5G!T8%z|2svZ8yzeAz>NQS}$NWaI3=nLk2_jv%}V9qVTus0w6pG0F!( zDS~(e!);Q@fZ2nuSBIBHpNT*D_4lGDVfKozy;|3}HuVCMP%%yFr07=?lmxOMwU*4I z%%bEJ!%KDuvZHH~h0-Z!AAg0<52tvwB4!t;nFt?$IN>pxyI}RK{q*Jitud>lh(kJbClB0Hg*A6Gmq%=gOQdF*N`x(!+D2=lsa)0-Peu+i85T1; zzB=U_{;;!)bQ`&i2$T#cwE1l_0CYJ3HQSj4fT8`%kTj*V*L+k3T!(MuT5 z*X=wNWc2|O5m#6a%f1Np`8Eef4=*s0UXwDMsEkO?Fry2Ut1ji=zH10Os5EDEZ$yh+ z+C(^|&6W)2eBWY)^|5Or)MLdmN5hZlKcsNe;@UD&oiW01ApGu6O2?@9C)+$ZKyyMY z;Z+>Qb9Cae1pUEFF8F&m+WPr4zN+zWi@JO!t8{pSwfHs6uw@CyFe>|9{t))DUU%tM zUuN&im$aFPUc9CXujE*+I_Q3_yt;Iel)!Mjfb}Bm;dNy71J7iX**>0(!nXxy{1sw} zv&QNWAgB;nLXzoz?7BAqq%s%Ljk{hRG$x=3;=ZuK>7Y6yy;YxN{Sis`tE)C_w<5gX zxFRzOP-Uq^{%o&CHu7t>U{Tf&F~ z(xP}$*&=G>!tragg(rF2f)vbk7Kr@=+j)~!La(26Y7bt! z|LpCHeQudu3ZxWl$irxwXda&3IVHw|T&T3+mV>41g_O%W%muC$m#sRu`i>Q~Xh+=}%s+iwC{uqmXnn*l5ouiR_eWqxY)zG4EMC{}b~;^Lm0N-Rri z=Yqv64YfB6Zpr{-?Ct7!I-HhHLMF(00nrh&2>Sf#%?Bg|`2KwYn0HETpKo;~G*lfj zO|c2~A8p3Dkj7;34Lz8CDp;hJDP%&#b$Z)`slyT>T&0TA$!78v;d>OJ%jHb9{%pJl zy+mu{{yL+vs%-DW8?Ogj*A$JDZ+%18EDGgS)B6AXqsxRE0dNgh5thozKK1!#xz1Wa z-W&K!vmDaQB+PD_H96~sP{k&TF8VEnpJE1 z5@YWxvZFoK+P#x`INg)+m=(A5U^SbIvvT_Cz%Cbqkn_{0JN9&FmRF__9Yjm~YL;Y~ zwl>dsVI2BIc2uA$ukdtLsebA9myYsH$SM=eaMa=z8T+}3`Ekfm;0mSLYoJmCeoRzX zE(^YxhCXK4rsR6bpi%^$6Phg7&3RN4Vg)Gea*7{BgVJXrR(9IkY5bE0=PneEiou^a!5?=f(AjrQtMR>{-?uNU!Ws8!y6#Jz)24uJCm8P*j|d$W zZH2kO9`UA0N`avc$4OAU{dF(DxS&Rp;>-Ww?JeV?TKm6IN{O zMk!H{PDxR^yBk4?kq`xu&Y_1!rIA)<=osc)%YD1=|BL52=X1{aobzUndziIm&01If zzNKa6`-Y`CFlC% zVufpieq51Jv6j*Cvq#rmc6Y~%Jwdc-=YBpxt0mgT!DRCuGRoAdaW)^Z@VMvy)Q+)x zXPp`qF8fye7DBxZY)Q_!%qqwZ?hMtg$S;8I!Zb*_&mz|wT>Y~3kjD#?C?nV6JYT5N zbo_XFV|VJpDv|A@oRwrez4LheP1tG8NUXKZf5Ct!7EWX_qNibS5g0N#y(;Uemy8z{Dlh7f-$4E7}vQW9r?5_RaP@I;M%S zZnIT7%375wk@|8lKm`8$!f*|}CThTK(Z}G zY4kBW&QRra%Fi$O8%}G{rW78Jm$mq5770+SJ0UpMCp-{&L0%to3Rbc!6}W?hA0hz- zNUy~{z_sG3LZ*y$U+Vpr=)A6RmWO$!9mk@BBQjDR-d?&%z1cnno~5lWtZaj^N?QoJ5pC3Sgj{38%y@?;l(zWt&W z*0(MX!17-N7?eC4QXQMCx#7|k2j8!x+gJD33=pY^tTD!r<4|^B@=~M zHg=8Z=W^$bDYhPbSQ#v8ZQlFYAzQL=Y*Zjoo2!A#1XAnRVv~8(c4coIP2j1Ms}uT2 zt^RbAweGesjE9{;6!K#aoFRmFa_lbqSdfb|`pD$2*T?lqh>ATGHW^!ctjTWNG#j?m zQ%PiQ-LcT&yg-3FNUToo7vdIjcL7DtRyer{!(p=q%9 z#wFhZS%c zIg;Vq-FNS&_rRB`&V?N7PP90dT!UK@F8w~!b=B5MNgz_Y+48z4ul+qj_sIT(GjrVF zeGY_0>NpktyjqZh-9@>&zT*sYDbB8re#I_V8@&!SnVlmyAs!yRNj1$E4%+&p*{C;) zn|vQhi+Wd=6h$s9dwC2!OXhQ%C6){2b7!|+9J>Gu3AS^`c}^;aetx-Wyd__b-G}`~ zC8ZaN-#;_4<$ba!ofE$pM&07oA`Sz*d%;9%Lo3$E!KLlGqo~tECnvG9kl^4e>%#|^ESxt#uqvslhu&p zo+I+$e3|551P;F zVlU6kiB4`#UNv#bn9ANUddCrM-OpZ`Q~NOVWY?7Jm*LL92MN46>4leXyt^g8d+hhS zFP{x{D5cNxOjPCRs1hg!;$GkgqPj&%VcMT5(Ut7@zcLE^;~E$}7C_vI$Zn5#4T+NA zF|hhduL{c1jd`LEuC0?NMCd|$V~BJQj0oM=6`QIZZvWr>pLv~Xg?8GAHJo>;wRWUZ zPtjP!R`Xnw>qVH1Pnrm4P2ODsgYEfS58{P>S^NhrH{3c|#3|lhdeOX3OMI^IJK%CY z=Aidqnd!vUM24W=5ORi4F~b5f z$yPvz$bTzerlO+3dH6T;Xi^c8>qLw|v|!Spx!>7$(0LG5gPG`)FlbJ@zT1-tN|5Tv za%@{uKx2&ZUoB2~a$WenoHDjiilVzY$3OY*`!yYPXI?@THEyRIOrL`ktTL&~6YTDS zO*AOD&|L<*x&W6@CzDB8v&g8!|5jPvQv{}8Oatm_^Zpb1i5b@+Y1PqhA6N^A4qTt* zl5ZkQFi#p!5)U{&EiK)7$DAQlKa9$(a!wb&3f0dql^d24)n2i2kXm6?ijl7%eb>CP zV;lWYjRSyD*OxGqr(XYRhsvqgc{s`+;C9HX$u!c4@(DabKMFvGU!_J}r5^nW%K!*K zRqm9)mH_%;Ce!-o6EY8xJ;;U}V=2QKNy2}=5%LMOK#@mk;NXJbG*8moNKZW}qYtO! z5PE<7HXmr(CdV}zj{FXoHsbP`z{UMh_Ab;mQj#){m8=dV{;^w^`=55}Pr&{Bo%mll zm-8En8*_JCVTMZ^W9wt)Kjg_-OHmz;SA*zcw`4DW!A`*w|688gFY3fG-Noq+GNHqb zZ2W`&xklfpRLCa!X-CeCNyasrb z%N@Mgc}T=kV?SN}v$~J}`9GrDXL-We0D;aX5{#Lrhhnn^er7tFEsBu?{_~~j2f}|^ zUpxO;G7c%8$gb0XjpAh2D!@zR#^cxFefPpe^VBaOAVL-1YR!ek-!%cU~;+b;Jdh*?9u(k_0^zobbP zafLG6-W_1w7 z|B!#WvtkSB*Qp~c!xP`N&sL`pmtmV?C!l*7>u2zC>*qaIz}t`$>Prj3iNVE6Cj{_q zmt-!`=CXfJc$(<2^s)51UZ(vGf&FhlKKVX+vhqh#0G^)t=Gf4=`C<6Sby*(0a?Yht ztn{Pq{IaO!A;@sOpD)L7h5%2E_>b<@u)R6WBO&l=5edD}i=4Ak4h`C;%M_v-0JTC+mzra=iQ`-n2xz7=8v&cwi9)K6tz%O(;6CP1!vwPI?z;e-mSs= ze6$$Z_i%tYXvrch_@dPEQc-~kz?~Ltn}LcR(aJc33I1dB{|?nA6Yo|FHBcj8LSu=T zHYnv1LXEU()<`;(&CRy23DT0!-vD2$s~(&N!S@eOUgcKkfC1h{)OA8&``zrGGJvv!d9V?{>kgygjR05w|Ll)lpN};?qo4S9!JrAF zu=S3rX?UQh2VTNI+>j4~5TE0**{2KI&poL2&TMOlORb+sbbZ13^P=6%5JXp)7K8HG z?(J4IbF?Z@k1Fw(#Jh7}h+%1aW)yXweWT;(-uUnLo@f{Z2NiaTs^-cC;v(dvNDYJ- zt)mpct*Ma(-rolpOW6m1!TI^}`oeju-_L4*FU%r>Hug9$?Icn1&f?7rqC)r_OG41? z1bPallNbNqOY4zKh)a>U5iPHOT2OiSC^59EV3b$6o+KYVlu)He+>(tvJ$IIZzTsFS zA1DvvCV+hc$vykLS|DGl0T%;ee^~@qbx!d=eLAUf{eIYgKCUj$h4V1U?bZUPVFl4|*+t>ByE1 zR)qBe3f$V<|B!=TyhX@ncSUYlvJ{r%Y`38SV+M?|il#@`nbzI*^gNB?BdfbW{4zsO z7$~OC?af#{y9TvfVx5|PE`mj7;ZFN-=2d3PI;l|+E$c#QZ;|!%68jDK%sX;Qp^R|u zOu)=KpgeuOo?cqLITK*REx9`ZWl>Bpwevo{NB~Soh-}ESjXIU4fwbA{Cc7z39mG+< zcmO8Ev!##E;WO!Sge9qQC$8TDIzMjG-3qu3eLbB?%~&##pr(XVmwckVC;8%ldEZU_ zU0#lTed(7MIqpS6y64QSMnH9FJg4lAKrZZR2!I2JFZZ|KX>bM`H*TNGuv~v{tT#ZO_7UYU6koHszj5gQ=xzm^|*7qalK0ilng5ab`fs*yX1g`yfD zk)sVz-`hbcJ&!`~p8ock{E`7#u^x|=$b2-yO7HfIWI`f9aiD?hiw*ET!+w*b^qPB% z#=@O`L_Y7K(VC2V8mGv4FGS~UQk-y-8dbcS7G2NxK=yk#Yi<=>WzkVgJkkm$W>a8k zFUDdUC+l;6`wcd{%zZgnzq}9U5o*^3+WWrTM z$zHe|Y1o?UQZD-yJ0ui3w^pKYn_-LdcC=UDmfeS<>5e{m_%at0cQ$>Mf7kCZZHVU%Z$EJ z2;*0mw%%;JET9HexVl~GdU*lN>4*du4Qv z#gT{IC!<3FM3kd8%BPcy;i0*@iGR7`Z>cN3Ag#fp*L8PzaIBpgIDJ ziJa^={x1U35xMCyE>(j<>c{QlB~l-Y#{xhkEYcB}XV(Jw;b%jcbSR_GQwf0Ojsjpm z4Khlu9lm#2OO13Y07SBmvV_tn$bcluVkpXS9l*=?wg(5xCz>lx+P>8q5;Vq+^3GP& zbTO+2b_E#*JN8p*NFXRb`eRq&Z$h132|M#vbzHUUr(Kb^eJemqoTiI02w5CCcb_y(^}OU2l_y~a z?#Q(AlwC*LI!#&eB#~aN`<#BB){s>auj-*Cy#q;lXQkqv6Pz3aLNug{! z{bsg?dGThoo?ibwVK_Qp9P*r;=N&rVT>?>7uyf7E)^Fy)>0(j7M7wn z{Ne=QnAz72EO4!_q-9xbNVpNaMRic8SQ|CGhh;Y{d);oU@$KzK7gR1M!)vWN1m2<9 z01GBrKt@M)CEUz!fBX{1<6rfwgTiANfP6jFK4H8wPmomRy&euF+g|E^1>=Jf6h?uN zzoeXWwu&*k-!8t|EP>4!mCz+@V~d$m@6J?ciMi)$@CkX95+9!@2v-dyAz0x1&Jq(; zHq1@(X6|MrZ$b^z%dM*0*t6YLu_NcS-yjUQ-*^+qyI;x}9D&ea2?sE>+ktrH0ZQ-j zJIH0q-HyopI6stFOAjl>k-nL?^$9@cQ=F^-{w*7BnH@W_|N7P*a-;$v!(MS_zffKQK>#Esls3-kRV{kML8;Dw!vkJ0Dz8aQ&F*+ zTDRA`5;rdGw`{gE^mrcEGTIxGQ)=5r1}dqz>=xtkG?(Km5dz1^Ah=jKai2F$Su1)4tusXuleI-IcmwqIcRmk+L`?9@cAfDe zdA?bRPJQ_qbhAq!b4I)0Uk?Y}i%iD#U5dgLk_G6jlZRehaI{uif7zdR_VQOf$F7&# zP4Q9$Rk2BDzC~0eLaS*DW|(}#yEtoKz9s(#(UjKO#SOlick*#I`kk9zJ9nIjt0ks| znd+ytay^9C=RjKgGnW^uAdw)R(f??n(JufDpKN+lSxp>)?VxSt{%XdackuYCSuCzT zn9Ic+&dD~X1EvZ`5dnQ-_b^7q>|B1bn^U4sKw8RlYh;`GV(M7VHYR*{@?pXbAy&Cp~#SymQ6Q&B6ica0?HEH1n5BswZ?HJ$#- zW*}Q;1c97U#UAqW6vHeXXyv}^whB|n^Cn@HZ_u|0D@If8`>Ej-C$-=5y$Qf98tYxg zE8MeQ64D(M>qVjxnE-24d)^Y|+k5}LR}!mC&c63PYB^EktsO13URf3_5J>4dXlL$& z+~LF7j(UPc_wC8e$R21Tn~jc7b&X3OJ=X!n3&pa<w15oLlGMX#he&qw-pD&a(TI9D>r4|KD(X343rlMM?Jc8tKMn}0Fs@|T|98T{Z z;2?|7AnxWIv&e0_qM~t)ZP8jV1Fu&}+EVmQ-#Z}gnx&`9Z2j9*M}Bn8b%Mw>;05*)zRF_Vn@C-p^)o-4}0 zO@K>FgGf^ScbC4E?yFJ>T9~}orA)g{_EQ(+^?k?9*IV~gr@18^#!3cA2Usm&`QH7; z)>Y2}N9DwmT8B^Y8MxeYBuq90P3wL$DFGh>zij0)73@&JxhsE;?uSaPS`Nk}^3jON zX?Q|6X{g}wghKZDsD^CzCyZsbRr6p9;%c-@{UUTJp$g(8+%WluVNmE`mrW2`Nz#_s zf6cVdCNK+@p*g$ahb%c(ie*O%D+B#a_G7){sFy$d8~tNMLjxJ!{QU5uxLC|WT*lAS zy2zlE@``?LEElSQtxqkzy7_A!{M}$I`F}pA2&8BzxzN7JT zgbfF82X2BpV%TVGTk%43456gsVr_JmprWpG{J($o)pBR<4d-rFiyR6K_j)@tdEvMx zepxX+?ihC8H!%=Kg$%xmsP#hX`=?)*rM`-gkI@$sowiDJo3Sf#ZxSWnPj@=@9HQr6 zwp8QhL2{BctHBIAbq_g*EJNKV3`_KK$#nSuL(C4OnD&G+TEld#cO7d#0Xl6|zS$2Q zvmzv=u37r^=Ar~jUGNS6yH|4^Ob=Ll`KDDtzb^VlZo2{T_Z<~Vjxc~2q&9k~sA|;m zow#q8F9lO4(ql^k;R5K`Xedad7LDLpb-;k)kPtjDz4o}|QJc2T=g0_iWb2ly=mFv0 z@t6?Pt0yiiODbEwn&xKOR;M|l7mw~)CRcFhY$?7!$0Iu>My{d=54;{GGB<=@>(gQ<+=elkoZViLu_q0Y1my{7bZib`i{|6I z0jV%)5YSNvscF*FM5io*&sa*4GAo*lcSA@0?RV=4+*dy;t}Iw{w|^&3I;tp5C>whDv7Z9U^XXA|dZ)14!-m;0g*b4l@FjDGiGm|W&t0vabM zXyiL2iCJ+5xD{Y|&vr&};8GQFI`5B)s8VCR3P=(ra+|Ulox@RAWu1(HGHADBLiI@K zlFs$o#cFXe;1wV)8Q7h63znzyMg=C8wvp z=B&vl&!TaRq)aYHD|Ln%%^kfnFP#f}pUcUFXnv>HOrhJfr&zYvNvSk>g1Ir?_VD%- zMH8`bft({GWwgtGM-8?L54WWulGl&a?X)(@V&uXTkp;oehs2yzHO5YYSv41nYS-px zx|%zb?MBiUR?n*BTVmR#<~JUdu*~21ZrVyjgUc$|1TIam32r_#X%@>+%BhZT944fg zvsh59zFZd7qir&Ff-e;NnWovF;3j)SWCM2346D_A$Kg7d=LZ&ls5~cWBo;F3)RswN zih1MJ)BSn>lp-vRlXS)Q?0di%hfU}y?6A?U2AZaz?FB#q#GLIs9l~i)} z37f8SG`@~RQiv|e{%|H&Z-aS-!)wv3Y#J_$s%Buz!1Qh(7Q*yd{B|rfS_(NPD_w+P z5Fz>yB0%RUONgY7&P2T{(ZeI>d?d zYW5X5b4FAL2VZtiA{Y&fn*)R?`MZWNwjNCZZgbFN#qh=k^&vyWK^z854sW}Fwmte&ZCEZm~r>Sm4qUkObcvC|dkDt^9QMPC} zcT|td+W)n>6iiFm$C(FDjB<3ML82m=Tl=#1AHZ zdy+@xp2q&VF>?32tb$#k^?fGrs0w4>sb+-)>iM!Ulh|kMuqvrbh#0deNv|7##wYL@ zOVXq&n)5r?MatP{3u+JtG@l0Xf^TDa{448!B1mzAujbQt^mSiN2N{+V|t{X5*0}k?fFGsGLc8U77 z7|yn0XT@E-`xatEYH5Nj1CqZR?H1lpt4H$H8JPL@7}BVVr)1v&C+es3pQx0_fd$?0 z&3|(pA$kZ+zBvKs-jc+3ywV*AqFSPeKJbVies?W7{+TK8Fh@$fd-~x{Ok0#eG+TE} zn?b=hWOaRbeJjVqj3mc3KzZc=W^Aq=SB++vzT2}3J|eiCGS9nXX@ZJrdoV&@pTqDb z-qLn}j^J~BeR_S>G|=va4Ly85)(bMievU+8g7A*?UWXcYuGniInnAD zFBsJ9nXbO5q7cL@3<~VJR=Nl<&ORDCuyqLuNh}Tt4|H66jA!G_YC#Ys7khIUTd5qY zH#jZ~ofY&z3xWoy$^BY%-2D574;^@9(th41;?OaH;KVn4Bi5 z$}I3#=(wO?(1iZw=v%|zH*)TSV>HYe^#}j?nkYF>Xc#g*bNKQ14Gm~nR3Z?|WBbq7 z+|T<$bkrC1qcfoH<1g&C;5RcP(S9Pg3%Gs_hP6D&Pv2=t67zlCv7ELSzcdVz$O4X; z?#VO!xx#jNIrX4($0%e$J6B&dD+~-ZJykU}SMXfOk0y~Pj*j2gzJFiV{jm(>cET(< zrAGzeAJ+c5f8==+zhQD|VZ_uUJ+Ua^W^S_do>=G2Lsn)r#W#^pm%F{v&67jbz^lOe z^QwFyC3g{qza6i(Z$F<*gHF@dko?o1}TU@L)^txJ;TQ!sMP|-LOMa$ zp~~%~(!{QK6v1kYFl=TDx=Q`n1{xNryG{Yz(6ZQ`ZwT!;B0WL%Ox#&JH8B+@44+!6 zSZP7|Q`A4^ofAx-8!mFZ0p^|HU0T_t|Al#{Pr*(>%;HuQ`D$qS-^-XVT)02+&~)7E z#}Pu?Nasw#2*Jf?RKnrURZ?5JyzvygJk8EID$YU{B$O3GFYZ2zsV*v!DwQ!Q;ALVx z+#DRiUH||1z=T2G<|I!aH&DkDln`r3q9d^JuuL@nBuvAr@$+ILE$`3?hKM9&#KOC4 z=qRYg!q4hMh@=R^H;V!R%JCW|`P>4eQ9Zi72H>7^+egi{*#6L^smJc!$BwuQ{++rc zAPdjoqM~HdU}5*@>son7-nV0Gr>Zu%*EN&R)RUF4&WPctueM zHLL|12HCl;fi4ORw?kWA*xDC3+wm8_X|2Uy7LwF2G{GPz#Ok^DjeZ&j%x~0pz&?kk z9D|>#Wcy`{X+yNY+Ft;`)oXtnVR8zM6_GP}gxnY^KD=yEqF$nDKN_5P&osH=v?xZ_ z3`q9Y1rI>&S7ZmOP`<{OYDF4Zg7NvWHIjOXTuZq)uIt^F&-thy$`zhr;> zmPHwf&5}TMl-BxjJsSHy+|=9hIym6r(jtqs^QG3iYWFwiuDxr27ekiPHHU$x{%ZCb zl9c)PyI9nxX8t4E%ZR&0NyxD|bX5KWOm4N?=XU#nGsRutM_=7>5GuQ5P8!Jm@}um} z$WRh_d}h#v;ZLK@n;{d=&)ELYBBGLWvKajz0h!RqG#d7)Kj$JyPECN4Q%fKd&!LEO zkQa*mOsOOE zBv}J)f5QSoHjk<6z@2rlZtout^T_xhEAj`qDEaccN%BvTZ9lQmNy~_aR1XVT;H~pH zdaIuF+scf#x{IAm#hpFaiVZmjv7O1M8z7i8MbFSWS=|o;EB1hHM{FCMhL(7vS7Sfw zGc$A3Ok(m|RCp{0Mq<^}L73qNG(TUdjfZWl%4+PuHUb zfBhflK~h#EQqI+iLqlSyI}e}p=x$^geJ3G)kvaz&Rse5JHpOEUNqP+Y6(9BqH2a!G zS3mm#L`X<7J*etOigXzNDs0oClZ7#DXGr+F8wKs#k&Z;eG0 zL+-JM@Kol51>VTP;aj4^Sx7}mWcLWTTjBdB@hqv3y&YnX43_&0@T8aT&#SWCoj=B( zH5^%N!$-r(oLHi?!shN$h(YB-#OX`1n^v(m0gU!a9)ft>(JO1bs)w4{m;*~ z%gaYaJTJzNZB@5hQBA2ucLd*`b=to}1RRwF{YdXz%>hVEOyLexZ!vZ5q_P8#{^4c5 zTFqi8AviMyzyNz)qD@uWlVH6h{S|nns6+OTNT|T)t2YmYC#D1+0%elqHzd=HOws{% z+c7{@-_%{VVY}`dGMG#ztx&bD#Mj zLL`7{7WYC#8(BcrPtOjxHqZy=y5$#RpmJ(`Hc#c}Co>koS0oDDCk0Z1w#(p65|fYL z6{o0_RW>|(@!XCn^K~ebznC9T9VtUXSoFfs8)`E#bIF~@)Z9o!UG0nM=<~hk}&cN?9jgH+%)ap~hy#Co`B?15%&Ps16Ip z0$2m628=?AIf4VYS0|6~tOYyfDHhao)WOukRW{^{7yt%gp0wYhs6%aHHJ9O3o)fk4&ebm z+$W2H!Ei;m$TgCqKHeI&95wOfE`oDNf*34vLcHbxBBs63Q2KJlPXLm-0oP-j)kUCx zGcBp87IEJga|2M<&)($rxT)6qdHU{eK)tm^RO(-K4q<6E*_7&HET67O?*Wgq*i|3b z57%x~Yg5~{&Dvx-Ac5*G!wfiMx-DCaZ1l-Eu#x@(YRi|q9Ro#|*ujJGk|{j_pw56r z?g?t*g2U27{H)Kti5w*$Qua;-KuFdhiT(KezUm;0#t=Dz>>K)<^rWuC{^nkXyARRY7SRr1a(8adcK2-1nnfKhYLvqgzlJP z2C^siWk%-(lOp_XAzT?l&lPeT0gzX%9kjIDDc~>EOxv!WVXsik^DVyQ^D_G&nxR~CW5d>OR=k_34q1N(=7Ae zM?rkdyNlMg2zadWI{+PX*s8Gic#^Uw@Cj9GtPUN`-|W8C9;D?#2Ira|6!R8C}LS+>>LDpzzKKOZ2L)GV0wo5Hp(% z{fK2{qm%NM){t@0H1#yWeC@mHS0wRksY_J06;nR|lgw39mRa6#pZTEVCV!#+QInUKw&&+~t;~W<2l7G2o8<}#_DKiUhoE@>OR73gYI&+^Ug&~xS8)!~8UygMsk5{o^iOcE${tztS`wO>TH#r`q>v^B(mU(5i)s2^4!V>k!OhHCUkVp!}_kx+u zEM}`(uiL!=s&c;H)jJP}&x(Sjkz$~vbZL2=!*BdDBG&W@qi5C2!bxvk_E;gOz?Qi4 zJmKjJk5^fLrD$gm9 z4HPy=)AdUpD(Z*x3tr0cob~p86n?juOaRSQQXY^#6dL0-TOnNFpw~aM5q&1Co=!5G zMLqnQU2^2S1mNRt$1AC;*?8>rG+rjm**%klzFsdXeRIqyy-e^leAgG!oXmnv3H^)2 zyIYs8=)u*pv|uQ(z`HGbxOzr7)M+UfLU!e`E0`(zB>859;{B8KrRta%%e)2^6&X71 zcw&-}Jxg-)Q%*4~=w8;HwPj#^=O|Ot7Lm;?4t!d?9qeRn#a_Q#7Vky_i&CzK>B7a@ z_seAm@g~EcKZwhDy1dYD`f~f@I+((?NW5%Unq;AzXph;aB9gQOSvTk{_v~D2u^?_) zT$a6{S#P@k!nJ?`|M+p`u4)MYO6RYoN~nweTZ|DCB)1hLr{Yvmpwc%hLO|#{>vWry)DSENYbR+~_+&&NYU8b6M7K?N6X3t3D zpyhN~Mr9M?h0Z?l7HR@(ouA>?#g7WgE34RYj*`lHV?{0@y15=J!B;^go_e#V#@9<~ zVjkzIVY7YX@7TRODdH9i=8n6G-H+ueuk6p`taXG_*1Q;tJzzC=Mr2=Qe~d%~zrvLy z?dY_1kH(kJXwkpv>|-zu90i((R)7VZ67o>VtGM6wX;ot~#Dl5wC_-d_$r}!eR zbF7{)ek&`#TZTu;TC!>QrmD^ArK!BN0u>ZK&+nbFlSHN)RxMQNtA(Dr%HEOe2)r)W z!ygge<5Dncq*?Vo2J_;oFR{7xm=-$={hRkE${aJ~WZaojSD$>zvEAOf?UeFLjF5tj z+Ro+xqg5{?uxN@#FYrQn_qnzW-r7fS3%s>7 zIW9m@0=%zJsyEGp47vyHO;jl#eY7m^5cS(z7x?al@$|o!+1Dz4pSk4{7(e;LD~2a? zO_|9oTPF0ZpnQWYxoL}2<8Izrl7@H!i#iCtCD40Yu18g1mMn8jFm8-S+P--h2xm&< z<1wFQ)MV6I>29#ImEX4n_R5sjI-%Tth~kIzw>!iwsRmi2z@ksA`4tV5rOtYpbhW(q zGalzxXcZO4I>Y=_~tIeat+}xZ_PMLOz6ie|WWm z0A)#=K79x~SUxj#YQ1o5@_?7n5b{F1C9A)PTv40r88(Zq)M?R&;!NG01NYWd|EsHc9FX4S< zFL&JOk{nvt^8S(V8VhW=>^UM)240McNJo$>!JM^FHYq9e*Cc(ewQXeL2e0)tS*2Tv z^Y-XT7;h9`Sti;ko*POZWF2^a5F`0(&A0QBM;DSMQaIiIXM`)qibM;v6) zag?f|lsZB1XZ$EZg`@5VWBlCQ4JvoHG_8hZ7HaDr$}TaRt+rCB-p*>!2zqMTLtHyN znT~43CGEC^TX>pV0~_(2rzy>KR$xZ9vS`B5R8vqr-Z3Tv#deA3-}gx32o_ITM`NWH zwe-B>IZRQvL`?jaFNut<>PqQ-?xFZl7VPQET%wZ8_q;a&-Vjl8_kn0ibQBT+N3M<# z;cr3~HMnT4lyNqE8RG%&MBj0R6&|wpzT^0eOmmOhR>j4RPn7)FUClDD>6N!lSC;tq z^o6+P`_g5e*nKk*&dAf1vAyPXCFv9O-WB|0F4}Q@-;Y`cI(5hbWH4HSmy|J9e9@S$ zN=@$@0g5wKOx}6=RYdBAlk*;aN!F|j^A0z}vl5bJVy?|aGxvn-btYa}7~px2)Mu3F zScf|TNA=zG8(tdH`#SzV61#Z`tZwxMje*sxxTGq5f=+t1fcP}$eln1d-MHe1aDK`N zI?jOQtV*PA@I|?&!z0Xi8r2Vfw&S@;pkKG$|$Dm2AEM(vc<@aa1;jbmS- zgmHGbB{5-yrVNwrqO>nN4?_rnXkA4Bu>M(wi`^8sp~((ws%ZH}<7+GL-9v%69g9CT zJu)LZqxzVerkC}EwS?^@*%_bs9t+z{fDg_G`w+V)8ihgPF`o(bH>F#5IfnSbG z&`&QCmkbPk%S^i-8A}@L3Hh2^F?<~?t&Ur20JO))$9b&qg{w{>V&y$c*F0|O$f7^A ze!AxM`YnERv0pM7^ux7NUU_N0vI;GOqt!B@%5ja?r$IXW;ER{&mkuZ-p{&}-ts={c2IBJB9TZQO zyQMmHL$)G^Jg+zrh*b<)46$C_XnlF!h>smsAX|YG2p{*xY~_?;Fq$ce zDQ}7I+~A|z@6;AAD)XAwoMT#l5)9Wx&)oD9))Edv?<;2AYD(()bce{~| zw3s zKbqL|+#yQ3K}K-kN_bw(SnOw(yYwBm?ugiu1d=c;UXCp9(Uslv#%S$ZE{>|>H2CTV z+Rmf;;&z;$l`_d&uPDwj&H5a*5X!`P-UMqdS8_zG&NeUHnKw~tONr6;8WD`%SusZ^ zoVEKC{gDAhtddjGk>Xu*`DICpgrN83S7m2zh4S(2Ve(A`=M{9%;6&`tE@UU-h%6H& zRiM{7c9Pja5o4DE^^*kOJk$i#+z8ip*a-(2V~Cq+AP!lS!jH^5T6IyW+xq_Ha4%gq zz5O!8ZN~|6FZsF7P0xLs3i{_af=Ka59+j&ZIJlO+C=IIYVHQFT*UIpC=^@Ic(gBt| z9DNcj3Kv9=OK;@2yR>&Ya~?UH8d{6ksjo|V^@x*#O<5L=)8aSWwWlTbeG1%95V^Dr ze103se%_KnFmAPe;;o1ek8G*m^vZ@9Rt>f4kP0l~tmoQyR)=0q#e|7kFX)g?2#hQx zKiqPacIG`AMmhy=k?Cuo6-G*a&nF=a6Drr;2x6p8UT29dx10~PY7EhO_y5H=MzrRS z!5sCZ@xF9Tp^54DlYOGG$JdYdXD~bl5Baq?x+=_LHCyLnB8O7wy|wZ0WaD(v;VqWn#gh-tj{9^zK?%^NiuE%)Z0HpUog@2LO(Pgu{^tN)OxZV+w5&uL!YB+0c9$M0& z1pP-Ta8kpf7YlyLe*F>f)?B$eLk^4*l$@WY?$di+2=@ywv^%R01H5l#LJECl!G7HpIPARB$Y)PHv?y|c3yOJE^4W%yg}4b z_Fbgs7wp)0-&qx4YPL;1-b^?pFQtom@1<+O(w(PsaZ^LKQSS-m=pXpCG2jW4XCp0C z{tI?}ULj~`2L&_U4hts(Ydo;TLYL3|R=h;Lz-E%92l9`HFffcF<{m}~f{5)t0nHdg z2B^~B+fDm~xEUPjZ{1#Yv_qtM#X#33A>LOn<86u5riSM&m8{oVz4~;|&Z5jsW#27{ z0-x64e^C>oaJVDxz2obz*;!G_APl9~dq2Ng%&>U}2ESZM^H=e~{e$7>h=IH!`JJujYU;_WuDA6TYXJ%)3Lw zSsb-r(u~r4qW#8_%knHL_e6PGv?I1QY25=G?(W+7Z>4m7+FSP@pVo2U)0!;&=j_{G z0}!Z|_5a-YZyO2eXUFRnR2EN>0)LVjc~<&rtt#fQv7cUtJ`LATPsu`w_^$w;R?bt^ z^j~_wr&ZTamuYkas(i0m&YWDW4?iBbqaSdH#9_7gD;>iH(y`QPU8#R?WVx~v6)Fu0 z(5glQeu5&I>Gjcz5ah@_I5kd-(tgFq-)XJN6OcbNat)5?@1`~a|Qa@VZUf_?{5Rf}J-$8BkG=GbeM0xri zfIn*)aq02s@%h96p)iYGEiKOA^_1b$x|e@w2YLphP)Z}cg!_ihZ}!^7jW6-{E%wMQ z&MfkUAoLj2W!&lCjMU60guDW%YJQ$o`ePPm7;ePj(3MKtmUix*wtv1Nnq!OKOEh2d zM=JnhopLKGTr4R+zcaj)6xwRD+4aR4d@4!;k4`%;BDR5o+5m!ejhjEC_&Gp+);{tq zp8RtRI1dZxD0{=5PP%{KSMaet2yyn=j`%F|_tZW_;J!(_37Js+g^j<4fNL`Qa-AEWK-V3x`xcM}gzM~pdA!(6)7snDkA?WfQHq_^z|citw+tN@en#`jUly-TQRj2m zegCM`V_gu<;2&k&%!K>+Cbx+q2y^T^doN{mQ?~1+QZ7nyiEt24HuNWSQ|KousygI? z6L$dU>v`T;`@%(T{w)U}tk4zZf$iU3xg!8rXS}h%ydzC8sPFeMGq@>q1Yh{xrp@O9 z7VaJ}MG(bi+Oc~-{AEGT;RhfvoLKT>K${?K={(y1trm2F<$!XLIR5v!$jiN4P?x$p z00ax(u%OeH{Qrzio8|MzPym))>ji514RnPlE2_d) z;WrxX-Fo$nYLf&;Aw0L(H=Tba={ny^pBn`Ba+$wX6)#p&Jr*{FkYGgWI$#ZrJZe&d zK;IO!bwiT&|GPu=jgB?5i2uvADY)^4G_du>Q7c+!)^k#=$9X|&r1Fxv3f>4 z3_)V^ou6Bv#73(3=*5;WljJBsJt}SMI=b?`t+K5LQzCj2TN(WKkO@OeCCXrSwhA|z zq)P?MJdDSNrN3kMPdV-^iDK}js&WB932}9B{~d;Fx{8Vux3bm|e2=!ozf;32K?CSw#Z_iOuqcY@4D zhKzqT3;*$Gm4G~2O*r(sKQ#ezQF>F^BhTD1RCganL7Jfp+TmEnI+yW1y>nIG!U;)C z_+AsO9LYgj>Q#WymUz_31}zn2Sl&0~yA?&Kc410RF&t)>0p$+#Y7wzdGsM9T;`0gY zVZ_YEN^A-ZZrn*6Kho;_F_|~r#l}&s$fGaVeI$nZw|959t+)-@FIkhLv`WMmxWru!&aSs^WN%4Kzs)it76$p5WgiCJ^-X&De&lxfMI#Ul_rYQ-#}lJ zqAtBZ7DMk{=#9~tD4z!&iK`_L2$t>Bc~WLFz213p8CxAwFMmGD35`B)zW8;0o~C{6 zHVQK$HAw&%kZCdx1L%zBfUlV#b5Ipq3=xMhz>IQ;6pyln1B7_}5no^cqWb^};5!$p zNJ1gK68&)XgU z^M-DTK+`g3O%zNL0bh(RI#;ODs86^daG+~0?y6FDt^%W5VoO0J`i~ydNCMpdWPWmM#{XB&#a^!g3^aC+nLyO!RI@S*Y z){9dIV=hRN>=b+lv4dG+9S0!XQ~(29f_uCn9>xqX7C=Ilr?vgUeQwLT0fEW;#tW1A;yc=B8HYY`D%>hoL zNMAVsx()pSy0bPP$crnfW$yfuse2xvM}win0Np!?T7RU4+I1cHKlj{?`}VXj8ol4rDaPfVjzafI{2xokeu@${T)~X`_iQ1 zH_#92`n780zbAuY3)X?J?|`jG3%Rr#P%_T_0SaX0(f$x_Vm}65=a)r zU2O>?S%;l=B&TFO?d7O=9uu`#oVEAx-?CB0MVvcXZp)pw@iQ)pbr$kkD;^8;F&sre z*U6rK7gz(Ug%)5Tag<0)uS~FTqA<@hb{lqlv$94Y4?_Z$!hXlMYhvUi-wC$#FCZdW zCSdOD=FaH!Qrgnr0M9iEg>X(NM^8iF#92v3yR{<#@BxZ0QL?-3BwiUew_^{2`)xmm z6lJPV9VKTcy+?eni$MMSZRU%aDvg)UL{8+8U$GSKIjFd+0k>jH37~1Z>PYNV8NB&c zLWHYE#C6W^(7OBps60BXdKM%WKYe#mJ=rUf%`Us0bg-1S4K5@cKM(Xhhptx=g7QmJ z&ZRpb;`f2tGm!tWWI{Z(4csZ#AuG48Q2e)zSMFg1zV0Dwdu~R$ov^xVX&T>*l>*8y zlb16?@&@cC^cj#K^f;QxKCT(Skg8IfkR93 z4?xH$za*(xq)GE+%o)}B}&SgJ&Yww@!r$PdEe{3 z-oJi-zy7>k&peO&{?6mRzn|@gLu{`fYWYy}f2*4=%Gl*;`TNVjq;$%ixJQ6+l=pMlv8GUiP9~jvjqB`M`M| z7?Z_B*oMf2$X_=ksuDF|&=t?Kb~*J(rq_WB8RlL~o!Vz+%3sD*cNS+m)+9_@oDa48 zY~48QBYM5VQQb3|1%|Vf4tj#R`M0Fz#y;A|&ZXtFtwe$t<~vT`W;Iz3$@iIPp<)ll z?563xnS#}3KW~=1_WgPw+$`*M^3YF8>!Q`vSylmCwc2 z{JBpP0IbQ#sjl=fWqZpapS9@};(Sg~*8zWvc;7r?z?;llY@ntB+-*<&|oUCP0MQzA+}wHuXx04kdzcNq74WeUq?p4mdD*S#jX zkxc6oFb@{2qO0SayVc^$Ye#NryrcFqE2F<8cwUp8o&e21(&@htdst+t&my88>AeUT zdstv%(l(1bBx)`(e5YJ@1W_^AIUql_yWiPsA`X`qR^+fReUM*48eZO>QBOxn>Fu*l zLw@v1AgtaQ-V_}=TTPw$lM{0Mu)r+?TF~^vNM%FqoOuE`tL!DLVzX|LzRv(dObUTA zO)zaDi$&;%oXhW05y%|z?*sx_NrUz4r8S>*-=5Q+t+>=U3euPsaFP;-iCeo2X4M~a z%GA>xHUO9JLWD?&XUNwU(N=LTE1kp<(*Oa+acI^@v86=VG*ez;5q9Q^(#D6I+nOoh zK>JT8mcw?}0kA2KtT0CBZ@{DEk{vv*qJ8P8KaQNlQsNt+1A`X@u>5KE+0*t++Q%-l z=B0}YzEepLy3oxok_dLYmrokyo2vC-4(|#D3qXj>aNWquulFwL65H=xDkEn#UL=O| z*k$*s5?t1f|G8$}&tg0n@UR`*Li6C0{D$Fw6SIrZ`5^Ohw>O7lwvu{DkPg1#qC`Ej z-yL5V=3tN>4tetD%-;1Dt4}Ss^2%HYs*TcpGper{ za8GmEft$@pg_;hb<3M6zdQEsC5C3iG^M2Z=Nj0UT#jME4@ub6No{SMeifHw@sU)W! z@{}?azyOeDV@(A&)QysT*smq=lH?xlsYZ-lVX}sCNQfOAb73`uiIMh+x<9BMNeC~WfsjevA!vkR_7b6 z3^5(48QAF1t5E^yC6RPR{_^6V&)g9qi;?l1e)5{KG`PPbg~_K@P9-w)J>DzRRe(&W8}x=1AhHyQ^gtP5e5}UmyR`oF}#+EWJ-I zT|HlCyV03PN@GDO(ezo=)AajruBjbB*`1|4mbxlAF9kN~&+yU8N2>VWgj?<}F=mrm zR6oYdD`~h@mpeJC6w;6kTPV4LrxDzyTh<|{xsu{cGcp7-6K6^Bdm-2Yp*y`mTOpaF z#YOyCl|QW?9*gWw(p^E3?NY+{3fwT2jl+f<#9~ZZmw0rnMYvJQYAEIog26E%eXi6U zJ5E~1{s75tX^KWrvoIB-31NVlCs>NLc~>;#x0xlTBuv8&b$!9QtLSu-pHeq8j4MYQ zSAe_nz&p~!4+^JDQJol%^qQ}GN771KOo=Enuy1CUc*hWYfv&P={ZKSRyf1S}k>z5+ zl+c|#E5sotT%qXxgs8E(l>=MP4>jn&GvwOzW2uW;-Up&;(y#f;AB(0OU*M21@MHY7 z2aQPXSQmlw>XdY+EIYdAkIB-Eq`dMs4z~f3-7oU`Oi6&Ja4(yz%+OL&RL6n5TK{zW zEzb?XCP;Ox&anQTXq$44+VJCXiD|GYqyRqbBV}(jy&!NloK3J;I*JRke@Ko{JLdCZ z=#Z*T$h60XU69hoVJn`|5V0pT+X8}ViyYUB7qZdN$;CXWx~WDTh(bDuXj0b`nMKOH zTDnXr0-RwDZFcvPs*yK`H%G=_*Bd^e?p+W0*i|NkU-1_hm_=v?l3{2nE*UcI^xh6R zo^+OHO0K!>FL~v9bS{JJZxVF+utHxLu{7xHbi&m>3F zTNy52Hr|&ssWh@I8lqxwVOG%*7Km$&F2|$3#5?(8DQ4SWrA9jW-PIhGR)#ZHl8{fs z^EY}l0N_?2MFZpw-R^{?`}BwN;^C$;=zA+>$HJ7-0h!fAZf6g~IAlBiyI)CL+DTX|O z!rPuP&g$UOzbvGJFe4s*vj2yIT*9JcO3@iIgv3QM=u3FQbT~N{stN_#pDV!ngE;#R zKf_=@%Ml4zA6IJ~#!G*0Bp?|{LoF3B)11HvAxuk)i{dOJ#O-Q~d3A1@(~ES4W6YZ~ z+Gl?TzGfXVQcOluYuDS zM=w_U>mb|M^|=%dC)f-3V~RycLjb;QRo z@F+}PZon2*ifm3H>P7|9rC{vassdTX0)=zVZl_N861(KvG-fe9Tc?8~?XxSiyu5HS z(W+lh?=m=ICf;2icxs>ibOKbGH|j|MQ1pVR;mM6HumigfK`nLHj}0w; zF=@OxQ^L#_+DnL{Kq!Zxx4iAKbwPAF&4N6G=l%#Wc#C{dshvmN;poMjss~ik&%#jF zR}+eTE~u{RpPDls>bYAwJBCFUI8ofC!Zt9BJnpILh<(t1!MEL+liTETxZgpAOLoJwegHxAMUF%K&D3{2<2%XMhA&LH#s%M@*d?aiY*Y0Wo!bT~$Fg{i7H&y~(B8 z1WAeNFJw%<;{F*k_{r;hRBbWDO*{pigRn(#yZVezMJ^UAsHe3V^pUrxjE5pS%KRCV zn|YOQZW~8oDBnG;q!dqYRJP`tF~Szk2mJ8X zwm+VaeBjC>wX(2VRVttesbn11GQ9YwdHqrxt`#eSK?XJDt^+!B*5Y-1b_~KB;Tv|B zBy`*G!`b>}OTZm5!{_~5nF6>JcLPU!knd7Ezh+|kKRYg??OzsI-9OJrCw zyfng>>ZnfBh4U)NbEDDZ+O>8OWcGJvC#Ql5H0E)b{Y}o?k22Zl14jqCG<>t4R^8sJ zu6a>vAB>`w@ULU+N~)HvB%%!CzRzKM?^xm^Li>pk3#A+pDww*a@Qb~~rTt^WW{Yb# z60`QI5jCE}APVjsK3TZPcNw~icOg`^uc>m+1*4?dCU9cc)fln@5kC0=T0>{}U6%6Ny9gerKKb=aMhBni2UWXcL{L8b*GSVy3xtlePh zEy2Iv`c5AX#sMX>EYPJdQ=G8EAm#KiQPJsxnyM|_KQkre%Je5}G0C}12bATj8998~k@VYA^;j*2*wx%}ZyLnx;Y$K{bt*s^%U#agJVo)orm;x-)aov<)^Tm0jn z8ur|Q70->Sz8P%zxJ$3&JyeIDb@xsAEepZ*A{cLI0+q_=L6bTo+n)rV(5pTEiRc(z zbgJ-j-Ar)pA#Lp7)%Q|QAHK|)f3Q5ycl-Pum7+P`3iA&1>$?b?o}0Dy)nuU?_5dU9 zDmLKMnN2nL}15 zbn_l{P1{_}b2TBZ_ErZy{j$na|7>c;uwomB|EAa7K7-oMg+g~+69P`dWO2KUiQ)MR z2Spz#1Tjm4e@yZ`{?fvCWL09!;`#P+Y`-89hy?M~2+bWuvDPjd-)8X^tqNjcZ4pLI z@>QJl(jL*LF@_I!3yo?^vWF!0E2#kJXyB*c2I)!(AL|_+AC`2vCEiK(W?^r34;_zM zOfN?QS=GKj@e67|4D1+f^3xPMy0T@bXZ^1mQW|$b|5_t=5sWj^t^`TfD~vbI`cj*G<&CMm{`1m8=4Ogi-&kN<@qv+&=3 zpHCMBtWozsZ0ep}-XqOPp#`l;>EJ>1?3&Cme4;FoHUKZ|4DDXp#_skA7(e;3bPMP9 zFFsY-KJ>uj!@^+$B!>ehibO%nQ%Mh}4s~t3l}r>-^m1U5ZtOQ4b?Q4ay>=R?;)dS* z)~h{5jm%t%v#saK?XZaI=}APgD`oe*pQpaQp2WgR?$1jPe*f1h!S7daDh&ju(rT~J zpRD*@5x&0LA#}8lV3dg8>{|O~INb-x%>Zi^r?^}ypn%|1E2$xW8PVHuEFm^^^UMo5 zvH87&rgyYI&r3h;*xBDIm$t?q{#(m`7x$?{K0l{|k?H*o!{_K?hNFcsXIFPE${qE6 zHW=$Y2oHv`_-I~(r>r6)+X67;mLf8uzxtPltL`~2 zv3tu_Z8CJTH>W^j&3Weg_UO@J+4Ccg!2Squ6tHJ{wCP)CA3pDnEuMZ9nVBNVg3F)- zsEpUUN@Ks2u%C!a{fY-c1yVeaHMLX~UmB+8as8sbM;vN}bU6FUr`X8C?S=9Jafy+& zoEfxk1WQ4v7wF=muB~R%1oW=V?UdNHVfrXn%NWSXxeEkt@xBJYXh8k?SF0|=?WlXK)*?&2CvBQet123; zWdY1ayhFkjI91?~bG=Fx%N#@AZK$b|Nxzr-OO5CV@+3p|^xMfWPNy{I%nhRAhyUIW zZtM+&*%hW82|i8N`LNdFq46mAZtz#1fMk)lO^uY7mYjTg*R@XZO`E$IpF`0ReV^`&nJ7Gi+H#_N?y7y!tCxF!4>Z&QPEAv7t#w)c4%YsSReXB21I0T7q4D5xLPN=}mOHl^WC3^A zLTVg$21YqRQH_qM|CP3b>OW&q&A$x=(RK#@=3>=Et8duB+bpd(82(MG9z^X7BnyC- zNpjMwu~T4ze`(5r-UXa`anDP42E;^Jr6HQpLDJkI9Y}(UuJBxQ(fU20s=}IH6&0d# zzz$R4|0jmE-2dssWYY95{8KQh!trth12388LtuF#Ie-{&xy3i+;J@4s1&(8DvC+BO zw6Etu$?v!VoB-giKJpd!UU&FM#lx@!H8JEfS^l*i417sEg0;{`rstop_flag == 0) { - uv__update_time(loop); + /* Maintain backwards compatibility by processing timers before entering the + * while loop for UV_RUN_DEFAULT. Otherwise timers only need to be executed + * once, which should be done after polling in order to maintain proper + * execution order of the conceptual event loop. */ + if (mode == UV_RUN_DEFAULT) { + if (r) + uv__update_time(loop); uv__run_timers(loop); + } + while (r != 0 && loop->stop_flag == 0) { can_sleep = QUEUE_EMPTY(&loop->pending_queue) && QUEUE_EMPTY(&loop->idle_handles); @@ -424,18 +431,8 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { uv__run_check(loop); uv__run_closing_handles(loop); - if (mode == UV_RUN_ONCE) { - /* UV_RUN_ONCE implies forward progress: at least one callback must have - * been invoked when it returns. uv__io_poll() can return without doing - * I/O (meaning: no callbacks) when its timeout expires - which means we - * have pending timers that satisfy the forward progress constraint. - * - * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from - * the check. - */ - uv__update_time(loop); - uv__run_timers(loop); - } + uv__update_time(loop); + uv__run_timers(loop); r = uv__loop_alive(loop); if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT) diff --git a/src/win/core.c b/src/win/core.c index 09a3c7b1865..a52af5a1b4b 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -609,10 +609,17 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { if (!r) uv_update_time(loop); - while (r != 0 && loop->stop_flag == 0) { - uv_update_time(loop); + /* Maintain backwards compatibility by processing timers before entering the + * while loop for UV_RUN_DEFAULT. Otherwise timers only need to be executed + * once, which should be done after polling in order to maintain proper + * execution order of the conceptual event loop. */ + if (mode == UV_RUN_DEFAULT) { + if (r) + uv_update_time(loop); uv__run_timers(loop); + } + while (r != 0 && loop->stop_flag == 0) { can_sleep = loop->pending_reqs_tail == NULL && loop->idle_handles == NULL; uv__process_reqs(loop); @@ -645,18 +652,8 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { uv__check_invoke(loop); uv__process_endgames(loop); - if (mode == UV_RUN_ONCE) { - /* UV_RUN_ONCE implies forward progress: at least one callback must have - * been invoked when it returns. uv__io_poll() can return without doing - * I/O (meaning: no callbacks) when its timeout expires - which means we - * have pending timers that satisfy the forward progress constraint. - * - * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from - * the check. - */ - uv_update_time(loop); - uv__run_timers(loop); - } + uv_update_time(loop); + uv__run_timers(loop); r = uv__loop_alive(loop); if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT) diff --git a/test/test-list.h b/test/test-list.h index 4cd06356ee9..13c96d1dc27 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -233,6 +233,8 @@ TEST_DECLARE (timer_from_check) TEST_DECLARE (timer_is_closing) TEST_DECLARE (timer_null_callback) TEST_DECLARE (timer_early_check) +TEST_DECLARE (timer_no_double_call_once) +TEST_DECLARE (timer_no_double_call_nowait) TEST_DECLARE (idle_starvation) TEST_DECLARE (idle_check) TEST_DECLARE (loop_handles) @@ -842,6 +844,8 @@ TASK_LIST_START TEST_ENTRY (timer_is_closing) TEST_ENTRY (timer_null_callback) TEST_ENTRY (timer_early_check) + TEST_ENTRY (timer_no_double_call_once) + TEST_ENTRY (timer_no_double_call_nowait) TEST_ENTRY (idle_starvation) TEST_ENTRY (idle_check) diff --git a/test/test-timer.c b/test/test-timer.c index 1753fbccc07..eb54bb25f0c 100644 --- a/test/test-timer.c +++ b/test/test-timer.c @@ -30,6 +30,7 @@ static int twice_close_cb_called = 0; static int repeat_cb_called = 0; static int repeat_close_cb_called = 0; static int order_cb_called = 0; +static int timer_check_double_call_called = 0; static uint64_t start_time; static uv_timer_t tiny_timer; static uv_timer_t huge_timer1; @@ -368,3 +369,41 @@ TEST_IMPL(timer_early_check) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } + +static void timer_check_double_call(uv_timer_t* handle) { + timer_check_double_call_called++; +} + +TEST_IMPL(timer_no_double_call_once) { + uv_timer_t timer_handle; + const uint64_t timeout_ms = 10; + + ASSERT_EQ(0, uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT_EQ(0, uv_timer_start(&timer_handle, + timer_check_double_call, + timeout_ms, + timeout_ms)); + uv_sleep(timeout_ms * 2); + ASSERT_EQ(1, uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_EQ(1, timer_check_double_call_called); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} + +TEST_IMPL(timer_no_double_call_nowait) { + uv_timer_t timer_handle; + const uint64_t timeout_ms = 10; + + ASSERT_EQ(0, uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT_EQ(0, uv_timer_start(&timer_handle, + timer_check_double_call, + timeout_ms, + timeout_ms)); + uv_sleep(timeout_ms * 2); + ASSERT_EQ(1, uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + ASSERT_EQ(1, timer_check_double_call_called); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} From 7b84d5b0ecb737b4cc30ce63eade690d994e00a6 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Mon, 20 Mar 2023 10:27:08 -0600 Subject: [PATCH 332/713] doc: add trevnorris to maintainers (#3931) --- MAINTAINERS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 477901f8680..a55606bf28e 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -22,6 +22,8 @@ libuv is currently managed by the following individuals: - GPG key: 612F 0EAD 9401 6223 79DF 4402 F28C 3C8D A33C 03BE (pubkey-santigimeno) * **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul)) - GPG key: FDF5 1936 4458 319F A823 3DC9 410E 5553 AE9B C059 (pubkey-saghul) +* **Trevor Norris** ([@trevnorris](https://github.com/trevnorris)) + - GPG key: AEFC 279A 0C93 0676 7E58 29A1 251C A676 820D C7F3 (pubkey-trevnorris) ## Project Maintainers emeriti From 0c8eccc3fc1bdfc1cdf6c3385c4a031a1a39b2be Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 28 Mar 2023 11:58:56 +0200 Subject: [PATCH 333/713] linux: remove epoll_pwait() emulation code path (#3936) This was removed before in 2018 but then reinstated again in 2019 to fix building with old Android SDKs. Well, time marches on; this time it's gone for good. Refs: https://github.com/libuv/libuv/pull/1372 Refs: https://github.com/libuv/libuv/pull/2358 --- src/unix/linux.c | 58 +++++++----------------------------------------- 1 file changed, 8 insertions(+), 50 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 049ef1f9cd7..e5def90d7ee 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -307,18 +307,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * that being the largest value I have seen in the wild (and only once.) */ static const int max_safe_timeout = 1789569; - static int no_epoll_pwait_cached; - static int no_epoll_wait_cached; - int no_epoll_pwait; - int no_epoll_wait; struct epoll_event events[1024]; struct epoll_event* pe; struct epoll_event e; int real_timeout; QUEUE* q; uv__io_t* w; + sigset_t* sigmask; sigset_t sigset; - uint64_t sigmask; uint64_t base; int have_signals; int nevents; @@ -372,11 +368,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w->events = w->pevents; } - sigmask = 0; + sigmask = NULL; if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { sigemptyset(&sigset); sigaddset(&sigset, SIGPROF); - sigmask |= 1 << (SIGPROF - 1); + sigmask = &sigset; } assert(timeout >= -1); @@ -393,15 +389,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { user_timeout = 0; } - /* You could argue there is a dependency between these two but - * ultimately we don't care about their ordering with respect - * to one another. Worst case, we make a few system calls that - * could have been avoided because another thread already knows - * they fail with ENOSYS. Hardly the end of the world. - */ - no_epoll_pwait = uv__load_relaxed(&no_epoll_pwait_cached); - no_epoll_wait = uv__load_relaxed(&no_epoll_wait_cached); - for (;;) { /* Only need to set the provider_entry_time if timeout != 0. The function * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. @@ -415,34 +402,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) timeout = max_safe_timeout; - if (sigmask != 0 && no_epoll_pwait != 0) - if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) - abort(); - - if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) { - nfds = epoll_pwait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout, - &sigset); - if (nfds == -1 && errno == ENOSYS) { - uv__store_relaxed(&no_epoll_pwait_cached, 1); - no_epoll_pwait = 1; - } - } else { - nfds = epoll_wait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout); - if (nfds == -1 && errno == ENOSYS) { - uv__store_relaxed(&no_epoll_wait_cached, 1); - no_epoll_wait = 1; - } - } - - if (sigmask != 0 && no_epoll_pwait != 0) - if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)) - abort(); + nfds = epoll_pwait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout, + sigmask); /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the @@ -471,12 +435,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (nfds == -1) { - if (errno == ENOSYS) { - /* epoll_wait() or epoll_pwait() failed, try the other system call. */ - assert(no_epoll_wait == 0 || no_epoll_pwait == 0); - continue; - } - if (errno != EINTR) abort(); From 28b9f1e68b399d3052b0f6b7a2fad9530f486518 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 31 Mar 2023 10:09:48 +0200 Subject: [PATCH 334/713] linux: replace unsafe macro with inline function (#3933) Replace the throw-type-safety-to-the-wind CAST() macro with an inline function that is hopefully harder to misuse. It should make the inotify code slightly more legible if nothing else. --- src/unix/internal.h | 1 - src/unix/linux.c | 125 ++++++++++++++++++++++++-------------------- 2 files changed, 69 insertions(+), 57 deletions(-) diff --git a/src/unix/internal.h b/src/unix/internal.h index 150f30a2ad5..d439ae6dd3d 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -393,7 +393,6 @@ UV_UNUSED(static int uv__stat(const char* path, struct stat* s)) { } #if defined(__linux__) -int uv__inotify_fork(uv_loop_t* loop, void* old_watchers); ssize_t uv__fs_copy_file_range(int fd_in, off_t* off_in, diff --git a/src/unix/linux.c b/src/unix/linux.c index e5def90d7ee..e6ce2f3cc81 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -124,8 +124,6 @@ # include #endif /* HAVE_IFADDRS_H */ -#define CAST(p) ((struct watcher_root*)(p)) - struct watcher_list { RB_ENTRY(watcher_list) entry; QUEUE watchers; @@ -138,6 +136,7 @@ struct watcher_root { struct watcher_list* rbh_root; }; +static int uv__inotify_fork(uv_loop_t* loop, struct watcher_list* root); static void uv__inotify_read(uv_loop_t* loop, uv__io_t* w, unsigned int revents); @@ -149,6 +148,16 @@ static void maybe_free_watcher_list(struct watcher_list* w, RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers) +static struct watcher_root* uv__inotify_watchers(uv_loop_t* loop) { + /* This cast works because watcher_root is a struct with a pointer as its + * sole member. Such type punning is unsafe in the presence of strict + * pointer aliasing (and is just plain nasty) but that is why libuv + * is compiled with -fno-strict-aliasing. + */ + return (struct watcher_root*) &loop->inotify_watchers; +} + + ssize_t uv__fs_copy_file_range(int fd_in, off_t* off_in, @@ -219,9 +228,9 @@ int uv__platform_loop_init(uv_loop_t* loop) { int uv__io_fork(uv_loop_t* loop) { int err; - void* old_watchers; + struct watcher_list* root; - old_watchers = loop->inotify_watchers; + root = uv__inotify_watchers(loop)->rbh_root; uv__close(loop->backend_fd); loop->backend_fd = -1; @@ -231,7 +240,7 @@ int uv__io_fork(uv_loop_t* loop) { if (err) return err; - return uv__inotify_fork(loop, old_watchers); + return uv__inotify_fork(loop, root); } @@ -1300,7 +1309,7 @@ static int init_inotify(uv_loop_t* loop) { } -int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) { +static int uv__inotify_fork(uv_loop_t* loop, struct watcher_list* root) { /* Open the inotify_fd, and re-arm all the inotify watchers. */ int err; struct watcher_list* tmp_watcher_list_iter; @@ -1311,54 +1320,55 @@ int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) { uv_fs_event_t* handle; char* tmp_path; - if (old_watchers != NULL) { - /* We must restore the old watcher list to be able to close items - * out of it. - */ - loop->inotify_watchers = old_watchers; - - QUEUE_INIT(&tmp_watcher_list.watchers); - /* Note that the queue we use is shared with the start and stop() - * functions, making QUEUE_FOREACH unsafe to use. So we use the - * QUEUE_MOVE trick to safely iterate. Also don't free the watcher - * list until we're done iterating. c.f. uv__inotify_read. - */ - RB_FOREACH_SAFE(watcher_list, watcher_root, - CAST(&old_watchers), tmp_watcher_list_iter) { - watcher_list->iterating = 1; - QUEUE_MOVE(&watcher_list->watchers, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - handle = QUEUE_DATA(q, uv_fs_event_t, watchers); - /* It's critical to keep a copy of path here, because it - * will be set to NULL by stop() and then deallocated by - * maybe_free_watcher_list - */ - tmp_path = uv__strdup(handle->path); - assert(tmp_path != NULL); - QUEUE_REMOVE(q); - QUEUE_INSERT_TAIL(&watcher_list->watchers, q); - uv_fs_event_stop(handle); + if (root == NULL) + return 0; - QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers); - handle->path = tmp_path; - } - watcher_list->iterating = 0; - maybe_free_watcher_list(watcher_list, loop); - } + /* We must restore the old watcher list to be able to close items + * out of it. + */ + loop->inotify_watchers = root; - QUEUE_MOVE(&tmp_watcher_list.watchers, &queue); + QUEUE_INIT(&tmp_watcher_list.watchers); + /* Note that the queue we use is shared with the start and stop() + * functions, making QUEUE_FOREACH unsafe to use. So we use the + * QUEUE_MOVE trick to safely iterate. Also don't free the watcher + * list until we're done iterating. c.f. uv__inotify_read. + */ + RB_FOREACH_SAFE(watcher_list, watcher_root, + uv__inotify_watchers(loop), tmp_watcher_list_iter) { + watcher_list->iterating = 1; + QUEUE_MOVE(&watcher_list->watchers, &queue); while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - QUEUE_REMOVE(q); - handle = QUEUE_DATA(q, uv_fs_event_t, watchers); - tmp_path = handle->path; - handle->path = NULL; - err = uv_fs_event_start(handle, handle->cb, tmp_path, 0); - uv__free(tmp_path); - if (err) - return err; + q = QUEUE_HEAD(&queue); + handle = QUEUE_DATA(q, uv_fs_event_t, watchers); + /* It's critical to keep a copy of path here, because it + * will be set to NULL by stop() and then deallocated by + * maybe_free_watcher_list + */ + tmp_path = uv__strdup(handle->path); + assert(tmp_path != NULL); + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&watcher_list->watchers, q); + uv_fs_event_stop(handle); + + QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers); + handle->path = tmp_path; } + watcher_list->iterating = 0; + maybe_free_watcher_list(watcher_list, loop); + } + + QUEUE_MOVE(&tmp_watcher_list.watchers, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + QUEUE_REMOVE(q); + handle = QUEUE_DATA(q, uv_fs_event_t, watchers); + tmp_path = handle->path; + handle->path = NULL; + err = uv_fs_event_start(handle, handle->cb, tmp_path, 0); + uv__free(tmp_path); + if (err) + return err; } return 0; @@ -1368,7 +1378,7 @@ int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) { static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) { struct watcher_list w; w.wd = wd; - return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w); + return RB_FIND(watcher_root, uv__inotify_watchers(loop), &w); } @@ -1376,7 +1386,7 @@ static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) { /* if the watcher_list->watchers is being iterated over, we can't free it. */ if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) { /* No watchers left for this path. Clean up. */ - RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w); + RB_REMOVE(watcher_root, uv__inotify_watchers(loop), w); inotify_rm_watch(loop->inotify_fd, w->wd); uv__free(w); } @@ -1470,6 +1480,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, const char* path, unsigned int flags) { struct watcher_list* w; + uv_loop_t* loop; size_t len; int events; int err; @@ -1478,7 +1489,9 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (uv__is_active(handle)) return UV_EINVAL; - err = init_inotify(handle->loop); + loop = handle->loop; + + err = init_inotify(loop); if (err) return err; @@ -1491,11 +1504,11 @@ int uv_fs_event_start(uv_fs_event_t* handle, | IN_MOVED_FROM | IN_MOVED_TO; - wd = inotify_add_watch(handle->loop->inotify_fd, path, events); + wd = inotify_add_watch(loop->inotify_fd, path, events); if (wd == -1) return UV__ERR(errno); - w = find_watcher(handle->loop, wd); + w = find_watcher(loop, wd); if (w) goto no_insert; @@ -1508,7 +1521,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, w->path = memcpy(w + 1, path, len); QUEUE_INIT(&w->watchers); w->iterating = 0; - RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w); + RB_INSERT(watcher_root, uv__inotify_watchers(loop), w); no_insert: uv__handle_start(handle); From 244df24bf411a396ceaf69f8a80a98e5629ee584 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 2 Apr 2023 00:20:26 +0200 Subject: [PATCH 335/713] linux: remove arm oabi support (#3942) The last major distro that supported the oabi calling convention was Debian 5 (Lenny) and that went out of support in February 2012. It seems like a fairly safe assumption that nothing speaks oabi anymore in this day and age. Fixes: https://github.com/libuv/libuv/issues/3935 --- src/unix/linux.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index e6ce2f3cc81..0512417af72 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -47,14 +47,6 @@ #include #include -#if defined(__arm__) -# if defined(__thumb__) || defined(__ARM_EABI__) -# define UV_SYSCALL_BASE 0 -# else -# define UV_SYSCALL_BASE 0x900000 -# endif -#endif /* __arm__ */ - #ifndef __NR_copy_file_range # if defined(__x86_64__) # define __NR_copy_file_range 326 @@ -63,7 +55,7 @@ # elif defined(__s390__) # define __NR_copy_file_range 375 # elif defined(__arm__) -# define __NR_copy_file_range (UV_SYSCALL_BASE + 391) +# define __NR_copy_file_range 391 # elif defined(__aarch64__) # define __NR_copy_file_range 285 # elif defined(__powerpc__) @@ -81,7 +73,7 @@ # elif defined(__aarch64__) # define __NR_statx 397 # elif defined(__arm__) -# define __NR_statx (UV_SYSCALL_BASE + 397) +# define __NR_statx 397 # elif defined(__ppc__) # define __NR_statx 383 # elif defined(__s390__) @@ -97,7 +89,7 @@ # elif defined(__aarch64__) # define __NR_getrandom 384 # elif defined(__arm__) -# define __NR_getrandom (UV_SYSCALL_BASE + 384) +# define __NR_getrandom 384 # elif defined(__ppc__) # define __NR_getrandom 359 # elif defined(__s390__) From 1eae55984d90e63269b5c3a9279e68f5211e26ab Mon Sep 17 00:00:00 2001 From: Stacey Marshall Date: Tue, 11 Apr 2023 18:49:25 +0100 Subject: [PATCH 336/713] unix,sunos: SO_REUSEPORT not valid on all sockets (#3949) Issue observed on Solaris with ISC BIND 9.18 which reported "unable to open route socket: unexpected error". illumos did not hit it because it does not have SO_REUSEPORT (open RFE https://www.illumos.org/issues/12455) --- src/unix/udp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index 110467ae5fc..f556808fbae 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -448,7 +448,8 @@ static int uv__set_reuse(int fd) { if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); } -#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) +#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) && \ + !defined(__sun__) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); #else From e189c31375b6b872ac63b30df370ef8de884cb17 Mon Sep 17 00:00:00 2001 From: Jason Zhang Date: Wed, 12 Apr 2023 03:20:31 +0930 Subject: [PATCH 337/713] doc: consistent single backquote in misc.rst (#3946) Fixes: https://github.com/libuv/libuv/issues/3928 --- docs/src/misc.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 39241df8cbc..e8b9a4c838d 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -214,7 +214,7 @@ API type of the stdio streams. For :man:`isatty(3)` equivalent functionality use this function and test - for ``UV_TTY``. + for `UV_TTY`. .. c:function:: int uv_replace_allocator(uv_malloc_func malloc_func, uv_realloc_func realloc_func, uv_calloc_func calloc_func, uv_free_func free_func) @@ -228,8 +228,8 @@ API after all resources have been freed and thus libuv doesn't reference any allocated memory chunk. - On success, it returns 0, if any of the function pointers is NULL it - returns UV_EINVAL. + On success, it returns 0, if any of the function pointers is `NULL` it + returns `UV_EINVAL`. .. warning:: There is no protection against changing the allocator multiple times. If the user changes it they are responsible for making @@ -368,7 +368,7 @@ API .. c:function:: int uv_cpumask_size(void) Returns the maximum size of the mask used for process/thread affinities, - or ``UV_ENOTSUP`` if affinities are not supported on the current platform. + or `UV_ENOTSUP` if affinities are not supported on the current platform. .. versionadded:: 1.45.0 From 2f33980a9141bd49cb2c34361854355b23b1e6fc Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Wed, 12 Apr 2023 13:54:22 -0600 Subject: [PATCH 338/713] src: switch to use C11 atomics where available (#3950) Switch all code in unix/ to use C11 atomics directly. Change uv_library_shutdown() to use an exchange instead of load/store. Unfortunately MSVC only started supporting C11 atomics in VS2022 version 17.5 Preview 2 as experimental. So resort to using the Interlocked API. Ref: https://devblogs.microsoft.com/cppblog/c11-atomics-in-visual-studio-2022-version-17-5-preview-2/ Fixes: https://github.com/libuv/libuv/issues/3948 --- src/unix/core.c | 6 +++--- src/unix/fs.c | 31 ++++++++++++++++--------------- src/unix/kqueue.c | 12 ++++++++---- src/unix/linux.c | 6 +++--- src/uv-common.c | 3 +-- src/uv-common.h | 14 +++++++++----- 6 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 9343ee724db..3dd7a94ca4d 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -233,10 +233,10 @@ int uv__getiovmax(void) { #if defined(IOV_MAX) return IOV_MAX; #elif defined(_SC_IOV_MAX) - static int iovmax_cached = -1; + static _Atomic int iovmax_cached = -1; int iovmax; - iovmax = uv__load_relaxed(&iovmax_cached); + iovmax = atomic_load_explicit(&iovmax_cached, memory_order_relaxed); if (iovmax != -1) return iovmax; @@ -248,7 +248,7 @@ int uv__getiovmax(void) { if (iovmax == -1) iovmax = 1; - uv__store_relaxed(&iovmax_cached, iovmax); + atomic_store_explicit(&iovmax_cached, iovmax, memory_order_relaxed); return iovmax; #else diff --git a/src/unix/fs.c b/src/unix/fs.c index 9c8ef6cc066..a54038c92e2 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -309,7 +309,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) { static uv_once_t once = UV_ONCE_INIT; int r; #ifdef O_CLOEXEC - static int no_cloexec_support; + static _Atomic int no_cloexec_support; #endif static const char pattern[] = "XXXXXX"; static const size_t pattern_size = sizeof(pattern) - 1; @@ -334,7 +334,8 @@ static int uv__fs_mkstemp(uv_fs_t* req) { uv_once(&once, uv__mkostemp_initonce); #ifdef O_CLOEXEC - if (uv__load_relaxed(&no_cloexec_support) == 0 && uv__mkostemp != NULL) { + if (atomic_load_explicit(&no_cloexec_support, memory_order_relaxed) == 0 && + uv__mkostemp != NULL) { r = uv__mkostemp(path, O_CLOEXEC); if (r >= 0) @@ -347,7 +348,7 @@ static int uv__fs_mkstemp(uv_fs_t* req) { /* We set the static variable so that next calls don't even try to use mkostemp. */ - uv__store_relaxed(&no_cloexec_support, 1); + atomic_store_explicit(&no_cloexec_support, 1, memory_order_relaxed); } #endif /* O_CLOEXEC */ @@ -457,7 +458,7 @@ static ssize_t uv__fs_preadv(uv_file fd, static ssize_t uv__fs_read(uv_fs_t* req) { #if defined(__linux__) - static int no_preadv; + static _Atomic int no_preadv; #endif unsigned int iovmax; ssize_t result; @@ -481,7 +482,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) { result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); #else # if defined(__linux__) - if (uv__load_relaxed(&no_preadv)) retry: + if (atomic_load_explicit(&no_preadv, memory_order_relaxed)) retry: # endif { result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off); @@ -493,7 +494,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) { req->nbufs, req->off); if (result == -1 && errno == ENOSYS) { - uv__store_relaxed(&no_preadv, 1); + atomic_store_explicit(&no_preadv, 1, memory_order_relaxed); goto retry; } } @@ -899,14 +900,14 @@ static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) { #ifdef __linux__ static unsigned uv__kernel_version(void) { - static unsigned cached_version; + static _Atomic unsigned cached_version; struct utsname u; unsigned version; unsigned major; unsigned minor; unsigned patch; - version = uv__load_relaxed(&cached_version); + version = atomic_load_explicit(&cached_version, memory_order_relaxed); if (version != 0) return version; @@ -917,7 +918,7 @@ static unsigned uv__kernel_version(void) { return 0; version = major * 65536 + minor * 256 + patch; - uv__store_relaxed(&cached_version, version); + atomic_store_explicit(&cached_version, version, memory_order_relaxed); return version; } @@ -959,10 +960,10 @@ static int uv__is_cifs_or_smb(int fd) { static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off, int out_fd, size_t len) { - static int no_copy_file_range_support; + static _Atomic int no_copy_file_range_support; ssize_t r; - if (uv__load_relaxed(&no_copy_file_range_support)) { + if (atomic_load_explicit(&no_copy_file_range_support, memory_order_relaxed)) { errno = ENOSYS; return -1; } @@ -981,7 +982,7 @@ static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off, errno = ENOSYS; /* Use fallback. */ break; case ENOSYS: - uv__store_relaxed(&no_copy_file_range_support, 1); + atomic_store_explicit(&no_copy_file_range_support, 1, memory_order_relaxed); break; case EPERM: /* It's been reported that CIFS spuriously fails. @@ -1530,14 +1531,14 @@ static int uv__fs_statx(int fd, uv_stat_t* buf) { STATIC_ASSERT(UV_ENOSYS != -1); #ifdef __linux__ - static int no_statx; + static _Atomic int no_statx; struct uv__statx statxbuf; int dirfd; int flags; int mode; int rc; - if (uv__load_relaxed(&no_statx)) + if (atomic_load_explicit(&no_statx, memory_order_relaxed)) return UV_ENOSYS; dirfd = AT_FDCWD; @@ -1571,7 +1572,7 @@ static int uv__fs_statx(int fd, * implemented, rc might return 1 with 0 set as the error code in which * case we return ENOSYS. */ - uv__store_relaxed(&no_statx, 1); + atomic_store_explicit(&no_statx, 1, memory_order_relaxed); return UV_ENOSYS; } diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index c68cd451b88..deb486bae7a 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -60,7 +60,7 @@ int uv__kqueue_init(uv_loop_t* loop) { #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 -static int uv__has_forked_with_cfrunloop; +static _Atomic int uv__has_forked_with_cfrunloop; #endif int uv__io_fork(uv_loop_t* loop) { @@ -82,7 +82,9 @@ int uv__io_fork(uv_loop_t* loop) { process. So we sidestep the issue by pretending like we never started it in the first place. */ - uv__store_relaxed(&uv__has_forked_with_cfrunloop, 1); + atomic_store_explicit(&uv__has_forked_with_cfrunloop, + 1, + memory_order_relaxed); uv__free(loop->cf_state); loop->cf_state = NULL; } @@ -530,7 +532,8 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (!(statbuf.st_mode & S_IFDIR)) goto fallback; - if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop)) { + if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop, + memory_order_relaxed)) { int r; /* The fallback fd is no longer needed */ uv__close_nocheckstdio(fd); @@ -565,7 +568,8 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { uv__handle_stop(handle); #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 - if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop)) + if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop, + memory_order_relaxed)) if (handle->cf_cb != NULL) r = uv__fsevents_close(handle); #endif diff --git a/src/unix/linux.c b/src/unix/linux.c index 0512417af72..a30f1bfbd3f 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -579,7 +579,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } uint64_t uv__hrtime(uv_clocktype_t type) { - static clock_t fast_clock_id = -1; + static _Atomic clock_t fast_clock_id = -1; struct timespec t; clock_t clock_id; @@ -595,7 +595,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) { if (type != UV_CLOCK_FAST) goto done; - clock_id = uv__load_relaxed(&fast_clock_id); + clock_id = atomic_load_explicit(&fast_clock_id, memory_order_relaxed); if (clock_id != -1) goto done; @@ -604,7 +604,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) { if (t.tv_nsec <= 1 * 1000 * 1000) clock_id = CLOCK_MONOTONIC_COARSE; - uv__store_relaxed(&fast_clock_id, clock_id); + atomic_store_explicit(&fast_clock_id, clock_id, memory_order_relaxed); done: diff --git a/src/uv-common.c b/src/uv-common.c index 1031be4a118..cec771fab21 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -944,7 +944,7 @@ __attribute__((destructor)) void uv_library_shutdown(void) { static int was_shutdown; - if (uv__load_relaxed(&was_shutdown)) + if (uv__exchange_int_relaxed(&was_shutdown, 1)) return; uv__process_title_cleanup(); @@ -955,7 +955,6 @@ void uv_library_shutdown(void) { #else uv__threadpool_cleanup(); #endif - uv__store_relaxed(&was_shutdown, 1); } diff --git a/src/uv-common.h b/src/uv-common.h index 26d0e49b805..2720121addc 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -37,6 +37,10 @@ #include "queue.h" #include "strscpy.h" +#ifndef _MSC_VER +# include +#endif + #if EDOM > 0 # define UV__ERR(x) (-(x)) #else @@ -61,12 +65,12 @@ extern int snprintf(char*, size_t, const char*, ...); void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)]) #endif -#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 7) -#define uv__load_relaxed(p) __atomic_load_n(p, __ATOMIC_RELAXED) -#define uv__store_relaxed(p, v) __atomic_store_n(p, v, __ATOMIC_RELAXED) +#ifdef _MSC_VER +#define uv__exchange_int_relaxed(p, v) \ + InterlockedExchangeNoFence((LONG volatile*)(p), v) #else -#define uv__load_relaxed(p) (*p) -#define uv__store_relaxed(p, v) do *p = v; while (0) +#define uv__exchange_int_relaxed(p, v) \ + atomic_exchange_explicit((_Atomic int*)(p), v, memory_order_relaxed) #endif #define UV__UDP_DGRAM_MAXSIZE (64 * 1024) From cb5da592268551592f86b291652193f23270a8cb Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 14 Apr 2023 16:54:28 +0200 Subject: [PATCH 339/713] test: don't use static buffer for formatting (#3953) Don't use a static buffer to hold human-readable "big" numbers. The buffer isn't big enough for benchmarks like fs_stat that print a large number of them. Have the caller pass in a buffer instead. --- test/benchmark-async-pummel.c | 5 +++-- test/benchmark-async.c | 3 ++- test/benchmark-fs-stat.c | 10 ++++++---- test/benchmark-million-async.c | 7 ++++--- test/benchmark-queue-work.c | 7 +++++-- test/runner.c | 22 ++++------------------ test/task.h | 4 ++-- 7 files changed, 26 insertions(+), 32 deletions(-) diff --git a/test/benchmark-async-pummel.c b/test/benchmark-async-pummel.c index 93f9b1aa996..bec91850616 100644 --- a/test/benchmark-async-pummel.c +++ b/test/benchmark-async-pummel.c @@ -62,6 +62,7 @@ static void pummel(void* arg) { static int test_async_pummel(int nthreads) { + char fmtbuf[2][32]; uv_thread_t* tids; uv_async_t handle; uint64_t time; @@ -88,9 +89,9 @@ static int test_async_pummel(int nthreads) { printf("async_pummel_%d: %s callbacks in %.2f seconds (%s/sec)\n", nthreads, - fmt(callbacks), + fmt(&fmtbuf[0], callbacks), time / 1e9, - fmt(callbacks / (time / 1e9))); + fmt(&fmtbuf[1], callbacks / (time / 1e9))); free(tids); diff --git a/test/benchmark-async.c b/test/benchmark-async.c index 59aed6f7bf5..d4b7c8bd914 100644 --- a/test/benchmark-async.c +++ b/test/benchmark-async.c @@ -73,6 +73,7 @@ static void worker(void* arg) { static int test_async(int nthreads) { + char fmtbuf[32]; struct ctx* threads; struct ctx* ctx; uint64_t time; @@ -112,7 +113,7 @@ static int test_async(int nthreads) { printf("async%d: %.2f sec (%s/sec)\n", nthreads, time / 1e9, - fmt(NUM_PINGS / (time / 1e9))); + fmt(&fmtbuf, NUM_PINGS / (time / 1e9))); free(threads); diff --git a/test/benchmark-fs-stat.c b/test/benchmark-fs-stat.c index 195f5052b8b..c4106224109 100644 --- a/test/benchmark-fs-stat.c +++ b/test/benchmark-fs-stat.c @@ -60,6 +60,7 @@ static void warmup(const char* path) { static void sync_bench(const char* path) { + char fmtbuf[2][32]; uint64_t before; uint64_t after; uv_fs_t req; @@ -74,9 +75,9 @@ static void sync_bench(const char* path) { after = uv_hrtime(); printf("%s stats (sync): %.2fs (%s/s)\n", - fmt(1.0 * NUM_SYNC_REQS), + fmt(&fmtbuf[0], 1.0 * NUM_SYNC_REQS), (after - before) / 1e9, - fmt((1.0 * NUM_SYNC_REQS) / ((after - before) / 1e9))); + fmt(&fmtbuf[1], (1.0 * NUM_SYNC_REQS) / ((after - before) / 1e9))); fflush(stdout); } @@ -93,6 +94,7 @@ static void stat_cb(uv_fs_t* fs_req) { static void async_bench(const char* path) { struct async_req reqs[MAX_CONCURRENT_REQS]; struct async_req* req; + char fmtbuf[2][32]; uint64_t before; uint64_t after; int count; @@ -112,10 +114,10 @@ static void async_bench(const char* path) { after = uv_hrtime(); printf("%s stats (%d concurrent): %.2fs (%s/s)\n", - fmt(1.0 * NUM_ASYNC_REQS), + fmt(&fmtbuf[0], 1.0 * NUM_ASYNC_REQS), i, (after - before) / 1e9, - fmt((1.0 * NUM_ASYNC_REQS) / ((after - before) / 1e9))); + fmt(&fmtbuf[1], (1.0 * NUM_ASYNC_REQS) / ((after - before) / 1e9))); fflush(stdout); } } diff --git a/test/benchmark-million-async.c b/test/benchmark-million-async.c index d398332ed20..30c21c38af1 100644 --- a/test/benchmark-million-async.c +++ b/test/benchmark-million-async.c @@ -76,6 +76,7 @@ static void timer_cb(uv_timer_t* handle) { BENCHMARK_IMPL(million_async) { + char fmtbuf[3][32]; uv_timer_t timer_handle; uv_async_t* handle; uv_loop_t* loop; @@ -101,10 +102,10 @@ BENCHMARK_IMPL(million_async) { ASSERT(0 == uv_thread_create(&thread_id, thread_cb, NULL)); ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); printf("%s async events in %.1f seconds (%s/s, %s unique handles seen)\n", - fmt(container->async_events), + fmt(&fmtbuf[0], container->async_events), timeout / 1000., - fmt(container->async_events / (timeout / 1000.)), - fmt(container->handles_seen)); + fmt(&fmtbuf[1], container->async_events / (timeout / 1000.)), + fmt(&fmtbuf[2], container->handles_seen)); free(container); MAKE_VALGRIND_HAPPY(loop); diff --git a/test/benchmark-queue-work.c b/test/benchmark-queue-work.c index 439be16a9f5..6e7b74becf6 100644 --- a/test/benchmark-queue-work.c +++ b/test/benchmark-queue-work.c @@ -46,6 +46,7 @@ static void after_work_cb(uv_work_t* req, int status) { static void timer_cb(uv_timer_t* handle) { done = 1; } BENCHMARK_IMPL(queue_work) { + char fmtbuf[2][32]; uv_timer_t timer_handle; uv_work_t work; uv_loop_t* loop; @@ -60,8 +61,10 @@ BENCHMARK_IMPL(queue_work) { ASSERT_EQ(0, uv_queue_work(loop, &work, work_cb, after_work_cb)); ASSERT_EQ(0, uv_run(loop, UV_RUN_DEFAULT)); - printf("%s async jobs in %.1f seconds (%s/s)\n", fmt(events), timeout / 1000., - fmt(events / (timeout / 1000.))); + printf("%s async jobs in %.1f seconds (%s/s)\n", + fmt(&fmtbuf[0], events), + timeout / 1000., + fmt(&fmtbuf[1], events / (timeout / 1000.))); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/runner.c b/test/runner.c index 00f2dea2179..d1dd02f5ce0 100644 --- a/test/runner.c +++ b/test/runner.c @@ -37,28 +37,14 @@ static int compare_task(const void* va, const void* vb) { } -const char* fmt(double d) { - static char buf[1024]; - static char* p; +char* fmt(char (*buf)[32], double d) { uint64_t v; + char* p; - if (p == NULL) - p = buf; - - p += 31; - - if (p >= buf + sizeof(buf)) - return ""; - + p = &(*buf)[32]; v = (uint64_t) d; -#if 0 /* works but we don't care about fractional precision */ - if (d - v >= 0.01) { - *--p = '0' + (uint64_t) (d * 100) % 10; - *--p = '0' + (uint64_t) (d * 10) % 10; - *--p = '.'; - } -#endif + *--p = '\0'; if (v == 0) *--p = '0'; diff --git a/test/task.h b/test/task.h index 0bf69927dd8..c90804ddfef 100644 --- a/test/task.h +++ b/test/task.h @@ -266,8 +266,8 @@ typedef enum { int run_helper_##name(void); \ int run_helper_##name(void) -/* Format big numbers nicely. WARNING: leaks memory. */ -const char* fmt(double d); +/* Format big numbers nicely. */ +char* fmt(char (*buf)[32], double d); /* Reserved test exit codes. */ enum test_status { From d2c31f429b87b476a7f1344d145dad4752a406d4 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 18 Apr 2023 12:32:08 +0200 Subject: [PATCH 340/713] linux: introduce io_uring support (#3952) Add io_uring support for several asynchronous file operations: - read, write - fsync, fdatasync - stat, fstat, lstat io_uring is used when the kernel is new enough, otherwise libuv simply falls back to the thread pool. Performance looks great; an 8x increase in throughput has been observed. This work was sponsored by ISC, the Internet Systems Consortium. Fixes: https://github.com/libuv/libuv/issues/1947 --- docs/src/fs.rst | 6 + src/threadpool.c | 4 + src/unix/fs.c | 51 ++-- src/unix/internal.h | 19 ++ src/unix/linux.c | 560 +++++++++++++++++++++++++++++++++- src/uv-common.h | 25 ++ test/test-threadpool-cancel.c | 32 +- 7 files changed, 662 insertions(+), 35 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index fb27a3b9654..e7522d59927 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -12,6 +12,12 @@ otherwise it will be performed asynchronously. All file operations are run on the threadpool. See :ref:`threadpool` for information on the threadpool size. +Starting with libuv v1.45.0, some file operations on Linux are handed off to +`io_uring ` when possible. Apart from +a (sometimes significant) increase in throughput there should be no change in +observable behavior. Libuv reverts to using its threadpool when the necessary +kernel features are unavailable or unsuitable. + .. note:: On Windows `uv_fs_*` functions use utf-8 encoding. diff --git a/src/threadpool.c b/src/threadpool.c index a3da53026f9..42322ebbbcf 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -275,9 +275,13 @@ void uv__work_submit(uv_loop_t* loop, } +/* TODO(bnoordhuis) teach libuv how to cancel file operations + * that go through io_uring instead of the thread pool. + */ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) { int cancelled; + uv_once(&once, init_once); /* Ensure |mutex| is initialized. */ uv_mutex_lock(&mutex); uv_mutex_lock(&w->loop->wq_mutex); diff --git a/src/unix/fs.c b/src/unix/fs.c index a54038c92e2..cdfc9fe3961 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -56,10 +56,11 @@ #endif #if defined(__linux__) -# include "sys/utsname.h" +# include +# include #endif -#if defined(__linux__) || defined(__sun) +#if defined(__sun) # include # include #endif @@ -1576,26 +1577,7 @@ static int uv__fs_statx(int fd, return UV_ENOSYS; } - buf->st_dev = makedev(statxbuf.stx_dev_major, statxbuf.stx_dev_minor); - buf->st_mode = statxbuf.stx_mode; - buf->st_nlink = statxbuf.stx_nlink; - buf->st_uid = statxbuf.stx_uid; - buf->st_gid = statxbuf.stx_gid; - buf->st_rdev = makedev(statxbuf.stx_rdev_major, statxbuf.stx_rdev_minor); - buf->st_ino = statxbuf.stx_ino; - buf->st_size = statxbuf.stx_size; - buf->st_blksize = statxbuf.stx_blksize; - buf->st_blocks = statxbuf.stx_blocks; - buf->st_atim.tv_sec = statxbuf.stx_atime.tv_sec; - buf->st_atim.tv_nsec = statxbuf.stx_atime.tv_nsec; - buf->st_mtim.tv_sec = statxbuf.stx_mtime.tv_sec; - buf->st_mtim.tv_nsec = statxbuf.stx_mtime.tv_nsec; - buf->st_ctim.tv_sec = statxbuf.stx_ctime.tv_sec; - buf->st_ctim.tv_nsec = statxbuf.stx_ctime.tv_nsec; - buf->st_birthtim.tv_sec = statxbuf.stx_btime.tv_sec; - buf->st_birthtim.tv_nsec = statxbuf.stx_btime.tv_nsec; - buf->st_flags = 0; - buf->st_gen = 0; + uv__statx_to_stat(&statxbuf, buf); return 0; #else @@ -1886,6 +1868,9 @@ int uv_fs_lchown(uv_loop_t* loop, int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { INIT(FDATASYNC); req->file = file; + if (cb != NULL) + if (uv__iou_fs_fsync_or_fdatasync(loop, req, /* IORING_FSYNC_DATASYNC */ 1)) + return 0; POST; } @@ -1893,6 +1878,9 @@ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { INIT(FSTAT); req->file = file; + if (cb != NULL) + if (uv__iou_fs_statx(loop, req, /* is_fstat */ 1, /* is_lstat */ 0)) + return 0; POST; } @@ -1900,6 +1888,9 @@ int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { INIT(FSYNC); req->file = file; + if (cb != NULL) + if (uv__iou_fs_fsync_or_fdatasync(loop, req, /* no flags */ 0)) + return 0; POST; } @@ -1946,6 +1937,9 @@ int uv_fs_lutime(uv_loop_t* loop, int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { INIT(LSTAT); PATH; + if (cb != NULL) + if (uv__iou_fs_statx(loop, req, /* is_fstat */ 0, /* is_lstat */ 1)) + return 0; POST; } @@ -2035,6 +2029,11 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); req->off = off; + + if (cb != NULL) + if (uv__iou_fs_read_or_write(loop, req, /* is_read */ 1)) + return 0; + POST; } @@ -2142,6 +2141,9 @@ int uv_fs_sendfile(uv_loop_t* loop, int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { INIT(STAT); PATH; + if (cb != NULL) + if (uv__iou_fs_statx(loop, req, /* is_fstat */ 0, /* is_lstat */ 0)) + return 0; POST; } @@ -2205,6 +2207,11 @@ int uv_fs_write(uv_loop_t* loop, memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); req->off = off; + + if (cb != NULL) + if (uv__iou_fs_read_or_write(loop, req, /* is_read */ 0)) + return 0; + POST; } diff --git a/src/unix/internal.h b/src/unix/internal.h index d439ae6dd3d..08d2d1ce8c6 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -329,6 +329,24 @@ int uv__random_getentropy(void* buf, size_t buflen); int uv__random_readpath(const char* path, void* buf, size_t buflen); int uv__random_sysctl(void* buf, size_t buflen); +/* io_uring */ +#ifdef __linux__ +int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop, + uv_fs_t* req, + uint32_t fsync_flags); +int uv__iou_fs_read_or_write(uv_loop_t* loop, + uv_fs_t* req, + int is_read); +int uv__iou_fs_statx(uv_loop_t* loop, + uv_fs_t* req, + int is_fstat, + int is_lstat); +#else +#define uv__iou_fs_fsync_or_fdatasync(loop, req, fsync_flags) 0 +#define uv__iou_fs_read_or_write(loop, req, is_read) 0 +#define uv__iou_fs_statx(loop, req, is_fstat, is_lstat) 0 +#endif + #if defined(__APPLE__) int uv___stream_fd(const uv_stream_t* handle); #define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle))) @@ -405,6 +423,7 @@ int uv__statx(int dirfd, int flags, unsigned int mask, struct uv__statx* statxbuf); +void uv__statx_to_stat(const struct uv__statx* statxbuf, uv_stat_t* buf); ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags); #endif diff --git a/src/unix/linux.c b/src/unix/linux.c index a30f1bfbd3f..875dfcbfa03 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -27,6 +27,8 @@ #include "internal.h" #include +#include +#include /* offsetof */ #include #include #include @@ -38,15 +40,29 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include +#ifndef __NR_io_uring_setup +# define __NR_io_uring_setup 425 +#endif + +#ifndef __NR_io_uring_enter +# define __NR_io_uring_enter 426 +#endif + +#ifndef __NR_io_uring_register +# define __NR_io_uring_register 427 +#endif + #ifndef __NR_copy_file_range # if defined(__x86_64__) # define __NR_copy_file_range 326 @@ -116,6 +132,119 @@ # include #endif /* HAVE_IFADDRS_H */ +enum { + UV__IORING_SETUP_SQPOLL = 2u, +}; + +enum { + UV__IORING_FEAT_SINGLE_MMAP = 1u, + UV__IORING_FEAT_NODROP = 2u, + UV__IORING_FEAT_RSRC_TAGS = 1024u, /* linux v5.13 */ +}; + +enum { + UV__IORING_OP_READV = 1, + UV__IORING_OP_WRITEV = 2, + UV__IORING_OP_FSYNC = 3, + UV__IORING_OP_STATX = 21, +}; + +enum { + UV__IORING_ENTER_SQ_WAKEUP = 2u, +}; + +enum { + UV__IORING_SQ_NEED_WAKEUP = 1u, +}; + +struct uv__io_cqring_offsets { + uint32_t head; + uint32_t tail; + uint32_t ring_mask; + uint32_t ring_entries; + uint32_t overflow; + uint32_t cqes; + uint64_t reserved0; + uint64_t reserved1; +}; + +STATIC_ASSERT(40 == sizeof(struct uv__io_cqring_offsets)); + +struct uv__io_sqring_offsets { + uint32_t head; + uint32_t tail; + uint32_t ring_mask; + uint32_t ring_entries; + uint32_t flags; + uint32_t dropped; + uint32_t array; + uint32_t reserved0; + uint64_t reserved1; +}; + +STATIC_ASSERT(40 == sizeof(struct uv__io_sqring_offsets)); + +struct uv__io_uring_cqe { + uint64_t user_data; + int32_t res; + uint32_t flags; +}; + +STATIC_ASSERT(16 == sizeof(struct uv__io_uring_cqe)); + +struct uv__io_uring_sqe { + uint8_t opcode; + uint8_t flags; + uint16_t ioprio; + int32_t fd; + union { + uint64_t off; + uint64_t addr2; + }; + union { + uint64_t addr; + }; + uint32_t len; + union { + uint32_t rw_flags; + uint32_t fsync_flags; + uint32_t statx_flags; + }; + uint64_t user_data; + union { + uint16_t buf_index; + uint64_t pad[3]; + }; +}; + +STATIC_ASSERT(64 == sizeof(struct uv__io_uring_sqe)); +STATIC_ASSERT(0 == offsetof(struct uv__io_uring_sqe, opcode)); +STATIC_ASSERT(1 == offsetof(struct uv__io_uring_sqe, flags)); +STATIC_ASSERT(2 == offsetof(struct uv__io_uring_sqe, ioprio)); +STATIC_ASSERT(4 == offsetof(struct uv__io_uring_sqe, fd)); +STATIC_ASSERT(8 == offsetof(struct uv__io_uring_sqe, off)); +STATIC_ASSERT(16 == offsetof(struct uv__io_uring_sqe, addr)); +STATIC_ASSERT(24 == offsetof(struct uv__io_uring_sqe, len)); +STATIC_ASSERT(28 == offsetof(struct uv__io_uring_sqe, rw_flags)); +STATIC_ASSERT(32 == offsetof(struct uv__io_uring_sqe, user_data)); +STATIC_ASSERT(40 == offsetof(struct uv__io_uring_sqe, buf_index)); + +struct uv__io_uring_params { + uint32_t sq_entries; + uint32_t cq_entries; + uint32_t flags; + uint32_t sq_thread_cpu; + uint32_t sq_thread_idle; + uint32_t features; + uint32_t reserved[4]; + struct uv__io_sqring_offsets sq_off; /* 40 bytes */ + struct uv__io_cqring_offsets cq_off; /* 40 bytes */ +}; + +STATIC_ASSERT(40 + 40 + 40 == sizeof(struct uv__io_uring_params)); +STATIC_ASSERT(40 == offsetof(struct uv__io_uring_params, sq_off)); +STATIC_ASSERT(80 == offsetof(struct uv__io_uring_params, cq_off)); + struct watcher_list { RB_ENTRY(watcher_list) entry; QUEUE watchers; @@ -206,7 +335,61 @@ ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) { } +int uv__io_uring_setup(int entries, struct uv__io_uring_params* params) { + return syscall(__NR_io_uring_setup, entries, params); +} + + +int uv__io_uring_enter(int fd, + unsigned to_submit, + unsigned min_complete, + unsigned flags) { + /* io_uring_enter used to take a sigset_t but it's unused + * in newer kernels unless IORING_ENTER_EXT_ARG is set, + * in which case it takes a struct io_uring_getevents_arg. + */ + return syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags, 0, 0); +} + + +int uv__io_uring_register(int fd, unsigned opcode, void* arg, unsigned nargs) { + return syscall(__NR_io_uring_register, fd, opcode, arg, nargs); +} + + +static int uv__use_io_uring(void) { + /* Ternary: unknown=0, yes=1, no=-1 */ + static _Atomic int use_io_uring; + char* val; + int use; + + use = atomic_load_explicit(&use_io_uring, memory_order_relaxed); + + if (use == 0) { + val = getenv("UV_USE_IO_URING"); + use = val == NULL || atoi(val) ? 1 : -1; + atomic_store_explicit(&use_io_uring, use, memory_order_relaxed); + } + + return use > 0; +} + + int uv__platform_loop_init(uv_loop_t* loop) { + struct uv__io_uring_params params; + struct epoll_event e; + struct uv__iou* iou; + size_t cqlen; + size_t sqlen; + size_t maxlen; + size_t sqelen; + char* sq; + char* sqe; + int ringfd; + + iou = &uv__get_internal_fields(loop)->iou; + iou->ringfd = -1; + loop->inotify_watchers = NULL; loop->inotify_fd = -1; loop->backend_fd = epoll_create1(O_CLOEXEC); @@ -214,7 +397,101 @@ int uv__platform_loop_init(uv_loop_t* loop) { if (loop->backend_fd == -1) return UV__ERR(errno); + if (!uv__use_io_uring()) + return 0; + + sq = MAP_FAILED; + sqe = MAP_FAILED; + + /* SQPOLL required CAP_SYS_NICE until linux v5.12 relaxed that requirement. + * Mostly academic because we check for a v5.13 kernel afterwards anyway. + */ + memset(¶ms, 0, sizeof(params)); + params.flags = UV__IORING_SETUP_SQPOLL; + params.sq_thread_idle = 10; /* milliseconds */ + + /* Kernel returns a file descriptor with O_CLOEXEC flag set. */ + ringfd = uv__io_uring_setup(64, ¶ms); + if (ringfd == -1) + return 0; /* Not an error, falls back to thread pool. */ + + /* IORING_FEAT_RSRC_TAGS is used to detect linux v5.13 but what we're + * actually detecting is whether IORING_OP_STATX works with SQPOLL. + */ + if (!(params.features & UV__IORING_FEAT_RSRC_TAGS)) + goto fail; + + /* Implied by IORING_FEAT_RSRC_TAGS but checked explicitly anyway. */ + if (!(params.features & UV__IORING_FEAT_SINGLE_MMAP)) + goto fail; + + /* Implied by IORING_FEAT_RSRC_TAGS but checked explicitly anyway. */ + if (!(params.features & UV__IORING_FEAT_NODROP)) + goto fail; + + sqlen = params.sq_off.array + params.sq_entries * sizeof(uint32_t); + cqlen = + params.cq_off.cqes + params.cq_entries * sizeof(struct uv__io_uring_cqe); + maxlen = sqlen < cqlen ? cqlen : sqlen; + sqelen = params.sq_entries * sizeof(struct uv__io_uring_sqe); + + sq = mmap(0, + maxlen, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_POPULATE, + ringfd, + 0); /* IORING_OFF_SQ_RING */ + + sqe = mmap(0, + sqelen, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_POPULATE, + ringfd, + 0x10000000ull); /* IORING_OFF_SQES */ + + if (sq == MAP_FAILED || sqe == MAP_FAILED) + goto fail; + + iou->sqhead = (uint32_t*) (sq + params.sq_off.head); + iou->sqtail = (uint32_t*) (sq + params.sq_off.tail); + iou->sqmask = *(uint32_t*) (sq + params.sq_off.ring_mask); + iou->sqarray = (uint32_t*) (sq + params.sq_off.array); + iou->sqflags = (uint32_t*) (sq + params.sq_off.flags); + iou->cqhead = (uint32_t*) (sq + params.cq_off.head); + iou->cqtail = (uint32_t*) (sq + params.cq_off.tail); + iou->cqmask = *(uint32_t*) (sq + params.cq_off.ring_mask); + iou->sq = sq; + iou->cqe = sq + params.cq_off.cqes; + iou->sqe = sqe; + iou->sqlen = sqlen; + iou->cqlen = cqlen; + iou->maxlen = maxlen; + iou->sqelen = sqelen; + iou->ringfd = ringfd; + iou->in_flight = 0; + + /* Only interested in completion events. To get notified when + * the kernel pulls items from the submission ring, add POLLOUT. + */ + memset(&e, 0, sizeof(e)); + e.events = POLLIN; + e.data.fd = ringfd; + + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, ringfd, &e)) + goto fail; + return 0; + +fail: + if (sq != MAP_FAILED) + munmap(sq, maxlen); + + if (sqe != MAP_FAILED) + munmap(sqe, sqelen); + + uv__close(ringfd); + + return 0; /* Not an error, falls back to thread pool. */ } @@ -226,6 +503,8 @@ int uv__io_fork(uv_loop_t* loop) { uv__close(loop->backend_fd); loop->backend_fd = -1; + + /* TODO(bnoordhuis) Loses items from the submission and completion rings. */ uv__platform_loop_delete(loop); err = uv__platform_loop_init(loop); @@ -237,10 +516,22 @@ int uv__io_fork(uv_loop_t* loop) { void uv__platform_loop_delete(uv_loop_t* loop) { - if (loop->inotify_fd == -1) return; - uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN); - uv__close(loop->inotify_fd); - loop->inotify_fd = -1; + struct uv__iou* iou; + + iou = &uv__get_internal_fields(loop)->iou; + + if (loop->inotify_fd != -1) { + uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN); + uv__close(loop->inotify_fd); + loop->inotify_fd = -1; + } + + if (iou->ringfd != -1) { + munmap(iou->sq, iou->maxlen); + munmap(iou->sqe, iou->sqelen); + uv__close(iou->ringfd); + iou->ringfd = -1; + } } @@ -298,6 +589,242 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { } +/* Caller must initialize SQE and call uv__iou_submit(). */ +static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, + uv_loop_t* loop, + uv_fs_t* req) { + struct uv__io_uring_sqe* sqe; + uint32_t head; + uint32_t slot; + + if (iou->ringfd == -1) + return NULL; + + head = atomic_load_explicit((_Atomic uint32_t*) iou->sqhead, + memory_order_acquire); + if (head == *iou->sqtail + 1) + return NULL; /* No room in ring buffer. TODO(bnoordhuis) maybe flush it? */ + + slot = *iou->sqtail & iou->sqmask; + iou->sqarray[slot] = slot; /* Identity mapping of index -> sqe. */ + + sqe = iou->sqe; + sqe = &sqe[slot]; + memset(sqe, 0, sizeof(*sqe)); + sqe->user_data = (uintptr_t) req; + + /* Pacify uv_cancel(). */ + req->work_req.loop = loop; + req->work_req.work = NULL; + req->work_req.done = NULL; + QUEUE_INIT(&req->work_req.wq); + + uv__req_register(loop, req); + iou->in_flight++; + + return sqe; +} + + +static void uv__iou_submit(struct uv__iou* iou) { + uint32_t flags; + + atomic_store_explicit((_Atomic uint32_t*) iou->sqtail, + *iou->sqtail + 1, + memory_order_release); + + flags = atomic_load_explicit((_Atomic uint32_t*) iou->sqflags, + memory_order_acquire); + + if (flags & UV__IORING_SQ_NEED_WAKEUP) + if (uv__io_uring_enter(iou->ringfd, 0, 0, UV__IORING_ENTER_SQ_WAKEUP)) + perror("libuv: io_uring_enter"); /* Can't happen. */ +} + + +int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop, + uv_fs_t* req, + uint32_t fsync_flags) { + struct uv__io_uring_sqe* sqe; + struct uv__iou* iou; + + iou = &uv__get_internal_fields(loop)->iou; + + sqe = uv__iou_get_sqe(iou, loop, req); + if (sqe == NULL) + return 0; + + /* Little known fact: setting seq->off and seq->len turns + * it into an asynchronous sync_file_range() operation. + */ + sqe->fd = req->file; + sqe->fsync_flags = fsync_flags; + sqe->opcode = UV__IORING_OP_FSYNC; + + uv__iou_submit(iou); + + return 1; +} + + +int uv__iou_fs_read_or_write(uv_loop_t* loop, + uv_fs_t* req, + int is_read) { + struct uv__io_uring_sqe* sqe; + struct uv__iou* iou; + + iou = &uv__get_internal_fields(loop)->iou; + + sqe = uv__iou_get_sqe(iou, loop, req); + if (sqe == NULL) + return 0; + + sqe->addr = (uintptr_t) req->bufs; + sqe->fd = req->file; + sqe->len = req->nbufs; + sqe->off = req->off < 0 ? -1 : req->off; + sqe->opcode = is_read ? UV__IORING_OP_READV : UV__IORING_OP_WRITEV; + + uv__iou_submit(iou); + + return 1; +} + + +int uv__iou_fs_statx(uv_loop_t* loop, + uv_fs_t* req, + int is_fstat, + int is_lstat) { + struct uv__io_uring_sqe* sqe; + struct uv__statx* statxbuf; + struct uv__iou* iou; + + statxbuf = uv__malloc(sizeof(*statxbuf)); + if (statxbuf == NULL) + return 0; + + iou = &uv__get_internal_fields(loop)->iou; + + sqe = uv__iou_get_sqe(iou, loop, req); + if (sqe == NULL) { + uv__free(statxbuf); + return 0; + } + + req->ptr = statxbuf; + + sqe->addr = (uintptr_t) req->path; + sqe->addr2 = (uintptr_t) statxbuf; + sqe->fd = AT_FDCWD; + sqe->len = 0xFFF; /* STATX_BASIC_STATS + STATX_BTIME */ + sqe->opcode = UV__IORING_OP_STATX; + + if (is_fstat) { + sqe->addr = (uintptr_t) ""; + sqe->fd = req->file; + sqe->statx_flags |= 0x1000; /* AT_EMPTY_PATH */ + } + + if (is_lstat) + sqe->statx_flags |= AT_SYMLINK_NOFOLLOW; + + uv__iou_submit(iou); + + return 1; +} + + +void uv__statx_to_stat(const struct uv__statx* statxbuf, uv_stat_t* buf) { + buf->st_dev = makedev(statxbuf->stx_dev_major, statxbuf->stx_dev_minor); + buf->st_mode = statxbuf->stx_mode; + buf->st_nlink = statxbuf->stx_nlink; + buf->st_uid = statxbuf->stx_uid; + buf->st_gid = statxbuf->stx_gid; + buf->st_rdev = makedev(statxbuf->stx_rdev_major, statxbuf->stx_rdev_minor); + buf->st_ino = statxbuf->stx_ino; + buf->st_size = statxbuf->stx_size; + buf->st_blksize = statxbuf->stx_blksize; + buf->st_blocks = statxbuf->stx_blocks; + buf->st_atim.tv_sec = statxbuf->stx_atime.tv_sec; + buf->st_atim.tv_nsec = statxbuf->stx_atime.tv_nsec; + buf->st_mtim.tv_sec = statxbuf->stx_mtime.tv_sec; + buf->st_mtim.tv_nsec = statxbuf->stx_mtime.tv_nsec; + buf->st_ctim.tv_sec = statxbuf->stx_ctime.tv_sec; + buf->st_ctim.tv_nsec = statxbuf->stx_ctime.tv_nsec; + buf->st_birthtim.tv_sec = statxbuf->stx_btime.tv_sec; + buf->st_birthtim.tv_nsec = statxbuf->stx_btime.tv_nsec; + buf->st_flags = 0; + buf->st_gen = 0; +} + + +static void uv__iou_fs_statx_post(uv_fs_t* req) { + struct uv__statx* statxbuf; + uv_stat_t* buf; + + buf = &req->statbuf; + statxbuf = req->ptr; + req->ptr = NULL; + + if (req->result == 0) { + uv__msan_unpoison(statxbuf, sizeof(*statxbuf)); + uv__statx_to_stat(statxbuf, buf); + req->ptr = buf; + } + + uv__free(statxbuf); +} + + +static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { + struct uv__io_uring_cqe* cqe; + struct uv__io_uring_cqe* e; + uv_fs_t* req; + uint32_t head; + uint32_t tail; + uint32_t mask; + uint32_t i; + + head = *iou->cqhead; + tail = atomic_load_explicit((_Atomic uint32_t*) iou->cqtail, + memory_order_acquire); + mask = iou->cqmask; + cqe = iou->cqe; + + for (i = head; i != tail; i++) { + e = &cqe[i & mask]; + + req = (uv_fs_t*) (uintptr_t) e->user_data; + assert(req->type == UV_FS); + + uv__req_unregister(loop, req); + iou->in_flight--; + + /* io_uring stores error codes as negative numbers, same as libuv. */ + req->result = e->res; + + switch (req->fs_type) { + case UV_FS_FSTAT: + case UV_FS_LSTAT: + case UV_FS_STAT: + uv__iou_fs_statx_post(req); + break; + default: /* Squelch -Wswitch warnings. */ + break; + } + + uv__metrics_update_idle_time(loop); + req->cb(req); + } + + atomic_store_explicit((_Atomic uint32_t*) iou->cqhead, + tail, + memory_order_release); + + uv__metrics_inc_events(loop, 1); +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes * effectively infinite on 32 bits architectures. To avoid blocking @@ -308,15 +835,18 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * that being the largest value I have seen in the wild (and only once.) */ static const int max_safe_timeout = 1789569; + uv__loop_internal_fields_t* lfields; struct epoll_event events[1024]; struct epoll_event* pe; struct epoll_event e; + struct uv__iou* iou; int real_timeout; QUEUE* q; uv__io_t* w; sigset_t* sigmask; sigset_t sigset; uint64_t base; + int have_iou_events; int have_signals; int nevents; int count; @@ -327,10 +857,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { int user_timeout; int reset_timeout; - if (loop->nfds == 0) { - assert(QUEUE_EMPTY(&loop->watcher_queue)); - return; - } + lfields = uv__get_internal_fields(loop); + iou = &lfields->iou; memset(&e, 0, sizeof(e)); @@ -381,7 +909,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { count = 48; /* Benchmarks suggest this gives the best throughput. */ real_timeout = timeout; - if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + if (lfields->flags & UV_METRICS_IDLE_TIME) { reset_timeout = 1; user_timeout = timeout; timeout = 0; @@ -391,6 +919,10 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } for (;;) { + if (loop->nfds == 0) + if (iou->in_flight == 0) + return; + /* 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. */ @@ -454,6 +986,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { goto update_timeout; } + have_iou_events = 0; have_signals = 0; nevents = 0; @@ -478,6 +1011,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (fd == -1) continue; + if (fd == iou->ringfd) { + uv__poll_io_uring(loop, iou); + have_iou_events = 1; + continue; + } + assert(fd >= 0); assert((unsigned) fd < loop->nwatchers); @@ -549,6 +1088,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; + if (have_iou_events != 0) + return; /* Event loop should cycle now so don't poll again. */ + if (have_signals != 0) return; /* Event loop should cycle now so don't poll again. */ diff --git a/src/uv-common.h b/src/uv-common.h index 2720121addc..df874f8a2c7 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -396,9 +396,34 @@ struct uv__loop_metrics_s { void uv__metrics_update_idle_time(uv_loop_t* loop); void uv__metrics_set_provider_entry_time(uv_loop_t* loop); +#ifdef __linux__ +struct uv__iou { + uint32_t* sqhead; + uint32_t* sqtail; + uint32_t* sqarray; + uint32_t sqmask; + uint32_t* sqflags; + uint32_t* cqhead; + uint32_t* cqtail; + uint32_t cqmask; + void* sq; /* pointer to munmap() on event loop teardown */ + void* cqe; /* pointer to array of struct uv__io_uring_cqe */ + void* sqe; /* pointer to array of struct uv__io_uring_sqe */ + size_t sqlen; + size_t cqlen; + size_t maxlen; + size_t sqelen; + int ringfd; + uint32_t in_flight; +}; +#endif /* __linux__ */ + struct uv__loop_internal_fields_s { unsigned int flags; uv__loop_metrics_t loop_metrics; +#ifdef __linux__ + struct uv__iou iou; +#endif /* __linux__ */ }; #endif /* UV_COMMON_H_ */ diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index a6c9d3465d6..f71cc9c3f8f 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -87,8 +87,32 @@ static void unblock_threadpool(void) { } +static int known_broken(uv_req_t* req) { + if (req->type != UV_FS) + return 0; + +#ifdef __linux__ + /* TODO(bnoordhuis) make cancellation work with io_uring */ + switch (((uv_fs_t*) req)->fs_type) { + case UV_FS_FDATASYNC: + case UV_FS_FSTAT: + case UV_FS_FSYNC: + case UV_FS_LSTAT: + case UV_FS_READ: + case UV_FS_STAT: + case UV_FS_WRITE: + return 1; + default: /* Squelch -Wswitch warnings. */ + break; + } +#endif + + return 0; +} + + static void fs_cb(uv_fs_t* req) { - ASSERT(req->result == UV_ECANCELED); + ASSERT(known_broken((uv_req_t*) req) || req->result == UV_ECANCELED); uv_fs_req_cleanup(req); fs_cb_called++; } @@ -133,7 +157,7 @@ static void timer_cb(uv_timer_t* handle) { for (i = 0; i < ci->nreqs; i++) { req = (uv_req_t*) ((char*) ci->reqs + i * ci->stride); - ASSERT(0 == uv_cancel(req)); + ASSERT(known_broken(req) || 0 == uv_cancel(req)); } uv_close((uv_handle_t*) &ci->timer_handle, NULL); @@ -305,7 +329,7 @@ TEST_IMPL(threadpool_cancel_fs) { ASSERT(0 == uv_fs_lstat(loop, reqs + n++, "/", fs_cb)); ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb)); ASSERT(0 == uv_fs_open(loop, reqs + n++, "/", 0, 0, fs_cb)); - ASSERT(0 == uv_fs_read(loop, reqs + n++, 0, &iov, 1, 0, fs_cb)); + ASSERT(0 == uv_fs_read(loop, reqs + n++, -1, &iov, 1, 0, fs_cb)); ASSERT(0 == uv_fs_scandir(loop, reqs + n++, "/", 0, fs_cb)); ASSERT(0 == uv_fs_readlink(loop, reqs + n++, "/", fs_cb)); ASSERT(0 == uv_fs_realpath(loop, reqs + n++, "/", fs_cb)); @@ -316,7 +340,7 @@ TEST_IMPL(threadpool_cancel_fs) { ASSERT(0 == uv_fs_symlink(loop, reqs + n++, "/", "/", 0, fs_cb)); ASSERT(0 == uv_fs_unlink(loop, reqs + n++, "/", fs_cb)); ASSERT(0 == uv_fs_utime(loop, reqs + n++, "/", 0, 0, fs_cb)); - ASSERT(0 == uv_fs_write(loop, reqs + n++, 0, &iov, 1, 0, fs_cb)); + ASSERT(0 == uv_fs_write(loop, reqs + n++, -1, &iov, 1, 0, fs_cb)); ASSERT(n == ARRAY_SIZE(reqs)); ASSERT(0 == uv_timer_init(loop, &ci.timer_handle)); From a7ff759ca1deacb2e0e6ae3c2d3dce91cc637dfe Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 19 Apr 2023 07:39:10 +0200 Subject: [PATCH 341/713] linux: fix academic valgrind warning (#3960) Fix a valgrind warning that only manifested with clang (not gcc!) by explicitly passing 0L instead of plain 0 as the |sigsz| argument to io_uring_enter(). That is, pass a long instead of an int. On x86_64, |sigsz| is passed on the stack (the other arguments are passed in registers) but where gcc emits a `push $0` that zeroes the entire stack slot, clang emits a `movl $0,(%rsp)` that leaves the upper 32 bits untouched. It's academic though since we don't pass IORING_ENTER_EXT_ARG and the kernel therefore completely ignores the argument. Refs: https://github.com/libuv/libuv/pull/3952 --- src/unix/linux.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 875dfcbfa03..5b6613be47d 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -348,7 +348,13 @@ int uv__io_uring_enter(int fd, * in newer kernels unless IORING_ENTER_EXT_ARG is set, * in which case it takes a struct io_uring_getevents_arg. */ - return syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags, 0, 0); + return syscall(__NR_io_uring_enter, + fd, + to_submit, + min_complete, + flags, + NULL, + 0L); } From 3ba75f130083092d43fa5126e6b9fc8fb638f532 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 19 Apr 2023 07:40:18 +0200 Subject: [PATCH 342/713] test: disable signal test under ASan and MSan (#3961) The signal_multiple_loops test is flaky when run under AddressSanitizer and MemorySanitizer. Sometimes thread creation fails, other times it simply times out. Fixes: https://github.com/libuv/libuv/issues/3956 --- test/test-signal-multiple-loops.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/test-signal-multiple-loops.c b/test/test-signal-multiple-loops.c index 483f59f2006..de511fc0680 100644 --- a/test/test-signal-multiple-loops.c +++ b/test/test-signal-multiple-loops.c @@ -208,9 +208,13 @@ TEST_IMPL(signal_multiple_loops) { #endif /* TODO(gengjiawen): Fix test on QEMU. */ #if defined(__QEMU__) - // See https://github.com/libuv/libuv/issues/2859 + /* See https://github.com/libuv/libuv/issues/2859 */ RETURN_SKIP("QEMU's signal emulation code is notoriously tricky"); #endif +#if defined(__ASAN__) || defined(__MSAN__) + /* See https://github.com/libuv/libuv/issues/3956 */ + RETURN_SKIP("Test is too slow to run under ASan or MSan"); +#endif #if defined(__TSAN__) /* ThreadSanitizer complains - likely legitimately - about data races * in uv__signal_compare() in src/unix/signal.c but that's pre-existing. From 5ca5e475bb1711e65323ef1594a31818e5a1a9eb Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 20 Apr 2023 10:17:06 +0200 Subject: [PATCH 343/713] linux: add IORING_OP_OPENAT support (#3963) --- src/unix/fs.c | 3 +++ src/unix/internal.h | 2 ++ src/unix/linux.c | 24 ++++++++++++++++++++++++ test/test-threadpool-cancel.c | 1 + 4 files changed, 30 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index cdfc9fe3961..c8e9107cb49 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -2001,6 +2001,9 @@ int uv_fs_open(uv_loop_t* loop, PATH; req->flags = flags; req->mode = mode; + if (cb != NULL) + if (uv__iou_fs_open(loop, req)) + return 0; POST; } diff --git a/src/unix/internal.h b/src/unix/internal.h index 08d2d1ce8c6..86e25a6b06b 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -334,6 +334,7 @@ int uv__random_sysctl(void* buf, size_t buflen); int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop, uv_fs_t* req, uint32_t fsync_flags); +int uv__iou_fs_open(uv_loop_t* loop, uv_fs_t* req); int uv__iou_fs_read_or_write(uv_loop_t* loop, uv_fs_t* req, int is_read); @@ -343,6 +344,7 @@ int uv__iou_fs_statx(uv_loop_t* loop, int is_lstat); #else #define uv__iou_fs_fsync_or_fdatasync(loop, req, fsync_flags) 0 +#define uv__iou_fs_open(loop, req) 0 #define uv__iou_fs_read_or_write(loop, req, is_read) 0 #define uv__iou_fs_statx(loop, req, is_fstat, is_lstat) 0 #endif diff --git a/src/unix/linux.c b/src/unix/linux.c index 5b6613be47d..99ae4f17b09 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -146,6 +146,7 @@ enum { UV__IORING_OP_READV = 1, UV__IORING_OP_WRITEV = 2, UV__IORING_OP_FSYNC = 3, + UV__IORING_OP_OPENAT = 18, UV__IORING_OP_STATX = 21, }; @@ -208,6 +209,7 @@ struct uv__io_uring_sqe { union { uint32_t rw_flags; uint32_t fsync_flags; + uint32_t open_flags; uint32_t statx_flags; }; uint64_t user_data; @@ -673,6 +675,28 @@ int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop, } +int uv__iou_fs_open(uv_loop_t* loop, uv_fs_t* req) { + struct uv__io_uring_sqe* sqe; + struct uv__iou* iou; + + iou = &uv__get_internal_fields(loop)->iou; + + sqe = uv__iou_get_sqe(iou, loop, req); + if (sqe == NULL) + return 0; + + sqe->addr = (uintptr_t) req->path; + sqe->fd = AT_FDCWD; + sqe->len = req->mode; + sqe->opcode = UV__IORING_OP_OPENAT; + sqe->open_flags = req->flags | O_CLOEXEC; + + uv__iou_submit(iou); + + return 1; +} + + int uv__iou_fs_read_or_write(uv_loop_t* loop, uv_fs_t* req, int is_read) { diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index f71cc9c3f8f..aafa84c9153 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -98,6 +98,7 @@ static int known_broken(uv_req_t* req) { case UV_FS_FSTAT: case UV_FS_FSYNC: case UV_FS_LSTAT: + case UV_FS_OPEN: case UV_FS_READ: case UV_FS_STAT: case UV_FS_WRITE: From dfae365f844e127621128a76bce7165e3f99a8d9 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 20 Apr 2023 10:44:16 +0200 Subject: [PATCH 344/713] linux: add IORING_OP_CLOSE support (#3964) --- src/unix/fs.c | 3 +++ src/unix/internal.h | 2 ++ src/unix/linux.c | 20 ++++++++++++++++++++ test/test-threadpool-cancel.c | 1 + 4 files changed, 26 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index c8e9107cb49..bf473d2099f 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1821,6 +1821,9 @@ int uv_fs_chown(uv_loop_t* loop, int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { INIT(CLOSE); req->file = file; + if (cb != NULL) + if (uv__iou_fs_close(loop, req)) + return 0; POST; } diff --git a/src/unix/internal.h b/src/unix/internal.h index 86e25a6b06b..6c5822e6a0d 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -331,6 +331,7 @@ int uv__random_sysctl(void* buf, size_t buflen); /* io_uring */ #ifdef __linux__ +int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req); int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop, uv_fs_t* req, uint32_t fsync_flags); @@ -343,6 +344,7 @@ int uv__iou_fs_statx(uv_loop_t* loop, int is_fstat, int is_lstat); #else +#define uv__iou_fs_close(loop, req) 0 #define uv__iou_fs_fsync_or_fdatasync(loop, req, fsync_flags) 0 #define uv__iou_fs_open(loop, req) 0 #define uv__iou_fs_read_or_write(loop, req, is_read) 0 diff --git a/src/unix/linux.c b/src/unix/linux.c index 99ae4f17b09..fc879f8ff6a 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -147,6 +147,7 @@ enum { UV__IORING_OP_WRITEV = 2, UV__IORING_OP_FSYNC = 3, UV__IORING_OP_OPENAT = 18, + UV__IORING_OP_CLOSE = 19, UV__IORING_OP_STATX = 21, }; @@ -650,6 +651,25 @@ static void uv__iou_submit(struct uv__iou* iou) { } +int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req) { + struct uv__io_uring_sqe* sqe; + struct uv__iou* iou; + + iou = &uv__get_internal_fields(loop)->iou; + + sqe = uv__iou_get_sqe(iou, loop, req); + if (sqe == NULL) + return 0; + + sqe->fd = req->file; + sqe->opcode = UV__IORING_OP_CLOSE; + + uv__iou_submit(iou); + + return 1; +} + + int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop, uv_fs_t* req, uint32_t fsync_flags) { diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index aafa84c9153..263d54a5234 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -94,6 +94,7 @@ static int known_broken(uv_req_t* req) { #ifdef __linux__ /* TODO(bnoordhuis) make cancellation work with io_uring */ switch (((uv_fs_t*) req)->fs_type) { + case UV_FS_CLOSE: case UV_FS_FDATASYNC: case UV_FS_FSTAT: case UV_FS_FSYNC: From 1c935a34454167b23f8eef7f0f63d7119f0de747 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 20 Apr 2023 12:15:32 +0200 Subject: [PATCH 345/713] linux: remove bug workaround for obsolete kernels (#3965) Libuv no longer supports such kernels so the workaround can be removed. --- src/unix/linux.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index fc879f8ff6a..59e22b74d16 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -876,15 +876,6 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { void uv__io_poll(uv_loop_t* loop, int timeout) { - /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes - * effectively infinite on 32 bits architectures. To avoid blocking - * indefinitely, we cap the timeout and poll again if necessary. - * - * Note that "30 minutes" is a simplification because it depends on - * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200, - * that being the largest value I have seen in the wild (and only once.) - */ - static const int max_safe_timeout = 1789569; uv__loop_internal_fields_t* lfields; struct epoll_event events[1024]; struct epoll_event* pe; @@ -979,12 +970,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (timeout != 0) uv__metrics_set_provider_entry_time(loop); - /* See the comment for max_safe_timeout for an explanation of why - * this is necessary. Executive summary: kernel bug workaround. - */ - if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) - timeout = max_safe_timeout; - nfds = epoll_pwait(loop->backend_fd, events, ARRAY_SIZE(events), From 507f2f950d5da7ab1586a46e81fc83dae10c0138 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 23 Apr 2023 10:54:25 +0100 Subject: [PATCH 346/713] macos: fix source not being followed when cloning (#3941) Fixes: https://github.com/libuv/libuv/issues/3940 --- src/unix/fs.c | 66 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index bf473d2099f..82fa2e1b93e 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -67,7 +67,8 @@ #if defined(__APPLE__) # include -# include +# include +# define UV__FS_CLONE_ACL 0x0004 #elif defined(__linux__) && !defined(FICLONE) # include # define FICLONE _IOW(0x94, 9, int) @@ -1242,9 +1243,34 @@ static ssize_t uv__fs_write(uv_fs_t* req) { return r; } -static ssize_t uv__fs_copyfile(uv_fs_t* req) { #if defined(__APPLE__) && !TARGET_OS_IPHONE - /* On macOS, use the native copyfile(3). */ + +static int uv__fs_clonefile_mac(uv_fs_t* req) { + static _Atomic int no_clone_acl; + int flags; + + flags = UV__FS_CLONE_ACL; + if (atomic_load_explicit(&no_clone_acl, memory_order_relaxed)) + flags = 0; + + /* Note: clonefile() does not set the group ID on the destination + * file correctly. */ + if (!clonefile(req->path, req->new_path, flags)) + return 0; /* success */ + + if (errno == EINVAL) { + atomic_store_explicit(&no_clone_acl, 1, memory_order_relaxed); + errno = 0; + /* UV__FS_CLONE_ACL flag not supported (macOS < 13); try without. */ + if (!clonefile(req->path, req->new_path, 0)) + return 0; /* success */ + } + + return UV__ERR(errno); +} + +static int uv__fs_fcopyfile_mac(uv_fs_t* req) { + int rc; copyfile_flags_t flags; /* Don't overwrite the destination if its permissions disallow it. */ @@ -1253,22 +1279,38 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { return UV__ERR(errno); } - flags = COPYFILE_ALL; + if ((req->flags & UV_FS_COPYFILE_FICLONE) || + (req->flags & UV_FS_COPYFILE_FICLONE_FORCE)) { + rc = uv__fs_clonefile_mac(req); - if (req->flags & UV_FS_COPYFILE_FICLONE) - flags |= COPYFILE_CLONE; + /* Return on success. + * If an error occurred and force was set, return the error to the caller; + * fall back to copyfile() when force was not set. */ + if (rc == 0 || (req->flags & UV_FS_COPYFILE_FICLONE_FORCE)) + return rc; - if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) - flags |= COPYFILE_CLONE_FORCE; - - if (req->flags & UV_FS_COPYFILE_EXCL) - flags |= COPYFILE_EXCL; + /* cloning failed. Inherit clonefile flags required for + falling back to copyfile. */ + flags = COPYFILE_ALL | COPYFILE_NOFOLLOW_SRC | COPYFILE_EXCL; + } else { + flags = COPYFILE_ALL; + if (req->flags & UV_FS_COPYFILE_EXCL) + flags |= COPYFILE_EXCL; + } if (copyfile(req->path, req->new_path, NULL, flags)) return UV__ERR(errno); return 0; -#else /* defined(__APPLE__) && !TARGET_OS_IPHONE */ +} + +#endif /* defined(__APPLE__) && !TARGET_OS_IPHONE */ + +static int uv__fs_copyfile(uv_fs_t* req) { +#if defined(__APPLE__) && !TARGET_OS_IPHONE + /* On macOS, use the native clonefile(2)/copyfile(3). */ + return uv__fs_fcopyfile_mac(req); +#else uv_fs_t fs_req; uv_file srcfd; uv_file dstfd; From 4fc331f8e828c9dfef012a4a58c198c956a81ab5 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 23 Apr 2023 17:52:41 +0200 Subject: [PATCH 347/713] doc: update active maintainers list (#3967) Move Bert and Fedor to emeriti. --- MAINTAINERS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index a55606bf28e..ff8be88b7b7 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -4,12 +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) -* **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) * **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) @@ -29,6 +26,9 @@ 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)) +* **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)) * **John Barboza** ([@jbarz](https://github.com/jbarz)) From b60f08e782e50b7ee2bed2e655570f6a5780199c Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Wed, 12 Apr 2023 13:30:56 -0600 Subject: [PATCH 348/713] test: add ASSERT_OK (#3957) The majority of uses for ASSERT_EQ are to check if the return value is 0. So make a macro specifically for this and make things easier to read. --- test/task.h | 1 + 1 file changed, 1 insertion(+) diff --git a/test/task.h b/test/task.h index c90804ddfef..fa6cc0ed535 100644 --- a/test/task.h +++ b/test/task.h @@ -198,6 +198,7 @@ typedef enum { #define ASSERT_LE(a, b) ASSERT_BASE(a, <=, b, int64_t, PRId64) #define ASSERT_LT(a, b) ASSERT_BASE(a, <, b, int64_t, PRId64) #define ASSERT_NE(a, b) ASSERT_BASE(a, !=, b, int64_t, PRId64) +#define ASSERT_OK(a) ASSERT_BASE(a, ==, 0, int64_t, PRId64) #define ASSERT_UINT64_EQ(a, b) ASSERT_BASE(a, ==, b, uint64_t, PRIu64) #define ASSERT_UINT64_GE(a, b) ASSERT_BASE(a, >=, b, uint64_t, PRIu64) From e02642cf3b768b2c58a41f97fa38507e032ae415 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Mon, 17 Apr 2023 12:48:39 -0600 Subject: [PATCH 349/713] src: fix events/events_waiting metrics counter (#3957) The worker pool calls all callbacks locally within the queue. So the value of nevents doesn't properly reflect that case. Increase the number of events directly from the worker pool's callback to correct this. In order to properly determine if the events_waiting counter needs to be incremented, store the timeout value at the time the event provider was called. --- src/threadpool.c | 17 +++++ src/unix/aix.c | 11 ++- src/unix/kqueue.c | 10 ++- src/unix/linux.c | 13 +++- src/unix/os390.c | 11 ++- src/unix/posix-poll.c | 11 ++- src/uv-common.h | 1 + src/win/core.c | 20 +++++- test/test-list.h | 2 + test/test-metrics.c | 151 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 240 insertions(+), 7 deletions(-) diff --git a/src/threadpool.c b/src/threadpool.c index 42322ebbbcf..51962bf0021 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -311,12 +311,15 @@ void uv__work_done(uv_async_t* handle) { QUEUE* q; QUEUE wq; int err; + int nevents; loop = container_of(handle, uv_loop_t, wq_async); uv_mutex_lock(&loop->wq_mutex); QUEUE_MOVE(&loop->wq, &wq); uv_mutex_unlock(&loop->wq_mutex); + nevents = 0; + while (!QUEUE_EMPTY(&wq)) { q = QUEUE_HEAD(&wq); QUEUE_REMOVE(q); @@ -324,6 +327,20 @@ void uv__work_done(uv_async_t* handle) { w = container_of(q, struct uv__work, wq); err = (w->work == uv__cancelled) ? UV_ECANCELED : 0; w->done(w, err); + nevents++; + } + + /* This check accomplishes 2 things: + * 1. Even if the queue was empty, the call to uv__work_done() should count + * as an event. Which will have been added by the event loop when + * calling this callback. + * 2. Prevents accidental wrap around in case nevents == 0 events == 0. + */ + if (nevents > 1) { + /* Subtract 1 to counter the call to uv__work_done(). */ + uv__metrics_inc_events(loop, nevents - 1); + if (uv__get_internal_fields(loop)->current_timeout == 0) + uv__metrics_inc_events_waiting(loop, nevents - 1); } } diff --git a/src/unix/aix.c b/src/unix/aix.c index b855282ebc8..f1afbed49ec 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -131,6 +131,7 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { void uv__io_poll(uv_loop_t* loop, int timeout) { + uv__loop_internal_fields_t* lfields; struct pollfd events[1024]; struct pollfd pqry; struct pollfd* pe; @@ -154,6 +155,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { return; } + lfields = uv__get_internal_fields(loop); + while (!QUEUE_EMPTY(&loop->watcher_queue)) { q = QUEUE_HEAD(&loop->watcher_queue); QUEUE_REMOVE(q); @@ -217,7 +220,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ - if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + if (lfields->flags & UV_METRICS_IDLE_TIME) { reset_timeout = 1; user_timeout = timeout; timeout = 0; @@ -232,6 +235,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { 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; + nfds = pollset_poll(loop->backend_fd, events, ARRAY_SIZE(events), diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index deb486bae7a..82916d65933 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -127,6 +127,7 @@ static void uv__kqueue_delete(int kqfd, const struct kevent *ev) { void uv__io_poll(uv_loop_t* loop, int timeout) { + uv__loop_internal_fields_t* lfields; struct kevent events[1024]; struct kevent* ev; struct timespec spec; @@ -155,6 +156,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { return; } + lfields = uv__get_internal_fields(loop); nevents = 0; while (!QUEUE_EMPTY(&loop->watcher_queue)) { @@ -222,7 +224,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { base = loop->time; count = 48; /* Benchmarks suggest this gives the best throughput. */ - if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + if (lfields->flags & UV_METRICS_IDLE_TIME) { reset_timeout = 1; user_timeout = timeout; timeout = 0; @@ -245,6 +247,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (pset != NULL) pthread_sigmask(SIG_BLOCK, pset, NULL); + /* Store the current timeout in a location that's globally accessible so + * other locations like uv__work_done() can determine whether the queue + * of events in the callback were waiting when poll was called. + */ + lfields->current_timeout = timeout; + nfds = kevent(loop->backend_fd, events, nevents, diff --git a/src/unix/linux.c b/src/unix/linux.c index 59e22b74d16..27ed37b1455 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -834,12 +834,14 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { uint32_t tail; uint32_t mask; uint32_t i; + int nevents; head = *iou->cqhead; tail = atomic_load_explicit((_Atomic uint32_t*) iou->cqtail, memory_order_acquire); mask = iou->cqmask; cqe = iou->cqe; + nevents = 0; for (i = head; i != tail; i++) { e = &cqe[i & mask]; @@ -865,13 +867,16 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { uv__metrics_update_idle_time(loop); req->cb(req); + nevents++; } atomic_store_explicit((_Atomic uint32_t*) iou->cqhead, tail, memory_order_release); - uv__metrics_inc_events(loop, 1); + uv__metrics_inc_events(loop, nevents); + if (uv__get_internal_fields(loop)->current_timeout == 0) + uv__metrics_inc_events_waiting(loop, nevents); } @@ -970,6 +975,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { 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; + nfds = epoll_pwait(loop->backend_fd, events, ARRAY_SIZE(events), diff --git a/src/unix/os390.c b/src/unix/os390.c index 3954b2c2753..a87c2d77faf 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -808,6 +808,7 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) { void uv__io_poll(uv_loop_t* loop, int timeout) { static const int max_safe_timeout = 1789569; + uv__loop_internal_fields_t* lfields; struct epoll_event events[1024]; struct epoll_event* pe; struct epoll_event e; @@ -830,6 +831,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { return; } + lfields = uv__get_internal_fields(loop); + while (!QUEUE_EMPTY(&loop->watcher_queue)) { uv_stream_t* stream; @@ -877,7 +880,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { int nevents = 0; have_signals = 0; - if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + if (lfields->flags & UV_METRICS_IDLE_TIME) { reset_timeout = 1; user_timeout = timeout; timeout = 0; @@ -896,6 +899,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) timeout = max_safe_timeout; + /* Store the current timeout in a location that's globally accessible so + * other locations like uv__work_done() can determine whether the queue + * of events in the callback were waiting when poll was called. + */ + lfields->current_timeout = timeout; + nfds = epoll_wait(loop->ep, events, ARRAY_SIZE(events), timeout); diff --git a/src/unix/posix-poll.c b/src/unix/posix-poll.c index 711780ece8d..7e7de86845d 100644 --- a/src/unix/posix-poll.c +++ b/src/unix/posix-poll.c @@ -132,6 +132,7 @@ static void uv__pollfds_del(uv_loop_t* loop, int fd) { void uv__io_poll(uv_loop_t* loop, int timeout) { + uv__loop_internal_fields_t* lfields; sigset_t* pset; sigset_t set; uint64_t time_base; @@ -152,6 +153,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { return; } + lfields = uv__get_internal_fields(loop); + /* Take queued watchers and add their fds to our poll fds array. */ while (!QUEUE_EMPTY(&loop->watcher_queue)) { q = QUEUE_HEAD(&loop->watcher_queue); @@ -179,7 +182,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { assert(timeout >= -1); time_base = loop->time; - if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + if (lfields->flags & UV_METRICS_IDLE_TIME) { reset_timeout = 1; user_timeout = timeout; timeout = 0; @@ -198,6 +201,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (timeout != 0) uv__metrics_set_provider_entry_time(loop); + /* Store the current timeout in a location that's globally accessible so + * other locations like uv__work_done() can determine whether the queue + * of events in the callback were waiting when poll was called. + */ + lfields->current_timeout = timeout; + if (pset != NULL) if (pthread_sigmask(SIG_BLOCK, pset, NULL)) abort(); diff --git a/src/uv-common.h b/src/uv-common.h index df874f8a2c7..b0d9c747137 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -421,6 +421,7 @@ struct uv__iou { struct uv__loop_internal_fields_s { unsigned int flags; uv__loop_metrics_t loop_metrics; + int current_timeout; #ifdef __linux__ struct uv__iou iou; #endif /* __linux__ */ diff --git a/src/win/core.c b/src/win/core.c index a52af5a1b4b..426edb18eb5 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -424,6 +424,7 @@ 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; @@ -433,9 +434,10 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { uint64_t user_timeout; int reset_timeout; + lfields = uv__get_internal_fields(loop); timeout_time = loop->time + timeout; - if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + if (lfields->flags & UV_METRICS_IDLE_TIME) { reset_timeout = 1; user_timeout = timeout; timeout = 0; @@ -450,6 +452,12 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { 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, @@ -507,6 +515,7 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { static void uv__poll(uv_loop_t* loop, DWORD timeout) { + uv__loop_internal_fields_t* lfields; BOOL success; uv_req_t* req; OVERLAPPED_ENTRY overlappeds[128]; @@ -518,9 +527,10 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { uint64_t actual_timeout; int reset_timeout; + lfields = uv__get_internal_fields(loop); timeout_time = loop->time + timeout; - if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { + if (lfields->flags & UV_METRICS_IDLE_TIME) { reset_timeout = 1; user_timeout = timeout; timeout = 0; @@ -537,6 +547,12 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { 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; + success = pGetQueuedCompletionStatusEx(loop->iocp, overlappeds, ARRAY_SIZE(overlappeds), diff --git a/test/test-list.h b/test/test-list.h index 13c96d1dc27..e6332ed46e4 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -556,6 +556,7 @@ TEST_DECLARE (utf8_decode1_overrun) TEST_DECLARE (uname) TEST_DECLARE (metrics_info_check) +TEST_DECLARE (metrics_pool_events) TEST_DECLARE (metrics_idle_time) TEST_DECLARE (metrics_idle_time_thread) TEST_DECLARE (metrics_idle_time_zero) @@ -1192,6 +1193,7 @@ TASK_LIST_START TEST_HELPER (readable_on_eof, tcp4_echo_server) TEST_ENTRY (metrics_info_check) + TEST_ENTRY (metrics_pool_events) TEST_ENTRY (metrics_idle_time) TEST_ENTRY (metrics_idle_time_thread) TEST_ENTRY (metrics_idle_time_zero) diff --git a/test/test-metrics.c b/test/test-metrics.c index c6fa432a55d..d532f4eff49 100644 --- a/test/test-metrics.c +++ b/test/test-metrics.c @@ -34,6 +34,7 @@ typedef struct { static uint64_t last_events_count; static char test_buf[] = "test-buffer\n"; static fs_reqs_t fs_reqs; +static int pool_events_counter; static void timer_spin_cb(uv_timer_t* handle) { @@ -239,3 +240,153 @@ TEST_IMPL(metrics_info_check) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } + + +static void fs_prepare_cb(uv_prepare_t* handle) { + uv_metrics_t metrics; + + ASSERT_OK(uv_metrics_info(uv_default_loop(), &metrics)); + + if (pool_events_counter == 1) + ASSERT_EQ(metrics.events, metrics.events_waiting); + + if (pool_events_counter < 7) + return; + + uv_prepare_stop(handle); + pool_events_counter = -42; +} + + +static void fs_stat_cb(uv_fs_t* req) { + uv_fs_req_cleanup(req); + pool_events_counter++; +} + + +static void fs_work_cb(uv_work_t* req) { +} + + +static void fs_after_work_cb(uv_work_t* req, int status) { + free(req); + pool_events_counter++; +} + + +static void fs_write_cb(uv_fs_t* req) { + uv_work_t* work1 = malloc(sizeof(*work1)); + uv_work_t* work2 = malloc(sizeof(*work2)); + pool_events_counter++; + + uv_fs_req_cleanup(req); + + ASSERT_OK(uv_queue_work(uv_default_loop(), + work1, + fs_work_cb, + fs_after_work_cb)); + ASSERT_OK(uv_queue_work(uv_default_loop(), + work2, + fs_work_cb, + fs_after_work_cb)); +} + + +static void fs_random_cb(uv_random_t* req, int status, void* buf, size_t len) { + pool_events_counter++; +} + + +static void fs_addrinfo_cb(uv_getaddrinfo_t* req, + int status, + struct addrinfo* res) { + uv_freeaddrinfo(req->addrinfo); + pool_events_counter++; +} + + +TEST_IMPL(metrics_pool_events) { + uv_buf_t iov; + uv_fs_t open_req; + uv_fs_t stat1_req; + uv_fs_t stat2_req; + uv_fs_t unlink_req; + uv_fs_t write_req; + uv_getaddrinfo_t addrinfo_req; + uv_metrics_t metrics; + uv_prepare_t prepare; + uv_random_t random_req; + int fd; + char rdata; + + ASSERT_OK(uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME)); + + uv_fs_unlink(NULL, &unlink_req, "test_file", NULL); + uv_fs_req_cleanup(&unlink_req); + + ASSERT_OK(uv_prepare_init(uv_default_loop(), &prepare)); + ASSERT_OK(uv_prepare_start(&prepare, fs_prepare_cb)); + + pool_events_counter = 0; + fd = uv_fs_open(NULL, + &open_req, + "test_file", + O_WRONLY | O_CREAT, + S_IRUSR | S_IWUSR, + NULL); + ASSERT_GT(fd, 0); + uv_fs_req_cleanup(&open_req); + + iov = uv_buf_init(test_buf, sizeof(test_buf)); + ASSERT_OK(uv_fs_write(uv_default_loop(), + &write_req, + fd, + &iov, + 1, + 0, + fs_write_cb)); + ASSERT_OK(uv_fs_stat(uv_default_loop(), + &stat1_req, + "test_file", + fs_stat_cb)); + ASSERT_OK(uv_fs_stat(uv_default_loop(), + &stat2_req, + "test_file", + fs_stat_cb)); + ASSERT_OK(uv_random(uv_default_loop(), + &random_req, + &rdata, + 1, + 0, + fs_random_cb)); + ASSERT_OK(uv_getaddrinfo(uv_default_loop(), + &addrinfo_req, + fs_addrinfo_cb, + "example.invalid", + NULL, + NULL)); + + /* Sleep for a moment to hopefully force the events to complete before + * entering the event loop. */ + uv_sleep(100); + + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT_OK(uv_metrics_info(uv_default_loop(), &metrics)); + /* It's possible for uv__work_done() to execute one extra time even though the + * QUEUE has already been cleared out. This has to do with the way we use an + * uv_async to tell the event loop thread to process the worker pool QUEUE. */ + ASSERT_GE(metrics.events, 7); + /* It's possible one of the other events also got stuck in the event queue, so + * check GE instead of EQ. Reason for 4 instead of 5 is because the call to + * uv_getaddrinfo() is racey and slow. So can't guarantee that it'll always + * execute before sleep completes. */ + ASSERT_GE(metrics.events_waiting, 4); + ASSERT_EQ(pool_events_counter, -42); + + uv_fs_unlink(NULL, &unlink_req, "test_file", NULL); + uv_fs_req_cleanup(&unlink_req); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} From c8a1e6132bf377ea84c7e1e9c840691ef4999a07 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 27 Apr 2023 22:13:46 +0200 Subject: [PATCH 350/713] unix,win: add uv_clock_gettime() (#3971) Fixes: https://github.com/libuv/libuv/issues/1674 --- docs/src/fs.rst | 3 ++- docs/src/misc.rst | 42 +++++++++++++++++++++++++++++++++++++++--- include/uv.h | 32 ++++++++++++++++++++++---------- src/unix/core.c | 30 ++++++++++++++++++++++++++++++ src/win/util.c | 33 +++++++++++++++++++++++++++++++++ test/test-hrtime.c | 13 +++++++++++++ test/test-list.h | 3 +++ 7 files changed, 142 insertions(+), 14 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index e7522d59927..891ee74c19d 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -30,7 +30,8 @@ Data types .. c:type:: uv_timespec_t - Portable equivalent of ``struct timespec``. + Y2K38-unsafe data type for storing times with nanosecond resolution. + Will be replaced with :c:type:`uv_timespec64_t` in libuv v2.0. :: diff --git a/docs/src/misc.rst b/docs/src/misc.rst index e8b9a4c838d..c2ad5804a6f 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -73,7 +73,8 @@ Data types .. c:type:: uv_timeval_t - Data type for storing times. + Y2K38-unsafe data type for storing times with microsecond resolution. + Will be replaced with :c:type:`uv_timeval64_t` in libuv v2.0. :: @@ -84,7 +85,7 @@ Data types .. c:type:: uv_timeval64_t - Alternative data type for storing times. + Y2K38-safe data type for storing times with microsecond resolution. :: @@ -93,6 +94,28 @@ Data types int32_t tv_usec; } uv_timeval64_t; +.. c:type:: uv_timespec64_t + + Y2K38-safe data type for storing times with nanosecond resolution. + + :: + + typedef struct { + int64_t tv_sec; + int32_t tv_nsec; + } uv_timespec64_t; + +.. c:enum:: uv_clock_id + + Clock source for :c:func:`uv_clock_gettime`. + + :: + + typedef enum { + UV_CLOCK_MONOTONIC, + UV_CLOCK_REALTIME + } uv_clock_id; + .. c:type:: uv_rusage_t Data type for resource usage results. @@ -588,7 +611,7 @@ API .. c:function:: uint64_t uv_hrtime(void) - Returns the current high-resolution real time. This is expressed in + Returns the current high-resolution timestamp. This is expressed in nanoseconds. It is relative to an arbitrary time in the past. It is not related to the time of day and therefore not subject to clock drift. The primary use is for measuring performance between intervals. @@ -597,6 +620,19 @@ API Not every platform can support nanosecond resolution; however, this value will always be in nanoseconds. +.. c:function:: int uv_clock_gettime(uv_clock_id clock_id, uv_timespec64_t* ts) + + Obtain the current system time from a high-resolution real-time or monotonic + clock source. + + The real-time clock counts from the UNIX epoch (1970-01-01) and is subject + to time adjustments; it can jump back in time. + + The monotonic clock counts from an arbitrary point in the past and never + jumps back in time. + + .. versionadded:: 1.45.0 + .. c:function:: void uv_print_all_handles(uv_loop_t* loop, FILE* stream) Prints all handles associated with the given `loop` to the given `stream`. diff --git a/include/uv.h b/include/uv.h index e6724deffdf..f3d70231ffa 100644 --- a/include/uv.h +++ b/include/uv.h @@ -345,11 +345,32 @@ typedef void (*uv_random_cb)(uv_random_t* req, void* buf, size_t buflen); +typedef enum { + UV_CLOCK_MONOTONIC, + UV_CLOCK_REALTIME +} uv_clock_id; + +/* XXX(bnoordhuis) not 2038-proof, https://github.com/libuv/libuv/issues/3864 */ typedef struct { long tv_sec; long tv_nsec; } uv_timespec_t; +typedef struct { + int64_t tv_sec; + int32_t tv_nsec; +} uv_timespec64_t; + +/* XXX(bnoordhuis) not 2038-proof, https://github.com/libuv/libuv/issues/3864 */ +typedef struct { + long tv_sec; + long tv_usec; +} uv_timeval_t; + +typedef struct { + int64_t tv_sec; + int32_t tv_usec; +} uv_timeval64_t; typedef struct { uint64_t st_dev; @@ -1191,16 +1212,6 @@ UV_EXTERN int uv_uptime(double* uptime); UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd); UV_EXTERN int uv_open_osfhandle(uv_os_fd_t os_fd); -typedef struct { - long tv_sec; - long tv_usec; -} uv_timeval_t; - -typedef struct { - int64_t tv_sec; - int32_t tv_usec; -} uv_timeval64_t; - typedef struct { uv_timeval_t ru_utime; /* user CPU time used */ uv_timeval_t ru_stime; /* system CPU time used */ @@ -1732,6 +1743,7 @@ UV_EXTERN uint64_t uv_get_total_memory(void); UV_EXTERN uint64_t uv_get_constrained_memory(void); UV_EXTERN uint64_t uv_get_available_memory(void); +UV_EXTERN int uv_clock_gettime(uv_clock_id clock_id, uv_timespec64_t* ts); UV_EXTERN uint64_t uv_hrtime(void); UV_EXTERN void uv_sleep(unsigned int msec); diff --git a/src/unix/core.c b/src/unix/core.c index 3dd7a94ca4d..9c0b3f99b80 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -44,6 +44,7 @@ #include #include #include +#include /* clock_gettime */ #ifdef __sun # include @@ -108,6 +109,35 @@ STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base)); STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len)); +/* https://github.com/libuv/libuv/issues/1674 */ +int uv_clock_gettime(uv_clock_id clock_id, uv_timespec64_t* ts) { + struct timespec t; + int r; + + if (ts == NULL) + return UV_EFAULT; + + switch (clock_id) { + default: + return UV_EINVAL; + case UV_CLOCK_MONOTONIC: + r = clock_gettime(CLOCK_MONOTONIC, &t); + break; + case UV_CLOCK_REALTIME: + r = clock_gettime(CLOCK_REALTIME, &t); + break; + } + + if (r) + return UV__ERR(errno); + + ts->tv_sec = t.tv_sec; + ts->tv_nsec = t.tv_nsec; + + return 0; +} + + uint64_t uv_hrtime(void) { return uv__hrtime(UV_CLOCK_PRECISE); } diff --git a/src/win/util.c b/src/win/util.c index 6232ce1505a..f6ec79cd57b 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -31,6 +31,7 @@ #include "internal.h" /* clang-format off */ +#include #include #include #include @@ -504,11 +505,43 @@ int uv_get_process_title(char* buffer, size_t size) { } +/* https://github.com/libuv/libuv/issues/1674 */ +int uv_clock_gettime(uv_clock_id clock_id, uv_timespec64_t* ts) { + FILETIME ft; + int64_t t; + + if (ts == NULL) + return UV_EFAULT; + + switch (clock_id) { + case UV_CLOCK_MONOTONIC: + uv__once_init(); + t = uv__hrtime(UV__NANOSEC); + ts->tv_sec = t / 1000000000; + ts->tv_nsec = t % 1000000000; + return 0; + case UV_CLOCK_REALTIME: + GetSystemTimePreciseAsFileTime(&ft); + /* In 100-nanosecond increments from 1601-01-01 UTC because why not? */ + t = (int64_t) ft.dwHighDateTime << 32 | ft.dwLowDateTime; + /* Convert to UNIX epoch, 1970-01-01. Still in 100 ns increments. */ + t -= 116444736000000000ll; + /* Now convert to seconds and nanoseconds. */ + ts->tv_sec = t / 10000000; + ts->tv_nsec = t % 10000000 * 100; + return 0; + } + + return UV_EINVAL; +} + + uint64_t uv_hrtime(void) { uv__once_init(); return uv__hrtime(UV__NANOSEC); } + uint64_t uv__hrtime(unsigned int scale) { LARGE_INTEGER counter; double scaled_freq; diff --git a/test/test-hrtime.c b/test/test-hrtime.c index 9d461d9623d..854a482f23c 100644 --- a/test/test-hrtime.c +++ b/test/test-hrtime.c @@ -50,3 +50,16 @@ TEST_IMPL(hrtime) { } return 0; } + + +TEST_IMPL(clock_gettime) { + uv_timespec64_t t; + + ASSERT_EQ(UV_EINVAL, uv_clock_gettime(1337, &t)); + ASSERT_EQ(UV_EFAULT, uv_clock_gettime(1337, NULL)); + ASSERT_EQ(0, uv_clock_gettime(UV_CLOCK_MONOTONIC, &t)); + ASSERT_EQ(0, uv_clock_gettime(UV_CLOCK_REALTIME, &t)); + ASSERT_GT(1682500000000ll, t.tv_sec); /* 2023-04-26T09:06:40.000Z */ + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index e6332ed46e4..85517fc136d 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -289,6 +289,7 @@ TEST_DECLARE (handle_fileno) TEST_DECLARE (homedir) TEST_DECLARE (tmpdir) TEST_DECLARE (hrtime) +TEST_DECLARE (clock_gettime) TEST_DECLARE (getaddrinfo_fail) TEST_DECLARE (getaddrinfo_fail_sync) TEST_DECLARE (getaddrinfo_basic) @@ -919,6 +920,8 @@ TASK_LIST_START TEST_ENTRY_CUSTOM (hrtime, 0, 0, 20000) + TEST_ENTRY (clock_gettime) + TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000) TEST_ENTRY_CUSTOM (getaddrinfo_fail_sync, 0, 0, 10000) From 932092e95dceb0d6665d5e1e04475b7ea07c08a7 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 27 Apr 2023 22:15:01 +0200 Subject: [PATCH 351/713] build: remove freebsd and openbsd buildbots (#3974) The buildbots are super flaky compared to other platforms and no one seems invested enough to investigate. They don't add nearly enough value for the friction they cause so away they go. Fixes: https://github.com/libuv/libuv/issues/3934 Fixes: https://github.com/libuv/libuv/issues/3972 Refs: https://github.com/libuv/libuv/pull/3548 --- .github/workflows/CI-unix.yml | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 858235e7651..c912a6faff5 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -146,36 +146,3 @@ jobs: - name: Test run: | ${{ matrix.config.qemu }} build/uv_run_tests_a - - build-bsd: - timeout-minutes: 30 - runs-on: ${{ matrix.config.runner }} - name: build-${{ matrix.config.os }}-${{ matrix.config.version }} - - strategy: - fail-fast: false - matrix: - config: - # The OS versions supported are specific to the version of the action - # https://github.com/cross-platform-actions/action/blob/master/changelog.md - - { os: freebsd, version: '13.1', runner: 'ubuntu-latest', install: 'pkg install -y' } - - { os: openbsd, version: '7.2', runner: 'macos-11', install: 'pkg_add -I' } - - steps: - - uses: actions/checkout@v2 - - - uses: cross-platform-actions/action@v0.9.0 - with: - operating_system: ${{ matrix.config.os }} - version: ${{ matrix.config.version }} - run: | - sudo ${{ matrix.config.install }} cmake ninja - sudo hostname -s ci-host - mkdir build - cd build - cmake .. -DBUILD_TESTING=ON -G Ninja - cmake --build . - ls -lh - ./uv_run_tests platform_output - ./uv_run_tests_a platform_output - ctest -V From c51522c08f8882b6d4a93b11325f09cd44aea1ba Mon Sep 17 00:00:00 2001 From: sivadeilra Date: Sat, 29 Apr 2023 03:59:56 -0700 Subject: [PATCH 352/713] win: fix race condition in uv__init_console() (#3973) Co-authored-by: Arlie Davis Fixes: https://github.com/libuv/libuv/issues/3970 --- src/win/tty.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/win/tty.c b/src/win/tty.c index c41a16ef00f..60f249b6a2a 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -170,14 +170,14 @@ void uv__console_init(void) { 0); if (uv__tty_console_handle != INVALID_HANDLE_VALUE) { CONSOLE_SCREEN_BUFFER_INFO sb_info; - QueueUserWorkItem(uv__tty_console_resize_message_loop_thread, - NULL, - WT_EXECUTELONGFUNCTION); uv_mutex_init(&uv__tty_console_resize_mutex); if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) { uv__tty_console_width = sb_info.dwSize.X; uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; } + QueueUserWorkItem(uv__tty_console_resize_message_loop_thread, + NULL, + WT_EXECUTELONGFUNCTION); } } @@ -2423,7 +2423,6 @@ static void uv__tty_console_signal_resize(void) { height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; uv_mutex_lock(&uv__tty_console_resize_mutex); - assert(uv__tty_console_width != -1 && uv__tty_console_height != -1); if (width != uv__tty_console_width || height != uv__tty_console_height) { uv__tty_console_width = width; uv__tty_console_height = height; From f27208224084fc972b9d2802486d97ef31b51a39 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 1 May 2023 06:17:26 +0200 Subject: [PATCH 353/713] linux: fix logic bug in sqe ring space check (#3980) Handle wraparound properly, otherwise we may end up overwriting elements that have not been consumed by the kernel yet. --- src/unix/linux.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 27ed37b1455..3f14e756839 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -604,6 +604,8 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, uv_fs_t* req) { struct uv__io_uring_sqe* sqe; uint32_t head; + uint32_t tail; + uint32_t mask; uint32_t slot; if (iou->ringfd == -1) @@ -611,10 +613,13 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, head = atomic_load_explicit((_Atomic uint32_t*) iou->sqhead, memory_order_acquire); - if (head == *iou->sqtail + 1) + tail = *iou->sqtail; + mask = iou->sqmask; + + if ((head & mask) == ((tail + 1) & mask)) return NULL; /* No room in ring buffer. TODO(bnoordhuis) maybe flush it? */ - slot = *iou->sqtail & iou->sqmask; + slot = tail & mask; iou->sqarray[slot] = slot; /* Identity mapping of index -> sqe. */ sqe = iou->sqe; From 6e073ef5daf93b708a654008959b823b58029e88 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 1 May 2023 09:00:08 +0200 Subject: [PATCH 354/713] linux: use io_uring to batch epoll_ctl calls (#3979) This work was sponsored by ISC, the Internet Systems Consortium. --- src/unix/linux.c | 410 +++++++++++++++++++++++++++++++++-------------- src/uv-common.h | 2 + 2 files changed, 288 insertions(+), 124 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 3f14e756839..c5911552773 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -149,9 +149,11 @@ enum { UV__IORING_OP_OPENAT = 18, UV__IORING_OP_CLOSE = 19, UV__IORING_OP_STATX = 21, + UV__IORING_OP_EPOLL_CTL = 29, }; enum { + UV__IORING_ENTER_GETEVENTS = 1u, UV__IORING_ENTER_SQ_WAKEUP = 2u, }; @@ -248,6 +250,10 @@ STATIC_ASSERT(40 + 40 + 40 == sizeof(struct uv__io_uring_params)); STATIC_ASSERT(40 == offsetof(struct uv__io_uring_params, sq_off)); STATIC_ASSERT(80 == offsetof(struct uv__io_uring_params, cq_off)); +STATIC_ASSERT(EPOLL_CTL_ADD < 4); +STATIC_ASSERT(EPOLL_CTL_DEL < 4); +STATIC_ASSERT(EPOLL_CTL_MOD < 4); + struct watcher_list { RB_ENTRY(watcher_list) entry; QUEUE watchers; @@ -269,6 +275,17 @@ static int compare_watchers(const struct watcher_list* a, static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop); +static void uv__epoll_ctl_flush(int epollfd, + struct uv__iou* ctl, + struct epoll_event (*events)[256]); + +static void uv__epoll_ctl_prep(int epollfd, + struct uv__iou* ctl, + struct epoll_event (*events)[256], + int op, + int fd, + struct epoll_event* e); + RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers) @@ -384,45 +401,40 @@ static int uv__use_io_uring(void) { } -int uv__platform_loop_init(uv_loop_t* loop) { +static void uv__iou_init(int epollfd, + struct uv__iou* iou, + uint32_t entries, + uint32_t flags) { struct uv__io_uring_params params; struct epoll_event e; - struct uv__iou* iou; size_t cqlen; size_t sqlen; size_t maxlen; size_t sqelen; + uint32_t i; char* sq; char* sqe; int ringfd; - iou = &uv__get_internal_fields(loop)->iou; - iou->ringfd = -1; - - loop->inotify_watchers = NULL; - loop->inotify_fd = -1; - loop->backend_fd = epoll_create1(O_CLOEXEC); - - if (loop->backend_fd == -1) - return UV__ERR(errno); - - if (!uv__use_io_uring()) - return 0; - sq = MAP_FAILED; sqe = MAP_FAILED; + if (!uv__use_io_uring()) + return; + /* SQPOLL required CAP_SYS_NICE until linux v5.12 relaxed that requirement. * Mostly academic because we check for a v5.13 kernel afterwards anyway. */ memset(¶ms, 0, sizeof(params)); - params.flags = UV__IORING_SETUP_SQPOLL; - params.sq_thread_idle = 10; /* milliseconds */ + params.flags = flags; + + if (flags & UV__IORING_SETUP_SQPOLL) + params.sq_thread_idle = 10; /* milliseconds */ /* Kernel returns a file descriptor with O_CLOEXEC flag set. */ - ringfd = uv__io_uring_setup(64, ¶ms); + ringfd = uv__io_uring_setup(entries, ¶ms); if (ringfd == -1) - return 0; /* Not an error, falls back to thread pool. */ + return; /* IORING_FEAT_RSRC_TAGS is used to detect linux v5.13 but what we're * actually detecting is whether IORING_OP_STATX works with SQPOLL. @@ -461,6 +473,18 @@ int uv__platform_loop_init(uv_loop_t* loop) { if (sq == MAP_FAILED || sqe == MAP_FAILED) goto fail; + if (flags & UV__IORING_SETUP_SQPOLL) { + /* Only interested in completion events. To get notified when + * the kernel pulls items from the submission ring, add POLLOUT. + */ + memset(&e, 0, sizeof(e)); + e.events = POLLIN; + e.data.fd = ringfd; + + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ringfd, &e)) + goto fail; + } + iou->sqhead = (uint32_t*) (sq + params.sq_off.head); iou->sqtail = (uint32_t*) (sq + params.sq_off.tail); iou->sqmask = *(uint32_t*) (sq + params.sq_off.ring_mask); @@ -479,17 +503,10 @@ int uv__platform_loop_init(uv_loop_t* loop) { iou->ringfd = ringfd; iou->in_flight = 0; - /* Only interested in completion events. To get notified when - * the kernel pulls items from the submission ring, add POLLOUT. - */ - memset(&e, 0, sizeof(e)); - e.events = POLLIN; - e.data.fd = ringfd; - - if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, ringfd, &e)) - goto fail; + for (i = 0; i <= iou->sqmask; i++) + iou->sqarray[i] = i; /* Slot -> sqe identity mapping. */ - return 0; + return; fail: if (sq != MAP_FAILED) @@ -499,8 +516,37 @@ int uv__platform_loop_init(uv_loop_t* loop) { munmap(sqe, sqelen); uv__close(ringfd); +} + + +static void uv__iou_delete(struct uv__iou* iou) { + if (iou->ringfd != -1) { + munmap(iou->sq, iou->maxlen); + munmap(iou->sqe, iou->sqelen); + uv__close(iou->ringfd); + iou->ringfd = -1; + } +} + + +int uv__platform_loop_init(uv_loop_t* loop) { + uv__loop_internal_fields_t* lfields; + + lfields = uv__get_internal_fields(loop); + lfields->ctl.ringfd = -1; + lfields->iou.ringfd = -1; - return 0; /* Not an error, falls back to thread pool. */ + loop->inotify_watchers = NULL; + loop->inotify_fd = -1; + loop->backend_fd = epoll_create1(O_CLOEXEC); + + if (loop->backend_fd == -1) + return UV__ERR(errno); + + uv__iou_init(loop->backend_fd, &lfields->iou, 64, UV__IORING_SETUP_SQPOLL); + uv__iou_init(loop->backend_fd, &lfields->ctl, 256, 0); + + return 0; } @@ -525,54 +571,62 @@ int uv__io_fork(uv_loop_t* loop) { void uv__platform_loop_delete(uv_loop_t* loop) { - struct uv__iou* iou; + uv__loop_internal_fields_t* lfields; - iou = &uv__get_internal_fields(loop)->iou; + lfields = uv__get_internal_fields(loop); + uv__iou_delete(&lfields->ctl); + uv__iou_delete(&lfields->iou); if (loop->inotify_fd != -1) { uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN); uv__close(loop->inotify_fd); loop->inotify_fd = -1; } - - if (iou->ringfd != -1) { - munmap(iou->sq, iou->maxlen); - munmap(iou->sqe, iou->sqelen); - uv__close(iou->ringfd); - iou->ringfd = -1; - } } -void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { +struct uv__invalidate { + struct epoll_event (*prep)[256]; struct epoll_event* events; + int nfds; +}; + + +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + uv__loop_internal_fields_t* lfields; + struct uv__invalidate* inv; struct epoll_event dummy; - uintptr_t i; - uintptr_t nfds; + int i; - assert(loop->watchers != NULL); - assert(fd >= 0); + lfields = uv__get_internal_fields(loop); + inv = lfields->inv; - events = (struct epoll_event*) loop->watchers[loop->nwatchers]; - nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; - if (events != NULL) - /* Invalidate events with same file descriptor */ - for (i = 0; i < nfds; i++) - if (events[i].data.fd == fd) - events[i].data.fd = -1; + /* Invalidate events with same file descriptor */ + if (inv != NULL) + for (i = 0; i < inv->nfds; i++) + if (inv->events[i].data.fd == fd) + inv->events[i].data.fd = -1; /* Remove the file descriptor from the epoll. * This avoids a problem where the same file description remains open * in another process, causing repeated junk epoll events. * * We pass in a dummy epoll_event, to work around a bug in old kernels. + * + * Work around a bug in kernels 3.10 to 3.19 where passing a struct that + * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. */ - if (loop->backend_fd >= 0) { - /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that - * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. - */ - memset(&dummy, 0, sizeof(dummy)); + memset(&dummy, 0, sizeof(dummy)); + + if (inv == NULL) { epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy); + } else { + uv__epoll_ctl_prep(loop->backend_fd, + &lfields->ctl, + inv->prep, + EPOLL_CTL_DEL, + fd, + &dummy); } } @@ -620,8 +674,6 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, return NULL; /* No room in ring buffer. TODO(bnoordhuis) maybe flush it? */ slot = tail & mask; - iou->sqarray[slot] = slot; /* Identity mapping of index -> sqe. */ - sqe = iou->sqe; sqe = &sqe[slot]; memset(sqe, 0, sizeof(*sqe)); @@ -652,7 +704,7 @@ static void uv__iou_submit(struct uv__iou* iou) { if (flags & UV__IORING_SQ_NEED_WAKEUP) if (uv__io_uring_enter(iou->ringfd, 0, 0, UV__IORING_ENTER_SQ_WAKEUP)) - perror("libuv: io_uring_enter"); /* Can't happen. */ + perror("libuv: io_uring_enter(wakeup)"); /* Can't happen. */ } @@ -885,11 +937,135 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { } +static void uv__epoll_ctl_prep(int epollfd, + struct uv__iou* ctl, + struct epoll_event (*events)[256], + int op, + int fd, + struct epoll_event* e) { + struct uv__io_uring_sqe* sqe; + struct epoll_event* pe; + uint32_t mask; + uint32_t slot; + + if (ctl->ringfd == -1) { + if (!epoll_ctl(epollfd, op, fd, e)) + return; + + if (op == EPOLL_CTL_DEL) + return; /* Ignore errors, may be racing with another thread. */ + + if (op != EPOLL_CTL_ADD) + abort(); + + if (errno != EEXIST) + abort(); + + /* File descriptor that's been watched before, update event mask. */ + if (!epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, e)) + return; + + abort(); + } else { + mask = ctl->sqmask; + slot = (*ctl->sqtail)++ & mask; + + pe = &(*events)[slot]; + *pe = *e; + + sqe = ctl->sqe; + sqe = &sqe[slot]; + + memset(sqe, 0, sizeof(*sqe)); + sqe->addr = (uintptr_t) pe; + sqe->fd = epollfd; + sqe->len = op; + sqe->off = fd; + sqe->opcode = UV__IORING_OP_EPOLL_CTL; + sqe->user_data = op | slot << 2 | (int64_t) fd << 32; + + if ((*ctl->sqhead & mask) == (*ctl->sqtail & mask)) + uv__epoll_ctl_flush(epollfd, ctl, events); + } +} + + +static void uv__epoll_ctl_flush(int epollfd, + struct uv__iou* ctl, + struct epoll_event (*events)[256]) { + struct epoll_event oldevents[256]; + struct uv__io_uring_cqe* cqe; + uint32_t oldslot; + uint32_t slot; + uint32_t n; + int fd; + int op; + int rc; + + STATIC_ASSERT(sizeof(oldevents) == sizeof(*events)); + assert(ctl->ringfd != -1); + assert(*ctl->sqhead != *ctl->sqtail); + + n = *ctl->sqtail - *ctl->sqhead; + do + rc = uv__io_uring_enter(ctl->ringfd, n, n, UV__IORING_ENTER_GETEVENTS); + while (rc == -1 && errno == EINTR); + + if (rc < 0) + perror("libuv: io_uring_enter(getevents)"); /* Can't happen. */ + + if (rc != (int) n) + abort(); + + assert(*ctl->sqhead == *ctl->sqtail); + + memcpy(oldevents, *events, sizeof(*events)); + + /* Failed submissions are either EPOLL_CTL_DEL commands for file descriptors + * that have been closed, or EPOLL_CTL_ADD commands for file descriptors + * that we are already watching. Ignore the former and retry the latter + * with EPOLL_CTL_MOD. + */ + while (*ctl->cqhead != *ctl->cqtail) { + slot = (*ctl->cqhead)++ & ctl->cqmask; + + cqe = ctl->cqe; + cqe = &cqe[slot]; + + if (cqe->res == 0) + continue; + + fd = cqe->user_data >> 32; + op = 3 & cqe->user_data; + oldslot = 255 & (cqe->user_data >> 2); + + if (op == EPOLL_CTL_DEL) + continue; + + if (op != EPOLL_CTL_ADD) + abort(); + + if (cqe->res != -EEXIST) + abort(); + + uv__epoll_ctl_prep(epollfd, + ctl, + events, + EPOLL_CTL_MOD, + fd, + &oldevents[oldslot]); + } +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { uv__loop_internal_fields_t* lfields; struct epoll_event events[1024]; + struct epoll_event prep[256]; + struct uv__invalidate inv; struct epoll_event* pe; struct epoll_event e; + struct uv__iou* ctl; struct uv__iou* iou; int real_timeout; QUEUE* q; @@ -900,6 +1076,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { int have_iou_events; int have_signals; int nevents; + int epollfd; int count; int nfds; int fd; @@ -909,45 +1086,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { int reset_timeout; lfields = uv__get_internal_fields(loop); + ctl = &lfields->ctl; iou = &lfields->iou; - memset(&e, 0, sizeof(e)); - - while (!QUEUE_EMPTY(&loop->watcher_queue)) { - q = QUEUE_HEAD(&loop->watcher_queue); - QUEUE_REMOVE(q); - QUEUE_INIT(q); - - w = QUEUE_DATA(q, uv__io_t, watcher_queue); - assert(w->pevents != 0); - assert(w->fd >= 0); - assert(w->fd < (int) loop->nwatchers); - - e.events = w->pevents; - e.data.fd = w->fd; - - if (w->events == 0) - op = EPOLL_CTL_ADD; - else - op = EPOLL_CTL_MOD; - - /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching - * events, skip the syscall and squelch the events after epoll_wait(). - */ - if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) { - if (errno != EEXIST) - abort(); - - assert(op == EPOLL_CTL_ADD); - - /* We've reactivated a file descriptor that's been watched before. */ - if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e)) - abort(); - } - - w->events = w->pevents; - } - sigmask = NULL; if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { sigemptyset(&sigset); @@ -969,10 +1110,42 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { user_timeout = 0; } + epollfd = loop->backend_fd; + + memset(&e, 0, sizeof(e)); + + while (!QUEUE_EMPTY(&loop->watcher_queue)) { + q = QUEUE_HEAD(&loop->watcher_queue); + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + QUEUE_REMOVE(q); + QUEUE_INIT(q); + + op = EPOLL_CTL_MOD; + if (w->events == 0) + op = EPOLL_CTL_ADD; + + w->events = w->pevents; + e.events = w->pevents; + e.data.fd = w->fd; + + uv__epoll_ctl_prep(epollfd, ctl, &prep, op, w->fd, &e); + } + + inv.events = events; + inv.prep = &prep; + inv.nfds = -1; + for (;;) { if (loop->nfds == 0) if (iou->in_flight == 0) - return; + break; + + /* All event mask mutations should be visible to the kernel before + * we enter epoll_pwait(). + */ + if (ctl->ringfd != -1) + while (*ctl->sqhead != *ctl->sqtail) + uv__epoll_ctl_flush(epollfd, ctl, &prep); /* Only need to set the provider_entry_time if timeout != 0. The function * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. @@ -986,11 +1159,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { */ lfields->current_timeout = timeout; - nfds = epoll_pwait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout, - sigmask); + nfds = epoll_pwait(epollfd, events, ARRAY_SIZE(events), timeout, sigmask); /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the @@ -1010,7 +1179,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { continue; if (timeout == 0) - return; + break; /* We may have been inside the system call for longer than |timeout| * milliseconds so we need to update the timestamp to avoid drift. @@ -1031,7 +1200,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { continue; if (timeout == 0) - return; + break; /* Interrupted by a signal. Update timeout and poll again. */ goto update_timeout; @@ -1041,18 +1210,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { have_signals = 0; nevents = 0; - { - /* Squelch a -Waddress-of-packed-member warning with gcc >= 9. */ - union { - struct epoll_event* events; - uv__io_t* watchers; - } x; - - x.events = events; - assert(loop->watchers != NULL); - loop->watchers[loop->nwatchers] = x.watchers; - loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; - } + inv.nfds = nfds; + lfields->inv = &inv; for (i = 0; i < nfds; i++) { pe = events + i; @@ -1079,7 +1238,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * Ignore all errors because we may be racing with another thread * when the file descriptor is closed. */ - epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe); + uv__epoll_ctl_prep(epollfd, ctl, &prep, EPOLL_CTL_DEL, fd, pe); continue; } @@ -1136,14 +1295,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); } - loop->watchers[loop->nwatchers] = NULL; - loop->watchers[loop->nwatchers + 1] = NULL; + lfields->inv = NULL; if (have_iou_events != 0) - return; /* Event loop should cycle now so don't poll again. */ + break; /* Event loop should cycle now so don't poll again. */ if (have_signals != 0) - return; /* Event loop should cycle now so don't poll again. */ + break; /* Event loop should cycle now so don't poll again. */ if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { @@ -1151,11 +1309,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { timeout = 0; continue; } - return; + break; } if (timeout == 0) - return; + break; if (timeout == -1) continue; @@ -1165,10 +1323,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { real_timeout -= (loop->time - base); if (real_timeout <= 0) - return; + break; timeout = real_timeout; } + + if (ctl->ringfd != -1) + while (*ctl->sqhead != *ctl->sqtail) + uv__epoll_ctl_flush(epollfd, ctl, &prep); } uint64_t uv__hrtime(uv_clocktype_t type) { diff --git a/src/uv-common.h b/src/uv-common.h index b0d9c747137..decde5362c8 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -423,7 +423,9 @@ struct uv__loop_internal_fields_s { uv__loop_metrics_t loop_metrics; int current_timeout; #ifdef __linux__ + struct uv__iou ctl; struct uv__iou iou; + void* inv; /* used by uv__platform_invalidate_fd() */ #endif /* __linux__ */ }; From 3f331e97da5b1cc2e24765dcb6d26c9dd313418f Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 2 May 2023 17:04:42 +0200 Subject: [PATCH 355/713] macos: update minimum supported version (#3982) Only support the versions still maintained by Apple. --- SUPPORTED_PLATFORMS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 014ffd1da98..8a435d2592e 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -3,7 +3,7 @@ | System | Support type | Supported versions | Notes | |---|---|---|---| | GNU/Linux | Tier 1 | Linux >= 3.10 with glibc >= 2.17 | | -| macOS | Tier 1 | macOS >= 10.15 | Current and previous macOS release | +| macOS | Tier 1 | macOS >= 11 | Currently supported macOS releases | | Windows | Tier 1 | >= Windows 8 | VS 2015 and later are supported | | FreeBSD | Tier 2 | >= 12 | | | AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | From 15e81386bf9a285cada688c5faf67b3ed1319dcf Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 10 May 2023 17:38:58 +0200 Subject: [PATCH 356/713] macos: revert clonefile (#3987) * Revert "macos: fix source not being followed when cloning (#3941)" This reverts commit 507f2f950d5da7ab1586a46e81fc83dae10c0138. * Revert "darwin: bring back macos-specific copyfile(3) (#3654)" This reverts commit d4eb276eea7cb19a888fe97d7759d97c7092ad02. --- src/unix/fs.c | 74 ++------------------------------------------------- 1 file changed, 2 insertions(+), 72 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 82fa2e1b93e..8606e8dc153 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -66,9 +66,7 @@ #endif #if defined(__APPLE__) -# include -# include -# define UV__FS_CLONE_ACL 0x0004 +# include #elif defined(__linux__) && !defined(FICLONE) # include # define FICLONE _IOW(0x94, 9, int) @@ -1243,74 +1241,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) { return r; } -#if defined(__APPLE__) && !TARGET_OS_IPHONE - -static int uv__fs_clonefile_mac(uv_fs_t* req) { - static _Atomic int no_clone_acl; - int flags; - - flags = UV__FS_CLONE_ACL; - if (atomic_load_explicit(&no_clone_acl, memory_order_relaxed)) - flags = 0; - - /* Note: clonefile() does not set the group ID on the destination - * file correctly. */ - if (!clonefile(req->path, req->new_path, flags)) - return 0; /* success */ - - if (errno == EINVAL) { - atomic_store_explicit(&no_clone_acl, 1, memory_order_relaxed); - errno = 0; - /* UV__FS_CLONE_ACL flag not supported (macOS < 13); try without. */ - if (!clonefile(req->path, req->new_path, 0)) - return 0; /* success */ - } - - return UV__ERR(errno); -} - -static int uv__fs_fcopyfile_mac(uv_fs_t* req) { - int rc; - copyfile_flags_t flags; - - /* Don't overwrite the destination if its permissions disallow it. */ - if (faccessat(AT_FDCWD, req->new_path, R_OK | W_OK, AT_EACCESS)) { - if (errno != ENOENT) - return UV__ERR(errno); - } - - if ((req->flags & UV_FS_COPYFILE_FICLONE) || - (req->flags & UV_FS_COPYFILE_FICLONE_FORCE)) { - rc = uv__fs_clonefile_mac(req); - - /* Return on success. - * If an error occurred and force was set, return the error to the caller; - * fall back to copyfile() when force was not set. */ - if (rc == 0 || (req->flags & UV_FS_COPYFILE_FICLONE_FORCE)) - return rc; - - /* cloning failed. Inherit clonefile flags required for - falling back to copyfile. */ - flags = COPYFILE_ALL | COPYFILE_NOFOLLOW_SRC | COPYFILE_EXCL; - } else { - flags = COPYFILE_ALL; - if (req->flags & UV_FS_COPYFILE_EXCL) - flags |= COPYFILE_EXCL; - } - - if (copyfile(req->path, req->new_path, NULL, flags)) - return UV__ERR(errno); - - return 0; -} - -#endif /* defined(__APPLE__) && !TARGET_OS_IPHONE */ - -static int uv__fs_copyfile(uv_fs_t* req) { -#if defined(__APPLE__) && !TARGET_OS_IPHONE - /* On macOS, use the native clonefile(2)/copyfile(3). */ - return uv__fs_fcopyfile_mac(req); -#else +static ssize_t uv__fs_copyfile(uv_fs_t* req) { uv_fs_t fs_req; uv_file srcfd; uv_file dstfd; @@ -1486,7 +1417,6 @@ static int uv__fs_copyfile(uv_fs_t* req) { errno = UV__ERR(result); return -1; -#endif /* defined(__APPLE__) && !TARGET_OS_IPHONE */ } static void uv__to_stat(struct stat* src, uv_stat_t* dst) { From 3990fcad624581a33fd09cd2daac7196669c4f38 Mon Sep 17 00:00:00 2001 From: cui fliter Date: Sat, 13 May 2023 02:12:01 +0800 Subject: [PATCH 357/713] docs: fix some typos (#3984) --- docs/src/guide/utilities.rst | 2 +- docs/src/udp.rst | 2 +- include/uv/win.h | 2 +- src/unix/fs.c | 2 +- src/unix/process.c | 2 +- src/win/fs.c | 2 +- test/test-fs-event.c | 4 ++-- test/test-tty-escape-sequence-processing.c | 12 ++++++------ 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/src/guide/utilities.rst b/docs/src/guide/utilities.rst index e2f3cf6a633..c67515a088b 100644 --- a/docs/src/guide/utilities.rst +++ b/docs/src/guide/utilities.rst @@ -235,7 +235,7 @@ Our downloader is to be invoked as:: $ ./uvwget [url1] [url2] ... -So we add each argument as an URL +So we add each argument as a URL .. rubric:: uvwget/main.c - Adding urls .. literalinclude:: ../../code/uvwget/main.c diff --git a/docs/src/udp.rst b/docs/src/udp.rst index 009767d55dc..d7da95edd50 100644 --- a/docs/src/udp.rst +++ b/docs/src/udp.rst @@ -56,7 +56,7 @@ Data types /* * Indicates if IP_RECVERR/IPV6_RECVERR will be set when binding the handle. * This sets IP_RECVERR for IPv4 and IPV6_RECVERR for IPv6 UDP sockets on - * Linux. This stops the Linux kernel from supressing some ICMP error messages + * Linux. This stops the Linux kernel from suppressing some ICMP error messages * and enables full ICMP error reporting for faster failover. * This flag is no-op on platforms other than Linux. */ diff --git a/include/uv/win.h b/include/uv/win.h index 1dee8ac5cb3..fbd26dbc5e8 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -499,7 +499,7 @@ typedef struct { struct { uv_pipe_connection_fields } conn; \ } pipe; -/* TODO: put the parser states in an union - TTY handles are always half-duplex +/* TODO: put the parser states in a union - TTY handles are always half-duplex * so read-state can safely overlap write-state. */ #define UV_TTY_PRIVATE_FIELDS \ HANDLE handle; \ diff --git a/src/unix/fs.c b/src/unix/fs.c index 8606e8dc153..5f9aae373b9 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -2198,7 +2198,7 @@ void uv_fs_req_cleanup(uv_fs_t* req) { if (req == NULL) return; - /* Only necessary for asychronous requests, i.e., requests with a callback. + /* Only necessary for asynchronous requests, i.e., requests with a callback. * Synchronous ones don't copy their arguments and have req->path and * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP and * UV_FS_MKSTEMP are the exception to the rule, they always allocate memory. diff --git a/src/unix/process.c b/src/unix/process.c index ab717404826..c4fb322d17f 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -686,7 +686,7 @@ static int uv__spawn_resolve_and_spawn(const uv_process_options_t* options, if (options->file == NULL) return ENOENT; - /* The environment for the child process is that of the parent unless overriden + /* The environment for the child process is that of the parent unless overridden * by options->env */ char** env = environ; if (options->env != NULL) diff --git a/src/win/fs.c b/src/win/fs.c index 1f813c3e2bb..2fc7481f9a2 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -2279,7 +2279,7 @@ static void fs__fchmod(uv_fs_t* req) { SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); goto fchmod_cleanup; } - /* Remeber to clear the flag later on */ + /* Remember to clear the flag later on */ clear_archive_flag = 1; } else { clear_archive_flag = 0; diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 017aed2654f..9f231ebfc01 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -614,7 +614,7 @@ TEST_IMPL(fs_event_watch_file_exact_path) { create_file("watch_dir/file.js"); create_file("watch_dir/file.jsx"); #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_12) - /* Empirically, FSEvents seems to (reliably) report the preceeding + /* Empirically, FSEvents seems to (reliably) report the preceding * create_file events prior to macOS 10.11.6 in the subsequent fs_watch * creation, but that behavior hasn't been observed to occur on newer * versions. Give a long delay here to let the system settle before running @@ -682,7 +682,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) { remove("watch_file"); create_file("watch_file"); #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_12) - /* Empirically, kevent seems to (sometimes) report the preceeding + /* Empirically, kevent seems to (sometimes) report the preceding * create_file events prior to macOS 10.11.6 in the subsequent fs_event_start * So let the system settle before running the test. */ uv_sleep(1100); diff --git a/test/test-tty-escape-sequence-processing.c b/test/test-tty-escape-sequence-processing.c index d40dca4974b..2f7d0364b8b 100644 --- a/test/test-tty-escape-sequence-processing.c +++ b/test/test-tty-escape-sequence-processing.c @@ -1121,7 +1121,7 @@ TEST_IMPL(tty_set_style) { ASSERT(compare_screen(&tty_out, &actual, &expect)); } - /* Set foregroud and background color */ + /* Set foreground and background color */ ASSERT(ARRAY_SIZE(fg_attrs) == ARRAY_SIZE(bg_attrs)); length = ARRAY_SIZE(bg_attrs); for (i = 0; i < length; i++) { @@ -1362,7 +1362,7 @@ TEST_IMPL(tty_escape_sequence_processing) { initialize_tty(&tty_out); - /* CSI + finaly byte does not output anything */ + /* CSI + finally byte does not output anything */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); @@ -1375,7 +1375,7 @@ TEST_IMPL(tty_escape_sequence_processing) { capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); - /* CSI(C1) + finaly byte does not output anything */ + /* CSI(C1) + finally byte does not output anything */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); @@ -1388,7 +1388,7 @@ TEST_IMPL(tty_escape_sequence_processing) { capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); - /* CSI + intermediate byte + finaly byte does not output anything */ + /* CSI + intermediate byte + finally byte does not output anything */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); @@ -1401,7 +1401,7 @@ TEST_IMPL(tty_escape_sequence_processing) { capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); - /* CSI + parameter byte + finaly byte does not output anything */ + /* CSI + parameter byte + finally byte does not output anything */ cursor_pos.X = 1; cursor_pos.Y = 1; set_cursor_position(&tty_out, cursor_pos); @@ -1605,7 +1605,7 @@ TEST_IMPL(tty_escape_sequence_processing) { capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); - /* Finaly byte immedately after CSI [ are also output(#1874 1.) */ + /* Finally byte immedately after CSI [ are also output(#1874 1.) */ cursor_pos.X = expect.si.width / 2; cursor_pos.Y = expect.si.height / 2; set_cursor_position(&tty_out, cursor_pos); From ff7dcd265486fed0a511b3201a863090830705ee Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 12 May 2023 20:12:47 +0200 Subject: [PATCH 358/713] unix: use memcpy() instead of type punning (#3990) Libuv makes no claim to being strict aliasing-clean but type punning makes me feel unclean so replace it with memcpy(). --- src/unix/stream.c | 42 +++++++++++++----------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 0b755de6bce..d8191cb11ab 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -797,13 +797,7 @@ static int uv__try_write(uv_stream_t* stream, cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send)); - - /* silence aliasing warning */ - { - void* pv = CMSG_DATA(cmsg); - int* pi = pv; - *pi = fd_to_send; - } + memcpy(CMSG_DATA(cmsg), &fd_to_send, sizeof(fd_to_send)); do n = sendmsg(uv__stream_fd(stream), &msg, 0); @@ -989,46 +983,36 @@ static int uv__stream_queue_fd(uv_stream_t* stream, int fd) { static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { struct cmsghdr* cmsg; + int fd; + int err; + size_t i; + size_t count; for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { - char* start; - char* end; - int err; - void* pv; - int* pi; - unsigned int i; - unsigned int count; - if (cmsg->cmsg_type != SCM_RIGHTS) { fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n", cmsg->cmsg_type); continue; } - /* silence aliasing warning */ - pv = CMSG_DATA(cmsg); - pi = pv; - - /* Count available fds */ - start = (char*) cmsg; - end = (char*) cmsg + cmsg->cmsg_len; - count = 0; - while (start + CMSG_LEN(count * sizeof(*pi)) < end) - count++; - assert(start + CMSG_LEN(count * sizeof(*pi)) == end); + assert(cmsg->cmsg_len >= CMSG_LEN(0)); + count = cmsg->cmsg_len - CMSG_LEN(0); + assert(count % sizeof(fd) == 0); + count /= sizeof(fd); for (i = 0; i < count; i++) { + memcpy(&fd, (char*) CMSG_DATA(cmsg) + i * sizeof(fd), sizeof(fd)); /* Already has accepted fd, queue now */ if (stream->accepted_fd != -1) { - err = uv__stream_queue_fd(stream, pi[i]); + err = uv__stream_queue_fd(stream, fd); if (err != 0) { /* Close rest */ for (; i < count; i++) - uv__close(pi[i]); + uv__close(fd); return err; } } else { - stream->accepted_fd = pi[i]; + stream->accepted_fd = fd; } } } From 8a5b0955de2ac0dad4af1bcaf3000919ea91b989 Mon Sep 17 00:00:00 2001 From: Mohammed Keyvanzadeh Date: Fri, 12 May 2023 21:43:23 +0330 Subject: [PATCH 359/713] test: add additional assert (#3983) Add a missing assert that checks whether `uv_pipe_init()` succeeded or not. --- test/test-getters-setters.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test-getters-setters.c b/test/test-getters-setters.c index 2a37122df3f..9869f7b9da8 100644 --- a/test/test-getters-setters.c +++ b/test/test-getters-setters.c @@ -68,6 +68,7 @@ TEST_IMPL(getters_setters) { pipe = malloc(uv_handle_size(UV_NAMED_PIPE)); r = uv_pipe_init(loop, pipe, 0); + ASSERT(r == 0); ASSERT(uv_handle_get_type((uv_handle_t*)pipe) == UV_NAMED_PIPE); ASSERT(uv_handle_get_loop((uv_handle_t*)pipe) == loop); From f70027cbdcc7ff5849466ca0b63d85e369e5596f Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 12 May 2023 19:15:24 +0100 Subject: [PATCH 360/713] build: export compile_commands.json (#3968) Allows LSP's like clangd to work. --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fb05a921a3..459ca0800f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,8 @@ set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) set(CMAKE_C_STANDARD 90) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + option(LIBUV_BUILD_SHARED "Build shared lib" ON) cmake_dependent_option(LIBUV_BUILD_TESTS From 748d894e82abcdfff7429cf745003e182c47f163 Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Fri, 12 May 2023 11:28:35 -0700 Subject: [PATCH 361/713] win,process: write minidumps when sending SIGQUIT (#3840) This commit adds the ability to dump core when sending the `SIGQUIT` signal on Windows. The change reads in the current registry setting for local dumps, and attempts to write out to that location before killing the process. See [collecting-user-mode-dumps] for registry and pathing details. This behavior mimics that of the dumps created by the typical Windows Error Reporting mechanism. [collecting-user-mode-dumps]: https://learn.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps --- CMakeLists.txt | 5 ++- configure.ac | 2 +- include/uv/win.h | 1 + src/win/process.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 459ca0800f9..e9d775208c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,7 +183,10 @@ if(WIN32) advapi32 iphlpapi userenv - ws2_32) + ws2_32 + dbghelp + ole32 + uuid) list(APPEND uv_sources src/win/async.c src/win/core.c diff --git a/configure.ac b/configure.ac index a64a3dd9017..57465f2d431 100644 --- a/configure.ac +++ b/configure.ac @@ -73,7 +73,7 @@ AM_CONDITIONAL([OS400], [AS_CASE([$host_os],[os400], [true], [false]) AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])]) AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])]) AS_CASE([$host_os],[mingw*], [ - LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32" + LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32 -ldbghelp -lole32 -luuid" ]) AS_CASE([$host_os], [solaris2.10], [ CFLAGS="$CFLAGS -DSUNOS_NO_IFADDRS" diff --git a/include/uv/win.h b/include/uv/win.h index fbd26dbc5e8..92a95fa15f1 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -91,6 +91,7 @@ typedef struct pollfd { * variants (Linux and Darwin) */ #define SIGHUP 1 +#define SIGQUIT 3 #define SIGKILL 9 #define SIGWINCH 28 diff --git a/src/win/process.c b/src/win/process.c index ed44adc67c6..3e46176f0d6 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -32,6 +32,9 @@ #include "internal.h" #include "handle-inl.h" #include "req-inl.h" +#include +#include +#include /* GetModuleBaseNameW */ #define SIGKILL 9 @@ -1194,7 +1197,116 @@ static int uv__kill(HANDLE process_handle, int signum) { return UV_EINVAL; } + /* Create a dump file for the targeted process, if the registry key + * `HKLM:Software\Microsoft\Windows\Windows Error Reporting\LocalDumps` + * exists. The location of the dumps can be influenced by the `DumpFolder` + * sub-key, which has a default value of `%LOCALAPPDATA%\CrashDumps`, see [0] + * for more detail. Note that if the dump folder does not exist, we attempt + * to create it, to match behavior with WER itself. + * [0]: https://learn.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps */ + if (signum == SIGQUIT) { + HKEY registry_key; + DWORD pid, ret; + WCHAR basename[MAX_PATH]; + + /* Get target process name. */ + GetModuleBaseNameW(process_handle, NULL, &basename[0], sizeof(basename)); + + /* Get PID of target process. */ + pid = GetProcessId(process_handle); + + /* Get LocalDumps directory path. */ + ret = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps", + 0, + KEY_QUERY_VALUE, + ®istry_key); + if (ret == ERROR_SUCCESS) { + HANDLE hDumpFile = NULL; + WCHAR dump_folder[MAX_PATH], dump_name[MAX_PATH]; + DWORD dump_folder_len = sizeof(dump_folder), key_type = 0; + ret = RegGetValueW(registry_key, + NULL, + L"DumpFolder", + RRF_RT_ANY, + &key_type, + (PVOID) dump_folder, + &dump_folder_len); + if (ret != ERROR_SUCCESS) { + /* Default value for `dump_folder` is `%LOCALAPPDATA%\CrashDumps`. */ + WCHAR* localappdata; + SHGetKnownFolderPath(&FOLDERID_LocalAppData, 0, NULL, &localappdata); + _snwprintf_s(dump_folder, + sizeof(dump_folder), + _TRUNCATE, + L"%ls\\CrashDumps", + localappdata); + CoTaskMemFree(localappdata); + } + RegCloseKey(registry_key); + + /* Create dump folder if it doesn't already exist. */ + CreateDirectoryW(dump_folder, NULL); + + /* Construct dump filename from process name and PID. */ + _snwprintf_s(dump_name, + sizeof(dump_name), + _TRUNCATE, + L"%ls\\%ls.%d.dmp", + dump_folder, + basename, + pid); + + hDumpFile = CreateFileW(dump_name, + GENERIC_WRITE, + 0, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hDumpFile != INVALID_HANDLE_VALUE) { + DWORD dump_options, sym_options; + FILE_DISPOSITION_INFO DeleteOnClose = { TRUE }; + + /* If something goes wrong while writing it out, delete the file. */ + SetFileInformationByHandle(hDumpFile, + FileDispositionInfo, + &DeleteOnClose, + sizeof(DeleteOnClose)); + + /* Tell wine to dump ELF modules as well. */ + sym_options = SymGetOptions(); + SymSetOptions(sym_options | 0x40000000); + + /* We default to a fairly complete dump. In the future, we may want to + * allow clients to customize what kind of dump to create. */ + dump_options = MiniDumpWithFullMemory | + MiniDumpIgnoreInaccessibleMemory | + MiniDumpWithAvxXStateContext; + + if (MiniDumpWriteDump(process_handle, + pid, + hDumpFile, + dump_options, + NULL, + NULL, + NULL)) { + /* Don't delete the file on close if we successfully wrote it out. */ + FILE_DISPOSITION_INFO DontDeleteOnClose = { FALSE }; + SetFileInformationByHandle(hDumpFile, + FileDispositionInfo, + &DontDeleteOnClose, + sizeof(DontDeleteOnClose)); + } + SymSetOptions(sym_options); + CloseHandle(hDumpFile); + } + } + } + switch (signum) { + case SIGQUIT: case SIGTERM: case SIGKILL: case SIGINT: { From 6ad347fae4520f39520d34bd7c7f5ddafab13a69 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Fri, 12 May 2023 20:34:20 +0200 Subject: [PATCH 362/713] unix: constrained_memory should return UINT64_MAX (#3753) Document that we return UINT64_MAX if the cgroup limit is set to the max. For cgroupv2, that happens if we encounter `max`, while cgroupv1 returns 9223372036854771712 when no limit is set (which according to [this StackExchange discussion] is derived from LONG_MAX and PAGE_SIZE). So make sure we also detect this case for cgroupv1. [this StackExchange discussion]: https://unix.stackexchange.com/questions/420906/what-is-the-value-for-the-cgroups-limit-in-bytes-if-the-memory-is-not-restricte Addresses: https://github.com/libuv/libuv/pull/3744/files#r974062912 --- docs/src/misc.rst | 5 +++-- src/unix/linux.c | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index c2ad5804a6f..8c3a00e934c 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -586,8 +586,9 @@ API Gets the total amount of memory available to the process (in bytes) based on limits imposed by the OS. If there is no such constraint, or the constraint - is unknown, `0` is returned. Note that it is not unusual for this value to - be less than or greater than :c:func:`uv_get_total_memory`. + is unknown, `0` is returned. If there is a constraining mechanism, but there + is no constraint set, `UINT64_MAX` is returned. Note that it is not unusual + for this value to be less than or greater than :c:func:`uv_get_total_memory`. .. note:: This function currently only returns a non-zero value on Linux, based diff --git a/src/unix/linux.c b/src/unix/linux.c index c5911552773..b4bc1de7d7b 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1841,7 +1841,7 @@ static uint64_t uv__read_uint64(const char* filename) { if (0 == uv__slurp(filename, buf, sizeof(buf))) if (1 != sscanf(buf, "%" PRIu64, &rc)) if (0 == strcmp(buf, "max\n")) - rc = ~0ull; + rc = UINT64_MAX; return rc; } @@ -1877,6 +1877,7 @@ static void uv__get_cgroup1_memory_limits(char buf[static 1024], uint64_t* high, char filename[4097]; char* p; int n; + uint64_t cgroup1_max; /* Find out where the controller is mounted. */ p = uv__cgroup1_find_memory_controller(buf, &n); @@ -1893,12 +1894,22 @@ static void uv__get_cgroup1_memory_limits(char buf[static 1024], uint64_t* high, * as indicated by uv__read_uint64 returning 0. */ if (*high != 0 && *max != 0) - return; + goto update_limits; } /* Fall back to the limits of the global memory controller. */ *high = uv__read_uint64("/sys/fs/cgroup/memory/memory.soft_limit_in_bytes"); *max = uv__read_uint64("/sys/fs/cgroup/memory/memory.limit_in_bytes"); + + /* uv__read_uint64 detects cgroup2's "max", so we need to separately detect + * cgroup1's maximum value (which is derived from LONG_MAX and PAGE_SIZE). + */ +update_limits: + cgroup1_max = LONG_MAX & ~(sysconf(_SC_PAGESIZE) - 1); + if (*high == cgroup1_max) + *high = UINT64_MAX; + if (*max == cgroup1_max) + *max = UINT64_MAX; } static void uv__get_cgroup2_memory_limits(char buf[static 1024], uint64_t* high, From 30fc896cc1b5822e9f1eb462587fe4b368a6215c Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 15 May 2023 10:42:14 +0200 Subject: [PATCH 363/713] unix: handle CQ overflow in iou ring (#3991) When there are more than 128 concurrent cq completions the CQ ring overflows as signaled via the `UV__IORING_SQ_CQ_OVERFLOW`. If this happens we have to enter the kernel to get the remaining items. --- src/unix/linux.c | 18 ++++++++++++++++++ test/test-fs.c | 33 +++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 3 files changed, 53 insertions(+) diff --git a/src/unix/linux.c b/src/unix/linux.c index b4bc1de7d7b..911cc69e376 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -159,6 +159,7 @@ enum { enum { UV__IORING_SQ_NEED_WAKEUP = 1u, + UV__IORING_SQ_CQ_OVERFLOW = 2u, }; struct uv__io_cqring_offsets { @@ -891,7 +892,9 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { uint32_t tail; uint32_t mask; uint32_t i; + uint32_t flags; int nevents; + int rc; head = *iou->cqhead; tail = atomic_load_explicit((_Atomic uint32_t*) iou->cqtail, @@ -931,6 +934,21 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { tail, memory_order_release); + /* Check whether CQE's overflowed, if so enter the kernel to make them + * available. Don't grab them immediately but in the next loop iteration to + * avoid loop starvation. */ + flags = atomic_load_explicit((_Atomic uint32_t*) iou->sqflags, + memory_order_acquire); + + if (flags & UV__IORING_SQ_CQ_OVERFLOW) { + do + rc = uv__io_uring_enter(iou->ringfd, 0, 0, UV__IORING_ENTER_GETEVENTS); + while (rc == -1 && errno == EINTR); + + if (rc < 0) + perror("libuv: io_uring_enter(getevents)"); /* Can't happen. */ + } + uv__metrics_inc_events(loop, nevents); if (uv__get_internal_fields(loop)->current_timeout == 0) uv__metrics_inc_events_waiting(loop, nevents); diff --git a/test/test-fs.c b/test/test-fs.c index 51b4144ec3a..7bc006513e6 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -662,6 +662,15 @@ static void stat_cb(uv_fs_t* req) { ASSERT(!req->ptr); } +static void stat_batch_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_STAT || req->fs_type == UV_FS_LSTAT); + ASSERT(req->result == 0); + ASSERT(req->ptr); + stat_cb_count++; + uv_fs_req_cleanup(req); + ASSERT(!req->ptr); +} + static void sendfile_cb(uv_fs_t* req) { ASSERT(req == &sendfile_req); @@ -4540,3 +4549,27 @@ TEST_IMPL(fs_get_system_error) { return 0; } + +TEST_IMPL(fs_stat_batch_multiple) { + uv_fs_t req[300]; + int r; + int i; + + rmdir("test_dir"); + + r = uv_fs_mkdir(NULL, &mkdir_req, "test_dir", 0755, NULL); + ASSERT_EQ(r, 0); + + loop = uv_default_loop(); + + for (i = 0; i < (int) ARRAY_SIZE(req); ++i) { + r = uv_fs_stat(loop, &req[i], "test_dir", stat_batch_cb); + ASSERT_EQ(r, 0); + } + + uv_run(loop, UV_RUN_DEFAULT); + ASSERT_EQ(stat_cb_count, ARRAY_SIZE(req)); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 85517fc136d..6753ebe2334 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -384,6 +384,7 @@ TEST_DECLARE (fs_futime) TEST_DECLARE (fs_lutime) TEST_DECLARE (fs_file_open_append) TEST_DECLARE (fs_statfs) +TEST_DECLARE (fs_stat_batch_multiple) TEST_DECLARE (fs_stat_missing_path) TEST_DECLARE (fs_read_bufs) TEST_DECLARE (fs_read_file_eof) @@ -1070,6 +1071,7 @@ TASK_LIST_START TEST_ENTRY (fs_fd_hash) #endif TEST_ENTRY (fs_statfs) + TEST_ENTRY (fs_stat_batch_multiple) TEST_ENTRY (fs_stat_missing_path) TEST_ENTRY (fs_read_bufs) TEST_ENTRY (fs_read_file_eof) From 44b8153005e4318f43637b2f724ca5f71e8412a8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 15 May 2023 10:52:23 +0200 Subject: [PATCH 364/713] unix: remove clang compiler warning pragmas (#3989) Instead of suppressing the VLA warning, use a fixed-size buffer that is big enough to receive at least one control message but not so big that IBMi PASE rejects it. --- src/unix/stream.c | 58 ++++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index d8191cb11ab..03f92b5045a 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -60,6 +60,16 @@ struct uv__stream_select_s { }; #endif /* defined(__APPLE__) */ +union uv__cmsg { + struct cmsghdr hdr; + /* This cannot be larger because of the IBMi PASE limitation that + * the total size of control messages cannot exceed 256 bytes. + */ + char pad[256]; +}; + +STATIC_ASSERT(256 == sizeof(union uv__cmsg)); + static void uv__stream_connect(uv_stream_t*); static void uv__write(uv_stream_t* stream); static void uv__read(uv_stream_t* stream); @@ -769,18 +779,14 @@ static int uv__try_write(uv_stream_t* stream, if (send_handle != NULL) { int fd_to_send; struct msghdr msg; - struct cmsghdr *cmsg; - union { - char data[64]; - struct cmsghdr alias; - } scratch; + union uv__cmsg cmsg; if (uv__is_closing(send_handle)) return UV_EBADF; fd_to_send = uv__handle_fd((uv_handle_t*) send_handle); - memset(&scratch, 0, sizeof(scratch)); + memset(&cmsg, 0, sizeof(cmsg)); assert(fd_to_send >= 0); @@ -790,14 +796,13 @@ static int uv__try_write(uv_stream_t* stream, msg.msg_iovlen = iovcnt; msg.msg_flags = 0; - msg.msg_control = &scratch.alias; + msg.msg_control = &cmsg.hdr; msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send)); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send)); - memcpy(CMSG_DATA(cmsg), &fd_to_send, sizeof(fd_to_send)); + cmsg.hdr.cmsg_level = SOL_SOCKET; + cmsg.hdr.cmsg_type = SCM_RIGHTS; + cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(fd_to_send)); + memcpy(CMSG_DATA(&cmsg.hdr), &fd_to_send, sizeof(fd_to_send)); do n = sendmsg(uv__stream_fd(stream), &msg, 0); @@ -972,15 +977,6 @@ static int uv__stream_queue_fd(uv_stream_t* stream, int fd) { } -#if defined(__PASE__) -/* on IBMi PASE the control message length can not exceed 256. */ -# define UV__CMSG_FD_COUNT 60 -#else -# define UV__CMSG_FD_COUNT 64 -#endif -#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int)) - - static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { struct cmsghdr* cmsg; int fd; @@ -1021,17 +1017,11 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { } -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wgnu-folding-constant" -# pragma clang diagnostic ignored "-Wvla-extension" -#endif - static void uv__read(uv_stream_t* stream) { uv_buf_t buf; ssize_t nread; struct msghdr msg; - char cmsg_space[CMSG_SPACE(UV__CMSG_FD_SIZE)]; + union uv__cmsg cmsg; int count; int err; int is_ipc; @@ -1077,8 +1067,8 @@ static void uv__read(uv_stream_t* stream) { msg.msg_name = NULL; msg.msg_namelen = 0; /* Set up to receive a descriptor even if one isn't in the message */ - msg.msg_controllen = sizeof(cmsg_space); - msg.msg_control = cmsg_space; + msg.msg_controllen = sizeof(cmsg); + msg.msg_control = &cmsg.hdr; do { nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); @@ -1162,14 +1152,6 @@ static void uv__read(uv_stream_t* stream) { } -#ifdef __clang__ -# pragma clang diagnostic pop -#endif - -#undef UV__CMSG_FD_COUNT -#undef UV__CMSG_FD_SIZE - - int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { assert(stream->type == UV_TCP || stream->type == UV_TTY || From e7ecd116e0e013bf8c01d66505ced4ce1b58c005 Mon Sep 17 00:00:00 2001 From: Jiawen Geng Date: Tue, 16 May 2023 05:35:35 +0800 Subject: [PATCH 365/713] win: fix mingw build (#3994) Fixes: https://github.com/libuv/libuv/issues/3992 --- src/win/process.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/win/process.c b/src/win/process.c index 3e46176f0d6..b86a7d478f9 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -1279,6 +1279,12 @@ static int uv__kill(HANDLE process_handle, int signum) { sym_options = SymGetOptions(); SymSetOptions(sym_options | 0x40000000); +/* patch for mingw under 12 */ +#ifdef __MINGW32__ +#ifndef MiniDumpWithAvxXStateContext +#define MiniDumpWithAvxXStateContext 0x00200000 +#endif +#endif /* We default to a fairly complete dump. In the future, we may want to * allow clients to customize what kind of dump to create. */ dump_options = MiniDumpWithFullMemory | From 1a56f684519c61d51d62ded7aa2d131beb97155e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 16 May 2023 10:56:41 +0200 Subject: [PATCH 366/713] test: fix -Wbool-compare compiler warning (#3996) Fixes: https://github.com/libuv/libuv/issues/3995 --- test/test-fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-fs.c b/test/test-fs.c index 7bc006513e6..f9fa20eff6b 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1573,7 +1573,7 @@ TEST_IMPL(fs_fstat_stdio) { switch (ft) { case UV_TTY: case UV_NAMED_PIPE: - ASSERT(st->st_mode == ft == UV_TTY ? S_IFCHR : S_IFIFO); + ASSERT(st->st_mode == (ft == UV_TTY ? S_IFCHR : S_IFIFO)); ASSERT(st->st_nlink == 1); ASSERT(st->st_rdev == (ft == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE) << 16); break; From d1a2efc77b75095d3ba1c6e928b2db596c30ee00 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 16 May 2023 16:29:03 +0200 Subject: [PATCH 367/713] win: define MiniDumpWithAvxXStateContext always (#3998) --- src/win/process.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index b86a7d478f9..3e451e2291d 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -1279,11 +1279,9 @@ static int uv__kill(HANDLE process_handle, int signum) { sym_options = SymGetOptions(); SymSetOptions(sym_options | 0x40000000); -/* patch for mingw under 12 */ -#ifdef __MINGW32__ +/* MiniDumpWithAvxXStateContext might be undef in server2012r2 or mingw < 12 */ #ifndef MiniDumpWithAvxXStateContext #define MiniDumpWithAvxXStateContext 0x00200000 -#endif #endif /* We default to a fairly complete dump. In the future, we may want to * allow clients to customize what kind of dump to create. */ From 6f94701467cf62c42034fc8535b69c224659ae3b Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 16 May 2023 20:43:30 +0200 Subject: [PATCH 368/713] freebsd: hard-code UV_ENODATA definition (#3999) `FreeBSD` defines `ENODATA` in /usr/include/c++/v1/errno.h which is only visible if C++ is the compilation unit. This can cause interop issues when integrating libuv build with C on a C++ project. Avoid this issue by directly defining with the value defined in the file previously mentioned. --- include/uv/errno.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uv/errno.h b/include/uv/errno.h index 82d84bfdb56..648e493d0e7 100644 --- a/include/uv/errno.h +++ b/include/uv/errno.h @@ -456,8 +456,14 @@ # define UV__ESOCKTNOSUPPORT (-4025) #endif +/* FreeBSD defines ENODATA in /usr/include/c++/v1/errno.h which is only visible + * if C++ is being used. Define it directly to avoid problems when integrating + * libuv in a C++ project. + */ #if defined(ENODATA) && !defined(_WIN32) # define UV__ENODATA UV__ERR(ENODATA) +#elif defined(__FreeBSD__) +# define UV__ENODATA (-9919) #else # define UV__ENODATA (-4024) #endif From d23a20f62cc50b9fd7694992263f1d296d8f5cb4 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 17 May 2023 16:54:36 +0200 Subject: [PATCH 369/713] linux: work around EOWNERDEAD io_uring kernel bug (#4002) io_uring sometimes erroneously returns EOWNERDEAD when the intention was to return 0. It's harmless and fixed in linux 5.14 so just ignore the error. Fixes: https://github.com/libuv/libuv/issues/4001 Refs: https://github.com/torvalds/linux/commit/21f965221e --- src/unix/linux.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 911cc69e376..e7e7a11154c 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -705,7 +705,8 @@ static void uv__iou_submit(struct uv__iou* iou) { if (flags & UV__IORING_SQ_NEED_WAKEUP) if (uv__io_uring_enter(iou->ringfd, 0, 0, UV__IORING_ENTER_SQ_WAKEUP)) - perror("libuv: io_uring_enter(wakeup)"); /* Can't happen. */ + if (errno != EOWNERDEAD) /* Kernel bug. Harmless, ignore. */ + perror("libuv: io_uring_enter(wakeup)"); /* Can't happen. */ } From ef6a9a624df0a00687037474025a3608472f722a Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 19 May 2023 11:03:17 +0200 Subject: [PATCH 370/713] linux: fix WRITEV with lots of bufs using io_uring (#4004) In the case of trying to write more than `IOV_MAX` buffers, the `IORING_OP_WRITEV` operation will return `EINVAL`. As a temporal fix, fallback to the old ways. In the future we might implement this by linking multiple `IORING_OP_WRITEV` requests using `IOSQE_IO_LINK`. --- src/unix/linux.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/unix/linux.c b/src/unix/linux.c index e7e7a11154c..a3439184c37 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -782,6 +782,11 @@ int uv__iou_fs_read_or_write(uv_loop_t* loop, struct uv__io_uring_sqe* sqe; struct uv__iou* iou; + /* For the moment, if iovcnt is greater than IOV_MAX, fallback to the + * threadpool. In the future we might take advantage of IOSQE_IO_LINK. */ + if (req->nbufs > IOV_MAX) + return 0; + iou = &uv__get_internal_fields(loop)->iou; sqe = uv__iou_get_sqe(iou, loop, req); From 03bb70374133264e7be71789b2def6154539bcdd Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 17 May 2023 20:57:54 +0200 Subject: [PATCH 371/713] Revert "win: fixes in uv__pipe_try_write() (#3825 2/2)" This reverts commit e1143f12657444c750e47ab3e1fb70ae6a030620. For some reason this is breaking node.js IPC. I plan to investigate it but we can let this for the next release. PR-URL: https://github.com/libuv/libuv/pull/4003 --- CMakeLists.txt | 1 - src/win/pipe.c | 46 ++++++++-------- test/test-pipe-try-write.c | 107 +++++++++++++------------------------ 3 files changed, 59 insertions(+), 95 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9d775208c4..93733dd0478 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -592,7 +592,6 @@ if(LIBUV_BUILD_TESTS) test/test-pipe-server-close.c test/test-pipe-set-fchmod.c test/test-pipe-set-non-blocking.c - test/test-pipe-try-write.c test/test-platform-output.c test/test-poll-close-doesnt-corrupt-stack.c test/test-poll-close.c diff --git a/src/win/pipe.c b/src/win/pipe.c index 85b3e7da47e..94233455388 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1786,7 +1786,6 @@ int uv__pipe_try_write(uv_pipe_t* handle, const uv_buf_t bufs[], unsigned int nbufs) { OVERLAPPED overlapped; - HANDLE event; const uv_buf_t* buf; int bytes_written; unsigned int idx; @@ -1808,47 +1807,44 @@ int uv__pipe_try_write(uv_pipe_t* handle, memset(&overlapped, 0, sizeof(overlapped)); - event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (event == NULL) { + overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (overlapped.hEvent == NULL) { uv_fatal_error(GetLastError(), "CreateEvent"); } - overlapped.hEvent = (HANDLE)((uintptr_t)event | 1); - bytes_written = 0; for (err = 0, idx = 0; idx < nbufs; err = 0, idx += 1) { buf = &bufs[idx]; - if (!WriteFile(handle->handle, buf->base, buf->len, NULL, &overlapped)) { - err = GetLastError(); - if (err != ERROR_IO_PENDING) { - break; - } + if (WriteFile(handle->handle, buf->base, buf->len, NULL, &overlapped)) { + bytes_written += buf->len; + continue; + } - err = WaitForSingleObject(event, timeout); - if (err != WAIT_OBJECT_0) { - CancelIoEx(handle->handle, &overlapped); - } + err = GetLastError(); + if (err != ERROR_IO_PENDING) { + break; + } + + err = WaitForSingleObject(overlapped.hEvent, timeout); + if (err == WAIT_OBJECT_0) { + bytes_written += buf->len; + continue; } - - if (GetOverlappedResult(handle->handle, &overlapped, &err, TRUE)) { + + if (err == WAIT_TIMEOUT && + CancelIo(handle->handle) && + GetOverlappedResult(handle->handle, &overlapped, &err, TRUE)) { bytes_written += err; - if (err == buf->len) - continue; - err = WSAEWOULDBLOCK; /* Ignored later. */ + err = WSAEWOULDBLOCK; /* Translates to UV_EAGAIN. */ } else { err = GetLastError(); - if (err == ERROR_OPERATION_ABORTED) { - err = WSAEWOULDBLOCK; /* Translates to UV_EAGAIN. */ - } } break; } - if (!CloseHandle(event)) { - uv_fatal_error(GetLastError(), "CloseHandle"); - } + CloseHandle(overlapped.hEvent); if (bytes_written == 0 && err != 0) { return uv_translate_sys_error(err); diff --git a/test/test-pipe-try-write.c b/test/test-pipe-try-write.c index 2dccd4b5c47..dd0dd54dd7e 100644 --- a/test/test-pipe-try-write.c +++ b/test/test-pipe-try-write.c @@ -1,64 +1,27 @@ #include "uv.h" #include "task.h" -typedef struct pipe_ctx_s { - uv_pipe_t handle; - uv_write_t write_req; - ssize_t read; - ssize_t written; -} pipe_ctx_t; - static void (*spam)(uv_pipe_t* handle); -static pipe_ctx_t client; -static pipe_ctx_t peer; +static uv_pipe_t client_handle; +static uv_pipe_t peer_handle; static uv_pipe_t server_handle; +static uv_write_t write_req; -static void write_cb(uv_write_t* req, int status) { - ASSERT_EQ(0, status); -} - -static int do_try_write(uv_pipe_t* handle, uv_buf_t* buf, size_t size) { - int rc; - pipe_ctx_t* pc; - pc = container_of(handle, struct pipe_ctx_s, handle); - rc = 0; - do { - pc->written += rc; - rc = uv_try_write((uv_stream_t*)handle, buf, size); - } while (rc > 0); - - return rc; -}; - - -static void handle_read(uv_stream_t* handle, - ssize_t nread, - const uv_buf_t* buf) { - pipe_ctx_t* send_ctx; - pipe_ctx_t* recv_ctx; - recv_ctx = container_of(handle, struct pipe_ctx_s, handle); - send_ctx = recv_ctx == &client ? &peer : &client; - ASSERT_UINT64_GT(nread, 0); - if (send_ctx->written >= recv_ctx->read + (ssize_t)buf->len) { - ASSERT_UINT64_EQ(nread, (ssize_t)buf->len); /* Expect saturation. */ - } - recv_ctx->read += nread; +static void write_cb(uv_write_t* req, int status) { + ASSERT(0 == status); } static void spam_0(uv_pipe_t* handle) { uv_buf_t buf; - pipe_ctx_t* pc; buf = uv_buf_init("", 0); - ASSERT_EQ(0, uv_try_write((uv_stream_t*) handle, &buf, 1)); + ASSERT(0 == uv_try_write((uv_stream_t*) handle, &buf, 1)); /* Non-empty write to start the event loop moving. */ - pc = container_of(handle, struct pipe_ctx_s, handle); buf = uv_buf_init("hello, world", sizeof("hello, world") - 1); - ASSERT_EQ(0, - uv_write(&pc->write_req,(uv_stream_t*) handle, &buf, 1, write_cb)); + ASSERT(0 == uv_write(&write_req, (uv_stream_t*) handle, &buf, 1, write_cb)); } @@ -67,9 +30,11 @@ static void spam_1(uv_pipe_t* handle) { int rc; buf = uv_buf_init("hello, world", sizeof("hello, world") - 1); - rc = do_try_write(handle, &buf, 1); + do + rc = uv_try_write((uv_stream_t*) handle, &buf, 1); + while (rc > 0); - ASSERT_EQ(rc, UV_EAGAIN); + ASSERT(rc == UV_EAGAIN); } @@ -79,9 +44,12 @@ static void spam_2(uv_pipe_t* handle) { bufs[0] = uv_buf_init("hello,", sizeof("hello,") - 1); bufs[1] = uv_buf_init(" world", sizeof(" world") - 1); - rc = do_try_write(handle, bufs, ARRAY_SIZE(bufs)); - ASSERT_EQ(rc, UV_EAGAIN); + do + rc = uv_try_write((uv_stream_t*) handle, bufs, ARRAY_SIZE(bufs)); + while (rc > 0); + + ASSERT(rc == UV_EAGAIN); } @@ -94,34 +62,35 @@ static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { - ASSERT_UINT64_GT(nread, 0); /* Expect some bytes. */ - if (spam != spam_0) { - handle_read(handle, nread, buf); + if (spam == spam_0) { + ASSERT(nread > 0); /* Expect some bytes. */ + } else { + ASSERT(nread == (ssize_t) buf->len); /* Expect saturation. */ } - if (handle == (uv_stream_t*) &client.handle) { - spam(&client.handle); + if (handle == (uv_stream_t*) &peer_handle) { + spam(&client_handle); } else { - uv_close((uv_handle_t*) &peer.handle, NULL); - uv_close((uv_handle_t*) &client.handle, NULL); + uv_close((uv_handle_t*) &peer_handle, NULL); + uv_close((uv_handle_t*) &client_handle, NULL); uv_close((uv_handle_t*) &server_handle, NULL); } } static void connection_cb(uv_stream_t* handle, int status) { - ASSERT_EQ(0, status); - ASSERT_EQ(0, uv_pipe_init(uv_default_loop(), &peer.handle, 0)); - ASSERT_EQ(0, uv_accept((uv_stream_t*) &server_handle, - (uv_stream_t*) &peer.handle)); - ASSERT_EQ(0, uv_read_start((uv_stream_t*) &peer.handle, alloc_cb, read_cb)); - spam(&peer.handle); + ASSERT(0 == status); + ASSERT(0 == uv_pipe_init(uv_default_loop(), &peer_handle, 0)); + ASSERT(0 == uv_accept((uv_stream_t*) &server_handle, + (uv_stream_t*) &peer_handle)); + ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb)); + spam(&peer_handle); } static void connect_cb(uv_connect_t* req, int status) { - ASSERT_EQ(0, status); - ASSERT_EQ(0, uv_read_start((uv_stream_t*) &client.handle, alloc_cb, read_cb)); + ASSERT(0 == status); + ASSERT(0 == uv_read_start((uv_stream_t*) &client_handle, alloc_cb, read_cb)); } @@ -129,12 +98,12 @@ static int pipe_try_write(void (*spammer)(uv_pipe_t*)) { uv_connect_t connect_req; spam = spammer; - ASSERT_EQ(0, uv_pipe_init(uv_default_loop(), &client.handle, 0)); - ASSERT_EQ(0, uv_pipe_init(uv_default_loop(), &server_handle, 0)); - ASSERT_EQ(0, uv_pipe_bind(&server_handle, TEST_PIPENAME)); - ASSERT_EQ(0, uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); - uv_pipe_connect(&connect_req, &client.handle, TEST_PIPENAME, connect_cb); - ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == uv_pipe_init(uv_default_loop(), &client_handle, 0)); + ASSERT(0 == uv_pipe_init(uv_default_loop(), &server_handle, 0)); + ASSERT(0 == uv_pipe_bind(&server_handle, TEST_PIPENAME)); + ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); + uv_pipe_connect(&connect_req, &client_handle, TEST_PIPENAME, connect_cb); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; From 07261493a76144fe2d47afba0dd2be045cbd780d Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 17 May 2023 20:58:32 +0200 Subject: [PATCH 372/713] Revert "win: implement uv_try_write() for pipes(#3825 1/2)" This reverts commit 244e0e20592f40fce87d573c9f7b6ff7f189c382. For some reason this is breaking node.js IPC. I plan to investigate it but we can let this for the next release.t PR-URL: https://github.com/libuv/libuv/pull/4003 --- Makefile.am | 1 - src/win/internal.h | 2 - src/win/pipe.c | 72 --------------------- src/win/stream.c | 2 +- test/test-list.h | 6 -- test/test-pipe-try-write.c | 125 ------------------------------------- 6 files changed, 1 insertion(+), 207 deletions(-) delete mode 100644 test/test-pipe-try-write.c diff --git a/Makefile.am b/Makefile.am index be2661580fa..1dca3dd1f8a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -224,7 +224,6 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-pipe-close-stdout-read-stdin.c \ test/test-pipe-set-non-blocking.c \ test/test-pipe-set-fchmod.c \ - test/test-pipe-try-write.c \ test/test-platform-output.c \ test/test-poll.c \ test/test-poll-close.c \ diff --git a/src/win/internal.h b/src/win/internal.h index 1b524b5cd92..bda321c17dc 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -134,8 +134,6 @@ int uv__pipe_write(uv_loop_t* loop, uv_stream_t* send_handle, uv_write_cb cb); void uv__pipe_shutdown(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req); -int uv__pipe_try_write(uv_pipe_t* handle, const uv_buf_t bufs[], - unsigned int nbufs); void uv__process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, uv_req_t* req); diff --git a/src/win/pipe.c b/src/win/pipe.c index 94233455388..787ba105c93 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1782,78 +1782,6 @@ int uv__pipe_write(uv_loop_t* loop, } -int uv__pipe_try_write(uv_pipe_t* handle, - const uv_buf_t bufs[], - unsigned int nbufs) { - OVERLAPPED overlapped; - const uv_buf_t* buf; - int bytes_written; - unsigned int idx; - DWORD timeout; - DWORD err; - - if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { - return UV_EAGAIN; - } - - if (handle->stream.conn.write_reqs_pending > 0) { - return UV_EAGAIN; - } - - timeout = 0; - if (handle->flags & UV_HANDLE_BLOCKING_WRITES) { - timeout = INFINITE; - } - - memset(&overlapped, 0, sizeof(overlapped)); - - overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (overlapped.hEvent == NULL) { - uv_fatal_error(GetLastError(), "CreateEvent"); - } - - bytes_written = 0; - for (err = 0, idx = 0; idx < nbufs; err = 0, idx += 1) { - buf = &bufs[idx]; - - if (WriteFile(handle->handle, buf->base, buf->len, NULL, &overlapped)) { - bytes_written += buf->len; - continue; - } - - err = GetLastError(); - if (err != ERROR_IO_PENDING) { - break; - } - - err = WaitForSingleObject(overlapped.hEvent, timeout); - if (err == WAIT_OBJECT_0) { - bytes_written += buf->len; - continue; - } - - if (err == WAIT_TIMEOUT && - CancelIo(handle->handle) && - GetOverlappedResult(handle->handle, &overlapped, &err, TRUE)) { - bytes_written += err; - err = WSAEWOULDBLOCK; /* Translates to UV_EAGAIN. */ - } else { - err = GetLastError(); - } - - break; - } - - CloseHandle(overlapped.hEvent); - - if (bytes_written == 0 && err != 0) { - return uv_translate_sys_error(err); - } - - return bytes_written; -} - - static void uv__pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, uv_buf_t buf) { /* If there is an eof timer running, we don't need it any more, so discard diff --git a/src/win/stream.c b/src/win/stream.c index 7ccc79be421..7bf9ca388cb 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -182,7 +182,7 @@ int uv_try_write(uv_stream_t* stream, case UV_TTY: return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs); case UV_NAMED_PIPE: - return uv__pipe_try_write((uv_pipe_t*) stream, bufs, nbufs); + return UV_EAGAIN; default: assert(0); return UV_ENOSYS; diff --git a/test/test-list.h b/test/test-list.h index 6753ebe2334..68c9c1171a7 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -207,9 +207,6 @@ TEST_DECLARE (pipe_getsockname_blocking) TEST_DECLARE (pipe_pending_instances) TEST_DECLARE (pipe_sendmsg) TEST_DECLARE (pipe_server_close) -TEST_DECLARE (pipe_try_write_0) -TEST_DECLARE (pipe_try_write_1) -TEST_DECLARE (pipe_try_write_2) TEST_DECLARE (connection_fail) TEST_DECLARE (connection_fail_doesnt_auto_close) TEST_DECLARE (shutdown_close_tcp) @@ -597,9 +594,6 @@ TASK_LIST_START TEST_ENTRY (pipe_connect_on_prepare) TEST_ENTRY (pipe_server_close) - TEST_ENTRY (pipe_try_write_0) - TEST_ENTRY (pipe_try_write_1) - TEST_ENTRY (pipe_try_write_2) #ifndef _WIN32 TEST_ENTRY (pipe_close_stdout_read_stdin) #endif diff --git a/test/test-pipe-try-write.c b/test/test-pipe-try-write.c deleted file mode 100644 index dd0dd54dd7e..00000000000 --- a/test/test-pipe-try-write.c +++ /dev/null @@ -1,125 +0,0 @@ -#include "uv.h" -#include "task.h" - -static void (*spam)(uv_pipe_t* handle); -static uv_pipe_t client_handle; -static uv_pipe_t peer_handle; -static uv_pipe_t server_handle; -static uv_write_t write_req; - - -static void write_cb(uv_write_t* req, int status) { - ASSERT(0 == status); -} - - -static void spam_0(uv_pipe_t* handle) { - uv_buf_t buf; - - buf = uv_buf_init("", 0); - ASSERT(0 == uv_try_write((uv_stream_t*) handle, &buf, 1)); - - /* Non-empty write to start the event loop moving. */ - buf = uv_buf_init("hello, world", sizeof("hello, world") - 1); - ASSERT(0 == uv_write(&write_req, (uv_stream_t*) handle, &buf, 1, write_cb)); -} - - -static void spam_1(uv_pipe_t* handle) { - uv_buf_t buf; - int rc; - - buf = uv_buf_init("hello, world", sizeof("hello, world") - 1); - do - rc = uv_try_write((uv_stream_t*) handle, &buf, 1); - while (rc > 0); - - ASSERT(rc == UV_EAGAIN); -} - - -static void spam_2(uv_pipe_t* handle) { - uv_buf_t bufs[2]; - int rc; - - bufs[0] = uv_buf_init("hello,", sizeof("hello,") - 1); - bufs[1] = uv_buf_init(" world", sizeof(" world") - 1); - - do - rc = uv_try_write((uv_stream_t*) handle, bufs, ARRAY_SIZE(bufs)); - while (rc > 0); - - ASSERT(rc == UV_EAGAIN); -} - - -static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { - static char base[256]; - - buf->base = base; - buf->len = sizeof(base); -} - - -static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { - if (spam == spam_0) { - ASSERT(nread > 0); /* Expect some bytes. */ - } else { - ASSERT(nread == (ssize_t) buf->len); /* Expect saturation. */ - } - - if (handle == (uv_stream_t*) &peer_handle) { - spam(&client_handle); - } else { - uv_close((uv_handle_t*) &peer_handle, NULL); - uv_close((uv_handle_t*) &client_handle, NULL); - uv_close((uv_handle_t*) &server_handle, NULL); - } -} - - -static void connection_cb(uv_stream_t* handle, int status) { - ASSERT(0 == status); - ASSERT(0 == uv_pipe_init(uv_default_loop(), &peer_handle, 0)); - ASSERT(0 == uv_accept((uv_stream_t*) &server_handle, - (uv_stream_t*) &peer_handle)); - ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb)); - spam(&peer_handle); -} - - -static void connect_cb(uv_connect_t* req, int status) { - ASSERT(0 == status); - ASSERT(0 == uv_read_start((uv_stream_t*) &client_handle, alloc_cb, read_cb)); -} - - -static int pipe_try_write(void (*spammer)(uv_pipe_t*)) { - uv_connect_t connect_req; - - spam = spammer; - ASSERT(0 == uv_pipe_init(uv_default_loop(), &client_handle, 0)); - ASSERT(0 == uv_pipe_init(uv_default_loop(), &server_handle, 0)); - ASSERT(0 == uv_pipe_bind(&server_handle, TEST_PIPENAME)); - ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); - uv_pipe_connect(&connect_req, &client_handle, TEST_PIPENAME, connect_cb); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - - MAKE_VALGRIND_HAPPY(uv_default_loop()); - return 0; -} - - -TEST_IMPL(pipe_try_write_0) { - return pipe_try_write(spam_0); -} - - -TEST_IMPL(pipe_try_write_1) { - return pipe_try_write(spam_1); -} - - -TEST_IMPL(pipe_try_write_2) { - return pipe_try_write(spam_2); -} From b9789a452f814c9f36fe16e15e5f7c1527ec4699 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 19 May 2023 13:21:01 +0200 Subject: [PATCH 373/713] 2023.05.19, Version 1.45.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.44.2: * win: remove stdint-msvc2008.h (Ben Noordhuis) * android: remove pthread-fixes.c (Ben Noordhuis) * build: enable MSVC_RUNTIME_LIBRARY setting (自发对称破缺) * unix: switch to c11 atomics (Ben Noordhuis) * unix: don't accept() connections in a loop (Ben Noordhuis) * win: fix off-by-1 buffer overrun in uv_exepath() (Ben Noordhuis) * build: switch ci from macos-10.15 to macos-11 (Ben Noordhuis) * win: fix thread race in uv_cwd() and uv_chdir() (Ben Noordhuis) * unix,win: remove UV_HANDLE_SHUTTING flag (Santiago Gimeno) * win: support Windows 11 in uv_os_uname() (Luan Devecchi) * unix: fix uv_getrusage() ru_maxrss reporting (Ben Noordhuis) * doc: add note about offset -1 in uv_fs_read/write (Steven Schveighoffer) * test: fix musl libc.a dlerror() test expectation (Ben Noordhuis) * kqueue: DRY file descriptor deletion logic (Ben Noordhuis) * linux: teach uv_get_constrained_memory() cgroupsv2 (Ben Noordhuis) * build: upgrade qemu-user-static package (Ben Noordhuis) * linux: move epoll.c back into linux-core.c (Ben Noordhuis) * unix: remove pre-macos 10.8 compatibility hack (Ben Noordhuis) * unix,win: fix memory leak in uv_fs_scandir() (Ben Noordhuis) * build: restore qemu download logic (Ben Noordhuis) * win: fix uv__pipe_accept memory leak (number201724) * doc: update LINKS.md (Daniel) * unix: simplify atomic op in uv_tty_reset_mode() (Ben Noordhuis) * build: add LIBUV_BUILD_SHARED cmake option (Christian Clason) * linux: remove unused or obsolete syscall wrappers (Ben Noordhuis) * linux: merge files back into single file (Ben Noordhuis) * stream: process more than one write req per loop tick (ywave620) * unix,win: give thread pool threads an 8 MB stack (Ben Noordhuis) * build: add MemorySanitizer (MSAN) support (Ben Noordhuis) * doc: add uv_poll_cb status==UV_EBADF note (jensbjorgensen) * build: support AddressSanitizer on MSVC (Jameson Nash) * win,pipe: improve method of obtaining pid for ipc (number201724) * thread: add support for affinity (daomingq) * include: map ENODATA error code (Ben Noordhuis) * build: remove bashism from autogen.sh (Santiago Gimeno) * win,tcp,udp: remove "active streams" optimization (Saúl Ibarra Corretgé) * win: drop code checking for Windows XP / Server 2k3 (Saúl Ibarra Corretgé) * unix,win: fix 'sprintf' is deprecated warning (twosee) * doc: mention close_cb can be NULL (Qix) * win: optimize udp receive performance (ywave620) * win: fix an incompatible types warning (twosee) * doc: document 0 return value for free/total memory (Ben Noordhuis) * darwin: use hw.cpufrequency again for frequency info (Jameson Nash) * win,test: change format of TEST_PIPENAME's (Santiago Gimeno) * win,pipe: fixes in uv_pipe_connect() (Santiago Gimeno) * misc: fix return value of memory functions (theanarkh) * src: add new metrics APIs (Trevor Norris) * thread: add uv_thread_getcpu() (daomingq) * build: don't use ifaddrs.h on solaris 10 (Edward Humes) * unix,win: add uv_get_available_memory() (Tim Besard) * test: fix -Wunused-but-set-variable warnings (Ben Noordhuis) * doc: bump min supported linux and freebsd versions (Ben Noordhuis) * Add Socket Runtime to the LINKS.md (Sergey Rubanov) * unix: drop kfreebsd support (Ben Noordhuis) * win: fix fstat for pipes and character files (Stefan Stojanovic) * win: fix -Wunused-variable warning (Ben Noordhuis) * win: fix -Wunused-function warning (Ben Noordhuis) * build: drop qemu-alpha from ci matrix (Ben Noordhuis) * win: move child_stdio_buffer out of uv_process_t (Santiago Gimeno) * test: fix some unreachable code warnings (Santiago Gimeno) * linux: simplify uv_uptime() (Ben Noordhuis) * test: unflake fs_event_watch_dir test (Ben Noordhuis) * darwin: remove unused fsevents symbol lookups (Ben Noordhuis) * build: add define guard around UV_EXTERN (Zvicii) * build: add UndefinedBehaviorSanitizer support (Ben Noordhuis) * build: enable platform_output test on qemu (Ben Noordhuis) * linux: handle cpu hotplugging in uv_cpu_info() (Ben Noordhuis) * build: remove unnecessary policy setting (dundargoc) * docs: add vcpkg instruction step (Jack·Boos·Yu) * win,fs: fix readlink errno for a non-symlink file (Darshan Sen) * misc: extend getpw to take uid as an argument (Jameson Nash) * unix,win: use static_assert when available (Ben Noordhuis) * docs: delete code Makefile (Jameson Nash) * docs: add CI for docs PRs (Jameson Nash) * docs: update Sphinx version on RTD (Jameson Nash) * doc: clean up license file (Ben Noordhuis) * test: fix some warnings when compiling tests (panran) * build,win: add mingw-w64 CI configuration (Jameson Nash) * build: add CI for distcheck (Jameson Nash) * unix: remove busy loop from uv_async_send (Jameson Nash) * doc: document uv_fs_cb type (Tamás Bálint Misius) * build: Improve build by cmake for Cygwin (erw7) * build: add libuv:: namespace to libuvConfig.cmake (AJ Heller) * test: fix ThreadSanitizer thread leak warning (Ben Noordhuis) * test: fix ThreadSanitizer data race warning (Ben Noordhuis) * test: fix ThreadSanitizer data race warning (Ben Noordhuis) * test: fix ThreadSanitizer data race warning (Ben Noordhuis) * test: cond-skip fork_threadpool_queue_work_simple (Ben Noordhuis) * test: cond-skip signal_multiple_loops (Ben Noordhuis) * test: cond-skip tcp_writealot (Ben Noordhuis) * build: promote tsan ci to must-pass (Ben Noordhuis) * build: add CI for OpenBSD and FreeBSD (James McCoy) * build,test: fix distcheck errors (Jameson Nash) * test: remove bad tty window size assumption (Ben Noordhuis) * darwin,process: feed kevent the signal to reap children (Jameson Nash) * unix: abort on clock_gettime() error (Ben Noordhuis) * test: remove timing-sensitive check (Ben Noordhuis) * unix: DRY and fix tcp bind error path (Jameson Nash) * macos: fix fsevents thread race conditions (Ben Noordhuis) * win: fix leak in uv_chdir (Trevor Norris) * test: make valgrind happy (Trevor Norris) * barrier: wait for prior out before next in (Jameson Nash) * test: fix visual studio 2015 build error (Ben Noordhuis) * linux: fix ceph copy error truncating readonly files (Bruno Passeri) * test: silence more valgrind warnings (Trevor Norris) * doc: add entries to LINKS.md (Trevor Norris) * win,unix: change execution order of timers (Trevor Norris) * doc: add trevnorris to maintainers (Trevor Norris) * linux: remove epoll_pwait() emulation code path (Ben Noordhuis) * linux: replace unsafe macro with inline function (Ben Noordhuis) * linux: remove arm oabi support (Ben Noordhuis) * unix,sunos: SO_REUSEPORT not valid on all sockets (Stacey Marshall) * doc: consistent single backquote in misc.rst (Jason Zhang) * src: switch to use C11 atomics where available (Trevor Norris) * test: don't use static buffer for formatting (Ben Noordhuis) * linux: introduce io_uring support (Ben Noordhuis) * linux: fix academic valgrind warning (Ben Noordhuis) * test: disable signal test under ASan and MSan (Ben Noordhuis) * linux: add IORING_OP_OPENAT support (Ben Noordhuis) * linux: add IORING_OP_CLOSE support (Ben Noordhuis) * linux: remove bug workaround for obsolete kernels (Ben Noordhuis) * doc: update active maintainers list (Ben Noordhuis) * test: add ASSERT_OK (Trevor Norris) * src: fix events/events_waiting metrics counter (Trevor Norris) * unix,win: add uv_clock_gettime() (Ben Noordhuis) * build: remove freebsd and openbsd buildbots (Ben Noordhuis) * win: fix race condition in uv__init_console() (sivadeilra) * linux: fix logic bug in sqe ring space check (Ben Noordhuis) * linux: use io_uring to batch epoll_ctl calls (Ben Noordhuis) * macos: update minimum supported version (Santiago Gimeno) * docs: fix some typos (cui fliter) * unix: use memcpy() instead of type punning (Ben Noordhuis) * test: add additional assert (Mohammed Keyvanzadeh) * build: export compile_commands.json (Lewis Russell) * win,process: write minidumps when sending SIGQUIT (Elliot Saba) * unix: constrained_memory should return UINT64_MAX (Tim Besard) * unix: handle CQ overflow in iou ring (Santiago Gimeno) * unix: remove clang compiler warning pragmas (Ben Noordhuis) * win: fix mingw build (gengjiawen) * test: fix -Wbool-compare compiler warning (Ben Noordhuis) * win: define MiniDumpWithAvxXStateContext always (Santiago Gimeno) * freebsd: hard-code UV_ENODATA definition (Santiago Gimeno) * linux: work around EOWNERDEAD io_uring kernel bug (Ben Noordhuis) * linux: fix WRITEV with lots of bufs using io_uring (Santiago Gimeno) --- .mailmap | 3 + AUTHORS | 25 ++++ ChangeLog | 293 +++++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 8 +- 5 files changed, 326 insertions(+), 5 deletions(-) diff --git a/.mailmap b/.mailmap index b23377c6151..bf12432495d 100644 --- a/.mailmap +++ b/.mailmap @@ -29,6 +29,7 @@ Keno Fischer Keno Fischer Leith Bade Leonard Hecker +Lewis Russell Maciej Małecki Marc Schlaich Michael @@ -60,5 +61,7 @@ gengjiawen jBarz jBarz ptlomholt +theanarkh <2923878201@qq.com> tjarlama <59913901+tjarlama@users.noreply.github.com> +ywave620 <60539365+ywave620@users.noreply.github.com> zlargon diff --git a/AUTHORS b/AUTHORS index e03100eab9d..b6860c6620f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -517,3 +517,28 @@ chucksilvers Sergey Fedorov theanarkh <2923878201@qq.com> Samuel Cabrero +自发对称破缺 <429839446@qq.com> +Luan Devecchi +Steven Schveighoffer +number201724 +Daniel +Christian Clason +ywave620 +jensbjorgensen +daomingq +Qix +Edward Humes <29870961+aurxenon@users.noreply.github.com> +Tim Besard +Sergey Rubanov +Stefan Stojanovic +Zvicii +dundargoc <33953936+dundargoc@users.noreply.github.com> +Jack·Boos·Yu <47264268+JackBoosY@users.noreply.github.com> +panran <310762957@qq.com> +Tamás Bálint Misius +Bruno Passeri +Jason Zhang +Lewis Russell +sivadeilra +cui fliter +Mohammed Keyvanzadeh diff --git a/ChangeLog b/ChangeLog index 6a883842a83..559c1442205 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,296 @@ +2023.05.19, Version 1.45.0 (Stable) + +Changes since version 1.44.2: + +* win: remove stdint-msvc2008.h (Ben Noordhuis) + +* android: remove pthread-fixes.c (Ben Noordhuis) + +* build: enable MSVC_RUNTIME_LIBRARY setting (自发对称破缺) + +* unix: switch to c11 atomics (Ben Noordhuis) + +* unix: don't accept() connections in a loop (Ben Noordhuis) + +* win: fix off-by-1 buffer overrun in uv_exepath() (Ben Noordhuis) + +* build: switch ci from macos-10.15 to macos-11 (Ben Noordhuis) + +* win: fix thread race in uv_cwd() and uv_chdir() (Ben Noordhuis) + +* unix,win: remove UV_HANDLE_SHUTTING flag (Santiago Gimeno) + +* win: support Windows 11 in uv_os_uname() (Luan Devecchi) + +* unix: fix uv_getrusage() ru_maxrss reporting (Ben Noordhuis) + +* doc: add note about offset -1 in uv_fs_read/write (Steven Schveighoffer) + +* test: fix musl libc.a dlerror() test expectation (Ben Noordhuis) + +* kqueue: DRY file descriptor deletion logic (Ben Noordhuis) + +* linux: teach uv_get_constrained_memory() cgroupsv2 (Ben Noordhuis) + +* build: upgrade qemu-user-static package (Ben Noordhuis) + +* linux: move epoll.c back into linux-core.c (Ben Noordhuis) + +* unix: remove pre-macos 10.8 compatibility hack (Ben Noordhuis) + +* unix,win: fix memory leak in uv_fs_scandir() (Ben Noordhuis) + +* build: restore qemu download logic (Ben Noordhuis) + +* win: fix uv__pipe_accept memory leak (number201724) + +* doc: update LINKS.md (Daniel) + +* unix: simplify atomic op in uv_tty_reset_mode() (Ben Noordhuis) + +* build: add LIBUV_BUILD_SHARED cmake option (Christian Clason) + +* linux: remove unused or obsolete syscall wrappers (Ben Noordhuis) + +* linux: merge files back into single file (Ben Noordhuis) + +* stream: process more than one write req per loop tick (ywave620) + +* unix,win: give thread pool threads an 8 MB stack (Ben Noordhuis) + +* build: add MemorySanitizer (MSAN) support (Ben Noordhuis) + +* doc: add uv_poll_cb status==UV_EBADF note (jensbjorgensen) + +* build: support AddressSanitizer on MSVC (Jameson Nash) + +* win,pipe: improve method of obtaining pid for ipc (number201724) + +* thread: add support for affinity (daomingq) + +* include: map ENODATA error code (Ben Noordhuis) + +* build: remove bashism from autogen.sh (Santiago Gimeno) + +* win,tcp,udp: remove "active streams" optimization (Saúl Ibarra Corretgé) + +* win: drop code checking for Windows XP / Server 2k3 (Saúl Ibarra Corretgé) + +* unix,win: fix 'sprintf' is deprecated warning (twosee) + +* doc: mention close_cb can be NULL (Qix) + +* win: optimize udp receive performance (ywave620) + +* win: fix an incompatible types warning (twosee) + +* doc: document 0 return value for free/total memory (Ben Noordhuis) + +* darwin: use hw.cpufrequency again for frequency info (Jameson Nash) + +* win,test: change format of TEST_PIPENAME's (Santiago Gimeno) + +* win,pipe: fixes in uv_pipe_connect() (Santiago Gimeno) + +* misc: fix return value of memory functions (theanarkh) + +* src: add new metrics APIs (Trevor Norris) + +* thread: add uv_thread_getcpu() (daomingq) + +* build: don't use ifaddrs.h on solaris 10 (Edward Humes) + +* unix,win: add uv_get_available_memory() (Tim Besard) + +* test: fix -Wunused-but-set-variable warnings (Ben Noordhuis) + +* doc: bump min supported linux and freebsd versions (Ben Noordhuis) + +* Add Socket Runtime to the LINKS.md (Sergey Rubanov) + +* unix: drop kfreebsd support (Ben Noordhuis) + +* win: fix fstat for pipes and character files (Stefan Stojanovic) + +* win: fix -Wunused-variable warning (Ben Noordhuis) + +* win: fix -Wunused-function warning (Ben Noordhuis) + +* build: drop qemu-alpha from ci matrix (Ben Noordhuis) + +* win: move child_stdio_buffer out of uv_process_t (Santiago Gimeno) + +* test: fix some unreachable code warnings (Santiago Gimeno) + +* linux: simplify uv_uptime() (Ben Noordhuis) + +* test: unflake fs_event_watch_dir test (Ben Noordhuis) + +* darwin: remove unused fsevents symbol lookups (Ben Noordhuis) + +* build: add define guard around UV_EXTERN (Zvicii) + +* build: add UndefinedBehaviorSanitizer support (Ben Noordhuis) + +* build: enable platform_output test on qemu (Ben Noordhuis) + +* linux: handle cpu hotplugging in uv_cpu_info() (Ben Noordhuis) + +* build: remove unnecessary policy setting (dundargoc) + +* docs: add vcpkg instruction step (Jack·Boos·Yu) + +* win,fs: fix readlink errno for a non-symlink file (Darshan Sen) + +* misc: extend getpw to take uid as an argument (Jameson Nash) + +* unix,win: use static_assert when available (Ben Noordhuis) + +* docs: delete code Makefile (Jameson Nash) + +* docs: add CI for docs PRs (Jameson Nash) + +* docs: update Sphinx version on RTD (Jameson Nash) + +* doc: clean up license file (Ben Noordhuis) + +* test: fix some warnings when compiling tests (panran) + +* build,win: add mingw-w64 CI configuration (Jameson Nash) + +* build: add CI for distcheck (Jameson Nash) + +* unix: remove busy loop from uv_async_send (Jameson Nash) + +* doc: document uv_fs_cb type (Tamás Bálint Misius) + +* build: Improve build by cmake for Cygwin (erw7) + +* build: add libuv:: namespace to libuvConfig.cmake (AJ Heller) + +* test: fix ThreadSanitizer thread leak warning (Ben Noordhuis) + +* test: fix ThreadSanitizer data race warning (Ben Noordhuis) + +* test: fix ThreadSanitizer data race warning (Ben Noordhuis) + +* test: fix ThreadSanitizer data race warning (Ben Noordhuis) + +* test: cond-skip fork_threadpool_queue_work_simple (Ben Noordhuis) + +* test: cond-skip signal_multiple_loops (Ben Noordhuis) + +* test: cond-skip tcp_writealot (Ben Noordhuis) + +* build: promote tsan ci to must-pass (Ben Noordhuis) + +* build: add CI for OpenBSD and FreeBSD (James McCoy) + +* build,test: fix distcheck errors (Jameson Nash) + +* test: remove bad tty window size assumption (Ben Noordhuis) + +* darwin,process: feed kevent the signal to reap children (Jameson Nash) + +* unix: abort on clock_gettime() error (Ben Noordhuis) + +* test: remove timing-sensitive check (Ben Noordhuis) + +* unix: DRY and fix tcp bind error path (Jameson Nash) + +* macos: fix fsevents thread race conditions (Ben Noordhuis) + +* win: fix leak in uv_chdir (Trevor Norris) + +* test: make valgrind happy (Trevor Norris) + +* barrier: wait for prior out before next in (Jameson Nash) + +* test: fix visual studio 2015 build error (Ben Noordhuis) + +* linux: fix ceph copy error truncating readonly files (Bruno Passeri) + +* test: silence more valgrind warnings (Trevor Norris) + +* doc: add entries to LINKS.md (Trevor Norris) + +* win,unix: change execution order of timers (Trevor Norris) + +* doc: add trevnorris to maintainers (Trevor Norris) + +* linux: remove epoll_pwait() emulation code path (Ben Noordhuis) + +* linux: replace unsafe macro with inline function (Ben Noordhuis) + +* linux: remove arm oabi support (Ben Noordhuis) + +* unix,sunos: SO_REUSEPORT not valid on all sockets (Stacey Marshall) + +* doc: consistent single backquote in misc.rst (Jason Zhang) + +* src: switch to use C11 atomics where available (Trevor Norris) + +* test: don't use static buffer for formatting (Ben Noordhuis) + +* linux: introduce io_uring support (Ben Noordhuis) + +* linux: fix academic valgrind warning (Ben Noordhuis) + +* test: disable signal test under ASan and MSan (Ben Noordhuis) + +* linux: add IORING_OP_OPENAT support (Ben Noordhuis) + +* linux: add IORING_OP_CLOSE support (Ben Noordhuis) + +* linux: remove bug workaround for obsolete kernels (Ben Noordhuis) + +* doc: update active maintainers list (Ben Noordhuis) + +* test: add ASSERT_OK (Trevor Norris) + +* src: fix events/events_waiting metrics counter (Trevor Norris) + +* unix,win: add uv_clock_gettime() (Ben Noordhuis) + +* build: remove freebsd and openbsd buildbots (Ben Noordhuis) + +* win: fix race condition in uv__init_console() (sivadeilra) + +* linux: fix logic bug in sqe ring space check (Ben Noordhuis) + +* linux: use io_uring to batch epoll_ctl calls (Ben Noordhuis) + +* macos: update minimum supported version (Santiago Gimeno) + +* docs: fix some typos (cui fliter) + +* unix: use memcpy() instead of type punning (Ben Noordhuis) + +* test: add additional assert (Mohammed Keyvanzadeh) + +* build: export compile_commands.json (Lewis Russell) + +* win,process: write minidumps when sending SIGQUIT (Elliot Saba) + +* unix: constrained_memory should return UINT64_MAX (Tim Besard) + +* unix: handle CQ overflow in iou ring (Santiago Gimeno) + +* unix: remove clang compiler warning pragmas (Ben Noordhuis) + +* win: fix mingw build (gengjiawen) + +* test: fix -Wbool-compare compiler warning (Ben Noordhuis) + +* win: define MiniDumpWithAvxXStateContext always (Santiago Gimeno) + +* freebsd: hard-code UV_ENODATA definition (Santiago Gimeno) + +* linux: work around EOWNERDEAD io_uring kernel bug (Ben Noordhuis) + +* linux: fix WRITEV with lots of bufs using io_uring (Santiago Gimeno) + + 2022.07.12, Version 1.44.2 (Stable), 0c1fa696aa502eb749c2c4735005f41ba00a27b8 Changes since version 1.44.1: diff --git a/configure.ac b/configure.ac index 57465f2d431..143ade35719 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.44.3-dev], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.45.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 82517af7160..febad1ef1c1 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 44 -#define UV_VERSION_PATCH 3 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 45 +#define UV_VERSION_PATCH 0 +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From d4f8a4ab5dbceabc78db6f47ed105a8547eff190 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 19 May 2023 13:21:01 +0200 Subject: [PATCH 374/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 559c1442205..1b6f2eee10d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2023.05.19, Version 1.45.0 (Stable) +2023.05.19, Version 1.45.0 (Stable), 96e05543f53b19d9642b4b0dd73b86ad3cea313e Changes since version 1.44.2: From a4649f5078134a4ef7fa355c21eeca9f2d5db9b0 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 19 May 2023 13:32:22 +0200 Subject: [PATCH 375/713] Now working on version 1.45.1 Fixes: https://github.com/libuv/libuv/issues/3887 --- configure.ac | 2 +- include/uv/version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 143ade35719..ae8466c1351 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.45.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.45.1-dev], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index febad1ef1c1..2d7309f0233 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 45 -#define UV_VERSION_PATCH 0 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 1 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 4e766761d00759e9c53d37ca0c04e2872cba6006 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 20 May 2023 09:36:23 -0400 Subject: [PATCH 376/713] misc: update readthedocs config (#4009) Now required: https://docs.readthedocs.io/en/stable/config-file/v2.html#build-os --- .readthedocs.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index c1c9ab238cd..b16bf0d4ab7 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -6,6 +6,7 @@ sphinx: fail_on_warning: false build: + os: "ubuntu-22.04" tools: python: "3.9" From 5bf18a6e88cd85cf5d70b109f20dbf3945030d16 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 23 May 2023 00:24:39 +0200 Subject: [PATCH 377/713] test: remove erroneous RETURN_SKIP (#4015) The threadpool_multiple_event_loops test already calls RETURN_SKIP when needed. Remove it from the callback function where it isn't needed work (nor works) and generates a build warning when compiling for qemu. Fixes: https://github.com/libuv/libuv/issues/4014 --- test/test-thread.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/test-thread.c b/test/test-thread.c index c01991b4723..82f80833ab1 100644 --- a/test/test-thread.c +++ b/test/test-thread.c @@ -78,10 +78,6 @@ static void getaddrinfo_do(struct getaddrinfo_req* req) { static void getaddrinfo_cb(uv_getaddrinfo_t* handle, int status, struct addrinfo* res) { -/* TODO(gengjiawen): Fix test on QEMU. */ -#if defined(__QEMU__) - RETURN_SKIP("Test does not currently work in QEMU"); -#endif struct getaddrinfo_req* req; ASSERT(status == 0); From 281e6185cc9e77c582ff6ca9e4c00d57e6b90d95 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 23 May 2023 00:25:09 +0200 Subject: [PATCH 378/713] android: disable io_uring support (#4016) Android's zealous seccomp filter blocks the io_uring_setup system call. Fixes: https://github.com/libuv/libuv/issues/4010 --- src/unix/linux.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/unix/linux.c b/src/unix/linux.c index a3439184c37..ebffb69dd69 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -385,6 +385,9 @@ int uv__io_uring_register(int fd, unsigned opcode, void* arg, unsigned nargs) { static int uv__use_io_uring(void) { +#if defined(__ANDROID_API__) + return 0; /* Possibly available but blocked by seccomp. */ +#else /* Ternary: unknown=0, yes=1, no=-1 */ static _Atomic int use_io_uring; char* val; @@ -399,6 +402,7 @@ static int uv__use_io_uring(void) { } return use > 0; +#endif } From 962b8e626ceaaf296eecab1d008e8b70dc6da5e7 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 23 May 2023 10:42:20 +0200 Subject: [PATCH 379/713] linux: add some more iouring backed fs ops (#4012) Specifically: `link`, `mkdir`, `rename`, `symlink` and `unlink`. --- src/unix/fs.c | 17 ++++- src/unix/internal.h | 11 +++ src/unix/linux.c | 128 ++++++++++++++++++++++++++++++++++ src/uv-common.h | 1 + test/test-threadpool-cancel.c | 5 ++ 5 files changed, 161 insertions(+), 1 deletion(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 5f9aae373b9..80b6a23970d 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -899,7 +899,7 @@ static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) { #ifdef __linux__ -static unsigned uv__kernel_version(void) { +unsigned uv__kernel_version(void) { static _Atomic unsigned cached_version; struct utsname u; unsigned version; @@ -1926,6 +1926,9 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_cb cb) { INIT(LINK); PATH2; + if (cb != NULL) + if (uv__iou_fs_link(loop, req)) + return 0; POST; } @@ -1938,6 +1941,9 @@ int uv_fs_mkdir(uv_loop_t* loop, INIT(MKDIR); PATH; req->mode = mode; + if (cb != NULL) + if (uv__iou_fs_mkdir(loop, req)) + return 0; POST; } @@ -2089,6 +2095,9 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_cb cb) { INIT(RENAME); PATH2; + if (cb != NULL) + if (uv__iou_fs_rename(loop, req)) + return 0; POST; } @@ -2135,6 +2144,9 @@ int uv_fs_symlink(uv_loop_t* loop, INIT(SYMLINK); PATH2; req->flags = flags; + if (cb != NULL) + if (uv__iou_fs_symlink(loop, req)) + return 0; POST; } @@ -2142,6 +2154,9 @@ int uv_fs_symlink(uv_loop_t* loop, int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { INIT(UNLINK); PATH; + if (cb != NULL) + if (uv__iou_fs_unlink(loop, req)) + return 0; POST; } diff --git a/src/unix/internal.h b/src/unix/internal.h index 6c5822e6a0d..fe588513603 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -335,20 +335,30 @@ int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req); int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop, uv_fs_t* req, uint32_t fsync_flags); +int uv__iou_fs_link(uv_loop_t* loop, uv_fs_t* req); +int uv__iou_fs_mkdir(uv_loop_t* loop, uv_fs_t* req); int uv__iou_fs_open(uv_loop_t* loop, uv_fs_t* req); int uv__iou_fs_read_or_write(uv_loop_t* loop, uv_fs_t* req, int is_read); +int uv__iou_fs_rename(uv_loop_t* loop, uv_fs_t* req); int uv__iou_fs_statx(uv_loop_t* loop, uv_fs_t* req, int is_fstat, int is_lstat); +int uv__iou_fs_symlink(uv_loop_t* loop, uv_fs_t* req); +int uv__iou_fs_unlink(uv_loop_t* loop, uv_fs_t* req); #else #define uv__iou_fs_close(loop, req) 0 #define uv__iou_fs_fsync_or_fdatasync(loop, req, fsync_flags) 0 +#define uv__iou_fs_link(loop, req) 0 +#define uv__iou_fs_mkdir(loop, req) 0 #define uv__iou_fs_open(loop, req) 0 #define uv__iou_fs_read_or_write(loop, req, is_read) 0 +#define uv__iou_fs_rename(loop, req) 0 #define uv__iou_fs_statx(loop, req, is_fstat, is_lstat) 0 +#define uv__iou_fs_symlink(loop, req) 0 +#define uv__iou_fs_unlink(loop, req) 0 #endif #if defined(__APPLE__) @@ -429,6 +439,7 @@ int uv__statx(int dirfd, struct uv__statx* statxbuf); void uv__statx_to_stat(const struct uv__statx* statxbuf, uv_stat_t* buf); ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags); +unsigned uv__kernel_version(void); #endif typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*); diff --git a/src/unix/linux.c b/src/unix/linux.c index ebffb69dd69..9432e8541da 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -150,6 +150,11 @@ enum { UV__IORING_OP_CLOSE = 19, UV__IORING_OP_STATX = 21, UV__IORING_OP_EPOLL_CTL = 29, + UV__IORING_OP_RENAMEAT = 35, + UV__IORING_OP_UNLINKAT = 36, + UV__IORING_OP_MKDIRAT = 37, + UV__IORING_OP_SYMLINKAT = 38, + UV__IORING_OP_LINKAT = 39, }; enum { @@ -162,6 +167,10 @@ enum { UV__IORING_SQ_CQ_OVERFLOW = 2u, }; +enum { + UV__MKDIRAT_SYMLINKAT_LINKAT = 1u, +}; + struct uv__io_cqring_offsets { uint32_t head; uint32_t tail; @@ -507,6 +516,10 @@ static void uv__iou_init(int epollfd, iou->sqelen = sqelen; iou->ringfd = ringfd; iou->in_flight = 0; + iou->flags = 0; + + if (uv__kernel_version() >= /* 5.15.0 */ 0x050F00) + iou->flags |= UV__MKDIRAT_SYMLINKAT_LINKAT; for (i = 0; i <= iou->sqmask; i++) iou->sqarray[i] = i; /* Slot -> sqe identity mapping. */ @@ -758,6 +771,55 @@ int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop, } +int uv__iou_fs_link(uv_loop_t* loop, uv_fs_t* req) { + struct uv__io_uring_sqe* sqe; + struct uv__iou* iou; + + iou = &uv__get_internal_fields(loop)->iou; + + if (!(iou->flags & UV__MKDIRAT_SYMLINKAT_LINKAT)) + return 0; + + sqe = uv__iou_get_sqe(iou, loop, req); + if (sqe == NULL) + return 0; + + sqe->addr = (uintptr_t) req->path; + sqe->fd = AT_FDCWD; + sqe->addr2 = (uintptr_t) req->new_path; + sqe->len = AT_FDCWD; + sqe->opcode = UV__IORING_OP_LINKAT; + + uv__iou_submit(iou); + + return 1; +} + + +int uv__iou_fs_mkdir(uv_loop_t* loop, uv_fs_t* req) { + struct uv__io_uring_sqe* sqe; + struct uv__iou* iou; + + iou = &uv__get_internal_fields(loop)->iou; + + if (!(iou->flags & UV__MKDIRAT_SYMLINKAT_LINKAT)) + return 0; + + sqe = uv__iou_get_sqe(iou, loop, req); + if (sqe == NULL) + return 0; + + sqe->addr = (uintptr_t) req->path; + sqe->fd = AT_FDCWD; + sqe->len = req->mode; + sqe->opcode = UV__IORING_OP_MKDIRAT; + + uv__iou_submit(iou); + + return 1; +} + + int uv__iou_fs_open(uv_loop_t* loop, uv_fs_t* req) { struct uv__io_uring_sqe* sqe; struct uv__iou* iou; @@ -780,6 +842,72 @@ int uv__iou_fs_open(uv_loop_t* loop, uv_fs_t* req) { } +int uv__iou_fs_rename(uv_loop_t* loop, uv_fs_t* req) { + struct uv__io_uring_sqe* sqe; + struct uv__iou* iou; + + iou = &uv__get_internal_fields(loop)->iou; + + sqe = uv__iou_get_sqe(iou, loop, req); + if (sqe == NULL) + return 0; + + sqe->addr = (uintptr_t) req->path; + sqe->fd = AT_FDCWD; + sqe->addr2 = (uintptr_t) req->new_path; + sqe->len = AT_FDCWD; + sqe->opcode = UV__IORING_OP_RENAMEAT; + + uv__iou_submit(iou); + + return 1; +} + + +int uv__iou_fs_symlink(uv_loop_t* loop, uv_fs_t* req) { + struct uv__io_uring_sqe* sqe; + struct uv__iou* iou; + + iou = &uv__get_internal_fields(loop)->iou; + + if (!(iou->flags & UV__MKDIRAT_SYMLINKAT_LINKAT)) + return 0; + + sqe = uv__iou_get_sqe(iou, loop, req); + if (sqe == NULL) + return 0; + + sqe->addr = (uintptr_t) req->path; + sqe->fd = AT_FDCWD; + sqe->addr2 = (uintptr_t) req->new_path; + sqe->opcode = UV__IORING_OP_SYMLINKAT; + + uv__iou_submit(iou); + + return 1; +} + + +int uv__iou_fs_unlink(uv_loop_t* loop, uv_fs_t* req) { + struct uv__io_uring_sqe* sqe; + struct uv__iou* iou; + + iou = &uv__get_internal_fields(loop)->iou; + + sqe = uv__iou_get_sqe(iou, loop, req); + if (sqe == NULL) + return 0; + + sqe->addr = (uintptr_t) req->path; + sqe->fd = AT_FDCWD; + sqe->opcode = UV__IORING_OP_UNLINKAT; + + uv__iou_submit(iou); + + return 1; +} + + int uv__iou_fs_read_or_write(uv_loop_t* loop, uv_fs_t* req, int is_read) { diff --git a/src/uv-common.h b/src/uv-common.h index decde5362c8..c0f6daf1b8f 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -415,6 +415,7 @@ struct uv__iou { size_t sqelen; int ringfd; uint32_t in_flight; + uint32_t flags; }; #endif /* __linux__ */ diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index 263d54a5234..07634e3f3fe 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -98,11 +98,16 @@ static int known_broken(uv_req_t* req) { case UV_FS_FDATASYNC: case UV_FS_FSTAT: case UV_FS_FSYNC: + case UV_FS_LINK: case UV_FS_LSTAT: + case UV_FS_MKDIR: case UV_FS_OPEN: case UV_FS_READ: + case UV_FS_RENAME: case UV_FS_STAT: + case UV_FS_SYMLINK: case UV_FS_WRITE: + case UV_FS_UNLINK: return 1; default: /* Squelch -Wswitch warnings. */ break; From 6d0d4a3e4d91bcd2845fe44c328d6c65cf4c9cea Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 23 May 2023 09:15:53 -0400 Subject: [PATCH 380/713] build: add autoconf option for disable-maintainer-mode (#4000) --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index ae8466c1351..214754bfa05 100644 --- a/configure.ac +++ b/configure.ac @@ -19,6 +19,7 @@ m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) m4_include([m4/libuv-check-flags.m4]) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS) +AM_MAINTAINER_MODE([enable]) # pass --disable-maintainer-mode if autotools may be unavailable AC_CANONICAL_HOST AC_ENABLE_SHARED AC_ENABLE_STATIC From 8f32a14afaaa47514a7d28e1e069a8329e2dd939 Mon Sep 17 00:00:00 2001 From: Stefan Karpinski Date: Tue, 23 May 2023 10:25:38 -0400 Subject: [PATCH 381/713] fs: use WTF-8 on Windows (#2970) This allows working with valid filenames that are not well-formed UTF-16. This is a superset of UTF-8, which does not error when it encounters an unpaired surrogate but simply allows it. Fixes: https://github.com/libuv/libuv/issues/2048 Refs: https://simonsapin.github.io/wtf-8/ Replaces: https://github.com/libuv/libuv/pull/2192 by Nikolai Vavilov Co-authored-by: Jameson Nash --- src/win/fs.c | 311 +++++++++++++++++++++++++++++++---------------- test/test-fs.c | 53 ++++++++ test/test-list.h | 2 + 3 files changed, 263 insertions(+), 103 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 2fc7481f9a2..9d0614f2c66 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -144,26 +144,97 @@ void uv__fs_init(void) { } +static int32_t fs__decode_wtf8_char(const char** input) { + uint32_t code_point; + uint8_t b1; + uint8_t b2; + uint8_t b3; + uint8_t b4; + + b1 = **input; + if (b1 <= 0x7F) + return b1; /* ASCII code point */ + if (b1 < 0xC2) + return -1; /* invalid: continuation byte */ + code_point = b1; + + b2 = *++*input; + if ((b2 & 0xC0) != 0x80) + return -1; /* invalid: not a continuation byte */ + code_point = (code_point << 6) | (b2 & 0x3F); + if (b1 <= 0xDF) + return 0x7FF & code_point; /* two-byte character */ + + b3 = *++*input; + if ((b3 & 0xC0) != 0x80) + return -1; /* invalid: not a continuation byte */ + code_point = (code_point << 6) | (b3 & 0x3F); + if (b1 <= 0xEF) + return 0xFFFF & code_point; /* three-byte character */ + + b4 = *++*input; + if ((b4 & 0xC0) != 0x80) + return -1; /* invalid: not a continuation byte */ + code_point = (code_point << 6) | (b4 & 0x3F); + if (b1 <= 0xF4) + if (code_point <= 0x10FFFF) + return code_point; /* four-byte character */ + + /* code point too large */ + return -1; +} + + +static ssize_t fs__get_length_wtf8(const char* source_ptr) { + size_t w_target_len = 0; + int32_t code_point; + + do { + code_point = fs__decode_wtf8_char(&source_ptr); + if (code_point < 0) + return -1; + if (code_point > 0xFFFF) + w_target_len++; + w_target_len++; + } while (*source_ptr++); + return w_target_len; +} + + +static void fs__wtf8_to_wide(const char* source_ptr, WCHAR* w_target) { + int32_t code_point; + + do { + code_point = fs__decode_wtf8_char(&source_ptr); + /* fs__get_length_wtf8 should have been called and checked first. */ + assert(code_point >= 0); + if (code_point > 0x10000) { + assert(code_point < 0x10FFFF); + *w_target++ = (((code_point - 0x10000) >> 10) + 0xD800); + *w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00; + } else { + *w_target++ = code_point; + } + } while (*source_ptr++); +} + + INLINE static int fs__capture_path(uv_fs_t* req, const char* path, const char* new_path, const int copy_path) { - char* buf; - char* pos; - ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0; + WCHAR* buf; + WCHAR* pos; + size_t buf_sz = 0; + size_t path_len = 0; + ssize_t pathw_len = 0; + ssize_t new_pathw_len = 0; /* new_path can only be set if path is also set. */ assert(new_path == NULL || path != NULL); if (path != NULL) { - pathw_len = MultiByteToWideChar(CP_UTF8, - 0, - path, - -1, - NULL, - 0); - if (pathw_len == 0) { - return GetLastError(); - } - + pathw_len = fs__get_length_wtf8(path); + if (pathw_len < 0) + return ERROR_INVALID_NAME; buf_sz += pathw_len * sizeof(WCHAR); } @@ -173,16 +244,9 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path, } if (new_path != NULL) { - new_pathw_len = MultiByteToWideChar(CP_UTF8, - 0, - new_path, - -1, - NULL, - 0); - if (new_pathw_len == 0) { - return GetLastError(); - } - + new_pathw_len = fs__get_length_wtf8(new_path); + if (new_pathw_len < 0) + return ERROR_INVALID_NAME; buf_sz += new_pathw_len * sizeof(WCHAR); } @@ -194,7 +258,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path, return 0; } - buf = (char*) uv__malloc(buf_sz); + buf = uv__malloc(buf_sz); if (buf == NULL) { return ERROR_OUTOFMEMORY; } @@ -202,29 +266,17 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path, pos = buf; if (path != NULL) { - DWORD r = MultiByteToWideChar(CP_UTF8, - 0, - path, - -1, - (WCHAR*) pos, - pathw_len); - assert(r == (DWORD) pathw_len); - req->file.pathw = (WCHAR*) pos; - pos += r * sizeof(WCHAR); + fs__wtf8_to_wide(path, pos); + req->file.pathw = pos; + pos += pathw_len; } else { req->file.pathw = NULL; } if (new_path != NULL) { - DWORD r = MultiByteToWideChar(CP_UTF8, - 0, - new_path, - -1, - (WCHAR*) pos, - new_pathw_len); - assert(r == (DWORD) new_pathw_len); - req->fs.info.new_pathw = (WCHAR*) pos; - pos += r * sizeof(WCHAR); + fs__wtf8_to_wide(new_path, pos); + req->fs.info.new_pathw = pos; + pos += new_pathw_len; } else { req->fs.info.new_pathw = NULL; } @@ -232,8 +284,8 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path, req->path = path; if (path != NULL && copy_path) { memcpy(pos, path, path_len); - assert(path_len == buf_sz - (pos - buf)); - req->path = pos; + assert(path_len == buf_sz - (pos - buf) * sizeof(WCHAR)); + req->path = (char*) pos; } req->flags |= UV_FS_FREE_PATHS; @@ -259,57 +311,115 @@ INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req, } -static int fs__wide_to_utf8(WCHAR* w_source_ptr, - DWORD w_source_len, - char** target_ptr, - uint64_t* target_len_ptr) { - int r; - int target_len; - char* target; - target_len = WideCharToMultiByte(CP_UTF8, - 0, - w_source_ptr, - w_source_len, - NULL, - 0, - NULL, - NULL); +static int32_t fs__get_surrogate_value(const WCHAR* w_source_ptr, + size_t w_source_len) { + WCHAR u; + WCHAR next; - if (target_len == 0) { - return -1; + u = w_source_ptr[0]; + if (u >= 0xD800 && u <= 0xDBFF && w_source_len > 1) { + next = w_source_ptr[1]; + if (next >= 0xDC00 && next <= 0xDFFF) + return 0x10000 + ((u - 0xD800) << 10) + (next - 0xDC00); } + return u; +} - if (target_len_ptr != NULL) { - *target_len_ptr = target_len; + +static size_t fs__get_length_wide(const WCHAR* w_source_ptr, + size_t w_source_len) { + size_t target_len; + int32_t code_point; + + target_len = 0; + for (; w_source_len; w_source_len--, w_source_ptr++) { + code_point = fs__get_surrogate_value(w_source_ptr, w_source_len); + /* Can be invalid UTF-8 but must be valid WTF-8. */ + assert(code_point >= 0); + if (code_point < 0x80) + target_len += 1; + else if (code_point < 0x800) + target_len += 2; + else if (code_point < 0x10000) + target_len += 3; + else { + target_len += 4; + w_source_ptr++; + w_source_len--; + } } + return target_len; +} - if (target_ptr == NULL) { - return 0; + +static int fs__wide_to_wtf8(WCHAR* w_source_ptr, + size_t w_source_len, + char** target_ptr, + size_t* target_len_ptr) { + size_t target_len; + char* target; + int32_t code_point; + + /* If *target_ptr is provided, then *target_len_ptr must be its length + * (excluding space for null), otherwise we will compute the target_len_ptr + * length and may return a new allocation in *target_ptr if target_ptr is + * provided. */ + if (target_ptr == NULL || *target_ptr == NULL) { + target_len = fs__get_length_wide(w_source_ptr, w_source_len); + if (target_len_ptr != NULL) + *target_len_ptr = target_len; + } else { + target_len = *target_len_ptr; } - target = uv__malloc(target_len + 1); - if (target == NULL) { - SetLastError(ERROR_OUTOFMEMORY); - return -1; + if (target_ptr == NULL) + return 0; + + if (*target_ptr == NULL) { + target = uv__malloc(target_len + 1); + if (target == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + *target_ptr = target; + } else { + target = *target_ptr; + } + + for (; w_source_len; w_source_len--, w_source_ptr++) { + code_point = fs__get_surrogate_value(w_source_ptr, w_source_len); + /* Can be invalid UTF-8 but must be valid WTF-8. */ + assert(code_point >= 0); + + if (code_point < 0x80) { + *target++ = code_point; + } else if (code_point < 0x800) { + *target++ = 0xC0 | (code_point >> 6); + *target++ = 0x80 | (code_point & 0x3F); + } else if (code_point < 0x10000) { + *target++ = 0xE0 | (code_point >> 12); + *target++ = 0x80 | ((code_point >> 6) & 0x3F); + *target++ = 0x80 | (code_point & 0x3F); + } else { + *target++ = 0xF0 | (code_point >> 18); + *target++ = 0x80 | ((code_point >> 12) & 0x3F); + *target++ = 0x80 | ((code_point >> 6) & 0x3F); + *target++ = 0x80 | (code_point & 0x3F); + w_source_ptr++; + w_source_len--; + } } + assert((size_t) (target - *target_ptr) == target_len); + + *target++ = '\0'; - r = WideCharToMultiByte(CP_UTF8, - 0, - w_source_ptr, - w_source_len, - target, - target_len, - NULL, - NULL); - assert(r == target_len); - target[target_len] = '\0'; - *target_ptr = target; return 0; } -INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, - uint64_t* target_len_ptr) { +INLINE static int fs__readlink_handle(HANDLE handle, + char** target_ptr, + size_t* target_len_ptr) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer; WCHAR* w_target; @@ -439,7 +549,8 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, return -1; } - return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr); + assert(target_ptr == NULL || *target_ptr == NULL); + return fs__wide_to_wtf8(w_target, w_target_len, target_ptr, target_len_ptr); } @@ -1429,7 +1540,8 @@ void fs__scandir(uv_fs_t* req) { uv__dirent_t* dirent; size_t wchar_len; - size_t utf8_len; + size_t wtf8_len; + char* wtf8; /* Obtain a pointer to the current directory entry. */ position += next_entry_offset; @@ -1456,11 +1568,8 @@ void fs__scandir(uv_fs_t* req) { info->FileName[1] == L'.') continue; - /* Compute the space required to store the filename as UTF-8. */ - utf8_len = WideCharToMultiByte( - CP_UTF8, 0, &info->FileName[0], wchar_len, NULL, 0, NULL, NULL); - if (utf8_len == 0) - goto win32_error; + /* Compute the space required to store the filename as WTF-8. */ + wtf8_len = fs__get_length_wide(&info->FileName[0], wchar_len); /* Resize the dirent array if needed. */ if (dirents_used >= dirents_size) { @@ -1480,26 +1589,17 @@ void fs__scandir(uv_fs_t* req) { * includes room for the first character of the filename, but `utf8_len` * doesn't count the NULL terminator at this point. */ - dirent = uv__malloc(sizeof *dirent + utf8_len); + dirent = uv__malloc(sizeof *dirent + wtf8_len); if (dirent == NULL) goto out_of_memory_error; dirents[dirents_used++] = dirent; /* Convert file name to UTF-8. */ - if (WideCharToMultiByte(CP_UTF8, - 0, - &info->FileName[0], - wchar_len, - &dirent->d_name[0], - utf8_len, - NULL, - NULL) == 0) + wtf8 = &dirent->d_name[0]; + if (fs__wide_to_wtf8(&info->FileName[0], wchar_len, &wtf8, &wtf8_len) == -1) goto win32_error; - /* Add a null terminator to the filename. */ - dirent->d_name[utf8_len] = '\0'; - /* Fill out the type field. */ if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE) dirent->d_type = UV__DT_CHAR; @@ -1708,6 +1808,7 @@ void fs__closedir(uv_fs_t* req) { INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, int do_lstat) { + size_t target_length = 0; FILE_FS_DEVICE_INFORMATION device_info; FILE_ALL_INFORMATION file_info; FILE_FS_VOLUME_INFORMATION volume_info; @@ -1803,9 +1904,10 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, * to be treated as a regular file. The higher level lstat function will * detect this failure and retry without do_lstat if appropriate. */ - if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) + if (fs__readlink_handle(handle, NULL, &target_length) != 0) return -1; statbuf->st_mode |= S_IFLNK; + statbuf->st_size = target_length; } if (statbuf->st_mode == 0) { @@ -2661,6 +2763,7 @@ static void fs__readlink(uv_fs_t* req) { return; } + assert(req->ptr == NULL); if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) { DWORD error = GetLastError(); SET_REQ_WIN32_ERROR(req, error); @@ -2720,7 +2823,8 @@ static ssize_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { return -1; } - r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); + assert(*realpath_ptr == NULL); + r = fs__wide_to_wtf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); uv__free(w_realpath_buf); return r; } @@ -2740,6 +2844,7 @@ static void fs__realpath(uv_fs_t* req) { return; } + assert(req->ptr == NULL); if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) { CloseHandle(handle); SET_REQ_WIN32_ERROR(req, GetLastError()); diff --git a/test/test-fs.c b/test/test-fs.c index f9fa20eff6b..e687dde3e25 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -4550,6 +4550,7 @@ TEST_IMPL(fs_get_system_error) { return 0; } + TEST_IMPL(fs_stat_batch_multiple) { uv_fs_t req[300]; int r; @@ -4573,3 +4574,55 @@ TEST_IMPL(fs_stat_batch_multiple) { MAKE_VALGRIND_HAPPY(loop); return 0; } + + +#ifdef _WIN32 +TEST_IMPL(fs_wtf) { + int r; + HANDLE file_handle; + uv_dirent_t dent; + static char test_file_buf[PATHMAX]; + + /* set-up */ + _wunlink(L"test_dir/hi\xD801\x0037"); + rmdir("test_dir"); + + loop = uv_default_loop(); + + r = uv_fs_mkdir(NULL, &mkdir_req, "test_dir", 0777, NULL); + ASSERT_EQ(r, 0); + uv_fs_req_cleanup(&mkdir_req); + + file_handle = CreateFileW(L"test_dir/hi\xD801\x0037", + GENERIC_WRITE | FILE_WRITE_ATTRIBUTES, + 0, + NULL, + CREATE_ALWAYS, + FILE_FLAG_OPEN_REPARSE_POINT | + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + ASSERT(file_handle != INVALID_HANDLE_VALUE); + + CloseHandle(file_handle); + + r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL); + ASSERT_EQ(r, 1); + ASSERT_EQ(scandir_req.result, 1); + ASSERT_NOT_NULL(scandir_req.ptr); + while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) { + snprintf(test_file_buf, sizeof(test_file_buf), "test_dir\\%s", dent.name); + printf("stat %s\n", test_file_buf); + r = uv_fs_stat(NULL, &stat_req, test_file_buf, NULL); + ASSERT_EQ(r, 0); + } + uv_fs_req_cleanup(&scandir_req); + ASSERT_NULL(scandir_req.ptr); + + /* clean-up */ + _wunlink(L"test_dir/hi\xD801\x0037"); + rmdir("test_dir"); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} +#endif diff --git a/test/test-list.h b/test/test-list.h index 68c9c1171a7..6da7812360a 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -437,6 +437,7 @@ TEST_DECLARE (fs_file_flag_no_buffering) TEST_DECLARE (fs_open_readonly_acl) TEST_DECLARE (fs_fchmod_archive_readonly) TEST_DECLARE (fs_invalid_mkdir_name) +TEST_DECLARE (fs_wtf) #endif TEST_DECLARE (fs_get_system_error) TEST_DECLARE (strscpy) @@ -1120,6 +1121,7 @@ TASK_LIST_START TEST_ENTRY (fs_open_readonly_acl) TEST_ENTRY (fs_fchmod_archive_readonly) TEST_ENTRY (fs_invalid_mkdir_name) + TEST_ENTRY (fs_wtf) #endif TEST_ENTRY (fs_get_system_error) TEST_ENTRY (get_osfhandle_valid_handle) From 1b01b786c0180d29f07dccbb98001a2b3148828a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 25 May 2023 00:04:30 +0200 Subject: [PATCH 382/713] unix,win: replace QUEUE with struct uv__queue (#4022) Recent versions of gcc have started emitting warnings about the liberal type casting inside the QUEUE macros. Although the warnings are false positives, let's use them as the impetus to switch to a type-safer and arguably cleaner approach. Fixes: https://github.com/libuv/libuv/issues/4019 --- include/uv.h | 10 +- include/uv/darwin.h | 6 +- include/uv/linux.h | 2 +- include/uv/threadpool.h | 2 +- include/uv/unix.h | 44 ++++----- include/uv/win.h | 4 +- src/queue.h | 154 ++++++++++++++----------------- src/threadpool.c | 72 +++++++-------- src/unix/aix.c | 14 +-- src/unix/async.c | 52 +++++------ src/unix/core.c | 53 +++++------ src/unix/fsevents.c | 84 ++++++++--------- src/unix/kqueue.c | 18 ++-- src/unix/linux.c | 76 +++++++-------- src/unix/loop-watcher.c | 20 ++-- src/unix/loop.c | 28 +++--- src/unix/os390-syscalls.c | 24 ++--- src/unix/os390-syscalls.h | 2 +- src/unix/os390.c | 14 +-- src/unix/pipe.c | 2 +- src/unix/posix-poll.c | 14 +-- src/unix/process.c | 38 ++++---- src/unix/signal.c | 8 +- src/unix/stream.c | 56 +++++------ src/unix/sunos.c | 18 ++-- src/unix/tcp.c | 4 +- src/unix/tty.c | 2 +- src/unix/udp.c | 76 +++++++-------- src/uv-common.c | 28 +++--- src/uv-common.h | 2 +- src/win/core.c | 6 +- src/win/handle-inl.h | 2 +- src/win/pipe.c | 26 +++--- src/win/tcp.c | 4 +- src/win/udp.c | 4 +- test/test-queue-foreach-delete.c | 5 +- 36 files changed, 482 insertions(+), 492 deletions(-) diff --git a/include/uv.h b/include/uv.h index f3d70231ffa..a68a42f1394 100644 --- a/include/uv.h +++ b/include/uv.h @@ -59,6 +59,12 @@ extern "C" { #include #include +/* Internal type, do not use. */ +struct uv__queue { + struct uv__queue* next; + struct uv__queue* prev; +}; + #if defined(_WIN32) # include "uv/win.h" #else @@ -459,7 +465,7 @@ struct uv_shutdown_s { uv_handle_type type; \ /* private */ \ uv_close_cb close_cb; \ - void* handle_queue[2]; \ + struct uv__queue handle_queue; \ union { \ int fd; \ void* reserved[4]; \ @@ -1849,7 +1855,7 @@ struct uv_loop_s { void* data; /* Loop reference counting. */ unsigned int active_handles; - void* handle_queue[2]; + struct uv__queue handle_queue; union { void* unused; unsigned int count; diff --git a/include/uv/darwin.h b/include/uv/darwin.h index d226415820b..06962bfda80 100644 --- a/include/uv/darwin.h +++ b/include/uv/darwin.h @@ -40,7 +40,7 @@ void* cf_state; \ uv_mutex_t cf_mutex; \ uv_sem_t cf_sem; \ - void* cf_signals[2]; \ + struct uv__queue cf_signals; \ #define UV_PLATFORM_FS_EVENT_FIELDS \ uv__io_t event_watcher; \ @@ -48,8 +48,8 @@ int realpath_len; \ int cf_flags; \ uv_async_t* cf_cb; \ - void* cf_events[2]; \ - void* cf_member[2]; \ + struct uv__queue cf_events; \ + struct uv__queue cf_member; \ int cf_error; \ uv_mutex_t cf_mutex; \ diff --git a/include/uv/linux.h b/include/uv/linux.h index 9b38405a190..9f22f8cf726 100644 --- a/include/uv/linux.h +++ b/include/uv/linux.h @@ -28,7 +28,7 @@ int inotify_fd; \ #define UV_PLATFORM_FS_EVENT_FIELDS \ - void* watchers[2]; \ + struct uv__queue watchers; \ int wd; \ #endif /* UV_LINUX_H */ diff --git a/include/uv/threadpool.h b/include/uv/threadpool.h index 9708ebdd530..24ce916fda4 100644 --- a/include/uv/threadpool.h +++ b/include/uv/threadpool.h @@ -31,7 +31,7 @@ struct uv__work { void (*work)(struct uv__work *w); void (*done)(struct uv__work *w, int status); struct uv_loop_s* loop; - void* wq[2]; + struct uv__queue wq; }; #endif /* UV_THREADPOOL_H_ */ diff --git a/include/uv/unix.h b/include/uv/unix.h index 0b1fdac2b25..d1a5f0438a5 100644 --- a/include/uv/unix.h +++ b/include/uv/unix.h @@ -92,8 +92,8 @@ typedef struct uv__io_s uv__io_t; struct uv__io_s { uv__io_cb cb; - void* pending_queue[2]; - void* watcher_queue[2]; + struct uv__queue pending_queue; + struct uv__queue watcher_queue; unsigned int pevents; /* Pending event mask i.e. mask at next tick. */ unsigned int events; /* Current event mask. */ int fd; @@ -220,21 +220,21 @@ typedef struct { #define UV_LOOP_PRIVATE_FIELDS \ unsigned long flags; \ int backend_fd; \ - void* pending_queue[2]; \ - void* watcher_queue[2]; \ + struct uv__queue pending_queue; \ + struct uv__queue watcher_queue; \ uv__io_t** watchers; \ unsigned int nwatchers; \ unsigned int nfds; \ - void* wq[2]; \ + struct uv__queue wq; \ uv_mutex_t wq_mutex; \ uv_async_t wq_async; \ uv_rwlock_t cloexec_lock; \ uv_handle_t* closing_handles; \ - void* process_handles[2]; \ - void* prepare_handles[2]; \ - void* check_handles[2]; \ - void* idle_handles[2]; \ - void* async_handles[2]; \ + struct uv__queue process_handles; \ + struct uv__queue prepare_handles; \ + struct uv__queue check_handles; \ + struct uv__queue idle_handles; \ + struct uv__queue async_handles; \ void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \ uv__io_t async_io_watcher; \ int async_wfd; \ @@ -257,7 +257,7 @@ typedef struct { #define UV_PRIVATE_REQ_TYPES /* empty */ #define UV_WRITE_PRIVATE_FIELDS \ - void* queue[2]; \ + struct uv__queue queue; \ unsigned int write_index; \ uv_buf_t* bufs; \ unsigned int nbufs; \ @@ -265,12 +265,12 @@ typedef struct { uv_buf_t bufsml[4]; \ #define UV_CONNECT_PRIVATE_FIELDS \ - void* queue[2]; \ + struct uv__queue queue; \ #define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */ #define UV_UDP_SEND_PRIVATE_FIELDS \ - void* queue[2]; \ + struct uv__queue queue; \ struct sockaddr_storage addr; \ unsigned int nbufs; \ uv_buf_t* bufs; \ @@ -286,8 +286,8 @@ typedef struct { uv_connect_t *connect_req; \ uv_shutdown_t *shutdown_req; \ uv__io_t io_watcher; \ - void* write_queue[2]; \ - void* write_completed_queue[2]; \ + struct uv__queue write_queue; \ + struct uv__queue write_completed_queue; \ uv_connection_cb connection_cb; \ int delayed_error; \ int accepted_fd; \ @@ -300,8 +300,8 @@ typedef struct { uv_alloc_cb alloc_cb; \ uv_udp_recv_cb recv_cb; \ uv__io_t io_watcher; \ - void* write_queue[2]; \ - void* write_completed_queue[2]; \ + struct uv__queue write_queue; \ + struct uv__queue write_completed_queue; \ #define UV_PIPE_PRIVATE_FIELDS \ const char* pipe_fname; /* strdup'ed */ @@ -311,19 +311,19 @@ typedef struct { #define UV_PREPARE_PRIVATE_FIELDS \ uv_prepare_cb prepare_cb; \ - void* queue[2]; \ + struct uv__queue queue; \ #define UV_CHECK_PRIVATE_FIELDS \ uv_check_cb check_cb; \ - void* queue[2]; \ + struct uv__queue queue; \ #define UV_IDLE_PRIVATE_FIELDS \ uv_idle_cb idle_cb; \ - void* queue[2]; \ + struct uv__queue queue; \ #define UV_ASYNC_PRIVATE_FIELDS \ uv_async_cb async_cb; \ - void* queue[2]; \ + struct uv__queue queue; \ int pending; \ #define UV_TIMER_PRIVATE_FIELDS \ @@ -352,7 +352,7 @@ typedef struct { int retcode; #define UV_PROCESS_PRIVATE_FIELDS \ - void* queue[2]; \ + struct uv__queue queue; \ int status; \ #define UV_FS_PRIVATE_FIELDS \ diff --git a/include/uv/win.h b/include/uv/win.h index 92a95fa15f1..6f8c47298e4 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -357,7 +357,7 @@ typedef struct { /* Counter to started timer */ \ uint64_t timer_counter; \ /* Threadpool */ \ - void* wq[2]; \ + struct uv__queue wq; \ uv_mutex_t wq_mutex; \ uv_async_t wq_async; @@ -486,7 +486,7 @@ typedef struct { uint32_t payload_remaining; \ uint64_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \ } ipc_data_frame; \ - void* ipc_xfer_queue[2]; \ + struct uv__queue ipc_xfer_queue; \ int ipc_xfer_queue_length; \ uv_write_t* non_overlapped_writes_tail; \ CRITICAL_SECTION readfile_thread_lock; \ diff --git a/src/queue.h b/src/queue.h index ff3540a0a51..5f8489e9bc5 100644 --- a/src/queue.h +++ b/src/queue.h @@ -18,91 +18,73 @@ #include -typedef void *QUEUE[2]; - -/* Private macros. */ -#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0])) -#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1])) -#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q))) -#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q))) - -/* Public macros. */ -#define QUEUE_DATA(ptr, type, field) \ - ((type *) ((char *) (ptr) - offsetof(type, field))) - -/* Important note: mutating the list while QUEUE_FOREACH is - * iterating over its elements results in undefined behavior. - */ -#define QUEUE_FOREACH(q, h) \ - for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q)) - -#define QUEUE_EMPTY(q) \ - ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q)) - -#define QUEUE_HEAD(q) \ - (QUEUE_NEXT(q)) - -#define QUEUE_INIT(q) \ - do { \ - QUEUE_NEXT(q) = (q); \ - QUEUE_PREV(q) = (q); \ - } \ - while (0) - -#define QUEUE_ADD(h, n) \ - do { \ - QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \ - QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \ - QUEUE_PREV(h) = QUEUE_PREV(n); \ - QUEUE_PREV_NEXT(h) = (h); \ - } \ - while (0) - -#define QUEUE_SPLIT(h, q, n) \ - do { \ - QUEUE_PREV(n) = QUEUE_PREV(h); \ - QUEUE_PREV_NEXT(n) = (n); \ - QUEUE_NEXT(n) = (q); \ - QUEUE_PREV(h) = QUEUE_PREV(q); \ - QUEUE_PREV_NEXT(h) = (h); \ - QUEUE_PREV(q) = (n); \ - } \ - while (0) - -#define QUEUE_MOVE(h, n) \ - do { \ - if (QUEUE_EMPTY(h)) \ - QUEUE_INIT(n); \ - else { \ - QUEUE* q = QUEUE_HEAD(h); \ - QUEUE_SPLIT(h, q, n); \ - } \ - } \ - while (0) - -#define QUEUE_INSERT_HEAD(h, q) \ - do { \ - QUEUE_NEXT(q) = QUEUE_NEXT(h); \ - QUEUE_PREV(q) = (h); \ - QUEUE_NEXT_PREV(q) = (q); \ - QUEUE_NEXT(h) = (q); \ - } \ - while (0) - -#define QUEUE_INSERT_TAIL(h, q) \ - do { \ - QUEUE_NEXT(q) = (h); \ - QUEUE_PREV(q) = QUEUE_PREV(h); \ - QUEUE_PREV_NEXT(q) = (q); \ - QUEUE_PREV(h) = (q); \ - } \ - while (0) - -#define QUEUE_REMOVE(q) \ - do { \ - QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \ - QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \ - } \ - while (0) +#define uv__queue_data(pointer, type, field) \ + ((type*) ((char*) (pointer) - offsetof(type, field))) + +#define uv__queue_foreach(q, h) \ + for ((q) = (h)->next; (q) != (h); (q) = (q)->next) + +static inline void uv__queue_init(struct uv__queue* q) { + q->next = q; + q->prev = q; +} + +static inline int uv__queue_empty(const struct uv__queue* q) { + return q == q->next; +} + +static inline struct uv__queue* uv__queue_head(const struct uv__queue* q) { + return q->next; +} + +static inline struct uv__queue* uv__queue_next(const struct uv__queue* q) { + return q->next; +} + +static inline void uv__queue_add(struct uv__queue* h, struct uv__queue* n) { + h->prev->next = n->next; + n->next->prev = h->prev; + h->prev = n->prev; + h->prev->next = h; +} + +static inline void uv__queue_split(struct uv__queue* h, + struct uv__queue* q, + struct uv__queue* n) { + n->prev = h->prev; + n->prev->next = n; + n->next = q; + h->prev = q->prev; + h->prev->next = h; + q->prev = n; +} + +static inline void uv__queue_move(struct uv__queue* h, struct uv__queue* n) { + if (uv__queue_empty(h)) + uv__queue_init(n); + else + uv__queue_split(h, h->next, n); +} + +static inline void uv__queue_insert_head(struct uv__queue* h, + struct uv__queue* q) { + q->next = h->next; + q->prev = h; + q->next->prev = q; + h->next = q; +} + +static inline void uv__queue_insert_tail(struct uv__queue* h, + struct uv__queue* q) { + q->next = h; + q->prev = h->prev; + q->prev->next = q; + h->prev = q; +} + +static inline void uv__queue_remove(struct uv__queue* q) { + q->prev->next = q->next; + q->next->prev = q->prev; +} #endif /* QUEUE_H_ */ diff --git a/src/threadpool.c b/src/threadpool.c index 51962bf0021..dbef67f2f10 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -37,10 +37,10 @@ static unsigned int slow_io_work_running; static unsigned int nthreads; static uv_thread_t* threads; static uv_thread_t default_threads[4]; -static QUEUE exit_message; -static QUEUE wq; -static QUEUE run_slow_work_message; -static QUEUE slow_io_pending_wq; +static struct uv__queue exit_message; +static struct uv__queue wq; +static struct uv__queue run_slow_work_message; +static struct uv__queue slow_io_pending_wq; static unsigned int slow_work_thread_threshold(void) { return (nthreads + 1) / 2; @@ -56,7 +56,7 @@ static void uv__cancelled(struct uv__work* w) { */ static void worker(void* arg) { struct uv__work* w; - QUEUE* q; + struct uv__queue* q; int is_slow_work; uv_sem_post((uv_sem_t*) arg); @@ -68,49 +68,49 @@ static void worker(void* arg) { /* Keep waiting while either no work is present or only slow I/O and we're at the threshold for that. */ - while (QUEUE_EMPTY(&wq) || - (QUEUE_HEAD(&wq) == &run_slow_work_message && - QUEUE_NEXT(&run_slow_work_message) == &wq && + while (uv__queue_empty(&wq) || + (uv__queue_head(&wq) == &run_slow_work_message && + uv__queue_next(&run_slow_work_message) == &wq && slow_io_work_running >= slow_work_thread_threshold())) { idle_threads += 1; uv_cond_wait(&cond, &mutex); idle_threads -= 1; } - q = QUEUE_HEAD(&wq); + q = uv__queue_head(&wq); if (q == &exit_message) { uv_cond_signal(&cond); uv_mutex_unlock(&mutex); break; } - QUEUE_REMOVE(q); - QUEUE_INIT(q); /* Signal uv_cancel() that the work req is executing. */ + uv__queue_remove(q); + uv__queue_init(q); /* Signal uv_cancel() that the work req is executing. */ is_slow_work = 0; if (q == &run_slow_work_message) { /* If we're at the slow I/O threshold, re-schedule until after all other work in the queue is done. */ if (slow_io_work_running >= slow_work_thread_threshold()) { - QUEUE_INSERT_TAIL(&wq, q); + uv__queue_insert_tail(&wq, q); continue; } /* If we encountered a request to run slow I/O work but there is none to run, that means it's cancelled => Start over. */ - if (QUEUE_EMPTY(&slow_io_pending_wq)) + if (uv__queue_empty(&slow_io_pending_wq)) continue; is_slow_work = 1; slow_io_work_running++; - q = QUEUE_HEAD(&slow_io_pending_wq); - QUEUE_REMOVE(q); - QUEUE_INIT(q); + q = uv__queue_head(&slow_io_pending_wq); + uv__queue_remove(q); + uv__queue_init(q); /* If there is more slow I/O work, schedule it to be run as well. */ - if (!QUEUE_EMPTY(&slow_io_pending_wq)) { - QUEUE_INSERT_TAIL(&wq, &run_slow_work_message); + if (!uv__queue_empty(&slow_io_pending_wq)) { + uv__queue_insert_tail(&wq, &run_slow_work_message); if (idle_threads > 0) uv_cond_signal(&cond); } @@ -118,13 +118,13 @@ static void worker(void* arg) { uv_mutex_unlock(&mutex); - w = QUEUE_DATA(q, struct uv__work, wq); + w = uv__queue_data(q, struct uv__work, wq); w->work(w); uv_mutex_lock(&w->loop->wq_mutex); w->work = NULL; /* Signal uv_cancel() that the work req is done executing. */ - QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq); + uv__queue_insert_tail(&w->loop->wq, &w->wq); uv_async_send(&w->loop->wq_async); uv_mutex_unlock(&w->loop->wq_mutex); @@ -139,12 +139,12 @@ static void worker(void* arg) { } -static void post(QUEUE* q, enum uv__work_kind kind) { +static void post(struct uv__queue* q, enum uv__work_kind kind) { uv_mutex_lock(&mutex); if (kind == UV__WORK_SLOW_IO) { /* Insert into a separate queue. */ - QUEUE_INSERT_TAIL(&slow_io_pending_wq, q); - if (!QUEUE_EMPTY(&run_slow_work_message)) { + uv__queue_insert_tail(&slow_io_pending_wq, q); + if (!uv__queue_empty(&run_slow_work_message)) { /* Running slow I/O tasks is already scheduled => Nothing to do here. The worker that runs said other task will schedule this one as well. */ uv_mutex_unlock(&mutex); @@ -153,7 +153,7 @@ static void post(QUEUE* q, enum uv__work_kind kind) { q = &run_slow_work_message; } - QUEUE_INSERT_TAIL(&wq, q); + uv__queue_insert_tail(&wq, q); if (idle_threads > 0) uv_cond_signal(&cond); uv_mutex_unlock(&mutex); @@ -220,9 +220,9 @@ static void init_threads(void) { if (uv_mutex_init(&mutex)) abort(); - QUEUE_INIT(&wq); - QUEUE_INIT(&slow_io_pending_wq); - QUEUE_INIT(&run_slow_work_message); + uv__queue_init(&wq); + uv__queue_init(&slow_io_pending_wq); + uv__queue_init(&run_slow_work_message); if (uv_sem_init(&sem, 0)) abort(); @@ -285,9 +285,9 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) { uv_mutex_lock(&mutex); uv_mutex_lock(&w->loop->wq_mutex); - cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL; + cancelled = !uv__queue_empty(&w->wq) && w->work != NULL; if (cancelled) - QUEUE_REMOVE(&w->wq); + uv__queue_remove(&w->wq); uv_mutex_unlock(&w->loop->wq_mutex); uv_mutex_unlock(&mutex); @@ -297,7 +297,7 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) { w->work = uv__cancelled; uv_mutex_lock(&loop->wq_mutex); - QUEUE_INSERT_TAIL(&loop->wq, &w->wq); + uv__queue_insert_tail(&loop->wq, &w->wq); uv_async_send(&loop->wq_async); uv_mutex_unlock(&loop->wq_mutex); @@ -308,21 +308,21 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) { void uv__work_done(uv_async_t* handle) { struct uv__work* w; uv_loop_t* loop; - QUEUE* q; - QUEUE wq; + struct uv__queue* q; + struct uv__queue wq; int err; int nevents; loop = container_of(handle, uv_loop_t, wq_async); uv_mutex_lock(&loop->wq_mutex); - QUEUE_MOVE(&loop->wq, &wq); + uv__queue_move(&loop->wq, &wq); uv_mutex_unlock(&loop->wq_mutex); nevents = 0; - while (!QUEUE_EMPTY(&wq)) { - q = QUEUE_HEAD(&wq); - QUEUE_REMOVE(q); + while (!uv__queue_empty(&wq)) { + q = uv__queue_head(&wq); + uv__queue_remove(q); w = container_of(q, struct uv__work, wq); err = (w->work == uv__cancelled) ? UV_ECANCELED : 0; diff --git a/src/unix/aix.c b/src/unix/aix.c index f1afbed49ec..3af3009a216 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -136,7 +136,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { struct pollfd pqry; struct pollfd* pe; struct poll_ctl pc; - QUEUE* q; + struct uv__queue* q; uv__io_t* w; uint64_t base; uint64_t diff; @@ -151,18 +151,18 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { int reset_timeout; if (loop->nfds == 0) { - assert(QUEUE_EMPTY(&loop->watcher_queue)); + assert(uv__queue_empty(&loop->watcher_queue)); return; } lfields = uv__get_internal_fields(loop); - while (!QUEUE_EMPTY(&loop->watcher_queue)) { - q = QUEUE_HEAD(&loop->watcher_queue); - QUEUE_REMOVE(q); - QUEUE_INIT(q); + while (!uv__queue_empty(&loop->watcher_queue)) { + q = uv__queue_head(&loop->watcher_queue); + uv__queue_remove(q); + uv__queue_init(q); - w = QUEUE_DATA(q, uv__io_t, watcher_queue); + w = uv__queue_data(q, uv__io_t, watcher_queue); assert(w->pevents != 0); assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); diff --git a/src/unix/async.c b/src/unix/async.c index 5751b6d02be..0ff2669e30a 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -55,7 +55,7 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { handle->pending = 0; handle->u.fd = 0; /* This will be used as a busy flag. */ - QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue); + uv__queue_insert_tail(&loop->async_handles, &handle->queue); uv__handle_start(handle); return 0; @@ -124,7 +124,7 @@ static void uv__async_spin(uv_async_t* handle) { void uv__async_close(uv_async_t* handle) { uv__async_spin(handle); - QUEUE_REMOVE(&handle->queue); + uv__queue_remove(&handle->queue); uv__handle_stop(handle); } @@ -132,8 +132,8 @@ void uv__async_close(uv_async_t* handle) { static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { char buf[1024]; ssize_t r; - QUEUE queue; - QUEUE* q; + struct uv__queue queue; + struct uv__queue* q; uv_async_t* h; _Atomic int *pending; @@ -157,13 +157,13 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { abort(); } - QUEUE_MOVE(&loop->async_handles, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - h = QUEUE_DATA(q, uv_async_t, queue); + uv__queue_move(&loop->async_handles, &queue); + while (!uv__queue_empty(&queue)) { + q = uv__queue_head(&queue); + h = uv__queue_data(q, uv_async_t, queue); - QUEUE_REMOVE(q); - QUEUE_INSERT_TAIL(&loop->async_handles, q); + uv__queue_remove(q); + uv__queue_insert_tail(&loop->async_handles, q); /* Atomically fetch and clear pending flag */ pending = (_Atomic int*) &h->pending; @@ -241,8 +241,8 @@ static int uv__async_start(uv_loop_t* loop) { void uv__async_stop(uv_loop_t* loop) { - QUEUE queue; - QUEUE* q; + struct uv__queue queue; + struct uv__queue* q; uv_async_t* h; if (loop->async_io_watcher.fd == -1) @@ -251,13 +251,13 @@ void uv__async_stop(uv_loop_t* loop) { /* Make sure no other thread is accessing the async handle fd after the loop * cleanup. */ - QUEUE_MOVE(&loop->async_handles, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - h = QUEUE_DATA(q, uv_async_t, queue); + uv__queue_move(&loop->async_handles, &queue); + while (!uv__queue_empty(&queue)) { + q = uv__queue_head(&queue); + h = uv__queue_data(q, uv_async_t, queue); - QUEUE_REMOVE(q); - QUEUE_INSERT_TAIL(&loop->async_handles, q); + uv__queue_remove(q); + uv__queue_insert_tail(&loop->async_handles, q); uv__async_spin(h); } @@ -275,20 +275,20 @@ void uv__async_stop(uv_loop_t* loop) { int uv__async_fork(uv_loop_t* loop) { - QUEUE queue; - QUEUE* q; + struct uv__queue queue; + struct uv__queue* q; uv_async_t* h; if (loop->async_io_watcher.fd == -1) /* never started */ return 0; - QUEUE_MOVE(&loop->async_handles, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - h = QUEUE_DATA(q, uv_async_t, queue); + uv__queue_move(&loop->async_handles, &queue); + while (!uv__queue_empty(&queue)) { + q = uv__queue_head(&queue); + h = uv__queue_data(q, uv_async_t, queue); - QUEUE_REMOVE(q); - QUEUE_INSERT_TAIL(&loop->async_handles, q); + uv__queue_remove(q); + uv__queue_insert_tail(&loop->async_handles, q); /* The state of any thread that set pending is now likely corrupt in this * child because the user called fork, so just clear these flags and move diff --git a/src/unix/core.c b/src/unix/core.c index 9c0b3f99b80..2f8395f2bdb 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -344,7 +344,7 @@ static void uv__finish_close(uv_handle_t* handle) { } uv__handle_unref(handle); - QUEUE_REMOVE(&handle->handle_queue); + uv__queue_remove(&handle->handle_queue); if (handle->close_cb) { handle->close_cb(handle); @@ -380,7 +380,7 @@ int uv_backend_fd(const uv_loop_t* loop) { static int uv__loop_alive(const uv_loop_t* loop) { return uv__has_active_handles(loop) || uv__has_active_reqs(loop) || - !QUEUE_EMPTY(&loop->pending_queue) || + !uv__queue_empty(&loop->pending_queue) || loop->closing_handles != NULL; } @@ -389,8 +389,8 @@ static int uv__backend_timeout(const uv_loop_t* loop) { if (loop->stop_flag == 0 && /* uv__loop_alive(loop) && */ (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) && - QUEUE_EMPTY(&loop->pending_queue) && - QUEUE_EMPTY(&loop->idle_handles) && + uv__queue_empty(&loop->pending_queue) && + uv__queue_empty(&loop->idle_handles) && (loop->flags & UV_LOOP_REAP_CHILDREN) == 0 && loop->closing_handles == NULL) return uv__next_timeout(loop); @@ -399,7 +399,7 @@ static int uv__backend_timeout(const uv_loop_t* loop) { int uv_backend_timeout(const uv_loop_t* loop) { - if (QUEUE_EMPTY(&loop->watcher_queue)) + if (uv__queue_empty(&loop->watcher_queue)) return uv__backend_timeout(loop); /* Need to call uv_run to update the backend fd state. */ return 0; @@ -432,7 +432,8 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { while (r != 0 && loop->stop_flag == 0) { can_sleep = - QUEUE_EMPTY(&loop->pending_queue) && QUEUE_EMPTY(&loop->idle_handles); + uv__queue_empty(&loop->pending_queue) && + uv__queue_empty(&loop->idle_handles); uv__run_pending(loop); uv__run_idle(loop); @@ -448,7 +449,7 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { /* Process immediate callbacks (e.g. write_cb) a small fixed number of * times to avoid loop starvation.*/ - for (r = 0; r < 8 && !QUEUE_EMPTY(&loop->pending_queue); r++) + for (r = 0; r < 8 && !uv__queue_empty(&loop->pending_queue); r++) uv__run_pending(loop); /* Run one final update on the provider_idle_time in case uv__io_poll @@ -827,17 +828,17 @@ int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) { static void uv__run_pending(uv_loop_t* loop) { - QUEUE* q; - QUEUE pq; + struct uv__queue* q; + struct uv__queue pq; uv__io_t* w; - QUEUE_MOVE(&loop->pending_queue, &pq); + uv__queue_move(&loop->pending_queue, &pq); - while (!QUEUE_EMPTY(&pq)) { - q = QUEUE_HEAD(&pq); - QUEUE_REMOVE(q); - QUEUE_INIT(q); - w = QUEUE_DATA(q, uv__io_t, pending_queue); + while (!uv__queue_empty(&pq)) { + q = uv__queue_head(&pq); + uv__queue_remove(q); + uv__queue_init(q); + w = uv__queue_data(q, uv__io_t, pending_queue); w->cb(loop, w, POLLOUT); } } @@ -892,8 +893,8 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { assert(cb != NULL); assert(fd >= -1); - QUEUE_INIT(&w->pending_queue); - QUEUE_INIT(&w->watcher_queue); + uv__queue_init(&w->pending_queue); + uv__queue_init(&w->watcher_queue); w->cb = cb; w->fd = fd; w->events = 0; @@ -919,8 +920,8 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { return; #endif - if (QUEUE_EMPTY(&w->watcher_queue)) - QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + if (uv__queue_empty(&w->watcher_queue)) + uv__queue_insert_tail(&loop->watcher_queue, &w->watcher_queue); if (loop->watchers[w->fd] == NULL) { loop->watchers[w->fd] = w; @@ -945,8 +946,8 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { w->pevents &= ~events; if (w->pevents == 0) { - QUEUE_REMOVE(&w->watcher_queue); - QUEUE_INIT(&w->watcher_queue); + uv__queue_remove(&w->watcher_queue); + uv__queue_init(&w->watcher_queue); w->events = 0; if (w == loop->watchers[w->fd]) { @@ -955,14 +956,14 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { loop->nfds--; } } - else if (QUEUE_EMPTY(&w->watcher_queue)) - QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + else if (uv__queue_empty(&w->watcher_queue)) + uv__queue_insert_tail(&loop->watcher_queue, &w->watcher_queue); } void uv__io_close(uv_loop_t* loop, uv__io_t* w) { uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); - QUEUE_REMOVE(&w->pending_queue); + uv__queue_remove(&w->pending_queue); /* Remove stale events for this file descriptor */ if (w->fd != -1) @@ -971,8 +972,8 @@ void uv__io_close(uv_loop_t* loop, uv__io_t* w) { void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { - if (QUEUE_EMPTY(&w->pending_queue)) - QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue); + if (uv__queue_empty(&w->pending_queue)) + uv__queue_insert_tail(&loop->pending_queue, &w->pending_queue); } diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c index 0535b4547aa..df703f3635f 100644 --- a/src/unix/fsevents.c +++ b/src/unix/fsevents.c @@ -80,13 +80,13 @@ enum uv__cf_loop_signal_type_e { typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t; struct uv__cf_loop_signal_s { - QUEUE member; + struct uv__queue member; uv_fs_event_t* handle; uv__cf_loop_signal_type_t type; }; struct uv__fsevents_event_s { - QUEUE member; + struct uv__queue member; int events; char path[1]; }; @@ -98,7 +98,7 @@ struct uv__cf_loop_state_s { FSEventStreamRef fsevent_stream; uv_sem_t fsevent_sem; uv_mutex_t fsevent_mutex; - void* fsevent_handles[2]; + struct uv__queue fsevent_handles; unsigned int fsevent_handle_count; }; @@ -150,22 +150,22 @@ static void (*pFSEventStreamStop)(FSEventStreamRef); #define UV__FSEVENTS_PROCESS(handle, block) \ do { \ - QUEUE events; \ - QUEUE* q; \ + struct uv__queue events; \ + struct uv__queue* q; \ uv__fsevents_event_t* event; \ int err; \ uv_mutex_lock(&(handle)->cf_mutex); \ /* Split-off all events and empty original queue */ \ - QUEUE_MOVE(&(handle)->cf_events, &events); \ + uv__queue_move(&(handle)->cf_events, &events); \ /* Get error (if any) and zero original one */ \ err = (handle)->cf_error; \ (handle)->cf_error = 0; \ uv_mutex_unlock(&(handle)->cf_mutex); \ /* Loop through events, deallocating each after processing */ \ - while (!QUEUE_EMPTY(&events)) { \ - q = QUEUE_HEAD(&events); \ - event = QUEUE_DATA(q, uv__fsevents_event_t, member); \ - QUEUE_REMOVE(q); \ + while (!uv__queue_empty(&events)) { \ + q = uv__queue_head(&events); \ + event = uv__queue_data(q, uv__fsevents_event_t, member); \ + uv__queue_remove(q); \ /* NOTE: Checking uv__is_active() is required here, because handle \ * callback may close handle and invoking it after it will lead to \ * incorrect behaviour */ \ @@ -193,14 +193,14 @@ static void uv__fsevents_cb(uv_async_t* cb) { /* Runs in CF thread, pushed event into handle's event list */ static void uv__fsevents_push_event(uv_fs_event_t* handle, - QUEUE* events, + struct uv__queue* events, int err) { assert(events != NULL || err != 0); uv_mutex_lock(&handle->cf_mutex); /* Concatenate two queues */ if (events != NULL) - QUEUE_ADD(&handle->cf_events, events); + uv__queue_add(&handle->cf_events, events); /* Propagate error */ if (err != 0) @@ -224,12 +224,12 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef, char* path; char* pos; uv_fs_event_t* handle; - QUEUE* q; + struct uv__queue* q; uv_loop_t* loop; uv__cf_loop_state_t* state; uv__fsevents_event_t* event; FSEventStreamEventFlags flags; - QUEUE head; + struct uv__queue head; loop = info; state = loop->cf_state; @@ -238,9 +238,9 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef, /* For each handle */ uv_mutex_lock(&state->fsevent_mutex); - QUEUE_FOREACH(q, &state->fsevent_handles) { - handle = QUEUE_DATA(q, uv_fs_event_t, cf_member); - QUEUE_INIT(&head); + uv__queue_foreach(q, &state->fsevent_handles) { + handle = uv__queue_data(q, uv_fs_event_t, cf_member); + uv__queue_init(&head); /* Process and filter out events */ for (i = 0; i < numEvents; i++) { @@ -318,10 +318,10 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef, event->events = UV_CHANGE; } - QUEUE_INSERT_TAIL(&head, &event->member); + uv__queue_insert_tail(&head, &event->member); } - if (!QUEUE_EMPTY(&head)) + if (!uv__queue_empty(&head)) uv__fsevents_push_event(handle, &head, 0); } uv_mutex_unlock(&state->fsevent_mutex); @@ -403,7 +403,7 @@ static void uv__fsevents_destroy_stream(uv__cf_loop_state_t* state) { static void uv__fsevents_reschedule(uv__cf_loop_state_t* state, uv_loop_t* loop, uv__cf_loop_signal_type_t type) { - QUEUE* q; + struct uv__queue* q; uv_fs_event_t* curr; CFArrayRef cf_paths; CFStringRef* paths; @@ -446,9 +446,9 @@ static void uv__fsevents_reschedule(uv__cf_loop_state_t* state, q = &state->fsevent_handles; for (; i < path_count; i++) { - q = QUEUE_NEXT(q); + q = uv__queue_next(q); assert(q != &state->fsevent_handles); - curr = QUEUE_DATA(q, uv_fs_event_t, cf_member); + curr = uv__queue_data(q, uv_fs_event_t, cf_member); assert(curr->realpath != NULL); paths[i] = @@ -486,8 +486,8 @@ static void uv__fsevents_reschedule(uv__cf_loop_state_t* state, /* Broadcast error to all handles */ uv_mutex_lock(&state->fsevent_mutex); - QUEUE_FOREACH(q, &state->fsevent_handles) { - curr = QUEUE_DATA(q, uv_fs_event_t, cf_member); + uv__queue_foreach(q, &state->fsevent_handles) { + curr = uv__queue_data(q, uv_fs_event_t, cf_member); uv__fsevents_push_event(curr, NULL, err); } uv_mutex_unlock(&state->fsevent_mutex); @@ -606,7 +606,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) { if (err) goto fail_sem_init; - QUEUE_INIT(&loop->cf_signals); + uv__queue_init(&loop->cf_signals); err = uv_sem_init(&state->fsevent_sem, 0); if (err) @@ -616,7 +616,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) { if (err) goto fail_fsevent_mutex_init; - QUEUE_INIT(&state->fsevent_handles); + uv__queue_init(&state->fsevent_handles); state->fsevent_need_reschedule = 0; state->fsevent_handle_count = 0; @@ -675,7 +675,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) { void uv__fsevents_loop_delete(uv_loop_t* loop) { uv__cf_loop_signal_t* s; uv__cf_loop_state_t* state; - QUEUE* q; + struct uv__queue* q; if (loop->cf_state == NULL) return; @@ -688,10 +688,10 @@ void uv__fsevents_loop_delete(uv_loop_t* loop) { uv_mutex_destroy(&loop->cf_mutex); /* Free any remaining data */ - while (!QUEUE_EMPTY(&loop->cf_signals)) { - q = QUEUE_HEAD(&loop->cf_signals); - s = QUEUE_DATA(q, uv__cf_loop_signal_t, member); - QUEUE_REMOVE(q); + while (!uv__queue_empty(&loop->cf_signals)) { + q = uv__queue_head(&loop->cf_signals); + s = uv__queue_data(q, uv__cf_loop_signal_t, member); + uv__queue_remove(q); uv__free(s); } @@ -735,22 +735,22 @@ static void* uv__cf_loop_runner(void* arg) { static void uv__cf_loop_cb(void* arg) { uv_loop_t* loop; uv__cf_loop_state_t* state; - QUEUE* item; - QUEUE split_head; + struct uv__queue* item; + struct uv__queue split_head; uv__cf_loop_signal_t* s; loop = arg; state = loop->cf_state; uv_mutex_lock(&loop->cf_mutex); - QUEUE_MOVE(&loop->cf_signals, &split_head); + uv__queue_move(&loop->cf_signals, &split_head); uv_mutex_unlock(&loop->cf_mutex); - while (!QUEUE_EMPTY(&split_head)) { - item = QUEUE_HEAD(&split_head); - QUEUE_REMOVE(item); + while (!uv__queue_empty(&split_head)) { + item = uv__queue_head(&split_head); + uv__queue_remove(item); - s = QUEUE_DATA(item, uv__cf_loop_signal_t, member); + s = uv__queue_data(item, uv__cf_loop_signal_t, member); /* This was a termination signal */ if (s->handle == NULL) @@ -778,7 +778,7 @@ int uv__cf_loop_signal(uv_loop_t* loop, item->type = type; uv_mutex_lock(&loop->cf_mutex); - QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member); + uv__queue_insert_tail(&loop->cf_signals, &item->member); state = loop->cf_state; assert(state != NULL); @@ -807,7 +807,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) { handle->realpath_len = strlen(handle->realpath); /* Initialize event queue */ - QUEUE_INIT(&handle->cf_events); + uv__queue_init(&handle->cf_events); handle->cf_error = 0; /* @@ -832,7 +832,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) { /* Insert handle into the list */ state = handle->loop->cf_state; uv_mutex_lock(&state->fsevent_mutex); - QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member); + uv__queue_insert_tail(&state->fsevent_handles, &handle->cf_member); state->fsevent_handle_count++; state->fsevent_need_reschedule = 1; uv_mutex_unlock(&state->fsevent_mutex); @@ -872,7 +872,7 @@ int uv__fsevents_close(uv_fs_event_t* handle) { /* Remove handle from the list */ state = handle->loop->cf_state; uv_mutex_lock(&state->fsevent_mutex); - QUEUE_REMOVE(&handle->cf_member); + uv__queue_remove(&handle->cf_member); state->fsevent_handle_count--; state->fsevent_need_reschedule = 1; uv_mutex_unlock(&state->fsevent_mutex); diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 82916d65933..b78242d3be4 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -133,7 +133,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { struct timespec spec; unsigned int nevents; unsigned int revents; - QUEUE* q; + struct uv__queue* q; uv__io_t* w; uv_process_t* process; sigset_t* pset; @@ -152,19 +152,19 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { int reset_timeout; if (loop->nfds == 0) { - assert(QUEUE_EMPTY(&loop->watcher_queue)); + assert(uv__queue_empty(&loop->watcher_queue)); return; } lfields = uv__get_internal_fields(loop); nevents = 0; - while (!QUEUE_EMPTY(&loop->watcher_queue)) { - q = QUEUE_HEAD(&loop->watcher_queue); - QUEUE_REMOVE(q); - QUEUE_INIT(q); + while (!uv__queue_empty(&loop->watcher_queue)) { + q = uv__queue_head(&loop->watcher_queue); + uv__queue_remove(q); + uv__queue_init(q); - w = QUEUE_DATA(q, uv__io_t, watcher_queue); + w = uv__queue_data(q, uv__io_t, watcher_queue); assert(w->pevents != 0); assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); @@ -307,8 +307,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { /* Handle kevent NOTE_EXIT results */ if (ev->filter == EVFILT_PROC) { - QUEUE_FOREACH(q, &loop->process_handles) { - process = QUEUE_DATA(q, uv_process_t, queue); + uv__queue_foreach(q, &loop->process_handles) { + process = uv__queue_data(q, uv_process_t, queue); if (process->pid == fd) { process->flags |= UV_HANDLE_REAP; loop->flags |= UV_LOOP_REAP_CHILDREN; diff --git a/src/unix/linux.c b/src/unix/linux.c index 9432e8541da..183e781b2af 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -266,7 +266,7 @@ STATIC_ASSERT(EPOLL_CTL_MOD < 4); struct watcher_list { RB_ENTRY(watcher_list) entry; - QUEUE watchers; + struct uv__queue watchers; int iterating; char* path; int wd; @@ -701,7 +701,7 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, req->work_req.loop = loop; req->work_req.work = NULL; req->work_req.done = NULL; - QUEUE_INIT(&req->work_req.wq); + uv__queue_init(&req->work_req.wq); uv__req_register(loop, req); iou->in_flight++; @@ -1224,7 +1224,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { struct uv__iou* ctl; struct uv__iou* iou; int real_timeout; - QUEUE* q; + struct uv__queue* q; uv__io_t* w; sigset_t* sigmask; sigset_t sigset; @@ -1270,11 +1270,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { memset(&e, 0, sizeof(e)); - while (!QUEUE_EMPTY(&loop->watcher_queue)) { - q = QUEUE_HEAD(&loop->watcher_queue); - w = QUEUE_DATA(q, uv__io_t, watcher_queue); - QUEUE_REMOVE(q); - QUEUE_INIT(q); + while (!uv__queue_empty(&loop->watcher_queue)) { + q = uv__queue_head(&loop->watcher_queue); + w = uv__queue_data(q, uv__io_t, watcher_queue); + uv__queue_remove(q); + uv__queue_init(q); op = EPOLL_CTL_MOD; if (w->events == 0) @@ -2229,8 +2229,8 @@ static int uv__inotify_fork(uv_loop_t* loop, struct watcher_list* root) { struct watcher_list* tmp_watcher_list_iter; struct watcher_list* watcher_list; struct watcher_list tmp_watcher_list; - QUEUE queue; - QUEUE* q; + struct uv__queue queue; + struct uv__queue* q; uv_fs_event_t* handle; char* tmp_path; @@ -2242,41 +2242,41 @@ static int uv__inotify_fork(uv_loop_t* loop, struct watcher_list* root) { */ loop->inotify_watchers = root; - QUEUE_INIT(&tmp_watcher_list.watchers); + uv__queue_init(&tmp_watcher_list.watchers); /* Note that the queue we use is shared with the start and stop() - * functions, making QUEUE_FOREACH unsafe to use. So we use the - * QUEUE_MOVE trick to safely iterate. Also don't free the watcher + * functions, making uv__queue_foreach unsafe to use. So we use the + * uv__queue_move trick to safely iterate. Also don't free the watcher * list until we're done iterating. c.f. uv__inotify_read. */ RB_FOREACH_SAFE(watcher_list, watcher_root, uv__inotify_watchers(loop), tmp_watcher_list_iter) { watcher_list->iterating = 1; - QUEUE_MOVE(&watcher_list->watchers, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - handle = QUEUE_DATA(q, uv_fs_event_t, watchers); + uv__queue_move(&watcher_list->watchers, &queue); + while (!uv__queue_empty(&queue)) { + q = uv__queue_head(&queue); + handle = uv__queue_data(q, uv_fs_event_t, watchers); /* It's critical to keep a copy of path here, because it * will be set to NULL by stop() and then deallocated by * maybe_free_watcher_list */ tmp_path = uv__strdup(handle->path); assert(tmp_path != NULL); - QUEUE_REMOVE(q); - QUEUE_INSERT_TAIL(&watcher_list->watchers, q); + uv__queue_remove(q); + uv__queue_insert_tail(&watcher_list->watchers, q); uv_fs_event_stop(handle); - QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers); + uv__queue_insert_tail(&tmp_watcher_list.watchers, &handle->watchers); handle->path = tmp_path; } watcher_list->iterating = 0; maybe_free_watcher_list(watcher_list, loop); } - QUEUE_MOVE(&tmp_watcher_list.watchers, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - QUEUE_REMOVE(q); - handle = QUEUE_DATA(q, uv_fs_event_t, watchers); + uv__queue_move(&tmp_watcher_list.watchers, &queue); + while (!uv__queue_empty(&queue)) { + q = uv__queue_head(&queue); + uv__queue_remove(q); + handle = uv__queue_data(q, uv_fs_event_t, watchers); tmp_path = handle->path; handle->path = NULL; err = uv_fs_event_start(handle, handle->cb, tmp_path, 0); @@ -2298,7 +2298,7 @@ static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) { static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) { /* if the watcher_list->watchers is being iterated over, we can't free it. */ - if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) { + if ((!w->iterating) && uv__queue_empty(&w->watchers)) { /* No watchers left for this path. Clean up. */ RB_REMOVE(watcher_root, uv__inotify_watchers(loop), w); inotify_rm_watch(loop->inotify_fd, w->wd); @@ -2313,8 +2313,8 @@ static void uv__inotify_read(uv_loop_t* loop, const struct inotify_event* e; struct watcher_list* w; uv_fs_event_t* h; - QUEUE queue; - QUEUE* q; + struct uv__queue queue; + struct uv__queue* q; const char* path; ssize_t size; const char *p; @@ -2357,7 +2357,7 @@ static void uv__inotify_read(uv_loop_t* loop, * What can go wrong? * A callback could call uv_fs_event_stop() * and the queue can change under our feet. - * So, we use QUEUE_MOVE() trick to safely iterate over the queue. + * So, we use uv__queue_move() trick to safely iterate over the queue. * And we don't free the watcher_list until we're done iterating. * * First, @@ -2365,13 +2365,13 @@ static void uv__inotify_read(uv_loop_t* loop, * not to free watcher_list. */ w->iterating = 1; - QUEUE_MOVE(&w->watchers, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - h = QUEUE_DATA(q, uv_fs_event_t, watchers); + uv__queue_move(&w->watchers, &queue); + while (!uv__queue_empty(&queue)) { + q = uv__queue_head(&queue); + h = uv__queue_data(q, uv_fs_event_t, watchers); - QUEUE_REMOVE(q); - QUEUE_INSERT_TAIL(&w->watchers, q); + uv__queue_remove(q); + uv__queue_insert_tail(&w->watchers, q); h->cb(h, path, events, 0); } @@ -2433,13 +2433,13 @@ int uv_fs_event_start(uv_fs_event_t* handle, w->wd = wd; w->path = memcpy(w + 1, path, len); - QUEUE_INIT(&w->watchers); + uv__queue_init(&w->watchers); w->iterating = 0; RB_INSERT(watcher_root, uv__inotify_watchers(loop), w); no_insert: uv__handle_start(handle); - QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers); + uv__queue_insert_tail(&w->watchers, &handle->watchers); handle->path = w->path; handle->cb = cb; handle->wd = wd; @@ -2460,7 +2460,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { handle->wd = -1; handle->path = NULL; uv__handle_stop(handle); - QUEUE_REMOVE(&handle->watchers); + uv__queue_remove(&handle->watchers); maybe_free_watcher_list(w, handle->loop); diff --git a/src/unix/loop-watcher.c b/src/unix/loop-watcher.c index b8c1c2a7102..2db8b515df7 100644 --- a/src/unix/loop-watcher.c +++ b/src/unix/loop-watcher.c @@ -32,7 +32,7 @@ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ if (uv__is_active(handle)) return 0; \ if (cb == NULL) return UV_EINVAL; \ - QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \ + uv__queue_insert_head(&handle->loop->name##_handles, &handle->queue); \ handle->name##_cb = cb; \ uv__handle_start(handle); \ return 0; \ @@ -40,21 +40,21 @@ \ int uv_##name##_stop(uv_##name##_t* handle) { \ if (!uv__is_active(handle)) return 0; \ - QUEUE_REMOVE(&handle->queue); \ + uv__queue_remove(&handle->queue); \ uv__handle_stop(handle); \ return 0; \ } \ \ void uv__run_##name(uv_loop_t* loop) { \ uv_##name##_t* h; \ - QUEUE queue; \ - QUEUE* q; \ - QUEUE_MOVE(&loop->name##_handles, &queue); \ - while (!QUEUE_EMPTY(&queue)) { \ - q = QUEUE_HEAD(&queue); \ - h = QUEUE_DATA(q, uv_##name##_t, queue); \ - QUEUE_REMOVE(q); \ - QUEUE_INSERT_TAIL(&loop->name##_handles, q); \ + struct uv__queue queue; \ + struct uv__queue* q; \ + uv__queue_move(&loop->name##_handles, &queue); \ + while (!uv__queue_empty(&queue)) { \ + q = uv__queue_head(&queue); \ + h = uv__queue_data(q, uv_##name##_t, queue); \ + uv__queue_remove(q); \ + uv__queue_insert_tail(&loop->name##_handles, q); \ h->name##_cb(h); \ } \ } \ diff --git a/src/unix/loop.c b/src/unix/loop.c index 90a51b339de..a9468e8e19c 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -50,20 +50,20 @@ int uv_loop_init(uv_loop_t* loop) { sizeof(lfields->loop_metrics.metrics)); heap_init((struct heap*) &loop->timer_heap); - QUEUE_INIT(&loop->wq); - QUEUE_INIT(&loop->idle_handles); - QUEUE_INIT(&loop->async_handles); - QUEUE_INIT(&loop->check_handles); - QUEUE_INIT(&loop->prepare_handles); - QUEUE_INIT(&loop->handle_queue); + uv__queue_init(&loop->wq); + uv__queue_init(&loop->idle_handles); + uv__queue_init(&loop->async_handles); + uv__queue_init(&loop->check_handles); + uv__queue_init(&loop->prepare_handles); + uv__queue_init(&loop->handle_queue); loop->active_handles = 0; loop->active_reqs.count = 0; loop->nfds = 0; loop->watchers = NULL; loop->nwatchers = 0; - QUEUE_INIT(&loop->pending_queue); - QUEUE_INIT(&loop->watcher_queue); + uv__queue_init(&loop->pending_queue); + uv__queue_init(&loop->watcher_queue); loop->closing_handles = NULL; uv__update_time(loop); @@ -85,7 +85,7 @@ int uv_loop_init(uv_loop_t* loop) { err = uv__process_init(loop); if (err) goto fail_signal_init; - QUEUE_INIT(&loop->process_handles); + uv__queue_init(&loop->process_handles); err = uv_rwlock_init(&loop->cloexec_lock); if (err) @@ -152,9 +152,9 @@ int uv_loop_fork(uv_loop_t* loop) { if (w == NULL) continue; - if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) { + if (w->pevents != 0 && uv__queue_empty(&w->watcher_queue)) { w->events = 0; /* Force re-registration in uv__io_poll. */ - QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + uv__queue_insert_tail(&loop->watcher_queue, &w->watcher_queue); } } @@ -180,7 +180,7 @@ void uv__loop_close(uv_loop_t* loop) { } uv_mutex_lock(&loop->wq_mutex); - assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!"); + assert(uv__queue_empty(&loop->wq) && "thread pool work queue not empty!"); assert(!uv__has_active_reqs(loop)); uv_mutex_unlock(&loop->wq_mutex); uv_mutex_destroy(&loop->wq_mutex); @@ -192,8 +192,8 @@ void uv__loop_close(uv_loop_t* loop) { uv_rwlock_destroy(&loop->cloexec_lock); #if 0 - assert(QUEUE_EMPTY(&loop->pending_queue)); - assert(QUEUE_EMPTY(&loop->watcher_queue)); + assert(uv__queue_empty(&loop->pending_queue)); + assert(uv__queue_empty(&loop->watcher_queue)); assert(loop->nfds == 0); #endif diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c index 5861aaaa202..7f90c270906 100644 --- a/src/unix/os390-syscalls.c +++ b/src/unix/os390-syscalls.c @@ -27,7 +27,7 @@ #include #include -static QUEUE global_epoll_queue; +static struct uv__queue global_epoll_queue; static uv_mutex_t global_epoll_lock; static uv_once_t once = UV_ONCE_INIT; @@ -178,18 +178,18 @@ static void after_fork(void) { static void child_fork(void) { - QUEUE* q; + struct uv__queue* q; uv_once_t child_once = UV_ONCE_INIT; /* reset once */ memcpy(&once, &child_once, sizeof(child_once)); /* reset epoll list */ - while (!QUEUE_EMPTY(&global_epoll_queue)) { + while (!uv__queue_empty(&global_epoll_queue)) { uv__os390_epoll* lst; - q = QUEUE_HEAD(&global_epoll_queue); - QUEUE_REMOVE(q); - lst = QUEUE_DATA(q, uv__os390_epoll, member); + q = uv__queue_head(&global_epoll_queue); + uv__queue_remove(q); + lst = uv__queue_data(q, uv__os390_epoll, member); uv__free(lst->items); lst->items = NULL; lst->size = 0; @@ -201,7 +201,7 @@ static void child_fork(void) { static void epoll_init(void) { - QUEUE_INIT(&global_epoll_queue); + uv__queue_init(&global_epoll_queue); if (uv_mutex_init(&global_epoll_lock)) abort(); @@ -225,7 +225,7 @@ uv__os390_epoll* epoll_create1(int flags) { lst->items[lst->size - 1].revents = 0; uv_once(&once, epoll_init); uv_mutex_lock(&global_epoll_lock); - QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); + uv__queue_insert_tail(&global_epoll_queue, &lst->member); uv_mutex_unlock(&global_epoll_lock); } @@ -352,14 +352,14 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, int epoll_file_close(int fd) { - QUEUE* q; + struct uv__queue* q; uv_once(&once, epoll_init); uv_mutex_lock(&global_epoll_lock); - QUEUE_FOREACH(q, &global_epoll_queue) { + uv__queue_foreach(q, &global_epoll_queue) { uv__os390_epoll* lst; - lst = QUEUE_DATA(q, uv__os390_epoll, member); + lst = uv__queue_data(q, uv__os390_epoll, member); if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1) lst->items[fd].fd = -1; } @@ -371,7 +371,7 @@ int epoll_file_close(int fd) { void epoll_queue_close(uv__os390_epoll* lst) { /* Remove epoll instance from global queue */ uv_mutex_lock(&global_epoll_lock); - QUEUE_REMOVE(&lst->member); + uv__queue_remove(&lst->member); uv_mutex_unlock(&global_epoll_lock); /* Free resources */ diff --git a/src/unix/os390-syscalls.h b/src/unix/os390-syscalls.h index 9f504171d85..d5f3bcf8b1c 100644 --- a/src/unix/os390-syscalls.h +++ b/src/unix/os390-syscalls.h @@ -45,7 +45,7 @@ struct epoll_event { }; typedef struct { - QUEUE member; + struct uv__queue member; struct pollfd* items; unsigned long size; int msg_queue; diff --git a/src/unix/os390.c b/src/unix/os390.c index a87c2d77faf..bbd37692d1d 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -815,7 +815,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { uv__os390_epoll* ep; int have_signals; int real_timeout; - QUEUE* q; + struct uv__queue* q; uv__io_t* w; uint64_t base; int count; @@ -827,19 +827,19 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { int reset_timeout; if (loop->nfds == 0) { - assert(QUEUE_EMPTY(&loop->watcher_queue)); + assert(uv__queue_empty(&loop->watcher_queue)); return; } lfields = uv__get_internal_fields(loop); - while (!QUEUE_EMPTY(&loop->watcher_queue)) { + while (!uv__queue_empty(&loop->watcher_queue)) { uv_stream_t* stream; - q = QUEUE_HEAD(&loop->watcher_queue); - QUEUE_REMOVE(q); - QUEUE_INIT(q); - w = QUEUE_DATA(q, uv__io_t, watcher_queue); + q = uv__queue_head(&loop->watcher_queue); + uv__queue_remove(q); + uv__queue_init(q); + w = uv__queue_data(q, uv__io_t, watcher_queue); assert(w->pevents != 0); assert(w->fd >= 0); diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 610b09b37f3..3b7bc881074 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -230,7 +230,7 @@ void uv_pipe_connect(uv_connect_t* req, uv__req_init(handle->loop, req, UV_CONNECT); req->handle = (uv_stream_t*)handle; req->cb = cb; - QUEUE_INIT(&req->queue); + uv__queue_init(&req->queue); /* Force callback to run on next tick in case of error. */ if (err) diff --git a/src/unix/posix-poll.c b/src/unix/posix-poll.c index 7e7de86845d..2e016c2fbae 100644 --- a/src/unix/posix-poll.c +++ b/src/unix/posix-poll.c @@ -137,7 +137,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { sigset_t set; uint64_t time_base; uint64_t time_diff; - QUEUE* q; + struct uv__queue* q; uv__io_t* w; size_t i; unsigned int nevents; @@ -149,19 +149,19 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { int reset_timeout; if (loop->nfds == 0) { - assert(QUEUE_EMPTY(&loop->watcher_queue)); + assert(uv__queue_empty(&loop->watcher_queue)); return; } lfields = uv__get_internal_fields(loop); /* Take queued watchers and add their fds to our poll fds array. */ - while (!QUEUE_EMPTY(&loop->watcher_queue)) { - q = QUEUE_HEAD(&loop->watcher_queue); - QUEUE_REMOVE(q); - QUEUE_INIT(q); + while (!uv__queue_empty(&loop->watcher_queue)) { + q = uv__queue_head(&loop->watcher_queue); + uv__queue_remove(q); + uv__queue_init(q); - w = QUEUE_DATA(q, uv__io_t, watcher_queue); + w = uv__queue_data(q, uv__io_t, watcher_queue); assert(w->pevents != 0); assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); diff --git a/src/unix/process.c b/src/unix/process.c index c4fb322d17f..dbb4a1dc684 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -108,17 +108,17 @@ void uv__wait_children(uv_loop_t* loop) { int status; int options; pid_t pid; - QUEUE pending; - QUEUE* q; - QUEUE* h; + struct uv__queue pending; + struct uv__queue* q; + struct uv__queue* h; - QUEUE_INIT(&pending); + uv__queue_init(&pending); h = &loop->process_handles; - q = QUEUE_HEAD(h); + q = uv__queue_head(h); while (q != h) { - process = QUEUE_DATA(q, uv_process_t, queue); - q = QUEUE_NEXT(q); + process = uv__queue_data(q, uv_process_t, queue); + q = uv__queue_next(q); #ifndef UV_USE_SIGCHLD if ((process->flags & UV_HANDLE_REAP) == 0) @@ -149,18 +149,18 @@ void uv__wait_children(uv_loop_t* loop) { assert(pid == process->pid); process->status = status; - QUEUE_REMOVE(&process->queue); - QUEUE_INSERT_TAIL(&pending, &process->queue); + uv__queue_remove(&process->queue); + uv__queue_insert_tail(&pending, &process->queue); } h = &pending; - q = QUEUE_HEAD(h); + q = uv__queue_head(h); while (q != h) { - process = QUEUE_DATA(q, uv_process_t, queue); - q = QUEUE_NEXT(q); + process = uv__queue_data(q, uv_process_t, queue); + q = uv__queue_next(q); - QUEUE_REMOVE(&process->queue); - QUEUE_INIT(&process->queue); + uv__queue_remove(&process->queue); + uv__queue_init(&process->queue); uv__handle_stop(process); if (process->exit_cb == NULL) @@ -176,7 +176,7 @@ void uv__wait_children(uv_loop_t* loop) { process->exit_cb(process, exit_status, term_signal); } - assert(QUEUE_EMPTY(&pending)); + assert(uv__queue_empty(&pending)); } /* @@ -978,7 +978,7 @@ int uv_spawn(uv_loop_t* loop, UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); - QUEUE_INIT(&process->queue); + uv__queue_init(&process->queue); process->status = 0; stdio_count = options->stdio_count; @@ -1041,7 +1041,7 @@ int uv_spawn(uv_loop_t* loop, process->pid = pid; process->exit_cb = options->exit_cb; - QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue); + uv__queue_insert_tail(&loop->process_handles, &process->queue); uv__handle_start(process); } @@ -1103,10 +1103,10 @@ int uv_kill(int pid, int signum) { void uv__process_close(uv_process_t* handle) { - QUEUE_REMOVE(&handle->queue); + uv__queue_remove(&handle->queue); uv__handle_stop(handle); #ifdef UV_USE_SIGCHLD - if (QUEUE_EMPTY(&handle->loop->process_handles)) + if (uv__queue_empty(&handle->loop->process_handles)) uv_signal_stop(&handle->loop->child_watcher); #endif } diff --git a/src/unix/signal.c b/src/unix/signal.c index bb70523f561..63aba5a60e0 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -291,16 +291,16 @@ int uv__signal_loop_fork(uv_loop_t* loop) { void uv__signal_loop_cleanup(uv_loop_t* loop) { - QUEUE* q; + struct uv__queue* q; /* Stop all the signal watchers that are still attached to this loop. This * ensures that the (shared) signal tree doesn't contain any invalid entries * entries, and that signal handlers are removed when appropriate. - * It's safe to use QUEUE_FOREACH here because the handles and the handle + * It's safe to use uv__queue_foreach here because the handles and the handle * queue are not modified by uv__signal_stop(). */ - QUEUE_FOREACH(q, &loop->handle_queue) { - uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue); + uv__queue_foreach(q, &loop->handle_queue) { + uv_handle_t* handle = uv__queue_data(q, uv_handle_t, handle_queue); if (handle->type == UV_SIGNAL) uv__signal_stop((uv_signal_t*) handle); diff --git a/src/unix/stream.c b/src/unix/stream.c index 03f92b5045a..28c4d5463c4 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -94,8 +94,8 @@ void uv__stream_init(uv_loop_t* loop, stream->accepted_fd = -1; stream->queued_fds = NULL; stream->delayed_error = 0; - QUEUE_INIT(&stream->write_queue); - QUEUE_INIT(&stream->write_completed_queue); + uv__queue_init(&stream->write_queue); + uv__queue_init(&stream->write_completed_queue); stream->write_queue_size = 0; if (loop->emfile_fd == -1) { @@ -439,15 +439,15 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { void uv__stream_flush_write_queue(uv_stream_t* stream, int error) { uv_write_t* req; - QUEUE* q; - while (!QUEUE_EMPTY(&stream->write_queue)) { - q = QUEUE_HEAD(&stream->write_queue); - QUEUE_REMOVE(q); + struct uv__queue* q; + while (!uv__queue_empty(&stream->write_queue)) { + q = uv__queue_head(&stream->write_queue); + uv__queue_remove(q); - req = QUEUE_DATA(q, uv_write_t, queue); + req = uv__queue_data(q, uv_write_t, queue); req->error = error; - QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue); + uv__queue_insert_tail(&stream->write_completed_queue, &req->queue); } } @@ -627,7 +627,7 @@ static void uv__drain(uv_stream_t* stream) { uv_shutdown_t* req; int err; - assert(QUEUE_EMPTY(&stream->write_queue)); + assert(uv__queue_empty(&stream->write_queue)); if (!(stream->flags & UV_HANDLE_CLOSING)) { uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); @@ -714,7 +714,7 @@ static void uv__write_req_finish(uv_write_t* req) { uv_stream_t* stream = req->handle; /* Pop the req off tcp->write_queue. */ - QUEUE_REMOVE(&req->queue); + uv__queue_remove(&req->queue); /* Only free when there was no error. On error, we touch up write_queue_size * right before making the callback. The reason we don't do that right away @@ -731,7 +731,7 @@ static void uv__write_req_finish(uv_write_t* req) { /* Add it to the write_completed_queue where it will have its * callback called in the near future. */ - QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue); + uv__queue_insert_tail(&stream->write_completed_queue, &req->queue); uv__io_feed(stream->loop, &stream->io_watcher); } @@ -837,7 +837,7 @@ static int uv__try_write(uv_stream_t* stream, } static void uv__write(uv_stream_t* stream) { - QUEUE* q; + struct uv__queue* q; uv_write_t* req; ssize_t n; int count; @@ -851,11 +851,11 @@ static void uv__write(uv_stream_t* stream) { count = 32; for (;;) { - if (QUEUE_EMPTY(&stream->write_queue)) + if (uv__queue_empty(&stream->write_queue)) return; - q = QUEUE_HEAD(&stream->write_queue); - req = QUEUE_DATA(q, uv_write_t, queue); + q = uv__queue_head(&stream->write_queue); + req = uv__queue_data(q, uv_write_t, queue); assert(req->handle == stream); n = uv__try_write(stream, @@ -899,19 +899,19 @@ static void uv__write(uv_stream_t* stream) { static void uv__write_callbacks(uv_stream_t* stream) { uv_write_t* req; - QUEUE* q; - QUEUE pq; + struct uv__queue* q; + struct uv__queue pq; - if (QUEUE_EMPTY(&stream->write_completed_queue)) + if (uv__queue_empty(&stream->write_completed_queue)) return; - QUEUE_MOVE(&stream->write_completed_queue, &pq); + uv__queue_move(&stream->write_completed_queue, &pq); - while (!QUEUE_EMPTY(&pq)) { + while (!uv__queue_empty(&pq)) { /* Pop a req off write_completed_queue. */ - q = QUEUE_HEAD(&pq); - req = QUEUE_DATA(q, uv_write_t, queue); - QUEUE_REMOVE(q); + q = uv__queue_head(&pq); + req = uv__queue_data(q, uv_write_t, queue); + uv__queue_remove(q); uv__req_unregister(stream->loop, req); if (req->bufs != NULL) { @@ -1174,7 +1174,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { stream->shutdown_req = req; stream->flags &= ~UV_HANDLE_WRITABLE; - if (QUEUE_EMPTY(&stream->write_queue)) + if (uv__queue_empty(&stream->write_queue)) uv__io_feed(stream->loop, &stream->io_watcher); return 0; @@ -1227,7 +1227,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { uv__write_callbacks(stream); /* Write queue drained. */ - if (QUEUE_EMPTY(&stream->write_queue)) + if (uv__queue_empty(&stream->write_queue)) uv__drain(stream); } } @@ -1270,7 +1270,7 @@ static void uv__stream_connect(uv_stream_t* stream) { stream->connect_req = NULL; uv__req_unregister(stream->loop, req); - if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) { + if (error < 0 || uv__queue_empty(&stream->write_queue)) { uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); } @@ -1352,7 +1352,7 @@ int uv_write2(uv_write_t* req, req->handle = stream; req->error = 0; req->send_handle = send_handle; - QUEUE_INIT(&req->queue); + uv__queue_init(&req->queue); req->bufs = req->bufsml; if (nbufs > ARRAY_SIZE(req->bufsml)) @@ -1367,7 +1367,7 @@ int uv_write2(uv_write_t* req, stream->write_queue_size += uv__count_bufs(bufs, nbufs); /* Append the request to write_queue. */ - QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue); + uv__queue_insert_tail(&stream->write_queue, &req->queue); /* If the queue was empty when this function began, we should attempt to * do the write immediately. Otherwise start the write_watcher and wait diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 75b6fbad493..2d6bae79604 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -148,7 +148,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { struct port_event events[1024]; struct port_event* pe; struct timespec spec; - QUEUE* q; + struct uv__queue* q; uv__io_t* w; sigset_t* pset; sigset_t set; @@ -166,16 +166,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { int reset_timeout; if (loop->nfds == 0) { - assert(QUEUE_EMPTY(&loop->watcher_queue)); + assert(uv__queue_empty(&loop->watcher_queue)); return; } - while (!QUEUE_EMPTY(&loop->watcher_queue)) { - q = QUEUE_HEAD(&loop->watcher_queue); - QUEUE_REMOVE(q); - QUEUE_INIT(q); + while (!uv__queue_empty(&loop->watcher_queue)) { + q = uv__queue_head(&loop->watcher_queue); + uv__queue_remove(q); + uv__queue_init(q); - w = QUEUE_DATA(q, uv__io_t, watcher_queue); + w = uv__queue_data(q, uv__io_t, watcher_queue); assert(w->pevents != 0); if (port_associate(loop->backend_fd, @@ -316,8 +316,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { continue; /* Disabled by callback. */ /* Events Ports operates in oneshot mode, rearm timer on next run. */ - if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) - QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + if (w->pevents != 0 && uv__queue_empty(&w->watcher_queue)) + uv__queue_insert_tail(&loop->watcher_queue, &w->watcher_queue); } uv__metrics_inc_events(loop, nevents); diff --git a/src/unix/tcp.c b/src/unix/tcp.c index ab4e06c2f67..d6c848f4610 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -124,7 +124,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) { if (domain != AF_UNSPEC) { err = new_socket(tcp, domain, 0); if (err) { - QUEUE_REMOVE(&tcp->handle_queue); + uv__queue_remove(&tcp->handle_queue); if (tcp->io_watcher.fd != -1) uv__close(tcp->io_watcher.fd); tcp->io_watcher.fd = -1; @@ -252,7 +252,7 @@ int uv__tcp_connect(uv_connect_t* req, uv__req_init(handle->loop, req, UV_CONNECT); req->cb = cb; req->handle = (uv_stream_t*) handle; - QUEUE_INIT(&req->queue); + uv__queue_init(&req->queue); handle->connect_req = req; uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); diff --git a/src/unix/tty.c b/src/unix/tty.c index 7a5390c1a8b..d099bdb3b67 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -222,7 +222,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) { int rc = r; if (newfd != -1) uv__close(newfd); - QUEUE_REMOVE(&tty->handle_queue); + uv__queue_remove(&tty->handle_queue); do r = fcntl(fd, F_SETFL, saved_flags); while (r == -1 && errno == EINTR); diff --git a/src/unix/udp.c b/src/unix/udp.c index f556808fbae..c2814512a5f 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -62,18 +62,18 @@ void uv__udp_close(uv_udp_t* handle) { void uv__udp_finish_close(uv_udp_t* handle) { uv_udp_send_t* req; - QUEUE* q; + struct uv__queue* q; assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT)); assert(handle->io_watcher.fd == -1); - while (!QUEUE_EMPTY(&handle->write_queue)) { - q = QUEUE_HEAD(&handle->write_queue); - QUEUE_REMOVE(q); + while (!uv__queue_empty(&handle->write_queue)) { + q = uv__queue_head(&handle->write_queue); + uv__queue_remove(q); - req = QUEUE_DATA(q, uv_udp_send_t, queue); + req = uv__queue_data(q, uv_udp_send_t, queue); req->status = UV_ECANCELED; - QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); + uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); } uv__udp_run_completed(handle); @@ -90,16 +90,16 @@ void uv__udp_finish_close(uv_udp_t* handle) { static void uv__udp_run_completed(uv_udp_t* handle) { uv_udp_send_t* req; - QUEUE* q; + struct uv__queue* q; assert(!(handle->flags & UV_HANDLE_UDP_PROCESSING)); handle->flags |= UV_HANDLE_UDP_PROCESSING; - while (!QUEUE_EMPTY(&handle->write_completed_queue)) { - q = QUEUE_HEAD(&handle->write_completed_queue); - QUEUE_REMOVE(q); + while (!uv__queue_empty(&handle->write_completed_queue)) { + q = uv__queue_head(&handle->write_completed_queue); + uv__queue_remove(q); - req = QUEUE_DATA(q, uv_udp_send_t, queue); + req = uv__queue_data(q, uv_udp_send_t, queue); uv__req_unregister(handle->loop, req); handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs); @@ -121,7 +121,7 @@ static void uv__udp_run_completed(uv_udp_t* handle) { req->send_cb(req, req->status); } - if (QUEUE_EMPTY(&handle->write_queue)) { + if (uv__queue_empty(&handle->write_queue)) { /* Pending queue and completion queue empty, stop watcher. */ uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT); if (!uv__io_active(&handle->io_watcher, POLLIN)) @@ -280,20 +280,20 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { uv_udp_send_t* req; struct mmsghdr h[20]; struct mmsghdr* p; - QUEUE* q; + struct uv__queue* q; ssize_t npkts; size_t pkts; size_t i; - if (QUEUE_EMPTY(&handle->write_queue)) + if (uv__queue_empty(&handle->write_queue)) return; write_queue_drain: - for (pkts = 0, q = QUEUE_HEAD(&handle->write_queue); + for (pkts = 0, q = uv__queue_head(&handle->write_queue); pkts < ARRAY_SIZE(h) && q != &handle->write_queue; - ++pkts, q = QUEUE_HEAD(q)) { + ++pkts, q = uv__queue_head(q)) { assert(q != NULL); - req = QUEUE_DATA(q, uv_udp_send_t, queue); + req = uv__queue_data(q, uv_udp_send_t, queue); assert(req != NULL); p = &h[pkts]; @@ -325,16 +325,16 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { if (npkts < 1) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) return; - for (i = 0, q = QUEUE_HEAD(&handle->write_queue); + for (i = 0, q = uv__queue_head(&handle->write_queue); i < pkts && q != &handle->write_queue; - ++i, q = QUEUE_HEAD(&handle->write_queue)) { + ++i, q = uv__queue_head(&handle->write_queue)) { assert(q != NULL); - req = QUEUE_DATA(q, uv_udp_send_t, queue); + req = uv__queue_data(q, uv_udp_send_t, queue); assert(req != NULL); req->status = UV__ERR(errno); - QUEUE_REMOVE(&req->queue); - QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); + uv__queue_remove(&req->queue); + uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); } uv__io_feed(handle->loop, &handle->io_watcher); return; @@ -343,11 +343,11 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { /* Safety: npkts known to be >0 below. Hence cast from ssize_t * to size_t safe. */ - for (i = 0, q = QUEUE_HEAD(&handle->write_queue); + for (i = 0, q = uv__queue_head(&handle->write_queue); i < (size_t)npkts && q != &handle->write_queue; - ++i, q = QUEUE_HEAD(&handle->write_queue)) { + ++i, q = uv__queue_head(&handle->write_queue)) { assert(q != NULL); - req = QUEUE_DATA(q, uv_udp_send_t, queue); + req = uv__queue_data(q, uv_udp_send_t, queue); assert(req != NULL); req->status = req->bufs[0].len; @@ -357,25 +357,25 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { * why we don't handle partial writes. Just pop the request * off the write queue and onto the completed queue, done. */ - QUEUE_REMOVE(&req->queue); - QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); + 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 (!QUEUE_EMPTY(&handle->write_queue)) + if (!uv__queue_empty(&handle->write_queue)) goto write_queue_drain; uv__io_feed(handle->loop, &handle->io_watcher); #else /* __linux__ || ____FreeBSD__ */ uv_udp_send_t* req; struct msghdr h; - QUEUE* q; + struct uv__queue* q; ssize_t size; - while (!QUEUE_EMPTY(&handle->write_queue)) { - q = QUEUE_HEAD(&handle->write_queue); + while (!uv__queue_empty(&handle->write_queue)) { + q = uv__queue_head(&handle->write_queue); assert(q != NULL); - req = QUEUE_DATA(q, uv_udp_send_t, queue); + req = uv__queue_data(q, uv_udp_send_t, queue); assert(req != NULL); memset(&h, 0, sizeof h); @@ -414,8 +414,8 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { * why we don't handle partial writes. Just pop the request * off the write queue and onto the completed queue, done. */ - QUEUE_REMOVE(&req->queue); - QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); + uv__queue_remove(&req->queue); + uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); uv__io_feed(handle->loop, &handle->io_watcher); } #endif /* __linux__ || ____FreeBSD__ */ @@ -729,7 +729,7 @@ int uv__udp_send(uv_udp_send_t* req, memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs); handle->send_queue_count++; - QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue); + uv__queue_insert_tail(&handle->write_queue, &req->queue); uv__handle_start(handle); if (empty_queue && !(handle->flags & UV_HANDLE_UDP_PROCESSING)) { @@ -739,7 +739,7 @@ int uv__udp_send(uv_udp_send_t* req, * away. In such cases the `io_watcher` has to be queued for asynchronous * write. */ - if (!QUEUE_EMPTY(&handle->write_queue)) + if (!uv__queue_empty(&handle->write_queue)) uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); } else { uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); @@ -1007,8 +1007,8 @@ int uv__udp_init_ex(uv_loop_t* loop, handle->send_queue_size = 0; handle->send_queue_count = 0; uv__io_init(&handle->io_watcher, uv__udp_io, fd); - QUEUE_INIT(&handle->write_queue); - QUEUE_INIT(&handle->write_completed_queue); + uv__queue_init(&handle->write_queue); + uv__queue_init(&handle->write_completed_queue); return 0; } diff --git a/src/uv-common.c b/src/uv-common.c index cec771fab21..916f3f4e006 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -533,17 +533,17 @@ int uv_udp_recv_stop(uv_udp_t* handle) { void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { - QUEUE queue; - QUEUE* q; + struct uv__queue queue; + struct uv__queue* q; uv_handle_t* h; - QUEUE_MOVE(&loop->handle_queue, &queue); - while (!QUEUE_EMPTY(&queue)) { - q = QUEUE_HEAD(&queue); - h = QUEUE_DATA(q, uv_handle_t, handle_queue); + uv__queue_move(&loop->handle_queue, &queue); + while (!uv__queue_empty(&queue)) { + q = uv__queue_head(&queue); + h = uv__queue_data(q, uv_handle_t, handle_queue); - QUEUE_REMOVE(q); - QUEUE_INSERT_TAIL(&loop->handle_queue, q); + uv__queue_remove(q); + uv__queue_insert_tail(&loop->handle_queue, q); if (h->flags & UV_HANDLE_INTERNAL) continue; walk_cb(h, arg); @@ -553,14 +553,14 @@ void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) { const char* type; - QUEUE* q; + struct uv__queue* q; uv_handle_t* h; if (loop == NULL) loop = uv_default_loop(); - QUEUE_FOREACH(q, &loop->handle_queue) { - h = QUEUE_DATA(q, uv_handle_t, handle_queue); + uv__queue_foreach(q, &loop->handle_queue) { + h = uv__queue_data(q, uv_handle_t, handle_queue); if (only_active && !uv__is_active(h)) continue; @@ -846,7 +846,7 @@ uv_loop_t* uv_loop_new(void) { int uv_loop_close(uv_loop_t* loop) { - QUEUE* q; + struct uv__queue* q; uv_handle_t* h; #ifndef NDEBUG void* saved_data; @@ -855,8 +855,8 @@ int uv_loop_close(uv_loop_t* loop) { if (uv__has_active_reqs(loop)) return UV_EBUSY; - QUEUE_FOREACH(q, &loop->handle_queue) { - h = QUEUE_DATA(q, uv_handle_t, handle_queue); + uv__queue_foreach(q, &loop->handle_queue) { + h = uv__queue_data(q, uv_handle_t, handle_queue); if (!(h->flags & UV_HANDLE_INTERNAL)) return UV_EBUSY; } diff --git a/src/uv-common.h b/src/uv-common.h index c0f6daf1b8f..cd57e5a3515 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -323,7 +323,7 @@ void uv__threadpool_cleanup(void); (h)->loop = (loop_); \ (h)->type = (type_); \ (h)->flags = UV_HANDLE_REF; /* Ref the loop when active. */ \ - QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \ + uv__queue_insert_tail(&(loop_)->handle_queue, &(h)->handle_queue); \ uv__handle_platform_init(h); \ } \ while (0) diff --git a/src/win/core.c b/src/win/core.c index 426edb18eb5..2ae8aa7da9b 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -255,8 +255,8 @@ int uv_loop_init(uv_loop_t* loop) { loop->time = 0; uv_update_time(loop); - QUEUE_INIT(&loop->wq); - QUEUE_INIT(&loop->handle_queue); + uv__queue_init(&loop->wq); + uv__queue_init(&loop->handle_queue); loop->active_reqs.count = 0; loop->active_handles = 0; @@ -358,7 +358,7 @@ void uv__loop_close(uv_loop_t* loop) { } uv_mutex_lock(&loop->wq_mutex); - assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!"); + assert(uv__queue_empty(&loop->wq) && "thread pool work queue not empty!"); assert(!uv__has_active_reqs(loop)); uv_mutex_unlock(&loop->wq_mutex); uv_mutex_destroy(&loop->wq_mutex); diff --git a/src/win/handle-inl.h b/src/win/handle-inl.h index 5c843c241ef..4722e85790a 100644 --- a/src/win/handle-inl.h +++ b/src/win/handle-inl.h @@ -75,7 +75,7 @@ #define uv__handle_close(handle) \ do { \ - QUEUE_REMOVE(&(handle)->handle_queue); \ + uv__queue_remove(&(handle)->handle_queue); \ uv__active_handle_rm((uv_handle_t*) (handle)); \ \ (handle)->flags |= UV_HANDLE_CLOSED; \ diff --git a/src/win/pipe.c b/src/win/pipe.c index 787ba105c93..6044259c5f8 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -55,7 +55,7 @@ static const int pipe_prefix_len = sizeof(pipe_prefix) - 1; typedef struct { uv__ipc_socket_xfer_type_t xfer_type; uv__ipc_socket_xfer_info_t xfer_info; - QUEUE member; + struct uv__queue member; } uv__ipc_xfer_queue_item_t; /* IPC frame header flags. */ @@ -111,7 +111,7 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { handle->name = NULL; handle->pipe.conn.ipc_remote_pid = 0; handle->pipe.conn.ipc_data_frame.payload_remaining = 0; - QUEUE_INIT(&handle->pipe.conn.ipc_xfer_queue); + uv__queue_init(&handle->pipe.conn.ipc_xfer_queue); handle->pipe.conn.ipc_xfer_queue_length = 0; handle->ipc = ipc; handle->pipe.conn.non_overlapped_writes_tail = NULL; @@ -637,13 +637,13 @@ void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { if (handle->flags & UV_HANDLE_CONNECTION) { /* Free pending sockets */ - while (!QUEUE_EMPTY(&handle->pipe.conn.ipc_xfer_queue)) { - QUEUE* q; + while (!uv__queue_empty(&handle->pipe.conn.ipc_xfer_queue)) { + struct uv__queue* q; SOCKET socket; - q = QUEUE_HEAD(&handle->pipe.conn.ipc_xfer_queue); - QUEUE_REMOVE(q); - xfer_queue_item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member); + q = uv__queue_head(&handle->pipe.conn.ipc_xfer_queue); + uv__queue_remove(q); + xfer_queue_item = uv__queue_data(q, uv__ipc_xfer_queue_item_t, member); /* Materialize socket and close it */ socket = WSASocketW(FROM_PROTOCOL_INFO, @@ -1062,20 +1062,20 @@ int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) { uv_loop_t* loop = server->loop; uv_pipe_t* pipe_client; uv_pipe_accept_t* req; - QUEUE* q; + struct uv__queue* q; uv__ipc_xfer_queue_item_t* item; int err; if (server->ipc) { - if (QUEUE_EMPTY(&server->pipe.conn.ipc_xfer_queue)) { + if (uv__queue_empty(&server->pipe.conn.ipc_xfer_queue)) { /* No valid pending sockets. */ return WSAEWOULDBLOCK; } - q = QUEUE_HEAD(&server->pipe.conn.ipc_xfer_queue); - QUEUE_REMOVE(q); + q = uv__queue_head(&server->pipe.conn.ipc_xfer_queue); + uv__queue_remove(q); server->pipe.conn.ipc_xfer_queue_length--; - item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member); + item = uv__queue_data(q, uv__ipc_xfer_queue_item_t, member); err = uv__tcp_xfer_import( (uv_tcp_t*) client, item->xfer_type, &item->xfer_info); @@ -1829,7 +1829,7 @@ static void uv__pipe_queue_ipc_xfer_info( item->xfer_type = xfer_type; item->xfer_info = *xfer_info; - QUEUE_INSERT_TAIL(&handle->pipe.conn.ipc_xfer_queue, &item->member); + uv__queue_insert_tail(&handle->pipe.conn.ipc_xfer_queue, &item->member); handle->pipe.conn.ipc_xfer_queue_length++; } diff --git a/src/win/tcp.c b/src/win/tcp.c index 6b282e0b501..187f36e2a61 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -175,14 +175,14 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) { sock = socket(domain, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { err = WSAGetLastError(); - QUEUE_REMOVE(&handle->handle_queue); + uv__queue_remove(&handle->handle_queue); return uv_translate_sys_error(err); } err = uv__tcp_set_socket(handle->loop, handle, sock, domain, 0); if (err) { closesocket(sock); - QUEUE_REMOVE(&handle->handle_queue); + uv__queue_remove(&handle->handle_queue); return uv_translate_sys_error(err); } diff --git a/src/win/udp.c b/src/win/udp.c index 8a982d1907d..eab53842d4f 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -146,14 +146,14 @@ int uv__udp_init_ex(uv_loop_t* loop, sock = socket(domain, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) { err = WSAGetLastError(); - QUEUE_REMOVE(&handle->handle_queue); + uv__queue_remove(&handle->handle_queue); return uv_translate_sys_error(err); } err = uv__udp_set_socket(handle->loop, handle, sock, domain); if (err) { closesocket(sock); - QUEUE_REMOVE(&handle->handle_queue); + uv__queue_remove(&handle->handle_queue); return uv_translate_sys_error(err); } } diff --git a/test/test-queue-foreach-delete.c b/test/test-queue-foreach-delete.c index 75d63f5cf17..4fe8aecee5f 100644 --- a/test/test-queue-foreach-delete.c +++ b/test/test-queue-foreach-delete.c @@ -29,7 +29,7 @@ * The idea behind the test is as follows. * Certain handle types are stored in a queue internally. * Extra care should be taken for removal of a handle from the queue while iterating over the queue. - * (i.e., QUEUE_REMOVE() called within QUEUE_FOREACH()) + * (i.e., uv__queue_remove() called within uv__queue_foreach()) * This usually happens when someone closes or stops a handle from within its callback. * So we need to check that we haven't screwed the queue on close/stop. * To do so we do the following (for each handle type): @@ -54,7 +54,8 @@ * wrong foreach "next" | * * 4. The callback for handle #1 shouldn't be called because the handle #1 is stopped in the previous step. - * However, if QUEUE_REMOVE() is not handled properly within QUEUE_FOREACH(), the callback _will_ be called. + * However, if uv__queue_remove() is not handled properly within uv__queue_foreach(), the callback _will_ + * be called. */ static const unsigned first_handle_number_idle = 2; From e7b96331703e929e75d93c574573c9736e34b0c0 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Thu, 25 May 2023 12:09:51 +0200 Subject: [PATCH 383/713] linux: fs_read to use io_uring if iovcnt > IOV_MAX (#4023) Just cap it to `IOV_MAX` as it's already done when performing reads using the threadpool. --- src/unix/linux.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 183e781b2af..77dac84bfbe 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -914,10 +914,14 @@ int uv__iou_fs_read_or_write(uv_loop_t* loop, struct uv__io_uring_sqe* sqe; struct uv__iou* iou; - /* For the moment, if iovcnt is greater than IOV_MAX, fallback to the - * threadpool. In the future we might take advantage of IOSQE_IO_LINK. */ - if (req->nbufs > IOV_MAX) - return 0; + /* If iovcnt is greater than IOV_MAX, cap it to IOV_MAX on reads and fallback + * to the threadpool on writes */ + if (req->nbufs > IOV_MAX) { + if (is_read) + req->nbufs = IOV_MAX; + else + return 0; + } iou = &uv__get_internal_fields(loop)->iou; From 65c1402ee66a37d8cdd294f64bfd6def4b9fcf3f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 25 May 2023 13:08:43 +0200 Subject: [PATCH 384/713] ios: fix uv_getrusage() ru_maxrss calculation (#4027) Apple's documentation claims ru_maxrss is reported in kilobytes but the XNU source code suggests the actual unit is bytes, like macOS. Fixes: https://github.com/libuv/libuv/issues/4025 --- src/unix/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 2f8395f2bdb..4db2b0afab7 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1021,8 +1021,8 @@ int uv_getrusage(uv_rusage_t* rusage) { /* Most platforms report ru_maxrss in kilobytes; macOS and Solaris are * the outliers because of course they are. */ -#if defined(__APPLE__) && !TARGET_OS_IPHONE - rusage->ru_maxrss /= 1024; /* macOS reports bytes. */ +#if defined(__APPLE__) + rusage->ru_maxrss /= 1024; /* macOS and iOS report bytes. */ #elif defined(__sun) rusage->ru_maxrss /= getpagesize() / 1024; /* Solaris reports pages. */ #endif From e8ec610f28dc2d4296502b645d283b00bada5489 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 4 Jun 2023 22:41:58 +0200 Subject: [PATCH 385/713] include: update outdated code comment (#4037) I believe it's fair to say at this point that these functions are not going to be removed in v0.12. They are still deprecated though. --- include/uv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uv.h b/include/uv.h index a68a42f1394..90795c6e814 100644 --- a/include/uv.h +++ b/include/uv.h @@ -289,13 +289,13 @@ UV_EXTERN int uv_loop_init(uv_loop_t* loop); UV_EXTERN int uv_loop_close(uv_loop_t* loop); /* * NOTE: - * This function is DEPRECATED (to be removed after 0.12), users should + * This function is DEPRECATED, users should * allocate the loop manually and use uv_loop_init instead. */ UV_EXTERN uv_loop_t* uv_loop_new(void); /* * NOTE: - * This function is DEPRECATED (to be removed after 0.12). Users should use + * This function is DEPRECATED. Users should use * uv_loop_close and free the memory manually instead. */ UV_EXTERN void uv_loop_delete(uv_loop_t*); From b9b6db052b82dd0a429091238181195ec785ac0b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 4 Jun 2023 22:43:14 +0200 Subject: [PATCH 386/713] linux: support abstract unix sockets (#4030) Add two new APIs for binding and connecting to abstract UNIX sockets. Fixes: https://github.com/libuv/libuv/issues/4028 --- docs/src/pipe.rst | 48 +++++++++++++++++-- include/uv.h | 10 ++++ include/uv/unix.h | 2 +- src/unix/pipe.c | 86 ++++++++++++++++++++++++++++------ src/win/pipe.c | 64 ++++++++++++++++++++++--- test/test-pipe-getsockname.c | 91 ++++++++++++++++++------------------ 6 files changed, 230 insertions(+), 71 deletions(-) diff --git a/docs/src/pipe.rst b/docs/src/pipe.rst index 5fa83b80d36..9d95b206a97 100644 --- a/docs/src/pipe.rst +++ b/docs/src/pipe.rst @@ -55,17 +55,55 @@ API Bind the pipe to a file path (Unix) or a name (Windows). + Does not support Linux abstract namespace sockets, + unlike :c:func:`uv_pipe_bind2`. + + Alias for ``uv_pipe_bind2(handle, name, strlen(name), 0)``. + + .. note:: + Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, + typically between 92 and 108 bytes. + +.. c:function:: int uv_pipe_bind2(uv_pipe_t* handle, const char* name, size_t namelen, unsigned int flags) + + Bind the pipe to a file path (Unix) or a name (Windows). + + ``flags`` must be zero. Returns ``UV_EINVAL`` for unsupported flags + without performing the bind operation. + + Supports Linux abstract namespace sockets. ``namelen`` must include + the leading nul byte but not the trailing nul byte. + .. note:: - Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between - 92 and 108 bytes. + Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, + typically between 92 and 108 bytes. .. c:function:: void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) - Connect to the Unix domain socket or the named pipe. + Connect to the Unix domain socket or the Windows named pipe. + + Does not support Linux abstract namespace sockets, + unlike :c:func:`uv_pipe_connect2`. + + Alias for ``uv_pipe_connect2(req, handle, name, strlen(name), 0, cb)``. + + .. note:: + Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, + typically between 92 and 108 bytes. + +.. c:function:: void uv_pipe_connect2(uv_connect_t* req, uv_pipe_t* handle, const char* name, size_t namelen, unsigned int flags, uv_connect_cb cb) + + Connect to the Unix domain socket or the Windows named pipe. + + ``flags`` must be zero. Returns ``UV_EINVAL`` for unsupported flags + without performing the connect operation. + + Supports Linux abstract namespace sockets. ``namelen`` must include + the leading nul byte but not the trailing nul byte. .. note:: - Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between - 92 and 108 bytes. + Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, + typically between 92 and 108 bytes. .. c:function:: int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) diff --git a/include/uv.h b/include/uv.h index 90795c6e814..0f624f4d7f7 100644 --- a/include/uv.h +++ b/include/uv.h @@ -823,10 +823,20 @@ struct uv_pipe_s { UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc); UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file); UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name); +UV_EXTERN int uv_pipe_bind2(uv_pipe_t* handle, + const char* name, + size_t namelen, + unsigned int flags); UV_EXTERN void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb); +UV_EXTERN int uv_pipe_connect2(uv_connect_t* req, + uv_pipe_t* handle, + const char* name, + size_t namelen, + unsigned int flags, + uv_connect_cb cb); UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size); diff --git a/include/uv/unix.h b/include/uv/unix.h index d1a5f0438a5..7944eff2e4b 100644 --- a/include/uv/unix.h +++ b/include/uv/unix.h @@ -304,7 +304,7 @@ typedef struct { struct uv__queue write_completed_queue; \ #define UV_PIPE_PRIVATE_FIELDS \ - const char* pipe_fname; /* strdup'ed */ + const char* pipe_fname; /* NULL or strdup'ed */ #define UV_POLL_PRIVATE_FIELDS \ uv__io_t io_watcher; diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 3b7bc881074..823deb3d975 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -41,26 +41,56 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { int uv_pipe_bind(uv_pipe_t* handle, const char* name) { + return uv_pipe_bind2(handle, name, strlen(name), 0); +} + + +int uv_pipe_bind2(uv_pipe_t* handle, + const char* name, + size_t namelen, + unsigned int flags) { struct sockaddr_un saddr; - const char* pipe_fname; + char* pipe_fname; int sockfd; int err; pipe_fname = NULL; + if (flags != 0) + return UV_EINVAL; + + if (name == NULL) + return UV_EINVAL; + + if (namelen == 0) + return UV_EINVAL; + +#ifndef __linux__ + /* Abstract socket namespace only works on Linux. */ + if (*name == '\0') + return UV_EINVAL; +#endif + + /* Truncate long paths. Documented behavior. */ + if (namelen > sizeof(saddr.sun_path)) + namelen = sizeof(saddr.sun_path); + /* Already bound? */ if (uv__stream_fd(handle) >= 0) return UV_EINVAL; - if (uv__is_closing(handle)) { + + if (uv__is_closing(handle)) return UV_EINVAL; - } - /* Make a copy of the file name, it outlives this function's scope. */ - pipe_fname = uv__strdup(name); - if (pipe_fname == NULL) - return UV_ENOMEM; - /* We've got a copy, don't touch the original any more. */ - name = NULL; + /* Make a copy of the file path unless it is an abstract socket. + * We unlink the file later but abstract sockets disappear + * automatically since they're not real file system entities. + */ + if (*name != '\0') { + pipe_fname = uv__strdup(name); + if (pipe_fname == NULL) + return UV_ENOMEM; + } err = uv__socket(AF_UNIX, SOCK_STREAM, 0); if (err < 0) @@ -68,7 +98,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { sockfd = err; memset(&saddr, 0, sizeof saddr); - uv__strscpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path)); + memcpy(&saddr.sun_path, name, namelen); saddr.sun_family = AF_UNIX; if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { @@ -83,12 +113,12 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { /* Success. */ handle->flags |= UV_HANDLE_BOUND; - handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ + handle->pipe_fname = pipe_fname; /* NULL or a strdup'ed copy. */ handle->io_watcher.fd = sockfd; return 0; err_socket: - uv__free((void*)pipe_fname); + uv__free(pipe_fname); return err; } @@ -176,11 +206,40 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { + uv_pipe_connect2(req, handle, name, strlen(name), 0, cb); +} + + +int uv_pipe_connect2(uv_connect_t* req, + uv_pipe_t* handle, + const char* name, + size_t namelen, + unsigned int flags, + uv_connect_cb cb) { struct sockaddr_un saddr; int new_sock; int err; int r; + if (flags != 0) + return UV_EINVAL; + + if (name == NULL) + return UV_EINVAL; + + if (namelen == 0) + return UV_EINVAL; + +#ifndef __linux__ + /* Abstract socket namespace only works on Linux. */ + if (*name == '\0') + return UV_EINVAL; +#endif + + /* Truncate long paths. Documented behavior. */ + if (namelen > sizeof(saddr.sun_path)) + namelen = sizeof(saddr.sun_path); + new_sock = (uv__stream_fd(handle) == -1); if (new_sock) { @@ -191,7 +250,7 @@ void uv_pipe_connect(uv_connect_t* req, } memset(&saddr, 0, sizeof saddr); - uv__strscpy(saddr.sun_path, name, sizeof(saddr.sun_path)); + memcpy(&saddr.sun_path, name, namelen); saddr.sun_family = AF_UNIX; do { @@ -236,6 +295,7 @@ void uv_pipe_connect(uv_connect_t* req, if (err) uv__io_feed(handle->loop, &handle->io_watcher); + return 0; } diff --git a/src/win/pipe.c b/src/win/pipe.c index 6044259c5f8..a3daa3b7a18 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -694,20 +694,42 @@ void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { /* Creates a pipe server. */ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { + return uv_pipe_bind2(handle, name, strlen(name), 0); +} + + +int uv_pipe_bind2(uv_pipe_t* handle, + const char* name, + size_t namelen, + unsigned int flags) { uv_loop_t* loop = handle->loop; int i, err, nameSize; uv_pipe_accept_t* req; - if (handle->flags & UV_HANDLE_BOUND) { + if (flags != 0) { + return UV_EINVAL; + } + + if (name == NULL) { + return UV_EINVAL; + } + + if (namelen == 0) { return UV_EINVAL; } - if (!name) { + if (*name == '\0') { + return UV_EINVAL; + } + + if (handle->flags & UV_HANDLE_BOUND) { return UV_EINVAL; } + if (uv__is_closing(handle)) { return UV_EINVAL; } + if (!(handle->flags & UV_HANDLE_PIPESERVER)) { handle->pipe.serv.pending_instances = default_pending_pipe_instances; } @@ -818,13 +840,41 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { } -void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, - const char* name, uv_connect_cb cb) { +void uv_pipe_connect(uv_connect_t* req, + uv_pipe_t* handle, + const char* name, + uv_connect_cb cb) { + uv_pipe_connect2(req, handle, name, strlen(name), 0, cb); +} + + +int uv_pipe_connect2(uv_connect_t* req, + uv_pipe_t* handle, + const char* name, + size_t namelen, + unsigned int flags, + uv_connect_cb cb) { uv_loop_t* loop = handle->loop; int err, nameSize; HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; + if (flags != 0) { + return UV_EINVAL; + } + + if (name == NULL) { + return UV_EINVAL; + } + + if (namelen == 0) { + return UV_EINVAL; + } + + if (*name == '\0') { + return UV_EINVAL; + } + UV_REQ_INIT(req, UV_CONNECT); req->handle = (uv_stream_t*) handle; req->cb = cb; @@ -882,7 +932,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, REGISTER_HANDLE_REQ(loop, handle, req); handle->reqs_pending++; - return; + return 0; } err = GetLastError(); @@ -895,7 +945,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, uv__insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); - return; + return 0; error: if (handle->name) { @@ -911,7 +961,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, uv__insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); - return; + return 0; } diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index 4b0aa53b927..d749933d44f 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -25,11 +25,6 @@ #include #include -#if defined(__linux__) - #include - #include -#endif - #ifndef _WIN32 # include /* close */ #else @@ -63,8 +58,14 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) { r = uv_pipe_getpeername(&pipe_client, buf, &len); ASSERT(r == 0); - ASSERT(buf[len - 1] != 0); - ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0); + if (*buf == '\0') { /* Linux abstract socket. */ + const char expected[] = "\0" TEST_PIPENAME; + ASSERT_GE(len, sizeof(expected)); + ASSERT_MEM_EQ(buf, expected, sizeof(expected)); + } else { + ASSERT_NE(0, buf[len - 1]); + ASSERT_MEM_EQ(buf, TEST_PIPENAME, len); + } len = sizeof buf; r = uv_pipe_getsockname(&pipe_client, buf, &len); @@ -72,7 +73,6 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) { pipe_client_connect_cb_called++; - uv_close((uv_handle_t*) &pipe_client, pipe_close_cb); uv_close((uv_handle_t*) &pipe_server, pipe_close_cb); } @@ -162,47 +162,48 @@ TEST_IMPL(pipe_getsockname) { TEST_IMPL(pipe_getsockname_abstract) { + /* TODO(bnoordhuis) Use unique name, susceptible to concurrent test runs. */ + static const char name[] = "\0" TEST_PIPENAME; #if defined(__linux__) - char buf[1024]; - size_t len; - int r; - int sock; - struct sockaddr_un sun; - socklen_t sun_len; - char abstract_pipe[] = "\0test-pipe"; - - sock = socket(AF_UNIX, SOCK_STREAM, 0); - ASSERT(sock != -1); - - sun_len = sizeof sun; - memset(&sun, 0, sun_len); - sun.sun_family = AF_UNIX; - memcpy(sun.sun_path, abstract_pipe, sizeof abstract_pipe); - - r = bind(sock, (struct sockaddr*)&sun, sun_len); - ASSERT(r == 0); - - r = uv_pipe_init(uv_default_loop(), &pipe_server, 0); - ASSERT(r == 0); - r = uv_pipe_open(&pipe_server, sock); - ASSERT(r == 0); - - len = sizeof buf; - r = uv_pipe_getsockname(&pipe_server, buf, &len); - ASSERT(r == 0); - - ASSERT(memcmp(buf, abstract_pipe, sizeof abstract_pipe) == 0); - - uv_close((uv_handle_t*)&pipe_server, pipe_close_cb); - - uv_run(uv_default_loop(), UV_RUN_DEFAULT); - - close(sock); - - ASSERT(pipe_close_cb_called == 1); + char buf[256]; + size_t buflen; + + buflen = sizeof(buf); + memset(buf, 0, sizeof(buf)); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0)); + ASSERT_OK(uv_pipe_bind2(&pipe_server, name, sizeof(name), 0)); + ASSERT_OK(uv_pipe_getsockname(&pipe_server, buf, &buflen)); + ASSERT_MEM_EQ(name, buf, sizeof(name)); + ASSERT_OK(uv_listen((uv_stream_t*) &pipe_server, + 0, + pipe_server_connection_cb)); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_client, 0)); + ASSERT_OK(uv_pipe_connect2(&connect_req, + &pipe_client, + name, + sizeof(name), + 0, + pipe_client_connect_cb)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, pipe_client_connect_cb_called); + ASSERT_EQ(2, pipe_close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; #else + /* On other platforms it should simply fail with UV_EINVAL. */ + ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0)); + ASSERT_EQ(UV_EINVAL, uv_pipe_bind2(&pipe_server, name, sizeof(name), 0)); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_client, 0)); + uv_close((uv_handle_t*) &pipe_server, pipe_close_cb); + ASSERT_EQ(UV_EINVAL, uv_pipe_connect2(&connect_req, + &pipe_client, + name, + sizeof(name), + 0, + (uv_connect_cb) abort)); + uv_close((uv_handle_t*) &pipe_client, pipe_close_cb); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(2, pipe_close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; #endif From 2f1614b1286f53b3b2ab96a15a525cb25462ba9a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 6 Jun 2023 17:08:36 +0200 Subject: [PATCH 387/713] unix,win: add UV_PIPE_NO_TRUNCATE flag (#4040) Libuv's default behavior is to truncate long Unix socket paths. The flag tells it to return an error instead. Fixes: https://github.com/libuv/libuv/issues/4036 --- docs/src/pipe.rst | 18 ++++++++++++------ include/uv.h | 4 ++++ src/unix/pipe.c | 12 ++++++++++-- src/win/pipe.c | 16 ++++++++++++++-- test/test-list.h | 2 ++ test/test-pipe-bind-error.c | 24 ++++++++++++++++++++++++ 6 files changed, 66 insertions(+), 10 deletions(-) diff --git a/docs/src/pipe.rst b/docs/src/pipe.rst index 9d95b206a97..4abdc65e715 100644 --- a/docs/src/pipe.rst +++ b/docs/src/pipe.rst @@ -68,15 +68,18 @@ API Bind the pipe to a file path (Unix) or a name (Windows). - ``flags`` must be zero. Returns ``UV_EINVAL`` for unsupported flags - without performing the bind operation. + ``flags`` must be zero or ``UV_PIPE_NO_TRUNCATE``. Returns ``UV_EINVAL`` + for unsupported flags without performing the bind operation. Supports Linux abstract namespace sockets. ``namelen`` must include the leading nul byte but not the trailing nul byte. + .. versionadded:: 1.46.0 + .. note:: Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, - typically between 92 and 108 bytes. + typically between 92 and 108 bytes, unless the ``UV_PIPE_NO_TRUNCATE`` + flag is specified, in which case an ``UV_EINVAL`` error is returned. .. c:function:: void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) @@ -95,15 +98,18 @@ API Connect to the Unix domain socket or the Windows named pipe. - ``flags`` must be zero. Returns ``UV_EINVAL`` for unsupported flags - without performing the connect operation. + ``flags`` must be zero or ``UV_PIPE_NO_TRUNCATE``. Returns ``UV_EINVAL`` + for unsupported flags without performing the connect operation. Supports Linux abstract namespace sockets. ``namelen`` must include the leading nul byte but not the trailing nul byte. + .. versionadded:: 1.46.0 + .. note:: Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, - typically between 92 and 108 bytes. + typically between 92 and 108 bytes, unless the ``UV_PIPE_NO_TRUNCATE`` + flag is specified, in which case an ``UV_EINVAL`` error is returned. .. c:function:: int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) diff --git a/include/uv.h b/include/uv.h index 0f624f4d7f7..f68ff083b04 100644 --- a/include/uv.h +++ b/include/uv.h @@ -807,6 +807,10 @@ inline int uv_tty_set_mode(uv_tty_t* handle, int mode) { UV_EXTERN uv_handle_type uv_guess_handle(uv_file file); +enum { + UV_PIPE_NO_TRUNCATE = 1u << 0 +}; + /* * uv_pipe_t is a subclass of uv_stream_t. * diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 823deb3d975..d332f351830 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -56,7 +56,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, pipe_fname = NULL; - if (flags != 0) + if (flags & ~UV_PIPE_NO_TRUNCATE) return UV_EINVAL; if (name == NULL) @@ -71,6 +71,10 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; #endif + if (flags & UV_PIPE_NO_TRUNCATE) + if (namelen > sizeof(saddr.sun_path)) + return UV_EINVAL; + /* Truncate long paths. Documented behavior. */ if (namelen > sizeof(saddr.sun_path)) namelen = sizeof(saddr.sun_path); @@ -221,7 +225,7 @@ int uv_pipe_connect2(uv_connect_t* req, int err; int r; - if (flags != 0) + if (flags & ~UV_PIPE_NO_TRUNCATE) return UV_EINVAL; if (name == NULL) @@ -236,6 +240,10 @@ int uv_pipe_connect2(uv_connect_t* req, return UV_EINVAL; #endif + if (flags & UV_PIPE_NO_TRUNCATE) + if (namelen > sizeof(saddr.sun_path)) + return UV_EINVAL; + /* Truncate long paths. Documented behavior. */ if (namelen > sizeof(saddr.sun_path)) namelen = sizeof(saddr.sun_path); diff --git a/src/win/pipe.c b/src/win/pipe.c index a3daa3b7a18..f0cac382256 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -706,7 +706,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, int i, err, nameSize; uv_pipe_accept_t* req; - if (flags != 0) { + if (flags & ~UV_PIPE_NO_TRUNCATE) { return UV_EINVAL; } @@ -722,6 +722,12 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; } + if (flags & UV_PIPE_NO_TRUNCATE) { + if (namelen > 256) { + return UV_EINVAL; + } + } + if (handle->flags & UV_HANDLE_BOUND) { return UV_EINVAL; } @@ -859,7 +865,7 @@ int uv_pipe_connect2(uv_connect_t* req, HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; - if (flags != 0) { + if (flags & ~UV_PIPE_NO_TRUNCATE) { return UV_EINVAL; } @@ -875,6 +881,12 @@ int uv_pipe_connect2(uv_connect_t* req, return UV_EINVAL; } + if (flags & UV_PIPE_NO_TRUNCATE) { + if (namelen > 256) { + return UV_EINVAL; + } + } + UV_REQ_INIT(req, UV_CONNECT); req->handle = (uv_stream_t*) handle; req->cb = cb; diff --git a/test/test-list.h b/test/test-list.h index 6da7812360a..b2c88170051 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -198,6 +198,7 @@ TEST_DECLARE (pipe_connect_close_multiple) TEST_DECLARE (pipe_connect_multiple) TEST_DECLARE (pipe_listen_without_bind) TEST_DECLARE (pipe_bind_or_listen_error_after_close) +TEST_DECLARE (pipe_overlong_path) TEST_DECLARE (pipe_connect_bad_name) TEST_DECLARE (pipe_connect_to_file) TEST_DECLARE (pipe_connect_on_prepare) @@ -799,6 +800,7 @@ TASK_LIST_START TEST_ENTRY (pipe_connect_multiple) TEST_ENTRY (pipe_listen_without_bind) TEST_ENTRY (pipe_bind_or_listen_error_after_close) + TEST_ENTRY (pipe_overlong_path) TEST_ENTRY (pipe_getsockname) TEST_ENTRY (pipe_getsockname_abstract) TEST_ENTRY (pipe_getsockname_blocking) diff --git a/test/test-pipe-bind-error.c b/test/test-pipe-bind-error.c index 88ece6ba5d8..f8626302a1d 100644 --- a/test/test-pipe-bind-error.c +++ b/test/test-pipe-bind-error.c @@ -153,3 +153,27 @@ TEST_IMPL(pipe_bind_or_listen_error_after_close) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } + +TEST_IMPL(pipe_overlong_path) { + char path[512]; + uv_pipe_t pipe; + uv_connect_t req; + + memset(path, '@', sizeof(path)); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe, 0)); + ASSERT_EQ(UV_EINVAL, + uv_pipe_bind2(&pipe, path, sizeof(path), UV_PIPE_NO_TRUNCATE)); + ASSERT_EQ(UV_EINVAL, + uv_pipe_connect2(&req, + &pipe, + path, + sizeof(path), + UV_PIPE_NO_TRUNCATE, + (uv_connect_cb) abort)); + uv_close((uv_handle_t*) &pipe, NULL); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; + +} From 7ada448d18bea9e6ab1219d31f048d133a484898 Mon Sep 17 00:00:00 2001 From: liuxiang88 <94350585+liuxiang88@users.noreply.github.com> Date: Fri, 16 Jun 2023 16:25:25 +0800 Subject: [PATCH 388/713] unix: add loongarch support (#4054) Signed-off-by: liuxiang --- include/uv/unix.h | 2 ++ src/unix/linux.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/uv/unix.h b/include/uv/unix.h index 7944eff2e4b..09f88a56742 100644 --- a/include/uv/unix.h +++ b/include/uv/unix.h @@ -417,6 +417,8 @@ typedef struct { # define UV_FS_O_DIRECT 0x04000 #elif defined(__linux__) && defined(__x86_64__) # define UV_FS_O_DIRECT 0x04000 +#elif defined(__linux__) && defined(__loongarch__) +# define UV_FS_O_DIRECT 0x04000 #elif defined(O_DIRECT) # define UV_FS_O_DIRECT O_DIRECT #else diff --git a/src/unix/linux.c b/src/unix/linux.c index 77dac84bfbe..29af6c077dd 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1615,6 +1615,8 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) { static const char model_marker[] = "CPU part\t: "; #elif defined(__mips__) static const char model_marker[] = "cpu model\t\t: "; +#elif defined(__loongarch__) + static const char model_marker[] = "cpu family\t\t: "; #else static const char model_marker[] = "model name\t: "; #endif From 4002231bd9b5769222de63c4a82f5d01faf00f6a Mon Sep 17 00:00:00 2001 From: "Jeffrey H. Johnson" Date: Fri, 16 Jun 2023 08:29:26 +0000 Subject: [PATCH 389/713] doc: add DPS8M to LINKS.md (#4052) --- LINKS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LINKS.md b/LINKS.md index c2d79f8bb7a..3e5800747bc 100644 --- a/LINKS.md +++ b/LINKS.md @@ -6,7 +6,8 @@ * [clearskies_core](https://github.com/larroy/clearskies_core): Clearskies file synchronization program. (C++11) * [CMake](https://cmake.org) open-source, cross-platform family of tools designed to build, test and package software * [Cocos-Engine](https://github.com/cocos/cocos-engine): The runtime framework for Cocos Creator editor. -* [Coherence](https://github.com/liesware/coherence/): Cryptographic server for modern web apps. +* [Coherence](https://github.com/liesware/coherence/): Cryptographic server for modern web apps. +* [DPS8M](https://dps8m.gitlab.io): GE ∕ Honeywell ∕ Bull DPS‑8/M and 6180/L68 mainframe simulator. * [DPS-For-IoT](https://github.com/intel/dps-for-iot/wiki): Fully distributed publish/subscribe protocol. * [HashLink](https://github.com/HaxeFoundation/hashlink): Haxe run-time with libuv support included. * [Haywire](https://github.com/kellabyte/Haywire): Asynchronous HTTP server. From 6a9e4293d8fc73ecbbf3b5ad5c6b0611f2ab182d Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Fri, 16 Jun 2023 08:27:39 -0500 Subject: [PATCH 390/713] include: add EUNATCH errno mapping (#4047) add EUNATCH errno mapping --- docs/src/errors.rst | 3 +++ include/uv.h | 1 + include/uv/errno.h | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/docs/src/errors.rst b/docs/src/errors.rst index c7240f3546f..a2e94d96a6e 100644 --- a/docs/src/errors.rst +++ b/docs/src/errors.rst @@ -339,6 +339,9 @@ Error constants socket type not supported +.. c:macro:: UV_EUNATCH + + protocol driver not attached API --- diff --git a/include/uv.h b/include/uv.h index f68ff083b04..02397dd0fdd 100644 --- a/include/uv.h +++ b/include/uv.h @@ -156,6 +156,7 @@ struct uv__queue { XX(EILSEQ, "illegal byte sequence") \ XX(ESOCKTNOSUPPORT, "socket type not supported") \ XX(ENODATA, "no data available") \ + XX(EUNATCH, "protocol driver not attached") \ #define UV_HANDLE_TYPE_MAP(XX) \ XX(ASYNC, async) \ diff --git a/include/uv/errno.h b/include/uv/errno.h index 648e493d0e7..127278ef916 100644 --- a/include/uv/errno.h +++ b/include/uv/errno.h @@ -468,4 +468,10 @@ # define UV__ENODATA (-4024) #endif +#if defined(EUNATCH) && !defined(_WIN32) +# define UV__EUNATCH UV__ERR(EUNATCH) +#else +# define UV__EUNATCH (-4023) +#endif + #endif /* UV_ERRNO_H_ */ From 24d1d0802d2c6ff6d0b2e556c0c2b1a5ebf33493 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Wed, 14 Jun 2023 10:25:55 -0600 Subject: [PATCH 391/713] src: don't run timers if loop is stopped/unref'd (#4048) The initial run of timers shouldn't happen if uv_stop() has been run before uv_run() was called, and for backwards compatibility they also shouldn't run if they have been unref'd before calling uv_run(). --- src/unix/core.c | 5 ++--- src/win/core.c | 5 ++--- test/test-list.h | 4 ++++ test/test-loop-stop.c | 11 +++++++++++ test/test-timer.c | 12 ++++++++++++ 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 4db2b0afab7..0756364fff8 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -424,9 +424,8 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { * while loop for UV_RUN_DEFAULT. Otherwise timers only need to be executed * once, which should be done after polling in order to maintain proper * execution order of the conceptual event loop. */ - if (mode == UV_RUN_DEFAULT) { - if (r) - uv__update_time(loop); + if (mode == UV_RUN_DEFAULT && r != 0 && loop->stop_flag == 0) { + uv__update_time(loop); uv__run_timers(loop); } diff --git a/src/win/core.c b/src/win/core.c index 2ae8aa7da9b..e9885a0f1ff 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -629,9 +629,8 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { * while loop for UV_RUN_DEFAULT. Otherwise timers only need to be executed * once, which should be done after polling in order to maintain proper * execution order of the conceptual event loop. */ - if (mode == UV_RUN_DEFAULT) { - if (r) - uv_update_time(loop); + if (mode == UV_RUN_DEFAULT && r != 0 && loop->stop_flag == 0) { + uv_update_time(loop); uv__run_timers(loop); } diff --git a/test/test-list.h b/test/test-list.h index b2c88170051..0d385f21240 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -29,6 +29,7 @@ TEST_DECLARE (loop_alive) TEST_DECLARE (loop_close) TEST_DECLARE (loop_instant_close) TEST_DECLARE (loop_stop) +TEST_DECLARE (loop_stop_before_run) TEST_DECLARE (loop_update_time) TEST_DECLARE (loop_backend_timeout) TEST_DECLARE (loop_configure) @@ -233,6 +234,7 @@ TEST_DECLARE (timer_null_callback) TEST_DECLARE (timer_early_check) TEST_DECLARE (timer_no_double_call_once) TEST_DECLARE (timer_no_double_call_nowait) +TEST_DECLARE (timer_no_run_on_unref) TEST_DECLARE (idle_starvation) TEST_DECLARE (idle_check) TEST_DECLARE (loop_handles) @@ -573,6 +575,7 @@ TASK_LIST_START TEST_ENTRY (loop_close) TEST_ENTRY (loop_instant_close) TEST_ENTRY (loop_stop) + TEST_ENTRY (loop_stop_before_run) TEST_ENTRY (loop_update_time) TEST_ENTRY (loop_backend_timeout) TEST_ENTRY (loop_configure) @@ -846,6 +849,7 @@ TASK_LIST_START TEST_ENTRY (timer_early_check) TEST_ENTRY (timer_no_double_call_once) TEST_ENTRY (timer_no_double_call_nowait) + TEST_ENTRY (timer_no_run_on_unref) TEST_ENTRY (idle_starvation) TEST_ENTRY (idle_check) diff --git a/test/test-loop-stop.c b/test/test-loop-stop.c index 02aa12f1a83..981d20d1099 100644 --- a/test/test-loop-stop.c +++ b/test/test-loop-stop.c @@ -70,3 +70,14 @@ TEST_IMPL(loop_stop) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } + + +TEST_IMPL(loop_stop_before_run) { + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, (uv_timer_cb) abort, 0, 0)); + uv_stop(uv_default_loop()); + ASSERT_NE(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} diff --git a/test/test-timer.c b/test/test-timer.c index eb54bb25f0c..2488f14c204 100644 --- a/test/test-timer.c +++ b/test/test-timer.c @@ -407,3 +407,15 @@ TEST_IMPL(timer_no_double_call_nowait) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } + +TEST_IMPL(timer_no_run_on_unref) { + uv_timer_t timer_handle; + + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, (uv_timer_cb) abort, 0, 0)); + uv_unref((uv_handle_t*) &timer_handle); + ASSERT_EQ(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} From dde50f0e22f74439e14e4ac40dbab49aba5d1ba0 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 19 Jun 2023 20:16:39 +0200 Subject: [PATCH 392/713] win: fix -Wpointer-to-int-cast warning --- src/win/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/fs.c b/src/win/fs.c index 9d0614f2c66..fc209c54f47 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -2063,7 +2063,7 @@ INLINE static int fs__fstat_handle(int fd, HANDLE handle, uv_stat_t* statbuf) { statbuf->st_mode = file_type == UV_TTY ? _S_IFCHR : _S_IFIFO; statbuf->st_nlink = 1; statbuf->st_rdev = (file_type == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE) << 16; - statbuf->st_ino = (uint64_t) handle; + statbuf->st_ino = (uintptr_t) handle; return 0; /* If file type is unknown it is an error. */ From 9179888c2bd5833024a1d0c0e9738735633f3113 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 19 Jun 2023 20:19:17 +0200 Subject: [PATCH 393/713] test,win: fix -Wunused-variable warning --- test/test-get-passwd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test-get-passwd.c b/test/test-get-passwd.c index d046e40c6e8..29a2bd1243d 100644 --- a/test/test-get-passwd.c +++ b/test/test-get-passwd.c @@ -120,6 +120,7 @@ TEST_IMPL(get_passwd2) { #ifdef _WIN32 ASSERT_EQ(r, UV_ENOTSUP); + (void) &len; #else ASSERT_EQ(r, 0); @@ -179,6 +180,7 @@ TEST_IMPL(get_group) { #ifdef _WIN32 ASSERT_EQ(r, UV_ENOTSUP); + (void) &len; #else ASSERT_EQ(r, 0); From 2bf97f123f3936a61dbaa723bd6654f716fc1fd8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 19 Jun 2023 20:21:54 +0200 Subject: [PATCH 394/713] test,win: fix -Wformat warning --- test/test-spawn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-spawn.c b/test/test-spawn.c index 182cf5ec3eb..5e84dcdbb11 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1108,7 +1108,7 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) { /* Create a pipe that'll cause a collision. */ snprintf(name, sizeof(name), - "\\\\.\\pipe\\uv\\%p-%d", + "\\\\.\\pipe\\uv\\%p-%lu", &out, GetCurrentProcessId()); pipe_handle = CreateNamedPipeA(name, From 1752791c9ea89dbf54e2a20a9d9f899119a2d179 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 20 Jun 2023 13:01:12 +0200 Subject: [PATCH 395/713] linux: work around io_uring IORING_OP_CLOSE bug (#4059) Work around a poorly understood bug in older kernels where closing a file descriptor pointing to /foo/bar results in ETXTBSY errors when trying to execve("/foo/bar") later on. The bug seems to have been fixed somewhere between 5.15.85 and 5.15.90. I couldn't pinpoint the responsible commit but good candidates are the several data race fixes. Interestingly, it seems to manifest only when running under Docker so the possibility of a Docker bug can't be completely ruled out either. This commit moves uv__kernel_version() from fs.c to linux.c because the latter now uses it more than the former. Fixes: https://github.com/nodejs/node/issues/48444 --- src/unix/fs.c | 26 -------------------------- src/unix/linux.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 80b6a23970d..17c2d8faae2 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -57,7 +57,6 @@ #if defined(__linux__) # include -# include #endif #if defined(__sun) @@ -899,31 +898,6 @@ static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) { #ifdef __linux__ -unsigned uv__kernel_version(void) { - static _Atomic unsigned cached_version; - struct utsname u; - unsigned version; - unsigned major; - unsigned minor; - unsigned patch; - - version = atomic_load_explicit(&cached_version, memory_order_relaxed); - if (version != 0) - return version; - - if (-1 == uname(&u)) - return 0; - - if (3 != sscanf(u.release, "%u.%u.%u", &major, &minor, &patch)) - return 0; - - version = major * 65536 + minor * 256 + patch; - atomic_store_explicit(&cached_version, version, memory_order_relaxed); - - return version; -} - - /* Pre-4.20 kernels have a bug where CephFS uses the RADOS copy-from command * in copy_file_range() when it shouldn't. There is no workaround except to * fall back to a regular copy. diff --git a/src/unix/linux.c b/src/unix/linux.c index 29af6c077dd..48b9c2c43e1 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -309,6 +310,31 @@ static struct watcher_root* uv__inotify_watchers(uv_loop_t* loop) { } +unsigned uv__kernel_version(void) { + static _Atomic unsigned cached_version; + struct utsname u; + unsigned version; + unsigned major; + unsigned minor; + unsigned patch; + + version = atomic_load_explicit(&cached_version, memory_order_relaxed); + if (version != 0) + return version; + + if (-1 == uname(&u)) + return 0; + + if (3 != sscanf(u.release, "%u.%u.%u", &major, &minor, &patch)) + return 0; + + version = major * 65536 + minor * 256 + patch; + atomic_store_explicit(&cached_version, version, memory_order_relaxed); + + return version; +} + + ssize_t uv__fs_copy_file_range(int fd_in, off_t* off_in, @@ -731,6 +757,17 @@ int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req) { struct uv__io_uring_sqe* sqe; struct uv__iou* iou; + /* Work around a poorly understood bug in older kernels where closing a file + * descriptor pointing to /foo/bar results in ETXTBSY errors when trying to + * execve("/foo/bar") later on. The bug seems to have been fixed somewhere + * between 5.15.85 and 5.15.90. I couldn't pinpoint the responsible commit + * but good candidates are the several data race fixes. Interestingly, it + * seems to manifest only when running under Docker so the possibility of + * a Docker bug can't be completely ruled out either. Yay, computers. + */ + if (uv__kernel_version() < /* 5.15.90 */ 0x050F5A) + return 0; + iou = &uv__get_internal_fields(loop)->iou; sqe = uv__iou_get_sqe(iou, loop, req); From 4b0fe81758501b021e07ac1b22e15f4f411d0673 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 20 Jun 2023 22:30:31 +0200 Subject: [PATCH 396/713] win: remove unused functions (#4063) --- src/win/internal.h | 14 ++------------ src/win/tty.c | 20 -------------------- 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/src/win/internal.h b/src/win/internal.h index bda321c17dc..9672fbc6826 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -168,18 +168,8 @@ void uv__process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, uv_req_t* req); void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, uv_write_t* req); -/* - * uv__process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working - * TODO: find a way to remove it - */ -void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, - uv_req_t* raw_req); -/* - * uv__process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working - * TODO: find a way to remove it - */ -void uv__process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, - uv_connect_t* req); +#define uv__process_tty_accept_req(loop, handle, req) abort() +#define uv__process_tty_connect_req(loop, handle, req) abort() void uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown_t* req); diff --git a/src/win/tty.c b/src/win/tty.c index 60f249b6a2a..7e1f15544b1 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -2298,26 +2298,6 @@ void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { } -/* - * uv__process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working - * TODO: find a way to remove it - */ -void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, - uv_req_t* raw_req) { - abort(); -} - - -/* - * uv__process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working - * TODO: find a way to remove it - */ -void uv__process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, - uv_connect_t* req) { - abort(); -} - - int uv_tty_reset_mode(void) { /* Not necessary to do anything. */ return 0; From 3e0b846bdb3afb3730d8fd37f28445438e0eef9e Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Tue, 28 Mar 2023 14:47:15 -0600 Subject: [PATCH 397/713] bench: add bench to check uv_loop_alive (#4065 1/2) --- test/benchmark-list.h | 2 ++ test/benchmark-loop-count.c | 42 +++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/test/benchmark-list.h b/test/benchmark-list.h index 1ab8f25813f..901e5ffa79f 100644 --- a/test/benchmark-list.h +++ b/test/benchmark-list.h @@ -22,6 +22,7 @@ BENCHMARK_DECLARE (sizes) BENCHMARK_DECLARE (loop_count) BENCHMARK_DECLARE (loop_count_timed) +BENCHMARK_DECLARE (loop_alive) BENCHMARK_DECLARE (ping_pongs) BENCHMARK_DECLARE (ping_udp1) BENCHMARK_DECLARE (ping_udp10) @@ -89,6 +90,7 @@ TASK_LIST_START BENCHMARK_ENTRY (sizes) BENCHMARK_ENTRY (loop_count) BENCHMARK_ENTRY (loop_count_timed) + BENCHMARK_ENTRY (loop_alive) BENCHMARK_ENTRY (ping_pongs) BENCHMARK_HELPER (ping_pongs, tcp4_echo_server) diff --git a/test/benchmark-loop-count.c b/test/benchmark-loop-count.c index 4aa39867bb1..72f25b56ba5 100644 --- a/test/benchmark-loop-count.c +++ b/test/benchmark-loop-count.c @@ -26,6 +26,7 @@ #include #define NUM_TICKS (2 * 1000 * 1000) +#define NUM_TICKS2 (2 * 1000 * 1000 * 100) static unsigned long ticks; static uv_idle_t idle_handle; @@ -37,6 +38,19 @@ static void idle_cb(uv_idle_t* handle) { uv_idle_stop(handle); } +static void idle_alive_cb(uv_idle_t* handle) { + int ticks = 0; + + while (++ticks < NUM_TICKS2) { + int r = uv_loop_alive(handle->loop); + if (r == 0) + abort(); + } + + *(int*)handle->data = ticks; + uv_idle_stop(handle); +} + static void idle2_cb(uv_idle_t* handle) { ticks++; @@ -90,3 +104,31 @@ BENCHMARK_IMPL(loop_count_timed) { MAKE_VALGRIND_HAPPY(loop); return 0; } + +/* Measure the performance of running uv_loop_alive(). Adding this so we can get + * some sort of metric for the impact of switching active_reqs.count to use + * atomics. No other code sits in a hot path. */ +BENCHMARK_IMPL(loop_alive) { + uv_loop_t* loop = uv_default_loop(); + int ticks = 0; + uint64_t ns; + + uv_idle_init(loop, &idle_handle); + idle_handle.data = &ticks; + uv_idle_start(&idle_handle, idle_alive_cb); + + ns = uv_hrtime(); + uv_run(loop, UV_RUN_DEFAULT); + ns = uv_hrtime() - ns; + + ASSERT_EQ(ticks, NUM_TICKS2); + + fprintf(stderr, "loop_alive: %d ticks in %.2fs (%.0f/s)\n", + NUM_TICKS2, + ns / 1e9, + NUM_TICKS2 / (ns / 1e9)); + fflush(stderr); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} From 6df5a72151e20036f821c87e9a9f77d098b383ef Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Thu, 6 Apr 2023 14:36:21 -0600 Subject: [PATCH 398/713] test: add uv_cancel test for threadpool (#4065 2/2) Check that uv_cancel() returns UV_EBUSY when called while the uv_work_cb is being executed. --- test/test-list.h | 2 ++ test/test-threadpool-cancel.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/test/test-list.h b/test/test-list.h index 0d385f21240..78ff9c2d162 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -454,6 +454,7 @@ TEST_DECLARE (threadpool_cancel_random) TEST_DECLARE (threadpool_cancel_work) TEST_DECLARE (threadpool_cancel_fs) TEST_DECLARE (threadpool_cancel_single) +TEST_DECLARE (threadpool_cancel_when_busy) TEST_DECLARE (thread_local_storage) TEST_DECLARE (thread_stack_size) TEST_DECLARE (thread_stack_size_explicit) @@ -1143,6 +1144,7 @@ TASK_LIST_START TEST_ENTRY (threadpool_cancel_work) TEST_ENTRY (threadpool_cancel_fs) TEST_ENTRY (threadpool_cancel_single) + TEST_ENTRY (threadpool_cancel_when_busy) TEST_ENTRY (thread_local_storage) TEST_ENTRY (thread_stack_size) TEST_ENTRY (thread_stack_size_explicit) diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index 07634e3f3fe..fed0b07a3ca 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -378,3 +378,36 @@ TEST_IMPL(threadpool_cancel_single) { MAKE_VALGRIND_HAPPY(loop); return 0; } + + +static void after_busy_cb(uv_work_t* req, int status) { + ASSERT_OK(status); + done_cb_called++; +} + +static void busy_cb(uv_work_t* req) { + uv_sem_post((uv_sem_t*) req->data); + /* Assume that calling uv_cancel() takes less than 10ms. */ + uv_sleep(10); +} + +TEST_IMPL(threadpool_cancel_when_busy) { + uv_sem_t sem_lock; + uv_work_t req; + + req.data = &sem_lock; + + ASSERT_OK(uv_sem_init(&sem_lock, 0)); + ASSERT_OK(uv_queue_work(uv_default_loop(), &req, busy_cb, after_busy_cb)); + + uv_sem_wait(&sem_lock); + + ASSERT_EQ(uv_cancel((uv_req_t*) &req), UV_EBUSY); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(done_cb_called, 1); + + uv_sem_destroy(&sem_lock); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} From ca544ed6fcbd115a3c6308dbdb9eb9535d1ddcde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=98=8E?= <7737673+caobug@users.noreply.github.com> Date: Fri, 23 Jun 2023 17:09:53 +0800 Subject: [PATCH 399/713] unix: skip prohibited syscalls on tvOS and watchOS (#4043) --- src/unix/process.c | 12 ++++---- test/runner-unix.c | 10 +++++++ test/test-fork.c | 36 ++++++++++++++++++++++++ test/test-pipe-close-stdout-read-stdin.c | 12 +++++++- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index dbb4a1dc684..dd58c18d9b9 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -183,6 +183,11 @@ void uv__wait_children(uv_loop_t* loop) { * Used for initializing stdio streams like options.stdin_stream. Returns * zero on success. See also the cleanup section in uv_spawn(). */ +#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) +/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be + * avoided. Since this isn't called on those targets, the function + * doesn't even need to be defined for them. + */ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { int mask; int fd; @@ -269,11 +274,6 @@ static void uv__write_errno(int error_fd) { } -#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) -/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be - * avoided. Since this isn't called on those targets, the function - * doesn't even need to be defined for them. - */ static void uv__process_child_init(const uv_process_options_t* options, int stdio_count, int (*pipes)[2], @@ -405,7 +405,6 @@ static void uv__process_child_init(const uv_process_options_t* options, uv__write_errno(error_fd); } -#endif #if defined(__APPLE__) @@ -952,6 +951,7 @@ static int uv__spawn_and_init_child( return err; } +#endif /* ISN'T TARGET_OS_TV || TARGET_OS_WATCH */ int uv_spawn(uv_loop_t* loop, uv_process_t* process, diff --git a/test/runner-unix.c b/test/runner-unix.c index 09191dbdaa1..81560add820 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -40,6 +40,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + extern char** environ; static void closefd(int fd) { @@ -131,7 +135,11 @@ int process_start(char* name, char* part, process_info_t* p, int is_helper) { p->terminated = 0; p->status = 0; +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + pid = -1; +#else pid = fork(); +#endif if (pid < 0) { perror("fork"); @@ -144,7 +152,9 @@ int process_start(char* name, char* part, process_info_t* p, int is_helper) { closefd(pipefd[0]); dup2(stdout_fd, STDOUT_FILENO); dup2(stdout_fd, STDERR_FILENO); +#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) execve(args[0], args, environ); +#endif perror("execve()"); _exit(127); } diff --git a/test/test-fork.c b/test/test-fork.c index 7a6eb9c411b..29ed132a488 100644 --- a/test/test-fork.c +++ b/test/test-fork.c @@ -27,6 +27,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + #include "uv.h" #include "task.h" @@ -100,7 +104,11 @@ TEST_IMPL(fork_timer) { pid_t child_pid; run_timer_loop_once(); +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + child_pid = -1; +#else child_pid = fork(); +#endif ASSERT(child_pid != -1); if (child_pid != 0) { @@ -132,7 +140,11 @@ TEST_IMPL(fork_socketpair) { /* Create the server watcher in the parent, use it in the child. */ ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + child_pid = -1; +#else child_pid = fork(); +#endif ASSERT(child_pid != -1); if (child_pid != 0) { @@ -181,7 +193,11 @@ TEST_IMPL(fork_socketpair_started) { */ ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + child_pid = -1; +#else child_pid = fork(); +#endif ASSERT(child_pid != -1); if (child_pid != 0) { @@ -245,7 +261,11 @@ TEST_IMPL(fork_signal_to_child) { ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle)); ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1)); +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + child_pid = -1; +#else child_pid = fork(); +#endif ASSERT(child_pid != -1); if (child_pid != 0) { @@ -297,7 +317,11 @@ TEST_IMPL(fork_signal_to_child_closed) { ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle)); ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1)); +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + child_pid = -1; +#else child_pid = fork(); +#endif ASSERT(child_pid != -1); if (child_pid != 0) { @@ -463,7 +487,11 @@ static int _do_fork_fs_events_child(int file_or_dir) { /* Watch in the parent, prime the loop and/or threads. */ assert_watch_file_current_dir(uv_default_loop(), file_or_dir); +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + child_pid = -1; +#else child_pid = fork(); +#endif ASSERT(child_pid != -1); if (child_pid != 0) { @@ -569,7 +597,11 @@ TEST_IMPL(fork_fs_events_file_parent_child) { r = uv_timer_init(loop, &timer); ASSERT(r == 0); +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + child_pid = -1; +#else child_pid = fork(); +#endif ASSERT(child_pid != -1); if (child_pid != 0) { /* parent */ @@ -654,7 +686,11 @@ TEST_IMPL(fork_threadpool_queue_work_simple) { /* Prime the pool and default loop. */ assert_run_work(uv_default_loop()); +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + child_pid = -1; +#else child_pid = fork(); +#endif ASSERT(child_pid != -1); if (child_pid != 0) { diff --git a/test/test-pipe-close-stdout-read-stdin.c b/test/test-pipe-close-stdout-read-stdin.c index e0f864e9cdf..a9295f0aa59 100644 --- a/test/test-pipe-close-stdout-read-stdin.c +++ b/test/test-pipe-close-stdout-read-stdin.c @@ -26,6 +26,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + #include "uv.h" #include "task.h" @@ -58,8 +62,14 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { r = pipe(fd); ASSERT(r == 0); + +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + pid = -1; +#else + pid = fork(); +#endif - if ((pid = fork()) == 0) { + if (pid == 0) { /* * Make the read side of the pipe our stdin. * The write side will be closed by the parent process. From c8fad2ac099ade0e07e567cc8b8304d9e93a4a06 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 23 Jun 2023 13:17:37 +0200 Subject: [PATCH 400/713] unix,fs: make no_pwritev access thread-safe (#4066) --- src/unix/fs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 17c2d8faae2..e9e323e7481 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1157,7 +1157,7 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) { static ssize_t uv__fs_write(uv_fs_t* req) { #if defined(__linux__) - static int no_pwritev; + static _Atomic int no_pwritev; #endif ssize_t r; @@ -1186,7 +1186,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) { r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); #else # if defined(__linux__) - if (no_pwritev) retry: + if (atomic_load_explicit(&no_pwritev, memory_order_relaxed)) retry: # endif { r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off); @@ -1198,7 +1198,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) { req->nbufs, req->off); if (r == -1 && errno == ENOSYS) { - no_pwritev = 1; + atomic_store_explicit(&no_pwritev, 1, memory_order_relaxed); goto retry; } } From 7b43d70be4fe9c3f9003b189e62e4f86a6a88516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=98=8E?= <7737673+caobug@users.noreply.github.com> Date: Mon, 26 Jun 2023 19:47:48 +0800 Subject: [PATCH 401/713] unix: fix build for lower versions of Android (#4046) Available since Android N (API level 24): getgrgid_r, preadv, pwritev Refs: https://cs.android.com/android/platform/superproject/+/master:bionic/docs/status.md --- src/unix/core.c | 5 +++++ src/unix/fs.c | 17 +++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 0756364fff8..25c5181f370 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1271,6 +1271,10 @@ static int uv__getpwuid_r(uv_passwd_t *pwd, uid_t uid) { int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) { +#if defined(__ANDROID__) && __ANDROID_API__ < 24 + /* This function getgrgid_r() was added in Android N (level 24) */ + return UV_ENOSYS; +#else struct group gp; struct group* result; char* buf; @@ -1347,6 +1351,7 @@ int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) { uv__free(buf); return 0; +#endif } diff --git a/src/unix/fs.c b/src/unix/fs.c index e9e323e7481..6b051c124f2 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -55,6 +55,11 @@ # define HAVE_PREADV 0 #endif +/* preadv() and pwritev() were added in Android N (level 24) */ +#if defined(__linux__) && !(defined(__ANDROID__) && __ANDROID_API__ < 24) +# define TRY_PREADV 1 +#endif + #if defined(__linux__) # include #endif @@ -456,7 +461,7 @@ static ssize_t uv__fs_preadv(uv_file fd, static ssize_t uv__fs_read(uv_fs_t* req) { -#if defined(__linux__) +#if TRY_PREADV static _Atomic int no_preadv; #endif unsigned int iovmax; @@ -480,13 +485,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) { #if HAVE_PREADV result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); #else -# if defined(__linux__) +# if TRY_PREADV if (atomic_load_explicit(&no_preadv, memory_order_relaxed)) retry: # endif { result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off); } -# if defined(__linux__) +# if TRY_PREADV else { result = preadv(req->file, (struct iovec*) req->bufs, @@ -1156,7 +1161,7 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) { static ssize_t uv__fs_write(uv_fs_t* req) { -#if defined(__linux__) +#if TRY_PREADV static _Atomic int no_pwritev; #endif ssize_t r; @@ -1185,13 +1190,13 @@ static ssize_t uv__fs_write(uv_fs_t* req) { #if HAVE_PREADV r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); #else -# if defined(__linux__) +# if TRY_PREADV if (atomic_load_explicit(&no_pwritev, memory_order_relaxed)) retry: # endif { r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off); } -# if defined(__linux__) +# if TRY_PREADV else { r = pwritev(req->file, (struct iovec*) req->bufs, From f0bb7e40f0508bedf6fad33769b3f87bb8aedfa6 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 30 Jun 2023 18:31:51 +0000 Subject: [PATCH 402/713] 2023.06.30, Version 1.46.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.45.0: * Add SHA to ChangeLog (Santiago Gimeno) * misc: update readthedocs config (Jameson Nash) * test: remove erroneous RETURN_SKIP (Ben Noordhuis) * android: disable io_uring support (Ben Noordhuis) * linux: add some more iouring backed fs ops (Santiago Gimeno) * build: add autoconf option for disable-maintainer-mode (Jameson Nash) * fs: use WTF-8 on Windows (Stefan Karpinski) * unix,win: replace QUEUE with struct uv__queue (Ben Noordhuis) * linux: fs_read to use io_uring if iovcnt > IOV_MAX (Santiago Gimeno) * ios: fix uv_getrusage() ru_maxrss calculation (Ben Noordhuis) * include: update outdated code comment (Ben Noordhuis) * linux: support abstract unix sockets (Ben Noordhuis) * unix,win: add UV_PIPE_NO_TRUNCATE flag (Ben Noordhuis) * unix: add loongarch support (liuxiang88) * doc: add DPS8M to LINKS.md (Jeffrey H. Johnson) * include: add EUNATCH errno mapping (Abdirahim Musse) * src: don't run timers if loop is stopped/unref'd (Trevor Norris) * win: fix -Wpointer-to-int-cast warning (Ben Noordhuis) * test,win: fix -Wunused-variable warning (Ben Noordhuis) * test,win: fix -Wformat warning (Ben Noordhuis) * linux: work around io_uring IORING_OP_CLOSE bug (Ben Noordhuis) * win: remove unused functions (Ben Noordhuis) * bench: add bench to check uv_loop_alive (Trevor Norris) * test: add uv_cancel test for threadpool (Trevor Norris) * unix: skip prohibited syscalls on tvOS and watchOS (小明) * unix,fs: make no_pwritev access thread-safe (Santiago Gimeno) * unix: fix build for lower versions of Android (小明) --- AUTHORS | 6 +++++ ChangeLog | 59 ++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 8 +++--- 4 files changed, 70 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index b6860c6620f..9b89421c428 100644 --- a/AUTHORS +++ b/AUTHORS @@ -542,3 +542,9 @@ Lewis Russell sivadeilra cui fliter Mohammed Keyvanzadeh +Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> +Stefan Karpinski +liuxiang88 <94350585+liuxiang88@users.noreply.github.com> +Jeffrey H. Johnson +Abdirahim Musse <33973272+abmusse@users.noreply.github.com> +小明 <7737673+caobug@users.noreply.github.com> diff --git a/ChangeLog b/ChangeLog index 1b6f2eee10d..e2cd8825222 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,62 @@ +2023.06.30, Version 1.46.0 (Stable) + +Changes since version 1.45.0: + +* Add SHA to ChangeLog (Santiago Gimeno) + +* misc: update readthedocs config (Jameson Nash) + +* test: remove erroneous RETURN_SKIP (Ben Noordhuis) + +* android: disable io_uring support (Ben Noordhuis) + +* linux: add some more iouring backed fs ops (Santiago Gimeno) + +* build: add autoconf option for disable-maintainer-mode (Jameson Nash) + +* fs: use WTF-8 on Windows (Stefan Karpinski) + +* unix,win: replace QUEUE with struct uv__queue (Ben Noordhuis) + +* linux: fs_read to use io_uring if iovcnt > IOV_MAX (Santiago Gimeno) + +* ios: fix uv_getrusage() ru_maxrss calculation (Ben Noordhuis) + +* include: update outdated code comment (Ben Noordhuis) + +* linux: support abstract unix sockets (Ben Noordhuis) + +* unix,win: add UV_PIPE_NO_TRUNCATE flag (Ben Noordhuis) + +* unix: add loongarch support (liuxiang88) + +* doc: add DPS8M to LINKS.md (Jeffrey H. Johnson) + +* include: add EUNATCH errno mapping (Abdirahim Musse) + +* src: don't run timers if loop is stopped/unref'd (Trevor Norris) + +* win: fix -Wpointer-to-int-cast warning (Ben Noordhuis) + +* test,win: fix -Wunused-variable warning (Ben Noordhuis) + +* test,win: fix -Wformat warning (Ben Noordhuis) + +* linux: work around io_uring IORING_OP_CLOSE bug (Ben Noordhuis) + +* win: remove unused functions (Ben Noordhuis) + +* bench: add bench to check uv_loop_alive (Trevor Norris) + +* test: add uv_cancel test for threadpool (Trevor Norris) + +* unix: skip prohibited syscalls on tvOS and watchOS (小明) + +* unix,fs: make no_pwritev access thread-safe (Santiago Gimeno) + +* unix: fix build for lower versions of Android (小明) + + 2023.05.19, Version 1.45.0 (Stable), 96e05543f53b19d9642b4b0dd73b86ad3cea313e Changes since version 1.44.2: diff --git a/configure.ac b/configure.ac index 214754bfa05..deb083605de 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.45.1-dev], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.46.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 2d7309f0233..24fac8d8aa7 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 45 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 46 +#define UV_VERSION_PATCH 0 +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From ad523c20c7792c00c3175ece54354d89c09569e7 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 30 Jun 2023 18:31:51 +0000 Subject: [PATCH 403/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index e2cd8825222..ea597f66346 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2023.06.30, Version 1.46.0 (Stable) +2023.06.30, Version 1.46.0 (Stable), f0bb7e40f0508bedf6fad33769b3f87bb8aedfa6 Changes since version 1.45.0: From c5644368b56872c4044946c35fa91f09adfadcec Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 30 Jun 2023 22:58:52 +0200 Subject: [PATCH 404/713] Now working on version 1.46.1 Fixes: https://github.com/libuv/libuv/issues/4060 --- configure.ac | 2 +- include/uv/version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index deb083605de..a2c025851ac 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.46.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.46.1-dev], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 24fac8d8aa7..e586d037f1c 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 46 -#define UV_VERSION_PATCH 0 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 1 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 2f87d5c114dd628d611766a3347a11f77799f06c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 10 Jul 2023 10:37:38 +0200 Subject: [PATCH 405/713] test: fix license blurb (#4085) Fixes: https://github.com/libuv/libuv/issues/4080 --- test/test-thread-affinity.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test-thread-affinity.c b/test/test-thread-affinity.c index 2c9b696ec7a..239dce3cbc4 100644 --- a/test/test-thread-affinity.c +++ b/test/test-thread-affinity.c @@ -1,4 +1,22 @@ /* 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" From a939d643dd416e0705b56c0d551181859a56e4da Mon Sep 17 00:00:00 2001 From: Shuduo Sang Date: Thu, 13 Jul 2023 05:00:59 +0800 Subject: [PATCH 406/713] linux: fix harmless warn_unused_result warning (#4056) --- src/unix/linux.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 48b9c2c43e1..2880322594e 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1718,7 +1718,8 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) { return UV__ERR(errno); } - fgets(buf, sizeof(buf), fp); /* Skip first line. */ + if (NULL == fgets(buf, sizeof(buf), fp)) + abort(); for (;;) { memset(&t, 0, sizeof(t)); @@ -1729,7 +1730,8 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) { if (n != 7) break; - fgets(buf, sizeof(buf), fp); /* Skip rest of line. */ + if (NULL == fgets(buf, sizeof(buf), fp)) + abort(); if (cpu >= ARRAY_SIZE(*cpus)) continue; @@ -1809,7 +1811,8 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) { if (fp == NULL) continue; - fscanf(fp, "%llu", &(*cpus)[cpu].freq); + if (1 != fscanf(fp, "%llu", &(*cpus)[cpu].freq)) + abort(); fclose(fp); fp = NULL; } From 1230fad8f43824850dabeab06468ba5718d7aa44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=98=8E?= <7737673+caobug@users.noreply.github.com> Date: Thu, 13 Jul 2023 05:03:36 +0800 Subject: [PATCH 407/713] darwin: fix build warnings (#4073) --- src/unix/darwin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/darwin.c b/src/unix/darwin.c index 90790d701c4..5e764a65ee4 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -209,7 +209,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { if (cpuspeed == 0) /* If sysctl hw.cputype == CPU_TYPE_ARM64, the correct value is unavailable * from Apple, but we can hard-code it here to a plausible value. */ - cpuspeed = 2400000000; + cpuspeed = 2400000000U; if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus, (processor_info_array_t*)&info, @@ -235,7 +235,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { cpu_info->cpu_times.irq = 0; cpu_info->model = uv__strdup(model); - cpu_info->speed = cpuspeed/1000000; + cpu_info->speed = (int)(cpuspeed / 1000000); } vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type); From 50b53cbd0db8d4e7be06939a0976ff520e791d31 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 12 Jul 2023 23:33:49 +0200 Subject: [PATCH 408/713] linux: don't use io_uring on pre-5.10.186 kernels (#4093) Those kernels have a known resource consumption bug where the sqpoll thread busy-loops. Fixes: https://github.com/libuv/libuv/issues/4089 --- src/unix/linux.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 2880322594e..65fb847f65b 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -431,8 +431,14 @@ static int uv__use_io_uring(void) { use = atomic_load_explicit(&use_io_uring, memory_order_relaxed); if (use == 0) { + /* Older kernels have a bug where the sqpoll thread uses 100% CPU. */ + use = uv__kernel_version() >= /* 5.10.186 */ 0x050ABA ? 1 : -1; + + /* But users can still enable it if they so desire. */ val = getenv("UV_USE_IO_URING"); - use = val == NULL || atoi(val) ? 1 : -1; + if (val != NULL) + use = atoi(val) ? 1 : -1; + atomic_store_explicit(&use_io_uring, use, memory_order_relaxed); } From d09441ca03e399fe641da88624c8ea0476967187 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 13 Jul 2023 12:22:07 -0400 Subject: [PATCH 409/713] fs: fix WTF-8 decoding issue (#4092) We forgot to mask off the high bits from the first byte, so we ended up always failing the subsequent range check. Refs: #2970 Fixes: https://github.com/nodejs/node/issues/48673 --- src/win/fs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/win/fs.c b/src/win/fs.c index fc209c54f47..4fc13b04bda 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -176,9 +176,11 @@ static int32_t fs__decode_wtf8_char(const char** input) { if ((b4 & 0xC0) != 0x80) return -1; /* invalid: not a continuation byte */ code_point = (code_point << 6) | (b4 & 0x3F); - if (b1 <= 0xF4) + if (b1 <= 0xF4) { + code_point &= 0x1FFFFF; if (code_point <= 0x10FFFF) return code_point; /* four-byte character */ + } /* code point too large */ return -1; From 49d83c0301b0a6bdf6404ad4fcef588c8933b0ae Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 25 Jul 2023 15:58:08 +0200 Subject: [PATCH 410/713] test: enable disabled tcp_connect6_error_fault (#4103) The test was added in commit e3f2631127 from 2011 but it appears the author forgot to add it to the test list. The other test from that commit was enabled by yours truly in 2012 in 7447048981 but apparently I overlooked the second test as well. --- test/test-list.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test-list.h b/test/test-list.h index 78ff9c2d162..582ced60ae6 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -127,6 +127,7 @@ TEST_DECLARE (tcp_bind_writable_flags) TEST_DECLARE (tcp_bind_or_listen_error_after_close) TEST_DECLARE (tcp_listen_without_bind) TEST_DECLARE (tcp_connect_error_fault) +TEST_DECLARE (tcp_connect6_error_fault) TEST_DECLARE (tcp_connect_timeout) TEST_DECLARE (tcp_local_connect_timeout) TEST_DECLARE (tcp6_local_connect_timeout) @@ -724,6 +725,7 @@ TASK_LIST_START TEST_ENTRY (tcp_bind_or_listen_error_after_close) TEST_ENTRY (tcp_listen_without_bind) TEST_ENTRY (tcp_connect_error_fault) + TEST_ENTRY (tcp_connect6_error_fault) TEST_ENTRY (tcp_connect_timeout) TEST_ENTRY (tcp_local_connect_timeout) TEST_ENTRY (tcp6_local_connect_timeout) From 9c1de6e93f419b97ed6f384ee924708eb2b80f7b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 25 Jul 2023 16:48:04 +0200 Subject: [PATCH 411/713] test: enable disabled fs_link (#4104) This test was added in commit 060026ced from 2011 but its author forgot to actually enable it. --- test/test-list.h | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test-list.h b/test/test-list.h index 582ced60ae6..dfff2bbbc8b 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -1057,6 +1057,7 @@ TASK_LIST_START TEST_ENTRY (fs_unlink_archive_readonly) #endif TEST_ENTRY (fs_chown) + TEST_ENTRY (fs_link) TEST_ENTRY (fs_utime) TEST_ENTRY (fs_utime_round) TEST_ENTRY (fs_futime) From 55376b044b74db40772e8a6e24d67a8673998e02 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 25 Jul 2023 16:48:22 +0200 Subject: [PATCH 412/713] test: enable disabled spawn_same_stdout_stderr (#4105) This test was added in commit e403a2c486 from 2014 but its author forgot to enable it. --- test/test-list.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test-list.h b/test/test-list.h index dfff2bbbc8b..ca59890b8fa 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -322,6 +322,7 @@ TEST_DECLARE (spawn_detached) TEST_DECLARE (spawn_and_kill_with_std) TEST_DECLARE (spawn_and_ping) TEST_DECLARE (spawn_preserve_env) +TEST_DECLARE (spawn_same_stdout_stderr) TEST_DECLARE (spawn_setuid_fails) TEST_DECLARE (spawn_setgid_fails) TEST_DECLARE (spawn_stdout_to_file) @@ -979,6 +980,7 @@ TASK_LIST_START TEST_ENTRY (spawn_and_kill_with_std) TEST_ENTRY (spawn_and_ping) TEST_ENTRY (spawn_preserve_env) + TEST_ENTRY (spawn_same_stdout_stderr) TEST_ENTRY (spawn_setuid_fails) TEST_ENTRY (spawn_setgid_fails) TEST_ENTRY (spawn_stdout_to_file) From 30c3ef9f6feff054e6bc2734d448de34b284fa9b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 31 Jul 2023 23:40:59 +0200 Subject: [PATCH 413/713] linux: handle UNAME26 personality (#4109) --- src/unix/linux.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/unix/linux.c b/src/unix/linux.c index 65fb847f65b..eac18e86b04 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -328,6 +328,31 @@ unsigned uv__kernel_version(void) { if (3 != sscanf(u.release, "%u.%u.%u", &major, &minor, &patch)) return 0; + /* Handle it when the process runs under the UNAME26 personality: + * + * - kernels >= 3.x identify as 2.6.40+x + * - kernels >= 4.x identify as 2.6.60+x + * + * UNAME26 is a poorly conceived hack that doesn't let us distinguish + * between 4.x kernels and 5.x/6.x kernels so we conservatively assume + * that 2.6.60+x means 4.x. + * + * Fun fact of the day: it's technically possible to observe the actual + * kernel version for a brief moment because uname() first copies out the + * real release string before overwriting it with the backcompat string. + */ + if (major == 2 && minor == 6) { + if (patch >= 60) { + major = 4; + minor = patch - 60; + patch = 0; + } else if (patch >= 40) { + major = 3; + minor = patch - 40; + patch = 0; + } + } + version = major * 65536 + minor * 256 + patch; atomic_store_explicit(&cached_version, version, memory_order_relaxed); From 124d55c97019c3f0fc4a0f1e9a6d1dd051d5c3a5 Mon Sep 17 00:00:00 2001 From: Keith Winstein Date: Tue, 1 Aug 2023 14:30:20 -0700 Subject: [PATCH 414/713] build: move cmake_minimum_required version to 3.9 (#4111) CMake 3.27 warns that "Compatibility with CMake < 3.5 will be removed from a future version of CMake." (https://cmake.org/cmake/help/latest/release/3.27.html#deprecated-and-removed-features) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 93733dd0478..3e1797f514d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.9) if(POLICY CMP0091) cmake_policy(SET CMP0091 NEW) # Enable MSVC_RUNTIME_LIBRARY setting From e893cd682644e4b76589570251b18edbf957b81f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 3 Aug 2023 22:18:50 +0200 Subject: [PATCH 415/713] unix: set ipv6 scope id for link-local addresses (#4107) Link-local addresses (prefix fe80::/64) don't route unless you specify the network interface to use so make libuv do that. Fixes: https://github.com/nodejs/node/issues/48846 --- src/unix/tcp.c | 50 ++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ test/test-tcp-connect6-error.c | 35 ++++++++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index d6c848f4610..c225a57c4f5 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -27,6 +27,9 @@ #include #include +#include +#include +#include static int maybe_bind_socket(int fd) { union uv__sockaddr s; @@ -198,11 +201,50 @@ int uv__tcp_bind(uv_tcp_t* tcp, } +static int uv__is_ipv6_link_local(const struct sockaddr* addr) { + const struct sockaddr_in6* a6; + uint8_t b[2]; + + if (addr->sa_family != AF_INET6) + return 0; + + a6 = (const struct sockaddr_in6*) addr; + memcpy(b, &a6->sin6_addr, sizeof(b)); + + return b[0] == 0xFE && b[1] == 0x80; +} + + +static int uv__ipv6_link_local_scope_id(void) { + struct sockaddr_in6* a6; + struct ifaddrs* ifa; + struct ifaddrs* p; + int rv; + + if (getifaddrs(&ifa)) + return 0; + + for (p = ifa; p != NULL; p = p->ifa_next) + if (uv__is_ipv6_link_local(p->ifa_addr)) + break; + + rv = 0; + if (p != NULL) { + a6 = (struct sockaddr_in6*) p->ifa_addr; + rv = a6->sin6_scope_id; + } + + freeifaddrs(ifa); + return rv; +} + + int uv__tcp_connect(uv_connect_t* req, uv_tcp_t* handle, const struct sockaddr* addr, unsigned int addrlen, uv_connect_cb cb) { + struct sockaddr_in6 tmp6; int err; int r; @@ -220,6 +262,14 @@ int uv__tcp_connect(uv_connect_t* req, if (err) return err; + if (uv__is_ipv6_link_local(addr)) { + memcpy(&tmp6, addr, sizeof(tmp6)); + if (tmp6.sin6_scope_id == 0) { + tmp6.sin6_scope_id = uv__ipv6_link_local_scope_id(); + addr = (void*) &tmp6; + } + } + do { errno = 0; r = connect(uv__stream_fd(handle), addr, addrlen); diff --git a/test/test-list.h b/test/test-list.h index ca59890b8fa..6e6e082409e 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -128,6 +128,7 @@ TEST_DECLARE (tcp_bind_or_listen_error_after_close) TEST_DECLARE (tcp_listen_without_bind) TEST_DECLARE (tcp_connect_error_fault) TEST_DECLARE (tcp_connect6_error_fault) +TEST_DECLARE (tcp_connect6_link_local) TEST_DECLARE (tcp_connect_timeout) TEST_DECLARE (tcp_local_connect_timeout) TEST_DECLARE (tcp6_local_connect_timeout) @@ -727,6 +728,7 @@ TASK_LIST_START TEST_ENTRY (tcp_listen_without_bind) TEST_ENTRY (tcp_connect_error_fault) TEST_ENTRY (tcp_connect6_error_fault) + TEST_ENTRY (tcp_connect6_link_local) TEST_ENTRY (tcp_connect_timeout) TEST_ENTRY (tcp_local_connect_timeout) TEST_ENTRY (tcp6_local_connect_timeout) diff --git a/test/test-tcp-connect6-error.c b/test/test-tcp-connect6-error.c index 8646dd56496..075670ce88d 100644 --- a/test/test-tcp-connect6-error.c +++ b/test/test-tcp-connect6-error.c @@ -69,3 +69,38 @@ TEST_IMPL(tcp_connect6_error_fault) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } + + +TEST_IMPL(tcp_connect6_link_local) { + struct sockaddr_in6 addr; + uv_connect_t req; + uv_tcp_t server; + +#if defined(__QEMU__) + /* qemu's sockaddr_in6 translation is broken pre-qemu 8.0.0 + * when host endianness != guest endiannes. + * Fixed in https://github.com/qemu/qemu/commit/44cf6731d6b. + */ + RETURN_SKIP("Test does not currently work in QEMU"); +#endif /* defined(__QEMU__) */ + + ASSERT_OK(uv_ip6_addr("fe80::0bad:babe", 1337, &addr)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &server)); + + /* We're making two shaky assumptions here: + * 1. There is a network interface that routes IPv6 link-local traffic, and + * 2. There is no firewall rule that blackholes or otherwise hard-kills the + * connection attempt to the address above, i.e., we don't expect the + * connect() system call to fail synchronously. + */ + ASSERT_OK(uv_tcp_connect(&req, + &server, + (struct sockaddr*) &addr, + connect_cb)); + + uv_close((uv_handle_t*) &server, NULL); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} From 2f8275009854599ec7de68dbef795e82b6b5fb30 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Tue, 11 Jul 2023 14:11:25 -0600 Subject: [PATCH 416/713] unix: match kqueue and epoll code (#4091) Match the implementation for linux.c to kqueue.c in the code around the calls to kevent and epoll. In linux.c the code was made more DRY by moving the nfds check up (including a comment of why it's possible) and combining two if checks into one. In kqueue.c the assert to check the timeout when nfds == 0 has been moved to be called directly after the EINTR check. Since it should always be true regardless. Ref: https://github.com/libuv/libuv/pull/3893 Ref: https://github.com/nodejs/node/issues/48490 --- src/unix/kqueue.c | 5 +++-- src/unix/linux.c | 37 ++++++++----------------------------- 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index b78242d3be4..6cb0ef2aa75 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -262,6 +262,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (nfds == -1) assert(errno == EINTR); + else if (nfds == 0) + /* Unlimited timeout should only return with events or signal. */ + assert(timeout != -1); if (pset != NULL) pthread_sigmask(SIG_UNBLOCK, pset, NULL); @@ -286,8 +289,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { timeout = user_timeout; reset_timeout = 0; } else if (nfds == 0) { - /* Reached the user timeout value. */ - assert(timeout != -1); return; } diff --git a/src/unix/linux.c b/src/unix/linux.c index eac18e86b04..1b2dbe0b95c 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1395,41 +1395,20 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { */ SAVE_ERRNO(uv__update_time(loop)); - if (nfds == 0) { + if (nfds == -1) + assert(errno == EINTR); + else if (nfds == 0) + /* Unlimited timeout should only return with events or signal. */ assert(timeout != -1); + if (nfds == 0 || nfds == -1) { if (reset_timeout != 0) { timeout = user_timeout; reset_timeout = 0; + } else if (nfds == 0) { + return; } - if (timeout == -1) - continue; - - if (timeout == 0) - break; - - /* We may have been inside the system call for longer than |timeout| - * milliseconds so we need to update the timestamp to avoid drift. - */ - goto update_timeout; - } - - if (nfds == -1) { - if (errno != EINTR) - abort(); - - if (reset_timeout != 0) { - timeout = user_timeout; - reset_timeout = 0; - } - - if (timeout == -1) - continue; - - if (timeout == 0) - break; - /* Interrupted by a signal. Update timeout and poll again. */ goto update_timeout; } @@ -1540,13 +1519,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { break; } +update_timeout: if (timeout == 0) break; if (timeout == -1) continue; -update_timeout: assert(timeout > 0); real_timeout -= (loop->time - base); From c97017dd1d8cdd02c1a7aeae39b7336babc313d7 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Mon, 14 Aug 2023 15:25:11 -0400 Subject: [PATCH 417/713] win,spawn: allow `%PATH%` to be unset (#4116) Fix: https://github.com/libuv/libuv/issues/4115 --- src/win/process.c | 29 +++++++++++++---------------- test/test-list.h | 2 ++ test/test-spawn.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index 3e451e2291d..3cfa89e7380 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -396,7 +396,7 @@ static WCHAR* search_path(const WCHAR *file, name_has_ext); while (result == NULL) { - if (*dir_end == L'\0') { + if (dir_end == NULL || *dir_end == L'\0') { break; } @@ -1025,22 +1025,19 @@ int uv_spawn(uv_loop_t* loop, DWORD path_len, r; path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); - if (path_len == 0) { - err = GetLastError(); - goto done; - } - - alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR)); - if (alloc_path == NULL) { - err = ERROR_OUTOFMEMORY; - goto done; - } - path = alloc_path; + if (path_len != 0) { + alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR)); + if (alloc_path == NULL) { + err = ERROR_OUTOFMEMORY; + goto done; + } + path = alloc_path; - r = GetEnvironmentVariableW(L"PATH", path, path_len); - if (r == 0 || r >= path_len) { - err = GetLastError(); - goto done; + r = GetEnvironmentVariableW(L"PATH", path, path_len); + if (r == 0 || r >= path_len) { + err = GetLastError(); + goto done; + } } } diff --git a/test/test-list.h b/test/test-list.h index 6e6e082409e..36de006f53f 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -504,6 +504,7 @@ TEST_DECLARE (listen_with_simultaneous_accepts) TEST_DECLARE (listen_no_simultaneous_accepts) TEST_DECLARE (fs_stat_root) TEST_DECLARE (spawn_with_an_odd_path) +TEST_DECLARE (spawn_no_path) TEST_DECLARE (ipc_listen_after_bind_twice) TEST_DECLARE (win32_signum_number) #else @@ -1021,6 +1022,7 @@ TASK_LIST_START TEST_ENTRY (listen_no_simultaneous_accepts) TEST_ENTRY (fs_stat_root) TEST_ENTRY (spawn_with_an_odd_path) + TEST_ENTRY (spawn_no_path) TEST_ENTRY (ipc_listen_after_bind_twice) TEST_ENTRY (win32_signum_number) #else diff --git a/test/test-spawn.c b/test/test-spawn.c index 5e84dcdbb11..066d5d62cec 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1366,6 +1366,34 @@ TEST_IMPL(spawn_with_an_odd_path) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } + + +TEST_IMPL(spawn_no_path) { + char* env[1]; + WCHAR* old_path = NULL; + DWORD old_path_len; + + if ((old_path_len = GetEnvironmentVariableW(L"PATH", NULL, 0)) > 0) { + old_path = malloc(old_path_len * sizeof(WCHAR)); + GetEnvironmentVariableW(L"PATH", old_path, old_path_len); + SetEnvironmentVariableW(L"PATH", NULL); + } + + init_process_options("spawn_helper1", exit_cb); + options.env = env; + env[0] = NULL; + + ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 1); + + SetEnvironmentVariableW(L"PATH", old_path); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} #endif #ifndef _WIN32 From 1b4bd9209e73c5b6f9333a4283718e746eb4ee43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 14 Aug 2023 21:27:18 +0200 Subject: [PATCH 418/713] doc: switch to Furo, a more modern Sphinx theme (#4094) --- docs/requirements.txt | 13 +++++++++++-- docs/src/conf.py | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index b037de46595..2e310ebe728 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,27 +1,36 @@ # primary -sphinx==6.1.3 +furo==2023.5.20 +Sphinx==6.1.3 # dependencies alabaster==0.7.13 Babel==2.11.0 +beautifulsoup4==4.12.2 certifi==2022.12.7 charset-normalizer==3.0.1 +colorama==0.4.6 docutils==0.19 idna==3.4 imagesize==1.4.1 importlib-metadata==6.0.0 Jinja2==3.1.2 +livereload==2.6.3 MarkupSafe==2.1.2 packaging==23.0 Pygments==2.14.0 pytz==2022.7.1 requests==2.28.2 +six==1.16.0 snowballstemmer==2.2.0 -sphinxcontrib-applehelp==1.0.3 +soupsieve==2.4.1 +sphinx-autobuild==2021.3.14 +sphinx-basic-ng==1.0.0b2 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==2.0.0 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 +sphinxcontrib.applehelp==1.0.3 +tornado==6.3.2 urllib3==1.26.14 zipp==3.11.0 diff --git a/docs/src/conf.py b/docs/src/conf.py index f6f43253d36..354759a23c5 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -118,7 +118,7 @@ def get_libuv_version(): # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'nature' +html_theme = 'furo' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the From 65541f772f7209d8273395fb3e99ea0f0bbfb73e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=98=8E?= <7737673+caobug@users.noreply.github.com> Date: Tue, 15 Aug 2023 03:33:12 +0800 Subject: [PATCH 419/713] darwin: make TCP_KEEPINTVL and TCP_KEEPCNT available (#3908) In earlier versions, macOS only defined TCP_KEEPALIVE, but since macOS 10.8 (Mountain Lion), it has supported TCP_KEEPINTVL and TCP_KEEPCNT. https://lists.apple.com/archives/macnetworkprog/2012/Jul/msg00005.html --- src/unix/tcp.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index c225a57c4f5..e4e2e02837a 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -424,28 +424,39 @@ int uv__tcp_nodelay(int fd, int on) { int uv__tcp_keepalive(int fd, int on, unsigned int delay) { + int intvl; + int cnt; + + (void) &intvl; + (void) &cnt; + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) return UV__ERR(errno); + if (!on) + return 0; + #ifdef TCP_KEEPIDLE - if (on) { - int intvl = 1; /* 1 second; same as default on Win32 */ - int cnt = 10; /* 10 retries; same as hardcoded on Win32 */ - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) - return UV__ERR(errno); - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) - return UV__ERR(errno); - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) - return UV__ERR(errno); - } + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) + return UV__ERR(errno); +/* Solaris/SmartOS, if you don't support keep-alive, + * then don't advertise it in your system headers... + */ +/* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */ +#elif defined(TCP_KEEPALIVE) && !defined(__sun) + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) + return UV__ERR(errno); #endif - /* Solaris/SmartOS, if you don't support keep-alive, - * then don't advertise it in your system headers... - */ - /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */ -#if defined(TCP_KEEPALIVE) && !defined(__sun) - if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) +#ifdef TCP_KEEPINTVL + intvl = 1; /* 1 second; same as default on Win32 */ + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) + return UV__ERR(errno); +#endif + +#ifdef TCP_KEEPCNT + cnt = 10; /* 10 retries; same as hardcoded on Win32 */ + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) return UV__ERR(errno); #endif From b3759772d20e89537980d5d43a01ce4c2f2535a8 Mon Sep 17 00:00:00 2001 From: Brad King Date: Sat, 19 Aug 2023 06:17:16 -0400 Subject: [PATCH 420/713] win,fs: avoid winapi macro redefinition (#4123) Adjust include order to avoid redefining `CTL_CODE`, `FILE_READ_ACCESS`, and `FILE_WRITE_ACCESS`. Without this, compilation shows: ``` ...\um\winioctl.h(273): warning C4005: 'CTL_CODE': macro redefinition ...\src\win\winapi.h(4497): note: see previous definition of 'CTL_CODE' ...\um\winioctl.h(320): warning C4005: 'FILE_READ_ACCESS': macro redefinition ...\src\win\winapi.h(4488): note: see previous definition of 'FILE_READ_ACCESS' ...\um\winioctl.h(321): warning C4005: 'FILE_WRITE_ACCESS': macro redefinition ...\src\win\winapi.h(4492): note: see previous definition of 'FILE_WRITE_ACCESS' ``` --- src/win/fs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 4fc13b04bda..314a3543496 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -31,13 +31,16 @@ #include #include "uv.h" + +/* requires , included via "uv.h" above, but needs to + be included before our "winapi.h", included via "internal.h" below. */ +#include + #include "internal.h" #include "req-inl.h" #include "handle-inl.h" #include "fs-fd-hash-inl.h" -#include - #define UV_FS_FREE_PATHS 0x0002 #define UV_FS_FREE_PTR 0x0008 From 65dc822d6c20a9130fa100c7b46d751f8cf4d233 Mon Sep 17 00:00:00 2001 From: michalbiesek Date: Fri, 25 Aug 2023 21:41:56 +0200 Subject: [PATCH 421/713] linux: add missing riscv syscall numbers (#4127) Signed-off-by: Michal Biesek --- src/unix/linux.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/unix/linux.c b/src/unix/linux.c index 1b2dbe0b95c..44c028372ef 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -79,6 +79,8 @@ # define __NR_copy_file_range 379 # elif defined(__arc__) # define __NR_copy_file_range 285 +# elif defined(__riscv) +# define __NR_copy_file_range 285 # endif #endif /* __NR_copy_file_range */ @@ -95,6 +97,8 @@ # define __NR_statx 383 # elif defined(__s390__) # define __NR_statx 379 +# elif defined(__riscv) +# define __NR_statx 291 # endif #endif /* __NR_statx */ @@ -111,6 +115,8 @@ # define __NR_getrandom 359 # elif defined(__s390__) # define __NR_getrandom 349 +# elif defined(__riscv) +# define __NR_getrandom 278 # endif #endif /* __NR_getrandom */ From 0a02887e623a3ff9e19de9271295ccf5868b11a6 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Mon, 28 Aug 2023 17:41:40 +0100 Subject: [PATCH 422/713] doc: fix broken "Shared library" Wikipedia link (#4128) `linkcheck` is printing the following error: ``` ( guide/utilities: line 311) broken https://en.wikipedia.org/wiki/Shared_library#Shared_libraries - Anchor 'Shared_libraries' not found ``` --- docs/src/guide/utilities.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/guide/utilities.rst b/docs/src/guide/utilities.rst index c67515a088b..44e4370dff1 100644 --- a/docs/src/guide/utilities.rst +++ b/docs/src/guide/utilities.rst @@ -363,7 +363,7 @@ to get the error message. argument. ``init_plugin_function`` is a function pointer to the sort of function we are looking for in the application's plugins. -.. _shared libraries: https://en.wikipedia.org/wiki/Shared_library#Shared_libraries +.. _shared libraries: https://en.wikipedia.org/wiki/Shared_library TTY --- From e2c8fed7b3b3ae6e4be8356dd229917a32e07d4e Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 30 Aug 2023 21:30:59 +0200 Subject: [PATCH 423/713] unix: get mainline kernel version in Ubuntu (#4131) In Ubuntu, the kernel version reported by `uname()` follows the versioning format that Ubuntu uses for their kernels which does not have a direct correspondence with the mainline kernel version they're based on. Get that version from `/proc/version_signature` as documented in: https://wiki.ubuntu.com/Kernel/FAQ#Kernel.2FFAQ.2FGeneralVersionRunning.How_can_we_determine_the_version_of_the_running_kernel.3F --- src/unix/linux.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/unix/linux.c b/src/unix/linux.c index 44c028372ef..bf102fe9796 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -323,11 +323,22 @@ unsigned uv__kernel_version(void) { unsigned major; unsigned minor; unsigned patch; + char v_sig[256]; version = atomic_load_explicit(&cached_version, memory_order_relaxed); if (version != 0) return version; + /* Check /proc/version_signature first as it's the way to get the mainline + * kernel version in Ubuntu. The format is: + * Ubuntu ubuntu_kernel_version mainline_kernel_version + * For example: + * Ubuntu 5.15.0-79.86-generic 5.15.111 + */ + if (0 == uv__slurp("/proc/version_signature", v_sig, sizeof(v_sig))) + if (3 == sscanf(v_sig, "Ubuntu %*s %u.%u.%u", &major, &minor, &patch)) + goto calculate_version; + if (-1 == uname(&u)) return 0; @@ -359,6 +370,7 @@ unsigned uv__kernel_version(void) { } } +calculate_version: version = major * 65536 + minor * 256 + patch; atomic_store_explicit(&cached_version, version, memory_order_relaxed); From 0d78f3c758fdc41019093353a7ff4fed83005ac9 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 31 Aug 2023 11:45:27 +0200 Subject: [PATCH 424/713] unix: get mainline kernel version in Debian (#4131) In Debian, the mainline kernel version is reported via the `uname()` `version` field. --- src/unix/linux.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/unix/linux.c b/src/unix/linux.c index bf102fe9796..ee3b3fbcb6b 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -324,6 +324,7 @@ unsigned uv__kernel_version(void) { unsigned minor; unsigned patch; char v_sig[256]; + char* needle; version = atomic_load_explicit(&cached_version, memory_order_relaxed); if (version != 0) @@ -342,6 +343,15 @@ unsigned uv__kernel_version(void) { if (-1 == uname(&u)) return 0; + /* In Debian we need to check `version` instead of `release` to extract the + * mainline kernel version. This is an example of how it looks like: + * #1 SMP Debian 5.10.46-4 (2021-08-03) + */ + needle = strstr(u.version, "Debian "); + if (needle != NULL) + if (3 == sscanf(needle, "Debian %u.%u.%u", &major, &minor, &patch)) + goto calculate_version; + if (3 != sscanf(u.release, "%u.%u.%u", &major, &minor, &patch)) return 0; From 4e416266f62bbcf9cc2eaa124847cd6fd0ef4227 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sun, 17 Sep 2023 21:18:50 +0200 Subject: [PATCH 425/713] build: fix qemu install in CI-unix workflow (#4142) The version of the deb package has changed to 7.2. --- .github/workflows/CI-unix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index c912a6faff5..993cfb74209 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -125,7 +125,7 @@ jobs: # this ensure install latest qemu on ubuntu, apt get version is old env: QEMU_SRC: "http://archive.ubuntu.com/ubuntu/pool/universe/q/qemu" - QEMU_VER: "qemu-user-static_7\\.0+dfsg-.*_amd64.deb$" + QEMU_VER: "qemu-user-static_7\\.2+dfsg-.*_amd64.deb$" run: | DEB=`curl -s $QEMU_SRC/ | grep -o -E 'href="([^"#]+)"' | cut -d'"' -f2 | grep $QEMU_VER | tail -1` wget $QEMU_SRC/$DEB From c811169f91b2101f7302e96de3d2dc366ade3a25 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sun, 17 Sep 2023 22:09:00 +0200 Subject: [PATCH 426/713] unix: disable io_uring close on selected kernels (#4141) Specifically on non-longterm kernels between 5.16.0 (non-longterm) and 6.1.0 (longterm). Starting with longterm 6.1.0, the issue is solved. --- src/unix/linux.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index ee3b3fbcb6b..e71bdb3377b 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -815,7 +815,9 @@ static void uv__iou_submit(struct uv__iou* iou) { int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req) { struct uv__io_uring_sqe* sqe; struct uv__iou* iou; + int kv; + kv = uv__kernel_version(); /* Work around a poorly understood bug in older kernels where closing a file * descriptor pointing to /foo/bar results in ETXTBSY errors when trying to * execve("/foo/bar") later on. The bug seems to have been fixed somewhere @@ -823,10 +825,17 @@ int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req) { * but good candidates are the several data race fixes. Interestingly, it * seems to manifest only when running under Docker so the possibility of * a Docker bug can't be completely ruled out either. Yay, computers. + * Also, disable on non-longterm versions between 5.16.0 (non-longterm) and + * 6.1.0 (longterm). Starting with longterm 6.1.x, the issue seems to be + * solved. */ - if (uv__kernel_version() < /* 5.15.90 */ 0x050F5A) + if (kv < /* 5.15.90 */ 0x050F5A) return 0; + if (kv >= /* 5.16.0 */ 0x050A00 && kv < /* 6.1.0 */ 0x060100) + return 0; + + iou = &uv__get_internal_fields(loop)->iou; sqe = uv__iou_get_sqe(iou, loop, req); From d277f71333fc7a35bd253913422988ceead104f7 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 26 Sep 2023 21:55:32 +0200 Subject: [PATCH 427/713] test: skip tests when ipv6 is not available (#4151) --- test/test-tcp-connect6-error.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/test-tcp-connect6-error.c b/test/test-tcp-connect6-error.c index 075670ce88d..70faf32378e 100644 --- a/test/test-tcp-connect6-error.c +++ b/test/test-tcp-connect6-error.c @@ -49,6 +49,9 @@ TEST_IMPL(tcp_connect6_error_fault) { int r; uv_connect_t req; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + garbage_addr = (const struct sockaddr_in6*) &garbage; r = uv_tcp_init(uv_default_loop(), &server); @@ -76,6 +79,9 @@ TEST_IMPL(tcp_connect6_link_local) { uv_connect_t req; uv_tcp_t server; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + #if defined(__QEMU__) /* qemu's sockaddr_in6 translation is broken pre-qemu 8.0.0 * when host endianness != guest endiannes. From d83fadaf098024857fda42b0d0becc9797339145 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Thu, 28 Sep 2023 19:16:11 +0000 Subject: [PATCH 428/713] ibmi: implement ifaddrs, getifaddrs, freeifaddrs (#4155) Add PASE implementation of ifaddrs, getifaddrs, freeifaddrs. Refs: https://github.com/libuv/libuv/issues/4117 --- src/unix/tcp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index e4e2e02837a..a6b53e59132 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -29,7 +29,15 @@ #include #include + +#if defined(__PASE__) +#include +#define ifaddrs ifaddrs_pase +#define getifaddrs Qp2getifaddrs +#define freeifaddrs Qp2freeifaddrs +#else #include +#endif static int maybe_bind_socket(int fd) { union uv__sockaddr s; From 2a4cab70ef0133fe3b06b8844eb4541fbab5f826 Mon Sep 17 00:00:00 2001 From: SmorkalovG Date: Fri, 29 Sep 2023 12:54:35 +0200 Subject: [PATCH 429/713] unix: reset signal counters after fork (#3485) If a signal was received but was not dispatched before fork then caught_signals counter should be reset. Closing of signal pipe makes impossible to receive the signal that was counted. There is no need in this signal because it was sent to parent process Fixes: https://github.com/libuv/libuv/issues/3483 --- src/unix/signal.c | 15 +++++++++++++++ test/test-fork.c | 41 +++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 3 files changed, 58 insertions(+) diff --git a/src/unix/signal.c b/src/unix/signal.c index 63aba5a60e0..bc4206e6d86 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -279,6 +279,8 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) { int uv__signal_loop_fork(uv_loop_t* loop) { + struct uv__queue* q; + if (loop->signal_pipefd[0] == -1) return 0; uv__io_stop(loop, &loop->signal_io_watcher, POLLIN); @@ -286,6 +288,19 @@ int uv__signal_loop_fork(uv_loop_t* loop) { uv__close(loop->signal_pipefd[1]); loop->signal_pipefd[0] = -1; loop->signal_pipefd[1] = -1; + + uv__queue_foreach(q, &loop->handle_queue) { + uv_handle_t* handle = uv__queue_data(q, uv_handle_t, handle_queue); + uv_signal_t* sh; + + if (handle->type != UV_SIGNAL) + continue; + + sh = (uv_signal_t*) handle; + sh->caught_signals = 0; + sh->dispatched_signals = 0; + } + return uv__signal_loop_once_init(loop); } diff --git a/test/test-fork.c b/test/test-fork.c index 29ed132a488..d1a273f4b96 100644 --- a/test/test-fork.c +++ b/test/test-fork.c @@ -371,6 +371,47 @@ TEST_IMPL(fork_signal_to_child_closed) { return 0; } +static void fork_signal_cb(uv_signal_t* h, int s) { + fork_signal_cb_called = s; +} +static void empty_close_cb(uv_handle_t* h){} + +TEST_IMPL(fork_close_signal_in_child) { + uv_loop_t loop; + uv_signal_t signal_handle; + pid_t child_pid; + + ASSERT_EQ(0, uv_loop_init(&loop)); + ASSERT_EQ(0, uv_signal_init(&loop, &signal_handle)); + ASSERT_EQ(0, uv_signal_start(&signal_handle, &fork_signal_cb, SIGHUP)); + + ASSERT_EQ(0, kill(getpid(), SIGHUP)); + child_pid = fork(); + ASSERT_NE(child_pid, -1); + ASSERT_EQ(0, fork_signal_cb_called); + + if (!child_pid) { + uv_loop_fork(&loop); + uv_close((uv_handle_t*)&signal_handle, &empty_close_cb); + uv_run(&loop, UV_RUN_DEFAULT); + /* Child doesn't receive the signal */ + ASSERT_EQ(0, fork_signal_cb_called); + } else { + /* Parent. Runing once to receive the signal */ + uv_run(&loop, UV_RUN_ONCE); + ASSERT_EQ(SIGHUP, fork_signal_cb_called); + + /* loop should stop after closing the only handle */ + uv_close((uv_handle_t*)&signal_handle, &empty_close_cb); + ASSERT_EQ(0, uv_run(&loop, UV_RUN_DEFAULT)); + + assert_wait_child(child_pid); + } + + MAKE_VALGRIND_HAPPY(&loop); + return 0; +} + static void create_file(const char* name) { int r; diff --git a/test/test-list.h b/test/test-list.h index 36de006f53f..d112d07a29a 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -546,6 +546,7 @@ TEST_DECLARE (fork_socketpair) TEST_DECLARE (fork_socketpair_started) TEST_DECLARE (fork_signal_to_child) TEST_DECLARE (fork_signal_to_child_closed) +TEST_DECLARE (fork_close_signal_in_child) #ifndef __APPLE__ /* This is forbidden in a fork child: The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec(). */ @@ -1184,6 +1185,7 @@ TASK_LIST_START TEST_ENTRY (fork_socketpair_started) TEST_ENTRY (fork_signal_to_child) TEST_ENTRY (fork_signal_to_child_closed) + TEST_ENTRY (fork_close_signal_in_child) #ifndef __APPLE__ TEST_ENTRY (fork_fs_events_child) TEST_ENTRY (fork_fs_events_child_dir) From c03569f0df3bb26e7e7bec9feabd9ae3c372568e Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 2 Oct 2023 15:15:18 +0200 Subject: [PATCH 430/713] win,process: avoid assert after spawning Store app (#4152) Make sure this handle is functional. The Windows kernel seems to have a bug that if the first use of AssignProcessToJobObject is for a Windows Store program, subsequent attempts to use the handle with fail with INVALID_PARAMETER (87). This is possilby because all uses of the handle must be for the same Terminal Services session. We can ensure it is tied to our current session now by adding ourself to it. We could remove ourself afterwards, but there doesn't seem to be a reason to. Secondly, we start the process suspended so that we can make sure we added it to the job control object before it does anything itself (such as launch more jobs or exit). Fixes: https://github.com/JuliaLang/julia/issues/51461 --- src/win/process.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index 3cfa89e7380..8f1b665ab74 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -105,6 +105,21 @@ static void uv__init_global_job_handle(void) { &info, sizeof info)) uv_fatal_error(GetLastError(), "SetInformationJobObject"); + + + if (!AssignProcessToJobObject(uv_global_job_handle_, GetCurrentProcess())) { + /* Make sure this handle is functional. The Windows kernel has a bug that + * if the first use of AssignProcessToJobObject is for a Windows Store + * program, subsequent attempts to use the handle with fail with + * INVALID_PARAMETER (87). This is possibly because all uses of the handle + * must be for the same Terminal Services session. We can ensure it is tied + * to our current session now by adding ourself to it. We could remove + * ourself afterwards, but there doesn't seem to be a reason to. + */ + DWORD err = GetLastError(); + if (err != ERROR_ACCESS_DENIED) + uv_fatal_error(err, "AssignProcessToJobObject"); + } } @@ -1099,6 +1114,7 @@ int uv_spawn(uv_loop_t* loop, * breakaway. */ process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; + process_flags |= CREATE_SUSPENDED; } if (!CreateProcessW(application_path, @@ -1116,11 +1132,6 @@ int uv_spawn(uv_loop_t* loop, goto done; } - /* Spawn succeeded. Beyond this point, failure is reported asynchronously. */ - - process->process_handle = info.hProcess; - process->pid = info.dwProcessId; - /* If the process isn't spawned as detached, assign to the global job object * so windows will kill it when the parent process dies. */ if (!(options->flags & UV_PROCESS_DETACHED)) { @@ -1143,6 +1154,19 @@ int uv_spawn(uv_loop_t* loop, } } + if (process_flags & CREATE_SUSPENDED) { + if (ResumeThread(info.hThread) == ((DWORD)-1)) { + err = GetLastError(); + TerminateProcess(info.hProcess, 1); + goto done; + } + } + + /* Spawn succeeded. Beyond this point, failure is reported asynchronously. */ + + process->process_handle = info.hProcess; + process->pid = info.dwProcessId; + /* Set IPC pid to all IPC pipes. */ for (i = 0; i < options->stdio_count; i++) { const uv_stdio_container_t* fdopt = &options->stdio[i]; From 663d88b677f22b74ed3002c1d704f87188692dc5 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 1 Oct 2023 14:10:20 +0200 Subject: [PATCH 431/713] unix: remove pread/preadv conditionals --- src/unix/fs.c | 141 ++++++++++++-------------------------------------- 1 file changed, 32 insertions(+), 109 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 6b051c124f2..de91e11ceec 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -46,20 +46,6 @@ #include #include -#if defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) -# define HAVE_PREADV 1 -#else -# define HAVE_PREADV 0 -#endif - -/* preadv() and pwritev() were added in Android N (level 24) */ -#if defined(__linux__) && !(defined(__ANDROID__) && __ANDROID_API__ < 24) -# define TRY_PREADV 1 -#endif - #if defined(__linux__) # include #endif @@ -410,103 +396,52 @@ static ssize_t uv__fs_open(uv_fs_t* req) { } -#if !HAVE_PREADV -static ssize_t uv__fs_preadv(uv_file fd, - uv_buf_t* bufs, - unsigned int nbufs, - off_t off) { - uv_buf_t* buf; - uv_buf_t* end; +static ssize_t uv__fs_read_do(int fd, + const struct iovec* bufs, + unsigned int nbufs, + int64_t off) { + unsigned int iovmax; ssize_t result; - ssize_t rc; - size_t pos; - - assert(nbufs > 0); - result = 0; - pos = 0; - buf = bufs + 0; - end = bufs + nbufs; - - for (;;) { - do - rc = pread(fd, buf->base + pos, buf->len - pos, off + result); - while (rc == -1 && errno == EINTR); - - if (rc == 0) - break; - - if (rc == -1 && result == 0) - return UV__ERR(errno); - - if (rc == -1) - break; /* We read some data so return that, ignore the error. */ - - pos += rc; - result += rc; - - if (pos < buf->len) - continue; + iovmax = uv__getiovmax(); + if (nbufs > iovmax) + nbufs = iovmax; - pos = 0; - buf += 1; + if (off < 0) { + if (nbufs == 1) + result = read(fd, bufs->iov_base, bufs->iov_len); + else + result = readv(fd, bufs, nbufs); + } else { + if (nbufs == 1) + result = pread(fd, bufs->iov_base, bufs->iov_len, off); + else + result = preadv(fd, bufs, nbufs, off); + } - if (buf == end) - break; +#ifdef __PASE__ + /* PASE returns EOPNOTSUPP when reading a directory, convert to EISDIR */ + if (result == -1 && errno == EOPNOTSUPP) { + struct stat buf; + ssize_t rc; + rc = uv__fstat(fd, &buf); + if (rc == 0 && S_ISDIR(buf.st_mode)) { + errno = EISDIR; + } } +#endif return result; } -#endif static ssize_t uv__fs_read(uv_fs_t* req) { -#if TRY_PREADV - static _Atomic int no_preadv; -#endif - unsigned int iovmax; + const struct iovec* iov; ssize_t result; - iovmax = uv__getiovmax(); - if (req->nbufs > iovmax) - req->nbufs = iovmax; - - if (req->off < 0) { - if (req->nbufs == 1) - result = read(req->file, req->bufs[0].base, req->bufs[0].len); - else - result = readv(req->file, (struct iovec*) req->bufs, req->nbufs); - } else { - if (req->nbufs == 1) { - result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off); - goto done; - } + iov = (const struct iovec*) req->bufs; + result = uv__fs_read_do(req->file, iov, req->nbufs, req->off); -#if HAVE_PREADV - result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); -#else -# if TRY_PREADV - if (atomic_load_explicit(&no_preadv, memory_order_relaxed)) retry: -# endif - { - result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off); - } -# if TRY_PREADV - else { - result = preadv(req->file, - (struct iovec*) req->bufs, - req->nbufs, - req->off); - if (result == -1 && errno == ENOSYS) { - atomic_store_explicit(&no_preadv, 1, memory_order_relaxed); - goto retry; - } - } -# endif -#endif - } - -done: /* Early cleanup of bufs allocation, since we're done with it. */ if (req->bufs != req->bufsml) uv__free(req->bufs); @@ -514,18 +449,6 @@ static ssize_t uv__fs_read(uv_fs_t* req) { req->bufs = NULL; req->nbufs = 0; -#ifdef __PASE__ - /* PASE returns EOPNOTSUPP when reading a directory, convert to EISDIR */ - if (result == -1 && errno == EOPNOTSUPP) { - struct stat buf; - ssize_t rc; - rc = uv__fstat(req->file, &buf); - if (rc == 0 && S_ISDIR(buf.st_mode)) { - errno = EISDIR; - } - } -#endif - return result; } From fef619608bda33a7cb37e78f08ee8abbb62458a3 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 1 Oct 2023 14:37:54 +0200 Subject: [PATCH 432/713] unix: remove pwrite/pwritev conditionals --- src/unix/fs.c | 56 +++++++++++++++++++-------------------------------- 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index de91e11ceec..676a20465cc 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1083,10 +1083,10 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) { } -static ssize_t uv__fs_write(uv_fs_t* req) { -#if TRY_PREADV - static _Atomic int no_pwritev; -#endif +static ssize_t uv__fs_write_do(int fd, + const struct iovec* bufs, + unsigned int nbufs, + int64_t off) { ssize_t r; /* Serialize writes on OS X, concurrent write() and pwrite() calls result in @@ -1100,41 +1100,18 @@ static ssize_t uv__fs_write(uv_fs_t* req) { abort(); #endif - if (req->off < 0) { - if (req->nbufs == 1) - r = write(req->file, req->bufs[0].base, req->bufs[0].len); + if (off < 0) { + if (nbufs == 1) + r = write(fd, bufs->iov_base, bufs->iov_len); else - r = writev(req->file, (struct iovec*) req->bufs, req->nbufs); + r = writev(fd, bufs, nbufs); } else { - if (req->nbufs == 1) { - r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off); - goto done; - } -#if HAVE_PREADV - r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off); -#else -# if TRY_PREADV - if (atomic_load_explicit(&no_pwritev, memory_order_relaxed)) retry: -# endif - { - r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off); - } -# if TRY_PREADV - else { - r = pwritev(req->file, - (struct iovec*) req->bufs, - req->nbufs, - req->off); - if (r == -1 && errno == ENOSYS) { - atomic_store_explicit(&no_pwritev, 1, memory_order_relaxed); - goto retry; - } - } -# endif -#endif + if (nbufs == 1) + r = pwrite(fd, bufs->iov_base, bufs->iov_len, off); + else + r = pwritev(fd, bufs, nbufs, off); } -done: #if defined(__APPLE__) if (pthread_mutex_unlock(&lock)) abort(); @@ -1143,6 +1120,15 @@ static ssize_t uv__fs_write(uv_fs_t* req) { return r; } + +static ssize_t uv__fs_write(uv_fs_t* req) { + const struct iovec* iov; + + iov = (const struct iovec*) req->bufs; + return uv__fs_write_do(req->file, iov, req->nbufs, req->off); +} + + static ssize_t uv__fs_copyfile(uv_fs_t* req) { uv_fs_t fs_req; uv_file srcfd; From 737f4f953fa908863c3492e6c6a1188acb58370c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 3 Oct 2023 12:52:47 +0200 Subject: [PATCH 433/713] darwin: remove workaround for data corruption bug XNU kernels anno ~2010 had a data corrruption bug where concurrent write and pwrite calls sometimes resulted in blocks of zeroes being written instead of the actual data. Libuv works around that by serializing all writes with a process-wide mutex, meaning oncurrent writes (for all files, not just single files) have a concurrency of 1. Obviously that's not great for performance. Modern day macOS no longer has this bug, so remove the workaround. --- src/unix/fs.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 676a20465cc..56c660b456e 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -1089,17 +1088,6 @@ static ssize_t uv__fs_write_do(int fd, int64_t off) { ssize_t r; - /* Serialize writes on OS X, concurrent write() and pwrite() calls result in - * data loss. We can't use a per-file descriptor lock, the descriptor may be - * a dup(). - */ -#if defined(__APPLE__) - static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - - if (pthread_mutex_lock(&lock)) - abort(); -#endif - if (off < 0) { if (nbufs == 1) r = write(fd, bufs->iov_base, bufs->iov_len); @@ -1112,11 +1100,6 @@ static ssize_t uv__fs_write_do(int fd, r = pwritev(fd, bufs, nbufs, off); } -#if defined(__APPLE__) - if (pthread_mutex_unlock(&lock)) - abort(); -#endif - return r; } From 56fada47f2343ac05df81a23a3e3237bbe6872a2 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 3 Oct 2023 13:30:16 +0200 Subject: [PATCH 434/713] src: default to stream=stderr in handle printer (#4161) Make printing handles from gdb a little easier because it doesn't always know how to locate the stdout or stderr globals from libc. With this commit `call uv_print_all_handles(0, 0)` prints the handles from the default loop to stderr. --- src/uv-common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/uv-common.c b/src/uv-common.c index 916f3f4e006..2200fe3f0a4 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -559,6 +559,9 @@ static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) { if (loop == NULL) loop = uv_default_loop(); + if (stream == NULL) + stream = stderr; + uv__queue_foreach(q, &loop->handle_queue) { h = uv__queue_data(q, uv_handle_t, handle_queue); From 011a1ac1a31e2d4a17fb9b20a94f9b66845b5bc9 Mon Sep 17 00:00:00 2001 From: Pleuvens Date: Fri, 6 Oct 2023 19:50:15 +0200 Subject: [PATCH 435/713] test: switch to new-style ASSERT_EQ macros (#4159) Switch from old-style ASSERT macro to new-style ASSERT_EQ,... macros. Using new-style macros makes it easier to debug test failures Fixes: https://github.com/libuv/libuv/issues/2974 --- test/benchmark-async-pummel.c | 8 +- test/benchmark-async.c | 32 +- test/benchmark-getaddrinfo.c | 8 +- test/benchmark-loop-count.c | 2 +- test/benchmark-million-async.c | 12 +- test/benchmark-million-timers.c | 12 +- test/benchmark-multi-accept.c | 114 +- test/benchmark-ping-pongs.c | 26 +- test/benchmark-ping-udp.c | 12 +- test/benchmark-pound.c | 12 +- test/benchmark-pump.c | 50 +- test/benchmark-queue-work.c | 10 +- test/benchmark-spawn.c | 22 +- test/benchmark-tcp-write-batch.c | 30 +- test/benchmark-thread.c | 8 +- test/benchmark-udp-pummel.c | 60 +- test/blackhole-server.c | 22 +- test/echo-server.c | 36 +- test/run-tests.c | 33 +- test/runner-win.c | 4 +- test/task.h | 2 +- test/test-active.c | 32 +- test/test-async-null-cb.c | 16 +- test/test-async.c | 26 +- test/test-barrier.c | 26 +- test/test-callback-stack.c | 35 +- test/test-close-fd.c | 34 +- test/test-close-order.c | 18 +- test/test-condvar.c | 36 +- test/test-connect-unspecified.c | 30 +- test/test-connection-fail.c | 34 +- test/test-cwd-and-chdir.c | 18 +- test/test-default-loop-close.c | 18 +- test/test-delayed-accept.c | 40 +- test/test-dlerror.c | 2 +- test/test-eintr-handling.c | 24 +- test/test-embed.c | 10 +- test/test-emfile.c | 30 +- test/test-env-vars.c | 68 +- test/test-error.c | 26 +- test/test-fork.c | 230 +-- test/test-fs-copyfile.c | 66 +- test/test-fs-event.c | 347 ++-- test/test-fs-fd-hash.c | 6 +- test/test-fs-open-flags.c | 96 +- test/test-fs-poll.c | 108 +- test/test-fs-readdir.c | 152 +- test/test-fs.c | 1727 +++++++++-------- test/test-get-currentexe.c | 26 +- test/test-get-loadavg.c | 6 +- test/test-get-memory.c | 8 +- test/test-get-passwd.c | 12 +- test/test-getaddrinfo.c | 68 +- test/test-gethostname.c | 14 +- test/test-getnameinfo.c | 26 +- test/test-getsockname.c | 68 +- test/test-getters-setters.c | 48 +- test/test-gettimeofday.c | 6 +- test/test-handle-fileno.c | 42 +- test/test-homedir.c | 28 +- test/test-hrtime.c | 6 +- test/test-idle.c | 38 +- test/test-idna.c | 72 +- test/test-ip-name.c | 20 +- test/test-ip4-addr.c | 28 +- test/test-ip6-addr.c | 50 +- test/test-ipc-heavy-traffic-deadlock-bug.c | 24 +- test/test-ipc-send-recv.c | 98 +- test/test-ipc.c | 216 +-- test/test-loop-alive.c | 8 +- test/test-loop-close.c | 24 +- test/test-loop-configure.c | 14 +- test/test-loop-handles.c | 72 +- test/test-loop-stop.c | 20 +- test/test-loop-time.c | 20 +- test/test-metrics.c | 80 +- test/test-multiple-listen.c | 26 +- test/test-mutexes.c | 44 +- ...-not-readable-nor-writable-on-read-error.c | 36 +- test/test-not-writable-after-shutdown.c | 14 +- test/test-osx-select.c | 20 +- test/test-ping-pong.c | 72 +- test/test-pipe-bind-error.c | 38 +- test/test-pipe-close-stdout-read-stdin.c | 12 +- test/test-pipe-connect-error.c | 12 +- test/test-pipe-connect-multiple.c | 34 +- test/test-pipe-connect-prepare.c | 16 +- test/test-pipe-getsockname.c | 80 +- test/test-pipe-pending-instances.c | 8 +- test/test-pipe-sendmsg.c | 38 +- test/test-pipe-server-close.c | 24 +- test/test-pipe-set-fchmod.c | 18 +- test/test-pipe-set-non-blocking.c | 36 +- test/test-platform-output.c | 40 +- test/test-poll-close-doesnt-corrupt-stack.c | 24 +- test/test-poll-close.c | 4 +- test/test-poll-closesocket.c | 24 +- test/test-poll-multiple-handles.c | 33 +- test/test-poll-oob.c | 90 +- test/test-poll.c | 110 +- test/test-process-priority.c | 26 +- test/test-process-title-threadsafe.c | 23 +- test/test-process-title.c | 26 +- test/test-queue-foreach-delete.c | 36 +- test/test-random.c | 42 +- test/test-readable-on-eof.c | 37 +- test/test-ref.c | 58 +- test/test-run-nowait.c | 6 +- test/test-run-once.c | 4 +- test/test-semaphore.c | 30 +- test/test-shutdown-close.c | 36 +- test/test-shutdown-eof.c | 52 +- test/test-shutdown-simultaneous.c | 28 +- test/test-shutdown-twice.c | 20 +- test/test-signal-multiple-loops.c | 64 +- test/test-signal-pending-on-close.c | 38 +- test/test-signal.c | 142 +- test/test-socket-buffer-size.c | 22 +- test/test-spawn.c | 570 +++--- test/test-stdio-over-pipes.c | 68 +- test/test-strscpy.c | 24 +- test/test-strtok.c | 6 +- test/test-tcp-alloc-cb-fail.c | 50 +- test/test-tcp-bind-error.c | 118 +- test/test-tcp-bind6-error.c | 48 +- test/test-tcp-close-accept.c | 68 +- test/test-tcp-close-after-read-timeout.c | 46 +- test/test-tcp-close-reset.c | 129 +- test/test-tcp-close-while-connecting.c | 24 +- test/test-tcp-close.c | 34 +- test/test-tcp-connect-error-after-write.c | 22 +- test/test-tcp-connect-error.c | 8 +- test/test-tcp-connect-timeout.c | 44 +- test/test-tcp-connect6-error.c | 8 +- test/test-tcp-create-socket-early.c | 64 +- test/test-tcp-flags.c | 8 +- test/test-tcp-oob.c | 56 +- test/test-tcp-open.c | 132 +- test/test-tcp-read-stop-start.c | 44 +- test/test-tcp-read-stop.c | 38 +- test/test-tcp-rst.c | 20 +- test/test-tcp-shutdown-after-write.c | 34 +- test/test-tcp-try-write-error.c | 40 +- test/test-tcp-try-write.c | 42 +- test/test-tcp-unexpected-read.c | 50 +- test/test-tcp-write-after-connect.c | 32 +- test/test-tcp-write-fail.c | 24 +- test/test-tcp-write-in-a-row.c | 38 +- test/test-tcp-write-queue-order.c | 60 +- test/test-tcp-write-to-half-open-connection.c | 36 +- test/test-tcp-writealot.c | 40 +- test/test-thread-affinity.c | 42 +- test/test-thread-equal.c | 14 +- test/test-thread.c | 98 +- test/test-threadpool-cancel.c | 165 +- test/test-threadpool.c | 22 +- test/test-timer-again.c | 38 +- test/test-timer-from-check.c | 50 +- test/test-timer.c | 172 +- test/test-tmpdir.c | 28 +- test/test-tty-duplicate-key.c | 60 +- test/test-tty-escape-sequence-processing.c | 182 +- test/test-tty.c | 128 +- test/test-udp-alloc-cb-fail.c | 56 +- test/test-udp-bind.c | 24 +- test/test-udp-connect.c | 72 +- test/test-udp-connect6.c | 54 +- test/test-udp-create-socket-early.c | 42 +- test/test-udp-dgram-too-big.c | 20 +- test/test-udp-ipv6.c | 70 +- test/test-udp-mmsg.c | 28 +- test/test-udp-multicast-interface.c | 26 +- test/test-udp-multicast-interface6.c | 24 +- test/test-udp-multicast-join.c | 46 +- test/test-udp-multicast-join6.c | 46 +- test/test-udp-multicast-ttl.c | 22 +- test/test-udp-open.c | 96 +- test/test-udp-options.c | 56 +- test/test-udp-recv-in-a-row.c | 22 +- test/test-udp-send-and-recv.c | 62 +- test/test-udp-send-hang-loop.c | 18 +- test/test-udp-send-immediate.c | 34 +- test/test-udp-send-unreachable.c | 38 +- test/test-udp-sendmmsg-error.c | 10 +- test/test-udp-try-send.c | 34 +- test/test-uname.c | 18 +- test/test-walk-handles.c | 16 +- test/test-watcher-cross-stop.c | 30 +- 188 files changed, 5254 insertions(+), 5189 deletions(-) diff --git a/test/benchmark-async-pummel.c b/test/benchmark-async-pummel.c index bec91850616..68864c842e5 100644 --- a/test/benchmark-async-pummel.c +++ b/test/benchmark-async-pummel.c @@ -71,21 +71,21 @@ static int test_async_pummel(int nthreads) { tids = calloc(nthreads, sizeof(tids[0])); ASSERT_NOT_NULL(tids); - ASSERT(0 == uv_async_init(uv_default_loop(), &handle, async_cb)); + ASSERT_OK(uv_async_init(uv_default_loop(), &handle, async_cb)); ACCESS_ONCE(const char*, handle.data) = running; for (i = 0; i < nthreads; i++) - ASSERT(0 == uv_thread_create(tids + i, pummel, &handle)); + ASSERT_OK(uv_thread_create(tids + i, pummel, &handle)); time = uv_hrtime(); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); time = uv_hrtime() - time; done = 1; for (i = 0; i < nthreads; i++) - ASSERT(0 == uv_thread_join(tids + i)); + ASSERT_OK(uv_thread_join(tids + i)); printf("async_pummel_%d: %s callbacks in %.2f seconds (%s/sec)\n", nthreads, diff --git a/test/benchmark-async.c b/test/benchmark-async.c index d4b7c8bd914..5544c46b3b2 100644 --- a/test/benchmark-async.c +++ b/test/benchmark-async.c @@ -43,7 +43,7 @@ struct ctx { static void worker_async_cb(uv_async_t* handle) { struct ctx* ctx = container_of(handle, struct ctx, worker_async); - ASSERT(0 == uv_async_send(&ctx->main_async)); + ASSERT_OK(uv_async_send(&ctx->main_async)); ctx->worker_sent++; ctx->worker_seen++; @@ -55,7 +55,7 @@ static void worker_async_cb(uv_async_t* handle) { static void main_async_cb(uv_async_t* handle) { struct ctx* ctx = container_of(handle, struct ctx, main_async); - ASSERT(0 == uv_async_send(&ctx->worker_async)); + ASSERT_OK(uv_async_send(&ctx->worker_async)); ctx->main_sent++; ctx->main_seen++; @@ -66,8 +66,8 @@ static void main_async_cb(uv_async_t* handle) { static void worker(void* arg) { struct ctx* ctx = arg; - ASSERT(0 == uv_async_send(&ctx->main_async)); - ASSERT(0 == uv_run(&ctx->loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_async_send(&ctx->main_async)); + ASSERT_OK(uv_run(&ctx->loop, UV_RUN_DEFAULT)); uv_loop_close(&ctx->loop); } @@ -85,29 +85,29 @@ static int test_async(int nthreads) { for (i = 0; i < nthreads; i++) { ctx = threads + i; ctx->nthreads = nthreads; - ASSERT(0 == uv_loop_init(&ctx->loop)); - ASSERT(0 == uv_async_init(&ctx->loop, &ctx->worker_async, worker_async_cb)); - ASSERT(0 == uv_async_init(uv_default_loop(), - &ctx->main_async, - main_async_cb)); - ASSERT(0 == uv_thread_create(&ctx->thread, worker, ctx)); + ASSERT_OK(uv_loop_init(&ctx->loop)); + ASSERT_OK(uv_async_init(&ctx->loop, &ctx->worker_async, worker_async_cb)); + ASSERT_OK(uv_async_init(uv_default_loop(), + &ctx->main_async, + main_async_cb)); + ASSERT_OK(uv_thread_create(&ctx->thread, worker, ctx)); } time = uv_hrtime(); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); for (i = 0; i < nthreads; i++) - ASSERT(0 == uv_thread_join(&threads[i].thread)); + ASSERT_OK(uv_thread_join(&threads[i].thread)); time = uv_hrtime() - time; for (i = 0; i < nthreads; i++) { ctx = threads + i; - ASSERT(ctx->worker_sent == NUM_PINGS); - ASSERT(ctx->worker_seen == NUM_PINGS); - ASSERT(ctx->main_sent == (unsigned int) NUM_PINGS); - ASSERT(ctx->main_seen == (unsigned int) NUM_PINGS); + ASSERT_EQ(ctx->worker_sent, NUM_PINGS); + ASSERT_EQ(ctx->worker_seen, NUM_PINGS); + ASSERT_EQ(ctx->main_sent, (unsigned int) NUM_PINGS); + ASSERT_EQ(ctx->main_seen, (unsigned int) NUM_PINGS); } printf("async%d: %.2f sec (%s/sec)\n", diff --git a/test/benchmark-getaddrinfo.c b/test/benchmark-getaddrinfo.c index 1ef7b1ef095..cb4d2bc935a 100644 --- a/test/benchmark-getaddrinfo.c +++ b/test/benchmark-getaddrinfo.c @@ -43,7 +43,7 @@ static void getaddrinfo_initiate(uv_getaddrinfo_t* handle); static void getaddrinfo_cb(uv_getaddrinfo_t* handle, int status, struct addrinfo* res) { - ASSERT(status == 0); + ASSERT_OK(status); calls_completed++; if (calls_initiated < TOTAL_CALLS) { getaddrinfo_initiate(handle); @@ -59,7 +59,7 @@ static void getaddrinfo_initiate(uv_getaddrinfo_t* handle) { calls_initiated++; r = uv_getaddrinfo(loop, handle, &getaddrinfo_cb, name, NULL, NULL); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -80,8 +80,8 @@ BENCHMARK_IMPL(getaddrinfo) { uv_update_time(loop); end_time = uv_now(loop); - ASSERT(calls_initiated == TOTAL_CALLS); - ASSERT(calls_completed == TOTAL_CALLS); + ASSERT_EQ(calls_initiated, TOTAL_CALLS); + ASSERT_EQ(calls_completed, TOTAL_CALLS); fprintf(stderr, "getaddrinfo: %.0f req/s\n", (double) calls_completed / (double) (end_time - start_time) * 1000.0); diff --git a/test/benchmark-loop-count.c b/test/benchmark-loop-count.c index 72f25b56ba5..0db4aa567a9 100644 --- a/test/benchmark-loop-count.c +++ b/test/benchmark-loop-count.c @@ -74,7 +74,7 @@ BENCHMARK_IMPL(loop_count) { uv_run(loop, UV_RUN_DEFAULT); ns = uv_hrtime() - ns; - ASSERT(ticks == NUM_TICKS); + ASSERT_UINT64_EQ(ticks, NUM_TICKS); fprintf(stderr, "loop_count: %d ticks in %.2fs (%.0f/s)\n", NUM_TICKS, diff --git a/test/benchmark-million-async.c b/test/benchmark-million-async.c index 30c21c38af1..13b52d488d0 100644 --- a/test/benchmark-million-async.c +++ b/test/benchmark-million-async.c @@ -60,7 +60,7 @@ static void timer_cb(uv_timer_t* handle) { unsigned i; done = 1; - ASSERT(0 == uv_thread_join(&thread_id)); + ASSERT_OK(uv_thread_join(&thread_id)); for (i = 0; i < ARRAY_SIZE(container->async_handles); i++) { uv_async_t* handle = container->async_handles + i; @@ -93,14 +93,14 @@ BENCHMARK_IMPL(million_async) { for (i = 0; i < ARRAY_SIZE(container->async_handles); i++) { handle = container->async_handles + i; - ASSERT(0 == uv_async_init(loop, handle, async_cb)); + ASSERT_OK(uv_async_init(loop, handle, async_cb)); handle->data = NULL; } - ASSERT(0 == uv_timer_init(loop, &timer_handle)); - ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, timeout, 0)); - ASSERT(0 == uv_thread_create(&thread_id, thread_cb, NULL)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_timer_init(loop, &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, timeout, 0)); + ASSERT_OK(uv_thread_create(&thread_id, thread_cb, NULL)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); printf("%s async events in %.1f seconds (%s/s, %s unique handles seen)\n", fmt(&fmtbuf[0], container->async_events), timeout / 1000., diff --git a/test/benchmark-million-timers.c b/test/benchmark-million-timers.c index b35fd5e7882..fd999c46976 100644 --- a/test/benchmark-million-timers.c +++ b/test/benchmark-million-timers.c @@ -57,22 +57,22 @@ BENCHMARK_IMPL(million_timers) { before_all = uv_hrtime(); for (i = 0; i < NUM_TIMERS; i++) { if (i % 1000 == 0) timeout++; - ASSERT(0 == uv_timer_init(loop, timers + i)); - ASSERT(0 == uv_timer_start(timers + i, timer_cb, timeout, 0)); + ASSERT_OK(uv_timer_init(loop, timers + i)); + ASSERT_OK(uv_timer_start(timers + i, timer_cb, timeout, 0)); } before_run = uv_hrtime(); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); after_run = uv_hrtime(); for (i = 0; i < NUM_TIMERS; i++) uv_close((uv_handle_t*) (timers + i), close_cb); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); after_all = uv_hrtime(); - ASSERT(timer_cb_called == NUM_TIMERS); - ASSERT(close_cb_called == NUM_TIMERS); + ASSERT_EQ(timer_cb_called, NUM_TIMERS); + ASSERT_EQ(close_cb_called, NUM_TIMERS); free(timers); fprintf(stderr, "%.2f seconds total\n", (after_all - before_all) / 1e9); diff --git a/test/benchmark-multi-accept.c b/test/benchmark-multi-accept.c index e2026276721..1d19e330b2b 100644 --- a/test/benchmark-multi-accept.c +++ b/test/benchmark-multi-accept.c @@ -117,19 +117,19 @@ static void ipc_connection_cb(uv_stream_t* ipc_pipe, int status) { ASSERT_NOT_NULL(pc); if (ipc_pipe->type == UV_TCP) - ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &pc->peer_handle)); + ASSERT_OK(uv_tcp_init(loop, (uv_tcp_t*) &pc->peer_handle)); else if (ipc_pipe->type == UV_NAMED_PIPE) - ASSERT(0 == uv_pipe_init(loop, (uv_pipe_t*) &pc->peer_handle, 1)); + ASSERT_OK(uv_pipe_init(loop, (uv_pipe_t*) &pc->peer_handle, 1)); else ASSERT(0); - ASSERT(0 == uv_accept(ipc_pipe, (uv_stream_t*) &pc->peer_handle)); - ASSERT(0 == uv_write2(&pc->write_req, - (uv_stream_t*) &pc->peer_handle, - &buf, - 1, - (uv_stream_t*) &sc->server_handle, - ipc_write_cb)); + ASSERT_OK(uv_accept(ipc_pipe, (uv_stream_t*) &pc->peer_handle)); + ASSERT_OK(uv_write2(&pc->write_req, + (uv_stream_t*) &pc->peer_handle, + &buf, + 1, + (uv_stream_t*) &sc->server_handle, + ipc_write_cb)); if (--sc->num_connects == 0) uv_close((uv_handle_t*) ipc_pipe, NULL); @@ -153,10 +153,10 @@ static void ipc_close_cb(uv_handle_t* handle) { static void ipc_connect_cb(uv_connect_t* req, int status) { struct ipc_client_ctx* ctx; ctx = container_of(req, struct ipc_client_ctx, connect_req); - ASSERT(0 == status); - ASSERT(0 == uv_read_start((uv_stream_t*) &ctx->ipc_pipe, - ipc_alloc_cb, - ipc_read_cb)); + ASSERT_OK(status); + ASSERT_OK(uv_read_start((uv_stream_t*) &ctx->ipc_pipe, + ipc_alloc_cb, + ipc_read_cb)); } @@ -182,16 +182,16 @@ static void ipc_read_cb(uv_stream_t* handle, ctx = container_of(ipc_pipe, struct ipc_client_ctx, ipc_pipe); loop = ipc_pipe->loop; - ASSERT(1 == uv_pipe_pending_count(ipc_pipe)); + ASSERT_EQ(1, uv_pipe_pending_count(ipc_pipe)); type = uv_pipe_pending_type(ipc_pipe); if (type == UV_TCP) - ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) ctx->server_handle)); + ASSERT_OK(uv_tcp_init(loop, (uv_tcp_t*) ctx->server_handle)); else if (type == UV_NAMED_PIPE) - ASSERT(0 == uv_pipe_init(loop, (uv_pipe_t*) ctx->server_handle, 0)); + ASSERT_OK(uv_pipe_init(loop, (uv_pipe_t*) ctx->server_handle, 0)); else ASSERT(0); - ASSERT(0 == uv_accept(handle, ctx->server_handle)); + ASSERT_OK(uv_accept(handle, ctx->server_handle)); uv_close((uv_handle_t*) &ctx->ipc_pipe, NULL); } @@ -211,10 +211,10 @@ static void send_listen_handles(uv_handle_type type, ctx.num_connects = num_servers; if (type == UV_TCP) { - ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &ctx.server_handle)); - ASSERT(0 == uv_tcp_bind((uv_tcp_t*) &ctx.server_handle, - (const struct sockaddr*) &listen_addr, - 0)); + ASSERT_OK(uv_tcp_init(loop, (uv_tcp_t*) &ctx.server_handle)); + ASSERT_OK(uv_tcp_bind((uv_tcp_t*) &ctx.server_handle, + (const struct sockaddr*) &listen_addr, + 0)); } else ASSERT(0); @@ -223,16 +223,16 @@ static void send_listen_handles(uv_handle_type type, * If we accept a connection then the connected pipe must be initialized * with ipc=1. */ - ASSERT(0 == uv_pipe_init(loop, &ctx.ipc_pipe, 0)); - ASSERT(0 == uv_pipe_bind(&ctx.ipc_pipe, IPC_PIPE_NAME)); - ASSERT(0 == uv_listen((uv_stream_t*) &ctx.ipc_pipe, 128, ipc_connection_cb)); + ASSERT_OK(uv_pipe_init(loop, &ctx.ipc_pipe, 0)); + ASSERT_OK(uv_pipe_bind(&ctx.ipc_pipe, IPC_PIPE_NAME)); + ASSERT_OK(uv_listen((uv_stream_t*) &ctx.ipc_pipe, 128, ipc_connection_cb)); for (i = 0; i < num_servers; i++) uv_sem_post(&servers[i].semaphore); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); uv_close((uv_handle_t*) &ctx.server_handle, NULL); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); for (i = 0; i < num_servers; i++) uv_sem_wait(&servers[i].semaphore); @@ -245,12 +245,12 @@ static void get_listen_handle(uv_loop_t* loop, uv_stream_t* server_handle) { ctx.server_handle = server_handle; ctx.server_handle->data = "server handle"; - ASSERT(0 == uv_pipe_init(loop, &ctx.ipc_pipe, 1)); + ASSERT_OK(uv_pipe_init(loop, &ctx.ipc_pipe, 1)); uv_pipe_connect(&ctx.connect_req, &ctx.ipc_pipe, IPC_PIPE_NAME, ipc_connect_cb); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); } @@ -259,9 +259,9 @@ static void server_cb(void *arg) { uv_loop_t loop; ctx = arg; - ASSERT(0 == uv_loop_init(&loop)); + ASSERT_OK(uv_loop_init(&loop)); - ASSERT(0 == uv_async_init(&loop, &ctx->async_handle, sv_async_cb)); + ASSERT_OK(uv_async_init(&loop, &ctx->async_handle, sv_async_cb)); uv_unref((uv_handle_t*) &ctx->async_handle); /* Wait until the main thread is ready. */ @@ -270,10 +270,10 @@ static void server_cb(void *arg) { uv_sem_post(&ctx->semaphore); /* Now start the actual benchmark. */ - ASSERT(0 == uv_listen((uv_stream_t*) &ctx->server_handle, - 128, - sv_connection_cb)); - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_listen((uv_stream_t*) &ctx->server_handle, + 128, + sv_connection_cb)); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); uv_loop_close(&loop); } @@ -292,20 +292,20 @@ static void sv_connection_cb(uv_stream_t* server_handle, int status) { struct server_ctx* ctx; ctx = container_of(server_handle, struct server_ctx, server_handle); - ASSERT(status == 0); + ASSERT_OK(status); storage = malloc(sizeof(*storage)); ASSERT_NOT_NULL(storage); if (server_handle->type == UV_TCP) - ASSERT(0 == uv_tcp_init(server_handle->loop, (uv_tcp_t*) storage)); + ASSERT_OK(uv_tcp_init(server_handle->loop, (uv_tcp_t*) storage)); else if (server_handle->type == UV_NAMED_PIPE) - ASSERT(0 == uv_pipe_init(server_handle->loop, (uv_pipe_t*) storage, 0)); + ASSERT_OK(uv_pipe_init(server_handle->loop, (uv_pipe_t*) storage, 0)); else ASSERT(0); - ASSERT(0 == uv_accept(server_handle, (uv_stream_t*) storage)); - ASSERT(0 == uv_read_start((uv_stream_t*) storage, sv_alloc_cb, sv_read_cb)); + ASSERT_OK(uv_accept(server_handle, (uv_stream_t*) storage)); + ASSERT_OK(uv_read_start((uv_stream_t*) storage, sv_alloc_cb, sv_read_cb)); ctx->num_connects++; } @@ -322,7 +322,7 @@ static void sv_alloc_cb(uv_handle_t* handle, static void sv_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { - ASSERT(nread == UV_EOF); + ASSERT_EQ(nread, UV_EOF); uv_close((uv_handle_t*) handle, (uv_close_cb) free); } @@ -330,7 +330,7 @@ static void sv_read_cb(uv_stream_t* handle, static void cl_connect_cb(uv_connect_t* req, int status) { struct client_ctx* ctx = container_of(req, struct client_ctx, connect_req); uv_idle_start(&ctx->idle_handle, cl_idle_cb); - ASSERT(0 == status); + ASSERT_OK(status); } @@ -351,11 +351,11 @@ static void cl_close_cb(uv_handle_t* handle) { return; } - ASSERT(0 == uv_tcp_init(handle->loop, (uv_tcp_t*) &ctx->client_handle)); - ASSERT(0 == uv_tcp_connect(&ctx->connect_req, - (uv_tcp_t*) &ctx->client_handle, - (const struct sockaddr*) &listen_addr, - cl_connect_cb)); + ASSERT_OK(uv_tcp_init(handle->loop, (uv_tcp_t*) &ctx->client_handle)); + ASSERT_OK(uv_tcp_connect(&ctx->connect_req, + (uv_tcp_t*) &ctx->client_handle, + (const struct sockaddr*) &listen_addr, + cl_connect_cb)); } @@ -367,7 +367,7 @@ static int test_tcp(unsigned int num_servers, unsigned int num_clients) { unsigned int i; double time; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &listen_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &listen_addr)); loop = uv_default_loop(); servers = calloc(num_servers, sizeof(servers[0])); @@ -381,8 +381,8 @@ static int test_tcp(unsigned int num_servers, unsigned int num_clients) { */ for (i = 0; i < num_servers; i++) { struct server_ctx* ctx = servers + i; - ASSERT(0 == uv_sem_init(&ctx->semaphore, 0)); - ASSERT(0 == uv_thread_create(&ctx->thread_id, server_cb, ctx)); + ASSERT_OK(uv_sem_init(&ctx->semaphore, 0)); + ASSERT_OK(uv_thread_create(&ctx->thread_id, server_cb, ctx)); } send_listen_handles(UV_TCP, num_servers, servers); @@ -392,17 +392,17 @@ static int test_tcp(unsigned int num_servers, unsigned int num_clients) { ctx->num_connects = NUM_CONNECTS / num_clients; handle = (uv_tcp_t*) &ctx->client_handle; handle->data = "client handle"; - ASSERT(0 == uv_tcp_init(loop, handle)); - ASSERT(0 == uv_tcp_connect(&ctx->connect_req, - handle, - (const struct sockaddr*) &listen_addr, - cl_connect_cb)); - ASSERT(0 == uv_idle_init(loop, &ctx->idle_handle)); + ASSERT_OK(uv_tcp_init(loop, handle)); + ASSERT_OK(uv_tcp_connect(&ctx->connect_req, + handle, + (const struct sockaddr*) &listen_addr, + cl_connect_cb)); + ASSERT_OK(uv_idle_init(loop, &ctx->idle_handle)); } { uint64_t t = uv_hrtime(); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); t = uv_hrtime() - t; time = t / 1e9; } @@ -410,7 +410,7 @@ static int test_tcp(unsigned int num_servers, unsigned int num_clients) { for (i = 0; i < num_servers; i++) { struct server_ctx* ctx = servers + i; uv_async_send(&ctx->async_handle); - ASSERT(0 == uv_thread_join(&ctx->thread_id)); + ASSERT_OK(uv_thread_join(&ctx->thread_id)); uv_sem_destroy(&ctx->semaphore); } diff --git a/test/benchmark-ping-pongs.c b/test/benchmark-ping-pongs.c index 0357704e66e..fd5f40b9103 100644 --- a/test/benchmark-ping-pongs.c +++ b/test/benchmark-ping-pongs.c @@ -90,7 +90,7 @@ static void pinger_close_cb(uv_handle_t* handle) { static void pinger_write_cb(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); free(req); } @@ -110,14 +110,14 @@ static void pinger_write_ping(pinger_t* pinger) { static void pinger_shutdown_cb(uv_shutdown_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); pinger_shutdown_cb_called++; /* * The close callback has not been triggered yet. We must wait for EOF * until we close the connection. */ - ASSERT(completed_pingers == 0); + ASSERT_OK(completed_pingers); } @@ -130,13 +130,13 @@ static void pinger_read_cb(uv_stream_t* tcp, pinger = (pinger_t*)tcp->data; if (nread < 0) { - ASSERT(nread == UV_EOF); + ASSERT_EQ(nread, UV_EOF); if (buf->base) { buf_free(buf); } - ASSERT(pinger_shutdown_cb_called == 1); + ASSERT_EQ(1, pinger_shutdown_cb_called); uv_close((uv_handle_t*)tcp, pinger_close_cb); return; @@ -144,7 +144,7 @@ static void pinger_read_cb(uv_stream_t* tcp, /* Now we count the pings */ for (i = 0; i < nread; i++) { - ASSERT(buf->base[i] == PING[pinger->state]); + ASSERT_EQ(buf->base[i], PING[pinger->state]); pinger->state = (pinger->state + 1) % (sizeof(PING) - 1); if (pinger->state == 0) { pinger->pongs++; @@ -166,7 +166,7 @@ static void pinger_read_cb(uv_stream_t* tcp, static void pinger_connect_cb(uv_connect_t* req, int status) { pinger_t *pinger = (pinger_t*)req->handle->data; - ASSERT(status == 0); + ASSERT_OK(status); pinger_write_ping(pinger); @@ -182,8 +182,8 @@ static void pinger_new(void) { pinger_t *pinger; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &client_addr)); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", 0, &client_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); pinger = malloc(sizeof(*pinger)); pinger->state = 0; pinger->pongs = 0; @@ -194,9 +194,9 @@ static void pinger_new(void) { pinger->tcp.data = pinger; - ASSERT(0 == uv_tcp_bind(&pinger->tcp, - (const struct sockaddr*) &client_addr, - 0)); + ASSERT_OK(uv_tcp_bind(&pinger->tcp, + (const struct sockaddr*) &client_addr, + 0)); r = uv_tcp_connect(&pinger->connect_req, &pinger->tcp, @@ -214,7 +214,7 @@ BENCHMARK_IMPL(ping_pongs) { pinger_new(); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(completed_pingers == 1); + ASSERT_EQ(1, completed_pingers); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/benchmark-ping-udp.c b/test/benchmark-ping-udp.c index 3db8765bf9c..2d2fe9c6339 100644 --- a/test/benchmark-ping-udp.c +++ b/test/benchmark-ping-udp.c @@ -95,11 +95,11 @@ static void pinger_read_cb(uv_udp_t* udp, pinger = (pinger_t*)udp->data; /* No data here means something went wrong */ - ASSERT(nread > 0); + ASSERT_GT(nread, 0); /* Now we count the pings */ for (i = 0; i < nread; i++) { - ASSERT(buf->base[i] == PING[pinger->state]); + ASSERT_EQ(buf->base[i], PING[pinger->state]); pinger->state = (pinger->state + 1) % (sizeof(PING) - 1); if (pinger->state == 0) { pinger->pongs++; @@ -119,15 +119,15 @@ static void udp_pinger_new(void) { pinger_t* pinger = malloc(sizeof(*pinger)); int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &pinger->server_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &pinger->server_addr)); pinger->state = 0; pinger->pongs = 0; /* Try to do NUM_PINGS ping-pongs (connection-less). */ r = uv_udp_init(loop, &pinger->udp); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&pinger->udp, (const struct sockaddr*) &pinger->server_addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); pinger->udp.data = pinger; @@ -148,7 +148,7 @@ static int ping_udp(unsigned pingers) { udp_pinger_new(); } uv_run(loop, UV_RUN_DEFAULT); - ASSERT(completed_pingers >= 1); + ASSERT_GE(completed_pingers, 1); fprintf(stderr, "ping_pongs: %d pingers, ~ %lu roundtrips/s\n", completed_pingers, completed_pings / (TIME/1000)); diff --git a/test/benchmark-pound.c b/test/benchmark-pound.c index acfe4497a2e..83ce522779a 100644 --- a/test/benchmark-pound.c +++ b/test/benchmark-pound.c @@ -115,7 +115,7 @@ static void connect_cb(uv_connect_t* req, int status) { } ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); conn = (conn_rec*)req->data; ASSERT_NOT_NULL(conn); @@ -125,13 +125,13 @@ static void connect_cb(uv_connect_t* req, int status) { #endif r = uv_read_start(&conn->stream, alloc_cb, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); buf.base = buffer; buf.len = sizeof(buffer) - 1; r = uv_write(&conn->write_req, &conn->stream, &buf, 1, after_write); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -200,9 +200,9 @@ static void tcp_make_connect(conn_rec* p) { tp = (tcp_conn_rec*) p; r = uv_tcp_init(loop, (uv_tcp_t*)&p->stream); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_connect(&tp->conn_req, (uv_tcp_t*) &p->stream, @@ -227,7 +227,7 @@ static void pipe_make_connect(conn_rec* p) { int r; r = uv_pipe_init(loop, (uv_pipe_t*)&p->stream, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_pipe_connect(&((pipe_conn_rec*) p)->conn_req, (uv_pipe_t*) &p->stream, diff --git a/test/benchmark-pump.c b/test/benchmark-pump.c index 316c6809960..8ab4bc8046f 100644 --- a/test/benchmark-pump.c +++ b/test/benchmark-pump.c @@ -159,9 +159,9 @@ static void start_stats_collection(void) { /* Show-stats timer */ stats_left = STATS_COUNT; r = uv_timer_init(loop, &timer_handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer_handle, show_stats, STATS_INTERVAL, STATS_INTERVAL); - ASSERT(r == 0); + ASSERT_OK(r); uv_update_time(loop); start_time = uv_now(loop); @@ -170,7 +170,7 @@ static void start_stats_collection(void) { static void read_cb(uv_stream_t* stream, ssize_t bytes, const uv_buf_t* buf) { if (nrecv_total == 0) { - ASSERT(start_time == 0); + ASSERT_OK(start_time); uv_update_time(loop); start_time = uv_now(loop); } @@ -188,7 +188,7 @@ static void read_cb(uv_stream_t* stream, ssize_t bytes, const uv_buf_t* buf) { static void write_cb(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); req_free((uv_req_t*) req); @@ -209,7 +209,7 @@ static void do_write(uv_stream_t* stream) { req = (uv_write_t*) req_alloc(); r = uv_write(req, stream, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -220,7 +220,7 @@ static void connect_cb(uv_connect_t* req, int status) { fprintf(stderr, "%s", uv_strerror(status)); fflush(stderr); } - ASSERT(status == 0); + ASSERT_OK(status); write_sockets++; req_free((uv_req_t*) req); @@ -253,19 +253,19 @@ static void maybe_connect_some(void) { tcp = &tcp_write_handles[max_connect_socket++]; r = uv_tcp_init(loop, tcp); - ASSERT(r == 0); + ASSERT_OK(r); req = (uv_connect_t*) req_alloc(); r = uv_tcp_connect(req, tcp, (const struct sockaddr*) &connect_addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); } else { pipe = &pipe_write_handles[max_connect_socket++]; r = uv_pipe_init(loop, pipe, 0); - ASSERT(r == 0); + ASSERT_OK(r); req = (uv_connect_t*) req_alloc(); uv_pipe_connect(req, pipe, TEST_PIPENAME, connect_cb); @@ -278,24 +278,24 @@ static void connection_cb(uv_stream_t* s, int status) { uv_stream_t* stream; int r; - ASSERT(server == s); - ASSERT(status == 0); + ASSERT_EQ(server, s); + ASSERT_OK(status); if (type == TCP) { stream = (uv_stream_t*)malloc(sizeof(uv_tcp_t)); r = uv_tcp_init(loop, (uv_tcp_t*)stream); - ASSERT(r == 0); + ASSERT_OK(r); } else { stream = (uv_stream_t*)malloc(sizeof(uv_pipe_t)); r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0); - ASSERT(r == 0); + ASSERT_OK(r); } r = uv_accept(s, stream); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start(stream, buf_alloc, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); read_sockets++; max_read_sockets++; @@ -379,16 +379,16 @@ HELPER_IMPL(tcp_pump_server) { type = TCP; loop = uv_default_loop(); - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &listen_addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &listen_addr)); /* Server */ server = (uv_stream_t*)&tcpServer; r = uv_tcp_init(loop, &tcpServer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &listen_addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&tcpServer, MAX_WRITE_HANDLES, connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); notify_parent_process(); uv_run(loop, UV_RUN_DEFAULT); @@ -406,11 +406,11 @@ HELPER_IMPL(pipe_pump_server) { /* Server */ server = (uv_stream_t*)&pipeServer; r = uv_pipe_init(loop, &pipeServer, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_bind(&pipeServer, TEST_PIPENAME); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&pipeServer, MAX_WRITE_HANDLES, connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); notify_parent_process(); uv_run(loop, UV_RUN_DEFAULT); @@ -421,13 +421,13 @@ HELPER_IMPL(pipe_pump_server) { static void tcp_pump(int n) { - ASSERT(n <= MAX_WRITE_HANDLES); + ASSERT_LE(n, MAX_WRITE_HANDLES); TARGET_CONNECTIONS = n; type = TCP; loop = uv_default_loop(); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &connect_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &connect_addr)); /* Start making connections */ maybe_connect_some(); @@ -439,7 +439,7 @@ static void tcp_pump(int n) { static void pipe_pump(int n) { - ASSERT(n <= MAX_WRITE_HANDLES); + ASSERT_LE(n, MAX_WRITE_HANDLES); TARGET_CONNECTIONS = n; type = PIPE; diff --git a/test/benchmark-queue-work.c b/test/benchmark-queue-work.c index 6e7b74becf6..5ae0883101f 100644 --- a/test/benchmark-queue-work.c +++ b/test/benchmark-queue-work.c @@ -40,7 +40,7 @@ static void work_cb(uv_work_t* req) { static void after_work_cb(uv_work_t* req, int status) { events++; if (!done) - ASSERT_EQ(0, uv_queue_work(req->loop, req, work_cb, after_work_cb)); + ASSERT_OK(uv_queue_work(req->loop, req, work_cb, after_work_cb)); } static void timer_cb(uv_timer_t* handle) { done = 1; } @@ -55,11 +55,11 @@ BENCHMARK_IMPL(queue_work) { loop = uv_default_loop(); timeout = 5000; - ASSERT_EQ(0, uv_timer_init(loop, &timer_handle)); - ASSERT_EQ(0, uv_timer_start(&timer_handle, timer_cb, timeout, 0)); + ASSERT_OK(uv_timer_init(loop, &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, timeout, 0)); - ASSERT_EQ(0, uv_queue_work(loop, &work, work_cb, after_work_cb)); - ASSERT_EQ(0, uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_queue_work(loop, &work, work_cb, after_work_cb)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); printf("%s async jobs in %.1f seconds (%s/s)\n", fmt(&fmtbuf[0], events), diff --git a/test/benchmark-spawn.c b/test/benchmark-spawn.c index bdaf6c1a254..ef27b385e7a 100644 --- a/test/benchmark-spawn.c +++ b/test/benchmark-spawn.c @@ -58,7 +58,7 @@ static void maybe_spawn(void) { static void process_close_cb(uv_handle_t* handle) { - ASSERT(process_open == 1); + ASSERT_EQ(1, process_open); process_open = 0; maybe_spawn(); } @@ -67,8 +67,8 @@ static void process_close_cb(uv_handle_t* handle) { static void exit_cb(uv_process_t* process, int64_t exit_status, int term_signal) { - ASSERT(exit_status == 42); - ASSERT(term_signal == 0); + ASSERT_EQ(42, exit_status); + ASSERT_OK(term_signal); uv_close((uv_handle_t*)process, process_close_cb); } @@ -82,7 +82,7 @@ static void on_alloc(uv_handle_t* handle, static void pipe_close_cb(uv_handle_t* pipe) { - ASSERT(pipe_open == 1); + ASSERT_EQ(1, pipe_open); pipe_open = 0; maybe_spawn(); } @@ -90,7 +90,7 @@ static void pipe_close_cb(uv_handle_t* pipe) { static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) { if (nread > 0) { - ASSERT(pipe_open == 1); + ASSERT_EQ(1, pipe_open); output_used += nread; } else if (nread < 0) { if (nread == UV_EOF) { @@ -104,8 +104,8 @@ static void spawn(void) { uv_stdio_container_t stdio[2]; int r; - ASSERT(process_open == 0); - ASSERT(pipe_open == 0); + ASSERT_OK(process_open); + ASSERT_OK(pipe_open); args[0] = exepath; args[1] = "spawn_helper"; @@ -123,14 +123,14 @@ static void spawn(void) { options.stdio[1].data.stream = (uv_stream_t*)&out; r = uv_spawn(loop, &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); process_open = 1; pipe_open = 1; output_used = 0; r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -141,7 +141,7 @@ BENCHMARK_IMPL(spawn) { loop = uv_default_loop(); r = uv_exepath(exepath, &exepath_size); - ASSERT(r == 0); + ASSERT_OK(r); exepath[exepath_size] = '\0'; uv_update_time(loop); @@ -150,7 +150,7 @@ BENCHMARK_IMPL(spawn) { spawn(); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); uv_update_time(loop); end_time = uv_now(loop); diff --git a/test/benchmark-tcp-write-batch.c b/test/benchmark-tcp-write-batch.c index aedefb74255..9dfcf14eb09 100644 --- a/test/benchmark-tcp-write-batch.c +++ b/test/benchmark-tcp-write-batch.c @@ -55,16 +55,16 @@ static void connect_cb(uv_connect_t* req, int status) { int i; int r; - ASSERT(req->handle == (uv_stream_t*)&tcp_client); + ASSERT_PTR_EQ(req->handle, (uv_stream_t*)&tcp_client); for (i = 0; i < NUM_WRITE_REQS; i++) { w = &write_reqs[i]; r = uv_write(&w->req, req->handle, &w->buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); } r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb); - ASSERT(r == 0); + ASSERT_OK(r); connect_cb_called++; } @@ -72,14 +72,14 @@ static void connect_cb(uv_connect_t* req, int status) { static void write_cb(uv_write_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); write_cb_called++; } static void shutdown_cb(uv_shutdown_t* req, int status) { - ASSERT(req->handle == (uv_stream_t*)&tcp_client); - ASSERT(req->handle->write_queue_size == 0); + ASSERT_PTR_EQ(req->handle, (uv_stream_t*)&tcp_client); + ASSERT_OK(req->handle->write_queue_size); uv_close((uv_handle_t*)req->handle, close_cb); free(write_reqs); @@ -89,7 +89,7 @@ static void shutdown_cb(uv_shutdown_t* req, int status) { static void close_cb(uv_handle_t* handle) { - ASSERT(handle == (uv_handle_t*)&tcp_client); + ASSERT_PTR_EQ(handle, (uv_handle_t*)&tcp_client); close_cb_called++; } @@ -112,28 +112,28 @@ BENCHMARK_IMPL(tcp_write_batch) { } loop = uv_default_loop(); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init(loop, &tcp_client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &tcp_client, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); start = uv_hrtime(); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); stop = uv_hrtime(); - ASSERT(connect_cb_called == 1); - ASSERT(write_cb_called == NUM_WRITE_REQS); - ASSERT(shutdown_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(write_cb_called, NUM_WRITE_REQS); + ASSERT_EQ(1, shutdown_cb_called); + ASSERT_EQ(1, close_cb_called); printf("%ld write requests in %.2fs.\n", (long)NUM_WRITE_REQS, diff --git a/test/benchmark-thread.c b/test/benchmark-thread.c index b37a7fd6d01..b339e7caad9 100644 --- a/test/benchmark-thread.c +++ b/test/benchmark-thread.c @@ -31,7 +31,7 @@ static volatile int num_threads; static void thread_entry(void* arg) { - ASSERT(arg == (void *) 42); + ASSERT_PTR_EQ(arg, (void *) 42); num_threads++; /* FIXME write barrier? */ } @@ -47,15 +47,15 @@ BENCHMARK_IMPL(thread_create) { for (i = 0; i < NUM_THREADS; i++) { r = uv_thread_create(&tid, thread_entry, (void *) 42); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_thread_join(&tid); - ASSERT(r == 0); + ASSERT_OK(r); } duration = (uv_hrtime() - start_time) / 1e9; - ASSERT(num_threads == NUM_THREADS); + ASSERT_EQ(num_threads, NUM_THREADS); printf("%d threads created in %.2f seconds (%.0f/s)\n", NUM_THREADS, duration, NUM_THREADS / duration); diff --git a/test/benchmark-udp-pummel.c b/test/benchmark-udp-pummel.c index f89913b6ceb..7b7e1afad7d 100644 --- a/test/benchmark-udp-pummel.c +++ b/test/benchmark-udp-pummel.c @@ -63,7 +63,7 @@ static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { static char slab[65536]; - ASSERT(suggested_size <= sizeof(slab)); + ASSERT_LE(suggested_size, sizeof(slab)); buf->base = slab; buf->len = sizeof(slab); } @@ -75,7 +75,7 @@ static void send_cb(uv_udp_send_t* req, int status) { ASSERT_NOT_NULL(req); if (status != 0) { - ASSERT(status == UV_ECANCELED); + ASSERT_EQ(status, UV_ECANCELED); return; } @@ -83,7 +83,7 @@ static void send_cb(uv_udp_send_t* req, int status) { return; s = container_of(req, struct sender_state, send_req); - ASSERT(req->handle == &s->udp_handle); + ASSERT_PTR_EQ(req->handle, &s->udp_handle); if (timed) goto send; @@ -96,12 +96,12 @@ static void send_cb(uv_udp_send_t* req, int status) { packet_counter--; send: - ASSERT(0 == uv_udp_send(&s->send_req, - &s->udp_handle, - bufs, - ARRAY_SIZE(bufs), - (const struct sockaddr*) &s->addr, - send_cb)); + ASSERT_OK(uv_udp_send(&s->send_req, + &s->udp_handle, + bufs, + ARRAY_SIZE(bufs), + (const struct sockaddr*) &s->addr, + send_cb)); send_cb_called++; } @@ -115,11 +115,11 @@ static void recv_cb(uv_udp_t* handle, return; if (nread < 0) { - ASSERT(nread == UV_ECANCELED); + ASSERT_EQ(nread, UV_ECANCELED); return; } - ASSERT(addr->sa_family == AF_INET); + ASSERT_EQ(addr->sa_family, AF_INET); ASSERT(!memcmp(buf->base, EXPECTED, nread)); recv_cb_called++; @@ -153,8 +153,8 @@ static int pummel(unsigned int n_senders, uv_loop_t* loop; unsigned int i; - ASSERT(n_senders <= ARRAY_SIZE(senders)); - ASSERT(n_receivers <= ARRAY_SIZE(receivers)); + ASSERT_LE(n_senders, ARRAY_SIZE(senders)); + ASSERT_LE(n_receivers, ARRAY_SIZE(receivers)); loop = uv_default_loop(); @@ -162,8 +162,8 @@ static int pummel(unsigned int n_senders, n_receivers_ = n_receivers; if (timeout) { - ASSERT(0 == uv_timer_init(loop, &timer_handle)); - ASSERT(0 == uv_timer_start(&timer_handle, timeout_cb, timeout, 0)); + ASSERT_OK(uv_timer_init(loop, &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, timeout_cb, timeout, 0)); /* Timer should not keep loop alive. */ uv_unref((uv_handle_t*)&timer_handle); timed = 1; @@ -172,10 +172,10 @@ static int pummel(unsigned int n_senders, for (i = 0; i < n_receivers; i++) { struct receiver_state* s = receivers + i; struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("0.0.0.0", BASE_PORT + i, &addr)); - ASSERT(0 == uv_udp_init(loop, &s->udp_handle)); - ASSERT(0 == uv_udp_bind(&s->udp_handle, (const struct sockaddr*) &addr, 0)); - ASSERT(0 == uv_udp_recv_start(&s->udp_handle, alloc_cb, recv_cb)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", BASE_PORT + i, &addr)); + ASSERT_OK(uv_udp_init(loop, &s->udp_handle)); + ASSERT_OK(uv_udp_bind(&s->udp_handle, (const struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_udp_recv_start(&s->udp_handle, alloc_cb, recv_cb)); uv_unref((uv_handle_t*)&s->udp_handle); } @@ -187,20 +187,20 @@ static int pummel(unsigned int n_senders, for (i = 0; i < n_senders; i++) { struct sender_state* s = senders + i; - ASSERT(0 == uv_ip4_addr("127.0.0.1", - BASE_PORT + (i % n_receivers), - &s->addr)); - ASSERT(0 == uv_udp_init(loop, &s->udp_handle)); - ASSERT(0 == uv_udp_send(&s->send_req, - &s->udp_handle, - bufs, - ARRAY_SIZE(bufs), - (const struct sockaddr*) &s->addr, - send_cb)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", + BASE_PORT + (i % n_receivers), + &s->addr)); + ASSERT_OK(uv_udp_init(loop, &s->udp_handle)); + ASSERT_OK(uv_udp_send(&s->send_req, + &s->udp_handle, + bufs, + ARRAY_SIZE(bufs), + (const struct sockaddr*) &s->addr, + send_cb)); } duration = uv_hrtime(); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); duration = uv_hrtime() - duration; /* convert from nanoseconds to milliseconds */ duration = duration / (uint64_t) 1e6; diff --git a/test/blackhole-server.c b/test/blackhole-server.c index 0a8758e1a17..79d6146f479 100644 --- a/test/blackhole-server.c +++ b/test/blackhole-server.c @@ -43,20 +43,20 @@ static void connection_cb(uv_stream_t* stream, int status) { conn_rec* conn; int r; - ASSERT(status == 0); - ASSERT(stream == (uv_stream_t*)&tcp_server); + ASSERT_OK(status); + ASSERT_PTR_EQ(stream, (uv_stream_t*)&tcp_server); conn = malloc(sizeof *conn); ASSERT_NOT_NULL(conn); r = uv_tcp_init(stream->loop, &conn->handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_accept(stream, (uv_stream_t*)&conn->handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*)&conn->handle, alloc_cb, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -76,12 +76,12 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { if (nread >= 0) return; - ASSERT(nread == UV_EOF); + ASSERT_EQ(nread, UV_EOF); conn = container_of(stream, conn_rec, handle); r = uv_shutdown(&conn->shutdown_req, stream, shutdown_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -103,16 +103,16 @@ HELPER_IMPL(tcp4_blackhole_server) { int r; loop = uv_default_loop(); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init(loop, &tcp_server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&tcp_server, 128, connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); notify_parent_process(); r = uv_run(loop, UV_RUN_DEFAULT); diff --git a/test/echo-server.c b/test/echo-server.c index 058c9925475..572f87df51e 100644 --- a/test/echo-server.c +++ b/test/echo-server.c @@ -65,14 +65,14 @@ static void after_write(uv_write_t* req, int status) { static void after_shutdown(uv_shutdown_t* req, int status) { - ASSERT_EQ(status, 0); + ASSERT_OK(status); uv_close((uv_handle_t*) req->handle, on_close); free(req); } static void on_shutdown(uv_shutdown_t* req, int status) { - ASSERT_EQ(status, 0); + ASSERT_OK(status); free(req); } @@ -92,7 +92,7 @@ static void after_read(uv_stream_t* handle, free(buf->base); sreq = malloc(sizeof* sreq); if (uv_is_writable(handle)) { - ASSERT_EQ(0, uv_shutdown(sreq, handle, after_shutdown)); + ASSERT_OK(uv_shutdown(sreq, handle, after_shutdown)); } return; } @@ -118,7 +118,7 @@ static void after_read(uv_stream_t* handle, if (i + 2 < nread && buf->base[i + 2] == 'H') reset = 1; if (reset && handle->type == UV_TCP) - ASSERT_EQ(0, uv_tcp_close_reset((uv_tcp_t*) handle, on_close)); + ASSERT_OK(uv_tcp_close_reset((uv_tcp_t*) handle, on_close)); else if (shutdown) break; else @@ -141,7 +141,7 @@ static void after_read(uv_stream_t* handle, } if (shutdown) - ASSERT_EQ(0, uv_shutdown(malloc(sizeof* sreq), handle, on_shutdown)); + ASSERT_OK(uv_shutdown(malloc(sizeof* sreq), handle, on_shutdown)); } @@ -173,21 +173,21 @@ static void on_connection(uv_stream_t* server, int status) { if (status != 0) { fprintf(stderr, "Connect error %s\n", uv_err_name(status)); } - ASSERT(status == 0); + ASSERT_OK(status); switch (serverType) { case TCP: stream = malloc(sizeof(uv_tcp_t)); ASSERT_NOT_NULL(stream); r = uv_tcp_init(loop, (uv_tcp_t*)stream); - ASSERT(r == 0); + ASSERT_OK(r); break; case PIPE: stream = malloc(sizeof(uv_pipe_t)); ASSERT_NOT_NULL(stream); r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0); - ASSERT(r == 0); + ASSERT_OK(r); break; default: @@ -199,15 +199,15 @@ static void on_connection(uv_stream_t* server, int status) { stream->data = server; r = uv_accept(server, stream); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start(stream, echo_alloc, after_read); - ASSERT(r == 0); + ASSERT_OK(r); } static void on_server_close(uv_handle_t* handle) { - ASSERT(handle == server); + ASSERT_PTR_EQ(handle, server); } static uv_udp_send_t* send_alloc(void) { @@ -221,7 +221,7 @@ static uv_udp_send_t* send_alloc(void) { static void on_send(uv_udp_send_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); req->data = send_freelist; send_freelist = req; } @@ -239,20 +239,20 @@ static void on_recv(uv_udp_t* handle, return; } - ASSERT(nread > 0); - ASSERT(addr->sa_family == AF_INET); + ASSERT_GT(nread, 0); + ASSERT_EQ(addr->sa_family, AF_INET); req = send_alloc(); ASSERT_NOT_NULL(req); sndbuf = uv_buf_init(rcvbuf->base, nread); - ASSERT(0 <= uv_udp_send(req, handle, &sndbuf, 1, addr, on_send)); + ASSERT_LE(0, uv_udp_send(req, handle, &sndbuf, 1, addr, on_send)); } static int tcp4_echo_start(int port) { struct sockaddr_in addr; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", port, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", port, &addr)); server = (uv_handle_t*)&tcpServer; serverType = TCP; @@ -286,7 +286,7 @@ static int tcp6_echo_start(int port) { struct sockaddr_in6 addr6; int r; - ASSERT(0 == uv_ip6_addr("::1", port, &addr6)); + ASSERT_OK(uv_ip6_addr("::1", port, &addr6)); server = (uv_handle_t*)&tcpServer; serverType = TCP; @@ -321,7 +321,7 @@ static int udp4_echo_start(int port) { struct sockaddr_in addr; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", port, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", port, &addr)); server = (uv_handle_t*)&udpServer; serverType = UDP; diff --git a/test/run-tests.c b/test/run-tests.c index d8cfe297c49..ce1c0ef0665 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -145,7 +145,7 @@ static int maybe_run_test(int argc, char **argv) { if (strcmp(argv[1], "spawn_helper3") == 0) { char buffer[256]; notify_parent_process(); - ASSERT(buffer == fgets(buffer, sizeof(buffer) - 1, stdin)); + ASSERT_EQ(buffer, fgets(buffer, sizeof(buffer) - 1, stdin)); buffer[sizeof(buffer) - 1] = '\0'; fputs(buffer, stdout); return 1; @@ -183,10 +183,10 @@ static int maybe_run_test(int argc, char **argv) { notify_parent_process(); r = fprintf(stdout, "hello world\n"); - ASSERT(r > 0); + ASSERT_GT(r, 0); r = fprintf(stderr, "hello errworld\n"); - ASSERT(r > 0); + ASSERT_GT(r, 0); return 1; } @@ -202,7 +202,7 @@ static int maybe_run_test(int argc, char **argv) { ASSERT_NOT_NULL(test); r = fprintf(stdout, "%s", test); - ASSERT(r > 0); + ASSERT_GT(r, 0); return 1; } @@ -216,23 +216,24 @@ static int maybe_run_test(int argc, char **argv) { sCompareObjectHandles pCompareObjectHandles; /* function introduced in Windows 10 */ #endif notify_parent_process(); - ASSERT(sizeof(closed_fd) == read(0, &closed_fd, sizeof(closed_fd))); - ASSERT(sizeof(open_fd) == read(0, &open_fd, sizeof(open_fd))); + ASSERT_EQ(sizeof(closed_fd), read(0, &closed_fd, sizeof(closed_fd))); + ASSERT_EQ(sizeof(open_fd), read(0, &open_fd, sizeof(open_fd))); #ifdef _WIN32 - ASSERT((intptr_t) closed_fd > 0); - ASSERT((intptr_t) open_fd > 0); - ASSERT(0 != GetHandleInformation(open_fd, &flags)); + ASSERT_GT((intptr_t) closed_fd, 0); + ASSERT_GT((intptr_t) open_fd, 0); + ASSERT_NE(0, GetHandleInformation(open_fd, &flags)); kernelbase_module = GetModuleHandleA("kernelbase.dll"); pCompareObjectHandles = (sCompareObjectHandles) GetProcAddress(kernelbase_module, "CompareObjectHandles"); - ASSERT(pCompareObjectHandles == NULL || !pCompareObjectHandles(open_fd, closed_fd)); + ASSERT_NE(pCompareObjectHandles == NULL || \ + !pCompareObjectHandles(open_fd, closed_fd), 0); #else - ASSERT(open_fd > 2); - ASSERT(closed_fd > 2); + ASSERT_GT(open_fd, 2); + ASSERT_GT(closed_fd, 2); # if defined(__PASE__) /* On IBMi PASE, write() returns 1 */ - ASSERT(1 == write(closed_fd, "x", 1)); + ASSERT_EQ(1, write(closed_fd, "x", 1)); # else - ASSERT(-1 == write(closed_fd, "x", 1)); + ASSERT_EQ(-1, write(closed_fd, "x", 1)); # endif /* !__PASE__ */ #endif return 1; @@ -249,8 +250,8 @@ static int maybe_run_test(int argc, char **argv) { uv_uid_t uid = atoi(argv[2]); uv_gid_t gid = atoi(argv[3]); - ASSERT(uid == getuid()); - ASSERT(gid == getgid()); + ASSERT_EQ(uid, getuid()); + ASSERT_EQ(gid, getgid()); notify_parent_process(); return 1; diff --git a/test/runner-win.c b/test/runner-win.c index 8c2a00b8a62..61d6f1431be 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -185,7 +185,7 @@ int process_wait(process_info_t *vec, int n, int timeout) { if (n == 0) return 0; - ASSERT(n <= MAXIMUM_WAIT_OBJECTS); + ASSERT_LE(n, MAXIMUM_WAIT_OBJECTS); for (i = 0; i < n; i++) handles[i] = vec[i].process; @@ -245,7 +245,7 @@ int process_read_last_line(process_info_t *p, DWORD start; OVERLAPPED overlapped; - ASSERT(buffer_len > 0); + ASSERT_GT(buffer_len, 0); size = GetFileSize(p->stdio_out, NULL); if (size == INVALID_FILE_SIZE) diff --git a/test/task.h b/test/task.h index fa6cc0ed535..b93b4a98d09 100644 --- a/test/task.h +++ b/test/task.h @@ -250,7 +250,7 @@ typedef enum { #define MAKE_VALGRIND_HAPPY(loop) \ do { \ close_loop(loop); \ - ASSERT(0 == uv_loop_close(loop)); \ + ASSERT_EQ(0, uv_loop_close(loop)); \ uv_library_shutdown(); \ } while (0) diff --git a/test/test-active.c b/test/test-active.c index aaff97087b1..fadbd10d228 100644 --- a/test/test-active.c +++ b/test/test-active.c @@ -45,39 +45,39 @@ TEST_IMPL(active) { uv_timer_t timer; r = uv_timer_init(uv_default_loop(), &timer); - ASSERT(r == 0); + ASSERT_OK(r); /* uv_is_active() and uv_is_closing() should always return either 0 or 1. */ - ASSERT(0 == uv_is_active((uv_handle_t*) &timer)); - ASSERT(0 == uv_is_closing((uv_handle_t*) &timer)); + ASSERT_OK(uv_is_active((uv_handle_t*) &timer)); + ASSERT_OK(uv_is_closing((uv_handle_t*) &timer)); r = uv_timer_start(&timer, timer_cb, 1000, 0); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(1 == uv_is_active((uv_handle_t*) &timer)); - ASSERT(0 == uv_is_closing((uv_handle_t*) &timer)); + ASSERT_EQ(1, uv_is_active((uv_handle_t*) &timer)); + ASSERT_OK(uv_is_closing((uv_handle_t*) &timer)); r = uv_timer_stop(&timer); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_is_active((uv_handle_t*) &timer)); - ASSERT(0 == uv_is_closing((uv_handle_t*) &timer)); + ASSERT_OK(uv_is_active((uv_handle_t*) &timer)); + ASSERT_OK(uv_is_closing((uv_handle_t*) &timer)); r = uv_timer_start(&timer, timer_cb, 1000, 0); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(1 == uv_is_active((uv_handle_t*) &timer)); - ASSERT(0 == uv_is_closing((uv_handle_t*) &timer)); + ASSERT_EQ(1, uv_is_active((uv_handle_t*) &timer)); + ASSERT_OK(uv_is_closing((uv_handle_t*) &timer)); uv_close((uv_handle_t*) &timer, close_cb); - ASSERT(0 == uv_is_active((uv_handle_t*) &timer)); - ASSERT(1 == uv_is_closing((uv_handle_t*) &timer)); + ASSERT_OK(uv_is_active((uv_handle_t*) &timer)); + ASSERT_EQ(1, uv_is_closing((uv_handle_t*) &timer)); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-async-null-cb.c b/test/test-async-null-cb.c index 1bdd0e03249..ac9fc899c7a 100644 --- a/test/test-async-null-cb.c +++ b/test/test-async-null-cb.c @@ -36,7 +36,7 @@ static void thread_cb(void* dummy) { static void check_cb(uv_check_t* handle) { - ASSERT(check_cb_called == 0); + ASSERT_OK(check_cb_called); uv_close((uv_handle_t*) &async_handle, NULL); uv_close((uv_handle_t*) &check_handle, NULL); check_cb_called++; @@ -52,13 +52,13 @@ TEST_IMPL(async_null_cb) { */ memset(&async_handle, 0xff, sizeof(async_handle)); - ASSERT(0 == uv_async_init(uv_default_loop(), &async_handle, NULL)); - ASSERT(0 == uv_check_init(uv_default_loop(), &check_handle)); - ASSERT(0 == uv_check_start(&check_handle, check_cb)); - ASSERT(0 == uv_thread_create(&thread, thread_cb, NULL)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(0 == uv_thread_join(&thread)); - ASSERT(1 == check_cb_called); + ASSERT_OK(uv_async_init(uv_default_loop(), &async_handle, NULL)); + ASSERT_OK(uv_check_init(uv_default_loop(), &check_handle)); + ASSERT_OK(uv_check_start(&check_handle, check_cb)); + ASSERT_OK(uv_thread_create(&thread, thread_cb, NULL)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_thread_join(&thread)); + ASSERT_EQ(1, check_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-async.c b/test/test-async.c index 73664ea5d67..935436ec093 100644 --- a/test/test-async.c +++ b/test/test-async.c @@ -49,7 +49,7 @@ static void thread_cb(void *arg) { } r = uv_async_send(&async); - ASSERT(r == 0); + ASSERT_OK(r); /* Work around a bug in Valgrind. * @@ -78,7 +78,7 @@ static void close_cb(uv_handle_t* handle) { static void async_cb(uv_async_t* handle) { int n; - ASSERT(handle == &async); + ASSERT_PTR_EQ(handle, &async); uv_mutex_lock(&mutex); n = ++async_cb_called; @@ -94,13 +94,13 @@ static void async_cb(uv_async_t* handle) { static void prepare_cb(uv_prepare_t* handle) { int r; - ASSERT(handle == &prepare); + ASSERT_PTR_EQ(handle, &prepare); if (prepare_cb_called++) return; r = uv_thread_create(&thread, thread_cb, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_mutex_unlock(&mutex); } @@ -109,25 +109,25 @@ TEST_IMPL(async) { int r; r = uv_mutex_init(&mutex); - ASSERT(r == 0); + ASSERT_OK(r); uv_mutex_lock(&mutex); r = uv_prepare_init(uv_default_loop(), &prepare); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_prepare_start(&prepare, prepare_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_async_init(uv_default_loop(), &async, async_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(prepare_cb_called > 0); - ASSERT(async_cb_called == 3); - ASSERT(close_cb_called == 2); + ASSERT_GT(prepare_cb_called, 0); + ASSERT_EQ(3, async_cb_called); + ASSERT_EQ(2, close_cb_called); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-barrier.c b/test/test-barrier.c index c780f0cf2dd..5e904c40bc4 100644 --- a/test/test-barrier.c +++ b/test/test-barrier.c @@ -53,13 +53,13 @@ TEST_IMPL(barrier_1) { memset(&wc, 0, sizeof(wc)); wc.niter = 1; - ASSERT_EQ(0, uv_barrier_init(&wc.barrier, 2)); - ASSERT_EQ(0, uv_thread_create(&thread, worker, &wc)); + ASSERT_OK(uv_barrier_init(&wc.barrier, 2)); + ASSERT_OK(uv_thread_create(&thread, worker, &wc)); uv_sleep(100); wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier); - ASSERT_EQ(0, uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); uv_barrier_destroy(&wc.barrier); ASSERT_EQ(1, (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval)); @@ -76,12 +76,12 @@ TEST_IMPL(barrier_2) { wc.delay = 100; wc.niter = 1; - ASSERT_EQ(0, uv_barrier_init(&wc.barrier, 2)); - ASSERT_EQ(0, uv_thread_create(&thread, worker, &wc)); + ASSERT_OK(uv_barrier_init(&wc.barrier, 2)); + ASSERT_OK(uv_thread_create(&thread, worker, &wc)); wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier); - ASSERT_EQ(0, uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); uv_barrier_destroy(&wc.barrier); ASSERT_EQ(1, (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval)); @@ -98,13 +98,13 @@ TEST_IMPL(barrier_3) { memset(&wc, 0, sizeof(wc)); wc.niter = 5; - ASSERT_EQ(0, uv_barrier_init(&wc.barrier, 2)); - ASSERT_EQ(0, uv_thread_create(&thread, worker, &wc)); + ASSERT_OK(uv_barrier_init(&wc.barrier, 2)); + ASSERT_OK(uv_thread_create(&thread, worker, &wc)); for (i = 0; i < wc.niter; i++) wc.main_barrier_wait_rval += uv_barrier_wait(&wc.barrier); - ASSERT_EQ(0, uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); uv_barrier_destroy(&wc.barrier); ASSERT_EQ(wc.niter, wc.main_barrier_wait_rval + wc.worker_barrier_wait_rval); @@ -133,10 +133,10 @@ TEST_IMPL(barrier_serial_thread) { uv_barrier_t barrier; unsigned i; - ASSERT_EQ(0, uv_barrier_init(&barrier, ARRAY_SIZE(threads) + 1)); + ASSERT_OK(uv_barrier_init(&barrier, ARRAY_SIZE(threads) + 1)); for (i = 0; i < ARRAY_SIZE(threads); ++i) - ASSERT_EQ(0, uv_thread_create(&threads[i], serial_worker, &barrier)); + ASSERT_OK(uv_thread_create(&threads[i], serial_worker, &barrier)); for (i = 0; i < 5; i++) uv_barrier_wait(&barrier); @@ -144,7 +144,7 @@ TEST_IMPL(barrier_serial_thread) { uv_barrier_destroy(&barrier); for (i = 0; i < ARRAY_SIZE(threads); ++i) - ASSERT_EQ(0, uv_thread_join(&threads[i])); + ASSERT_OK(uv_thread_join(&threads[i])); return 0; } @@ -153,7 +153,7 @@ TEST_IMPL(barrier_serial_thread) { TEST_IMPL(barrier_serial_thread_single) { uv_barrier_t barrier; - ASSERT_EQ(0, uv_barrier_init(&barrier, 1)); + ASSERT_OK(uv_barrier_init(&barrier, 1)); ASSERT_LT(0, uv_barrier_wait(&barrier)); uv_barrier_destroy(&barrier); return 0; diff --git a/test/test-callback-stack.c b/test/test-callback-stack.c index 5dad8d75d2a..dfd102c0247 100644 --- a/test/test-callback-stack.c +++ b/test/test-callback-stack.c @@ -60,7 +60,7 @@ static void close_cb(uv_handle_t* handle) { static void shutdown_cb(uv_shutdown_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); ASSERT(nested == 0 && "shutdown_cb must be called from a fresh stack"); shutdown_cb_called++; @@ -77,7 +77,7 @@ static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { return; } else if (nread < 0) { - ASSERT(nread == UV_EOF); + ASSERT_EQ(nread, UV_EOF); nested++; uv_close((uv_handle_t*)tcp, close_cb); @@ -105,7 +105,7 @@ static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { static void timer_cb(uv_timer_t* handle) { - ASSERT(handle == &timer); + ASSERT_PTR_EQ(handle, &timer); ASSERT(nested == 0 && "timer_cb must be called from a fresh stack"); puts("Timeout complete. Now read data..."); @@ -125,7 +125,7 @@ static void timer_cb(uv_timer_t* handle) { static void write_cb(uv_write_t* req, int status) { int r; - ASSERT(status == 0); + ASSERT_OK(status); ASSERT(nested == 0 && "write_cb must be called from a fresh stack"); puts("Data written. 500ms timeout..."); @@ -136,9 +136,9 @@ static void write_cb(uv_write_t* req, int status) { * for the backend to use dirty stack for calling read_cb. */ nested++; r = uv_timer_init(uv_default_loop(), &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, timer_cb, 500, 0); - ASSERT(r == 0); + ASSERT_OK(r); nested--; write_cb_called++; @@ -150,7 +150,7 @@ static void connect_cb(uv_connect_t* req, int status) { puts("Connected. Write some data to echo server..."); - ASSERT(status == 0); + ASSERT_OK(status); ASSERT(nested == 0 && "connect_cb must be called from a fresh stack"); nested++; @@ -171,7 +171,7 @@ static void connect_cb(uv_connect_t* req, int status) { TEST_IMPL(callback_stack) { struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); if (uv_tcp_init(uv_default_loop(), &client)) { FATAL("uv_tcp_init failed"); @@ -191,13 +191,18 @@ TEST_IMPL(callback_stack) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(nested == 0); - ASSERT(connect_cb_called == 1 && "connect_cb must be called exactly once"); - ASSERT(write_cb_called == 1 && "write_cb must be called exactly once"); - ASSERT(timer_cb_called == 1 && "timer_cb must be called exactly once"); - ASSERT(bytes_received == sizeof MESSAGE); - ASSERT(shutdown_cb_called == 1 && "shutdown_cb must be called exactly once"); - ASSERT(close_cb_called == 2 && "close_cb must be called exactly twice"); + ASSERT_OK(nested); + ASSERT_NE(connect_cb_called == 1 && \ + "connect_cb must be called exactly once", 0); + ASSERT_NE(write_cb_called == 1 && "write_cb must be called exactly once", + 0); + ASSERT_NE(timer_cb_called == 1 && "timer_cb must be called exactly once", + 0); + ASSERT_EQ(bytes_received, sizeof MESSAGE); + ASSERT_NE(shutdown_cb_called == 1 && \ + "shutdown_cb must be called exactly once", 0); + ASSERT_NE(close_cb_called == 2 && "close_cb must be called exactly twice", + 0); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-close-fd.c b/test/test-close-fd.c index d8e12653f77..c072fdbb79a 100644 --- a/test/test-close-fd.c +++ b/test/test-close-fd.c @@ -36,11 +36,11 @@ static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { switch (++read_cb_called) { case 1: - ASSERT(nread == 1); + ASSERT_EQ(1, nread); uv_read_stop(handle); break; case 2: - ASSERT(nread == UV_EOF); + ASSERT_EQ(nread, UV_EOF); uv_close((uv_handle_t *) handle, NULL); break; default: @@ -55,29 +55,29 @@ TEST_IMPL(close_fd) { uv_file fd[2]; bufs[0] = uv_buf_init("", 1); - ASSERT(0 == uv_pipe(fd, 0, 0)); - ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0)); - ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0])); + ASSERT_OK(uv_pipe(fd, 0, 0)); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_handle, 0)); + ASSERT_OK(uv_pipe_open(&pipe_handle, fd[0])); /* uv_pipe_open() takes ownership of the file descriptor. */ fd[0] = -1; - ASSERT(1 == uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL)); - ASSERT(1 == req.result); + ASSERT_EQ(1, uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL)); + ASSERT_EQ(1, req.result); uv_fs_req_cleanup(&req); #ifdef _WIN32 - ASSERT(0 == _close(fd[1])); + ASSERT_OK(_close(fd[1])); #else - ASSERT(0 == close(fd[1])); + ASSERT_OK(close(fd[1])); #endif fd[1] = -1; - ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(1 == read_cb_called); - ASSERT(0 == uv_is_active((const uv_handle_t *) &pipe_handle)); - ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(2 == read_cb_called); - ASSERT(0 != uv_is_closing((const uv_handle_t *) &pipe_handle)); + ASSERT_OK(uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, read_cb_called); + ASSERT_OK(uv_is_active((const uv_handle_t *) &pipe_handle)); + ASSERT_OK(uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(2, read_cb_called); + ASSERT_NE(0, uv_is_closing((const uv_handle_t *) &pipe_handle)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-close-order.c b/test/test-close-order.c index 768e1ceedbe..e1aae93b7a8 100644 --- a/test/test-close-order.c +++ b/test/test-close-order.c @@ -39,9 +39,9 @@ static void close_cb(uv_handle_t* handle) { /* check_cb should run before any close_cb */ static void check_cb(uv_check_t* handle) { - ASSERT(check_cb_called == 0); - ASSERT(timer_cb_called == 1); - ASSERT(close_cb_called == 0); + ASSERT_OK(check_cb_called); + ASSERT_EQ(1, timer_cb_called); + ASSERT_OK(close_cb_called); uv_close((uv_handle_t*) handle, close_cb); uv_close((uv_handle_t*) &timer_handle2, close_cb); check_cb_called++; @@ -65,15 +65,15 @@ TEST_IMPL(close_order) { uv_timer_init(loop, &timer_handle2); uv_timer_start(&timer_handle2, timer_cb, 100000, 0); - ASSERT(check_cb_called == 0); - ASSERT(close_cb_called == 0); - ASSERT(timer_cb_called == 0); + ASSERT_OK(check_cb_called); + ASSERT_OK(close_cb_called); + ASSERT_OK(timer_cb_called); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(check_cb_called == 1); - ASSERT(close_cb_called == 3); - ASSERT(timer_cb_called == 1); + ASSERT_EQ(1, check_cb_called); + ASSERT_EQ(3, close_cb_called); + ASSERT_EQ(1, timer_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-condvar.c b/test/test-condvar.c index 61592d0e2d1..2711f8cc1b3 100644 --- a/test/test-condvar.c +++ b/test/test-condvar.c @@ -55,10 +55,10 @@ void worker_config_init(worker_config* wc, wc->use_broadcast = use_broadcast; /* Init. */ - ASSERT(0 == uv_sem_init(&wc->sem_waiting, 0)); - ASSERT(0 == uv_sem_init(&wc->sem_signaled, 0)); - ASSERT(0 == uv_cond_init(&wc->cond)); - ASSERT(0 == uv_mutex_init(&wc->mutex)); + ASSERT_OK(uv_sem_init(&wc->sem_waiting, 0)); + ASSERT_OK(uv_sem_init(&wc->sem_signaled, 0)); + ASSERT_OK(uv_cond_init(&wc->cond)); + ASSERT_OK(uv_mutex_init(&wc->mutex)); } void worker_config_destroy(worker_config* wc) { @@ -87,7 +87,7 @@ static void condvar_signal(worker_config* c, int* flag) { uv_mutex_lock(&c->mutex); /* Help waiter differentiate between spurious and legitimate wakeup. */ - ASSERT(*flag == 0); + ASSERT_OK(*flag); *flag = 1; if (c->use_broadcast) @@ -113,7 +113,7 @@ static int condvar_wait(worker_config* c, const int* flag) { do { uv_cond_wait(&c->cond, &c->mutex); } while (*flag == 0); - ASSERT(*flag == 1); + ASSERT_EQ(1, *flag); uv_mutex_unlock(&c->mutex); @@ -130,13 +130,13 @@ TEST_IMPL(condvar_1) { /* Helper signal-then-wait. */ worker_config_init(&wc, 0, condvar_signal, condvar_wait); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + ASSERT_OK(uv_thread_create(&thread, worker, &wc)); /* We wait-then-signal. */ - ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); + ASSERT_OK(wc.wait_cond(&wc, &wc.posted_1)); wc.signal_cond(&wc, &wc.posted_2); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); worker_config_destroy(&wc); return 0; @@ -149,13 +149,13 @@ TEST_IMPL(condvar_2) { /* Helper to signal-then-wait. */ worker_config_init(&wc, 1, condvar_signal, condvar_wait); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + ASSERT_OK(uv_thread_create(&thread, worker, &wc)); /* We wait-then-signal. */ - ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); + ASSERT_OK(wc.wait_cond(&wc, &wc.posted_1)); wc.signal_cond(&wc, &wc.posted_2); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); worker_config_destroy(&wc); return 0; @@ -176,9 +176,9 @@ static int condvar_timedwait(worker_config* c, const int* flag) { /* Wait until I get a non-spurious signal. */ do { r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(1 * 1e9)); /* 1 s */ - ASSERT(r == 0); /* Should not time out. */ + ASSERT_OK(r); /* Should not time out. */ } while (*flag == 0); - ASSERT(*flag == 1); + ASSERT_EQ(1, *flag); uv_mutex_unlock(&c->mutex); @@ -194,13 +194,13 @@ TEST_IMPL(condvar_3) { /* Helper to signal-then-wait. */ worker_config_init(&wc, 0, condvar_signal, condvar_timedwait); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + ASSERT_OK(uv_thread_create(&thread, worker, &wc)); /* We wait-then-signal. */ wc.wait_cond(&wc, &wc.posted_1); wc.signal_cond(&wc, &wc.posted_2); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); worker_config_destroy(&wc); return 0; @@ -213,13 +213,13 @@ TEST_IMPL(condvar_4) { /* Helper to signal-then-wait. */ worker_config_init(&wc, 1, condvar_signal, condvar_timedwait); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + ASSERT_OK(uv_thread_create(&thread, worker, &wc)); /* We wait-then-signal. */ wc.wait_cond(&wc, &wc.posted_1); wc.signal_cond(&wc, &wc.posted_2); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); worker_config_destroy(&wc); return 0; diff --git a/test/test-connect-unspecified.c b/test/test-connect-unspecified.c index ecbe98538ed..73e59a9972b 100644 --- a/test/test-connect-unspecified.c +++ b/test/test-connect-unspecified.c @@ -23,11 +23,11 @@ #include "task.h" static void connect_4(uv_connect_t* req, int status) { - ASSERT(status != UV_EADDRNOTAVAIL); + ASSERT_NE(status, UV_EADDRNOTAVAIL); } static void connect_6(uv_connect_t* req, int status) { - ASSERT(status != UV_EADDRNOTAVAIL); + ASSERT_NE(status, UV_EADDRNOTAVAIL); } TEST_IMPL(connect_unspecified) { @@ -41,23 +41,23 @@ TEST_IMPL(connect_unspecified) { loop = uv_default_loop(); - ASSERT(uv_tcp_init(loop, &socket4) == 0); - ASSERT(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr4) == 0); - ASSERT(uv_tcp_connect(&connect4, - &socket4, - (const struct sockaddr*) &addr4, - connect_4) == 0); + ASSERT_OK(uv_tcp_init(loop, &socket4)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr4)); + ASSERT_OK(uv_tcp_connect(&connect4, + &socket4, + (const struct sockaddr*) &addr4, + connect_4)); if (can_ipv6()) { - ASSERT(uv_tcp_init(loop, &socket6) == 0); - ASSERT(uv_ip6_addr("::", TEST_PORT, &addr6) == 0); - ASSERT(uv_tcp_connect(&connect6, - &socket6, - (const struct sockaddr*) &addr6, - connect_6) == 0); + ASSERT_OK(uv_tcp_init(loop, &socket6)); + ASSERT_OK(uv_ip6_addr("::", TEST_PORT, &addr6)); + ASSERT_OK(uv_tcp_connect(&connect6, + &socket6, + (const struct sockaddr*) &addr6, + connect_6)); } - ASSERT(uv_run(loop, UV_RUN_DEFAULT) == 0); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-connection-fail.c b/test/test-connection-fail.c index aa7db30d85a..9efd3ac907a 100644 --- a/test/test-connection-fail.c +++ b/test/test-connection-fail.c @@ -54,8 +54,8 @@ static void timer_cb(uv_timer_t* handle) { * but libuv hasn't automatically closed the socket. The user must * uv_close the handle manually. */ - ASSERT(close_cb_calls == 0); - ASSERT(connect_cb_calls == 1); + ASSERT_OK(close_cb_calls); + ASSERT_EQ(1, connect_cb_calls); /* Close the tcp handle. */ uv_close((uv_handle_t*)&tcp, on_close); @@ -66,22 +66,22 @@ static void timer_cb(uv_timer_t* handle) { static void on_connect_with_close(uv_connect_t *req, int status) { - ASSERT((uv_stream_t*) &tcp == req->handle); - ASSERT(status == UV_ECONNREFUSED); + ASSERT_PTR_EQ((uv_stream_t*) &tcp, req->handle); + ASSERT_EQ(status, UV_ECONNREFUSED); connect_cb_calls++; - ASSERT(close_cb_calls == 0); + ASSERT_OK(close_cb_calls); uv_close((uv_handle_t*)req->handle, on_close); } static void on_connect_without_close(uv_connect_t *req, int status) { - ASSERT(status == UV_ECONNREFUSED); + ASSERT_EQ(status, UV_ECONNREFUSED); connect_cb_calls++; uv_timer_start(&timer, timer_cb, 100, 0); - ASSERT(close_cb_calls == 0); + ASSERT_OK(close_cb_calls); } @@ -89,10 +89,10 @@ static void connection_fail(uv_connect_cb connect_cb) { struct sockaddr_in client_addr, server_addr; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &client_addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", 0, &client_addr)); /* There should be no servers listening on this port. */ - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); /* Try to connect to the server and do NUM_PINGS ping-pongs. */ r = uv_tcp_init(uv_default_loop(), &tcp); @@ -100,7 +100,7 @@ static void connection_fail(uv_connect_cb connect_cb) { /* We are never doing multiple reads/connects at a time anyway. so these * handles can be pre-initialized. */ - ASSERT(0 == uv_tcp_bind(&tcp, (const struct sockaddr*) &client_addr, 0)); + ASSERT_OK(uv_tcp_bind(&tcp, (const struct sockaddr*) &client_addr, 0)); r = uv_tcp_connect(&req, &tcp, @@ -110,8 +110,8 @@ static void connection_fail(uv_connect_cb connect_cb) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(connect_cb_calls == 1); - ASSERT(close_cb_calls == 1); + ASSERT_EQ(1, connect_cb_calls); + ASSERT_EQ(1, close_cb_calls); } @@ -127,8 +127,8 @@ TEST_IMPL(connection_fail) { connection_fail(on_connect_with_close); - ASSERT(timer_close_cb_calls == 0); - ASSERT(timer_cb_calls == 0); + ASSERT_OK(timer_close_cb_calls); + ASSERT_OK(timer_cb_calls); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -149,12 +149,12 @@ TEST_IMPL(connection_fail_doesnt_auto_close) { int r; r = uv_timer_init(uv_default_loop(), &timer); - ASSERT(r == 0); + ASSERT_OK(r); connection_fail(on_connect_without_close); - ASSERT(timer_close_cb_calls == 1); - ASSERT(timer_cb_calls == 1); + ASSERT_EQ(1, timer_close_cb_calls); + ASSERT_EQ(1, timer_cb_calls); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-cwd-and-chdir.c b/test/test-cwd-and-chdir.c index faeed021030..e4a0eef0767 100644 --- a/test/test-cwd-and-chdir.c +++ b/test/test-cwd-and-chdir.c @@ -34,24 +34,24 @@ TEST_IMPL(cwd_and_chdir) { size1 = 1; err = uv_cwd(buffer_orig, &size1); - ASSERT(err == UV_ENOBUFS); - ASSERT(size1 > 1); + ASSERT_EQ(err, UV_ENOBUFS); + ASSERT_GT(size1, 1); size1 = sizeof buffer_orig; err = uv_cwd(buffer_orig, &size1); - ASSERT(err == 0); - ASSERT(size1 > 0); - ASSERT(buffer_orig[size1] != '/'); + ASSERT_OK(err); + ASSERT_GT(size1, 0); + ASSERT_NE(buffer_orig[size1], '/'); err = uv_chdir(buffer_orig); - ASSERT(err == 0); + ASSERT_OK(err); size2 = sizeof buffer_new; err = uv_cwd(buffer_new, &size2); - ASSERT(err == 0); + ASSERT_OK(err); - ASSERT(size1 == size2); - ASSERT(strcmp(buffer_orig, buffer_new) == 0); + ASSERT_EQ(size1, size2); + ASSERT_OK(strcmp(buffer_orig, buffer_new)); return 0; } diff --git a/test/test-default-loop-close.c b/test/test-default-loop-close.c index 8d960e1130a..d08a33ea551 100644 --- a/test/test-default-loop-close.c +++ b/test/test-default-loop-close.c @@ -39,19 +39,19 @@ TEST_IMPL(default_loop_close) { loop = uv_default_loop(); ASSERT_NOT_NULL(loop); - ASSERT(0 == uv_timer_init(loop, &timer_handle)); - ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(1 == timer_cb_called); - ASSERT(0 == uv_loop_close(loop)); + ASSERT_OK(uv_timer_init(loop, &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, 1, 0)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, timer_cb_called); + ASSERT_OK(uv_loop_close(loop)); loop = uv_default_loop(); ASSERT_NOT_NULL(loop); - ASSERT(0 == uv_timer_init(loop, &timer_handle)); - ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(2 == timer_cb_called); + ASSERT_OK(uv_timer_init(loop, &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, 1, 0)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(2, timer_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-delayed-accept.c b/test/test-delayed-accept.c index c1d6ce0b45b..f7cf80ab7b3 100644 --- a/test/test-delayed-accept.c +++ b/test/test-delayed-accept.c @@ -54,11 +54,11 @@ static void do_accept(uv_timer_t* timer_handle) { ASSERT_NOT_NULL(accepted_handle); r = uv_tcp_init(uv_default_loop(), accepted_handle); - ASSERT(r == 0); + ASSERT_OK(r); server = (uv_tcp_t*)timer_handle->data; r = uv_accept((uv_stream_t*)server, (uv_stream_t*)accepted_handle); - ASSERT(r == 0); + ASSERT_OK(r); do_accept_called++; @@ -79,19 +79,19 @@ static void connection_cb(uv_stream_t* tcp, int status) { int r; uv_timer_t* timer_handle; - ASSERT(status == 0); + ASSERT_OK(status); timer_handle = (uv_timer_t*)malloc(sizeof *timer_handle); ASSERT_NOT_NULL(timer_handle); /* Accept the client after 1 second */ r = uv_timer_init(uv_default_loop(), timer_handle); - ASSERT(r == 0); + ASSERT_OK(r); timer_handle->data = tcp; r = uv_timer_start(timer_handle, do_accept, 1000, 0); - ASSERT(r == 0); + ASSERT_OK(r); connection_cb_called++; } @@ -102,16 +102,16 @@ static void start_server(void) { uv_tcp_t* server = (uv_tcp_t*)malloc(sizeof *server); int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); ASSERT_NOT_NULL(server); r = uv_tcp_init(uv_default_loop(), server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)server, 128, connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -123,10 +123,10 @@ static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { } if (nread >= 0) { - ASSERT(nread == 0); + ASSERT_OK(nread); } else { ASSERT_NOT_NULL(tcp); - ASSERT(nread == UV_EOF); + ASSERT_EQ(nread, UV_EOF); uv_close((uv_handle_t*)tcp, close_cb); } } @@ -136,12 +136,12 @@ static void connect_cb(uv_connect_t* req, int status) { int r; ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); /* Not that the server will send anything, but otherwise we'll never know * when the server closes the connection. */ r = uv_read_start((uv_stream_t*)(req->handle), alloc_cb, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); connect_cb_called++; @@ -155,18 +155,18 @@ static void client_connect(void) { uv_connect_t* connect_req = malloc(sizeof *connect_req); int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); ASSERT_NOT_NULL(client); ASSERT_NOT_NULL(connect_req); r = uv_tcp_init(uv_default_loop(), client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(connect_req, client, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -179,10 +179,10 @@ TEST_IMPL(delayed_accept) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(connection_cb_called == 2); - ASSERT(do_accept_called == 2); - ASSERT(connect_cb_called == 2); - ASSERT(close_cb_called == 7); + ASSERT_EQ(2, connection_cb_called); + ASSERT_EQ(2, do_accept_called); + ASSERT_EQ(2, connect_cb_called); + ASSERT_EQ(7, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-dlerror.c b/test/test-dlerror.c index 631e67cc5f3..dec0da3afc8 100644 --- a/test/test-dlerror.c +++ b/test/test-dlerror.c @@ -38,7 +38,7 @@ TEST_IMPL(dlerror) { ASSERT_NOT_NULL(strstr(msg, dlerror_no_error)); r = uv_dlopen(path, &lib); - ASSERT(r == -1); + ASSERT_EQ(r, -1); msg = uv_dlerror(&lib); ASSERT_NOT_NULL(msg); diff --git a/test/test-eintr-handling.c b/test/test-eintr-handling.c index d37aba4aa52..1f75e77e251 100644 --- a/test/test-eintr-handling.c +++ b/test/test-eintr-handling.c @@ -48,13 +48,13 @@ struct thread_ctx { static void thread_main(void* arg) { int nwritten; - ASSERT(0 == kill(getpid(), SIGUSR1)); + ASSERT_OK(kill(getpid(), SIGUSR1)); do nwritten = write(pipe_fds[1], test_buf, sizeof(test_buf)); while (nwritten == -1 && errno == EINTR); - ASSERT(nwritten == sizeof(test_buf)); + ASSERT_EQ(nwritten, sizeof(test_buf)); } static void sig_func(uv_signal_t* handle, int signum) { @@ -70,24 +70,24 @@ TEST_IMPL(eintr_handling) { iov = uv_buf_init(buf, sizeof(buf)); loop = uv_default_loop(); - ASSERT(0 == uv_signal_init(loop, &signal)); - ASSERT(0 == uv_signal_start(&signal, sig_func, SIGUSR1)); + ASSERT_OK(uv_signal_init(loop, &signal)); + ASSERT_OK(uv_signal_start(&signal, sig_func, SIGUSR1)); - ASSERT(0 == pipe(pipe_fds)); - ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); + ASSERT_OK(pipe(pipe_fds)); + ASSERT_OK(uv_thread_create(&thread, thread_main, &ctx)); nread = uv_fs_read(loop, &read_req, pipe_fds[0], &iov, 1, -1, NULL); - ASSERT(nread == sizeof(test_buf)); - ASSERT(0 == strcmp(buf, test_buf)); + ASSERT_EQ(nread, sizeof(test_buf)); + ASSERT_OK(strcmp(buf, test_buf)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(0 == close(pipe_fds[0])); - ASSERT(0 == close(pipe_fds[1])); + ASSERT_OK(close(pipe_fds[0])); + ASSERT_OK(close(pipe_fds[1])); uv_close((uv_handle_t*) &signal, NULL); - ASSERT_EQ(0, uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-embed.c b/test/test-embed.c index bbe56e176db..6e9917239aa 100644 --- a/test/test-embed.c +++ b/test/test-embed.c @@ -36,7 +36,7 @@ static uv_barrier_t barrier; static void thread_main(void* arg) { ASSERT_LE(0, uv_barrier_wait(&barrier)); uv_sleep(250); - ASSERT_EQ(0, uv_async_send(&async)); + ASSERT_OK(uv_async_send(&async)); } @@ -50,9 +50,9 @@ TEST_IMPL(embed) { uv_loop_t* loop; loop = uv_default_loop(); - ASSERT_EQ(0, uv_async_init(loop, &async, async_cb)); - ASSERT_EQ(0, uv_barrier_init(&barrier, 2)); - ASSERT_EQ(0, uv_thread_create(&thread, thread_main, NULL)); + ASSERT_OK(uv_async_init(loop, &async, async_cb)); + ASSERT_OK(uv_barrier_init(&barrier, 2)); + ASSERT_OK(uv_thread_create(&thread, thread_main, NULL)); ASSERT_LE(0, uv_barrier_wait(&barrier)); while (uv_loop_alive(loop)) { @@ -71,7 +71,7 @@ TEST_IMPL(embed) { #endif } - ASSERT_EQ(0, uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); uv_barrier_destroy(&barrier); MAKE_VALGRIND_HAPPY(loop); diff --git a/test/test-emfile.c b/test/test-emfile.c index 343c9521dc7..ef2338cdfbb 100644 --- a/test/test-emfile.c +++ b/test/test-emfile.c @@ -54,37 +54,37 @@ TEST_IMPL(emfile) { /* Lower the file descriptor limit and use up all fds save one. */ limits.rlim_cur = limits.rlim_max = maxfd + 1; if (setrlimit(RLIMIT_NOFILE, &limits)) { - ASSERT(errno == EPERM); /* Valgrind blocks the setrlimit() call. */ + ASSERT_EQ(errno, EPERM); /* Valgrind blocks the setrlimit() call. */ RETURN_SKIP("setrlimit(RLIMIT_NOFILE) failed, running under valgrind?"); } loop = uv_default_loop(); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(loop, &server_handle)); - ASSERT(0 == uv_tcp_init(loop, &client_handle)); - ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); - ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 8, connection_cb)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_tcp_init(loop, &server_handle)); + ASSERT_OK(uv_tcp_init(loop, &client_handle)); + ASSERT_OK(uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_listen((uv_stream_t*) &server_handle, 8, connection_cb)); /* Remember the first one so we can clean up afterwards. */ do first_fd = dup(0); while (first_fd == -1 && errno == EINTR); - ASSERT(first_fd > 0); + ASSERT_GT(first_fd, 0); while (dup(0) != -1 || errno == EINTR); - ASSERT(errno == EMFILE); + ASSERT_EQ(errno, EMFILE); close(maxfd); /* Now connect and use up the last available file descriptor. The EMFILE * handling logic in src/unix/stream.c should ensure that connect_cb() runs * whereas connection_cb() should *not* run. */ - ASSERT(0 == uv_tcp_connect(&connect_req, - &client_handle, - (const struct sockaddr*) &addr, - connect_cb)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(1 == connect_cb_called); + ASSERT_OK(uv_tcp_connect(&connect_req, + &client_handle, + (const struct sockaddr*) &addr, + connect_cb)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, connect_cb_called); /* Close the dups again. Ignore errors in the unlikely event that the * file descriptors were not contiguous. @@ -108,7 +108,7 @@ static void connect_cb(uv_connect_t* req, int status) { /* |status| should equal 0 because the connection should have been accepted, * it's just that the server immediately closes it again. */ - ASSERT(0 == status); + ASSERT_OK(status); connect_cb_called += 1; uv_close((uv_handle_t*) &server_handle, NULL); uv_close((uv_handle_t*) &client_handle, NULL); diff --git a/test/test-env-vars.c b/test/test-env-vars.c index 8118e3da5d7..016f0733c6e 100644 --- a/test/test-env-vars.c +++ b/test/test-env-vars.c @@ -35,83 +35,83 @@ TEST_IMPL(env_vars) { /* Reject invalid inputs when setting an environment variable */ r = uv_os_setenv(NULL, "foo"); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_os_setenv(name, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_os_setenv(NULL, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); /* Reject invalid inputs when retrieving an environment variable */ size = BUF_SIZE; r = uv_os_getenv(NULL, buf, &size); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_os_getenv(name, NULL, &size); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_os_getenv(name, buf, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); size = 0; r = uv_os_getenv(name, buf, &size); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); /* Reject invalid inputs when deleting an environment variable */ r = uv_os_unsetenv(NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); /* Successfully set an environment variable */ r = uv_os_setenv(name, "123456789"); - ASSERT(r == 0); + ASSERT_OK(r); /* Successfully read an environment variable */ size = BUF_SIZE; buf[0] = '\0'; r = uv_os_getenv(name, buf, &size); - ASSERT(r == 0); - ASSERT(strcmp(buf, "123456789") == 0); - ASSERT(size == BUF_SIZE - 1); + ASSERT_OK(r); + ASSERT_OK(strcmp(buf, "123456789")); + ASSERT_EQ(size, BUF_SIZE - 1); /* Return UV_ENOBUFS if the buffer cannot hold the environment variable */ size = BUF_SIZE - 1; buf[0] = '\0'; r = uv_os_getenv(name, buf, &size); - ASSERT(r == UV_ENOBUFS); - ASSERT(size == BUF_SIZE); + ASSERT_EQ(r, UV_ENOBUFS); + ASSERT_EQ(size, BUF_SIZE); /* Successfully delete an environment variable */ r = uv_os_unsetenv(name); - ASSERT(r == 0); + ASSERT_OK(r); /* Return UV_ENOENT retrieving an environment variable that does not exist */ r = uv_os_getenv(name, buf, &size); - ASSERT(r == UV_ENOENT); + ASSERT_EQ(r, UV_ENOENT); /* Successfully delete an environment variable that does not exist */ r = uv_os_unsetenv(name); - ASSERT(r == 0); + ASSERT_OK(r); /* Setting an environment variable to the empty string does not delete it. */ r = uv_os_setenv(name, ""); - ASSERT(r == 0); + ASSERT_OK(r); size = BUF_SIZE; r = uv_os_getenv(name, buf, &size); - ASSERT(r == 0); - ASSERT(size == 0); - ASSERT(strlen(buf) == 0); + ASSERT_OK(r); + ASSERT_OK(size); + ASSERT_OK(strlen(buf)); /* Check getting all env variables. */ r = uv_os_setenv(name, "123456789"); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_os_setenv(name2, ""); - ASSERT(r == 0); + ASSERT_OK(r); #ifdef _WIN32 /* Create a special environment variable on Windows in case there are no naturally occurring ones. */ r = uv_os_setenv("=Z:", "\\"); - ASSERT(r == 0); + ASSERT_OK(r); #endif r = uv_os_environ(&envitems, &envcount); - ASSERT(r == 0); - ASSERT(envcount > 0); + ASSERT_OK(r); + ASSERT_GT(envcount, 0); found = 0; found_win_special = 0; @@ -120,16 +120,16 @@ TEST_IMPL(env_vars) { /* printf("Env: %s = %s\n", envitems[i].name, envitems[i].value); */ if (strcmp(envitems[i].name, name) == 0) { found++; - ASSERT(strcmp(envitems[i].value, "123456789") == 0); + ASSERT_OK(strcmp(envitems[i].value, "123456789")); } else if (strcmp(envitems[i].name, name2) == 0) { found++; - ASSERT(strlen(envitems[i].value) == 0); + ASSERT_OK(strlen(envitems[i].value)); } else if (envitems[i].name[0] == '=') { found_win_special++; } } - ASSERT(found == 2); + ASSERT_EQ(2, found); #ifdef _WIN32 ASSERT_GT(found_win_special, 0); #else @@ -140,10 +140,10 @@ TEST_IMPL(env_vars) { uv_os_free_environ(envitems, envcount); r = uv_os_unsetenv(name); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_os_unsetenv(name2); - ASSERT(r == 0); + ASSERT_OK(r); for (i = 1; i <= 4; i++) { size_t n; @@ -158,14 +158,14 @@ TEST_IMPL(env_vars) { memset(p, 'x', n); p[n] = '\0'; - ASSERT_EQ(0, uv_os_setenv(name, p)); - ASSERT_EQ(0, uv_os_getenv(name, p, &size)); + ASSERT_OK(uv_os_setenv(name, p)); + ASSERT_OK(uv_os_getenv(name, p, &size)); ASSERT_EQ(n, size); for (n = 0; n < size; n++) ASSERT_EQ('x', p[n]); - ASSERT_EQ(0, uv_os_unsetenv(name)); + ASSERT_OK(uv_os_unsetenv(name)); free(p); } diff --git a/test/test-error.c b/test/test-error.c index f0fb864607f..2c6d0ca4979 100644 --- a/test/test-error.c +++ b/test/test-error.c @@ -51,8 +51,8 @@ TEST_IMPL(error_message) { } ASSERT_NULL(strstr(uv_strerror(UV_EINVAL), "Success")); - ASSERT(strcmp(uv_strerror(1337), "Unknown error") == 0); - ASSERT(strcmp(uv_strerror(-1337), "Unknown error") == 0); + ASSERT_OK(strcmp(uv_strerror(1337), "Unknown error")); + ASSERT_OK(strcmp(uv_strerror(-1337), "Unknown error")); ASSERT_NULL(strstr(uv_strerror_r(UV_EINVAL, buf, sizeof(buf)), "Success")); ASSERT_NOT_NULL(strstr(uv_strerror_r(1337, buf, sizeof(buf)), "1337")); @@ -64,19 +64,19 @@ TEST_IMPL(error_message) { TEST_IMPL(sys_error) { #if defined(_WIN32) - ASSERT(uv_translate_sys_error(ERROR_NOACCESS) == UV_EACCES); - ASSERT(uv_translate_sys_error(ERROR_ELEVATION_REQUIRED) == UV_EACCES); - ASSERT(uv_translate_sys_error(WSAEADDRINUSE) == UV_EADDRINUSE); - ASSERT(uv_translate_sys_error(ERROR_BAD_PIPE) == UV_EPIPE); + ASSERT_EQ(uv_translate_sys_error(ERROR_NOACCESS), UV_EACCES); + ASSERT_EQ(uv_translate_sys_error(ERROR_ELEVATION_REQUIRED), UV_EACCES); + ASSERT_EQ(uv_translate_sys_error(WSAEADDRINUSE), UV_EADDRINUSE); + ASSERT_EQ(uv_translate_sys_error(ERROR_BAD_PIPE), UV_EPIPE); #else - ASSERT(uv_translate_sys_error(EPERM) == UV_EPERM); - ASSERT(uv_translate_sys_error(EPIPE) == UV_EPIPE); - ASSERT(uv_translate_sys_error(EINVAL) == UV_EINVAL); + ASSERT_EQ(uv_translate_sys_error(EPERM), UV_EPERM); + ASSERT_EQ(uv_translate_sys_error(EPIPE), UV_EPIPE); + ASSERT_EQ(uv_translate_sys_error(EINVAL), UV_EINVAL); #endif - ASSERT(uv_translate_sys_error(UV_EINVAL) == UV_EINVAL); - ASSERT(uv_translate_sys_error(UV_ERANGE) == UV_ERANGE); - ASSERT(uv_translate_sys_error(UV_EACCES) == UV_EACCES); - ASSERT(uv_translate_sys_error(0) == 0); + ASSERT_EQ(uv_translate_sys_error(UV_EINVAL), UV_EINVAL); + ASSERT_EQ(uv_translate_sys_error(UV_ERANGE), UV_ERANGE); + ASSERT_EQ(uv_translate_sys_error(UV_EACCES), UV_EACCES); + ASSERT_OK(uv_translate_sys_error(0)); return 0; } diff --git a/test/test-fork.c b/test/test-fork.c index d1a273f4b96..fe42f03daf5 100644 --- a/test/test-fork.c +++ b/test/test-fork.c @@ -51,12 +51,12 @@ static char socket_cb_read_buf[1024]; static void socket_cb(uv_poll_t* poll, int status, int events) { ssize_t cnt; socket_cb_called++; - ASSERT(0 == status); + ASSERT_OK(status); printf("Socket cb got events %d\n", events); - ASSERT(UV_READABLE == (events & UV_READABLE)); + ASSERT_EQ(UV_READABLE, (events & UV_READABLE)); if (socket_cb_read_fd) { cnt = read(socket_cb_read_fd, socket_cb_read_buf, socket_cb_read_size); - ASSERT(cnt == socket_cb_read_size); + ASSERT_EQ(cnt, socket_cb_read_size); } uv_close((uv_handle_t*) poll, NULL); } @@ -66,15 +66,15 @@ static void run_timer_loop_once(void) { uv_loop_t loop; uv_timer_t timer_handle; - ASSERT_EQ(0, uv_loop_init(&loop)); + ASSERT_OK(uv_loop_init(&loop)); timer_cb_called = 0; /* Reset for the child. */ - ASSERT(0 == uv_timer_init(&loop, &timer_handle)); - ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0)); - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); - ASSERT(1 == timer_cb_called); - ASSERT_EQ(0, uv_loop_close(&loop)); + ASSERT_OK(uv_timer_init(&loop, &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, 1, 0)); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, timer_cb_called); + ASSERT_OK(uv_loop_close(&loop)); } @@ -87,10 +87,10 @@ static void assert_wait_child(pid_t child_pid) { if (waited_pid == -1) { perror("Failed to wait"); } - ASSERT(child_pid == waited_pid); + ASSERT_EQ(child_pid, waited_pid); ASSERT(WIFEXITED(child_stat)); /* Clean exit, not a signal. */ ASSERT(!WIFSIGNALED(child_stat)); - ASSERT(0 == WEXITSTATUS(child_stat)); + ASSERT_OK(WEXITSTATUS(child_stat)); } @@ -109,14 +109,14 @@ TEST_IMPL(fork_timer) { #else child_pid = fork(); #endif - ASSERT(child_pid != -1); + ASSERT_NE(child_pid, -1); if (child_pid != 0) { /* parent */ assert_wait_child(child_pid); } else { /* child */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); + ASSERT_OK(uv_loop_fork(uv_default_loop())); run_timer_loop_once(); } @@ -135,30 +135,30 @@ TEST_IMPL(fork_socketpair) { /* Prime the loop. */ run_timer_loop_once(); - ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds)); + ASSERT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds)); /* Create the server watcher in the parent, use it in the child. */ - ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); + ASSERT_OK(uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); #if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) child_pid = -1; #else child_pid = fork(); #endif - ASSERT(child_pid != -1); + ASSERT_NE(child_pid, -1); if (child_pid != 0) { /* parent */ - ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0)); + ASSERT_EQ(3, send(socket_fds[1], "hi\n", 3, 0)); assert_wait_child(child_pid); } else { /* child */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); - ASSERT(0 == socket_cb_called); - ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb)); + ASSERT_OK(uv_loop_fork(uv_default_loop())); + ASSERT_OK(socket_cb_called); + ASSERT_OK(uv_poll_start(&poll_handle, UV_READABLE, socket_cb)); printf("Going to run the loop in the child\n"); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(1 == socket_cb_called); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, socket_cb_called); } MAKE_VALGRIND_HAPPY(uv_default_loop()); @@ -176,57 +176,57 @@ TEST_IMPL(fork_socketpair_started) { char sync_buf[1]; uv_poll_t poll_handle; - ASSERT(0 == pipe(sync_pipe)); + ASSERT_OK(pipe(sync_pipe)); /* Prime the loop. */ run_timer_loop_once(); - ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds)); + ASSERT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds)); /* Create and start the server watcher in the parent, use it in the child. */ - ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); - ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb)); + ASSERT_OK(uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); + ASSERT_OK(uv_poll_start(&poll_handle, UV_READABLE, socket_cb)); /* Run the loop AFTER the poll watcher is registered to make sure it gets passed to the kernel. Use NOWAIT and expect a non-zero return to prove the poll watcher is active. */ - ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + ASSERT_EQ(1, uv_run(uv_default_loop(), UV_RUN_NOWAIT)); #if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) child_pid = -1; #else child_pid = fork(); #endif - ASSERT(child_pid != -1); + ASSERT_NE(child_pid, -1); if (child_pid != 0) { /* parent */ - ASSERT(0 == uv_poll_stop(&poll_handle)); + ASSERT_OK(uv_poll_stop(&poll_handle)); uv_close((uv_handle_t*)&poll_handle, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(0 == socket_cb_called); - ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert child */ - ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(socket_cb_called); + ASSERT_EQ(1, write(sync_pipe[1], "1", 1)); /* alert child */ + ASSERT_EQ(3, send(socket_fds[1], "hi\n", 3, 0)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(0 == socket_cb_called); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(socket_cb_called); assert_wait_child(child_pid); } else { /* child */ printf("Child is %d\n", getpid()); - ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for parent */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); - ASSERT(0 == socket_cb_called); + ASSERT_EQ(1, read(sync_pipe[0], sync_buf, 1)); /* wait for parent */ + ASSERT_OK(uv_loop_fork(uv_default_loop())); + ASSERT_OK(socket_cb_called); printf("Going to run the loop in the child\n"); socket_cb_read_fd = socket_fds[0]; socket_cb_read_size = 3; - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(1 == socket_cb_called); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, socket_cb_called); printf("Buf %s\n", socket_cb_read_buf); - ASSERT(0 == strcmp("hi\n", socket_cb_read_buf)); + ASSERT_OK(strcmp("hi\n", socket_cb_read_buf)); } MAKE_VALGRIND_HAPPY(uv_default_loop()); @@ -253,41 +253,43 @@ TEST_IMPL(fork_signal_to_child) { fork_signal_cb_called = 0; /* reset */ - ASSERT(0 == pipe(sync_pipe)); + ASSERT_OK(pipe(sync_pipe)); /* Prime the loop. */ run_timer_loop_once(); - ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle)); - ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1)); + ASSERT_OK(uv_signal_init(uv_default_loop(), &signal_handle)); + ASSERT_OK(uv_signal_start(&signal_handle, + fork_signal_to_child_cb, + SIGUSR1)); #if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) child_pid = -1; #else child_pid = fork(); #endif - ASSERT(child_pid != -1); + ASSERT_NE(child_pid, -1); if (child_pid != 0) { /* parent */ - ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */ - ASSERT(0 == kill(child_pid, SIGUSR1)); + ASSERT_EQ(1, read(sync_pipe[0], sync_buf, 1)); /* wait for child */ + ASSERT_OK(kill(child_pid, SIGUSR1)); /* Run the loop, make sure we don't get the signal. */ printf("Running loop in parent\n"); uv_unref((uv_handle_t*)&signal_handle); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); - ASSERT(0 == fork_signal_cb_called); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + ASSERT_OK(fork_signal_cb_called); printf("Waiting for child in parent\n"); assert_wait_child(child_pid); } else { /* child */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); - ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */ + ASSERT_OK(uv_loop_fork(uv_default_loop())); + ASSERT_EQ(1, write(sync_pipe[1], "1", 1)); /* alert parent */ /* Get the signal. */ - ASSERT(0 != uv_loop_alive(uv_default_loop())); + ASSERT_NE(0, uv_loop_alive(uv_default_loop())); printf("Running loop in child\n"); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); - ASSERT(SIGUSR1 == fork_signal_cb_called); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_EQ(SIGUSR1, fork_signal_cb_called); } MAKE_VALGRIND_HAPPY(uv_default_loop()); @@ -308,47 +310,49 @@ TEST_IMPL(fork_signal_to_child_closed) { fork_signal_cb_called = 0; /* reset */ - ASSERT(0 == pipe(sync_pipe)); - ASSERT(0 == pipe(sync_pipe2)); + ASSERT_OK(pipe(sync_pipe)); + ASSERT_OK(pipe(sync_pipe2)); /* Prime the loop. */ run_timer_loop_once(); - ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle)); - ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1)); + ASSERT_OK(uv_signal_init(uv_default_loop(), &signal_handle)); + ASSERT_OK(uv_signal_start(&signal_handle, + fork_signal_to_child_cb, + SIGUSR1)); #if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) child_pid = -1; #else child_pid = fork(); #endif - ASSERT(child_pid != -1); + ASSERT_NE(child_pid, -1); if (child_pid != 0) { /* parent */ printf("Wating on child in parent\n"); - ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */ + ASSERT_EQ(1, read(sync_pipe[0], sync_buf, 1)); /* wait for child */ printf("Parent killing child\n"); - ASSERT(0 == kill(child_pid, SIGUSR1)); + ASSERT_OK(kill(child_pid, SIGUSR1)); /* Run the loop, make sure we don't get the signal. */ printf("Running loop in parent\n"); uv_unref((uv_handle_t*)&signal_handle); /* so the loop can exit; we *shouldn't* get any signals */ run_timer_loop_once(); /* but while we share a pipe, we do, so have something active. */ - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); printf("Signal in parent %d\n", fork_signal_cb_called); - ASSERT(0 == fork_signal_cb_called); - ASSERT(1 == write(sync_pipe2[1], "1", 1)); /* alert child */ + ASSERT_OK(fork_signal_cb_called); + ASSERT_EQ(1, write(sync_pipe2[1], "1", 1)); /* alert child */ printf("Waiting for child in parent\n"); assert_wait_child(child_pid); } else { /* Child. Our signal handler should still be installed. */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); + ASSERT_OK(uv_loop_fork(uv_default_loop())); printf("Checking loop in child\n"); - ASSERT(0 != uv_loop_alive(uv_default_loop())); + ASSERT_NE(0, uv_loop_alive(uv_default_loop())); printf("Alerting parent in child\n"); - ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */ + ASSERT_EQ(1, write(sync_pipe[1], "1", 1)); /* alert parent */ /* Don't run the loop. Wait for the parent to call us */ printf("Waiting on parent in child\n"); /* Wait for parent. read may fail if the parent tripped an ASSERT @@ -356,7 +360,7 @@ TEST_IMPL(fork_signal_to_child_closed) { */ r = read(sync_pipe2[0], sync_buf, 1); ASSERT(-1 <= r && r <= 1); - ASSERT(0 == fork_signal_cb_called); + ASSERT_OK(fork_signal_cb_called); printf("Exiting child \n"); /* Note that we're deliberately not running the loop * in the child, and also not closing the loop's handles, @@ -381,21 +385,21 @@ TEST_IMPL(fork_close_signal_in_child) { uv_signal_t signal_handle; pid_t child_pid; - ASSERT_EQ(0, uv_loop_init(&loop)); - ASSERT_EQ(0, uv_signal_init(&loop, &signal_handle)); - ASSERT_EQ(0, uv_signal_start(&signal_handle, &fork_signal_cb, SIGHUP)); + ASSERT_OK(uv_loop_init(&loop)); + ASSERT_OK(uv_signal_init(&loop, &signal_handle)); + ASSERT_OK(uv_signal_start(&signal_handle, &fork_signal_cb, SIGHUP)); - ASSERT_EQ(0, kill(getpid(), SIGHUP)); + ASSERT_OK(kill(getpid(), SIGHUP)); child_pid = fork(); ASSERT_NE(child_pid, -1); - ASSERT_EQ(0, fork_signal_cb_called); + ASSERT_OK(fork_signal_cb_called); if (!child_pid) { uv_loop_fork(&loop); uv_close((uv_handle_t*)&signal_handle, &empty_close_cb); uv_run(&loop, UV_RUN_DEFAULT); /* Child doesn't receive the signal */ - ASSERT_EQ(0, fork_signal_cb_called); + ASSERT_OK(fork_signal_cb_called); } else { /* Parent. Runing once to receive the signal */ uv_run(&loop, UV_RUN_ONCE); @@ -403,7 +407,7 @@ TEST_IMPL(fork_close_signal_in_child) { /* loop should stop after closing the only handle */ uv_close((uv_handle_t*)&signal_handle, &empty_close_cb); - ASSERT_EQ(0, uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); assert_wait_child(child_pid); } @@ -419,11 +423,11 @@ static void create_file(const char* name) { uv_fs_t req; r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); file = r; uv_fs_req_cleanup(&req); r = uv_fs_close(NULL, &req, file, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); } @@ -435,17 +439,17 @@ static void touch_file(const char* name) { uv_buf_t buf; r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); file = r; uv_fs_req_cleanup(&req); buf = uv_buf_init("foo", 4); r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); uv_fs_req_cleanup(&req); r = uv_fs_close(NULL, &req, file, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); } @@ -465,11 +469,11 @@ static void fs_event_cb_file_current_dir(uv_fs_event_t* handle, const char* filename, int events, int status) { - ASSERT(fs_event_cb_called == 0); + ASSERT_OK(fs_event_cb_called); ++fs_event_cb_called; - ASSERT(status == 0); + ASSERT_OK(status); #if defined(__APPLE__) || defined(__linux__) - ASSERT(strcmp(filename, "watch_file") == 0); + ASSERT_OK(strcmp(filename, "watch_file")); #else ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0); #endif @@ -487,28 +491,28 @@ static void assert_watch_file_current_dir(uv_loop_t* const loop, int file_or_dir create_file("watch_file"); r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); /* watching a dir is the only way to get fsevents involved on apple platforms */ r = uv_fs_event_start(&fs_event, fs_event_cb_file_current_dir, file_or_dir == 1 ? "." : "watch_file", 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, timer_cb_touch, 100, 0); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(timer_cb_touch_called == 0); - ASSERT(fs_event_cb_called == 0); + ASSERT_OK(timer_cb_touch_called); + ASSERT_OK(fs_event_cb_called); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(timer_cb_touch_called == 1); - ASSERT(fs_event_cb_called == 1); + ASSERT_EQ(1, timer_cb_touch_called); + ASSERT_EQ(1, fs_event_cb_called); /* Cleanup */ remove("watch_file"); @@ -533,7 +537,7 @@ static int _do_fork_fs_events_child(int file_or_dir) { #else child_pid = fork(); #endif - ASSERT(child_pid != -1); + ASSERT_NE(child_pid, -1); if (child_pid != 0) { /* parent */ @@ -549,10 +553,10 @@ static int _do_fork_fs_events_child(int file_or_dir) { uv_loop_init(&loop); printf("Child first watch\n"); assert_watch_file_current_dir(&loop, file_or_dir); - ASSERT(0 == uv_loop_close(&loop)); + ASSERT_OK(uv_loop_close(&loop)); printf("Child second watch default loop\n"); /* Ee can watch in the default loop. */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); + ASSERT_OK(uv_loop_fork(uv_default_loop())); /* On some platforms (OS X), if we don't update the time now, * the timer cb fires before the event loop enters uv__io_poll, * instead of after, meaning we don't see the change! This may be @@ -565,7 +569,7 @@ static int _do_fork_fs_events_child(int file_or_dir) { especially important on Apple platforms where if we're not careful trying to touch the CFRunLoop, even just to shut it down, that we allocated in the FS_TEST_DIR case would crash. */ - ASSERT(0 == uv_loop_close(uv_default_loop())); + ASSERT_OK(uv_loop_close(uv_default_loop())); printf("Exiting child \n"); } @@ -628,40 +632,40 @@ TEST_IMPL(fork_fs_events_file_parent_child) { create_file("watch_file"); r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_cb_file_current_dir, "watch_file", 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); #if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) child_pid = -1; #else child_pid = fork(); #endif - ASSERT(child_pid != -1); + ASSERT_NE(child_pid, -1); if (child_pid != 0) { /* parent */ assert_wait_child(child_pid); } else { /* child */ printf("Running child\n"); - ASSERT(0 == uv_loop_fork(loop)); + ASSERT_OK(uv_loop_fork(loop)); r = uv_timer_start(&timer, timer_cb_touch, 100, 0); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(timer_cb_touch_called == 0); - ASSERT(fs_event_cb_called == 0); + ASSERT_OK(timer_cb_touch_called); + ASSERT_OK(fs_event_cb_called); printf("Running loop in child \n"); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(timer_cb_touch_called == 1); - ASSERT(fs_event_cb_called == 1); + ASSERT_EQ(1, timer_cb_touch_called); + ASSERT_EQ(1, fs_event_cb_called); /* Cleanup */ remove("watch_file"); @@ -687,7 +691,7 @@ static void work_cb(uv_work_t* req) { static void after_work_cb(uv_work_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); after_work_cb_count++; } @@ -696,16 +700,16 @@ static void assert_run_work(uv_loop_t* const loop) { uv_work_t work_req; int r; - ASSERT(work_cb_count == 0); - ASSERT(after_work_cb_count == 0); + ASSERT_OK(work_cb_count); + ASSERT_OK(after_work_cb_count); printf("Queue in %d\n", getpid()); r = uv_queue_work(loop, &work_req, work_cb, after_work_cb); - ASSERT(r == 0); + ASSERT_OK(r); printf("Running in %d\n", getpid()); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(work_cb_count == 1); - ASSERT(after_work_cb_count == 1); + ASSERT_EQ(1, work_cb_count); + ASSERT_EQ(1, after_work_cb_count); /* cleanup */ work_cb_count = 0; @@ -732,7 +736,7 @@ TEST_IMPL(fork_threadpool_queue_work_simple) { #else child_pid = fork(); #endif - ASSERT(child_pid != -1); + ASSERT_NE(child_pid, -1); if (child_pid != 0) { /* Parent. We can still run work. */ @@ -747,7 +751,7 @@ TEST_IMPL(fork_threadpool_queue_work_simple) { uv_loop_close(&loop); printf("Child second watch default loop\n"); /* We can work in the default loop. */ - ASSERT(0 == uv_loop_fork(uv_default_loop())); + ASSERT_OK(uv_loop_fork(uv_default_loop())); assert_run_work(uv_default_loop()); printf("Exiting child \n"); } diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index d7f04cf4cdd..3f159aeb68f 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -48,19 +48,19 @@ static void handle_result(uv_fs_t* req) { uint64_t mode; int r; - ASSERT(req->fs_type == UV_FS_COPYFILE); - ASSERT(req->result == 0); + ASSERT_EQ(req->fs_type, UV_FS_COPYFILE); + ASSERT_OK(req->result); /* Verify that the file size and mode are the same. */ r = uv_fs_stat(NULL, &stat_req, req->path, NULL); - ASSERT(r == 0); + ASSERT_OK(r); size = stat_req.statbuf.st_size; mode = stat_req.statbuf.st_mode; uv_fs_req_cleanup(&stat_req); r = uv_fs_stat(NULL, &stat_req, dst, NULL); - ASSERT(r == 0); - ASSERT(stat_req.statbuf.st_size == size); - ASSERT(stat_req.statbuf.st_mode == mode); + ASSERT_OK(r); + ASSERT_EQ(stat_req.statbuf.st_size, size); + ASSERT_EQ(stat_req.statbuf.st_mode, mode); uv_fs_req_cleanup(&stat_req); uv_fs_req_cleanup(req); result_check_count++; @@ -77,7 +77,7 @@ static void touch_file(const char* name, unsigned int size) { r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR, NULL); uv_fs_req_cleanup(&req); - ASSERT(r >= 0); + ASSERT_GE(r, 0); file = r; buf = uv_buf_init("a", 1); @@ -86,12 +86,12 @@ static void touch_file(const char* name, unsigned int size) { for (i = 0; i < size; i++) { r = uv_fs_write(NULL, &req, file, &buf, 1, i, NULL); uv_fs_req_cleanup(&req); - ASSERT(r >= 0); + ASSERT_GE(r, 0); } r = uv_fs_close(NULL, &req, file, NULL); uv_fs_req_cleanup(&req); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -105,102 +105,102 @@ TEST_IMPL(fs_copyfile) { /* Fails with EINVAL if bad flags are passed. */ r = uv_fs_copyfile(NULL, &req, src, dst, -1, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_fs_req_cleanup(&req); /* Fails with ENOENT if source does not exist. */ unlink(src); unlink(dst); r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); - ASSERT(req.result == UV_ENOENT); - ASSERT(r == UV_ENOENT); + ASSERT_EQ(req.result, UV_ENOENT); + ASSERT_EQ(r, UV_ENOENT); uv_fs_req_cleanup(&req); /* The destination should not exist. */ r = uv_fs_stat(NULL, &req, dst, NULL); - ASSERT(r != 0); + ASSERT(r); uv_fs_req_cleanup(&req); /* Succeeds if src and dst files are identical. */ touch_file(src, 12); r = uv_fs_copyfile(NULL, &req, src, src, 0, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); /* Verify that the src file did not get truncated. */ r = uv_fs_stat(NULL, &req, src, NULL); - ASSERT_EQ(r, 0); - ASSERT_EQ(req.statbuf.st_size, 12); + ASSERT_OK(r); + ASSERT_EQ(12, req.statbuf.st_size); uv_fs_req_cleanup(&req); unlink(src); /* Copies file synchronously. Creates new file. */ unlink(dst); r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); - ASSERT(r == 0); + ASSERT_OK(r); handle_result(&req); /* Copies a file of size zero. */ unlink(dst); touch_file(src, 0); r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); - ASSERT(r == 0); + ASSERT_OK(r); handle_result(&req); /* Copies file synchronously. Overwrites existing file. */ r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); - ASSERT(r == 0); + ASSERT_OK(r); handle_result(&req); /* Fails to overwrites existing file. */ - ASSERT_EQ(uv_fs_chmod(NULL, &req, dst, 0644, NULL), 0); + ASSERT_OK(uv_fs_chmod(NULL, &req, dst, 0644, NULL)); uv_fs_req_cleanup(&req); r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_EXCL, NULL); - ASSERT(r == UV_EEXIST); + ASSERT_EQ(r, UV_EEXIST); uv_fs_req_cleanup(&req); /* Truncates when an existing destination is larger than the source file. */ - ASSERT_EQ(uv_fs_chmod(NULL, &req, dst, 0644, NULL), 0); + ASSERT_OK(uv_fs_chmod(NULL, &req, dst, 0644, NULL)); uv_fs_req_cleanup(&req); touch_file(src, 1); r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); handle_result(&req); /* Copies a larger file. */ unlink(dst); touch_file(src, 4096 * 2); r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); - ASSERT(r == 0); + ASSERT_OK(r); handle_result(&req); unlink(src); /* Copies file asynchronously */ unlink(dst); r = uv_fs_copyfile(loop, &req, fixture, dst, 0, handle_result); - ASSERT(r == 0); - ASSERT(result_check_count == 5); + ASSERT_OK(r); + ASSERT_EQ(5, result_check_count); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(result_check_count == 6); + ASSERT_EQ(6, result_check_count); /* Ensure file is user-writable (not copied from src). */ - ASSERT_EQ(uv_fs_chmod(NULL, &req, dst, 0644, NULL), 0); + ASSERT_OK(uv_fs_chmod(NULL, &req, dst, 0644, NULL)); uv_fs_req_cleanup(&req); /* If the flags are invalid, the loop should not be kept open */ unlink(dst); r = uv_fs_copyfile(loop, &req, fixture, dst, -1, fail_cb); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_run(loop, UV_RUN_DEFAULT); /* Copies file using UV_FS_COPYFILE_FICLONE. */ unlink(dst); r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_FICLONE, NULL); - ASSERT(r == 0); + ASSERT_OK(r); handle_result(&req); /* Copies file using UV_FS_COPYFILE_FICLONE_FORCE. */ unlink(dst); r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_FICLONE_FORCE, NULL); - ASSERT(r <= 0); + ASSERT_LE(r, 0); if (r == 0) handle_result(&req); @@ -213,8 +213,8 @@ TEST_IMPL(fs_copyfile) { r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); /* On IBMi PASE, qsecofr users can overwrite read-only files */ # ifndef __PASE__ - ASSERT(req.result == UV_EACCES); - ASSERT(r == UV_EACCES); + ASSERT_EQ(req.result, UV_EACCES); + ASSERT_EQ(r, UV_EACCES); # endif uv_fs_req_cleanup(&req); #endif diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 9f231ebfc01..b5c888d690f 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -81,11 +81,11 @@ static void create_file(const char* name) { uv_fs_t req; r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); file = r; uv_fs_req_cleanup(&req); r = uv_fs_close(NULL, &req, file, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); } @@ -96,17 +96,17 @@ static void touch_file(const char* name) { uv_buf_t buf; r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); file = r; uv_fs_req_cleanup(&req); buf = uv_buf_init("foo", 4); r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); uv_fs_req_cleanup(&req); r = uv_fs_close(NULL, &req, file, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); } @@ -125,15 +125,15 @@ static void fail_cb(uv_fs_event_t* handle, static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename, int events, int status) { ++fs_event_cb_called; - ASSERT(handle == &fs_event); - ASSERT(status == 0); - ASSERT(events == UV_CHANGE); + ASSERT_PTR_EQ(handle, &fs_event); + ASSERT_OK(status); + ASSERT_EQ(events, UV_CHANGE); #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) - ASSERT(strcmp(filename, "file1") == 0); + ASSERT_OK(strcmp(filename, "file1")); #else ASSERT(filename == NULL || strcmp(filename, "file1") == 0); #endif - ASSERT(0 == uv_fs_event_stop(handle)); + ASSERT_OK(uv_fs_event_stop(handle)); uv_close((uv_handle_t*)handle, close_cb); } @@ -148,7 +148,7 @@ static const char* fs_event_get_filename(int i) { static void fs_event_create_files(uv_timer_t* handle) { /* Make sure we're not attempting to create files we do not intend */ - ASSERT(fs_event_created < fs_event_file_count); + ASSERT_LT(fs_event_created, fs_event_file_count); /* Create the file */ create_file(fs_event_get_filename(fs_event_created)); @@ -156,7 +156,7 @@ static void fs_event_create_files(uv_timer_t* handle) { if (++fs_event_created < fs_event_file_count) { /* Create another file on a different event loop tick. We do it this way * to avoid fs events coalescing into one fs event. */ - ASSERT_EQ(0, uv_timer_start(&timer, fs_event_create_files, 100, 0)); + ASSERT_OK(uv_timer_start(&timer, fs_event_create_files, 100, 0)); } } @@ -170,19 +170,19 @@ static void fs_event_unlink_files(uv_timer_t* handle) { for (i = 0; i < 16; i++) { r = remove(fs_event_get_filename(i)); if (handle != NULL) - ASSERT(r == 0); + ASSERT_OK(r); } } else { /* Make sure we're not attempting to remove files we do not intend */ - ASSERT(fs_event_removed < fs_event_file_count); + ASSERT_LT(fs_event_removed, fs_event_file_count); /* Remove the file */ - ASSERT(0 == remove(fs_event_get_filename(fs_event_removed))); + ASSERT_OK(remove(fs_event_get_filename(fs_event_removed))); if (++fs_event_removed < fs_event_file_count) { /* Remove another file on a different event loop tick. We do it this way * to avoid fs events coalescing into one fs event. */ - ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 1, 0)); + ASSERT_OK(uv_timer_start(&timer, fs_event_unlink_files, 1, 0)); } } } @@ -192,19 +192,19 @@ static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle, int events, int status) { fs_event_cb_called++; - ASSERT(handle == &fs_event); - ASSERT(status == 0); + ASSERT_PTR_EQ(handle, &fs_event); + ASSERT_OK(status); ASSERT(events == UV_CHANGE || events == UV_RENAME); #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) - ASSERT(strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0); + ASSERT_OK(strncmp(filename, file_prefix, sizeof(file_prefix) - 1)); #else - ASSERT(filename == NULL || - strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0); + ASSERT_NE(filename == NULL || + strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0, 0); #endif if (fs_event_created + fs_event_removed == fs_event_file_count) { /* Once we've processed all create events, delete all files */ - ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 1, 0)); + ASSERT_OK(uv_timer_start(&timer, fs_event_unlink_files, 1, 0)); } else if (fs_event_cb_called == 2 * fs_event_file_count) { /* Once we've processed all create and delete events, stop watching */ uv_close((uv_handle_t*) &timer, close_cb); @@ -224,7 +224,7 @@ static const char* fs_event_get_filename_in_subdir(int i) { static void fs_event_create_files_in_subdir(uv_timer_t* handle) { /* Make sure we're not attempting to create files we do not intend */ - ASSERT(fs_event_created < fs_event_file_count); + ASSERT_LT(fs_event_created, fs_event_file_count); /* Create the file */ create_file(fs_event_get_filename_in_subdir(fs_event_created)); @@ -232,8 +232,7 @@ static void fs_event_create_files_in_subdir(uv_timer_t* handle) { if (++fs_event_created < fs_event_file_count) { /* Create another file on a different event loop tick. We do it this way * to avoid fs events coalescing into one fs event. */ - ASSERT_EQ(0, - uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0)); + ASSERT_OK(uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0)); } } @@ -247,19 +246,22 @@ static void fs_event_unlink_files_in_subdir(uv_timer_t* handle) { for (i = 0; i < 16; i++) { r = remove(fs_event_get_filename_in_subdir(i)); if (handle != NULL) - ASSERT(r == 0); + ASSERT_OK(r); } } else { /* Make sure we're not attempting to remove files we do not intend */ - ASSERT(fs_event_removed < fs_event_file_count); + ASSERT_LT(fs_event_removed, fs_event_file_count); /* Remove the file */ - ASSERT(0 == remove(fs_event_get_filename_in_subdir(fs_event_removed))); + ASSERT_OK(remove(fs_event_get_filename_in_subdir(fs_event_removed))); if (++fs_event_removed < fs_event_file_count) { /* Remove another file on a different event loop tick. We do it this way * to avoid fs events coalescing into one fs event. */ - ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files_in_subdir, 1, 0)); + ASSERT_OK(uv_timer_start(&timer, + fs_event_unlink_files_in_subdir, + 1, + 0)); } } } @@ -283,27 +285,30 @@ static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle, return; fs_multievent_cb_called++; - ASSERT(handle == &fs_event); - ASSERT(status == 0); + ASSERT_PTR_EQ(handle, &fs_event); + ASSERT_OK(status); ASSERT(events == UV_CHANGE || events == UV_RENAME); #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) - ASSERT(strncmp(filename, - file_prefix_in_subdir, - sizeof(file_prefix_in_subdir) - 1) == 0); + ASSERT_OK(strncmp(filename, + file_prefix_in_subdir, + sizeof(file_prefix_in_subdir) - 1)); #else - ASSERT(filename == NULL || - strncmp(filename, - file_prefix_in_subdir, - sizeof(file_prefix_in_subdir) - 1) == 0); + ASSERT_NE(filename == NULL || + strncmp(filename, + file_prefix_in_subdir, + sizeof(file_prefix_in_subdir) - 1) == 0, 0); #endif if (fs_event_created == fs_event_file_count && fs_multievent_cb_called == fs_event_created) { /* Once we've processed all create events, delete all files */ - ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files_in_subdir, 1, 0)); + ASSERT_OK(uv_timer_start(&timer, + fs_event_unlink_files_in_subdir, + 1, + 0)); } else if (fs_multievent_cb_called == 2 * fs_event_file_count) { /* Once we've processed all create and delete events, stop watching */ - ASSERT(fs_event_removed == fs_event_file_count); + ASSERT_EQ(fs_event_removed, fs_event_file_count); uv_close((uv_handle_t*) &timer, close_cb); uv_close((uv_handle_t*) handle, close_cb); } @@ -313,15 +318,15 @@ static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle, static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename, int events, int status) { ++fs_event_cb_called; - ASSERT(handle == &fs_event); - ASSERT(status == 0); - ASSERT(events == UV_CHANGE); + ASSERT_PTR_EQ(handle, &fs_event); + ASSERT_OK(status); + ASSERT_EQ(events, UV_CHANGE); #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) - ASSERT(strcmp(filename, "file2") == 0); + ASSERT_OK(strcmp(filename, "file2")); #else ASSERT(filename == NULL || strcmp(filename, "file2") == 0); #endif - ASSERT(0 == uv_fs_event_stop(handle)); + ASSERT_OK(uv_fs_event_stop(handle)); uv_close((uv_handle_t*)handle, close_cb); } @@ -329,11 +334,11 @@ static void fs_event_cb_file_current_dir(uv_fs_event_t* handle, const char* filename, int events, int status) { ++fs_event_cb_called; - ASSERT(handle == &fs_event); - ASSERT(status == 0); - ASSERT(events == UV_CHANGE); + ASSERT_PTR_EQ(handle, &fs_event); + ASSERT_OK(status); + ASSERT_EQ(events, UV_CHANGE); #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) - ASSERT(strcmp(filename, "watch_file") == 0); + ASSERT_OK(strcmp(filename, "watch_file")); #else ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0); #endif @@ -366,7 +371,7 @@ static void timer_cb_exact(uv_timer_t* handle) { } else { uv_close((uv_handle_t*)handle, NULL); r = uv_fs_event_stop(&fs_event); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &fs_event, NULL); } @@ -384,9 +389,9 @@ static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, int events, int status) { - ASSERT(status == 0); + ASSERT_OK(status); - ASSERT(fs_event_cb_called < 3); + ASSERT_LT(fs_event_cb_called, 3); ++fs_event_cb_called; if (fs_event_cb_called == 3) { @@ -413,18 +418,18 @@ TEST_IMPL(fs_event_watch_dir) { create_dir("watch_dir"); r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file, "watch_dir", 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, fs_event_create_files, 100, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(fs_event_cb_called == fs_event_created + fs_event_removed); - ASSERT(close_cb_called == 2); + ASSERT_EQ(fs_event_cb_called, fs_event_created + fs_event_removed); + ASSERT_EQ(2, close_cb_called); /* Cleanup */ fs_event_unlink_files(NULL); @@ -454,27 +459,27 @@ TEST_IMPL(fs_event_watch_dir_recursive) { create_dir("watch_dir/subdir"); r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file_in_subdir, "watch_dir", UV_FS_EVENT_RECURSIVE); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0); - ASSERT(r == 0); + ASSERT_OK(r); #ifndef _WIN32 /* Also try to watch the root directory. * This will be noisier, so we're just checking for any couple events to happen. */ r = uv_fs_event_init(loop, &fs_event_root); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event_root, fs_event_cb_close, "/", UV_FS_EVENT_RECURSIVE); - ASSERT(r == 0); + ASSERT_OK(r); #else fs_event_cb_called += 3; close_cb_called += 1; @@ -483,9 +488,9 @@ TEST_IMPL(fs_event_watch_dir_recursive) { uv_run(loop, UV_RUN_DEFAULT); - ASSERT(fs_multievent_cb_called == fs_event_created + fs_event_removed); - ASSERT(fs_event_cb_called == 3); - ASSERT(close_cb_called == 3); + ASSERT_EQ(fs_multievent_cb_called, fs_event_created + fs_event_removed); + ASSERT_EQ(3, fs_event_cb_called); + ASSERT_EQ(3, close_cb_called); /* Cleanup */ fs_event_unlink_files_in_subdir(NULL); @@ -522,19 +527,19 @@ TEST_IMPL(fs_event_watch_dir_short_path) { has_shortnames = uv_fs_stat(NULL, &req, "watch_~1", NULL) != UV_ENOENT; if (has_shortnames) { r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_cb_dir, "watch_~1", 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, timer_cb_file, 100, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(fs_event_cb_called == 1); - ASSERT(timer_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, fs_event_cb_called); + ASSERT_EQ(1, timer_cb_called); + ASSERT_EQ(1, close_cb_called); } /* Cleanup */ @@ -568,19 +573,19 @@ TEST_IMPL(fs_event_watch_file) { create_file("watch_dir/file2"); r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_cb_file, "watch_dir/file2", 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, timer_cb_file, 100, 100); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(fs_event_cb_called == 1); - ASSERT(timer_cb_called == 2); - ASSERT(close_cb_called == 2); + ASSERT_EQ(1, fs_event_cb_called); + ASSERT_EQ(2, timer_cb_called); + ASSERT_EQ(2, close_cb_called); /* Cleanup */ remove("watch_dir/file2"); @@ -624,16 +629,16 @@ TEST_IMPL(fs_event_watch_file_exact_path) { #endif r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file.jsx", 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, timer_cb_exact, 100, 100); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); - ASSERT(timer_cb_exact_called == 2); + ASSERT_OK(r); + ASSERT_EQ(2, timer_cb_exact_called); /* Cleanup */ remove("watch_dir/file.js"); @@ -656,13 +661,13 @@ TEST_IMPL(fs_event_watch_file_twice) { loop = uv_default_loop(); timer.data = watchers; - ASSERT(0 == uv_fs_event_init(loop, watchers + 0)); - ASSERT(0 == uv_fs_event_start(watchers + 0, fail_cb, path, 0)); - ASSERT(0 == uv_fs_event_init(loop, watchers + 1)); - ASSERT(0 == uv_fs_event_start(watchers + 1, fail_cb, path, 0)); - ASSERT(0 == uv_timer_init(loop, &timer)); - ASSERT(0 == uv_timer_start(&timer, timer_cb_watch_twice, 10, 0)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_fs_event_init(loop, watchers + 0)); + ASSERT_OK(uv_fs_event_start(watchers + 0, fail_cb, path, 0)); + ASSERT_OK(uv_fs_event_init(loop, watchers + 1)); + ASSERT_OK(uv_fs_event_start(watchers + 1, fail_cb, path, 0)); + ASSERT_OK(uv_timer_init(loop, &timer)); + ASSERT_OK(uv_timer_start(&timer, timer_cb_watch_twice, 10, 0)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -690,31 +695,31 @@ TEST_IMPL(fs_event_watch_file_current_dir) { #endif r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_cb_file_current_dir, "watch_file", 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); timer.data = "watch_file"; r = uv_timer_start(&timer, timer_cb_touch, 1100, 0); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(timer_cb_touch_called == 0); - ASSERT(fs_event_cb_called == 0); - ASSERT(close_cb_called == 0); + ASSERT_OK(timer_cb_touch_called); + ASSERT_OK(fs_event_cb_called); + ASSERT_OK(close_cb_called); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(timer_cb_touch_called == 1); + ASSERT_EQ(1, timer_cb_touch_called); /* FSEvents on macOS sometimes sends one change event, sometimes two. */ ASSERT_NE(0, fs_event_cb_called); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); /* Cleanup */ remove("watch_file"); @@ -737,11 +742,11 @@ TEST_IMPL(fs_event_watch_file_root_dir) { loop = uv_default_loop(); r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fail_cb, path, 0); if (r == UV_ENOENT) RETURN_SKIP("bootsect.bak doesn't exist in system root.\n"); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &fs_event, NULL); @@ -765,20 +770,20 @@ TEST_IMPL(fs_event_no_callback_after_close) { create_file("watch_dir/file1"); r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_cb_file, "watch_dir/file1", 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*)&fs_event, close_cb); touch_file("watch_dir/file1"); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(fs_event_cb_called == 0); - ASSERT(close_cb_called == 1); + ASSERT_OK(fs_event_cb_called); + ASSERT_EQ(1, close_cb_called); /* Cleanup */ remove("watch_dir/file1"); @@ -803,19 +808,19 @@ TEST_IMPL(fs_event_no_callback_on_close) { create_file("watch_dir/file1"); r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_cb_file, "watch_dir/file1", 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*)&fs_event, close_cb); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(fs_event_cb_called == 0); - ASSERT(close_cb_called == 1); + ASSERT_OK(fs_event_cb_called); + ASSERT_EQ(1, close_cb_called); /* Cleanup */ remove("watch_dir/file1"); @@ -830,9 +835,9 @@ static void timer_cb(uv_timer_t* handle) { int r; r = uv_fs_event_init(handle->loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_fail, ".", 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*)&fs_event, close_cb); uv_close((uv_handle_t*)handle, close_cb); @@ -850,14 +855,14 @@ TEST_IMPL(fs_event_immediate_close) { loop = uv_default_loop(); r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, timer_cb, 1, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(close_cb_called == 2); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -877,9 +882,9 @@ TEST_IMPL(fs_event_close_with_pending_event) { create_file("watch_dir/file"); r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir", 0); - ASSERT(r == 0); + ASSERT_OK(r); /* Generate an fs event. */ touch_file("watch_dir/file"); @@ -888,7 +893,7 @@ TEST_IMPL(fs_event_close_with_pending_event) { uv_run(loop, UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); /* Clean up */ remove("watch_dir/file"); @@ -911,9 +916,9 @@ TEST_IMPL(fs_event_close_with_pending_delete_event) { create_file("watch_dir/file"); r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file", 0); - ASSERT(r == 0); + ASSERT_OK(r); /* Generate an fs event. */ remove("watch_dir/file"); @@ -927,7 +932,7 @@ TEST_IMPL(fs_event_close_with_pending_delete_event) { uv_run(loop, UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); /* Clean up */ remove("watch_dir/"); @@ -951,14 +956,14 @@ TEST_IMPL(fs_event_close_in_callback) { create_dir("watch_dir"); r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, fs_event_create_files, 100, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); @@ -966,8 +971,8 @@ TEST_IMPL(fs_event_close_in_callback) { uv_run(loop, UV_RUN_ONCE); - ASSERT(close_cb_called == 2); - ASSERT(fs_event_cb_called == 3); + ASSERT_EQ(2, close_cb_called); + ASSERT_EQ(3, fs_event_cb_called); /* Clean up */ fs_event_unlink_files(NULL); @@ -991,21 +996,21 @@ TEST_IMPL(fs_event_start_and_close) { create_dir("watch_dir"); r = uv_fs_event_init(loop, &fs_event1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event1, fs_event_cb_dir, "watch_dir", 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_init(loop, &fs_event2); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event2, fs_event_cb_dir, "watch_dir", 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &fs_event2, close_cb); uv_close((uv_handle_t*) &fs_event1, close_cb); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(close_cb_called == 2); + ASSERT_EQ(2, close_cb_called); remove("watch_dir/"); MAKE_VALGRIND_HAPPY(loop); @@ -1035,28 +1040,28 @@ TEST_IMPL(fs_event_getpath) { for (i = 0; i < ARRAY_SIZE(watch_dir); i++) { r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); len = sizeof buf; r = uv_fs_event_getpath(&fs_event, buf, &len); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_event_start(&fs_event, fail_cb, watch_dir[i], 0); - ASSERT(r == 0); + ASSERT_OK(r); len = 0; r = uv_fs_event_getpath(&fs_event, buf, &len); - ASSERT(r == UV_ENOBUFS); - ASSERT(len < sizeof buf); /* sanity check */ - ASSERT(len == strlen(watch_dir[i]) + 1); + ASSERT_EQ(r, UV_ENOBUFS); + ASSERT_LT(len, sizeof buf); /* sanity check */ + ASSERT_EQ(len, strlen(watch_dir[i]) + 1); r = uv_fs_event_getpath(&fs_event, buf, &len); - ASSERT(r == 0); - ASSERT(len == strlen(watch_dir[i])); + ASSERT_OK(r); + ASSERT_EQ(len, strlen(watch_dir[i])); ASSERT(strcmp(buf, watch_dir[i]) == 0); r = uv_fs_event_stop(&fs_event); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &fs_event, close_cb); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); close_cb_called = 0; } @@ -1108,43 +1113,43 @@ TEST_IMPL(fs_event_error_reporting) { */ for (i = 0; i < ARRAY_SIZE(loops); i++) { loop = &loops[i]; - ASSERT(0 == uv_loop_init(loop)); + ASSERT_OK(uv_loop_init(loop)); event = &events[i]; timer_cb_called = 0; close_cb_called = 0; - ASSERT(0 == uv_fs_event_init(loop, event)); - ASSERT(0 == uv_fs_event_start(event, - fs_event_error_report_cb, - "watch_dir", - 0)); + ASSERT_OK(uv_fs_event_init(loop, event)); + ASSERT_OK(uv_fs_event_start(event, + fs_event_error_report_cb, + "watch_dir", + 0)); uv_unref((uv_handle_t*) event); /* Let loop run for some time */ - ASSERT(0 == uv_timer_init(loop, &timer)); - ASSERT(0 == uv_timer_start(&timer, timer_cb_nop, 2, 0)); + ASSERT_OK(uv_timer_init(loop, &timer)); + ASSERT_OK(uv_timer_start(&timer, timer_cb_nop, 2, 0)); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(1 == timer_cb_called); - ASSERT(1 == close_cb_called); + ASSERT_EQ(1, timer_cb_called); + ASSERT_EQ(1, close_cb_called); if (fs_event_error_reported != 0) break; } /* At least one loop should fail */ - ASSERT(fs_event_error_reported == UV_EMFILE); + ASSERT_EQ(fs_event_error_reported, UV_EMFILE); /* Stop and close all events, and destroy loops */ do { loop = &loops[i]; event = &events[i]; - ASSERT(0 == uv_fs_event_stop(event)); + ASSERT_OK(uv_fs_event_stop(event)); uv_ref((uv_handle_t*) event); uv_close((uv_handle_t*) event, fs_event_error_report_close_cb); close_cb_called = 0; uv_run(loop, UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); uv_loop_close(loop); } while (i-- != 0); @@ -1175,13 +1180,13 @@ TEST_IMPL(fs_event_watch_invalid_path) { loop = uv_default_loop(); r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event, fs_event_cb_file, "<:;", 0); - ASSERT(r != 0); - ASSERT(uv_is_active((uv_handle_t*) &fs_event) == 0); + ASSERT(r); + ASSERT_OK(uv_is_active((uv_handle_t*) &fs_event)); r = uv_fs_event_start(&fs_event, fs_event_cb_file, "", 0); - ASSERT(r != 0); - ASSERT(uv_is_active((uv_handle_t*) &fs_event) == 0); + ASSERT(r); + ASSERT_OK(uv_is_active((uv_handle_t*) &fs_event)); MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1206,24 +1211,24 @@ TEST_IMPL(fs_event_stop_in_cb) { remove(path); create_file(path); - ASSERT_EQ(0, uv_fs_event_init(uv_default_loop(), &fs)); - ASSERT_EQ(0, uv_fs_event_start(&fs, fs_event_cb_stop, path, 0)); + ASSERT_OK(uv_fs_event_init(uv_default_loop(), &fs)); + ASSERT_OK(uv_fs_event_start(&fs, fs_event_cb_stop, path, 0)); /* Note: timer_cb_touch() closes the handle. */ timer.data = path; - ASSERT_EQ(0, uv_timer_init(uv_default_loop(), &timer)); - ASSERT_EQ(0, uv_timer_start(&timer, timer_cb_touch, 100, 0)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer)); + ASSERT_OK(uv_timer_start(&timer, timer_cb_touch, 100, 0)); - ASSERT_EQ(0, fs_event_cb_stop_calls); - ASSERT_EQ(0, timer_cb_touch_called); + ASSERT_OK(fs_event_cb_stop_calls); + ASSERT_OK(timer_cb_touch_called); - ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT_EQ(1, fs_event_cb_stop_calls); ASSERT_EQ(1, timer_cb_touch_called); uv_close((uv_handle_t*) &fs, NULL); - ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT_EQ(1, fs_event_cb_stop_calls); remove(path); diff --git a/test/test-fs-fd-hash.c b/test/test-fs-fd-hash.c index 8b4bc0351b3..4ed3d548e62 100644 --- a/test/test-fs-fd-hash.c +++ b/test/test-fs-fd-hash.c @@ -43,7 +43,7 @@ void assert_nonexistent(int fd) { void assert_existent(int fd) { struct uv__fd_info_s info = { 0 }; ASSERT(uv__fd_hash_get(fd, &info)); - ASSERT(info.flags == fd + FD_DIFF); + ASSERT_EQ(info.flags, fd + FD_DIFF); } void assert_insertion(int fd) { @@ -58,7 +58,7 @@ void assert_removal(int fd) { struct uv__fd_info_s info = { 0 }; assert_existent(fd); uv__fd_hash_remove(fd, &info); - ASSERT(info.flags == fd + FD_DIFF); + ASSERT_EQ(info.flags, fd + FD_DIFF); assert_nonexistent(fd); } @@ -106,7 +106,7 @@ TEST_IMPL(fs_fd_hash) { { struct uv__fd_info_s info = { 0 }; ASSERT(uv__fd_hash_get(0, &info)); - ASSERT(info.flags == FD_DIFF + FD_DIFF); + ASSERT_EQ(info.flags, FD_DIFF + FD_DIFF); } { /* Leave as it was, will be again tested below */ diff --git a/test/test-fs-open-flags.c b/test/test-fs-open-flags.c index ea9be25afc1..e64ac20d72b 100644 --- a/test/test-fs-open-flags.c +++ b/test/test-fs-open-flags.c @@ -68,8 +68,8 @@ static void setup(void) { uv_fs_req_cleanup(&rmdir_req); r = uv_fs_mkdir(NULL, &mkdir_req, empty_dir, 0755, NULL); - ASSERT(r == 0); - ASSERT(mkdir_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(mkdir_req.result); uv_fs_req_cleanup(&mkdir_req); } @@ -89,13 +89,13 @@ static void refresh(void) { r = uv_fs_open(NULL, &open_req, empty_file, UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req.result, 0); uv_fs_req_cleanup(&open_req); r = uv_fs_close(NULL, &close_req, open_req.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* dummy_file */ @@ -103,19 +103,19 @@ static void refresh(void) { r = uv_fs_open(NULL, &open_req, dummy_file, UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_WRONLY, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req.result, 0); uv_fs_req_cleanup(&open_req); iov = uv_buf_init("a", 1); r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL); - ASSERT(r == 1); - ASSERT(write_req.result == 1); + ASSERT_EQ(1, r); + ASSERT_EQ(1, write_req.result); uv_fs_req_cleanup(&write_req); r = uv_fs_close(NULL, &close_req, open_req.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); } @@ -131,14 +131,14 @@ static void openFail(char *file, int error) { refresh(); r = uv_fs_open(NULL, &open_req, file, flags, S_IWUSR | S_IRUSR, NULL); - ASSERT(r == error); - ASSERT(open_req.result == error); + ASSERT_EQ(r, error); + ASSERT_EQ(open_req.result, error); uv_fs_req_cleanup(&open_req); /* Ensure the first call does not create the file */ r = uv_fs_open(NULL, &open_req, file, flags, S_IWUSR | S_IRUSR, NULL); - ASSERT(r == error); - ASSERT(open_req.result == error); + ASSERT_EQ(r, error); + ASSERT_EQ(open_req.result, error); uv_fs_req_cleanup(&open_req); cleanup(); @@ -150,8 +150,8 @@ static void refreshOpen(char *file) { refresh(); r = uv_fs_open(NULL, &open_req, file, flags, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req.result, 0); uv_fs_req_cleanup(&open_req); } @@ -162,37 +162,37 @@ static void writeExpect(char *file, char *expected, int size) { iov = uv_buf_init("b", 1); r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL); - ASSERT(r == 1); - ASSERT(write_req.result == 1); + ASSERT_EQ(1, r); + ASSERT_EQ(1, write_req.result); uv_fs_req_cleanup(&write_req); iov = uv_buf_init("c", 1); r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL); - ASSERT(r == 1); - ASSERT(write_req.result == 1); + ASSERT_EQ(1, r); + ASSERT_EQ(1, write_req.result); uv_fs_req_cleanup(&write_req); r = uv_fs_close(NULL, &close_req, open_req.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* Check contents */ r = uv_fs_open(NULL, &open_req, file, UV_FS_O_RDONLY, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req.result, 0); uv_fs_req_cleanup(&open_req); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL); - ASSERT(r == size); - ASSERT(read_req.result == size); - ASSERT(strncmp(buf, expected, size) == 0); + ASSERT_EQ(r, size); + ASSERT_EQ(read_req.result, size); + ASSERT_OK(strncmp(buf, expected, size)); uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); cleanup(); @@ -205,19 +205,19 @@ static void writeFail(char *file, int error) { iov = uv_buf_init("z", 1); r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL); - ASSERT(r == error); - ASSERT(write_req.result == error); + ASSERT_EQ(r, error); + ASSERT_EQ(write_req.result, error); uv_fs_req_cleanup(&write_req); iov = uv_buf_init("z", 1); r = uv_fs_write(NULL, &write_req, open_req.result, &iov, 1, -1, NULL); - ASSERT(r == error); - ASSERT(write_req.result == error); + ASSERT_EQ(r, error); + ASSERT_EQ(write_req.result, error); uv_fs_req_cleanup(&write_req); r = uv_fs_close(NULL, &close_req, open_req.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); cleanup(); @@ -230,14 +230,14 @@ static void readExpect(char *file, char *expected, int size) { iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL); - ASSERT(r == size); - ASSERT(read_req.result == size); - ASSERT(strncmp(buf, expected, size) == 0); + ASSERT_EQ(r, size); + ASSERT_EQ(read_req.result, size); + ASSERT_OK(strncmp(buf, expected, size)); uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); cleanup(); @@ -250,19 +250,19 @@ static void readFail(char *file, int error) { iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL); - ASSERT(r == error); - ASSERT(read_req.result == error); + ASSERT_EQ(r, error); + ASSERT_EQ(read_req.result, error); uv_fs_req_cleanup(&read_req); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req.result, &iov, 1, -1, NULL); - ASSERT(r == error); - ASSERT(read_req.result == error); + ASSERT_EQ(r, error); + ASSERT_EQ(read_req.result, error); uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); cleanup(); diff --git a/test/test-fs-poll.c b/test/test-fs-poll.c index af486023d10..5f95baf3d3f 100644 --- a/test/test-fs-poll.c +++ b/test/test-fs-poll.c @@ -103,44 +103,44 @@ static void poll_cb(uv_fs_poll_t* handle, memset(&zero_statbuf, 0, sizeof(zero_statbuf)); - ASSERT(handle == &poll_handle); - ASSERT(1 == uv_is_active((uv_handle_t*) handle)); + ASSERT_PTR_EQ(handle, &poll_handle); + ASSERT_EQ(1, uv_is_active((uv_handle_t*) handle)); ASSERT_NOT_NULL(prev); ASSERT_NOT_NULL(curr); switch (poll_cb_called++) { case 0: - ASSERT(status == UV_ENOENT); - ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); - ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT_EQ(status, UV_ENOENT); + ASSERT_OK(memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT_OK(memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); touch_file(FIXTURE); break; case 1: - ASSERT(status == 0); - ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); - ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); - ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 20, 0)); + ASSERT_OK(status); + ASSERT_OK(memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT_NE(0, memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, 20, 0)); break; case 2: - ASSERT(status == 0); - ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); - ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); - ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 200, 0)); + ASSERT_OK(status); + ASSERT_NE(0, memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT_NE(0, memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, 200, 0)); break; case 3: - ASSERT(status == 0); - ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); - ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT_OK(status); + ASSERT_NE(0, memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT_NE(0, memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); remove(FIXTURE); break; case 4: - ASSERT(status == UV_ENOENT); - ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); - ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT_EQ(status, UV_ENOENT); + ASSERT_NE(0, memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); + ASSERT_OK(memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); uv_close((uv_handle_t*)handle, close_cb); break; @@ -155,14 +155,14 @@ TEST_IMPL(fs_poll) { remove(FIXTURE); - ASSERT(0 == uv_timer_init(loop, &timer_handle)); - ASSERT(0 == uv_fs_poll_init(loop, &poll_handle)); - ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb, FIXTURE, 100)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_timer_init(loop, &timer_handle)); + ASSERT_OK(uv_fs_poll_init(loop, &poll_handle)); + ASSERT_OK(uv_fs_poll_start(&poll_handle, poll_cb, FIXTURE, 100)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(poll_cb_called == 5); - ASSERT(timer_cb_called == 2); - ASSERT(close_cb_called == 1); + ASSERT_EQ(5, poll_cb_called); + ASSERT_EQ(2, timer_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -176,21 +176,21 @@ TEST_IMPL(fs_poll_getpath) { remove(FIXTURE); - ASSERT(0 == uv_fs_poll_init(loop, &poll_handle)); + ASSERT_OK(uv_fs_poll_init(loop, &poll_handle)); len = sizeof buf; - ASSERT(UV_EINVAL == uv_fs_poll_getpath(&poll_handle, buf, &len)); - ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); + ASSERT_EQ(UV_EINVAL, uv_fs_poll_getpath(&poll_handle, buf, &len)); + ASSERT_OK(uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); len = sizeof buf; - ASSERT(0 == uv_fs_poll_getpath(&poll_handle, buf, &len)); - ASSERT(buf[len - 1] != 0); - ASSERT(buf[len] == '\0'); - ASSERT(0 == memcmp(buf, FIXTURE, len)); + ASSERT_OK(uv_fs_poll_getpath(&poll_handle, buf, &len)); + ASSERT_NE(0, buf[len - 1]); + ASSERT_EQ(buf[len], '\0'); + ASSERT_OK(memcmp(buf, FIXTURE, len)); uv_close((uv_handle_t*) &poll_handle, close_cb); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -203,14 +203,14 @@ TEST_IMPL(fs_poll_close_request) { remove(FIXTURE); - ASSERT(0 == uv_loop_init(&loop)); + ASSERT_OK(uv_loop_init(&loop)); - ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle)); - ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); + ASSERT_OK(uv_fs_poll_init(&loop, &poll_handle)); + ASSERT_OK(uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); uv_close((uv_handle_t*) &poll_handle, close_cb); while (close_cb_called == 0) uv_run(&loop, UV_RUN_ONCE); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(&loop); return 0; @@ -223,18 +223,18 @@ TEST_IMPL(fs_poll_close_request_multi_start_stop) { remove(FIXTURE); - ASSERT(0 == uv_loop_init(&loop)); + ASSERT_OK(uv_loop_init(&loop)); - ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle)); + ASSERT_OK(uv_fs_poll_init(&loop, &poll_handle)); for (i = 0; i < 10; ++i) { - ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); - ASSERT(0 == uv_fs_poll_stop(&poll_handle)); + ASSERT_OK(uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); + ASSERT_OK(uv_fs_poll_stop(&poll_handle)); } uv_close((uv_handle_t*) &poll_handle, close_cb); while (close_cb_called == 0) uv_run(&loop, UV_RUN_ONCE); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(&loop); return 0; @@ -247,18 +247,18 @@ TEST_IMPL(fs_poll_close_request_multi_stop_start) { remove(FIXTURE); - ASSERT(0 == uv_loop_init(&loop)); + ASSERT_OK(uv_loop_init(&loop)); - ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle)); + ASSERT_OK(uv_fs_poll_init(&loop, &poll_handle)); for (i = 0; i < 10; ++i) { - ASSERT(0 == uv_fs_poll_stop(&poll_handle)); - ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); + ASSERT_OK(uv_fs_poll_stop(&poll_handle)); + ASSERT_OK(uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); } uv_close((uv_handle_t*) &poll_handle, close_cb); while (close_cb_called == 0) uv_run(&loop, UV_RUN_ONCE); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(&loop); return 0; @@ -271,21 +271,21 @@ TEST_IMPL(fs_poll_close_request_stop_when_active) { remove(FIXTURE); - ASSERT(0 == uv_loop_init(&loop)); + ASSERT_OK(uv_loop_init(&loop)); /* Set up all handles. */ - ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle)); - ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_noop, FIXTURE, 100)); + ASSERT_OK(uv_fs_poll_init(&loop, &poll_handle)); + ASSERT_OK(uv_fs_poll_start(&poll_handle, poll_cb_noop, FIXTURE, 100)); uv_run(&loop, UV_RUN_ONCE); /* Close the timer handle, and do not crash. */ - ASSERT(0 == uv_fs_poll_stop(&poll_handle)); + ASSERT_OK(uv_fs_poll_stop(&poll_handle)); uv_run(&loop, UV_RUN_ONCE); /* Clean up after the test. */ uv_close((uv_handle_t*) &poll_handle, close_cb); uv_run(&loop, UV_RUN_ONCE); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(&loop); return 0; diff --git a/test/test-fs-readdir.c b/test/test-fs-readdir.c index 43c9edf178b..7eaca6f89c4 100644 --- a/test/test-fs-readdir.c +++ b/test/test-fs-readdir.c @@ -47,9 +47,9 @@ static void cleanup_test_files(void) { } static void empty_closedir_cb(uv_fs_t* req) { - ASSERT(req == &closedir_req); - ASSERT(req->fs_type == UV_FS_CLOSEDIR); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &closedir_req); + ASSERT_EQ(req->fs_type, UV_FS_CLOSEDIR); + ASSERT_OK(req->result); ++empty_closedir_cb_count; uv_fs_req_cleanup(req); } @@ -58,25 +58,25 @@ static void empty_readdir_cb(uv_fs_t* req) { uv_dir_t* dir; int r; - ASSERT(req == &readdir_req); - ASSERT(req->fs_type == UV_FS_READDIR); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &readdir_req); + ASSERT_EQ(req->fs_type, UV_FS_READDIR); + ASSERT_OK(req->result); dir = req->ptr; uv_fs_req_cleanup(req); r = uv_fs_closedir(uv_default_loop(), &closedir_req, dir, empty_closedir_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static void empty_opendir_cb(uv_fs_t* req) { uv_dir_t* dir; int r; - ASSERT(req == &opendir_req); - ASSERT(req->fs_type == UV_FS_OPENDIR); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &opendir_req); + ASSERT_EQ(req->fs_type, UV_FS_OPENDIR); + ASSERT_OK(req->result); ASSERT_NOT_NULL(req->ptr); dir = req->ptr; dir->dirents = dirents; @@ -85,7 +85,7 @@ static void empty_opendir_cb(uv_fs_t* req) { &readdir_req, dir, empty_readdir_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(req); ++empty_opendir_cb_count; } @@ -115,9 +115,9 @@ TEST_IMPL(fs_readdir_empty_dir) { &opendir_req, path, NULL); - ASSERT(r == 0); - ASSERT(opendir_req.fs_type == UV_FS_OPENDIR); - ASSERT(opendir_req.result == 0); + ASSERT_OK(r); + ASSERT_EQ(opendir_req.fs_type, UV_FS_OPENDIR); + ASSERT_OK(opendir_req.result); ASSERT_NOT_NULL(opendir_req.ptr); dir = opendir_req.ptr; uv_fs_req_cleanup(&opendir_req); @@ -130,13 +130,13 @@ TEST_IMPL(fs_readdir_empty_dir) { &readdir_req, dir, NULL); - ASSERT(nb_entries_read == 0); + ASSERT_OK(nb_entries_read); uv_fs_req_cleanup(&readdir_req); /* Fill the req to ensure that required fields are cleaned up. */ memset(&closedir_req, 0xdb, sizeof(closedir_req)); uv_fs_closedir(uv_default_loop(), &closedir_req, dir, NULL); - ASSERT(closedir_req.result == 0); + ASSERT_OK(closedir_req.result); uv_fs_req_cleanup(&closedir_req); /* Testing the asynchronous flavor. */ @@ -147,13 +147,13 @@ TEST_IMPL(fs_readdir_empty_dir) { memset(&closedir_req, 0xdb, sizeof(closedir_req)); r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, empty_opendir_cb); - ASSERT(r == 0); - ASSERT(empty_opendir_cb_count == 0); - ASSERT(empty_closedir_cb_count == 0); + ASSERT_OK(r); + ASSERT_OK(empty_opendir_cb_count); + ASSERT_OK(empty_closedir_cb_count); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); - ASSERT(empty_opendir_cb_count == 1); - ASSERT(empty_closedir_cb_count == 1); + ASSERT_OK(r); + ASSERT_EQ(1, empty_opendir_cb_count); + ASSERT_EQ(1, empty_closedir_cb_count); uv_fs_rmdir(uv_default_loop(), &rmdir_req, path, NULL); uv_fs_req_cleanup(&rmdir_req); MAKE_VALGRIND_HAPPY(uv_default_loop()); @@ -168,9 +168,9 @@ TEST_IMPL(fs_readdir_empty_dir) { static int non_existing_opendir_cb_count; static void non_existing_opendir_cb(uv_fs_t* req) { - ASSERT(req == &opendir_req); - ASSERT(req->fs_type == UV_FS_OPENDIR); - ASSERT(req->result == UV_ENOENT); + ASSERT_PTR_EQ(req, &opendir_req); + ASSERT_EQ(req->fs_type, UV_FS_OPENDIR); + ASSERT_EQ(req->result, UV_ENOENT); ASSERT_NULL(req->ptr); uv_fs_req_cleanup(req); @@ -188,9 +188,9 @@ TEST_IMPL(fs_readdir_non_existing_dir) { /* Testing the synchronous flavor. */ r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, NULL); - ASSERT(r == UV_ENOENT); - ASSERT(opendir_req.fs_type == UV_FS_OPENDIR); - ASSERT(opendir_req.result == UV_ENOENT); + ASSERT_EQ(r, UV_ENOENT); + ASSERT_EQ(opendir_req.fs_type, UV_FS_OPENDIR); + ASSERT_EQ(opendir_req.result, UV_ENOENT); ASSERT_NULL(opendir_req.ptr); uv_fs_req_cleanup(&opendir_req); @@ -202,11 +202,11 @@ TEST_IMPL(fs_readdir_non_existing_dir) { &opendir_req, path, non_existing_opendir_cb); - ASSERT(r == 0); - ASSERT(non_existing_opendir_cb_count == 0); + ASSERT_OK(r); + ASSERT_OK(non_existing_opendir_cb_count); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); - ASSERT(non_existing_opendir_cb_count == 1); + ASSERT_OK(r); + ASSERT_EQ(1, non_existing_opendir_cb_count); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -220,9 +220,9 @@ TEST_IMPL(fs_readdir_non_existing_dir) { static int file_opendir_cb_count; static void file_opendir_cb(uv_fs_t* req) { - ASSERT(req == &opendir_req); - ASSERT(req->fs_type == UV_FS_OPENDIR); - ASSERT(req->result == UV_ENOTDIR); + ASSERT_PTR_EQ(req, &opendir_req); + ASSERT_EQ(req->fs_type, UV_FS_OPENDIR); + ASSERT_EQ(req->result, UV_ENOTDIR); ASSERT_NULL(req->ptr); uv_fs_req_cleanup(req); @@ -241,9 +241,9 @@ TEST_IMPL(fs_readdir_file) { /* Testing the synchronous flavor. */ r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, NULL); - ASSERT(r == UV_ENOTDIR); - ASSERT(opendir_req.fs_type == UV_FS_OPENDIR); - ASSERT(opendir_req.result == UV_ENOTDIR); + ASSERT_EQ(r, UV_ENOTDIR); + ASSERT_EQ(opendir_req.fs_type, UV_FS_OPENDIR); + ASSERT_EQ(opendir_req.result, UV_ENOTDIR); ASSERT_NULL(opendir_req.ptr); uv_fs_req_cleanup(&opendir_req); @@ -253,11 +253,11 @@ TEST_IMPL(fs_readdir_file) { /* Testing the async flavor. */ r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, file_opendir_cb); - ASSERT(r == 0); - ASSERT(file_opendir_cb_count == 0); + ASSERT_OK(r); + ASSERT_OK(file_opendir_cb_count); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); - ASSERT(file_opendir_cb_count == 1); + ASSERT_OK(r); + ASSERT_EQ(1, file_opendir_cb_count); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -273,8 +273,8 @@ static int non_empty_readdir_cb_count; static int non_empty_closedir_cb_count; static void non_empty_closedir_cb(uv_fs_t* req) { - ASSERT(req == &closedir_req); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &closedir_req); + ASSERT_OK(req->result); uv_fs_req_cleanup(req); ++non_empty_closedir_cb_count; } @@ -282,30 +282,30 @@ static void non_empty_closedir_cb(uv_fs_t* req) { static void non_empty_readdir_cb(uv_fs_t* req) { uv_dir_t* dir; - ASSERT(req == &readdir_req); - ASSERT(req->fs_type == UV_FS_READDIR); + ASSERT_PTR_EQ(req, &readdir_req); + ASSERT_EQ(req->fs_type, UV_FS_READDIR); dir = req->ptr; if (req->result == 0) { uv_fs_req_cleanup(req); - ASSERT(non_empty_readdir_cb_count == 3); + ASSERT_EQ(3, non_empty_readdir_cb_count); uv_fs_closedir(uv_default_loop(), &closedir_req, dir, non_empty_closedir_cb); } else { - ASSERT(req->result == 1); - ASSERT(dir->dirents == dirents); + ASSERT_EQ(1, req->result); + ASSERT_EQ(dir->dirents, dirents); ASSERT(strcmp(dirents[0].name, "file1") == 0 || strcmp(dirents[0].name, "file2") == 0 || strcmp(dirents[0].name, "test_subdir") == 0); #ifdef HAVE_DIRENT_TYPES if (!strcmp(dirents[0].name, "test_subdir")) - ASSERT(dirents[0].type == UV_DIRENT_DIR); + ASSERT_EQ(dirents[0].type, UV_DIRENT_DIR); else - ASSERT(dirents[0].type == UV_DIRENT_FILE); + ASSERT_EQ(dirents[0].type, UV_DIRENT_FILE); #else - ASSERT(dirents[0].type == UV_DIRENT_UNKNOWN); + ASSERT_EQ(dirents[0].type, UV_DIRENT_UNKNOWN); #endif /* HAVE_DIRENT_TYPES */ ++non_empty_readdir_cb_count; @@ -323,9 +323,9 @@ static void non_empty_opendir_cb(uv_fs_t* req) { uv_dir_t* dir; int r; - ASSERT(req == &opendir_req); - ASSERT(req->fs_type == UV_FS_OPENDIR); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &opendir_req); + ASSERT_EQ(req->fs_type, UV_FS_OPENDIR); + ASSERT_OK(req->result); ASSERT_NOT_NULL(req->ptr); dir = req->ptr; @@ -336,7 +336,7 @@ static void non_empty_opendir_cb(uv_fs_t* req) { &readdir_req, dir, non_empty_readdir_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(req); ++non_empty_opendir_cb_count; } @@ -353,7 +353,7 @@ TEST_IMPL(fs_readdir_non_empty_dir) { cleanup_test_files(); r = uv_fs_mkdir(uv_default_loop(), &mkdir_req, "test_dir", 0755, NULL); - ASSERT(r == 0); + ASSERT_OK(r); /* Create two files synchronously. */ r = uv_fs_open(uv_default_loop(), @@ -361,13 +361,13 @@ TEST_IMPL(fs_readdir_non_empty_dir) { "test_dir/file1", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); uv_fs_req_cleanup(&create_req); r = uv_fs_close(uv_default_loop(), &close_req, create_req.result, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&close_req); r = uv_fs_open(uv_default_loop(), @@ -375,13 +375,13 @@ TEST_IMPL(fs_readdir_non_empty_dir) { "test_dir/file2", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); uv_fs_req_cleanup(&create_req); r = uv_fs_close(uv_default_loop(), &close_req, create_req.result, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&close_req); r = uv_fs_mkdir(uv_default_loop(), @@ -389,7 +389,7 @@ TEST_IMPL(fs_readdir_non_empty_dir) { "test_dir/test_subdir", 0755, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&mkdir_req); /* Fill the req to ensure that required fields are cleaned up. */ @@ -397,9 +397,9 @@ TEST_IMPL(fs_readdir_non_empty_dir) { /* Testing the synchronous flavor. */ r = uv_fs_opendir(uv_default_loop(), &opendir_req, "test_dir", NULL); - ASSERT(r == 0); - ASSERT(opendir_req.fs_type == UV_FS_OPENDIR); - ASSERT(opendir_req.result == 0); + ASSERT_OK(r); + ASSERT_EQ(opendir_req.fs_type, UV_FS_OPENDIR); + ASSERT_OK(opendir_req.result); ASSERT_NOT_NULL(opendir_req.ptr); entries_count = 0; @@ -417,23 +417,23 @@ TEST_IMPL(fs_readdir_non_empty_dir) { strcmp(dirents[0].name, "test_subdir") == 0); #ifdef HAVE_DIRENT_TYPES if (!strcmp(dirents[0].name, "test_subdir")) - ASSERT(dirents[0].type == UV_DIRENT_DIR); + ASSERT_EQ(dirents[0].type, UV_DIRENT_DIR); else - ASSERT(dirents[0].type == UV_DIRENT_FILE); + ASSERT_EQ(dirents[0].type, UV_DIRENT_FILE); #else - ASSERT(dirents[0].type == UV_DIRENT_UNKNOWN); + ASSERT_EQ(dirents[0].type, UV_DIRENT_UNKNOWN); #endif /* HAVE_DIRENT_TYPES */ uv_fs_req_cleanup(&readdir_req); ++entries_count; } - ASSERT(entries_count == 3); + ASSERT_EQ(3, entries_count); uv_fs_req_cleanup(&readdir_req); /* Fill the req to ensure that required fields are cleaned up. */ memset(&closedir_req, 0xdb, sizeof(closedir_req)); uv_fs_closedir(uv_default_loop(), &closedir_req, dir, NULL); - ASSERT(closedir_req.result == 0); + ASSERT_OK(closedir_req.result); uv_fs_req_cleanup(&closedir_req); /* Testing the asynchronous flavor. */ @@ -445,13 +445,13 @@ TEST_IMPL(fs_readdir_non_empty_dir) { &opendir_req, "test_dir", non_empty_opendir_cb); - ASSERT(r == 0); - ASSERT(non_empty_opendir_cb_count == 0); - ASSERT(non_empty_closedir_cb_count == 0); + ASSERT_OK(r); + ASSERT_OK(non_empty_opendir_cb_count); + ASSERT_OK(non_empty_closedir_cb_count); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); - ASSERT(non_empty_opendir_cb_count == 1); - ASSERT(non_empty_closedir_cb_count == 1); + ASSERT_OK(r); + ASSERT_EQ(1, non_empty_opendir_cb_count); + ASSERT_EQ(1, non_empty_closedir_cb_count); uv_fs_rmdir(uv_default_loop(), &rmdir_req, "test_subdir", NULL); uv_fs_req_cleanup(&rmdir_req); diff --git a/test/test-fs.c b/test/test-fs.c index e687dde3e25..5be48dd5c3a 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -170,8 +170,8 @@ static void check_permission(const char* filename, unsigned int mode) { uv_stat_t* s; r = uv_fs_stat(NULL, &req, filename, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); s = &req.statbuf; #if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__) @@ -195,24 +195,24 @@ static void dummy_cb(uv_fs_t* req) { static void link_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_LINK); - ASSERT(req->result == 0); + ASSERT_EQ(req->fs_type, UV_FS_LINK); + ASSERT_OK(req->result); link_cb_count++; uv_fs_req_cleanup(req); } static void symlink_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_SYMLINK); - ASSERT(req->result == 0); + ASSERT_EQ(req->fs_type, UV_FS_SYMLINK); + ASSERT_OK(req->result); symlink_cb_count++; uv_fs_req_cleanup(req); } static void readlink_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_READLINK); - ASSERT(req->result == 0); - ASSERT(strcmp(req->ptr, "test_file_symlink2") == 0); + ASSERT_EQ(req->fs_type, UV_FS_READLINK); + ASSERT_OK(req->result); + ASSERT_OK(strcmp(req->ptr, "test_file_symlink2")); readlink_cb_count++; uv_fs_req_cleanup(req); } @@ -221,16 +221,16 @@ static void readlink_cb(uv_fs_t* req) { static void realpath_cb(uv_fs_t* req) { char test_file_abs_buf[PATHMAX]; size_t test_file_abs_size = sizeof(test_file_abs_buf); - ASSERT(req->fs_type == UV_FS_REALPATH); - ASSERT(req->result == 0); + ASSERT_EQ(req->fs_type, UV_FS_REALPATH); + ASSERT_OK(req->result); uv_cwd(test_file_abs_buf, &test_file_abs_size); #ifdef _WIN32 strcat(test_file_abs_buf, "\\test_file"); - ASSERT(stricmp(req->ptr, test_file_abs_buf) == 0); + ASSERT_OK(stricmp(req->ptr, test_file_abs_buf)); #else strcat(test_file_abs_buf, "/test_file"); - ASSERT(strcmp(req->ptr, test_file_abs_buf) == 0); + ASSERT_OK(strcmp(req->ptr, test_file_abs_buf)); #endif realpath_cb_count++; uv_fs_req_cleanup(req); @@ -238,15 +238,15 @@ static void realpath_cb(uv_fs_t* req) { static void access_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_ACCESS); + ASSERT_EQ(req->fs_type, UV_FS_ACCESS); access_cb_count++; uv_fs_req_cleanup(req); } static void fchmod_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_FCHMOD); - ASSERT(req->result == 0); + ASSERT_EQ(req->fs_type, UV_FS_FCHMOD); + ASSERT_OK(req->result); fchmod_cb_count++; uv_fs_req_cleanup(req); check_permission("test_file", *(int*)req->data); @@ -254,8 +254,8 @@ static void fchmod_cb(uv_fs_t* req) { static void chmod_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_CHMOD); - ASSERT(req->result == 0); + ASSERT_EQ(req->fs_type, UV_FS_CHMOD); + ASSERT_OK(req->result); chmod_cb_count++; uv_fs_req_cleanup(req); check_permission("test_file", *(int*)req->data); @@ -263,42 +263,42 @@ static void chmod_cb(uv_fs_t* req) { static void fchown_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_FCHOWN); - ASSERT(req->result == 0); + ASSERT_EQ(req->fs_type, UV_FS_FCHOWN); + ASSERT_OK(req->result); fchown_cb_count++; uv_fs_req_cleanup(req); } static void chown_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_CHOWN); - ASSERT(req->result == 0); + ASSERT_EQ(req->fs_type, UV_FS_CHOWN); + ASSERT_OK(req->result); chown_cb_count++; uv_fs_req_cleanup(req); } static void lchown_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_LCHOWN); - ASSERT(req->result == 0); + ASSERT_EQ(req->fs_type, UV_FS_LCHOWN); + ASSERT_OK(req->result); lchown_cb_count++; uv_fs_req_cleanup(req); } static void chown_root_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_CHOWN); + ASSERT_EQ(req->fs_type, UV_FS_CHOWN); #if defined(_WIN32) || defined(__MSYS__) /* On windows, chown is a no-op and always succeeds. */ - ASSERT(req->result == 0); + ASSERT_OK(req->result); #else /* On unix, chown'ing the root directory is not allowed - * unless you're root, of course. */ if (geteuid() == 0) - ASSERT(req->result == 0); + ASSERT_OK(req->result); else # if defined(__CYGWIN__) /* On Cygwin, uid 0 is invalid (no root). */ - ASSERT(req->result == UV_EINVAL); + ASSERT_EQ(req->result, UV_EINVAL); # elif defined(__PASE__) /* On IBMi PASE, there is no root user. uid 0 is user qsecofr. * User may grant qsecofr's privileges, including changing @@ -306,7 +306,7 @@ static void chown_root_cb(uv_fs_t* req) { */ ASSERT(req->result == 0 || req->result == UV_EPERM); # else - ASSERT(req->result == UV_EPERM); + ASSERT_EQ(req->result, UV_EPERM); # endif #endif chown_cb_count++; @@ -314,18 +314,18 @@ static void chown_root_cb(uv_fs_t* req) { } static void unlink_cb(uv_fs_t* req) { - ASSERT(req == &unlink_req); - ASSERT(req->fs_type == UV_FS_UNLINK); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &unlink_req); + ASSERT_EQ(req->fs_type, UV_FS_UNLINK); + ASSERT_OK(req->result); unlink_cb_count++; uv_fs_req_cleanup(req); } static void fstat_cb(uv_fs_t* req) { uv_stat_t* s = req->ptr; - ASSERT(req->fs_type == UV_FS_FSTAT); - ASSERT(req->result == 0); - ASSERT(s->st_size == sizeof(test_buf)); + ASSERT_EQ(req->fs_type, UV_FS_FSTAT); + ASSERT_OK(req->result); + ASSERT_EQ(s->st_size, sizeof(test_buf)); uv_fs_req_cleanup(req); fstat_cb_count++; } @@ -334,29 +334,29 @@ static void fstat_cb(uv_fs_t* req) { static void statfs_cb(uv_fs_t* req) { uv_statfs_t* stats; - ASSERT(req->fs_type == UV_FS_STATFS); - ASSERT(req->result == 0); + ASSERT_EQ(req->fs_type, UV_FS_STATFS); + ASSERT_OK(req->result); ASSERT_NOT_NULL(req->ptr); stats = req->ptr; #if defined(_WIN32) || defined(__sun) || defined(_AIX) || defined(__MVS__) || \ defined(__OpenBSD__) || defined(__NetBSD__) - ASSERT(stats->f_type == 0); + ASSERT_OK(stats->f_type); #else - ASSERT(stats->f_type > 0); + ASSERT_GT(stats->f_type, 0); #endif - ASSERT(stats->f_bsize > 0); - ASSERT(stats->f_blocks > 0); - ASSERT(stats->f_bfree <= stats->f_blocks); - ASSERT(stats->f_bavail <= stats->f_bfree); + ASSERT_GT(stats->f_bsize, 0); + ASSERT_GT(stats->f_blocks, 0); + ASSERT_LE(stats->f_bfree, stats->f_blocks); + ASSERT_LE(stats->f_bavail, stats->f_bfree); #ifdef _WIN32 - ASSERT(stats->f_files == 0); - ASSERT(stats->f_ffree == 0); + ASSERT_OK(stats->f_files); + ASSERT_OK(stats->f_ffree); #else /* There is no assertion for stats->f_files that makes sense, so ignore it. */ - ASSERT(stats->f_ffree <= stats->f_files); + ASSERT_LE(stats->f_ffree, stats->f_files); #endif uv_fs_req_cleanup(req); ASSERT_NULL(req->ptr); @@ -366,27 +366,27 @@ static void statfs_cb(uv_fs_t* req) { static void close_cb(uv_fs_t* req) { int r; - ASSERT(req == &close_req); - ASSERT(req->fs_type == UV_FS_CLOSE); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &close_req); + ASSERT_EQ(req->fs_type, UV_FS_CLOSE); + ASSERT_OK(req->result); close_cb_count++; uv_fs_req_cleanup(req); if (close_cb_count == 3) { r = uv_fs_unlink(loop, &unlink_req, "test_file2", unlink_cb); - ASSERT(r == 0); + ASSERT_OK(r); } } static void ftruncate_cb(uv_fs_t* req) { int r; - ASSERT(req == &ftruncate_req); - ASSERT(req->fs_type == UV_FS_FTRUNCATE); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &ftruncate_req); + ASSERT_EQ(req->fs_type, UV_FS_FTRUNCATE); + ASSERT_OK(req->result); ftruncate_cb_count++; uv_fs_req_cleanup(req); r = uv_fs_close(loop, &close_req, open_req1.result, close_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static void fail_cb(uv_fs_t* req) { @@ -395,45 +395,45 @@ static void fail_cb(uv_fs_t* req) { static void read_cb(uv_fs_t* req) { int r; - ASSERT(req == &read_req); - ASSERT(req->fs_type == UV_FS_READ); - ASSERT(req->result >= 0); /* FIXME(bnoordhuis) Check if requested size? */ + ASSERT_PTR_EQ(req, &read_req); + ASSERT_EQ(req->fs_type, UV_FS_READ); + ASSERT_GE(req->result, 0); /* FIXME(bnoordhuis) Check if requested size? */ read_cb_count++; uv_fs_req_cleanup(req); if (read_cb_count == 1) { - ASSERT(strcmp(buf, test_buf) == 0); + ASSERT_OK(strcmp(buf, test_buf)); r = uv_fs_ftruncate(loop, &ftruncate_req, open_req1.result, 7, ftruncate_cb); } else { - ASSERT(strcmp(buf, "test-bu") == 0); + ASSERT_OK(strcmp(buf, "test-bu")); r = uv_fs_close(loop, &close_req, open_req1.result, close_cb); } - ASSERT(r == 0); + ASSERT_OK(r); } static void open_cb(uv_fs_t* req) { int r; - ASSERT(req == &open_req1); - ASSERT(req->fs_type == UV_FS_OPEN); + ASSERT_PTR_EQ(req, &open_req1); + ASSERT_EQ(req->fs_type, UV_FS_OPEN); if (req->result < 0) { fprintf(stderr, "async open error: %d\n", (int) req->result); ASSERT(0); } open_cb_count++; ASSERT(req->path); - ASSERT(memcmp(req->path, "test_file2\0", 11) == 0); + ASSERT_OK(memcmp(req->path, "test_file2\0", 11)); uv_fs_req_cleanup(req); memset(buf, 0, sizeof(buf)); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static void open_cb_simple(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_OPEN); + ASSERT_EQ(req->fs_type, UV_FS_OPEN); if (req->result < 0) { fprintf(stderr, "async open error: %d\n", (int) req->result); ASSERT(0); @@ -446,69 +446,69 @@ static void open_cb_simple(uv_fs_t* req) { static void fsync_cb(uv_fs_t* req) { int r; - ASSERT(req == &fsync_req); - ASSERT(req->fs_type == UV_FS_FSYNC); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &fsync_req); + ASSERT_EQ(req->fs_type, UV_FS_FSYNC); + ASSERT_OK(req->result); fsync_cb_count++; uv_fs_req_cleanup(req); r = uv_fs_close(loop, &close_req, open_req1.result, close_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static void fdatasync_cb(uv_fs_t* req) { int r; - ASSERT(req == &fdatasync_req); - ASSERT(req->fs_type == UV_FS_FDATASYNC); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &fdatasync_req); + ASSERT_EQ(req->fs_type, UV_FS_FDATASYNC); + ASSERT_OK(req->result); fdatasync_cb_count++; uv_fs_req_cleanup(req); r = uv_fs_fsync(loop, &fsync_req, open_req1.result, fsync_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static void write_cb(uv_fs_t* req) { int r; - ASSERT(req == &write_req); - ASSERT(req->fs_type == UV_FS_WRITE); - ASSERT(req->result >= 0); /* FIXME(bnoordhuis) Check if requested size? */ + ASSERT_PTR_EQ(req, &write_req); + ASSERT_EQ(req->fs_type, UV_FS_WRITE); + ASSERT_GE(req->result, 0); /* FIXME(bnoordhuis) Check if requested size? */ write_cb_count++; uv_fs_req_cleanup(req); r = uv_fs_fdatasync(loop, &fdatasync_req, open_req1.result, fdatasync_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static void create_cb(uv_fs_t* req) { int r; - ASSERT(req == &open_req1); - ASSERT(req->fs_type == UV_FS_OPEN); - ASSERT(req->result >= 0); + ASSERT_PTR_EQ(req, &open_req1); + ASSERT_EQ(req->fs_type, UV_FS_OPEN); + ASSERT_GE(req->result, 0); create_cb_count++; uv_fs_req_cleanup(req); iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(loop, &write_req, req->result, &iov, 1, -1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static void rename_cb(uv_fs_t* req) { - ASSERT(req == &rename_req); - ASSERT(req->fs_type == UV_FS_RENAME); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &rename_req); + ASSERT_EQ(req->fs_type, UV_FS_RENAME); + ASSERT_OK(req->result); rename_cb_count++; uv_fs_req_cleanup(req); } static void mkdir_cb(uv_fs_t* req) { - ASSERT(req == &mkdir_req); - ASSERT(req->fs_type == UV_FS_MKDIR); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &mkdir_req); + ASSERT_EQ(req->fs_type, UV_FS_MKDIR); + ASSERT_OK(req->result); mkdir_cb_count++; ASSERT(req->path); - ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); + ASSERT_OK(memcmp(req->path, "test_dir\0", 9)); uv_fs_req_cleanup(req); } @@ -516,24 +516,24 @@ static void mkdir_cb(uv_fs_t* req) { static void check_mkdtemp_result(uv_fs_t* req) { int r; - ASSERT(req->fs_type == UV_FS_MKDTEMP); - ASSERT(req->result == 0); + ASSERT_EQ(req->fs_type, UV_FS_MKDTEMP); + ASSERT_OK(req->result); ASSERT(req->path); - ASSERT(strlen(req->path) == 15); - ASSERT(memcmp(req->path, "test_dir_", 9) == 0); - ASSERT(memcmp(req->path + 9, "XXXXXX", 6) != 0); + ASSERT_EQ(15, strlen(req->path)); + ASSERT_OK(memcmp(req->path, "test_dir_", 9)); + ASSERT_NE(0, memcmp(req->path + 9, "XXXXXX", 6)); check_permission(req->path, 0700); /* Check if req->path is actually a directory */ r = uv_fs_stat(NULL, &stat_req, req->path, NULL); - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(((uv_stat_t*)stat_req.ptr)->st_mode & S_IFDIR); uv_fs_req_cleanup(&stat_req); } static void mkdtemp_cb(uv_fs_t* req) { - ASSERT(req == &mkdtemp_req1); + ASSERT_PTR_EQ(req, &mkdtemp_req1); check_mkdtemp_result(req); mkdtemp_cb_count++; } @@ -542,36 +542,36 @@ static void mkdtemp_cb(uv_fs_t* req) { static void check_mkstemp_result(uv_fs_t* req) { int r; - ASSERT(req->fs_type == UV_FS_MKSTEMP); - ASSERT(req->result >= 0); + ASSERT_EQ(req->fs_type, UV_FS_MKSTEMP); + ASSERT_GE(req->result, 0); ASSERT(req->path); - ASSERT(strlen(req->path) == 16); - ASSERT(memcmp(req->path, "test_file_", 10) == 0); - ASSERT(memcmp(req->path + 10, "XXXXXX", 6) != 0); + ASSERT_EQ(16, strlen(req->path)); + ASSERT_OK(memcmp(req->path, "test_file_", 10)); + ASSERT_NE(0, memcmp(req->path + 10, "XXXXXX", 6)); check_permission(req->path, 0600); /* Check if req->path is actually a file */ r = uv_fs_stat(NULL, &stat_req, req->path, NULL); - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(stat_req.statbuf.st_mode & S_IFREG); uv_fs_req_cleanup(&stat_req); } static void mkstemp_cb(uv_fs_t* req) { - ASSERT(req == &mkstemp_req1); + ASSERT_PTR_EQ(req, &mkstemp_req1); check_mkstemp_result(req); mkstemp_cb_count++; } static void rmdir_cb(uv_fs_t* req) { - ASSERT(req == &rmdir_req); - ASSERT(req->fs_type == UV_FS_RMDIR); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &rmdir_req); + ASSERT_EQ(req->fs_type, UV_FS_RMDIR); + ASSERT_OK(req->result); rmdir_cb_count++; ASSERT(req->path); - ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); + ASSERT_OK(memcmp(req->path, "test_dir\0", 9)); uv_fs_req_cleanup(req); } @@ -588,21 +588,21 @@ static void assert_is_file_type(uv_dirent_t dent) { * https://github.com/libuv/libuv/issues/501 */ #if defined(__APPLE__) || defined(_WIN32) - ASSERT(dent.type == UV_DIRENT_FILE); + ASSERT_EQ(dent.type, UV_DIRENT_FILE); #else ASSERT(dent.type == UV_DIRENT_FILE || dent.type == UV_DIRENT_UNKNOWN); #endif #else - ASSERT(dent.type == UV_DIRENT_UNKNOWN); + ASSERT_EQ(dent.type, UV_DIRENT_UNKNOWN); #endif } static void scandir_cb(uv_fs_t* req) { uv_dirent_t dent; - ASSERT(req == &scandir_req); - ASSERT(req->fs_type == UV_FS_SCANDIR); - ASSERT(req->result == 2); + ASSERT_PTR_EQ(req, &scandir_req); + ASSERT_EQ(req->fs_type, UV_FS_SCANDIR); + ASSERT_EQ(2, req->result); ASSERT(req->ptr); while (UV_EOF != uv_fs_scandir_next(req, &dent)) { @@ -611,7 +611,7 @@ static void scandir_cb(uv_fs_t* req) { } scandir_cb_count++; ASSERT(req->path); - ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); + ASSERT_OK(memcmp(req->path, "test_dir\0", 9)); uv_fs_req_cleanup(req); ASSERT(!req->ptr); } @@ -620,11 +620,11 @@ static void scandir_cb(uv_fs_t* req) { static void empty_scandir_cb(uv_fs_t* req) { uv_dirent_t dent; - ASSERT(req == &scandir_req); - ASSERT(req->fs_type == UV_FS_SCANDIR); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &scandir_req); + ASSERT_EQ(req->fs_type, UV_FS_SCANDIR); + ASSERT_OK(req->result); ASSERT_NULL(req->ptr); - ASSERT(UV_EOF == uv_fs_scandir_next(req, &dent)); + ASSERT_EQ(UV_EOF, uv_fs_scandir_next(req, &dent)); uv_fs_req_cleanup(req); scandir_cb_count++; } @@ -632,20 +632,20 @@ static void empty_scandir_cb(uv_fs_t* req) { static void non_existent_scandir_cb(uv_fs_t* req) { uv_dirent_t dent; - ASSERT(req == &scandir_req); - ASSERT(req->fs_type == UV_FS_SCANDIR); - ASSERT(req->result == UV_ENOENT); + ASSERT_PTR_EQ(req, &scandir_req); + ASSERT_EQ(req->fs_type, UV_FS_SCANDIR); + ASSERT_EQ(req->result, UV_ENOENT); ASSERT_NULL(req->ptr); - ASSERT(UV_ENOENT == uv_fs_scandir_next(req, &dent)); + ASSERT_EQ(UV_ENOENT, uv_fs_scandir_next(req, &dent)); uv_fs_req_cleanup(req); scandir_cb_count++; } static void file_scandir_cb(uv_fs_t* req) { - ASSERT(req == &scandir_req); - ASSERT(req->fs_type == UV_FS_SCANDIR); - ASSERT(req->result == UV_ENOTDIR); + ASSERT_PTR_EQ(req, &scandir_req); + ASSERT_EQ(req->fs_type, UV_FS_SCANDIR); + ASSERT_EQ(req->result, UV_ENOTDIR); ASSERT_NULL(req->ptr); uv_fs_req_cleanup(req); scandir_cb_count++; @@ -653,9 +653,9 @@ static void file_scandir_cb(uv_fs_t* req) { static void stat_cb(uv_fs_t* req) { - ASSERT(req == &stat_req); + ASSERT_PTR_EQ(req, &stat_req); ASSERT(req->fs_type == UV_FS_STAT || req->fs_type == UV_FS_LSTAT); - ASSERT(req->result == 0); + ASSERT_OK(req->result); ASSERT(req->ptr); stat_cb_count++; uv_fs_req_cleanup(req); @@ -664,7 +664,7 @@ static void stat_cb(uv_fs_t* req) { static void stat_batch_cb(uv_fs_t* req) { ASSERT(req->fs_type == UV_FS_STAT || req->fs_type == UV_FS_LSTAT); - ASSERT(req->result == 0); + ASSERT_OK(req->result); ASSERT(req->ptr); stat_cb_count++; uv_fs_req_cleanup(req); @@ -673,40 +673,40 @@ static void stat_batch_cb(uv_fs_t* req) { static void sendfile_cb(uv_fs_t* req) { - ASSERT(req == &sendfile_req); - ASSERT(req->fs_type == UV_FS_SENDFILE); - ASSERT(req->result == 65545); + ASSERT_PTR_EQ(req, &sendfile_req); + ASSERT_EQ(req->fs_type, UV_FS_SENDFILE); + ASSERT_EQ(65545, req->result); sendfile_cb_count++; uv_fs_req_cleanup(req); } static void sendfile_nodata_cb(uv_fs_t* req) { - ASSERT(req == &sendfile_req); - ASSERT(req->fs_type == UV_FS_SENDFILE); - ASSERT(req->result == 0); + ASSERT_PTR_EQ(req, &sendfile_req); + ASSERT_EQ(req->fs_type, UV_FS_SENDFILE); + ASSERT_OK(req->result); sendfile_cb_count++; uv_fs_req_cleanup(req); } static void open_noent_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_OPEN); - ASSERT(req->result == UV_ENOENT); + ASSERT_EQ(req->fs_type, UV_FS_OPEN); + ASSERT_EQ(req->result, UV_ENOENT); open_cb_count++; uv_fs_req_cleanup(req); } static void open_nametoolong_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_OPEN); - ASSERT(req->result == UV_ENAMETOOLONG); + ASSERT_EQ(req->fs_type, UV_FS_OPEN); + ASSERT_EQ(req->result, UV_ENAMETOOLONG); open_cb_count++; uv_fs_req_cleanup(req); } static void open_loop_cb(uv_fs_t* req) { - ASSERT(req->fs_type == UV_FS_OPEN); - ASSERT(req->result == UV_ELOOP); + ASSERT_EQ(req->fs_type, UV_FS_OPEN); + ASSERT_EQ(req->result, UV_ELOOP); open_cb_count++; uv_fs_req_cleanup(req); } @@ -719,16 +719,16 @@ TEST_IMPL(fs_file_noent) { loop = uv_default_loop(); r = uv_fs_open(NULL, &req, "does_not_exist", O_RDONLY, 0, NULL); - ASSERT(r == UV_ENOENT); - ASSERT(req.result == UV_ENOENT); + ASSERT_EQ(r, UV_ENOENT); + ASSERT_EQ(req.result, UV_ENOENT); uv_fs_req_cleanup(&req); r = uv_fs_open(loop, &req, "does_not_exist", O_RDONLY, 0, open_noent_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(open_cb_count == 0); + ASSERT_OK(open_cb_count); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(open_cb_count == 1); + ASSERT_EQ(1, open_cb_count); /* TODO add EACCES test */ @@ -747,16 +747,16 @@ TEST_IMPL(fs_file_nametoolong) { name[TOO_LONG_NAME_LENGTH] = 0; r = uv_fs_open(NULL, &req, name, O_RDONLY, 0, NULL); - ASSERT(r == UV_ENAMETOOLONG); - ASSERT(req.result == UV_ENAMETOOLONG); + ASSERT_EQ(r, UV_ENAMETOOLONG); + ASSERT_EQ(req.result, UV_ENAMETOOLONG); uv_fs_req_cleanup(&req); r = uv_fs_open(loop, &req, name, O_RDONLY, 0, open_nametoolong_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(open_cb_count == 0); + ASSERT_OK(open_cb_count); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(open_cb_count == 1); + ASSERT_EQ(1, open_cb_count); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -783,20 +783,20 @@ TEST_IMPL(fs_file_loop) { if (r == UV_ENOENT) return 0; #endif - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); r = uv_fs_open(NULL, &req, "test_symlink", O_RDONLY, 0, NULL); - ASSERT(r == UV_ELOOP); - ASSERT(req.result == UV_ELOOP); + ASSERT_EQ(r, UV_ELOOP); + ASSERT_EQ(req.result, UV_ELOOP); uv_fs_req_cleanup(&req); r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, open_loop_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(open_cb_count == 0); + ASSERT_OK(open_cb_count); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(open_cb_count == 1); + ASSERT_EQ(1, open_cb_count); unlink("test_symlink"); @@ -817,9 +817,9 @@ static void check_utime(const char* path, else r = uv_fs_stat(loop, &req, path, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); - ASSERT_EQ(req.result, 0); + ASSERT_OK(req.result); s = &req.statbuf; if (s->st_atim.tv_nsec == 0 && s->st_mtim.tv_nsec == 0) { @@ -868,9 +868,9 @@ static void check_utime(const char* path, static void utime_cb(uv_fs_t* req) { utime_check_t* c; - ASSERT(req == &utime_req); - ASSERT(req->result == 0); - ASSERT(req->fs_type == UV_FS_UTIME); + ASSERT_PTR_EQ(req, &utime_req); + ASSERT_OK(req->result); + ASSERT_EQ(req->fs_type, UV_FS_UTIME); c = req->data; check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 0); @@ -883,9 +883,9 @@ static void utime_cb(uv_fs_t* req) { static void futime_cb(uv_fs_t* req) { utime_check_t* c; - ASSERT(req == &futime_req); - ASSERT(req->result == 0); - ASSERT(req->fs_type == UV_FS_FUTIME); + ASSERT_PTR_EQ(req, &futime_req); + ASSERT_OK(req->result); + ASSERT_EQ(req->fs_type, UV_FS_FUTIME); c = req->data; check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 0); @@ -898,8 +898,8 @@ static void futime_cb(uv_fs_t* req) { static void lutime_cb(uv_fs_t* req) { utime_check_t* c; - ASSERT(req->result == 0); - ASSERT(req->fs_type == UV_FS_LUTIME); + ASSERT_OK(req->result); + ASSERT_EQ(req->fs_type, UV_FS_LUTIME); c = req->data; check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 1); @@ -920,48 +920,48 @@ TEST_IMPL(fs_file_async) { r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR, create_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(create_cb_count == 1); - ASSERT(write_cb_count == 1); - ASSERT(fsync_cb_count == 1); - ASSERT(fdatasync_cb_count == 1); - ASSERT(close_cb_count == 1); + ASSERT_EQ(1, create_cb_count); + ASSERT_EQ(1, write_cb_count); + ASSERT_EQ(1, fsync_cb_count); + ASSERT_EQ(1, fdatasync_cb_count); + ASSERT_EQ(1, close_cb_count); r = uv_fs_rename(loop, &rename_req, "test_file", "test_file2", rename_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(create_cb_count == 1); - ASSERT(write_cb_count == 1); - ASSERT(close_cb_count == 1); - ASSERT(rename_cb_count == 1); + ASSERT_EQ(1, create_cb_count); + ASSERT_EQ(1, write_cb_count); + ASSERT_EQ(1, close_cb_count); + ASSERT_EQ(1, rename_cb_count); r = uv_fs_open(loop, &open_req1, "test_file2", O_RDWR, 0, open_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(open_cb_count == 1); - ASSERT(read_cb_count == 1); - ASSERT(close_cb_count == 2); - ASSERT(rename_cb_count == 1); - ASSERT(create_cb_count == 1); - ASSERT(write_cb_count == 1); - ASSERT(ftruncate_cb_count == 1); + ASSERT_EQ(1, open_cb_count); + ASSERT_EQ(1, read_cb_count); + ASSERT_EQ(2, close_cb_count); + ASSERT_EQ(1, rename_cb_count); + ASSERT_EQ(1, create_cb_count); + ASSERT_EQ(1, write_cb_count); + ASSERT_EQ(1, ftruncate_cb_count); r = uv_fs_open(loop, &open_req1, "test_file2", O_RDONLY, 0, open_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(open_cb_count == 2); - ASSERT(read_cb_count == 2); - ASSERT(close_cb_count == 3); - ASSERT(rename_cb_count == 1); - ASSERT(unlink_cb_count == 1); - ASSERT(create_cb_count == 1); - ASSERT(write_cb_count == 1); - ASSERT(ftruncate_cb_count == 1); + ASSERT_EQ(2, open_cb_count); + ASSERT_EQ(2, read_cb_count); + ASSERT_EQ(3, close_cb_count); + ASSERT_EQ(1, rename_cb_count); + ASSERT_EQ(1, unlink_cb_count); + ASSERT_EQ(1, create_cb_count); + ASSERT_EQ(1, write_cb_count); + ASSERT_EQ(1, ftruncate_cb_count); /* Cleanup. */ unlink("test_file"); @@ -983,70 +983,70 @@ static void fs_file_sync(int add_flags) { r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r >= 0); - ASSERT(write_req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(write_req.result, 0); uv_fs_req_cleanup(&write_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR | add_flags, 0, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r >= 0); - ASSERT(read_req.result >= 0); - ASSERT(strcmp(buf, test_buf) == 0); + ASSERT_GE(r, 0); + ASSERT_GE(read_req.result, 0); + ASSERT_OK(strcmp(buf, test_buf)); uv_fs_req_cleanup(&read_req); r = uv_fs_ftruncate(NULL, &ftruncate_req, open_req1.result, 7, NULL); - ASSERT(r == 0); - ASSERT(ftruncate_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(ftruncate_req.result); uv_fs_req_cleanup(&ftruncate_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL); - ASSERT(r == 0); - ASSERT(rename_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(rename_req.result); uv_fs_req_cleanup(&rename_req); r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY | add_flags, 0, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); memset(buf, 0, sizeof(buf)); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r >= 0); - ASSERT(read_req.result >= 0); - ASSERT(strcmp(buf, "test-bu") == 0); + ASSERT_GE(r, 0); + ASSERT_GE(read_req.result, 0); + ASSERT_OK(strcmp(buf, "test-bu")); uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); r = uv_fs_unlink(NULL, &unlink_req, "test_file2", NULL); - ASSERT(r == 0); - ASSERT(unlink_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(unlink_req.result); uv_fs_req_cleanup(&unlink_req); /* Cleanup */ @@ -1072,19 +1072,19 @@ static void fs_file_write_null_buffer(int add_flags) { r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); iov = uv_buf_init(NULL, 0); r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r == 0); - ASSERT(write_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(write_req.result); uv_fs_req_cleanup(&write_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); unlink("test_file"); @@ -1110,38 +1110,38 @@ TEST_IMPL(fs_async_dir) { loop = uv_default_loop(); r = uv_fs_mkdir(loop, &mkdir_req, "test_dir", 0755, mkdir_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(mkdir_cb_count == 1); + ASSERT_EQ(1, mkdir_cb_count); /* Create 2 files synchronously. */ r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&close_req); r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&close_req); r = uv_fs_scandir(loop, &scandir_req, "test_dir", 0, scandir_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(scandir_cb_count == 1); + ASSERT_EQ(1, scandir_cb_count); /* sync uv_fs_scandir */ r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL); - ASSERT(r == 2); - ASSERT(scandir_req.result == 2); + ASSERT_EQ(2, r); + ASSERT_EQ(2, scandir_req.result); ASSERT(scandir_req.ptr); while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) { ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0); @@ -1151,37 +1151,37 @@ TEST_IMPL(fs_async_dir) { ASSERT(!scandir_req.ptr); r = uv_fs_stat(loop, &stat_req, "test_dir", stat_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); r = uv_fs_stat(loop, &stat_req, "test_dir/", stat_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); r = uv_fs_lstat(loop, &stat_req, "test_dir", stat_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); r = uv_fs_lstat(loop, &stat_req, "test_dir/", stat_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(stat_cb_count == 4); + ASSERT_EQ(4, stat_cb_count); r = uv_fs_unlink(loop, &unlink_req, "test_dir/file1", unlink_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(unlink_cb_count == 1); + ASSERT_EQ(1, unlink_cb_count); r = uv_fs_unlink(loop, &unlink_req, "test_dir/file2", unlink_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(unlink_cb_count == 2); + ASSERT_EQ(2, unlink_cb_count); r = uv_fs_rmdir(loop, &rmdir_req, "test_dir", rmdir_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(rmdir_cb_count == 1); + ASSERT_EQ(1, rmdir_cb_count); /* Cleanup */ unlink("test_dir/file1"); @@ -1206,58 +1206,58 @@ static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) { unlink("test_file2"); f = open("test_file", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR); - ASSERT(f != -1); + ASSERT_NE(f, -1); if (setup != NULL) setup(f); r = close(f); - ASSERT(r == 0); + ASSERT_OK(r); /* Test starts here. */ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR, 0, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); r = uv_fs_open(NULL, &open_req2, "test_file2", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req2.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req2.result, 0); uv_fs_req_cleanup(&open_req2); r = uv_fs_sendfile(loop, &sendfile_req, open_req2.result, open_req1.result, 1, 131072, cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(sendfile_cb_count == 1); + ASSERT_EQ(1, sendfile_cb_count); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&close_req); r = uv_fs_close(NULL, &close_req, open_req2.result, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&close_req); memset(&s1, 0, sizeof(s1)); memset(&s2, 0, sizeof(s2)); - ASSERT(0 == stat("test_file", &s1)); - ASSERT(0 == stat("test_file2", &s2)); - ASSERT(s2.st_size == expected_size); + ASSERT_OK(stat("test_file", &s1)); + ASSERT_OK(stat("test_file2", &s2)); + ASSERT_EQ(s2.st_size, expected_size); if (expected_size > 0) { ASSERT_UINT64_EQ(s1.st_size, s2.st_size + 1); r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDWR, 0, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); memset(buf1, 0, sizeof(buf1)); iov = uv_buf_init(buf1, sizeof(buf1)); r = uv_fs_read(NULL, &req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); ASSERT_EQ(buf1[0], 'e'); /* 'e' from begin */ uv_fs_req_cleanup(&req); } else { @@ -1274,9 +1274,9 @@ static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) { static void sendfile_setup(int f) { - ASSERT(6 == write(f, "begin\n", 6)); - ASSERT(65542 == lseek(f, 65536, SEEK_CUR)); - ASSERT(4 == write(f, "end\n", 4)); + ASSERT_EQ(6, write(f, "begin\n", 6)); + ASSERT_EQ(65542, lseek(f, 65536, SEEK_CUR)); + ASSERT_EQ(4, write(f, "end\n", 4)); } @@ -1297,18 +1297,18 @@ TEST_IMPL(fs_mkdtemp) { loop = uv_default_loop(); r = uv_fs_mkdtemp(loop, &mkdtemp_req1, path_template, mkdtemp_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(mkdtemp_cb_count == 1); + ASSERT_EQ(1, mkdtemp_cb_count); /* sync mkdtemp */ r = uv_fs_mkdtemp(NULL, &mkdtemp_req2, path_template, NULL); - ASSERT(r == 0); + ASSERT_OK(r); check_mkdtemp_result(&mkdtemp_req2); /* mkdtemp return different values on subsequent calls */ - ASSERT(strcmp(mkdtemp_req1.path, mkdtemp_req2.path) != 0); + ASSERT_NE(0, strcmp(mkdtemp_req1.path, mkdtemp_req2.path)); /* Cleanup */ rmdir(mkdtemp_req1.path); @@ -1330,32 +1330,32 @@ TEST_IMPL(fs_mkstemp) { loop = uv_default_loop(); r = uv_fs_mkstemp(loop, &mkstemp_req1, path_template, mkstemp_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(mkstemp_cb_count == 1); + ASSERT_EQ(1, mkstemp_cb_count); /* sync mkstemp */ r = uv_fs_mkstemp(NULL, &mkstemp_req2, path_template, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); check_mkstemp_result(&mkstemp_req2); /* mkstemp return different values on subsequent calls */ - ASSERT(strcmp(mkstemp_req1.path, mkstemp_req2.path) != 0); + ASSERT_NE(0, strcmp(mkstemp_req1.path, mkstemp_req2.path)); /* invalid template returns EINVAL */ ASSERT_EQ(UV_EINVAL, uv_fs_mkstemp(NULL, &mkstemp_req3, "test_file", NULL)); /* Make sure that path is empty string */ - ASSERT_EQ(0, strlen(mkstemp_req3.path)); + ASSERT_OK(strlen(mkstemp_req3.path)); uv_fs_req_cleanup(&mkstemp_req3); /* We can write to the opened file */ iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &req, mkstemp_req1.result, &iov, 1, -1, NULL); - ASSERT(r == sizeof(test_buf)); - ASSERT(req.result == sizeof(test_buf)); + ASSERT_EQ(r, sizeof(test_buf)); + ASSERT_EQ(req.result, sizeof(test_buf)); uv_fs_req_cleanup(&req); /* Cleanup */ @@ -1365,15 +1365,15 @@ TEST_IMPL(fs_mkstemp) { uv_fs_req_cleanup(&req); fd = uv_fs_open(NULL, &req, mkstemp_req1.path , O_RDONLY, 0, NULL); - ASSERT(fd >= 0); + ASSERT_GE(fd, 0); uv_fs_req_cleanup(&req); memset(buf, 0, sizeof(buf)); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &req, fd, &iov, 1, -1, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); - ASSERT(strcmp(buf, test_buf) == 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); + ASSERT_OK(strcmp(buf, test_buf)); uv_fs_req_cleanup(&req); uv_fs_close(NULL, &req, fd, NULL); @@ -1412,20 +1412,20 @@ TEST_IMPL(fs_fstat) { r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); file = req.result; uv_fs_req_cleanup(&req); #ifndef _WIN32 memset(&t, 0, sizeof(t)); - ASSERT(0 == fstat(file, &t)); - ASSERT(0 == uv_fs_fstat(NULL, &req, file, NULL)); - ASSERT(req.result == 0); + ASSERT_OK(fstat(file, &t)); + ASSERT_OK(uv_fs_fstat(NULL, &req, file, NULL)); + ASSERT_OK(req.result); s = req.ptr; # if defined(__APPLE__) - ASSERT(s->st_birthtim.tv_sec == t.st_birthtimespec.tv_sec); - ASSERT(s->st_birthtim.tv_nsec == t.st_birthtimespec.tv_nsec); + ASSERT_EQ(s->st_birthtim.tv_sec, t.st_birthtimespec.tv_sec); + ASSERT_EQ(s->st_birthtim.tv_nsec, t.st_birthtimespec.tv_nsec); # elif defined(__linux__) /* If statx() is supported, the birth time should be equal to the change time * because we just created the file. On older kernels, it's set to zero. @@ -1439,53 +1439,53 @@ TEST_IMPL(fs_fstat) { iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL); - ASSERT(r == sizeof(test_buf)); - ASSERT(req.result == sizeof(test_buf)); + ASSERT_EQ(r, sizeof(test_buf)); + ASSERT_EQ(req.result, sizeof(test_buf)); uv_fs_req_cleanup(&req); memset(&req.statbuf, 0xaa, sizeof(req.statbuf)); r = uv_fs_fstat(NULL, &req, file, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); s = req.ptr; - ASSERT(s->st_size == sizeof(test_buf)); + ASSERT_EQ(s->st_size, sizeof(test_buf)); #ifndef _WIN32 r = fstat(file, &t); - ASSERT(r == 0); - - ASSERT(s->st_dev == (uint64_t) t.st_dev); - ASSERT(s->st_mode == (uint64_t) t.st_mode); - ASSERT(s->st_nlink == (uint64_t) t.st_nlink); - ASSERT(s->st_uid == (uint64_t) t.st_uid); - ASSERT(s->st_gid == (uint64_t) t.st_gid); - ASSERT(s->st_rdev == (uint64_t) t.st_rdev); - ASSERT(s->st_ino == (uint64_t) t.st_ino); - ASSERT(s->st_size == (uint64_t) t.st_size); - ASSERT(s->st_blksize == (uint64_t) t.st_blksize); - ASSERT(s->st_blocks == (uint64_t) t.st_blocks); + ASSERT_OK(r); + + ASSERT_EQ(s->st_dev, (uint64_t) t.st_dev); + ASSERT_EQ(s->st_mode, (uint64_t) t.st_mode); + ASSERT_EQ(s->st_nlink, (uint64_t) t.st_nlink); + ASSERT_EQ(s->st_uid, (uint64_t) t.st_uid); + ASSERT_EQ(s->st_gid, (uint64_t) t.st_gid); + ASSERT_EQ(s->st_rdev, (uint64_t) t.st_rdev); + ASSERT_EQ(s->st_ino, (uint64_t) t.st_ino); + ASSERT_EQ(s->st_size, (uint64_t) t.st_size); + ASSERT_EQ(s->st_blksize, (uint64_t) t.st_blksize); + ASSERT_EQ(s->st_blocks, (uint64_t) t.st_blocks); #if defined(__APPLE__) - ASSERT(s->st_atim.tv_sec == t.st_atimespec.tv_sec); - ASSERT(s->st_atim.tv_nsec == t.st_atimespec.tv_nsec); - ASSERT(s->st_mtim.tv_sec == t.st_mtimespec.tv_sec); - ASSERT(s->st_mtim.tv_nsec == t.st_mtimespec.tv_nsec); - ASSERT(s->st_ctim.tv_sec == t.st_ctimespec.tv_sec); - ASSERT(s->st_ctim.tv_nsec == t.st_ctimespec.tv_nsec); + ASSERT_EQ(s->st_atim.tv_sec, t.st_atimespec.tv_sec); + ASSERT_EQ(s->st_atim.tv_nsec, t.st_atimespec.tv_nsec); + ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtimespec.tv_sec); + ASSERT_EQ(s->st_mtim.tv_nsec, t.st_mtimespec.tv_nsec); + ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctimespec.tv_sec); + ASSERT_EQ(s->st_ctim.tv_nsec, t.st_ctimespec.tv_nsec); #elif defined(_AIX) || \ defined(__MVS__) - ASSERT(s->st_atim.tv_sec == t.st_atime); - ASSERT(s->st_atim.tv_nsec == 0); - ASSERT(s->st_mtim.tv_sec == t.st_mtime); - ASSERT(s->st_mtim.tv_nsec == 0); - ASSERT(s->st_ctim.tv_sec == t.st_ctime); - ASSERT(s->st_ctim.tv_nsec == 0); + ASSERT_EQ(s->st_atim.tv_sec, t.st_atime); + ASSERT_OK(s->st_atim.tv_nsec); + ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtime); + ASSERT_OK(s->st_mtim.tv_nsec); + ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctime); + ASSERT_OK(s->st_ctim.tv_nsec); #elif defined(__ANDROID__) - ASSERT(s->st_atim.tv_sec == t.st_atime); - ASSERT(s->st_atim.tv_nsec == t.st_atimensec); - ASSERT(s->st_mtim.tv_sec == t.st_mtime); - ASSERT(s->st_mtim.tv_nsec == t.st_mtimensec); - ASSERT(s->st_ctim.tv_sec == t.st_ctime); - ASSERT(s->st_ctim.tv_nsec == t.st_ctimensec); + ASSERT_EQ(s->st_atim.tv_sec, t.st_atime); + ASSERT_EQ(s->st_atim.tv_nsec, t.st_atimensec); + ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtime); + ASSERT_EQ(s->st_mtim.tv_nsec, t.st_mtimensec); + ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctime); + ASSERT_EQ(s->st_ctim.tv_nsec, t.st_ctimensec); #elif defined(__sun) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ @@ -1496,47 +1496,47 @@ TEST_IMPL(fs_fstat) { defined(_SVID_SOURCE) || \ defined(_XOPEN_SOURCE) || \ defined(_DEFAULT_SOURCE) - ASSERT(s->st_atim.tv_sec == t.st_atim.tv_sec); - ASSERT(s->st_atim.tv_nsec == t.st_atim.tv_nsec); - ASSERT(s->st_mtim.tv_sec == t.st_mtim.tv_sec); - ASSERT(s->st_mtim.tv_nsec == t.st_mtim.tv_nsec); - ASSERT(s->st_ctim.tv_sec == t.st_ctim.tv_sec); - ASSERT(s->st_ctim.tv_nsec == t.st_ctim.tv_nsec); + ASSERT_EQ(s->st_atim.tv_sec, t.st_atim.tv_sec); + ASSERT_EQ(s->st_atim.tv_nsec, t.st_atim.tv_nsec); + ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtim.tv_sec); + ASSERT_EQ(s->st_mtim.tv_nsec, t.st_mtim.tv_nsec); + ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctim.tv_sec); + ASSERT_EQ(s->st_ctim.tv_nsec, t.st_ctim.tv_nsec); # if defined(__FreeBSD__) || \ defined(__NetBSD__) - ASSERT(s->st_birthtim.tv_sec == t.st_birthtim.tv_sec); - ASSERT(s->st_birthtim.tv_nsec == t.st_birthtim.tv_nsec); + ASSERT_EQ(s->st_birthtim.tv_sec, t.st_birthtim.tv_sec); + ASSERT_EQ(s->st_birthtim.tv_nsec, t.st_birthtim.tv_nsec); # endif #else - ASSERT(s->st_atim.tv_sec == t.st_atime); - ASSERT(s->st_atim.tv_nsec == 0); - ASSERT(s->st_mtim.tv_sec == t.st_mtime); - ASSERT(s->st_mtim.tv_nsec == 0); - ASSERT(s->st_ctim.tv_sec == t.st_ctime); - ASSERT(s->st_ctim.tv_nsec == 0); + ASSERT_EQ(s->st_atim.tv_sec, t.st_atime); + ASSERT_OK(s->st_atim.tv_nsec); + ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtime); + ASSERT_OK(s->st_mtim.tv_nsec); + ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctime); + ASSERT_OK(s->st_ctim.tv_nsec); #endif #endif #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) - ASSERT(s->st_flags == t.st_flags); - ASSERT(s->st_gen == t.st_gen); + ASSERT_EQ(s->st_flags, t.st_flags); + ASSERT_EQ(s->st_gen, t.st_gen); #else - ASSERT(s->st_flags == 0); - ASSERT(s->st_gen == 0); + ASSERT_OK(s->st_flags); + ASSERT_OK(s->st_gen); #endif uv_fs_req_cleanup(&req); /* Now do the uv_fs_fstat call asynchronously */ r = uv_fs_fstat(loop, &req, file, fstat_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(fstat_cb_count == 1); + ASSERT_EQ(1, fstat_cb_count); r = uv_fs_close(NULL, &req, file, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* @@ -1564,8 +1564,8 @@ TEST_IMPL(fs_fstat_stdio) { for (fd = 0; fd <= 2; ++fd) { res = uv_fs_fstat(NULL, &req, fd, NULL); - ASSERT(res == 0); - ASSERT(req.result == 0); + ASSERT_OK(res); + ASSERT_OK(req.result); #ifdef _WIN32 st = req.ptr; @@ -1573,9 +1573,11 @@ TEST_IMPL(fs_fstat_stdio) { switch (ft) { case UV_TTY: case UV_NAMED_PIPE: - ASSERT(st->st_mode == (ft == UV_TTY ? S_IFCHR : S_IFIFO)); - ASSERT(st->st_nlink == 1); - ASSERT(st->st_rdev == (ft == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE) << 16); + ASSERT_EQ(st->st_mode, (ft == UV_TTY ? S_IFCHR : S_IFIFO)); + ASSERT_EQ(1, st->st_nlink); + ASSERT_EQ(st->st_rdev, + (ft == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE) + << 16); break; default: break; @@ -1603,52 +1605,52 @@ TEST_IMPL(fs_access) { /* File should not exist */ r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL); - ASSERT(r < 0); - ASSERT(req.result < 0); + ASSERT_LT(r, 0); + ASSERT_LT(req.result, 0); uv_fs_req_cleanup(&req); /* File should not exist */ r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(access_cb_count == 1); + ASSERT_EQ(1, access_cb_count); access_cb_count = 0; /* reset for the next test */ /* Create file */ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); file = req.result; uv_fs_req_cleanup(&req); /* File should exist */ r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* File should exist */ r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(access_cb_count == 1); + ASSERT_EQ(1, access_cb_count); access_cb_count = 0; /* reset for the next test */ /* Close file */ r = uv_fs_close(NULL, &req, file, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* Directory access */ r = uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); r = uv_fs_access(NULL, &req, "test_dir", W_OK, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* @@ -1678,22 +1680,22 @@ TEST_IMPL(fs_chmod) { r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); file = req.result; uv_fs_req_cleanup(&req); iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL); - ASSERT(r == sizeof(test_buf)); - ASSERT(req.result == sizeof(test_buf)); + ASSERT_EQ(r, sizeof(test_buf)); + ASSERT_EQ(req.result, sizeof(test_buf)); uv_fs_req_cleanup(&req); #ifndef _WIN32 /* Make the file write-only */ r = uv_fs_chmod(NULL, &req, "test_file", 0200, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); check_permission("test_file", 0200); @@ -1701,16 +1703,16 @@ TEST_IMPL(fs_chmod) { /* Make the file read-only */ r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); check_permission("test_file", 0400); /* Make the file read+write with sync uv_fs_fchmod */ r = uv_fs_fchmod(NULL, &req, file, 0600, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); check_permission("test_file", 0600); @@ -1722,9 +1724,9 @@ TEST_IMPL(fs_chmod) { req.data = &mode; } r = uv_fs_chmod(loop, &req, "test_file", 0200, chmod_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(chmod_cb_count == 1); + ASSERT_EQ(1, chmod_cb_count); chmod_cb_count = 0; /* reset for the next test */ #endif @@ -1734,9 +1736,9 @@ TEST_IMPL(fs_chmod) { req.data = &mode; } r = uv_fs_chmod(loop, &req, "test_file", 0400, chmod_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(chmod_cb_count == 1); + ASSERT_EQ(1, chmod_cb_count); /* async fchmod */ { @@ -1744,9 +1746,9 @@ TEST_IMPL(fs_chmod) { req.data = &mode; } r = uv_fs_fchmod(loop, &req, file, 0600, fchmod_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(fchmod_cb_count == 1); + ASSERT_EQ(1, fchmod_cb_count); uv_fs_close(loop, &req, file, NULL); @@ -1780,31 +1782,31 @@ TEST_IMPL(fs_unlink_readonly) { O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); file = req.result; uv_fs_req_cleanup(&req); iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL); - ASSERT(r == sizeof(test_buf)); - ASSERT(req.result == sizeof(test_buf)); + ASSERT_EQ(r, sizeof(test_buf)); + ASSERT_EQ(req.result, sizeof(test_buf)); uv_fs_req_cleanup(&req); uv_fs_close(loop, &req, file, NULL); /* Make the file read-only */ r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); check_permission("test_file", 0400); /* Try to unlink the file */ r = uv_fs_unlink(NULL, &req, "test_file", NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* @@ -1839,30 +1841,30 @@ TEST_IMPL(fs_unlink_archive_readonly) { O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); file = req.result; uv_fs_req_cleanup(&req); iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL); - ASSERT(r == sizeof(test_buf)); - ASSERT(req.result == sizeof(test_buf)); + ASSERT_EQ(r, sizeof(test_buf)); + ASSERT_EQ(req.result, sizeof(test_buf)); uv_fs_req_cleanup(&req); uv_fs_close(loop, &req, file, NULL); /* Make the file read-only and clear archive flag */ r = SetFileAttributes("test_file", FILE_ATTRIBUTE_READONLY); - ASSERT(r != 0); + ASSERT(r); uv_fs_req_cleanup(&req); check_permission("test_file", 0400); /* Try to unlink the file */ r = uv_fs_unlink(NULL, &req, "test_file", NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* @@ -1894,69 +1896,69 @@ TEST_IMPL(fs_chown) { r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); file = req.result; uv_fs_req_cleanup(&req); /* sync chown */ r = uv_fs_chown(NULL, &req, "test_file", -1, -1, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* sync fchown */ r = uv_fs_fchown(NULL, &req, file, -1, -1, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* async chown */ r = uv_fs_chown(loop, &req, "test_file", -1, -1, chown_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(chown_cb_count == 1); + ASSERT_EQ(1, chown_cb_count); #ifndef __MVS__ /* chown to root (fail) */ chown_cb_count = 0; r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(chown_cb_count == 1); + ASSERT_EQ(1, chown_cb_count); #endif /* async fchown */ r = uv_fs_fchown(loop, &req, file, -1, -1, fchown_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(fchown_cb_count == 1); + ASSERT_EQ(1, fchown_cb_count); #ifndef __HAIKU__ /* Haiku doesn't support hardlink */ /* sync link */ r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* sync lchown */ r = uv_fs_lchown(NULL, &req, "test_file_link", -1, -1, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* async lchown */ r = uv_fs_lchown(loop, &req, "test_file_link", -1, -1, lchown_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(lchown_cb_count == 1); + ASSERT_EQ(1, lchown_cb_count); #endif /* Close file */ r = uv_fs_close(NULL, &req, file, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* @@ -1989,58 +1991,58 @@ TEST_IMPL(fs_link) { r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); file = req.result; uv_fs_req_cleanup(&req); iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL); - ASSERT(r == sizeof(test_buf)); - ASSERT(req.result == sizeof(test_buf)); + ASSERT_EQ(r, sizeof(test_buf)); + ASSERT_EQ(req.result, sizeof(test_buf)); uv_fs_req_cleanup(&req); uv_fs_close(loop, &req, file, NULL); /* sync link */ r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); r = uv_fs_open(NULL, &req, "test_file_link", O_RDWR, 0, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); link = req.result; uv_fs_req_cleanup(&req); memset(buf, 0, sizeof(buf)); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); - ASSERT(strcmp(buf, test_buf) == 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); + ASSERT_OK(strcmp(buf, test_buf)); close(link); /* async link */ r = uv_fs_link(loop, &req, "test_file", "test_file_link2", link_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(link_cb_count == 1); + ASSERT_EQ(1, link_cb_count); r = uv_fs_open(NULL, &req, "test_file_link2", O_RDWR, 0, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); link = req.result; uv_fs_req_cleanup(&req); memset(buf, 0, sizeof(buf)); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); - ASSERT(strcmp(buf, test_buf) == 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); + ASSERT_OK(strcmp(buf, test_buf)); uv_fs_close(loop, &req, link, NULL); @@ -2066,16 +2068,16 @@ TEST_IMPL(fs_readlink) { uv_fs_t req; loop = uv_default_loop(); - ASSERT(0 == uv_fs_readlink(loop, &req, "no_such_file", dummy_cb)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(dummy_cb_count == 1); + ASSERT_OK(uv_fs_readlink(loop, &req, "no_such_file", dummy_cb)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, dummy_cb_count); ASSERT_NULL(req.ptr); - ASSERT(req.result == UV_ENOENT); + ASSERT_EQ(req.result, UV_ENOENT); uv_fs_req_cleanup(&req); - ASSERT(UV_ENOENT == uv_fs_readlink(NULL, &req, "no_such_file", NULL)); + ASSERT_EQ(UV_ENOENT, uv_fs_readlink(NULL, &req, "no_such_file", NULL)); ASSERT_NULL(req.ptr); - ASSERT(req.result == UV_ENOENT); + ASSERT_EQ(req.result, UV_ENOENT); uv_fs_req_cleanup(&req); } @@ -2096,8 +2098,8 @@ TEST_IMPL(fs_readlink) { uv_fs_req_cleanup(&req); r = uv_fs_close(NULL, &req, file, NULL); - ASSERT_EQ(r, 0); - ASSERT_EQ(req.result, 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* Test */ @@ -2118,16 +2120,16 @@ TEST_IMPL(fs_realpath) { uv_fs_t req; loop = uv_default_loop(); - ASSERT(0 == uv_fs_realpath(loop, &req, "no_such_file", dummy_cb)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(dummy_cb_count == 1); + ASSERT_OK(uv_fs_realpath(loop, &req, "no_such_file", dummy_cb)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, dummy_cb_count); ASSERT_NULL(req.ptr); - ASSERT(req.result == UV_ENOENT); + ASSERT_EQ(req.result, UV_ENOENT); uv_fs_req_cleanup(&req); - ASSERT(UV_ENOENT == uv_fs_realpath(NULL, &req, "no_such_file", NULL)); + ASSERT_EQ(UV_ENOENT, uv_fs_realpath(NULL, &req, "no_such_file", NULL)); ASSERT_NULL(req.ptr); - ASSERT(req.result == UV_ENOENT); + ASSERT_EQ(req.result, UV_ENOENT); uv_fs_req_cleanup(&req); MAKE_VALGRIND_HAPPY(loop); @@ -2162,15 +2164,15 @@ TEST_IMPL(fs_symlink) { r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); file = req.result; uv_fs_req_cleanup(&req); iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL); - ASSERT(r == sizeof(test_buf)); - ASSERT(req.result == sizeof(test_buf)); + ASSERT_EQ(r, sizeof(test_buf)); + ASSERT_EQ(req.result, sizeof(test_buf)); uv_fs_req_cleanup(&req); uv_fs_close(loop, &req, file, NULL); @@ -2194,22 +2196,22 @@ TEST_IMPL(fs_symlink) { } } #endif - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); r = uv_fs_open(NULL, &req, "test_file_symlink", O_RDWR, 0, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); link = req.result; uv_fs_req_cleanup(&req); memset(buf, 0, sizeof(buf)); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); - ASSERT(strcmp(buf, test_buf) == 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); + ASSERT_OK(strcmp(buf, test_buf)); uv_fs_close(loop, &req, link, NULL); @@ -2219,7 +2221,7 @@ TEST_IMPL(fs_symlink) { "test_file_symlink_symlink", 0, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); #if defined(__MSYS__) @@ -2227,16 +2229,16 @@ TEST_IMPL(fs_symlink) { #endif r = uv_fs_readlink(NULL, &req, "test_file_symlink_symlink", NULL); - ASSERT(r == 0); - ASSERT(strcmp(req.ptr, "test_file_symlink") == 0); + ASSERT_OK(r); + ASSERT_OK(strcmp(req.ptr, "test_file_symlink")); uv_fs_req_cleanup(&req); r = uv_fs_realpath(NULL, &req, "test_file_symlink_symlink", NULL); - ASSERT(r == 0); + ASSERT_OK(r); #ifdef _WIN32 - ASSERT(stricmp(req.ptr, test_file_abs_buf) == 0); + ASSERT_OK(stricmp(req.ptr, test_file_abs_buf)); #else - ASSERT(strcmp(req.ptr, test_file_abs_buf) == 0); + ASSERT_OK(strcmp(req.ptr, test_file_abs_buf)); #endif uv_fs_req_cleanup(&req); @@ -2247,22 +2249,22 @@ TEST_IMPL(fs_symlink) { "test_file_symlink2", 0, symlink_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(symlink_cb_count == 1); + ASSERT_EQ(1, symlink_cb_count); r = uv_fs_open(NULL, &req, "test_file_symlink2", O_RDWR, 0, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); link = req.result; uv_fs_req_cleanup(&req); memset(buf, 0, sizeof(buf)); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); - ASSERT(strcmp(buf, test_buf) == 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); + ASSERT_OK(strcmp(buf, test_buf)); uv_fs_close(loop, &req, link, NULL); @@ -2272,18 +2274,18 @@ TEST_IMPL(fs_symlink) { "test_file_symlink2_symlink", 0, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); r = uv_fs_readlink(loop, &req, "test_file_symlink2_symlink", readlink_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(readlink_cb_count == 1); + ASSERT_EQ(1, readlink_cb_count); r = uv_fs_realpath(loop, &req, "test_file", realpath_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(realpath_cb_count == 1); + ASSERT_EQ(1, realpath_cb_count); /* * Run the loop just to check we don't have make any extraneous uv_ref() @@ -2344,71 +2346,71 @@ int test_symlink_dir_impl(int type) { "creation of directory symlinks"); } fprintf(stderr, "r == %i\n", r); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); r = uv_fs_stat(NULL, &req, "test_dir_symlink", NULL); - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFDIR); uv_fs_req_cleanup(&req); r = uv_fs_lstat(NULL, &req, "test_dir_symlink", NULL); - ASSERT(r == 0); + ASSERT_OK(r); #if defined(__MSYS__) RETURN_SKIP("symlink reading is not supported on MSYS2"); #endif ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFLNK); #ifdef _WIN32 - ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen(test_dir + 4)); + ASSERT_EQ(((uv_stat_t*)req.ptr)->st_size, strlen(test_dir + 4)); #else # ifdef __PASE__ /* On IBMi PASE, st_size returns the length of the symlink itself. */ - ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen("test_dir_symlink")); + ASSERT_EQ(((uv_stat_t*)req.ptr)->st_size, strlen("test_dir_symlink")); # else - ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen(test_dir)); + ASSERT_EQ(((uv_stat_t*)req.ptr)->st_size, strlen(test_dir)); # endif #endif uv_fs_req_cleanup(&req); r = uv_fs_readlink(NULL, &req, "test_dir_symlink", NULL); - ASSERT(r == 0); + ASSERT_OK(r); #ifdef _WIN32 - ASSERT(strcmp(req.ptr, test_dir + 4) == 0); + ASSERT_OK(strcmp(req.ptr, test_dir + 4)); #else - ASSERT(strcmp(req.ptr, test_dir) == 0); + ASSERT_OK(strcmp(req.ptr, test_dir)); #endif uv_fs_req_cleanup(&req); r = uv_fs_realpath(NULL, &req, "test_dir_symlink", NULL); - ASSERT(r == 0); + ASSERT_OK(r); #ifdef _WIN32 - ASSERT(strlen(req.ptr) == test_dir_abs_size - 5); - ASSERT(strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5) == 0); + ASSERT_EQ(strlen(req.ptr), test_dir_abs_size - 5); + ASSERT_OK(strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5)); #else - ASSERT(strcmp(req.ptr, test_dir_abs_buf) == 0); + ASSERT_OK(strcmp(req.ptr, test_dir_abs_buf)); #endif uv_fs_req_cleanup(&req); r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&close_req); r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&close_req); r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL); - ASSERT(r == 2); - ASSERT(scandir_req.result == 2); + ASSERT_EQ(2, r); + ASSERT_EQ(2, scandir_req.result); ASSERT(scandir_req.ptr); while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) { ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0); @@ -2419,16 +2421,16 @@ int test_symlink_dir_impl(int type) { /* unlink will remove the directory symlink */ r = uv_fs_unlink(NULL, &req, "test_dir_symlink", NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL); - ASSERT(r == UV_ENOENT); + ASSERT_EQ(r, UV_ENOENT); uv_fs_req_cleanup(&scandir_req); r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL); - ASSERT(r == 2); - ASSERT(scandir_req.result == 2); + ASSERT_EQ(2, r); + ASSERT_EQ(2, scandir_req.result); ASSERT(scandir_req.ptr); while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) { ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0); @@ -2481,7 +2483,7 @@ TEST_IMPL(fs_non_symlink_reparse_point) { FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); - ASSERT(file_handle != INVALID_HANDLE_VALUE); + ASSERT_NE(file_handle, INVALID_HANDLE_VALUE); memset(&reparse_buffer, 0, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE); reparse_buffer.ReparseTag = REPARSE_TAG; @@ -2496,7 +2498,7 @@ TEST_IMPL(fs_non_symlink_reparse_point) { 0, &bytes_returned, NULL); - ASSERT(r != 0); + ASSERT(r); CloseHandle(file_handle); @@ -2510,11 +2512,11 @@ TEST_IMPL(fs_non_symlink_reparse_point) { shared via SMB as "Macintosh HD". r = uv_fs_stat(NULL, &req, "\\\\\\Macintosh HD\\.DS_Store", NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); r = uv_fs_lstat(NULL, &req, "\\\\\\Macintosh HD\\.DS_Store", NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); */ @@ -2525,25 +2527,25 @@ TEST_IMPL(fs_non_symlink_reparse_point) { the scope of this test. r = uv_fs_stat(NULL, &req, "test_dir/test_file", NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); r = uv_fs_lstat(NULL, &req, "test_dir/test_file", NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); */ r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL); - ASSERT(r == 1); - ASSERT(scandir_req.result == 1); + ASSERT_EQ(1, r); + ASSERT_EQ(1, scandir_req.result); ASSERT(scandir_req.ptr); while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) { - ASSERT(strcmp(dent.name, "test_file") == 0); + ASSERT_OK(strcmp(dent.name, "test_file")); /* uv_fs_scandir incorrectly identifies non-symlink reparse points as links because it doesn't open the file and verify the reparse point tag. The PowerShell Get-ChildItem command shares this behavior, so it's reasonable to leave it as is. */ - ASSERT(dent.type == UV_DIRENT_LINK); + ASSERT_EQ(dent.type, UV_DIRENT_LINK); } uv_fs_req_cleanup(&scandir_req); ASSERT(!scandir_req.ptr); @@ -2575,7 +2577,7 @@ TEST_IMPL(fs_lstat_windows_store_apps) { MAKE_VALGRIND_HAPPY(loop); return TEST_SKIP; } - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = snprintf(windowsapps_path, sizeof(localappdata), "%s\\Microsoft\\WindowsApps", @@ -2601,7 +2603,7 @@ TEST_IMPL(fs_lstat_windows_store_apps) { dirent.name) < 0) { continue; } - ASSERT_EQ(uv_fs_lstat(loop, &stat_req, file_path, NULL), 0); + ASSERT_OK(uv_fs_lstat(loop, &stat_req, file_path, NULL)); } MAKE_VALGRIND_HAPPY(loop); return 0; @@ -2621,16 +2623,16 @@ TEST_IMPL(fs_utime) { loop = uv_default_loop(); unlink(path); r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); uv_fs_req_cleanup(&req); uv_fs_close(loop, &req, r, NULL); atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */ r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); check_utime(path, atime, mtime, /* test_lutime */ 0); @@ -2643,9 +2645,9 @@ TEST_IMPL(fs_utime) { /* async utime */ utime_req.data = &checkme; r = uv_fs_utime(loop, &utime_req, path, atime, mtime, utime_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(utime_cb_count == 1); + ASSERT_EQ(1, utime_cb_count); /* Cleanup. */ unlink(path); @@ -2668,7 +2670,7 @@ TEST_IMPL(fs_utime_round) { ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); uv_fs_req_cleanup(&req); - ASSERT_EQ(0, uv_fs_close(loop, &req, r, NULL)); + ASSERT_OK(uv_fs_close(loop, &req, r, NULL)); atime = mtime = -14245440.25; /* 1969-07-20T02:56:00.25Z */ @@ -2683,8 +2685,8 @@ TEST_IMPL(fs_utime_round) { RETURN_SKIP("utime on some OS (z/OS, IBM i PASE, AIX) or filesystems may reject pre-epoch timestamps"); } #endif - ASSERT_EQ(0, r); - ASSERT_EQ(0, req.result); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); check_utime(path, atime, mtime, /* test_lutime */ 0); unlink(path); @@ -2699,26 +2701,26 @@ TEST_IMPL(fs_stat_root) { int r; r = uv_fs_stat(NULL, &stat_req, "\\", NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_stat(NULL, &stat_req, "..\\..\\..\\..\\..\\..\\..", NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_stat(NULL, &stat_req, "..", NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_stat(NULL, &stat_req, "..\\", NULL); - ASSERT(r == 0); + ASSERT_OK(r); /* stats the current directory on c: */ r = uv_fs_stat(NULL, &stat_req, "c:", NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_stat(NULL, &stat_req, "c:\\", NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_stat(NULL, &stat_req, "\\\\?\\C:\\", NULL); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -2742,26 +2744,26 @@ TEST_IMPL(fs_futime) { loop = uv_default_loop(); unlink(path); r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); uv_fs_req_cleanup(&req); uv_fs_close(loop, &req, r, NULL); atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */ r = uv_fs_open(NULL, &req, path, O_RDWR, 0, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); file = req.result; /* FIXME probably not how it's supposed to be used */ uv_fs_req_cleanup(&req); r = uv_fs_futime(NULL, &req, file, atime, mtime, NULL); #if defined(__CYGWIN__) || defined(__MSYS__) - ASSERT(r == UV_ENOSYS); + ASSERT_EQ(r, UV_ENOSYS); RETURN_SKIP("futime not supported on Cygwin"); #else - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); #endif uv_fs_req_cleanup(&req); @@ -2776,9 +2778,9 @@ TEST_IMPL(fs_futime) { /* async futime */ futime_req.data = &checkme; r = uv_fs_futime(loop, &futime_req, file, atime, mtime, futime_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(futime_cb_count == 1); + ASSERT_EQ(1, futime_cb_count); /* Cleanup. */ unlink(path); @@ -2819,8 +2821,8 @@ TEST_IMPL(fs_lutime) { "Symlink creation requires elevated console (with admin rights)"); } #endif - ASSERT_EQ(s, 0); - ASSERT_EQ(req.result, 0); + ASSERT_OK(s); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); /* Test the synchronous version. */ @@ -2837,9 +2839,9 @@ TEST_IMPL(fs_lutime) { ASSERT_EQ(r, UV_ENOSYS); RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1"); #endif - ASSERT_EQ(r, 0); + ASSERT_OK(r); lutime_cb(&req); - ASSERT_EQ(lutime_cb_count, 1); + ASSERT_EQ(1, lutime_cb_count); /* Test the asynchronous version. */ atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */ @@ -2849,9 +2851,9 @@ TEST_IMPL(fs_lutime) { checkme.path = symlink_path; r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT_EQ(lutime_cb_count, 2); + ASSERT_EQ(2, lutime_cb_count); /* Cleanup. */ unlink(path); @@ -2869,8 +2871,8 @@ TEST_IMPL(fs_stat_missing_path) { loop = uv_default_loop(); r = uv_fs_stat(NULL, &req, "non_existent_file", NULL); - ASSERT(r == UV_ENOENT); - ASSERT(req.result == UV_ENOENT); + ASSERT_EQ(r, UV_ENOENT); + ASSERT_EQ(req.result, UV_ENOENT); uv_fs_req_cleanup(&req); MAKE_VALGRIND_HAPPY(loop); @@ -2894,18 +2896,18 @@ TEST_IMPL(fs_scandir_empty_dir) { memset(&req, 0xdb, sizeof(req)); r = uv_fs_scandir(NULL, &req, path, 0, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); ASSERT_NULL(req.ptr); - ASSERT(UV_EOF == uv_fs_scandir_next(&req, &dent)); + ASSERT_EQ(UV_EOF, uv_fs_scandir_next(&req, &dent)); uv_fs_req_cleanup(&req); r = uv_fs_scandir(loop, &scandir_req, path, 0, empty_scandir_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(scandir_cb_count == 0); + ASSERT_OK(scandir_cb_count); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(scandir_cb_count == 1); + ASSERT_EQ(1, scandir_cb_count); uv_fs_rmdir(NULL, &req, path, NULL); uv_fs_req_cleanup(&req); @@ -2931,18 +2933,18 @@ TEST_IMPL(fs_scandir_non_existent_dir) { memset(&req, 0xdb, sizeof(req)); r = uv_fs_scandir(NULL, &req, path, 0, NULL); - ASSERT(r == UV_ENOENT); - ASSERT(req.result == UV_ENOENT); + ASSERT_EQ(r, UV_ENOENT); + ASSERT_EQ(req.result, UV_ENOENT); ASSERT_NULL(req.ptr); - ASSERT(UV_ENOENT == uv_fs_scandir_next(&req, &dent)); + ASSERT_EQ(UV_ENOENT, uv_fs_scandir_next(&req, &dent)); uv_fs_req_cleanup(&req); r = uv_fs_scandir(loop, &scandir_req, path, 0, non_existent_scandir_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(scandir_cb_count == 0); + ASSERT_OK(scandir_cb_count); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(scandir_cb_count == 1); + ASSERT_EQ(1, scandir_cb_count); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -2956,15 +2958,15 @@ TEST_IMPL(fs_scandir_file) { loop = uv_default_loop(); r = uv_fs_scandir(NULL, &scandir_req, path, 0, NULL); - ASSERT(r == UV_ENOTDIR); + ASSERT_EQ(r, UV_ENOTDIR); uv_fs_req_cleanup(&scandir_req); r = uv_fs_scandir(loop, &scandir_req, path, 0, file_scandir_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(scandir_cb_count == 0); + ASSERT_OK(scandir_cb_count); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(scandir_cb_count == 1); + ASSERT_EQ(1, scandir_cb_count); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -2998,21 +3000,21 @@ TEST_IMPL(fs_open_dir) { loop = uv_default_loop(); r = uv_fs_open(NULL, &req, path, O_RDONLY, 0, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); ASSERT_NULL(req.ptr); file = r; uv_fs_req_cleanup(&req); r = uv_fs_close(NULL, &req, file, NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_open(loop, &req, path, O_RDONLY, 0, open_cb_simple); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(open_cb_count == 0); + ASSERT_OK(open_cb_count); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(open_cb_count == 1); + ASSERT_EQ(1, open_cb_count); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -3029,57 +3031,57 @@ static void fs_file_open_append(int add_flags) { r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r >= 0); - ASSERT(write_req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(write_req.result, 0); uv_fs_req_cleanup(&write_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR | O_APPEND | add_flags, 0, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r >= 0); - ASSERT(write_req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(write_req.result, 0); uv_fs_req_cleanup(&write_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL); printf("read = %d\n", r); - ASSERT(r == 26); - ASSERT(read_req.result == 26); - ASSERT(memcmp(buf, - "test-buffer\n\0test-buffer\n\0", - sizeof("test-buffer\n\0test-buffer\n\0") - 1) == 0); + ASSERT_EQ(26, r); + ASSERT_EQ(26, read_req.result); + ASSERT_OK(memcmp(buf, + "test-buffer\n\0test-buffer\n\0", + sizeof("test-buffer\n\0test-buffer\n\0") - 1)); uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* Cleanup */ @@ -3105,53 +3107,53 @@ TEST_IMPL(fs_rename_to_existing_file) { r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r >= 0); - ASSERT(write_req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(write_req.result, 0); uv_fs_req_cleanup(&write_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); r = uv_fs_open(NULL, &open_req1, "test_file2", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + 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(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL); - ASSERT(r == 0); - ASSERT(rename_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(rename_req.result); uv_fs_req_cleanup(&rename_req); r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY, 0, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); memset(buf, 0, sizeof(buf)); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r >= 0); - ASSERT(read_req.result >= 0); - ASSERT(strcmp(buf, test_buf) == 0); + ASSERT_GE(r, 0); + ASSERT_GE(read_req.result, 0); + ASSERT_OK(strcmp(buf, test_buf)); uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* Cleanup */ @@ -3167,49 +3169,49 @@ static void fs_read_bufs(int add_flags) { char scratch[768]; uv_buf_t bufs[4]; - ASSERT(0 <= uv_fs_open(NULL, &open_req1, - "test/fixtures/lorem_ipsum.txt", - O_RDONLY | add_flags, 0, NULL)); - ASSERT(open_req1.result >= 0); + ASSERT_LE(0, uv_fs_open(NULL, &open_req1, + "test/fixtures/lorem_ipsum.txt", + O_RDONLY | add_flags, 0, NULL)); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); - ASSERT(UV_EINVAL == uv_fs_read(NULL, &read_req, open_req1.result, - NULL, 0, 0, NULL)); - ASSERT(UV_EINVAL == uv_fs_read(NULL, &read_req, open_req1.result, - NULL, 1, 0, NULL)); - ASSERT(UV_EINVAL == uv_fs_read(NULL, &read_req, open_req1.result, - bufs, 0, 0, NULL)); + ASSERT_EQ(UV_EINVAL, uv_fs_read(NULL, &read_req, open_req1.result, + NULL, 0, 0, NULL)); + ASSERT_EQ(UV_EINVAL, uv_fs_read(NULL, &read_req, open_req1.result, + NULL, 1, 0, NULL)); + ASSERT_EQ(UV_EINVAL, uv_fs_read(NULL, &read_req, open_req1.result, + bufs, 0, 0, NULL)); bufs[0] = uv_buf_init(scratch + 0, 256); bufs[1] = uv_buf_init(scratch + 256, 256); bufs[2] = uv_buf_init(scratch + 512, 128); bufs[3] = uv_buf_init(scratch + 640, 128); - ASSERT(446 == uv_fs_read(NULL, - &read_req, - open_req1.result, - bufs + 0, - 2, /* 2x 256 bytes. */ - 0, /* Positional read. */ - NULL)); - ASSERT(read_req.result == 446); + ASSERT_EQ(446, uv_fs_read(NULL, + &read_req, + open_req1.result, + bufs + 0, + 2, /* 2x 256 bytes. */ + 0, /* Positional read. */ + NULL)); + ASSERT_EQ(446, read_req.result); uv_fs_req_cleanup(&read_req); - ASSERT(190 == uv_fs_read(NULL, - &read_req, - open_req1.result, - bufs + 2, - 2, /* 2x 128 bytes. */ - 256, /* Positional read. */ - NULL)); - ASSERT(read_req.result == /* 446 - 256 */ 190); + ASSERT_EQ(190, uv_fs_read(NULL, + &read_req, + open_req1.result, + bufs + 2, + 2, /* 2x 128 bytes. */ + 256, /* Positional read. */ + NULL)); + ASSERT_EQ(read_req.result, /* 446 - 256 */ 190); uv_fs_req_cleanup(&read_req); - ASSERT(0 == memcmp(bufs[1].base + 0, bufs[2].base, 128)); - ASSERT(0 == memcmp(bufs[1].base + 128, bufs[3].base, 190 - 128)); + ASSERT_OK(memcmp(bufs[1].base + 0, bufs[2].base, 128)); + ASSERT_OK(memcmp(bufs[1].base + 128, bufs[3].base, 190 - 128)); - ASSERT(0 == uv_fs_close(NULL, &close_req, open_req1.result, NULL)); - ASSERT(close_req.result == 0); + ASSERT_OK(uv_fs_close(NULL, &close_req, open_req1.result, NULL)); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); } TEST_IMPL(fs_read_bufs) { @@ -3234,45 +3236,45 @@ static void fs_read_file_eof(int add_flags) { r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r >= 0); - ASSERT(write_req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(write_req.result, 0); uv_fs_req_cleanup(&write_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); memset(buf, 0, sizeof(buf)); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r >= 0); - ASSERT(read_req.result >= 0); - ASSERT(strcmp(buf, test_buf) == 0); + ASSERT_GE(r, 0); + ASSERT_GE(read_req.result, 0); + ASSERT_OK(strcmp(buf, test_buf)); uv_fs_req_cleanup(&read_req); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, read_req.result, NULL); - ASSERT(r == 0); - ASSERT(read_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(read_req.result); uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* Cleanup */ @@ -3298,26 +3300,26 @@ static void fs_write_multiple_bufs(int add_flags) { r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); iovs[0] = uv_buf_init(test_buf, sizeof(test_buf)); iovs[1] = uv_buf_init(test_buf2, sizeof(test_buf2)); r = uv_fs_write(NULL, &write_req, open_req1.result, iovs, 2, 0, NULL); - ASSERT(r >= 0); - ASSERT(write_req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(write_req.result, 0); uv_fs_req_cleanup(&write_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); memset(buf, 0, sizeof(buf)); @@ -3325,48 +3327,48 @@ static void fs_write_multiple_bufs(int add_flags) { /* Read the strings back to separate buffers. */ iovs[0] = uv_buf_init(buf, sizeof(test_buf)); iovs[1] = uv_buf_init(buf2, sizeof(test_buf2)); - ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0); + ASSERT_OK(lseek(open_req1.result, 0, SEEK_CUR)); r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, -1, NULL); - ASSERT(r >= 0); - ASSERT(read_req.result == sizeof(test_buf) + sizeof(test_buf2)); - ASSERT(strcmp(buf, test_buf) == 0); - ASSERT(strcmp(buf2, test_buf2) == 0); + ASSERT_GE(r, 0); + ASSERT_EQ(read_req.result, sizeof(test_buf) + sizeof(test_buf2)); + ASSERT_OK(strcmp(buf, test_buf)); + ASSERT_OK(strcmp(buf2, test_buf2)); uv_fs_req_cleanup(&read_req); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r == 0); - ASSERT(read_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(read_req.result); uv_fs_req_cleanup(&read_req); /* Read the strings back to separate buffers. */ iovs[0] = uv_buf_init(buf, sizeof(test_buf)); iovs[1] = uv_buf_init(buf2, sizeof(test_buf2)); r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, 0, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); if (read_req.result == sizeof(test_buf)) { /* Infer that preadv is not available. */ uv_fs_req_cleanup(&read_req); r = uv_fs_read(NULL, &read_req, open_req1.result, &iovs[1], 1, read_req.result, NULL); - ASSERT(r >= 0); - ASSERT(read_req.result == sizeof(test_buf2)); + ASSERT_GE(r, 0); + ASSERT_EQ(read_req.result, sizeof(test_buf2)); } else { - ASSERT(read_req.result == sizeof(test_buf) + sizeof(test_buf2)); + ASSERT_EQ(read_req.result, sizeof(test_buf) + sizeof(test_buf2)); } - ASSERT(strcmp(buf, test_buf) == 0); - ASSERT(strcmp(buf2, test_buf2) == 0); + ASSERT_OK(strcmp(buf, test_buf)); + ASSERT_OK(strcmp(buf2, test_buf2)); uv_fs_req_cleanup(&read_req); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, sizeof(test_buf) + sizeof(test_buf2), NULL); - ASSERT(r == 0); - ASSERT(read_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(read_req.result); uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* Cleanup */ @@ -3406,8 +3408,8 @@ static void fs_write_alotof_bufs(int add_flags) { O_RDWR | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); for (index = 0; index < iovcount; ++index) @@ -3420,8 +3422,8 @@ static void fs_write_alotof_bufs(int add_flags) { iovcount, -1, NULL); - ASSERT(r >= 0); - ASSERT((size_t)write_req.result == sizeof(test_buf) * iovcount); + ASSERT_GE(r, 0); + ASSERT_EQ((size_t)write_req.result, sizeof(test_buf) * iovcount); uv_fs_req_cleanup(&write_req); /* Read the strings back to separate buffers. */ @@ -3433,31 +3435,32 @@ static void fs_write_alotof_bufs(int add_flags) { sizeof(test_buf)); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, -1, NULL); if (iovcount > iovmax) iovcount = iovmax; - ASSERT(r >= 0); - ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount); + ASSERT_GE(r, 0); + ASSERT_EQ((size_t)read_req.result, sizeof(test_buf) * iovcount); for (index = 0; index < iovcount; ++index) - ASSERT(strncmp(buffer + index * sizeof(test_buf), - test_buf, - sizeof(test_buf)) == 0); + ASSERT_OK(strncmp(buffer + index * sizeof(test_buf), + test_buf, + sizeof(test_buf))); uv_fs_req_cleanup(&read_req); free(buffer); - ASSERT(lseek(open_req1.result, write_req.result, SEEK_SET) == write_req.result); + ASSERT_EQ(lseek(open_req1.result, write_req.result, SEEK_SET), + write_req.result); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, @@ -3466,13 +3469,13 @@ static void fs_write_alotof_bufs(int add_flags) { 1, -1, NULL); - ASSERT(r == 0); - ASSERT(read_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(read_req.result); uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* Cleanup */ @@ -3518,14 +3521,14 @@ static void fs_write_alotof_bufs_with_offset(int add_flags) { O_RDWR | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); iov = uv_buf_init(filler, filler_len); r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r == filler_len); - ASSERT(write_req.result == filler_len); + ASSERT_EQ(r, filler_len); + ASSERT_EQ(write_req.result, filler_len); uv_fs_req_cleanup(&write_req); offset = (int64_t)r; @@ -3539,8 +3542,8 @@ static void fs_write_alotof_bufs_with_offset(int add_flags) { iovcount, offset, NULL); - ASSERT(r >= 0); - ASSERT((size_t)write_req.result == sizeof(test_buf) * iovcount); + ASSERT_GE(r, 0); + ASSERT_EQ((size_t)write_req.result, sizeof(test_buf) * iovcount); uv_fs_req_cleanup(&write_req); /* Read the strings back to separate buffers. */ @@ -3553,25 +3556,25 @@ static void fs_write_alotof_bufs_with_offset(int add_flags) { r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, offset, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); if (r == sizeof(test_buf)) iovcount = 1; /* Infer that preadv is not available. */ else if (iovcount > iovmax) iovcount = iovmax; - ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount); + ASSERT_EQ((size_t)read_req.result, sizeof(test_buf) * iovcount); for (index = 0; index < iovcount; ++index) - ASSERT(strncmp(buffer + index * sizeof(test_buf), - test_buf, - sizeof(test_buf)) == 0); + ASSERT_OK(strncmp(buffer + index * sizeof(test_buf), + test_buf, + sizeof(test_buf))); uv_fs_req_cleanup(&read_req); free(buffer); r = uv_fs_stat(NULL, &stat_req, "test_file", NULL); - ASSERT(r == 0); - ASSERT((int64_t)((uv_stat_t*)stat_req.ptr)->st_size == - offset + (int64_t)write_req.result); + ASSERT_OK(r); + ASSERT_EQ((int64_t)((uv_stat_t*)stat_req.ptr)->st_size, + offset + (int64_t)write_req.result); uv_fs_req_cleanup(&stat_req); iov = uv_buf_init(buf, sizeof(buf)); @@ -3582,13 +3585,13 @@ static void fs_write_alotof_bufs_with_offset(int add_flags) { 1, offset + write_req.result, NULL); - ASSERT(r == 0); - ASSERT(read_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(read_req.result); uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* Cleanup */ @@ -3611,9 +3614,9 @@ TEST_IMPL(fs_read_dir) { /* Setup */ rmdir("test_dir"); r = uv_fs_mkdir(loop, &mkdir_req, "test_dir", 0755, mkdir_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(mkdir_cb_count == 1); + ASSERT_EQ(1, mkdir_cb_count); /* Setup Done Here */ /* Get a file descriptor for the directory */ @@ -3623,7 +3626,7 @@ TEST_IMPL(fs_read_dir) { UV_FS_O_RDONLY | UV_FS_O_DIRECTORY, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); + ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); /* Try to read data from the directory */ @@ -3643,12 +3646,12 @@ TEST_IMPL(fs_read_dir) { */ ASSERT((r >= 0) || (r == UV_EISDIR)); #else - ASSERT(r == UV_EISDIR); + ASSERT_EQ(r, UV_EISDIR); #endif uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&close_req); /* Cleanup */ @@ -3695,7 +3698,7 @@ static void thread_main(void* arg) { if (ctx->doread) { result = write(ctx->fd, data, nbytes); /* Should not see EINTR (or other errors) */ - ASSERT(result == nbytes); + ASSERT_EQ(result, nbytes); } else { result = read(ctx->fd, data, nbytes); /* Should not see EINTR (or other errors), @@ -3757,13 +3760,13 @@ static void test_fs_partial(int doread) { loop = uv_default_loop(); - ASSERT(0 == uv_signal_init(loop, &signal)); - ASSERT(0 == uv_signal_start(&signal, sig_func, SIGUSR1)); + ASSERT_OK(uv_signal_init(loop, &signal)); + ASSERT_OK(uv_signal_start(&signal, sig_func, SIGUSR1)); - ASSERT(0 == pipe(pipe_fds)); + ASSERT_OK(pipe(pipe_fds)); ctx.fd = pipe_fds[doread]; - ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); + ASSERT_OK(uv_thread_create(&thread, thread_main, &ctx)); if (doread) { uv_buf_t* read_iovs; @@ -3780,34 +3783,34 @@ static void test_fs_partial(int doread) { iovcount -= read_iovcount; nread += result; } else { - ASSERT(result == UV_EINTR); + ASSERT_EQ(result, UV_EINTR); } uv_fs_req_cleanup(&read_req); } } else { int result; result = uv_fs_write(loop, &write_req, pipe_fds[1], iovs, iovcount, -1, NULL); - ASSERT(write_req.result == result); - ASSERT(result == ctx.size); + ASSERT_EQ(write_req.result, result); + ASSERT_EQ(result, ctx.size); uv_fs_req_cleanup(&write_req); } - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); ASSERT_MEM_EQ(buffer, ctx.data, ctx.size); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(0 == close(pipe_fds[1])); + ASSERT_OK(close(pipe_fds[1])); uv_close((uv_handle_t*) &signal, NULL); { /* Make sure we read everything that we wrote. */ int result; result = uv_fs_read(loop, &read_req, pipe_fds[0], iovs, 1, -1, NULL); - ASSERT(result == 0); + ASSERT_OK(result); uv_fs_req_cleanup(&read_req); } - ASSERT(0 == close(pipe_fds[0])); + ASSERT_OK(close(pipe_fds[0])); free(iovs); free(buffer); @@ -3832,13 +3835,13 @@ TEST_IMPL(fs_read_write_null_arguments) { int r; r = uv_fs_read(NULL, &read_req, 0, NULL, 0, -1, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_fs_req_cleanup(&read_req); r = uv_fs_write(NULL, &write_req, 0, NULL, 0, -1, NULL); /* Validate some memory management on failed input validation before sending fs work to the thread pool. */ - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); ASSERT_NULL(write_req.path); ASSERT_NULL(write_req.ptr); #ifdef _WIN32 @@ -3853,36 +3856,36 @@ TEST_IMPL(fs_read_write_null_arguments) { iov = uv_buf_init(NULL, 0); r = uv_fs_read(NULL, &read_req, 0, &iov, 0, -1, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_fs_req_cleanup(&read_req); iov = uv_buf_init(NULL, 0); r = uv_fs_write(NULL, &write_req, 0, &iov, 0, -1, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_fs_req_cleanup(&write_req); /* If the arguments are invalid, the loop should not be kept open */ loop = uv_default_loop(); r = uv_fs_read(loop, &read_req, 0, NULL, 0, -1, fail_cb); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_run(loop, UV_RUN_DEFAULT); uv_fs_req_cleanup(&read_req); r = uv_fs_write(loop, &write_req, 0, NULL, 0, -1, fail_cb); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_run(loop, UV_RUN_DEFAULT); uv_fs_req_cleanup(&write_req); iov = uv_buf_init(NULL, 0); r = uv_fs_read(loop, &read_req, 0, &iov, 0, -1, fail_cb); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_run(loop, UV_RUN_DEFAULT); uv_fs_req_cleanup(&read_req); iov = uv_buf_init(NULL, 0); r = uv_fs_write(loop, &write_req, 0, &iov, 0, -1, fail_cb); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_run(loop, UV_RUN_DEFAULT); uv_fs_req_cleanup(&write_req); @@ -3906,20 +3909,20 @@ TEST_IMPL(get_osfhandle_valid_handle) { O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); fd = uv_get_osfhandle(open_req1.result); #ifdef _WIN32 - ASSERT(fd != INVALID_HANDLE_VALUE); + ASSERT_NE(fd, INVALID_HANDLE_VALUE); #else - ASSERT(fd >= 0); + ASSERT_GE(fd, 0); #endif r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* Cleanup. */ @@ -3945,27 +3948,27 @@ TEST_IMPL(open_osfhandle_valid_handle) { O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); handle = uv_get_osfhandle(open_req1.result); #ifdef _WIN32 - ASSERT(handle != INVALID_HANDLE_VALUE); + ASSERT_NE(handle, INVALID_HANDLE_VALUE); #else - ASSERT(handle >= 0); + ASSERT_GE(handle, 0); #endif fd = uv_open_osfhandle(handle); #ifdef _WIN32 - ASSERT(fd > 0); + ASSERT_GT(fd, 0); #else - ASSERT(fd == open_req1.result); + ASSERT_EQ(fd, open_req1.result); #endif r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* Cleanup. */ @@ -3988,24 +3991,24 @@ TEST_IMPL(fs_file_pos_after_op_with_offset) { O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r > 0); + ASSERT_GT(r, 0); uv_fs_req_cleanup(&open_req1); iov = uv_buf_init(test_buf, sizeof(test_buf)); r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 0, NULL); - ASSERT(r == sizeof(test_buf)); - ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0); + ASSERT_EQ(r, sizeof(test_buf)); + ASSERT_OK(lseek(open_req1.result, 0, SEEK_CUR)); uv_fs_req_cleanup(&write_req); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 0, NULL); - ASSERT(r == sizeof(test_buf)); - ASSERT(strcmp(buf, test_buf) == 0); - ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0); + ASSERT_EQ(r, sizeof(test_buf)); + ASSERT_OK(strcmp(buf, test_buf)); + ASSERT_OK(lseek(open_req1.result, 0, SEEK_CUR)); uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&close_req); /* Cleanup */ @@ -4021,30 +4024,30 @@ static void fs_file_pos_common(void) { iov = uv_buf_init("abc", 3); r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r == 3); + ASSERT_EQ(3, r); uv_fs_req_cleanup(&write_req); /* Read with offset should not change the position */ iov = uv_buf_init(buf, 1); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 1, NULL); - ASSERT(r == 1); - ASSERT(buf[0] == 'b'); + ASSERT_EQ(1, r); + ASSERT_EQ(buf[0], 'b'); uv_fs_req_cleanup(&read_req); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&read_req); /* Write without offset should change the position */ iov = uv_buf_init("d", 1); r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r == 1); + ASSERT_EQ(1, r); uv_fs_req_cleanup(&write_req); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&read_req); } @@ -4053,23 +4056,23 @@ static void fs_file_pos_close_check(const char *contents, int size) { /* Close */ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&close_req); /* Confirm file contents */ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r == size); - ASSERT(strncmp(buf, contents, size) == 0); + ASSERT_EQ(r, size); + ASSERT_OK(strncmp(buf, contents, size)); uv_fs_req_cleanup(&read_req); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&close_req); /* Cleanup */ @@ -4088,7 +4091,7 @@ static void fs_file_pos_write(int add_flags) { O_TRUNC | O_CREAT | O_RDWR | add_flags, S_IWUSR | S_IRUSR, NULL); - ASSERT(r > 0); + ASSERT_GT(r, 0); uv_fs_req_cleanup(&open_req1); fs_file_pos_common(); @@ -4096,12 +4099,12 @@ static void fs_file_pos_write(int add_flags) { /* Write with offset should not change the position */ iov = uv_buf_init("e", 1); r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 1, NULL); - ASSERT(r == 1); + ASSERT_EQ(1, r); uv_fs_req_cleanup(&write_req); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&read_req); fs_file_pos_close_check("aecd", 4); @@ -4126,7 +4129,7 @@ static void fs_file_pos_append(int add_flags) { O_APPEND | O_CREAT | O_RDWR | add_flags, S_IWUSR | S_IRUSR, NULL); - ASSERT(r > 0); + ASSERT_GT(r, 0); uv_fs_req_cleanup(&open_req1); fs_file_pos_common(); @@ -4135,13 +4138,13 @@ static void fs_file_pos_append(int add_flags) { * but does not change the position */ iov = uv_buf_init("e", 1); r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 1, NULL); - ASSERT(r == 1); + ASSERT_EQ(1, r); uv_fs_req_cleanup(&write_req); iov = uv_buf_init(buf, sizeof(buf)); r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL); - ASSERT(r == 1); - ASSERT(buf[0] == 'e'); + ASSERT_EQ(1, r); + ASSERT_EQ(buf[0], 'e'); uv_fs_req_cleanup(&read_req); fs_file_pos_close_check("abcde", 5); @@ -4160,97 +4163,97 @@ TEST_IMPL(fs_null_req) { int r; r = uv_fs_open(NULL, NULL, NULL, 0, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_close(NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_read(NULL, NULL, 0, NULL, 0, -1, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_write(NULL, NULL, 0, NULL, 0, -1, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_unlink(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_mkdir(NULL, NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_mkdtemp(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_mkstemp(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_rmdir(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_scandir(NULL, NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_link(NULL, NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_symlink(NULL, NULL, NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_readlink(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_realpath(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_chown(NULL, NULL, NULL, 0, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_fchown(NULL, NULL, 0, 0, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_stat(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_lstat(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_fstat(NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_rename(NULL, NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_fsync(NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_fdatasync(NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_ftruncate(NULL, NULL, 0, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_copyfile(NULL, NULL, NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_sendfile(NULL, NULL, 0, 0, 0, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_access(NULL, NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_chmod(NULL, NULL, NULL, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_fchmod(NULL, NULL, 0, 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_utime(NULL, NULL, NULL, 0.0, 0.0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_futime(NULL, NULL, 0, 0.0, 0.0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_fs_statfs(NULL, NULL, NULL, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); /* This should be a no-op. */ uv_fs_req_cleanup(NULL); @@ -4265,7 +4268,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) { /* Setup. */ unlink("test_file"); - ASSERT(UV_FS_O_EXLOCK > 0); + ASSERT_GT(UV_FS_O_EXLOCK, 0); r = uv_fs_open(NULL, &open_req1, @@ -4273,8 +4276,8 @@ TEST_IMPL(fs_exclusive_sharing_mode) { O_RDWR | O_CREAT | UV_FS_O_EXLOCK, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); r = uv_fs_open(NULL, @@ -4283,13 +4286,13 @@ TEST_IMPL(fs_exclusive_sharing_mode) { O_RDONLY | UV_FS_O_EXLOCK, S_IWUSR | S_IRUSR, NULL); - ASSERT(r < 0); - ASSERT(open_req2.result < 0); + ASSERT_LT(r, 0); + ASSERT_LT(open_req2.result, 0); uv_fs_req_cleanup(&open_req2); r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); r = uv_fs_open(NULL, @@ -4298,13 +4301,13 @@ TEST_IMPL(fs_exclusive_sharing_mode) { O_RDONLY | UV_FS_O_EXLOCK, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req2.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(open_req2.result, 0); uv_fs_req_cleanup(&open_req2); r = uv_fs_close(NULL, &close_req, open_req2.result, NULL); - ASSERT(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* Cleanup */ @@ -4322,10 +4325,10 @@ TEST_IMPL(fs_file_flag_no_buffering) { /* Setup. */ unlink("test_file"); - ASSERT(UV_FS_O_APPEND > 0); - ASSERT(UV_FS_O_CREAT > 0); - ASSERT(UV_FS_O_DIRECT > 0); - ASSERT(UV_FS_O_RDWR > 0); + ASSERT_GT(UV_FS_O_APPEND, 0); + ASSERT_GT(UV_FS_O_CREAT, 0); + ASSERT_GT(UV_FS_O_DIRECT, 0); + ASSERT_GT(UV_FS_O_RDWR, 0); /* FILE_APPEND_DATA must be excluded from FILE_GENERIC_WRITE: */ r = uv_fs_open(NULL, @@ -4334,13 +4337,13 @@ TEST_IMPL(fs_file_flag_no_buffering) { UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_DIRECT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + 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(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually exclusive: */ @@ -4350,8 +4353,8 @@ TEST_IMPL(fs_file_flag_no_buffering) { UV_FS_O_APPEND | UV_FS_O_DIRECT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r == UV_EINVAL); - ASSERT(open_req2.result == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); + ASSERT_EQ(open_req2.result, UV_EINVAL); uv_fs_req_cleanup(&open_req2); /* Cleanup */ @@ -4392,7 +4395,7 @@ TEST_IMPL(fs_open_readonly_acl) { /* Setup - clear the ACL and remove the file */ loop = uv_default_loop(); r = uv_os_get_passwd(&pwd); - ASSERT(r == 0); + ASSERT_OK(r); call_icacls("icacls test_file_icacls /remove \"%s\" /inheritance:e", pwd.username); uv_fs_chmod(loop, &req, "test_file_icacls", S_IWUSR, NULL); @@ -4405,12 +4408,12 @@ TEST_IMPL(fs_open_readonly_acl) { O_RDONLY | O_CREAT, S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(open_req1.result >= 0); + 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(r == 0); - ASSERT(close_req.result == 0); + ASSERT_OK(r); + ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); /* Set up ACL */ @@ -4442,7 +4445,7 @@ TEST_IMPL(fs_open_readonly_acl) { pwd.username); unlink("test_file_icacls"); uv_os_free_passwd(&pwd); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -4463,35 +4466,35 @@ TEST_IMPL(fs_fchmod_archive_readonly) { O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); file = req.result; uv_fs_req_cleanup(&req); r = uv_fs_close(NULL, &req, file, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); /* Make the file read-only and clear archive flag */ r = SetFileAttributes("test_file", FILE_ATTRIBUTE_READONLY); - ASSERT(r != 0); + ASSERT(r); check_permission("test_file", 0400); /* Try fchmod */ r = uv_fs_open(NULL, &req, "test_file", O_RDONLY, 0, NULL); - ASSERT(r >= 0); - ASSERT(req.result >= 0); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); file = req.result; uv_fs_req_cleanup(&req); r = uv_fs_fchmod(NULL, &req, file, S_IWUSR, NULL); - ASSERT(r == 0); - ASSERT(req.result == 0); + ASSERT_OK(r); + ASSERT_OK(req.result); uv_fs_req_cleanup(&req); r = uv_fs_close(NULL, &req, file, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&req); check_permission("test_file", S_IWUSR); /* Restore Archive flag for rest of the tests */ r = SetFileAttributes("test_file", FILE_ATTRIBUTE_ARCHIVE); - ASSERT(r != 0); + ASSERT(r); return 0; } @@ -4503,7 +4506,7 @@ TEST_IMPL(fs_invalid_mkdir_name) { loop = uv_default_loop(); r = uv_fs_mkdir(loop, &req, "invalid>", 0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); ASSERT_EQ(UV_EINVAL, uv_fs_mkdir(loop, &req, "test:lol", 0, NULL)); return 0; @@ -4518,15 +4521,15 @@ TEST_IMPL(fs_statfs) { /* Test the synchronous version. */ r = uv_fs_statfs(NULL, &req, ".", NULL); - ASSERT(r == 0); + ASSERT_OK(r); statfs_cb(&req); - ASSERT(statfs_cb_count == 1); + ASSERT_EQ(1, statfs_cb_count); /* Test the asynchronous version. */ r = uv_fs_statfs(loop, &req, ".", statfs_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(statfs_cb_count == 2); + ASSERT_EQ(2, statfs_cb_count); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -4538,13 +4541,13 @@ TEST_IMPL(fs_get_system_error) { int system_error; r = uv_fs_statfs(NULL, &req, "non_existing_file", NULL); - ASSERT(r != 0); + ASSERT(r); system_error = uv_fs_get_system_error(&req); #ifdef _WIN32 - ASSERT(system_error == ERROR_FILE_NOT_FOUND); + ASSERT_EQ(system_error, ERROR_FILE_NOT_FOUND); #else - ASSERT(system_error == ENOENT); + ASSERT_EQ(system_error, ENOENT); #endif return 0; @@ -4559,13 +4562,13 @@ TEST_IMPL(fs_stat_batch_multiple) { rmdir("test_dir"); r = uv_fs_mkdir(NULL, &mkdir_req, "test_dir", 0755, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); loop = uv_default_loop(); for (i = 0; i < (int) ARRAY_SIZE(req); ++i) { r = uv_fs_stat(loop, &req[i], "test_dir", stat_batch_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } uv_run(loop, UV_RUN_DEFAULT); @@ -4590,7 +4593,7 @@ TEST_IMPL(fs_wtf) { loop = uv_default_loop(); r = uv_fs_mkdir(NULL, &mkdir_req, "test_dir", 0777, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_fs_req_cleanup(&mkdir_req); file_handle = CreateFileW(L"test_dir/hi\xD801\x0037", @@ -4601,19 +4604,19 @@ TEST_IMPL(fs_wtf) { FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); - ASSERT(file_handle != INVALID_HANDLE_VALUE); + ASSERT_NE(file_handle, INVALID_HANDLE_VALUE); CloseHandle(file_handle); r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL); - ASSERT_EQ(r, 1); - ASSERT_EQ(scandir_req.result, 1); + ASSERT_EQ(1, r); + ASSERT_EQ(1, scandir_req.result); ASSERT_NOT_NULL(scandir_req.ptr); while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) { snprintf(test_file_buf, sizeof(test_file_buf), "test_dir\\%s", dent.name); printf("stat %s\n", test_file_buf); r = uv_fs_stat(NULL, &stat_req, test_file_buf, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } uv_fs_req_cleanup(&scandir_req); ASSERT_NULL(scandir_req.ptr); diff --git a/test/test-get-currentexe.c b/test/test-get-currentexe.c index becaf5c1bb8..c813d3a5c4f 100644 --- a/test/test-get-currentexe.c +++ b/test/test-get-currentexe.c @@ -60,43 +60,43 @@ TEST_IMPL(get_currentexe) { * executable_path. */ ASSERT(match && !strcmp(match, path)); - ASSERT(size == strlen(buffer)); + ASSERT_EQ(size, strlen(buffer)); /* Negative tests */ size = sizeof(buffer) / sizeof(buffer[0]); r = uv_exepath(NULL, &size); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_exepath(buffer, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); size = 0; r = uv_exepath(buffer, &size); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); memset(buffer, -1, sizeof(buffer)); size = 1; r = uv_exepath(buffer, &size); - ASSERT(r == 0); - ASSERT(size == 0); - ASSERT(buffer[0] == '\0'); + ASSERT_OK(r); + ASSERT_OK(size); + ASSERT_EQ(buffer[0], '\0'); memset(buffer, -1, sizeof(buffer)); size = 2; r = uv_exepath(buffer, &size); - ASSERT(r == 0); - ASSERT(size == 1); - ASSERT(buffer[0] != '\0'); - ASSERT(buffer[1] == '\0'); + ASSERT_OK(r); + ASSERT_EQ(1, size); + ASSERT_NE(buffer[0], '\0'); + ASSERT_EQ(buffer[1], '\0'); /* Verify uv_exepath is not affected by uv_set_process_title(). */ r = uv_set_process_title("foobar"); - ASSERT_EQ(r, 0); + ASSERT_OK(r); size = sizeof(buffer); r = uv_exepath(buffer, &size); - ASSERT_EQ(r, 0); + ASSERT_OK(r); match = strstr(buffer, path); /* Verify that the path returned from uv_exepath is a subdirectory of diff --git a/test/test-get-loadavg.c b/test/test-get-loadavg.c index 4762e47576d..ef1719c047f 100644 --- a/test/test-get-loadavg.c +++ b/test/test-get-loadavg.c @@ -27,9 +27,9 @@ TEST_IMPL(get_loadavg) { double avg[3] = {-1, -1, -1}; uv_loadavg(avg); - ASSERT(avg[0] >= 0); - ASSERT(avg[1] >= 0); - ASSERT(avg[2] >= 0); + ASSERT_GE(avg[0], 0); + ASSERT_GE(avg[1], 0); + ASSERT_GE(avg[2], 0); return 0; } diff --git a/test/test-get-memory.c b/test/test-get-memory.c index 9ac42c383c9..2a23f79470f 100644 --- a/test/test-get-memory.c +++ b/test/test-get-memory.c @@ -35,13 +35,13 @@ TEST_IMPL(get_memory) { (unsigned long long) constrained_mem, (unsigned long long) available_mem); - ASSERT(free_mem > 0); - ASSERT(total_mem > 0); + ASSERT_GT(free_mem, 0); + ASSERT_GT(total_mem, 0); /* On IBMi PASE, the amount of memory in use is always zero. */ #ifdef __PASE__ - ASSERT(total_mem == free_mem); + ASSERT_EQ(total_mem, free_mem); #else - ASSERT(total_mem > free_mem); + ASSERT_GT(total_mem, free_mem); #endif ASSERT_LE(available_mem, total_mem); /* we'd really want to test if available <= free, but that is fragile: diff --git a/test/test-get-passwd.c b/test/test-get-passwd.c index 29a2bd1243d..c70c69a9b81 100644 --- a/test/test-get-passwd.c +++ b/test/test-get-passwd.c @@ -39,7 +39,7 @@ TEST_IMPL(get_passwd) { /* Test the normal case */ r = uv_os_get_passwd(&pwd); - ASSERT_EQ(r, 0); + ASSERT_OK(r); len = strlen(pwd.username); ASSERT_GT(len, 0); @@ -114,7 +114,7 @@ TEST_IMPL(get_passwd2) { /* Test the normal case */ r = uv_os_get_passwd(&pwd); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_os_get_passwd2(&pwd2, pwd.uid); @@ -123,7 +123,7 @@ TEST_IMPL(get_passwd2) { (void) &len; #else - ASSERT_EQ(r, 0); + ASSERT_OK(r); ASSERT_EQ(pwd.uid, pwd2.uid); ASSERT_STR_EQ(pwd.username, pwd2.username); ASSERT_STR_EQ(pwd.shell, pwd2.shell); @@ -131,7 +131,7 @@ TEST_IMPL(get_passwd2) { uv_os_free_passwd(&pwd2); r = uv_os_get_passwd2(&pwd2, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); len = strlen(pwd2.username); ASSERT_GT(len, 0); @@ -174,7 +174,7 @@ TEST_IMPL(get_group) { int r; r = uv_os_get_passwd(&pwd); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_os_get_group(&grp, pwd.gid); @@ -183,7 +183,7 @@ TEST_IMPL(get_group) { (void) &len; #else - ASSERT_EQ(r, 0); + ASSERT_OK(r); ASSERT_EQ(pwd.gid, grp.gid); len = strlen(grp.groupname); diff --git a/test/test-getaddrinfo.c b/test/test-getaddrinfo.c index 1032537ad56..76137f06ca0 100644 --- a/test/test-getaddrinfo.c +++ b/test/test-getaddrinfo.c @@ -40,8 +40,8 @@ static void getaddrinfo_fail_cb(uv_getaddrinfo_t* req, int status, struct addrinfo* res) { - ASSERT(fail_cb_called == 0); - ASSERT(status < 0); + ASSERT_OK(fail_cb_called); + ASSERT_LT(status, 0); ASSERT_NULL(res); uv_freeaddrinfo(res); /* Should not crash. */ fail_cb_called++; @@ -51,7 +51,7 @@ static void getaddrinfo_fail_cb(uv_getaddrinfo_t* req, static void getaddrinfo_basic_cb(uv_getaddrinfo_t* handle, int status, struct addrinfo* res) { - ASSERT(handle == getaddrinfo_handle); + ASSERT_PTR_EQ(handle, getaddrinfo_handle); getaddrinfo_cbs++; free(handle); uv_freeaddrinfo(res); @@ -66,7 +66,7 @@ static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle, for (i = 0; i < CONCURRENT_COUNT; i++) { if (&getaddrinfo_handles[i] == handle) { - ASSERT(i == *data); + ASSERT_EQ(i, *data); callback_counts[i]++; break; @@ -89,22 +89,22 @@ TEST_IMPL(getaddrinfo_fail) { uv_getaddrinfo_t req; - ASSERT(UV_EINVAL == uv_getaddrinfo(uv_default_loop(), - &req, - (uv_getaddrinfo_cb) abort, - NULL, - NULL, - NULL)); + ASSERT_EQ(UV_EINVAL, uv_getaddrinfo(uv_default_loop(), + &req, + (uv_getaddrinfo_cb) abort, + NULL, + NULL, + NULL)); /* Use a FQDN by ending in a period */ - ASSERT(0 == uv_getaddrinfo(uv_default_loop(), - &req, - getaddrinfo_fail_cb, - "example.invalid.", - NULL, - NULL)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(fail_cb_called == 1); + ASSERT_OK(uv_getaddrinfo(uv_default_loop(), + &req, + getaddrinfo_fail_cb, + "example.invalid.", + NULL, + NULL)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, fail_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -119,12 +119,12 @@ TEST_IMPL(getaddrinfo_fail_sync) { uv_getaddrinfo_t req; /* Use a FQDN by ending in a period */ - ASSERT(0 > uv_getaddrinfo(uv_default_loop(), - &req, - NULL, - "example.invalid.", - NULL, - NULL)); + ASSERT_GT(0, uv_getaddrinfo(uv_default_loop(), + &req, + NULL, + "example.invalid.", + NULL, + NULL)); uv_freeaddrinfo(req.addrinfo); MAKE_VALGRIND_HAPPY(uv_default_loop()); @@ -147,11 +147,11 @@ TEST_IMPL(getaddrinfo_basic) { name, NULL, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(getaddrinfo_cbs == 1); + ASSERT_EQ(1, getaddrinfo_cbs); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -165,12 +165,12 @@ TEST_IMPL(getaddrinfo_basic_sync) { #endif uv_getaddrinfo_t req; - ASSERT(0 == uv_getaddrinfo(uv_default_loop(), - &req, - NULL, - name, - NULL, - NULL)); + ASSERT_OK(uv_getaddrinfo(uv_default_loop(), + &req, + NULL, + name, + NULL, + NULL)); uv_freeaddrinfo(req.addrinfo); MAKE_VALGRIND_HAPPY(uv_default_loop()); @@ -201,13 +201,13 @@ TEST_IMPL(getaddrinfo_concurrent) { name, NULL, NULL); - ASSERT(r == 0); + ASSERT_OK(r); } uv_run(uv_default_loop(), UV_RUN_DEFAULT); for (i = 0; i < CONCURRENT_COUNT; i++) { - ASSERT(callback_counts[i] == 1); + ASSERT_EQ(1, callback_counts[i]); } MAKE_VALGRIND_HAPPY(uv_default_loop()); diff --git a/test/test-gethostname.c b/test/test-gethostname.c index dc29cd69234..cc15a8253eb 100644 --- a/test/test-gethostname.c +++ b/test/test-gethostname.c @@ -32,27 +32,27 @@ TEST_IMPL(gethostname) { /* Reject invalid inputs */ size = 1; r = uv_os_gethostname(NULL, &size); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_os_gethostname(buf, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); size = 0; r = uv_os_gethostname(buf, &size); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); /* Return UV_ENOBUFS if the buffer cannot hold the hostname */ enobufs_size = 1; buf[0] = '\0'; r = uv_os_gethostname(buf, &enobufs_size); ASSERT_EQ(r, UV_ENOBUFS); - ASSERT(buf[0] == '\0'); - ASSERT(enobufs_size > 1); + ASSERT_EQ(buf[0], '\0'); + ASSERT_GT(enobufs_size, 1); /* Successfully get the hostname */ size = UV_MAXHOSTNAMESIZE; r = uv_os_gethostname(buf, &size); - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(size > 0 && size == strlen(buf)); - ASSERT(size + 1 == enobufs_size); + ASSERT_EQ(size + 1, enobufs_size); return 0; } diff --git a/test/test-getnameinfo.c b/test/test-getnameinfo.c index cea57b012f1..415e48a4f96 100644 --- a/test/test-getnameinfo.c +++ b/test/test-getnameinfo.c @@ -39,7 +39,7 @@ static void getnameinfo_req(uv_getnameinfo_t* handle, const char* hostname, const char* service) { ASSERT_NOT_NULL(handle); - ASSERT(status == 0); + ASSERT_OK(status); ASSERT_NOT_NULL(hostname); ASSERT_NOT_NULL(service); } @@ -54,14 +54,14 @@ TEST_IMPL(getnameinfo_basic_ip4) { int r; r = uv_ip4_addr(address_ip4, port, &addr4); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_getnameinfo(uv_default_loop(), &req, &getnameinfo_req, (const struct sockaddr*)&addr4, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); @@ -76,15 +76,15 @@ TEST_IMPL(getnameinfo_basic_ip4_sync) { RETURN_SKIP("Test does not currently work in QEMU"); #endif - ASSERT(0 == uv_ip4_addr(address_ip4, port, &addr4)); + ASSERT_OK(uv_ip4_addr(address_ip4, port, &addr4)); - ASSERT(0 == uv_getnameinfo(uv_default_loop(), - &req, - NULL, - (const struct sockaddr*)&addr4, - 0)); - ASSERT(req.host[0] != '\0'); - ASSERT(req.service[0] != '\0'); + ASSERT_OK(uv_getnameinfo(uv_default_loop(), + &req, + NULL, + (const struct sockaddr*)&addr4, + 0)); + ASSERT_NE(req.host[0], '\0'); + ASSERT_NE(req.service[0], '\0'); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -100,14 +100,14 @@ TEST_IMPL(getnameinfo_basic_ip6) { int r; r = uv_ip6_addr(address_ip6, port, &addr6); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_getnameinfo(uv_default_loop(), &req, &getnameinfo_req, (const struct sockaddr*)&addr6, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); diff --git a/test/test-getsockname.c b/test/test-getsockname.c index 1d4d9f12bda..7bc0ba2e9f2 100644 --- a/test/test-getsockname.c +++ b/test/test-getsockname.c @@ -73,7 +73,7 @@ static void after_read(uv_stream_t* handle, req = (uv_shutdown_t*) malloc(sizeof *req); r = uv_shutdown(req, handle, after_shutdown); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -84,22 +84,22 @@ static void check_sockname(struct sockaddr* addr, const char* compare_ip, char check_ip[17]; int r; - ASSERT(0 == uv_ip4_addr(compare_ip, compare_port, &compare_addr)); + ASSERT_OK(uv_ip4_addr(compare_ip, compare_port, &compare_addr)); /* Both addresses should be ipv4 */ - ASSERT(check_addr.sin_family == AF_INET); - ASSERT(compare_addr.sin_family == AF_INET); + ASSERT_EQ(check_addr.sin_family, AF_INET); + ASSERT_EQ(compare_addr.sin_family, AF_INET); /* Check if the ip matches */ - ASSERT(memcmp(&check_addr.sin_addr, - &compare_addr.sin_addr, - sizeof compare_addr.sin_addr) == 0); + ASSERT_OK(memcmp(&check_addr.sin_addr, + &compare_addr.sin_addr, + sizeof compare_addr.sin_addr)); /* Check if the port matches. If port == 0 anything goes. */ ASSERT(compare_port == 0 || check_addr.sin_port == compare_addr.sin_port); r = uv_ip4_name(&check_addr, (char*) check_ip, sizeof check_ip); - ASSERT(r == 0); + ASSERT_OK(r); printf("%s: %s:%d\n", context, check_ip, ntohs(check_addr.sin_port)); } @@ -114,34 +114,34 @@ static void on_connection(uv_stream_t* server, int status) { if (status != 0) { fprintf(stderr, "Connect error %s\n", uv_err_name(status)); } - ASSERT(status == 0); + ASSERT_OK(status); handle = malloc(sizeof(*handle)); ASSERT_NOT_NULL(handle); r = uv_tcp_init(loop, handle); - ASSERT(r == 0); + ASSERT_OK(r); /* associate server with stream */ handle->data = server; r = uv_accept(server, (uv_stream_t*)handle); - ASSERT(r == 0); + ASSERT_OK(r); namelen = sizeof sockname; r = uv_tcp_getsockname(handle, &sockname, &namelen); - ASSERT(r == 0); + ASSERT_OK(r); check_sockname(&sockname, "127.0.0.1", server_port, "accepted socket"); getsocknamecount_tcp++; namelen = sizeof peername; r = uv_tcp_getpeername(handle, &peername, &namelen); - ASSERT(r == 0); + ASSERT_OK(r); check_sockname(&peername, "127.0.0.1", connect_port, "accepted socket peer"); getpeernamecount++; r = uv_read_start((uv_stream_t*)handle, alloc, after_read); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -149,17 +149,17 @@ static void on_connect(uv_connect_t* req, int status) { struct sockaddr sockname, peername; int r, namelen; - ASSERT(status == 0); + ASSERT_OK(status); namelen = sizeof sockname; r = uv_tcp_getsockname((uv_tcp_t*) req->handle, &sockname, &namelen); - ASSERT(r == 0); + ASSERT_OK(r); check_sockname(&sockname, "127.0.0.1", 0, "connected socket"); getsocknamecount_tcp++; namelen = sizeof peername; r = uv_tcp_getpeername((uv_tcp_t*) req->handle, &peername, &namelen); - ASSERT(r == 0); + ASSERT_OK(r); check_sockname(&peername, "127.0.0.1", server_port, "connected socket peer"); getpeernamecount++; @@ -173,7 +173,7 @@ static int tcp_listener(void) { int namelen; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", server_port, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", server_port, &addr)); r = uv_tcp_init(loop, &tcpServer); if (r) { @@ -196,13 +196,13 @@ static int tcp_listener(void) { memset(&sockname, -1, sizeof sockname); namelen = sizeof sockname; r = uv_tcp_getsockname(&tcpServer, &sockname, &namelen); - ASSERT(r == 0); + ASSERT_OK(r); check_sockname(&sockname, "0.0.0.0", server_port, "server socket"); getsocknamecount_tcp++; namelen = sizeof sockname; r = uv_tcp_getpeername(&tcpServer, &peername, &namelen); - ASSERT(r == UV_ENOTCONN); + ASSERT_EQ(r, UV_ENOTCONN); getpeernamecount++; return 0; @@ -214,7 +214,7 @@ static void tcp_connector(void) { struct sockaddr sockname; int r, namelen; - ASSERT(0 == uv_ip4_addr("127.0.0.1", server_port, &server_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", server_port, &server_addr)); r = uv_tcp_init(loop, &tcp); tcp.data = &connect_req; @@ -230,9 +230,9 @@ static void tcp_connector(void) { namelen = sizeof sockname; r = uv_tcp_getsockname(&tcp, &sockname, &namelen); ASSERT(!r); - ASSERT(sockname.sa_family == AF_INET); + ASSERT_EQ(sockname.sa_family, AF_INET); connect_port = ntohs(((struct sockaddr_in*) &sockname)->sin_port); - ASSERT(connect_port > 0); + ASSERT_GT(connect_port, 0); } @@ -245,7 +245,7 @@ static void udp_recv(uv_udp_t* handle, int namelen; int r; - ASSERT(nread >= 0); + ASSERT_GE(nread, 0); free(buf->base); if (nread == 0) { @@ -255,7 +255,7 @@ static void udp_recv(uv_udp_t* handle, memset(&sockname, -1, sizeof sockname); namelen = sizeof(sockname); r = uv_udp_getsockname(&udp, &sockname, &namelen); - ASSERT(r == 0); + ASSERT_OK(r); check_sockname(&sockname, "0.0.0.0", 0, "udp receiving socket"); getsocknamecount_udp++; @@ -275,7 +275,7 @@ static int udp_listener(void) { int namelen; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", server_port, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", server_port, &addr)); r = uv_udp_init(loop, &udpServer); if (r) { @@ -292,12 +292,12 @@ static int udp_listener(void) { memset(&sockname, -1, sizeof sockname); namelen = sizeof sockname; r = uv_udp_getsockname(&udpServer, &sockname, &namelen); - ASSERT(r == 0); + ASSERT_OK(r); check_sockname(&sockname, "0.0.0.0", server_port, "udp listener socket"); getsocknamecount_udp++; r = uv_udp_recv_start(&udpServer, alloc, udp_recv); - ASSERT(r == 0); + ASSERT_OK(r); return 0; } @@ -312,7 +312,7 @@ static void udp_sender(void) { ASSERT(!r); buf = uv_buf_init("PING", 4); - ASSERT(0 == uv_ip4_addr("127.0.0.1", server_port, &server_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", server_port, &server_addr)); r = uv_udp_send(&send_req, &udp, @@ -334,8 +334,8 @@ TEST_IMPL(getsockname_tcp) { uv_run(loop, UV_RUN_DEFAULT); - ASSERT(getsocknamecount_tcp == 3); - ASSERT(getpeernamecount == 3); + ASSERT_EQ(3, getsocknamecount_tcp); + ASSERT_EQ(3, getpeernamecount); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -352,10 +352,10 @@ TEST_IMPL(getsockname_udp) { uv_run(loop, UV_RUN_DEFAULT); - ASSERT(getsocknamecount_udp == 2); + ASSERT_EQ(2, getsocknamecount_udp); - ASSERT(udp.send_queue_size == 0); - ASSERT(udpServer.send_queue_size == 0); + ASSERT_OK(udp.send_queue_size); + ASSERT_OK(udpServer.send_queue_size); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-getters-setters.c b/test/test-getters-setters.c index 9869f7b9da8..57cbfedc131 100644 --- a/test/test-getters-setters.c +++ b/test/test-getters-setters.c @@ -30,9 +30,9 @@ int cookie3; TEST_IMPL(handle_type_name) { - ASSERT(strcmp(uv_handle_type_name(UV_NAMED_PIPE), "pipe") == 0); - ASSERT(strcmp(uv_handle_type_name(UV_UDP), "udp") == 0); - ASSERT(strcmp(uv_handle_type_name(UV_FILE), "file") == 0); + ASSERT_OK(strcmp(uv_handle_type_name(UV_NAMED_PIPE), "pipe")); + ASSERT_OK(strcmp(uv_handle_type_name(UV_UDP), "udp")); + ASSERT_OK(strcmp(uv_handle_type_name(UV_FILE), "file")); ASSERT_NULL(uv_handle_type_name(UV_HANDLE_TYPE_MAX)); ASSERT_NULL(uv_handle_type_name(UV_HANDLE_TYPE_MAX + 1)); ASSERT_NULL(uv_handle_type_name(UV_UNKNOWN_HANDLE)); @@ -41,9 +41,9 @@ TEST_IMPL(handle_type_name) { TEST_IMPL(req_type_name) { - ASSERT(strcmp(uv_req_type_name(UV_REQ), "req") == 0); - ASSERT(strcmp(uv_req_type_name(UV_UDP_SEND), "udp_send") == 0); - ASSERT(strcmp(uv_req_type_name(UV_WORK), "work") == 0); + ASSERT_OK(strcmp(uv_req_type_name(UV_REQ), "req")); + ASSERT_OK(strcmp(uv_req_type_name(UV_UDP_SEND), "udp_send")); + ASSERT_OK(strcmp(uv_req_type_name(UV_WORK), "work")); ASSERT_NULL(uv_req_type_name(UV_REQ_TYPE_MAX)); ASSERT_NULL(uv_req_type_name(UV_REQ_TYPE_MAX + 1)); ASSERT_NULL(uv_req_type_name(UV_UNKNOWN_REQ)); @@ -60,48 +60,48 @@ TEST_IMPL(getters_setters) { loop = malloc(uv_loop_size()); ASSERT_NOT_NULL(loop); r = uv_loop_init(loop); - ASSERT(r == 0); + ASSERT_OK(r); uv_loop_set_data(loop, &cookie1); - ASSERT(loop->data == &cookie1); - ASSERT(uv_loop_get_data(loop) == &cookie1); + ASSERT_PTR_EQ(loop->data, &cookie1); + ASSERT_PTR_EQ(uv_loop_get_data(loop), &cookie1); pipe = malloc(uv_handle_size(UV_NAMED_PIPE)); r = uv_pipe_init(loop, pipe, 0); - ASSERT(r == 0); - ASSERT(uv_handle_get_type((uv_handle_t*)pipe) == UV_NAMED_PIPE); + ASSERT_OK(r); + ASSERT_EQ(uv_handle_get_type((uv_handle_t*)pipe), UV_NAMED_PIPE); - ASSERT(uv_handle_get_loop((uv_handle_t*)pipe) == loop); + ASSERT_EQ(uv_handle_get_loop((uv_handle_t*)pipe), loop); pipe->data = &cookie2; - ASSERT(uv_handle_get_data((uv_handle_t*)pipe) == &cookie2); + ASSERT_PTR_EQ(uv_handle_get_data((uv_handle_t*)pipe), &cookie2); uv_handle_set_data((uv_handle_t*)pipe, &cookie1); - ASSERT(uv_handle_get_data((uv_handle_t*)pipe) == &cookie1); - ASSERT(pipe->data == &cookie1); + ASSERT_PTR_EQ(uv_handle_get_data((uv_handle_t*)pipe), &cookie1); + ASSERT_PTR_EQ(pipe->data, &cookie1); - ASSERT(uv_stream_get_write_queue_size((uv_stream_t*)pipe) == 0); + ASSERT_OK(uv_stream_get_write_queue_size((uv_stream_t*)pipe)); pipe->write_queue_size++; - ASSERT(uv_stream_get_write_queue_size((uv_stream_t*)pipe) == 1); + ASSERT_EQ(1, uv_stream_get_write_queue_size((uv_stream_t*)pipe)); pipe->write_queue_size--; uv_close((uv_handle_t*)pipe, NULL); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); fs = malloc(uv_req_size(UV_FS)); uv_fs_stat(loop, fs, ".", NULL); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(uv_fs_get_type(fs) == UV_FS_STAT); - ASSERT(uv_fs_get_result(fs) == 0); - ASSERT(uv_fs_get_ptr(fs) == uv_fs_get_statbuf(fs)); + ASSERT_EQ(uv_fs_get_type(fs), UV_FS_STAT); + ASSERT_OK(uv_fs_get_result(fs)); + ASSERT_EQ(uv_fs_get_ptr(fs), uv_fs_get_statbuf(fs)); ASSERT(uv_fs_get_statbuf(fs)->st_mode & S_IFDIR); - ASSERT(strcmp(uv_fs_get_path(fs), ".") == 0); + ASSERT_OK(strcmp(uv_fs_get_path(fs), ".")); uv_fs_req_cleanup(fs); r = uv_loop_close(loop); - ASSERT(r == 0); + ASSERT_OK(r); free(pipe); free(fs); diff --git a/test/test-gettimeofday.c b/test/test-gettimeofday.c index 4ebc11f93ed..7d9012815c4 100644 --- a/test/test-gettimeofday.c +++ b/test/test-gettimeofday.c @@ -28,12 +28,12 @@ TEST_IMPL(gettimeofday) { tv.tv_sec = 0; r = uv_gettimeofday(&tv); - ASSERT(r == 0); - ASSERT(tv.tv_sec != 0); + ASSERT_OK(r); + ASSERT_NE(0, tv.tv_sec); /* Test invalid input. */ r = uv_gettimeofday(NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); return 0; } diff --git a/test/test-handle-fileno.c b/test/test-handle-fileno.c index 6c4c2b6601d..be53152ce84 100644 --- a/test/test-handle-fileno.c +++ b/test/test-handle-fileno.c @@ -56,49 +56,49 @@ TEST_IMPL(handle_fileno) { uv_loop_t* loop; loop = uv_default_loop(); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_idle_init(loop, &idle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fileno((uv_handle_t*) &idle, &fd); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_close((uv_handle_t*) &idle, NULL); r = uv_tcp_init(loop, &tcp); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fileno((uv_handle_t*) &tcp, &fd); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); r = uv_tcp_bind(&tcp, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fileno((uv_handle_t*) &tcp, &fd); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &tcp, NULL); r = uv_fileno((uv_handle_t*) &tcp, &fd); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); r = uv_udp_init(loop, &udp); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fileno((uv_handle_t*) &udp, &fd); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); r = uv_udp_bind(&udp, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fileno((uv_handle_t*) &udp, &fd); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &udp, NULL); r = uv_fileno((uv_handle_t*) &udp, &fd); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); r = uv_pipe_init(loop, &pipe, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fileno((uv_handle_t*) &pipe, &fd); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); r = uv_pipe_bind(&pipe, TEST_PIPENAME); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fileno((uv_handle_t*) &pipe, &fd); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &pipe, NULL); r = uv_fileno((uv_handle_t*) &pipe, &fd); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); tty_fd = get_tty_fd(); if (tty_fd < 0) { @@ -106,14 +106,14 @@ TEST_IMPL(handle_fileno) { fflush(stderr); } else { r = uv_tty_init(loop, &tty, tty_fd, 0); - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(uv_is_readable((uv_stream_t*) &tty)); ASSERT(!uv_is_writable((uv_stream_t*) &tty)); r = uv_fileno((uv_handle_t*) &tty, &fd); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &tty, NULL); r = uv_fileno((uv_handle_t*) &tty, &fd); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); ASSERT(!uv_is_readable((uv_stream_t*) &tty)); ASSERT(!uv_is_writable((uv_stream_t*) &tty)); } diff --git a/test/test-homedir.c b/test/test-homedir.c index 508351f72c0..769d5c8179f 100644 --- a/test/test-homedir.c +++ b/test/test-homedir.c @@ -34,39 +34,39 @@ TEST_IMPL(homedir) { /* Test the normal case */ len = sizeof homedir; homedir[0] = '\0'; - ASSERT(strlen(homedir) == 0); + ASSERT_OK(strlen(homedir)); r = uv_os_homedir(homedir, &len); - ASSERT(r == 0); - ASSERT(strlen(homedir) == len); - ASSERT(len > 0); - ASSERT(homedir[len] == '\0'); + ASSERT_OK(r); + ASSERT_EQ(strlen(homedir), len); + ASSERT_GT(len, 0); + ASSERT_EQ(homedir[len], '\0'); #ifdef _WIN32 if (len == 3 && homedir[1] == ':') - ASSERT(homedir[2] == '\\'); + ASSERT_EQ(homedir[2], '\\'); else - ASSERT(homedir[len - 1] != '\\'); + ASSERT_NE(homedir[len - 1], '\\'); #else if (len == 1) - ASSERT(homedir[0] == '/'); + ASSERT_EQ(homedir[0], '/'); else - ASSERT(homedir[len - 1] != '/'); + ASSERT_NE(homedir[len - 1], '/'); #endif /* Test the case where the buffer is too small */ len = SMALLPATH; r = uv_os_homedir(homedir, &len); - ASSERT(r == UV_ENOBUFS); - ASSERT(len > SMALLPATH); + ASSERT_EQ(r, UV_ENOBUFS); + ASSERT_GT(len, SMALLPATH); /* Test invalid inputs */ r = uv_os_homedir(NULL, &len); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_os_homedir(homedir, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); len = 0; r = uv_os_homedir(homedir, &len); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); return 0; } diff --git a/test/test-hrtime.c b/test/test-hrtime.c index 854a482f23c..c0b88c6757d 100644 --- a/test/test-hrtime.c +++ b/test/test-hrtime.c @@ -45,7 +45,7 @@ TEST_IMPL(hrtime) { * that the difference between the two hrtime values has a reasonable * lower bound. */ - ASSERT(diff > (uint64_t) 25 * NANOSEC / MILLISEC); + ASSERT_UINT64_GT(diff, (uint64_t) 25 * NANOSEC / MILLISEC); --i; } return 0; @@ -57,8 +57,8 @@ TEST_IMPL(clock_gettime) { ASSERT_EQ(UV_EINVAL, uv_clock_gettime(1337, &t)); ASSERT_EQ(UV_EFAULT, uv_clock_gettime(1337, NULL)); - ASSERT_EQ(0, uv_clock_gettime(UV_CLOCK_MONOTONIC, &t)); - ASSERT_EQ(0, uv_clock_gettime(UV_CLOCK_REALTIME, &t)); + ASSERT_OK(uv_clock_gettime(UV_CLOCK_MONOTONIC, &t)); + ASSERT_OK(uv_clock_gettime(UV_CLOCK_REALTIME, &t)); ASSERT_GT(1682500000000ll, t.tv_sec); /* 2023-04-26T09:06:40.000Z */ return 0; diff --git a/test/test-idle.c b/test/test-idle.c index e3f4c2bcb65..069e3483580 100644 --- a/test/test-idle.c +++ b/test/test-idle.c @@ -39,7 +39,7 @@ static void close_cb(uv_handle_t* handle) { static void timer_cb(uv_timer_t* handle) { - ASSERT(handle == &timer_handle); + ASSERT_PTR_EQ(handle, &timer_handle); uv_close((uv_handle_t*) &idle_handle, close_cb); uv_close((uv_handle_t*) &check_handle, close_cb); @@ -52,7 +52,7 @@ static void timer_cb(uv_timer_t* handle) { static void idle_cb(uv_idle_t* handle) { - ASSERT(handle == &idle_handle); + ASSERT_PTR_EQ(handle, &idle_handle); idle_cb_called++; fprintf(stderr, "idle_cb %d\n", idle_cb_called); @@ -61,7 +61,7 @@ static void idle_cb(uv_idle_t* handle) { static void check_cb(uv_check_t* handle) { - ASSERT(handle == &check_handle); + ASSERT_PTR_EQ(handle, &check_handle); check_cb_called++; fprintf(stderr, "check_cb %d\n", check_cb_called); @@ -73,26 +73,26 @@ TEST_IMPL(idle_starvation) { int r; r = uv_idle_init(uv_default_loop(), &idle_handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_idle_start(&idle_handle, idle_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_check_init(uv_default_loop(), &check_handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_check_start(&check_handle, check_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(uv_default_loop(), &timer_handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer_handle, timer_cb, 50, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(idle_cb_called > 0); - ASSERT(timer_cb_called == 1); - ASSERT(close_cb_called == 3); + ASSERT_GT(idle_cb_called, 0); + ASSERT_EQ(1, timer_cb_called); + ASSERT_EQ(3, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -105,19 +105,19 @@ static void idle_stop(uv_idle_t* handle) { TEST_IMPL(idle_check) { - ASSERT_EQ(0, uv_idle_init(uv_default_loop(), &idle_handle)); - ASSERT_EQ(0, uv_idle_start(&idle_handle, idle_stop)); + ASSERT_OK(uv_idle_init(uv_default_loop(), &idle_handle)); + ASSERT_OK(uv_idle_start(&idle_handle, idle_stop)); - ASSERT_EQ(0, uv_check_init(uv_default_loop(), &check_handle)); - ASSERT_EQ(0, uv_check_start(&check_handle, check_cb)); + ASSERT_OK(uv_check_init(uv_default_loop(), &check_handle)); + ASSERT_OK(uv_check_start(&check_handle, check_cb)); ASSERT_EQ(1, uv_run(uv_default_loop(), UV_RUN_ONCE)); ASSERT_EQ(1, check_cb_called); - ASSERT_EQ(0, close_cb_called); + ASSERT_OK(close_cb_called); uv_close((uv_handle_t*) &idle_handle, close_cb); uv_close((uv_handle_t*) &check_handle, close_cb); - ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); diff --git a/test/test-idna.c b/test/test-idna.c index 9b7002819fa..e6ebfe824e4 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -31,66 +31,66 @@ TEST_IMPL(utf8_decode1) { /* ASCII. */ p = b; snprintf(b, sizeof(b), "%c\x7F", 0x00); - ASSERT(0 == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 1); - ASSERT(127 == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 2); + ASSERT_OK(uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 1); + ASSERT_EQ(127, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 2); /* Two-byte sequences. */ p = b; snprintf(b, sizeof(b), "\xC2\x80\xDF\xBF"); - ASSERT(128 == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 2); - ASSERT(0x7FF == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 4); + ASSERT_EQ(128, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 2); + ASSERT_EQ(0x7FF, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 4); /* Three-byte sequences. */ p = b; snprintf(b, sizeof(b), "\xE0\xA0\x80\xEF\xBF\xBF"); - ASSERT(0x800 == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 3); - ASSERT(0xFFFF == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 6); + ASSERT_EQ(0x800, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 3); + ASSERT_EQ(0xFFFF, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 6); /* Four-byte sequences. */ p = b; snprintf(b, sizeof(b), "\xF0\x90\x80\x80\xF4\x8F\xBF\xBF"); - ASSERT(0x10000 == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 4); - ASSERT(0x10FFFF == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 8); + ASSERT_EQ(0x10000, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 4); + ASSERT_EQ(0x10FFFF, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 8); /* Four-byte sequences > U+10FFFF; disallowed. */ p = b; snprintf(b, sizeof(b), "\xF4\x90\xC0\xC0\xF7\xBF\xBF\xBF"); - ASSERT((unsigned) -1 == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 4); - ASSERT((unsigned) -1 == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 8); + ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 4); + ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 8); /* Overlong; disallowed. */ p = b; snprintf(b, sizeof(b), "\xC0\x80\xC1\x80"); - ASSERT((unsigned) -1 == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 2); - ASSERT((unsigned) -1 == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 4); + ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 2); + ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 4); /* Surrogate pairs; disallowed. */ p = b; snprintf(b, sizeof(b), "\xED\xA0\x80\xED\xA3\xBF"); - ASSERT((unsigned) -1 == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 3); - ASSERT((unsigned) -1 == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + 6); + ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 3); + ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + 6); /* Simply illegal. */ p = b; snprintf(b, sizeof(b), "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"); for (i = 1; i <= 8; i++) { - ASSERT((unsigned) -1 == uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT(p == b + i); + ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); + ASSERT_EQ(p, b + i); } return 0; @@ -122,7 +122,7 @@ TEST_IMPL(utf8_decode1_overrun) { do { \ char d[256] = {0}; \ static const char s[] = "" input ""; \ - ASSERT(err == uv__idna_toascii(s, s + sizeof(s) - 1, d, d + sizeof(d))); \ + ASSERT_EQ(err, uv__idna_toascii(s, s + sizeof(s) - 1, d, d + sizeof(d))); \ } while (0) #define T(input, expected) \ @@ -132,13 +132,13 @@ TEST_IMPL(utf8_decode1_overrun) { char d2[256] = {0}; \ static const char s[] = "" input ""; \ n = uv__idna_toascii(s, s + sizeof(s) - 1, d1, d1 + sizeof(d1)); \ - ASSERT(n == sizeof(expected)); \ - ASSERT(0 == memcmp(d1, expected, n)); \ + ASSERT_EQ(n, sizeof(expected)); \ + ASSERT_OK(memcmp(d1, expected, n)); \ /* Sanity check: encoding twice should not change the output. */ \ n = uv__idna_toascii(d1, d1 + strlen(d1), d2, d2 + sizeof(d2)); \ - ASSERT(n == sizeof(expected)); \ - ASSERT(0 == memcmp(d2, expected, n)); \ - ASSERT(0 == memcmp(d1, d2, sizeof(d2))); \ + ASSERT_EQ(n, sizeof(expected)); \ + ASSERT_OK(memcmp(d2, expected, n)); \ + ASSERT_OK(memcmp(d1, d2, sizeof(d2))); \ } while (0) TEST_IMPL(idna_toascii) { diff --git a/test/test-ip-name.c b/test/test-ip-name.c index 006095f5f97..cdc0c563427 100644 --- a/test/test-ip-name.c +++ b/test/test-ip-name.c @@ -40,20 +40,20 @@ TEST_IMPL(ip_name) { struct sockaddr_in6* addr6 = &test_addr.addr6; /* test ip4_name */ - ASSERT_EQ(0, uv_ip4_addr("192.168.0.1", TEST_PORT, addr4)); - ASSERT_EQ(0, uv_ip4_name(addr4, dst, INET_ADDRSTRLEN)); - ASSERT_EQ(0, strcmp("192.168.0.1", dst)); + ASSERT_OK(uv_ip4_addr("192.168.0.1", TEST_PORT, addr4)); + ASSERT_OK(uv_ip4_name(addr4, dst, INET_ADDRSTRLEN)); + ASSERT_OK(strcmp("192.168.0.1", dst)); - ASSERT_EQ(0, uv_ip_name(addr, dst, INET_ADDRSTRLEN)); - ASSERT_EQ(0, strcmp("192.168.0.1", dst)); + ASSERT_OK(uv_ip_name(addr, dst, INET_ADDRSTRLEN)); + ASSERT_OK(strcmp("192.168.0.1", dst)); /* test ip6_name */ - ASSERT_EQ(0, uv_ip6_addr("fe80::2acf:daff:fedd:342a", TEST_PORT, addr6)); - ASSERT_EQ(0, uv_ip6_name(addr6, dst, INET6_ADDRSTRLEN)); - ASSERT_EQ(0, strcmp("fe80::2acf:daff:fedd:342a", dst)); + ASSERT_OK(uv_ip6_addr("fe80::2acf:daff:fedd:342a", TEST_PORT, addr6)); + ASSERT_OK(uv_ip6_name(addr6, dst, INET6_ADDRSTRLEN)); + ASSERT_OK(strcmp("fe80::2acf:daff:fedd:342a", dst)); - ASSERT_EQ(0, uv_ip_name(addr, dst, INET6_ADDRSTRLEN)); - ASSERT_EQ(0, strcmp("fe80::2acf:daff:fedd:342a", dst)); + ASSERT_OK(uv_ip_name(addr, dst, INET6_ADDRSTRLEN)); + ASSERT_OK(strcmp("fe80::2acf:daff:fedd:342a", dst)); /* test other sa_family */ addr->sa_family = AF_UNIX; diff --git a/test/test-ip4-addr.c b/test/test-ip4-addr.c index 722ffb390a9..4a16c832d33 100644 --- a/test/test-ip4-addr.c +++ b/test/test-ip4-addr.c @@ -30,25 +30,25 @@ TEST_IMPL(ip4_addr) { struct sockaddr_in addr; char dst[16]; - ASSERT(0 == uv_inet_ntop(AF_INET, "\xFF\xFF\xFF\xFF", dst, sizeof(dst))); - ASSERT(0 == strcmp(dst, "255.255.255.255")); - ASSERT(UV_ENOSPC == uv_inet_ntop(AF_INET, "\xFF\xFF\xFF\xFF", - dst, sizeof(dst) - 1)); - - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT(0 == uv_ip4_addr("255.255.255.255", TEST_PORT, &addr)); - ASSERT(UV_EINVAL == uv_ip4_addr("255.255.255*000", TEST_PORT, &addr)); - ASSERT(UV_EINVAL == uv_ip4_addr("255.255.255.256", TEST_PORT, &addr)); - ASSERT(UV_EINVAL == uv_ip4_addr("2555.0.0.0", TEST_PORT, &addr)); - ASSERT(UV_EINVAL == uv_ip4_addr("255", TEST_PORT, &addr)); + ASSERT_OK(uv_inet_ntop(AF_INET, "\xFF\xFF\xFF\xFF", dst, sizeof(dst))); + ASSERT_OK(strcmp(dst, "255.255.255.255")); + ASSERT_EQ(UV_ENOSPC, uv_inet_ntop(AF_INET, "\xFF\xFF\xFF\xFF", + dst, sizeof(dst) - 1)); + + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("255.255.255.255", TEST_PORT, &addr)); + ASSERT_EQ(UV_EINVAL, uv_ip4_addr("255.255.255*000", TEST_PORT, &addr)); + ASSERT_EQ(UV_EINVAL, uv_ip4_addr("255.255.255.256", TEST_PORT, &addr)); + ASSERT_EQ(UV_EINVAL, uv_ip4_addr("2555.0.0.0", TEST_PORT, &addr)); + ASSERT_EQ(UV_EINVAL, uv_ip4_addr("255", TEST_PORT, &addr)); #ifdef SIN6_LEN - ASSERT(addr.sin_len == sizeof(addr)); + ASSERT_EQ(addr.sin_len, sizeof(addr)); #endif /* for broken address family */ - ASSERT(UV_EAFNOSUPPORT == uv_inet_pton(42, "127.0.0.1", - &addr.sin_addr.s_addr)); + ASSERT_EQ(UV_EAFNOSUPPORT, uv_inet_pton(42, "127.0.0.1", + &addr.sin_addr.s_addr)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-ip6-addr.c b/test/test-ip6-addr.c index 8f0c18601ba..632b7928994 100644 --- a/test/test-ip6-addr.c +++ b/test/test-ip6-addr.c @@ -51,7 +51,7 @@ TEST_IMPL(ip6_addr_link_local) { int ix; int r; - ASSERT(0 == uv_interface_addresses(&addresses, &count)); + ASSERT_OK(uv_interface_addresses(&addresses, &count)); for (ix = 0; ix < count; ix++) { address = addresses + ix; @@ -59,10 +59,10 @@ TEST_IMPL(ip6_addr_link_local) { if (address->address.address6.sin6_family != AF_INET6) continue; - ASSERT(0 == uv_inet_ntop(AF_INET6, - &address->address.address6.sin6_addr, - string_address, - sizeof(string_address))); + ASSERT_OK(uv_inet_ntop(AF_INET6, + &address->address.address6.sin6_addr, + string_address, + sizeof(string_address))); /* Skip addresses that are not link-local. */ if (strncmp(string_address, "fe80::", 6) != 0) @@ -72,21 +72,23 @@ TEST_IMPL(ip6_addr_link_local) { device_name = address->name; scoped_addr_len = sizeof(scoped_addr); - ASSERT(0 == uv_if_indextoname(iface_index, scoped_addr, &scoped_addr_len)); + ASSERT_OK(uv_if_indextoname(iface_index, + scoped_addr, + &scoped_addr_len)); #ifndef _WIN32 /* This assert fails on Windows, as Windows semantics are different. */ - ASSERT(0 == strcmp(device_name, scoped_addr)); + ASSERT_OK(strcmp(device_name, scoped_addr)); #endif interface_id_len = sizeof(interface_id); r = uv_if_indextoiid(iface_index, interface_id, &interface_id_len); - ASSERT(0 == r); + ASSERT_OK(r); #ifdef _WIN32 /* On Windows, the interface identifier is the numeric string of the index. */ - ASSERT(strtoul(interface_id, NULL, 10) == iface_index); + ASSERT_EQ(strtoul(interface_id, NULL, 10), iface_index); #else /* On Unix/Linux, the interface identifier is the interface device name. */ - ASSERT(0 == strcmp(device_name, interface_id)); + ASSERT_OK(strcmp(device_name, interface_id)); #endif snprintf(scoped_addr, @@ -102,16 +104,18 @@ TEST_IMPL(ip6_addr_link_local) { device_name); fflush(stderr); - ASSERT(0 == uv_ip6_addr(scoped_addr, TEST_PORT, &addr)); + ASSERT_OK(uv_ip6_addr(scoped_addr, TEST_PORT, &addr)); fprintf(stderr, "Got scope_id 0x%2x\n", (unsigned)addr.sin6_scope_id); fflush(stderr); - ASSERT(iface_index == addr.sin6_scope_id); + ASSERT_EQ(iface_index, addr.sin6_scope_id); } uv_free_interface_addresses(addresses, count); scoped_addr_len = sizeof(scoped_addr); - ASSERT(0 != uv_if_indextoname((unsigned int)-1, scoped_addr, &scoped_addr_len)); + ASSERT_NE(0, uv_if_indextoname((unsigned int)-1, + scoped_addr, + &scoped_addr_len)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -137,16 +141,16 @@ TEST_IMPL(ip6_addr_link_local) { X("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255.255") \ #define TEST_GOOD(ADDR) \ - ASSERT(0 == uv_inet_pton(AF_INET6, ADDR, &addr)); \ - ASSERT(0 == uv_inet_pton(AF_INET6, ADDR "%en1", &addr)); \ - ASSERT(0 == uv_inet_pton(AF_INET6, ADDR "%%%%", &addr)); \ - ASSERT(0 == uv_inet_pton(AF_INET6, ADDR "%en1:1.2.3.4", &addr)); \ + ASSERT_OK(uv_inet_pton(AF_INET6, ADDR, &addr)); \ + ASSERT_OK(uv_inet_pton(AF_INET6, ADDR "%en1", &addr)); \ + ASSERT_OK(uv_inet_pton(AF_INET6, ADDR "%%%%", &addr)); \ + ASSERT_OK(uv_inet_pton(AF_INET6, ADDR "%en1:1.2.3.4", &addr)); \ #define TEST_BAD(ADDR) \ - ASSERT(0 != uv_inet_pton(AF_INET6, ADDR, &addr)); \ - ASSERT(0 != uv_inet_pton(AF_INET6, ADDR "%en1", &addr)); \ - ASSERT(0 != uv_inet_pton(AF_INET6, ADDR "%%%%", &addr)); \ - ASSERT(0 != uv_inet_pton(AF_INET6, ADDR "%en1:1.2.3.4", &addr)); \ + ASSERT_NE(0, uv_inet_pton(AF_INET6, ADDR, &addr)); \ + ASSERT_NE(0, uv_inet_pton(AF_INET6, ADDR "%en1", &addr)); \ + ASSERT_NE(0, uv_inet_pton(AF_INET6, ADDR "%%%%", &addr)); \ + ASSERT_NE(0, uv_inet_pton(AF_INET6, ADDR "%en1:1.2.3.4", &addr)); \ TEST_IMPL(ip6_pton) { struct in6_addr addr; @@ -163,9 +167,9 @@ TEST_IMPL(ip6_pton) { TEST_IMPL(ip6_sin6_len) { struct sockaddr_in6 s; - ASSERT_EQ(0, uv_ip6_addr("::", 0, &s)); + ASSERT_OK(uv_ip6_addr("::", 0, &s)); #ifdef SIN6_LEN - ASSERT(s.sin6_len == sizeof(s)); + ASSERT_EQ(s.sin6_len, sizeof(s)); #endif return 0; } diff --git a/test/test-ipc-heavy-traffic-deadlock-bug.c b/test/test-ipc-heavy-traffic-deadlock-bug.c index f239d1fc01f..0305500abfb 100644 --- a/test/test-ipc-heavy-traffic-deadlock-bug.c +++ b/test/test-ipc-heavy-traffic-deadlock-bug.c @@ -49,7 +49,7 @@ static size_t bytes_read; static void write_cb(uv_write_t* req, int status) { struct write_info* write_info = container_of(req, struct write_info, write_req); - ASSERT(status == 0); + ASSERT_OK(status); bytes_written += BUFFERS_PER_WRITE * BUFFER_SIZE; free(write_info); } @@ -75,7 +75,7 @@ static void do_write(uv_stream_t* handle) { r = uv_write( &write_info->write_req, handle, bufs, BUFFERS_PER_WRITE, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static void alloc_cb(uv_handle_t* handle, @@ -94,18 +94,18 @@ static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { ssize_t i; int r; - ASSERT(nread >= 0); + ASSERT_GE(nread, 0); bytes_read += nread; for (i = 0; i < nread; i++) - ASSERT(buf->base[i] == BUFFER_CONTENT); + ASSERT_EQ(buf->base[i], BUFFER_CONTENT); free(buf->base); if (bytes_read >= XFER_SIZE) { r = uv_read_stop(handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_shutdown(&shutdown_req, handle, shutdown_cb); - ASSERT(r == 0); + ASSERT_OK(r); } } @@ -121,13 +121,13 @@ static void do_writes_and_reads(uv_stream_t* handle) { } r = uv_read_start(handle, alloc_cb, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(handle->loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(bytes_written == XFER_SIZE); - ASSERT(bytes_read == XFER_SIZE); + ASSERT_EQ(bytes_written, XFER_SIZE); + ASSERT_EQ(bytes_read, XFER_SIZE); } TEST_IMPL(ipc_heavy_traffic_deadlock_bug) { @@ -146,9 +146,9 @@ int ipc_helper_heavy_traffic_deadlock_bug(void) { int r; r = uv_pipe_init(uv_default_loop(), &pipe, 1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_open(&pipe, 0); - ASSERT(r == 0); + ASSERT_OK(r); notify_parent_process(); do_writes_and_reads((uv_stream_t*) &pipe); diff --git a/test/test-ipc-send-recv.c b/test/test-ipc-send-recv.c index 48eea7286b8..f24cc99fe8d 100644 --- a/test/test-ipc-send-recv.c +++ b/test/test-ipc-send-recv.c @@ -96,7 +96,7 @@ static void recv_cb(uv_stream_t* handle, free(buf->base); pipe = (uv_pipe_t*) handle; - ASSERT(pipe == &ctx.channel); + ASSERT_EQ(pipe, &ctx.channel); do { if (++recv_cb_count == 1) { @@ -112,13 +112,13 @@ static void recv_cb(uv_stream_t* handle, * acceptable value. */ if (nread == UV_EOF) { /* UV_EOF is only acceptable for the final recv_cb call */ - ASSERT(recv_cb_count == 2); + ASSERT_EQ(2, recv_cb_count); } else { - ASSERT(nread >= 0); - ASSERT(uv_pipe_pending_count(pipe) > 0); + ASSERT_GE(nread, 0); + ASSERT_GT(uv_pipe_pending_count(pipe), 0); pending = uv_pipe_pending_type(pipe); - ASSERT(pending == ctx.expected_type); + ASSERT_EQ(pending, ctx.expected_type); if (pending == UV_NAMED_PIPE) r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0); @@ -126,10 +126,10 @@ static void recv_cb(uv_stream_t* handle, r = uv_tcp_init(ctx.channel.loop, &recv->tcp); else abort(); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_accept(handle, &recv->stream); - ASSERT(r == 0); + ASSERT_OK(r); } } while (uv_pipe_pending_count(pipe) > 0); @@ -143,8 +143,8 @@ static void connect_cb(uv_connect_t* req, int status) { int r; uv_buf_t buf; - ASSERT(req == &ctx.connect_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &ctx.connect_req); + ASSERT_OK(status); buf = uv_buf_init(".", 1); r = uv_write2(&ctx.write_req, @@ -152,7 +152,7 @@ static void connect_cb(uv_connect_t* req, int status) { &buf, 1, &ctx.send.stream, NULL); - ASSERT(r == 0); + ASSERT_OK(r); /* Perform two writes to the same pipe to make sure that on Windows we are * not running into issue 505: @@ -163,10 +163,10 @@ static void connect_cb(uv_connect_t* req, int status) { &buf, 1, &ctx.send2.stream, NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static int run_test(int inprocess) { @@ -176,12 +176,12 @@ static int run_test(int inprocess) { if (inprocess) { r = uv_thread_create(&tid, ipc_send_recv_helper_threadproc, (void *) 42); - ASSERT(r == 0); + ASSERT_OK(r); uv_sleep(1000); r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1); - ASSERT(r == 0); + ASSERT_OK(r); uv_pipe_connect(&ctx.connect_req, &ctx.channel, TEST_PIPENAME_3, connect_cb); } else { @@ -191,13 +191,13 @@ static int run_test(int inprocess) { } r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(recv_cb_count == 2); + ASSERT_EQ(2, recv_cb_count); if (inprocess) { r = uv_thread_join(&tid); - ASSERT(r == 0); + ASSERT_OK(r); } return 0; @@ -209,19 +209,19 @@ static int run_ipc_send_recv_pipe(int inprocess) { ctx.expected_type = UV_NAMED_PIPE; r = uv_pipe_init(uv_default_loop(), &ctx.send.pipe, 1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_bind(&ctx.send.pipe, TEST_PIPENAME); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_init(uv_default_loop(), &ctx.send2.pipe, 1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_bind(&ctx.send2.pipe, TEST_PIPENAME_2); - ASSERT(r == 0); + ASSERT_OK(r); r = run_test(inprocess); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -245,24 +245,24 @@ static int run_ipc_send_recv_tcp(int inprocess) { struct sockaddr_in addr; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); ctx.expected_type = UV_TCP; r = uv_tcp_init(uv_default_loop(), &ctx.send.tcp); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_init(uv_default_loop(), &ctx.send2.tcp); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&ctx.send.tcp, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&ctx.send2.tcp, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = run_test(inprocess); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -286,7 +286,7 @@ TEST_IMPL(ipc_send_recv_tcp_inprocess) { /* Everything here runs in a child process or second thread. */ static void write2_cb(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); /* After two successful writes in the child process, allow the child * process to be closed. */ @@ -337,10 +337,10 @@ static void read_cb(uv_stream_t* handle, r = uv_tcp_init(ctx2.channel.loop, &recv->tcp); else abort(); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_accept(handle, &recv->stream); - ASSERT(r == 0); + ASSERT_OK(r); wrbuf = uv_buf_init(".", 1); r = uv_write2(write_req, @@ -349,27 +349,27 @@ static void read_cb(uv_stream_t* handle, 1, &recv->stream, write2_cb); - ASSERT(r == 0); + ASSERT_OK(r); } } static void send_recv_start(void) { int r; - ASSERT(1 == uv_is_readable((uv_stream_t*)&ctx2.channel)); - ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx2.channel)); - ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx2.channel)); + ASSERT_EQ(1, uv_is_readable((uv_stream_t*)&ctx2.channel)); + ASSERT_EQ(1, uv_is_writable((uv_stream_t*)&ctx2.channel)); + ASSERT_OK(uv_is_closing((uv_handle_t*)&ctx2.channel)); r = uv_read_start((uv_stream_t*)&ctx2.channel, alloc_cb, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static void listen_cb(uv_stream_t* handle, int status) { int r; - ASSERT(handle == (uv_stream_t*)&ctx2.listen); - ASSERT(status == 0); + ASSERT_PTR_EQ(handle, (uv_stream_t*)&ctx2.listen); + ASSERT_OK(status); r = uv_accept((uv_stream_t*)&ctx2.listen, (uv_stream_t*)&ctx2.channel); - ASSERT(r == 0); + ASSERT_OK(r); send_recv_start(); } @@ -382,27 +382,27 @@ int run_ipc_send_recv_helper(uv_loop_t* loop, int inprocess) { memset(&ctx2, 0, sizeof(ctx2)); r = uv_pipe_init(loop, &ctx2.listen, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_init(loop, &ctx2.channel, 1); - ASSERT(r == 0); + ASSERT_OK(r); if (inprocess) { r = uv_pipe_bind(&ctx2.listen, TEST_PIPENAME_3); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&ctx2.listen, SOMAXCONN, listen_cb); - ASSERT(r == 0); + ASSERT_OK(r); } else { r = uv_pipe_open(&ctx2.channel, 0); - ASSERT(r == 0); + ASSERT_OK(r); send_recv_start(); } notify_parent_process(); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); return 0; } @@ -414,7 +414,7 @@ int ipc_send_recv_helper(void) { int r; r = run_ipc_send_recv_helper(uv_default_loop(), 0); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -425,11 +425,11 @@ void ipc_send_recv_helper_threadproc(void* arg) { uv_loop_t loop; r = uv_loop_init(&loop); - ASSERT(r == 0); + ASSERT_OK(r); r = run_ipc_send_recv_helper(&loop, 1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_loop_close(&loop); - ASSERT(r == 0); + ASSERT_OK(r); } diff --git a/test/test-ipc.c b/test/test-ipc.c index 7ec6ec9ce3a..49975d9b4d7 100644 --- a/test/test-ipc.c +++ b/test/test-ipc.c @@ -68,16 +68,16 @@ static void on_connection(uv_stream_t* server, int status) { if (!local_conn_accepted) { /* Accept the connection and close it. Also and close the server. */ - ASSERT_EQ(status, 0); + ASSERT_OK(status); ASSERT_PTR_EQ(&tcp_server, server); conn = malloc(sizeof(*conn)); ASSERT_NOT_NULL(conn); r = uv_tcp_init(server->loop, conn); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_accept(server, (uv_stream_t*)conn); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_close((uv_handle_t*)conn, close_server_conn_cb); uv_close((uv_handle_t*)server, NULL); @@ -91,8 +91,8 @@ static void exit_cb(uv_process_t* process, int term_signal) { printf("exit_cb\n"); exit_cb_called++; - ASSERT_EQ(exit_status, 0); - ASSERT_EQ(term_signal, 0); + ASSERT_OK(exit_status); + ASSERT_OK(term_signal); uv_close((uv_handle_t*)process, NULL); } @@ -126,14 +126,14 @@ static void make_many_connections(void) { ASSERT_NOT_NULL(conn); r = uv_tcp_init(uv_default_loop(), &conn->conn); - ASSERT_EQ(r, 0); - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(r); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_connect(&conn->conn_req, (uv_tcp_t*) &conn->conn, (const struct sockaddr*) &addr, connect_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); conn->conn.data = conn; } @@ -179,13 +179,13 @@ static void on_read(uv_stream_t* handle, /* Accept the pending TCP server, and start listening on it. */ ASSERT_EQ(pending, UV_TCP); r = uv_tcp_init(uv_default_loop(), &tcp_server); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, on_connection); - ASSERT_EQ(r, 0); + ASSERT_OK(r); tcp_server_listening = 1; @@ -194,13 +194,13 @@ static void on_read(uv_stream_t* handle, outbuf = uv_buf_init("foobar\n", 7); r = uv_write(&write_req, (uv_stream_t*)pipe, &outbuf, 1, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); /* Create a bunch of connections to get both servers to accept. */ make_many_connections(); } else if (memcmp("accepted_connection\n", buf->base, nread) == 0) { /* Remote server has accepted a connection. Close the channel. */ - ASSERT_EQ(0, uv_pipe_pending_count(pipe)); + ASSERT_OK(uv_pipe_pending_count(pipe)); ASSERT_EQ(pending, UV_UNKNOWN_HANDLE); remote_conn_accepted = 1; uv_close((uv_handle_t*)&channel, NULL); @@ -248,28 +248,28 @@ static void on_read_listen_after_bound_twice(uv_stream_t* handle, /* Accept the first TCP server, and start listening on it. */ ASSERT_EQ(pending, UV_TCP); r = uv_tcp_init(uv_default_loop(), &tcp_server); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, on_connection); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } else if (read_cb_called == 2) { /* Accept the second TCP server, and start listening on it. */ ASSERT_EQ(pending, UV_TCP); r = uv_tcp_init(uv_default_loop(), &tcp_server2); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server2); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&tcp_server2, BACKLOG, on_connection); ASSERT_EQ(r, UV_EADDRINUSE); uv_close((uv_handle_t*)&tcp_server, NULL); uv_close((uv_handle_t*)&tcp_server2, NULL); - ASSERT_EQ(0, uv_pipe_pending_count(pipe)); + ASSERT_OK(uv_pipe_pending_count(pipe)); uv_close((uv_handle_t*)&channel, NULL); } @@ -288,12 +288,12 @@ void spawn_helper(uv_pipe_t* channel, uv_stdio_container_t stdio[3]; r = uv_pipe_init(uv_default_loop(), channel, 1); - ASSERT_EQ(r, 0); - ASSERT_NE(channel->ipc, 0); + ASSERT_OK(r); + ASSERT_NE(0, channel->ipc); exepath_size = sizeof(exepath); r = uv_exepath(exepath, &exepath_size); - ASSERT_EQ(r, 0); + ASSERT_OK(r); exepath[exepath_size] = '\0'; args[0] = exepath; @@ -315,12 +315,12 @@ void spawn_helper(uv_pipe_t* channel, stdio[2].data.fd = 2; r = uv_spawn(uv_default_loop(), process, &options); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } static void on_tcp_write(uv_write_t* req, int status) { - ASSERT_EQ(status, 0); + ASSERT_OK(status); ASSERT_PTR_EQ(req->handle, &tcp_connection); tcp_write_cb_called++; } @@ -385,10 +385,10 @@ static void on_read_connection(uv_stream_t* handle, /* Accept the pending TCP connection */ ASSERT_EQ(pending, UV_TCP); r = uv_tcp_init(uv_default_loop(), &tcp_connection); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_accept(handle, (uv_stream_t*)&tcp_connection); - ASSERT_EQ(r, 0); + ASSERT_OK(r); /* Make sure that the expected data is correctly multiplexed. */ ASSERT_MEM_EQ("hello\n", buf->base, nread); @@ -397,10 +397,10 @@ static void on_read_connection(uv_stream_t* handle, outbuf = uv_buf_init("world\n", 6); r = uv_write(&write_req, (uv_stream_t*)&tcp_connection, &outbuf, 1, on_tcp_write); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*)&tcp_connection, on_read_alloc, on_tcp_read); - ASSERT_EQ(r, 0); + ASSERT_OK(r); free(buf->base); } @@ -422,7 +422,7 @@ static int run_ipc_test(const char* helper, uv_read_cb read_cb) { uv_read_start((uv_stream_t*)&channel, on_alloc, read_cb); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(r, 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -434,10 +434,10 @@ TEST_IMPL(ipc_listen_before_write) { RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); #endif int r = run_ipc_test("ipc_helper_listen_before_write", on_read); - ASSERT_EQ(local_conn_accepted, 1); - ASSERT_EQ(remote_conn_accepted, 1); - ASSERT_EQ(read_cb_called, 1); - ASSERT_EQ(exit_cb_called, 1); + ASSERT_EQ(1, local_conn_accepted); + ASSERT_EQ(1, remote_conn_accepted); + ASSERT_EQ(1, read_cb_called); + ASSERT_EQ(1, exit_cb_called); return r; } @@ -447,10 +447,10 @@ TEST_IMPL(ipc_listen_after_write) { RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); #endif int r = run_ipc_test("ipc_helper_listen_after_write", on_read); - ASSERT_EQ(local_conn_accepted, 1); - ASSERT_EQ(remote_conn_accepted, 1); - ASSERT_EQ(read_cb_called, 1); - ASSERT_EQ(exit_cb_called, 1); + ASSERT_EQ(1, local_conn_accepted); + ASSERT_EQ(1, remote_conn_accepted); + ASSERT_EQ(1, read_cb_called); + ASSERT_EQ(1, exit_cb_called); return r; } @@ -460,10 +460,10 @@ TEST_IMPL(ipc_tcp_connection) { RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); #endif int r = run_ipc_test("ipc_helper_tcp_connection", on_read_connection); - ASSERT_EQ(read_cb_called, 1); - ASSERT_EQ(tcp_write_cb_called, 1); - ASSERT_EQ(tcp_read_cb_called, 1); - ASSERT_EQ(exit_cb_called, 1); + ASSERT_EQ(1, read_cb_called); + ASSERT_EQ(1, tcp_write_cb_called); + ASSERT_EQ(1, tcp_read_cb_called); + ASSERT_EQ(1, exit_cb_called); return r; } @@ -474,20 +474,20 @@ TEST_IMPL(listen_with_simultaneous_accepts) { int r; struct sockaddr_in addr; - ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_simultaneous_accepts(&server, 1); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL); - ASSERT_EQ(r, 0); - ASSERT_EQ(server.reqs_pending, 32); + ASSERT_OK(r); + ASSERT_EQ(32, server.reqs_pending); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -499,20 +499,20 @@ TEST_IMPL(listen_no_simultaneous_accepts) { int r; struct sockaddr_in addr; - ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_simultaneous_accepts(&server, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL); - ASSERT_EQ(r, 0); - ASSERT_EQ(server.reqs_pending, 1); + ASSERT_OK(r); + ASSERT_EQ(1, server.reqs_pending); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -523,8 +523,8 @@ TEST_IMPL(ipc_listen_after_bind_twice) { RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); #endif int r = run_ipc_test("ipc_helper_bind_twice", on_read_listen_after_bound_twice); - ASSERT_EQ(read_cb_called, 2); - ASSERT_EQ(exit_cb_called, 1); + ASSERT_EQ(2, read_cb_called); + ASSERT_EQ(1, exit_cb_called); return r; } #endif @@ -532,7 +532,7 @@ TEST_IMPL(ipc_listen_after_bind_twice) { TEST_IMPL(ipc_send_zero) { int r; r = run_ipc_test("ipc_helper_send_zero", on_read_send_zero); - ASSERT_EQ(r, 0); + ASSERT_OK(r); return 0; } @@ -563,7 +563,7 @@ static void tcp_connection_write_cb(uv_write_t* req, int status) { static void send_zero_write_cb(uv_write_t* req, int status) { - ASSERT_EQ(status, 0); + ASSERT_OK(status); send_zero_write++; } @@ -591,7 +591,7 @@ static void on_tcp_child_process_read(uv_stream_t* tcp, /* Write to the socket */ outbuf = uv_buf_init("hello again\n", 12); r = uv_write(&conn.tcp_write_req, tcp, &outbuf, 1, tcp_connection_write_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); tcp_conn_read_cb_called++; } @@ -600,9 +600,9 @@ static void on_tcp_child_process_read(uv_stream_t* tcp, static void connect_child_process_cb(uv_connect_t* req, int status) { int r; - ASSERT_EQ(status, 0); + ASSERT_OK(status); r = uv_read_start(req->handle, on_read_alloc, on_tcp_child_process_read); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } @@ -615,21 +615,21 @@ static void ipc_on_connection(uv_stream_t* server, int status) { * Accept the connection and close it. Also let the other * side know. */ - ASSERT_EQ(status, 0); + ASSERT_OK(status); ASSERT_PTR_EQ(&tcp_server, server); r = uv_tcp_init(server->loop, &conn.conn); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_accept(server, (uv_stream_t*)&conn.conn); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_close((uv_handle_t*)&conn.conn, close_cb); buf = uv_buf_init("accepted_connection\n", 20); r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1, NULL, conn_notify_write_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); connection_accepted = 1; } @@ -646,28 +646,28 @@ static void ipc_on_connection_tcp_conn(uv_stream_t* server, int status) { uv_buf_t buf; uv_tcp_t* conn; - ASSERT_EQ(status, 0); + ASSERT_OK(status); ASSERT_PTR_EQ(&tcp_server, server); conn = malloc(sizeof(*conn)); ASSERT_NOT_NULL(conn); r = uv_tcp_init(server->loop, conn); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_accept(server, (uv_stream_t*)conn); - ASSERT_EQ(r, 0); + ASSERT_OK(r); /* Send the accepted connection to the other process */ buf = uv_buf_init("hello\n", 6); r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1, (uv_stream_t*)conn, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) conn, on_read_alloc, on_tcp_child_process_read); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_close((uv_handle_t*)conn, close_and_free_cb); } @@ -682,44 +682,44 @@ int ipc_helper(int listen_after_write) { int r; uv_buf_t buf; - ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_pipe_init(uv_default_loop(), &channel, 1); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_pipe_open(&channel, 0); ASSERT_EQ(1, uv_is_readable((uv_stream_t*) &channel)); ASSERT_EQ(1, uv_is_writable((uv_stream_t*) &channel)); - ASSERT_EQ(0, uv_is_closing((uv_handle_t*) &channel)); + ASSERT_OK(uv_is_closing((uv_handle_t*) &channel)); r = uv_tcp_init(uv_default_loop(), &tcp_server); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); if (!listen_after_write) { r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } buf = uv_buf_init("hello\n", 6); r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1, (uv_stream_t*)&tcp_server, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); if (listen_after_write) { r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } notify_parent_process(); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(r, 0); + ASSERT_OK(r); - ASSERT_EQ(connection_accepted, 1); - ASSERT_EQ(close_cb_called, 3); + ASSERT_EQ(1, connection_accepted); + ASSERT_EQ(3, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -736,43 +736,43 @@ int ipc_helper_tcp_connection(void) { struct sockaddr_in addr; r = uv_pipe_init(uv_default_loop(), &channel, 1); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_pipe_open(&channel, 0); ASSERT_EQ(1, uv_is_readable((uv_stream_t*) &channel)); ASSERT_EQ(1, uv_is_writable((uv_stream_t*) &channel)); - ASSERT_EQ(0, uv_is_closing((uv_handle_t*) &channel)); + ASSERT_OK(uv_is_closing((uv_handle_t*) &channel)); r = uv_tcp_init(uv_default_loop(), &tcp_server); - ASSERT_EQ(r, 0); + ASSERT_OK(r); - ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection_tcp_conn); - ASSERT_EQ(r, 0); + ASSERT_OK(r); /* Make a connection to the server */ r = uv_tcp_init(uv_default_loop(), &conn.conn); - ASSERT_EQ(r, 0); + ASSERT_OK(r); - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_connect(&conn.conn_req, (uv_tcp_t*) &conn.conn, (const struct sockaddr*) &addr, connect_child_process_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(r, 0); + ASSERT_OK(r); - ASSERT_EQ(tcp_conn_read_cb_called, 1); - ASSERT_EQ(tcp_conn_write_cb_called, 1); - ASSERT_EQ(close_cb_called, 4); + ASSERT_EQ(1, tcp_conn_read_cb_called); + ASSERT_EQ(1, tcp_conn_write_cb_called); + ASSERT_EQ(4, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -787,38 +787,38 @@ int ipc_helper_bind_twice(void) { int r; uv_buf_t buf; - ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_pipe_init(uv_default_loop(), &channel, 1); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_pipe_open(&channel, 0); ASSERT_EQ(1, uv_is_readable((uv_stream_t*) &channel)); ASSERT_EQ(1, uv_is_writable((uv_stream_t*) &channel)); - ASSERT_EQ(0, uv_is_closing((uv_handle_t*) &channel)); + ASSERT_OK(uv_is_closing((uv_handle_t*) &channel)); buf = uv_buf_init("hello\n", 6); r = uv_tcp_init(uv_default_loop(), &tcp_server); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_init(uv_default_loop(), &tcp_server2); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_bind(&tcp_server2, (const struct sockaddr*) &addr, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1, (uv_stream_t*)&tcp_server, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_write2(&write_req2, (uv_stream_t*)&channel, &buf, 1, (uv_stream_t*)&tcp_server2, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(r, 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -831,13 +831,13 @@ int ipc_helper_send_zero(void) { zero_buf = uv_buf_init(0, 0); r = uv_pipe_init(uv_default_loop(), &channel, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_pipe_open(&channel, 0); ASSERT_EQ(1, uv_is_readable((uv_stream_t*) &channel)); ASSERT_EQ(1, uv_is_writable((uv_stream_t*) &channel)); - ASSERT_EQ(0, uv_is_closing((uv_handle_t*) &channel)); + ASSERT_OK(uv_is_closing((uv_handle_t*) &channel)); r = uv_write(&write_req, (uv_stream_t*)&channel, @@ -845,12 +845,12 @@ int ipc_helper_send_zero(void) { 1, send_zero_write_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(r, 0); + ASSERT_OK(r); - ASSERT_EQ(send_zero_write, 1); + ASSERT_EQ(1, send_zero_write); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-loop-alive.c b/test/test-loop-alive.c index 76a2b04cc9d..279cfc32270 100644 --- a/test/test-loop-alive.c +++ b/test/test-loop-alive.c @@ -37,7 +37,7 @@ static void work_cb(uv_work_t* req) { static void after_work_cb(uv_work_t* req, int status) { ASSERT(req); - ASSERT(status == 0); + ASSERT_OK(status); } @@ -51,16 +51,16 @@ TEST_IMPL(loop_alive) { ASSERT(uv_loop_alive(uv_default_loop())); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(!uv_loop_alive(uv_default_loop())); /* loops with requests are alive */ r = uv_queue_work(uv_default_loop(), &work_req, work_cb, after_work_cb); - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(uv_loop_alive(uv_default_loop())); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(!uv_loop_alive(uv_default_loop())); MAKE_VALGRIND_HAPPY(uv_default_loop()); diff --git a/test/test-loop-close.c b/test/test-loop-close.c index f5814796e8f..cd1b76ce1b0 100644 --- a/test/test-loop-close.c +++ b/test/test-loop-close.c @@ -35,23 +35,23 @@ TEST_IMPL(loop_close) { uv_loop_t loop; loop.data = &loop; - ASSERT(0 == uv_loop_init(&loop)); - ASSERT(loop.data == (void*) &loop); + ASSERT_OK(uv_loop_init(&loop)); + ASSERT_PTR_EQ(loop.data, (void*) &loop); uv_timer_init(&loop, &timer_handle); uv_timer_start(&timer_handle, timer_cb, 100, 100); - ASSERT(UV_EBUSY == uv_loop_close(&loop)); + ASSERT_EQ(UV_EBUSY, uv_loop_close(&loop)); uv_run(&loop, UV_RUN_DEFAULT); uv_close((uv_handle_t*) &timer_handle, NULL); r = uv_run(&loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(loop.data == (void*) &loop); - ASSERT(0 == uv_loop_close(&loop)); - ASSERT(loop.data == (void*) &loop); + ASSERT_PTR_EQ(loop.data, (void*) &loop); + ASSERT_OK(uv_loop_close(&loop)); + ASSERT_PTR_EQ(loop.data, (void*) &loop); return 0; } @@ -67,11 +67,11 @@ static void loop_instant_close_after_work_cb(uv_work_t* req, int status) { TEST_IMPL(loop_instant_close) { static uv_loop_t loop; static uv_work_t req; - ASSERT(0 == uv_loop_init(&loop)); - ASSERT(0 == uv_queue_work(&loop, - &req, - loop_instant_close_work_cb, - loop_instant_close_after_work_cb)); + ASSERT_OK(uv_loop_init(&loop)); + ASSERT_OK(uv_queue_work(&loop, + &req, + loop_instant_close_work_cb, + loop_instant_close_after_work_cb)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-loop-configure.c b/test/test-loop-configure.c index d057c1ed8a7..1bc328431c9 100644 --- a/test/test-loop-configure.c +++ b/test/test-loop-configure.c @@ -24,15 +24,15 @@ static void timer_cb(uv_timer_t* handle) { TEST_IMPL(loop_configure) { uv_timer_t timer_handle; uv_loop_t loop; - ASSERT(0 == uv_loop_init(&loop)); + ASSERT_OK(uv_loop_init(&loop)); #ifdef _WIN32 - ASSERT(UV_ENOSYS == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, 0)); + ASSERT_EQ(UV_ENOSYS, uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, 0)); #else - ASSERT(0 == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, SIGPROF)); + ASSERT_OK(uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, SIGPROF)); #endif - ASSERT(0 == uv_timer_init(&loop, &timer_handle)); - ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 10, 0)); - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); - ASSERT(0 == uv_loop_close(&loop)); + ASSERT_OK(uv_timer_init(&loop, &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, 10, 0)); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_loop_close(&loop)); return 0; } diff --git a/test/test-loop-handles.c b/test/test-loop-handles.c index 5d3df0245aa..58368bf73ce 100644 --- a/test/test-loop-handles.c +++ b/test/test-loop-handles.c @@ -108,7 +108,7 @@ static int idle_2_is_active = 0; static void timer_cb(uv_timer_t* handle) { - ASSERT(handle == &timer_handle); + ASSERT_PTR_EQ(handle, &timer_handle); } @@ -116,7 +116,7 @@ static void idle_2_close_cb(uv_handle_t* handle) { fprintf(stderr, "%s", "IDLE_2_CLOSE_CB\n"); fflush(stderr); - ASSERT(handle == (uv_handle_t*)&idle_2_handle); + ASSERT_PTR_EQ(handle, (uv_handle_t*)&idle_2_handle); ASSERT(idle_2_is_active); @@ -129,7 +129,7 @@ static void idle_2_cb(uv_idle_t* handle) { fprintf(stderr, "%s", "IDLE_2_CB\n"); fflush(stderr); - ASSERT(handle == &idle_2_handle); + ASSERT_PTR_EQ(handle, &idle_2_handle); idle_2_cb_called++; @@ -144,14 +144,14 @@ static void idle_1_cb(uv_idle_t* handle) { fflush(stderr); ASSERT_NOT_NULL(handle); - ASSERT(idles_1_active > 0); + ASSERT_GT(idles_1_active, 0); /* Init idle_2 and make it active */ if (!idle_2_is_active && !uv_is_closing((uv_handle_t*)&idle_2_handle)) { r = uv_idle_init(uv_default_loop(), &idle_2_handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_idle_start(&idle_2_handle, idle_2_cb); - ASSERT(r == 0); + ASSERT_OK(r); idle_2_is_active = 1; idle_2_cb_started++; } @@ -160,7 +160,7 @@ static void idle_1_cb(uv_idle_t* handle) { if (idle_1_cb_called % 5 == 0) { r = uv_idle_stop((uv_idle_t*)handle); - ASSERT(r == 0); + ASSERT_OK(r); idles_1_active--; } } @@ -179,7 +179,7 @@ static void idle_1_close_cb(uv_handle_t* handle) { static void prepare_1_close_cb(uv_handle_t* handle) { fprintf(stderr, "%s", "PREPARE_1_CLOSE_CB"); fflush(stderr); - ASSERT(handle == (uv_handle_t*)&prepare_1_handle); + ASSERT_PTR_EQ(handle, (uv_handle_t*)&prepare_1_handle); prepare_1_close_cb_called++; } @@ -188,7 +188,7 @@ static void prepare_1_close_cb(uv_handle_t* handle) { static void check_close_cb(uv_handle_t* handle) { fprintf(stderr, "%s", "CHECK_CLOSE_CB\n"); fflush(stderr); - ASSERT(handle == (uv_handle_t*)&check_handle); + ASSERT_PTR_EQ(handle, (uv_handle_t*)&check_handle); check_close_cb_called++; } @@ -197,7 +197,7 @@ static void check_close_cb(uv_handle_t* handle) { static void prepare_2_close_cb(uv_handle_t* handle) { fprintf(stderr, "%s", "PREPARE_2_CLOSE_CB\n"); fflush(stderr); - ASSERT(handle == (uv_handle_t*)&prepare_2_handle); + ASSERT_PTR_EQ(handle, (uv_handle_t*)&prepare_2_handle); prepare_2_close_cb_called++; } @@ -208,13 +208,13 @@ static void check_cb(uv_check_t* handle) { fprintf(stderr, "%s", "CHECK_CB\n"); fflush(stderr); - ASSERT(handle == &check_handle); + ASSERT_PTR_EQ(handle, &check_handle); if (loop_iteration < ITERATIONS) { /* Make some idle watchers active */ for (i = 0; i < 1 + (loop_iteration % IDLE_COUNT); i++) { r = uv_idle_start(&idle_1_handles[i], idle_1_cb); - ASSERT(r == 0); + ASSERT_OK(r); idles_1_active++; } @@ -244,16 +244,16 @@ static void prepare_2_cb(uv_prepare_t* handle) { fprintf(stderr, "%s", "PREPARE_2_CB\n"); fflush(stderr); - ASSERT(handle == &prepare_2_handle); + ASSERT_PTR_EQ(handle, &prepare_2_handle); /* Prepare_2 gets started by prepare_1 when (loop_iteration % 2 == 0), and it * stops itself immediately. A started watcher is not queued until the next * round, so when this callback is made (loop_iteration % 2 == 0) cannot be * true. */ - ASSERT(loop_iteration % 2 != 0); + ASSERT_NE(0, loop_iteration % 2); r = uv_prepare_stop((uv_prepare_t*)handle); - ASSERT(r == 0); + ASSERT_OK(r); prepare_2_cb_called++; } @@ -264,11 +264,11 @@ static void prepare_1_cb(uv_prepare_t* handle) { fprintf(stderr, "%s", "PREPARE_1_CB\n"); fflush(stderr); - ASSERT(handle == &prepare_1_handle); + ASSERT_PTR_EQ(handle, &prepare_1_handle); if (loop_iteration % 2 == 0) { r = uv_prepare_start(&prepare_2_handle, prepare_2_cb); - ASSERT(r == 0); + ASSERT_OK(r); } prepare_1_cb_called++; @@ -283,23 +283,23 @@ TEST_IMPL(loop_handles) { int r; r = uv_prepare_init(uv_default_loop(), &prepare_1_handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_prepare_start(&prepare_1_handle, prepare_1_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_check_init(uv_default_loop(), &check_handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_check_start(&check_handle, check_cb); - ASSERT(r == 0); + ASSERT_OK(r); /* initialize only, prepare_2 is started by prepare_1_cb */ r = uv_prepare_init(uv_default_loop(), &prepare_2_handle); - ASSERT(r == 0); + ASSERT_OK(r); for (i = 0; i < IDLE_COUNT; i++) { /* initialize only, idle_1 handles are started by check_cb */ r = uv_idle_init(uv_default_loop(), &idle_1_handles[i]); - ASSERT(r == 0); + ASSERT_OK(r); } /* don't init or start idle_2, both is done by idle_1_cb */ @@ -307,30 +307,30 @@ TEST_IMPL(loop_handles) { /* The timer callback is there to keep the event loop polling unref it as it * is not supposed to keep the loop alive */ r = uv_timer_init(uv_default_loop(), &timer_handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer_handle, timer_cb, TIMEOUT, TIMEOUT); - ASSERT(r == 0); + ASSERT_OK(r); uv_unref((uv_handle_t*)&timer_handle); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(loop_iteration == ITERATIONS); + ASSERT_EQ(loop_iteration, ITERATIONS); - ASSERT(prepare_1_cb_called == ITERATIONS); - ASSERT(prepare_1_close_cb_called == 1); + ASSERT_EQ(prepare_1_cb_called, ITERATIONS); + ASSERT_EQ(1, prepare_1_close_cb_called); - ASSERT(prepare_2_cb_called == ITERATIONS / 2); - ASSERT(prepare_2_close_cb_called == 1); + ASSERT_EQ(prepare_2_cb_called, ITERATIONS / 2); + ASSERT_EQ(1, prepare_2_close_cb_called); - ASSERT(check_cb_called == ITERATIONS); - ASSERT(check_close_cb_called == 1); + ASSERT_EQ(check_cb_called, ITERATIONS); + ASSERT_EQ(1, check_close_cb_called); /* idle_1_cb should be called a lot */ - ASSERT(idle_1_close_cb_called == IDLE_COUNT); + ASSERT_EQ(idle_1_close_cb_called, IDLE_COUNT); - ASSERT(idle_2_close_cb_called == idle_2_cb_started); - ASSERT(idle_2_is_active == 0); + ASSERT_EQ(idle_2_close_cb_called, idle_2_cb_started); + ASSERT_OK(idle_2_is_active); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-loop-stop.c b/test/test-loop-stop.c index 981d20d1099..a00a5b81ade 100644 --- a/test/test-loop-stop.c +++ b/test/test-loop-stop.c @@ -30,7 +30,7 @@ static int num_ticks = 10; static void prepare_cb(uv_prepare_t* handle) { - ASSERT(handle == &prepare_handle); + ASSERT_PTR_EQ(handle, &prepare_handle); prepare_called++; if (prepare_called == num_ticks) uv_prepare_stop(handle); @@ -38,7 +38,7 @@ static void prepare_cb(uv_prepare_t* handle) { static void timer_cb(uv_timer_t* handle) { - ASSERT(handle == &timer_handle); + ASSERT_PTR_EQ(handle, &timer_handle); timer_called++; if (timer_called == 1) uv_stop(uv_default_loop()); @@ -55,17 +55,17 @@ TEST_IMPL(loop_stop) { uv_timer_start(&timer_handle, timer_cb, 100, 100); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r != 0); - ASSERT(timer_called == 1); + ASSERT(r); + ASSERT_EQ(1, timer_called); r = uv_run(uv_default_loop(), UV_RUN_NOWAIT); - ASSERT(r != 0); - ASSERT(prepare_called > 1); + ASSERT(r); + ASSERT_GT(prepare_called, 1); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); - ASSERT(timer_called == 10); - ASSERT(prepare_called == 10); + ASSERT_OK(r); + ASSERT_EQ(10, timer_called); + ASSERT_EQ(10, prepare_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -76,7 +76,7 @@ TEST_IMPL(loop_stop_before_run) { ASSERT_OK(uv_timer_init(uv_default_loop(), &timer_handle)); ASSERT_OK(uv_timer_start(&timer_handle, (uv_timer_cb) abort, 0, 0)); uv_stop(uv_default_loop()); - ASSERT_NE(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0); + ASSERT_NE(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-loop-time.c b/test/test-loop-time.c index 5d083064ae3..01e44ffbdad 100644 --- a/test/test-loop-time.c +++ b/test/test-loop-time.c @@ -28,7 +28,7 @@ TEST_IMPL(loop_update_time) { start = uv_now(uv_default_loop()); while (uv_now(uv_default_loop()) - start < 1000) - ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_NOWAIT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -46,23 +46,23 @@ TEST_IMPL(loop_backend_timeout) { /* The default loop has some internal watchers to initialize. */ loop->active_handles++; r = uv_run(loop, UV_RUN_NOWAIT); - ASSERT_EQ(r, 1); + ASSERT_EQ(1, r); loop->active_handles--; - ASSERT_EQ(uv_loop_alive(loop), 0); + ASSERT_OK(uv_loop_alive(loop)); r = uv_timer_init(loop, &timer); - ASSERT_EQ(r, 0); + ASSERT_OK(r); - ASSERT_EQ(uv_loop_alive(loop), 0); - ASSERT_EQ(uv_backend_timeout(loop), 0); + ASSERT_OK(uv_loop_alive(loop)); + ASSERT_OK(uv_backend_timeout(loop)); r = uv_timer_start(&timer, cb, 1000, 0); /* 1 sec */ - ASSERT_EQ(r, 0); - ASSERT_EQ(uv_backend_timeout(loop), 1000); + ASSERT_OK(r); + ASSERT_EQ(1000, uv_backend_timeout(loop)); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT_EQ(r, 0); - ASSERT_EQ(uv_backend_timeout(loop), 0); + ASSERT_OK(r); + ASSERT_OK(uv_backend_timeout(loop)); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-metrics.c b/test/test-metrics.c index d532f4eff49..c7c73aa53d7 100644 --- a/test/test-metrics.c +++ b/test/test-metrics.c @@ -59,11 +59,11 @@ TEST_IMPL(metrics_idle_time) { cntr = 0; timer.data = &cntr; - ASSERT_EQ(0, uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME)); - ASSERT_EQ(0, uv_timer_init(uv_default_loop(), &timer)); - ASSERT_EQ(0, uv_timer_start(&timer, timer_spin_cb, timeout, 0)); + ASSERT_OK(uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer)); + ASSERT_OK(uv_timer_start(&timer, timer_spin_cb, timeout, 0)); - ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT_GT(cntr, 0); idle_time = uv_metrics_idle_time(uv_default_loop()); @@ -87,12 +87,12 @@ static void metrics_routine_cb(void* arg) { cntr = 0; timer.data = &cntr; - ASSERT_EQ(0, uv_loop_init(&loop)); - ASSERT_EQ(0, uv_loop_configure(&loop, UV_METRICS_IDLE_TIME)); - ASSERT_EQ(0, uv_timer_init(&loop, &timer)); - ASSERT_EQ(0, uv_timer_start(&timer, timer_spin_cb, timeout, 0)); + ASSERT_OK(uv_loop_init(&loop)); + ASSERT_OK(uv_loop_configure(&loop, UV_METRICS_IDLE_TIME)); + ASSERT_OK(uv_timer_init(&loop, &timer)); + ASSERT_OK(uv_timer_start(&timer, timer_spin_cb, timeout, 0)); - ASSERT_EQ(0, uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); ASSERT_GT(cntr, 0); idle_time = uv_metrics_idle_time(&loop); @@ -104,7 +104,7 @@ static void metrics_routine_cb(void* arg) { ASSERT_GE(idle_time, (timeout - 500) * UV_NS_TO_MS); close_loop(&loop); - ASSERT_EQ(0, uv_loop_close(&loop)); + ASSERT_OK(uv_loop_close(&loop)); } @@ -113,7 +113,7 @@ TEST_IMPL(metrics_idle_time_thread) { int i; for (i = 0; i < 5; i++) { - ASSERT_EQ(0, uv_thread_create(&threads[i], metrics_routine_cb, NULL)); + ASSERT_OK(uv_thread_create(&threads[i], metrics_routine_cb, NULL)); } for (i = 0; i < 5; i++) { @@ -136,16 +136,16 @@ TEST_IMPL(metrics_idle_time_zero) { cntr = 0; timer.data = &cntr; - ASSERT_EQ(0, uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME)); - ASSERT_EQ(0, uv_timer_init(uv_default_loop(), &timer)); - ASSERT_EQ(0, uv_timer_start(&timer, timer_noop_cb, 0, 0)); + ASSERT_OK(uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer)); + ASSERT_OK(uv_timer_start(&timer, timer_noop_cb, 0, 0)); - ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT_GT(cntr, 0); - ASSERT_EQ(0, uv_metrics_idle_time(uv_default_loop())); + ASSERT_OK(uv_metrics_idle_time(uv_default_loop())); - ASSERT_EQ(0, uv_metrics_info(uv_default_loop(), &metrics)); + ASSERT_OK(uv_metrics_info(uv_default_loop(), &metrics)); ASSERT_UINT64_EQ(cntr, metrics.loop_count); MAKE_VALGRIND_HAPPY(uv_default_loop()); @@ -156,7 +156,7 @@ TEST_IMPL(metrics_idle_time_zero) { static void close_cb(uv_fs_t* req) { uv_metrics_t metrics; - ASSERT_EQ(0, uv_metrics_info(uv_default_loop(), &metrics)); + ASSERT_OK(uv_metrics_info(uv_default_loop(), &metrics)); ASSERT_UINT64_EQ(3, metrics.loop_count); ASSERT_UINT64_GT(metrics.events, last_events_count); @@ -168,7 +168,7 @@ static void close_cb(uv_fs_t* req) { static void write_cb(uv_fs_t* req) { uv_metrics_t metrics; - ASSERT_EQ(0, uv_metrics_info(uv_default_loop(), &metrics)); + ASSERT_OK(uv_metrics_info(uv_default_loop(), &metrics)); ASSERT_UINT64_EQ(2, metrics.loop_count); ASSERT_UINT64_GT(metrics.events, last_events_count); ASSERT_EQ(req->result, sizeof(test_buf)); @@ -176,17 +176,17 @@ static void write_cb(uv_fs_t* req) { uv_fs_req_cleanup(req); last_events_count = metrics.events; - ASSERT_EQ(0, uv_fs_close(uv_default_loop(), - &fs_reqs.close_req, - fs_reqs.open_req.result, - close_cb)); + ASSERT_OK(uv_fs_close(uv_default_loop(), + &fs_reqs.close_req, + fs_reqs.open_req.result, + close_cb)); } static void create_cb(uv_fs_t* req) { uv_metrics_t metrics; - ASSERT_EQ(0, uv_metrics_info(uv_default_loop(), &metrics)); + ASSERT_OK(uv_metrics_info(uv_default_loop(), &metrics)); /* Event count here is still 0 so not going to check. */ ASSERT_UINT64_EQ(1, metrics.loop_count); ASSERT_GE(req->result, 0); @@ -195,13 +195,13 @@ static void create_cb(uv_fs_t* req) { last_events_count = metrics.events; uv_buf_t iov = uv_buf_init(test_buf, sizeof(test_buf)); - ASSERT_EQ(0, uv_fs_write(uv_default_loop(), - &fs_reqs.write_req, - req->result, - &iov, - 1, - 0, - write_cb)); + ASSERT_OK(uv_fs_write(uv_default_loop(), + &fs_reqs.write_req, + req->result, + &iov, + 1, + 0, + write_cb)); } @@ -210,15 +210,15 @@ static void prepare_cb(uv_prepare_t* handle) { uv_prepare_stop(handle); - ASSERT_EQ(0, uv_metrics_info(uv_default_loop(), &metrics)); + ASSERT_OK(uv_metrics_info(uv_default_loop(), &metrics)); ASSERT_UINT64_EQ(0, metrics.loop_count); ASSERT_UINT64_EQ(0, metrics.events); - ASSERT_EQ(0, uv_fs_open(uv_default_loop(), - &fs_reqs.open_req, - "test_file", - O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR, - create_cb)); + ASSERT_OK(uv_fs_open(uv_default_loop(), + &fs_reqs.open_req, + "test_file", + O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR, + create_cb)); } @@ -229,10 +229,10 @@ TEST_IMPL(metrics_info_check) { uv_fs_unlink(NULL, &unlink_req, "test_file", NULL); uv_fs_req_cleanup(&unlink_req); - ASSERT_EQ(0, uv_prepare_init(uv_default_loop(), &prepare)); - ASSERT_EQ(0, uv_prepare_start(&prepare, prepare_cb)); + ASSERT_OK(uv_prepare_init(uv_default_loop(), &prepare)); + ASSERT_OK(uv_prepare_start(&prepare, prepare_cb)); - ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); uv_fs_unlink(NULL, &unlink_req, "test_file", NULL); uv_fs_req_cleanup(&unlink_req); diff --git a/test/test-multiple-listen.c b/test/test-multiple-listen.c index bbaa9bc1ef1..47f35f6c058 100644 --- a/test/test-multiple-listen.c +++ b/test/test-multiple-listen.c @@ -38,7 +38,7 @@ static void close_cb(uv_handle_t* handle) { static void connection_cb(uv_stream_t* tcp, int status) { - ASSERT(status == 0); + ASSERT_OK(status); uv_close((uv_handle_t*)&server, close_cb); connection_cb_called++; } @@ -48,25 +48,25 @@ static void start_server(void) { struct sockaddr_in addr; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server, 128, connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server, 128, connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static void connect_cb(uv_connect_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); free(req); uv_close((uv_handle_t*)&client, close_cb); connect_cb_called++; @@ -78,17 +78,17 @@ static void client_connect(void) { uv_connect_t* connect_req = malloc(sizeof *connect_req); int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); ASSERT_NOT_NULL(connect_req); r = uv_tcp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(connect_req, &client, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -100,9 +100,9 @@ TEST_IMPL(multiple_listen) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(connection_cb_called == 1); - ASSERT(connect_cb_called == 1); - ASSERT(close_cb_called == 2); + ASSERT_EQ(1, connection_cb_called); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-mutexes.c b/test/test-mutexes.c index 975222ca122..ca3377324b2 100644 --- a/test/test-mutexes.c +++ b/test/test-mutexes.c @@ -40,7 +40,7 @@ TEST_IMPL(thread_mutex) { int r; r = uv_mutex_init(&mutex); - ASSERT(r == 0); + ASSERT_OK(r); uv_mutex_lock(&mutex); uv_mutex_unlock(&mutex); @@ -55,11 +55,11 @@ TEST_IMPL(thread_mutex_recursive) { int r; r = uv_mutex_init_recursive(&mutex); - ASSERT(r == 0); + ASSERT_OK(r); uv_mutex_lock(&mutex); uv_mutex_lock(&mutex); - ASSERT(0 == uv_mutex_trylock(&mutex)); + ASSERT_OK(uv_mutex_trylock(&mutex)); uv_mutex_unlock(&mutex); uv_mutex_unlock(&mutex); @@ -75,7 +75,7 @@ TEST_IMPL(thread_rwlock) { int r; r = uv_rwlock_init(&rwlock); - ASSERT(r == 0); + ASSERT_OK(r); uv_rwlock_rdlock(&rwlock); uv_rwlock_rdunlock(&rwlock); @@ -101,7 +101,7 @@ static void synchronize(void) { synchronize_nowait(); /* Wait for the other thread. Guard against spurious wakeups. */ for (current = step; current == step; uv_cond_wait(&condvar, &mutex)); - ASSERT(step == current + 1); + ASSERT_EQ(step, current + 1); } @@ -111,23 +111,23 @@ static void thread_rwlock_trylock_peer(void* unused) { uv_mutex_lock(&mutex); /* Write lock held by other thread. */ - ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock)); - ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); + ASSERT_EQ(UV_EBUSY, uv_rwlock_tryrdlock(&rwlock)); + ASSERT_EQ(UV_EBUSY, uv_rwlock_trywrlock(&rwlock)); synchronize(); /* Read lock held by other thread. */ - ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); + ASSERT_OK(uv_rwlock_tryrdlock(&rwlock)); uv_rwlock_rdunlock(&rwlock); - ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); + ASSERT_EQ(UV_EBUSY, uv_rwlock_trywrlock(&rwlock)); synchronize(); /* Acquire write lock. */ - ASSERT(0 == uv_rwlock_trywrlock(&rwlock)); + ASSERT_OK(uv_rwlock_trywrlock(&rwlock)); synchronize(); /* Release write lock and acquire read lock. */ uv_rwlock_wrunlock(&rwlock); - ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); + ASSERT_OK(uv_rwlock_tryrdlock(&rwlock)); synchronize(); uv_rwlock_rdunlock(&rwlock); @@ -139,22 +139,22 @@ static void thread_rwlock_trylock_peer(void* unused) { TEST_IMPL(thread_rwlock_trylock) { uv_thread_t thread; - ASSERT(0 == uv_cond_init(&condvar)); - ASSERT(0 == uv_mutex_init(&mutex)); - ASSERT(0 == uv_rwlock_init(&rwlock)); + ASSERT_OK(uv_cond_init(&condvar)); + ASSERT_OK(uv_mutex_init(&mutex)); + ASSERT_OK(uv_rwlock_init(&rwlock)); uv_mutex_lock(&mutex); - ASSERT(0 == uv_thread_create(&thread, thread_rwlock_trylock_peer, NULL)); + ASSERT_OK(uv_thread_create(&thread, thread_rwlock_trylock_peer, NULL)); /* Hold write lock. */ - ASSERT(0 == uv_rwlock_trywrlock(&rwlock)); + ASSERT_OK(uv_rwlock_trywrlock(&rwlock)); synchronize(); /* Releases the mutex to the other thread. */ /* Release write lock and acquire read lock. Pthreads doesn't support * the notion of upgrading or downgrading rwlocks, so neither do we. */ uv_rwlock_wrunlock(&rwlock); - ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); + ASSERT_OK(uv_rwlock_tryrdlock(&rwlock)); synchronize(); /* Release read lock. */ @@ -162,17 +162,17 @@ TEST_IMPL(thread_rwlock_trylock) { synchronize(); /* Write lock held by other thread. */ - ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock)); - ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); + ASSERT_EQ(UV_EBUSY, uv_rwlock_tryrdlock(&rwlock)); + ASSERT_EQ(UV_EBUSY, uv_rwlock_trywrlock(&rwlock)); synchronize(); /* Read lock held by other thread. */ - ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); + ASSERT_OK(uv_rwlock_tryrdlock(&rwlock)); uv_rwlock_rdunlock(&rwlock); - ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); + ASSERT_EQ(UV_EBUSY, uv_rwlock_trywrlock(&rwlock)); synchronize(); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); uv_rwlock_destroy(&rwlock); uv_mutex_unlock(&mutex); uv_mutex_destroy(&mutex); diff --git a/test/test-not-readable-nor-writable-on-read-error.c b/test/test-not-readable-nor-writable-on-read-error.c index 823a4e91e29..2c45a2da2e8 100644 --- a/test/test-not-readable-nor-writable-on-read-error.c +++ b/test/test-not-readable-nor-writable-on-read-error.c @@ -35,7 +35,7 @@ static int close_cb_called; static void write_cb(uv_write_t* req, int status) { write_cb_called++; - ASSERT(status == 0); + ASSERT_OK(status); } static void alloc_cb(uv_handle_t* handle, @@ -54,8 +54,8 @@ static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { read_cb_called++; ASSERT((nread < 0) && (nread != UV_EOF)); - ASSERT(0 == uv_is_writable(handle)); - ASSERT(0 == uv_is_readable(handle)); + ASSERT_OK(uv_is_writable(handle)); + ASSERT_OK(uv_is_readable(handle)); uv_close((uv_handle_t*) handle, close_cb); } @@ -65,10 +65,10 @@ static void connect_cb(uv_connect_t* req, int status) { uv_buf_t reset_me; connect_cb_called++; - ASSERT(status == 0); + ASSERT_OK(status); r = uv_read_start((uv_stream_t*) &tcp_client, alloc_cb, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); reset_me = uv_buf_init(reset_me_cmd, sizeof(reset_me_cmd)); @@ -78,26 +78,26 @@ static void connect_cb(uv_connect_t* req, int status) { 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); } TEST_IMPL(not_readable_nor_writable_on_read_error) { struct sockaddr_in sa; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &sa)); - ASSERT(0 == uv_loop_init(&loop)); - ASSERT(0 == uv_tcp_init(&loop, &tcp_client)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &sa)); + ASSERT_OK(uv_loop_init(&loop)); + ASSERT_OK(uv_tcp_init(&loop, &tcp_client)); - ASSERT(0 == uv_tcp_connect(&connect_req, - &tcp_client, - (const struct sockaddr*) &sa, - connect_cb)); + ASSERT_OK(uv_tcp_connect(&connect_req, + &tcp_client, + (const struct sockaddr*) &sa, + connect_cb)); - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); - ASSERT(connect_cb_called == 1); - ASSERT(read_cb_called == 1); - ASSERT(write_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, read_cb_called); + ASSERT_EQ(1, write_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(&loop); return 0; diff --git a/test/test-not-writable-after-shutdown.c b/test/test-not-writable-after-shutdown.c index 84e09177bd3..066f8bbafeb 100644 --- a/test/test-not-writable-after-shutdown.c +++ b/test/test-not-writable-after-shutdown.c @@ -34,12 +34,12 @@ static void shutdown_cb(uv_shutdown_t* req, int status) { static void connect_cb(uv_connect_t* req, int status) { int r; - ASSERT(status == 0); + ASSERT_OK(status); r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_is_writable(req->handle)); + ASSERT_OK(uv_is_writable(req->handle)); } TEST_IMPL(not_writable_after_shutdown) { @@ -49,20 +49,20 @@ TEST_IMPL(not_writable_after_shutdown) { uv_tcp_t socket; uv_connect_t connect_req; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); loop = uv_default_loop(); r = uv_tcp_init(loop, &socket); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &socket, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-osx-select.c b/test/test-osx-select.c index 00ae540b405..44e2c6d8dd2 100644 --- a/test/test-osx-select.c +++ b/test/test-osx-select.c @@ -62,7 +62,7 @@ TEST_IMPL(osx_select) { } r = uv_tty_init(uv_default_loop(), &tty, fd, 1); - ASSERT(r == 0); + ASSERT_OK(r); uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb); @@ -72,12 +72,12 @@ TEST_IMPL(osx_select) { "feel pretty happy\n"; for (i = 0, len = strlen(str); i < len; i++) { r = ioctl(fd, TIOCSTI, str + i); - ASSERT(r == 0); + ASSERT_OK(r); } uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(read_count == 3); + ASSERT_EQ(3, read_count); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -97,13 +97,13 @@ TEST_IMPL(osx_select_many_fds) { TEST_FILE_LIMIT(ARRAY_SIZE(tcps) + 100); r = uv_ip4_addr("127.0.0.1", 0, &addr); - ASSERT(r == 0); + ASSERT_OK(r); for (i = 0; i < ARRAY_SIZE(tcps); i++) { r = uv_tcp_init(uv_default_loop(), &tcps[i]); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&tcps[i], (const struct sockaddr *) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_unref((uv_handle_t*) &tcps[i]); } @@ -115,10 +115,10 @@ TEST_IMPL(osx_select_many_fds) { } r = uv_tty_init(uv_default_loop(), &tty, fd, 1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); /* Emulate user-input */ str = "got some input\n" @@ -126,12 +126,12 @@ TEST_IMPL(osx_select_many_fds) { "feel pretty happy\n"; for (i = 0, len = strlen(str); i < len; i++) { r = ioctl(fd, TIOCSTI, str + i); - ASSERT(r == 0); + ASSERT_OK(r); } uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(read_count == 3); + ASSERT_EQ(3, read_count); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-ping-pong.c b/test/test-ping-pong.c index f54f2ad22e5..cd9fbf62bba 100644 --- a/test/test-ping-pong.c +++ b/test/test-ping-pong.c @@ -83,7 +83,7 @@ static void pinger_on_close(uv_handle_t* handle) { static void pinger_after_write(uv_write_t* req, int status) { - ASSERT_EQ(status, 0); + ASSERT_OK(status); free(req->data); free(req); } @@ -112,7 +112,7 @@ static void pinger_write_ping(pinger_t* pinger) { req = malloc(sizeof(*req)); ASSERT_NOT_NULL(req); req->data = NULL; - ASSERT_EQ(0, uv_write(req, stream, bufs, nbufs, pinger_after_write)); + ASSERT_OK(uv_write(req, stream, bufs, nbufs, pinger_after_write)); puts("PING"); } @@ -188,7 +188,7 @@ static void ponger_read_cb(uv_stream_t* stream, req = malloc(sizeof(*req)); ASSERT_NOT_NULL(req); req->data = buf->base; - ASSERT_EQ(0, uv_write(req, stream, &writebuf, 1, pinger_after_write)); + ASSERT_OK(uv_write(req, stream, &writebuf, 1, pinger_after_write)); } @@ -197,17 +197,17 @@ static void pinger_on_connect(uv_connect_t* req, int status) { pinger_on_connect_count++; - ASSERT_EQ(status, 0); + ASSERT_OK(status); ASSERT_EQ(1, uv_is_readable(req->handle)); ASSERT_EQ(1, uv_is_writable(req->handle)); - ASSERT_EQ(0, uv_is_closing((uv_handle_t *) req->handle)); + ASSERT_OK(uv_is_closing((uv_handle_t *) req->handle)); pinger_write_ping(pinger); - ASSERT_EQ(0, uv_read_start((uv_stream_t*) req->handle, - alloc_cb, - pinger_read_cb)); + ASSERT_OK(uv_read_start((uv_stream_t*) req->handle, + alloc_cb, + pinger_read_cb)); } @@ -218,7 +218,7 @@ static void tcp_pinger_v6_new(int vectored_writes) { pinger_t* pinger; - ASSERT_EQ(0, uv_ip6_addr("::1", TEST_PORT, &server_addr)); + ASSERT_OK(uv_ip6_addr("::1", TEST_PORT, &server_addr)); pinger = malloc(sizeof(*pinger)); ASSERT_NOT_NULL(pinger); pinger->vectored_writes = vectored_writes; @@ -229,7 +229,7 @@ static void tcp_pinger_v6_new(int vectored_writes) { /* Try to connect to the server and do NUM_PINGS ping-pongs. */ r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp); pinger->stream.tcp.data = pinger; - ASSERT_EQ(0, r); + ASSERT_OK(r); /* We are never doing multiple reads/connects at a time anyway, so these * handles can be pre-initialized. */ @@ -237,10 +237,10 @@ static void tcp_pinger_v6_new(int vectored_writes) { &pinger->stream.tcp, (const struct sockaddr*) &server_addr, pinger_on_connect); - ASSERT_EQ(0, r); + ASSERT_OK(r); /* Synchronous connect callbacks are not allowed. */ - ASSERT_EQ(pinger_on_connect_count, 0); + ASSERT_OK(pinger_on_connect_count); } @@ -249,7 +249,7 @@ static void tcp_pinger_new(int vectored_writes) { struct sockaddr_in server_addr; pinger_t* pinger; - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); pinger = malloc(sizeof(*pinger)); ASSERT_NOT_NULL(pinger); pinger->vectored_writes = vectored_writes; @@ -260,7 +260,7 @@ static void tcp_pinger_new(int vectored_writes) { /* Try to connect to the server and do NUM_PINGS ping-pongs. */ r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp); pinger->stream.tcp.data = pinger; - ASSERT_EQ(0, r); + ASSERT_OK(r); /* We are never doing multiple reads/connects at a time anyway, so these * handles can be pre-initialized. */ @@ -268,10 +268,10 @@ static void tcp_pinger_new(int vectored_writes) { &pinger->stream.tcp, (const struct sockaddr*) &server_addr, pinger_on_connect); - ASSERT_EQ(0, r); + ASSERT_OK(r); /* Synchronous connect callbacks are not allowed. */ - ASSERT_EQ(pinger_on_connect_count, 0); + ASSERT_OK(pinger_on_connect_count); } @@ -289,7 +289,7 @@ static void pipe_pinger_new(int vectored_writes) { /* Try to connect to the server and do NUM_PINGS ping-pongs. */ r = uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0); pinger->stream.pipe.data = pinger; - ASSERT_EQ(0, r); + ASSERT_OK(r); /* We are never doing multiple reads/connects at a time anyway, so these * handles can be pre-initialized. */ @@ -297,7 +297,7 @@ static void pipe_pinger_new(int vectored_writes) { pinger_on_connect); /* Synchronous connect callbacks are not allowed. */ - ASSERT_EQ(pinger_on_connect_count, 0); + ASSERT_OK(pinger_on_connect_count); } @@ -315,31 +315,31 @@ static void socketpair_pinger_new(int vectored_writes) { /* Try to make a socketpair and do NUM_PINGS ping-pongs. */ (void)uv_default_loop(); /* ensure WSAStartup has been performed */ - ASSERT_EQ(0, uv_socketpair(SOCK_STREAM, 0, fds, UV_NONBLOCK_PIPE, UV_NONBLOCK_PIPE)); + ASSERT_OK(uv_socketpair(SOCK_STREAM, 0, fds, UV_NONBLOCK_PIPE, UV_NONBLOCK_PIPE)); #ifndef _WIN32 /* On Windows, this is actually a UV_TCP, but libuv doesn't detect that. */ ASSERT_EQ(uv_guess_handle((uv_file) fds[0]), UV_NAMED_PIPE); ASSERT_EQ(uv_guess_handle((uv_file) fds[1]), UV_NAMED_PIPE); #endif - ASSERT_EQ(0, uv_tcp_init(uv_default_loop(), &pinger->stream.tcp)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &pinger->stream.tcp)); pinger->stream.pipe.data = pinger; - ASSERT_EQ(0, uv_tcp_open(&pinger->stream.tcp, fds[1])); + ASSERT_OK(uv_tcp_open(&pinger->stream.tcp, fds[1])); ponger = malloc(sizeof(*ponger)); ASSERT_NOT_NULL(ponger); ponger->data = NULL; - ASSERT_EQ(0, uv_tcp_init(uv_default_loop(), ponger)); - ASSERT_EQ(0, uv_tcp_open(ponger, fds[0])); + ASSERT_OK(uv_tcp_init(uv_default_loop(), ponger)); + ASSERT_OK(uv_tcp_open(ponger, fds[0])); pinger_write_ping(pinger); - ASSERT_EQ(0, uv_read_start((uv_stream_t*) &pinger->stream.tcp, - alloc_cb, - pinger_read_cb)); - ASSERT_EQ(0, uv_read_start((uv_stream_t*) ponger, - alloc_cb, - ponger_read_cb)); + ASSERT_OK(uv_read_start((uv_stream_t*) &pinger->stream.tcp, + alloc_cb, + pinger_read_cb)); + ASSERT_OK(uv_read_start((uv_stream_t*) ponger, + alloc_cb, + ponger_read_cb)); } @@ -349,14 +349,14 @@ static void pipe2_pinger_new(int vectored_writes) { uv_pipe_t* ponger; /* Try to make a pipe and do NUM_PINGS pings. */ - ASSERT_EQ(0, uv_pipe(fds, UV_NONBLOCK_PIPE, UV_NONBLOCK_PIPE)); + ASSERT_OK(uv_pipe(fds, UV_NONBLOCK_PIPE, UV_NONBLOCK_PIPE)); ASSERT_EQ(uv_guess_handle(fds[0]), UV_NAMED_PIPE); ASSERT_EQ(uv_guess_handle(fds[1]), UV_NAMED_PIPE); ponger = malloc(sizeof(*ponger)); ASSERT_NOT_NULL(ponger); - ASSERT_EQ(0, uv_pipe_init(uv_default_loop(), ponger, 0)); - ASSERT_EQ(0, uv_pipe_open(ponger, fds[0])); + ASSERT_OK(uv_pipe_init(uv_default_loop(), ponger, 0)); + ASSERT_OK(uv_pipe_open(ponger, fds[0])); pinger = malloc(sizeof(*pinger)); ASSERT_NOT_NULL(pinger); @@ -364,19 +364,19 @@ static void pipe2_pinger_new(int vectored_writes) { pinger->state = 0; pinger->pongs = 0; pinger->pong = PING; - ASSERT_EQ(0, uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0)); - ASSERT_EQ(0, uv_pipe_open(&pinger->stream.pipe, fds[1])); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0)); + ASSERT_OK(uv_pipe_open(&pinger->stream.pipe, fds[1])); pinger->stream.pipe.data = pinger; /* record for close_cb */ ponger->data = pinger; /* record for read_cb */ pinger_write_ping(pinger); - ASSERT_EQ(0, uv_read_start((uv_stream_t*) ponger, alloc_cb, pinger_read_cb)); + ASSERT_OK(uv_read_start((uv_stream_t*) ponger, alloc_cb, pinger_read_cb)); } static int run_ping_pong_test(void) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(completed_pingers, 1); + ASSERT_EQ(1, completed_pingers); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-pipe-bind-error.c b/test/test-pipe-bind-error.c index f8626302a1d..381a0084dec 100644 --- a/test/test-pipe-bind-error.c +++ b/test/test-pipe-bind-error.c @@ -46,26 +46,26 @@ TEST_IMPL(pipe_bind_error_addrinuse) { int r; r = uv_pipe_init(uv_default_loop(), &server1, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_bind(&server1, TEST_PIPENAME); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_init(uv_default_loop(), &server2, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_bind(&server2, TEST_PIPENAME); - ASSERT(r == UV_EADDRINUSE); + ASSERT_EQ(r, UV_EADDRINUSE); r = uv_listen((uv_stream_t*)&server1, SOMAXCONN, NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server2, SOMAXCONN, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_close((uv_handle_t*)&server1, close_cb); uv_close((uv_handle_t*)&server2, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 2); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -77,16 +77,16 @@ TEST_IMPL(pipe_bind_error_addrnotavail) { int r; r = uv_pipe_init(uv_default_loop(), &server, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_bind(&server, BAD_PIPENAME); - ASSERT(r == UV_EACCES); + ASSERT_EQ(r, UV_EACCES); uv_close((uv_handle_t*)&server, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -98,17 +98,17 @@ TEST_IMPL(pipe_bind_error_inval) { int r; r = uv_pipe_init(uv_default_loop(), &server, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_bind(&server, TEST_PIPENAME); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_bind(&server, TEST_PIPENAME_2); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_close((uv_handle_t*)&server, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -123,16 +123,16 @@ TEST_IMPL(pipe_listen_without_bind) { int r; r = uv_pipe_init(uv_default_loop(), &server, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_close((uv_handle_t*)&server, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -141,14 +141,14 @@ TEST_IMPL(pipe_listen_without_bind) { TEST_IMPL(pipe_bind_or_listen_error_after_close) { uv_pipe_t server; - ASSERT_EQ(uv_pipe_init(uv_default_loop(), &server, 0), 0); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &server, 0)); uv_close((uv_handle_t*) &server, NULL); ASSERT_EQ(uv_pipe_bind(&server, TEST_PIPENAME), UV_EINVAL); ASSERT_EQ(uv_listen((uv_stream_t*) &server, SOMAXCONN, NULL), UV_EINVAL); - ASSERT_EQ(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-pipe-close-stdout-read-stdin.c b/test/test-pipe-close-stdout-read-stdin.c index a9295f0aa59..51bbf0f54e2 100644 --- a/test/test-pipe-close-stdout-read-stdin.c +++ b/test/test-pipe-close-stdout-read-stdin.c @@ -61,7 +61,7 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { uv_pipe_t stdin_pipe; r = pipe(fd); - ASSERT(r == 0); + ASSERT_OK(r); #if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) pid = -1; @@ -80,24 +80,24 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { ASSERT(-1 <= r && r <= 1); close(0); r = dup(fd[0]); - ASSERT(r != -1); + ASSERT_NE(r, -1); /* Create a stream that reads from the pipe. */ r = uv_pipe_init(uv_default_loop(), (uv_pipe_t *)&stdin_pipe, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_open((uv_pipe_t *)&stdin_pipe, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t *)&stdin_pipe, alloc_buffer, read_stdin); - ASSERT(r == 0); + ASSERT_OK(r); /* * Because the other end of the pipe was closed, there should * be no event left to process after one run of the event loop. * Otherwise, it means that events were not processed correctly. */ - ASSERT(uv_run(uv_default_loop(), UV_RUN_NOWAIT) == 0); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_NOWAIT)); } else { /* * Close both ends of the pipe so that the child diff --git a/test/test-pipe-connect-error.c b/test/test-pipe-connect-error.c index 140e7d32daf..ee6e0776f33 100644 --- a/test/test-pipe-connect-error.c +++ b/test/test-pipe-connect-error.c @@ -64,13 +64,13 @@ TEST_IMPL(pipe_connect_bad_name) { int r; r = uv_pipe_init(uv_default_loop(), &client, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_pipe_connect(&req, &client, BAD_PIPENAME, connect_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(close_cb_called, 1); - ASSERT_EQ(connect_cb_called, 1); + ASSERT_EQ(1, close_cb_called); + ASSERT_EQ(1, connect_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -84,13 +84,13 @@ TEST_IMPL(pipe_connect_to_file) { int r; r = uv_pipe_init(uv_default_loop(), &client, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_pipe_connect(&req, &client, path, connect_cb_file); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(close_cb_called, 1); - ASSERT_EQ(connect_cb_called, 1); + ASSERT_EQ(1, close_cb_called); + ASSERT_EQ(1, connect_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-pipe-connect-multiple.c b/test/test-pipe-connect-multiple.c index b8f417e81ca..69a09ec6cdd 100644 --- a/test/test-pipe-connect-multiple.c +++ b/test/test-pipe-connect-multiple.c @@ -44,14 +44,14 @@ static uv_pipe_t connections[NUM_CLIENTS]; static void connection_cb(uv_stream_t* server, int status) { int r; uv_pipe_t* conn; - ASSERT(status == 0); + ASSERT_OK(status); conn = &connections[connection_cb_called]; r = uv_pipe_init(server->loop, conn, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_accept(server, (uv_stream_t*)conn); - ASSERT(r == 0); + ASSERT_OK(r); if (++connection_cb_called == NUM_CLIENTS && connect_cb_called == NUM_CLIENTS) { @@ -61,7 +61,7 @@ static void connection_cb(uv_stream_t* server, int status) { static void connect_cb(uv_connect_t* connect_req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); if (++connect_cb_called == NUM_CLIENTS && connection_cb_called == NUM_CLIENTS) { uv_stop(connect_req->handle->loop); @@ -80,17 +80,17 @@ TEST_IMPL(pipe_connect_multiple) { loop = uv_default_loop(); r = uv_pipe_init(loop, &server_handle, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_bind(&server_handle, TEST_PIPENAME); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server_handle, 128, connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); for (i = 0; i < NUM_CLIENTS; i++) { r = uv_pipe_init(loop, &clients[i].pipe_handle, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_pipe_connect(&clients[i].conn_req, &clients[i].pipe_handle, TEST_PIPENAME, @@ -99,8 +99,8 @@ TEST_IMPL(pipe_connect_multiple) { uv_run(loop, UV_RUN_DEFAULT); - ASSERT(connection_cb_called == NUM_CLIENTS); - ASSERT(connect_cb_called == NUM_CLIENTS); + ASSERT_EQ(connection_cb_called, NUM_CLIENTS); + ASSERT_EQ(connect_cb_called, NUM_CLIENTS); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -110,14 +110,14 @@ TEST_IMPL(pipe_connect_multiple) { static void connection_cb2(uv_stream_t* server, int status) { int r; uv_pipe_t* conn; - ASSERT_EQ(status, 0); + ASSERT_OK(status); conn = &connections[connection_cb_called]; r = uv_pipe_init(server->loop, conn, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_accept(server, (uv_stream_t*)conn); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_close((uv_handle_t*)conn, NULL); if (++connection_cb_called == NUM_CLIENTS && @@ -146,17 +146,17 @@ TEST_IMPL(pipe_connect_close_multiple) { loop = uv_default_loop(); r = uv_pipe_init(loop, &server_handle, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_pipe_bind(&server_handle, TEST_PIPENAME); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server_handle, 128, connection_cb2); - ASSERT_EQ(r, 0); + ASSERT_OK(r); for (i = 0; i < NUM_CLIENTS; i++) { r = uv_pipe_init(loop, &clients[i].pipe_handle, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_pipe_connect(&clients[i].conn_req, &clients[i].pipe_handle, TEST_PIPENAME, diff --git a/test/test-pipe-connect-prepare.c b/test/test-pipe-connect-prepare.c index f7a79404048..93d15a473f3 100644 --- a/test/test-pipe-connect-prepare.c +++ b/test/test-pipe-connect-prepare.c @@ -48,7 +48,7 @@ static void close_cb(uv_handle_t* handle) { static void connect_cb(uv_connect_t* connect_req, int status) { - ASSERT(status == UV_ENOENT); + ASSERT_EQ(status, UV_ENOENT); connect_cb_called++; uv_close((uv_handle_t*)&prepare_handle, close_cb); uv_close((uv_handle_t*)&pipe_handle, close_cb); @@ -56,7 +56,7 @@ static void connect_cb(uv_connect_t* connect_req, int status) { static void prepare_cb(uv_prepare_t* handle) { - ASSERT(handle == &prepare_handle); + ASSERT_PTR_EQ(handle, &prepare_handle); uv_pipe_connect(&conn_req, &pipe_handle, BAD_PIPENAME, connect_cb); } @@ -65,18 +65,18 @@ TEST_IMPL(pipe_connect_on_prepare) { int r; r = uv_pipe_init(uv_default_loop(), &pipe_handle, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_prepare_init(uv_default_loop(), &prepare_handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_prepare_start(&prepare_handle, prepare_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 2); - ASSERT(connect_cb_called == 1); + ASSERT_EQ(2, close_cb_called); + ASSERT_EQ(1, connect_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index d749933d44f..eb09d88fd2b 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -40,8 +40,8 @@ static int pipe_client_connect_cb_called = 0; static void pipe_close_cb(uv_handle_t* handle) { - ASSERT(handle == (uv_handle_t*) &pipe_client || - handle == (uv_handle_t*) &pipe_server); + ASSERT_NE(handle == (uv_handle_t*) &pipe_client || + handle == (uv_handle_t*) &pipe_server, 0); pipe_close_cb_called++; } @@ -51,12 +51,12 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) { size_t len; int r; - ASSERT(req == &connect_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &connect_req); + ASSERT_OK(status); len = sizeof buf; r = uv_pipe_getpeername(&pipe_client, buf, &len); - ASSERT(r == 0); + ASSERT_OK(r); if (*buf == '\0') { /* Linux abstract socket. */ const char expected[] = "\0" TEST_PIPENAME; @@ -82,7 +82,7 @@ static void pipe_server_connection_cb(uv_stream_t* handle, int status) { /* This function *may* be called, depending on whether accept or the * connection callback is called first. */ - ASSERT(status == 0); + ASSERT_OK(status); } @@ -99,44 +99,44 @@ TEST_IMPL(pipe_getsockname) { ASSERT_NOT_NULL(loop); r = uv_pipe_init(loop, &pipe_server, 0); - ASSERT(r == 0); + ASSERT_OK(r); len = sizeof buf; r = uv_pipe_getsockname(&pipe_server, buf, &len); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); len = sizeof buf; r = uv_pipe_getpeername(&pipe_server, buf, &len); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); r = uv_pipe_bind(&pipe_server, TEST_PIPENAME); - ASSERT(r == 0); + ASSERT_OK(r); len = sizeof buf; r = uv_pipe_getsockname(&pipe_server, buf, &len); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(buf[len - 1] != 0); - ASSERT(buf[len] == '\0'); - ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0); + ASSERT_NE(0, buf[len - 1]); + ASSERT_EQ(buf[len], '\0'); + ASSERT_OK(memcmp(buf, TEST_PIPENAME, len)); len = sizeof buf; r = uv_pipe_getpeername(&pipe_server, buf, &len); - ASSERT(r == UV_ENOTCONN); + ASSERT_EQ(r, UV_ENOTCONN); r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_init(loop, &pipe_client, 0); - ASSERT(r == 0); + ASSERT_OK(r); len = sizeof buf; r = uv_pipe_getsockname(&pipe_client, buf, &len); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); len = sizeof buf; r = uv_pipe_getpeername(&pipe_client, buf, &len); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb); @@ -146,15 +146,15 @@ TEST_IMPL(pipe_getsockname) { len = sizeof buf; r = uv_pipe_getpeername(&pipe_client, buf, &len); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(buf[len - 1] != 0); - ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0); + ASSERT_NE(0, buf[len - 1]); + ASSERT_OK(memcmp(buf, TEST_PIPENAME, len)); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); - ASSERT(pipe_client_connect_cb_called == 1); - ASSERT(pipe_close_cb_called == 2); + ASSERT_OK(r); + ASSERT_EQ(1, pipe_client_connect_cb_called); + ASSERT_EQ(2, pipe_close_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -218,50 +218,50 @@ TEST_IMPL(pipe_getsockname_blocking) { int r; r = CreatePipe(&readh, &writeh, NULL, 65536); - ASSERT(r != 0); + ASSERT(r); r = uv_pipe_init(uv_default_loop(), &pipe_client, 0); - ASSERT(r == 0); + ASSERT_OK(r); readfd = _open_osfhandle((intptr_t)readh, _O_RDONLY); - ASSERT(r != -1); + ASSERT_NE(r, -1); r = uv_pipe_open(&pipe_client, readfd); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &pipe_client, (uv_alloc_cb) abort, (uv_read_cb) abort); - ASSERT(r == 0); + ASSERT_OK(r); Sleep(100); r = uv_read_stop((uv_stream_t*)&pipe_client); - ASSERT(r == 0); + ASSERT_OK(r); len1 = sizeof buf1; r = uv_pipe_getsockname(&pipe_client, buf1, &len1); - ASSERT(r == 0); - ASSERT(len1 == 0); /* It's an annonymous pipe. */ + ASSERT_OK(r); + ASSERT_OK(len1); /* It's an annonymous pipe. */ r = uv_read_start((uv_stream_t*)&pipe_client, (uv_alloc_cb) abort, (uv_read_cb) abort); - ASSERT(r == 0); + ASSERT_OK(r); Sleep(100); len2 = sizeof buf2; r = uv_pipe_getsockname(&pipe_client, buf2, &len2); - ASSERT(r == 0); - ASSERT(len2 == 0); /* It's an annonymous pipe. */ + ASSERT_OK(r); + ASSERT_OK(len2); /* It's an annonymous pipe. */ r = uv_read_stop((uv_stream_t*)&pipe_client); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(len1 == len2); - ASSERT(memcmp(buf1, buf2, len1) == 0); + ASSERT_EQ(len1, len2); + ASSERT_OK(memcmp(buf1, buf2, len1)); pipe_close_cb_called = 0; uv_close((uv_handle_t*)&pipe_client, pipe_close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(pipe_close_cb_called == 1); + ASSERT_EQ(1, pipe_close_cb_called); CloseHandle(writeh); #endif diff --git a/test/test-pipe-pending-instances.c b/test/test-pipe-pending-instances.c index 9b1bfbc9aac..570ecd69b73 100644 --- a/test/test-pipe-pending-instances.c +++ b/test/test-pipe-pending-instances.c @@ -37,22 +37,22 @@ TEST_IMPL(pipe_pending_instances) { loop = uv_default_loop(); r = uv_pipe_init(loop, &pipe_handle, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_pipe_pending_instances(&pipe_handle, 8); r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME); - ASSERT(r == 0); + ASSERT_OK(r); uv_pipe_pending_instances(&pipe_handle, 16); r = uv_listen((uv_stream_t*)&pipe_handle, 128, connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*)&pipe_handle, NULL); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-pipe-sendmsg.c b/test/test-pipe-sendmsg.c index 7758b65b05c..3958b05378c 100644 --- a/test/test-pipe-sendmsg.c +++ b/test/test-pipe-sendmsg.c @@ -45,12 +45,12 @@ static void set_nonblocking(uv_os_sock_t sock) { #ifdef _WIN32 unsigned long on = 1; r = ioctlsocket(sock, FIONBIO, &on); - ASSERT(r == 0); + ASSERT_OK(r); #else int flags = fcntl(sock, F_GETFL, 0); - ASSERT(flags >= 0); + ASSERT_GE(flags, 0); r = fcntl(sock, F_SETFL, flags | O_NONBLOCK); - ASSERT(r >= 0); + ASSERT_GE(r, 0); #endif } @@ -79,22 +79,22 @@ static void read_cb(uv_stream_t* handle, unsigned int i; p = (uv_pipe_t*) handle; - ASSERT(nread >= 0); + ASSERT_GE(nread, 0); while (uv_pipe_pending_count(p) != 0) { pending = uv_pipe_pending_type(p); - ASSERT(pending == UV_NAMED_PIPE); + ASSERT_EQ(pending, UV_NAMED_PIPE); - ASSERT(incoming_count < ARRAY_SIZE(incoming)); + ASSERT_LT(incoming_count, ARRAY_SIZE(incoming)); inc = &incoming[incoming_count++]; - ASSERT(0 == uv_pipe_init(p->loop, inc, 0)); - ASSERT(0 == uv_accept(handle, (uv_stream_t*) inc)); + ASSERT_OK(uv_pipe_init(p->loop, inc, 0)); + ASSERT_OK(uv_accept(handle, (uv_stream_t*) inc)); } if (incoming_count != ARRAY_SIZE(incoming)) return; - ASSERT(0 == uv_read_stop((uv_stream_t*) p)); + ASSERT_OK(uv_read_stop((uv_stream_t*) p)); uv_close((uv_handle_t*) p, close_cb); for (i = 0; i < ARRAY_SIZE(incoming); i++) uv_close((uv_handle_t*) &incoming[i], close_cb); @@ -115,12 +115,12 @@ TEST_IMPL(pipe_sendmsg) { unsigned int i; uv_buf_t buf; - ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fds)); + ASSERT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds)); for (i = 0; i < ARRAY_SIZE(send_fds); i += 2) - ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, send_fds + i)); - ASSERT(i == ARRAY_SIZE(send_fds)); - ASSERT(0 == uv_pipe_init(uv_default_loop(), &p, 1)); - ASSERT(0 == uv_pipe_open(&p, fds[1])); + ASSERT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, send_fds + i)); + ASSERT_EQ(i, ARRAY_SIZE(send_fds)); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &p, 1)); + ASSERT_OK(uv_pipe_open(&p, fds[1])); buf = uv_buf_init("X", 1); memset(&msg, 0, sizeof(msg)); @@ -130,7 +130,7 @@ TEST_IMPL(pipe_sendmsg) { msg.msg_control = (void*) scratch; msg.msg_controllen = CMSG_LEN(sizeof(send_fds)); - ASSERT(sizeof(scratch) >= msg.msg_controllen); + ASSERT_GE(sizeof(scratch), msg.msg_controllen); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; @@ -146,16 +146,16 @@ TEST_IMPL(pipe_sendmsg) { } set_nonblocking(fds[1]); - ASSERT(0 == uv_read_start((uv_stream_t*) &p, alloc_cb, read_cb)); + ASSERT_OK(uv_read_start((uv_stream_t*) &p, alloc_cb, read_cb)); do r = sendmsg(fds[0], &msg, 0); while (r == -1 && errno == EINTR); - ASSERT(r == 1); + ASSERT_EQ(1, r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(ARRAY_SIZE(incoming) == incoming_count); - ASSERT(ARRAY_SIZE(incoming) + 1 == close_called); + ASSERT_EQ(ARRAY_SIZE(incoming), incoming_count); + ASSERT_EQ(ARRAY_SIZE(incoming) + 1, close_called); close(fds[0]); MAKE_VALGRIND_HAPPY(uv_default_loop()); diff --git a/test/test-pipe-server-close.c b/test/test-pipe-server-close.c index dc20661916d..ad7d792acc3 100644 --- a/test/test-pipe-server-close.c +++ b/test/test-pipe-server-close.c @@ -35,15 +35,15 @@ static int pipe_client_connect_cb_called = 0; static void pipe_close_cb(uv_handle_t* handle) { - ASSERT(handle == (uv_handle_t*) &pipe_client || - handle == (uv_handle_t*) &pipe_server); + ASSERT_NE(handle == (uv_handle_t*) &pipe_client || + handle == (uv_handle_t*) &pipe_server, 0); pipe_close_cb_called++; } static void pipe_client_connect_cb(uv_connect_t* req, int status) { - ASSERT(req == &connect_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &connect_req); + ASSERT_OK(status); pipe_client_connect_cb_called++; @@ -56,7 +56,7 @@ static void pipe_server_connection_cb(uv_stream_t* handle, int status) { /* This function *may* be called, depending on whether accept or the * connection callback is called first. */ - ASSERT(status == 0); + ASSERT_OK(status); } @@ -71,23 +71,23 @@ TEST_IMPL(pipe_server_close) { ASSERT_NOT_NULL(loop); r = uv_pipe_init(loop, &pipe_server, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_bind(&pipe_server, TEST_PIPENAME); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_init(loop, &pipe_client, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); - ASSERT(pipe_client_connect_cb_called == 1); - ASSERT(pipe_close_cb_called == 2); + ASSERT_OK(r); + ASSERT_EQ(1, pipe_client_connect_cb_called); + ASSERT_EQ(2, pipe_close_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-pipe-set-fchmod.c b/test/test-pipe-set-fchmod.c index 402970e3da9..9563e4fdd50 100644 --- a/test/test-pipe-set-fchmod.c +++ b/test/test-pipe-set-fchmod.c @@ -35,10 +35,10 @@ TEST_IMPL(pipe_set_chmod) { loop = uv_default_loop(); r = uv_pipe_init(loop, &pipe_handle, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME); - ASSERT(r == 0); + ASSERT_OK(r); /* No easy way to test if this works, we will only make sure that the call is * successful. */ @@ -47,17 +47,17 @@ TEST_IMPL(pipe_set_chmod) { MAKE_VALGRIND_HAPPY(loop); RETURN_SKIP("Insufficient privileges to alter pipe fmode"); } - ASSERT(r == 0); + ASSERT_OK(r); #ifndef _WIN32 memset(&stat_buf, 0, sizeof(stat_buf)); - ASSERT_EQ(0, stat(TEST_PIPENAME, &stat_buf)); + ASSERT_OK(stat(TEST_PIPENAME, &stat_buf)); ASSERT(stat_buf.st_mode & S_IRUSR); ASSERT(stat_buf.st_mode & S_IRGRP); ASSERT(stat_buf.st_mode & S_IROTH); #endif r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE); - ASSERT(r == 0); + ASSERT_OK(r); #ifndef _WIN32 stat(TEST_PIPENAME, &stat_buf); ASSERT(stat_buf.st_mode & S_IWUSR); @@ -66,7 +66,7 @@ TEST_IMPL(pipe_set_chmod) { #endif r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); - ASSERT(r == 0); + ASSERT_OK(r); #ifndef _WIN32 stat(TEST_PIPENAME, &stat_buf); ASSERT(stat_buf.st_mode & S_IRUSR); @@ -78,14 +78,14 @@ TEST_IMPL(pipe_set_chmod) { #endif r = uv_pipe_chmod(NULL, UV_WRITABLE | UV_READABLE); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); r = uv_pipe_chmod(&pipe_handle, 12345678); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_close((uv_handle_t*)&pipe_handle, NULL); r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-pipe-set-non-blocking.c b/test/test-pipe-set-non-blocking.c index 1b90bca3d2a..bf1c284189f 100644 --- a/test/test-pipe-set-non-blocking.c +++ b/test/test-pipe-set-non-blocking.c @@ -46,13 +46,13 @@ static void thread_main(void* arg) { uv_fs_req_cleanup(&req); } while (n > 0 || (n == -1 && uv_errno == UV_EINTR)); - ASSERT(n == 0); + ASSERT_OK(n); } #ifdef _WIN32 static void write_cb(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); req->handle = NULL; /* signal completion of write_cb */ } #endif @@ -77,15 +77,15 @@ TEST_IMPL(pipe_set_non_blocking) { uv_write_t write_req; #endif - ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0)); - ASSERT(0 == uv_pipe(fd, 0, 0)); - ASSERT(0 == uv_pipe_open(&pipe_handle, fd[1])); - ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &pipe_handle, 1)); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_handle, 0)); + ASSERT_OK(uv_pipe(fd, 0, 0)); + ASSERT_OK(uv_pipe_open(&pipe_handle, fd[1])); + ASSERT_OK(uv_stream_set_blocking((uv_stream_t*) &pipe_handle, 1)); fd[1] = -1; /* fd[1] is owned by pipe_handle now. */ ctx.fd = fd[0]; - ASSERT(0 == uv_barrier_init(&ctx.barrier, 2)); - ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); + ASSERT_OK(uv_barrier_init(&ctx.barrier, 2)); + ASSERT_OK(uv_thread_create(&thread, thread_main, &ctx)); uv_barrier_wait(&ctx.barrier); buf.len = sizeof(data); @@ -99,25 +99,29 @@ TEST_IMPL(pipe_set_non_blocking) { */ n = uv_try_write((uv_stream_t*) &pipe_handle, &buf, 1); #ifdef _WIN32 - ASSERT(n == UV_EAGAIN); /* E_NOTIMPL */ - ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &pipe_handle, &buf, 1, write_cb)); + ASSERT_EQ(n, UV_EAGAIN); /* E_NOTIMPL */ + ASSERT_OK(uv_write(&write_req, + (uv_stream_t*) &pipe_handle, + &buf, + 1, + write_cb)); ASSERT_NOT_NULL(write_req.handle); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); ASSERT_NULL(write_req.handle); /* check for signaled completion of write_cb */ n = buf.len; #endif - ASSERT(n == sizeof(data)); + ASSERT_EQ(n, sizeof(data)); nwritten += n; } uv_close((uv_handle_t*) &pipe_handle, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); #ifdef _WIN32 - ASSERT(0 == _close(fd[0])); /* fd[1] is closed by uv_close(). */ + ASSERT_OK(_close(fd[0])); /* fd[1] is closed by uv_close(). */ #else - ASSERT(0 == close(fd[0])); /* fd[1] is closed by uv_close(). */ + ASSERT_OK(close(fd[0])); /* fd[1] is closed by uv_close(). */ #endif fd[0] = -1; uv_barrier_destroy(&ctx.barrier); diff --git a/test/test-platform-output.c b/test/test-platform-output.c index 5839f52dfe5..f18e097f913 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -44,37 +44,37 @@ TEST_IMPL(platform_output) { int err; err = uv_get_process_title(buffer, sizeof(buffer)); - ASSERT(err == 0); + ASSERT_OK(err); printf("uv_get_process_title: %s\n", buffer); size = sizeof(buffer); err = uv_cwd(buffer, &size); - ASSERT(err == 0); + ASSERT_OK(err); printf("uv_cwd: %s\n", buffer); err = uv_resident_set_memory(&rss); #if defined(__MSYS__) - ASSERT(err == UV_ENOSYS); + ASSERT_EQ(err, UV_ENOSYS); #else - ASSERT(err == 0); + ASSERT_OK(err); printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss); #endif err = uv_uptime(&uptime); #if defined(__PASE__) - ASSERT(err == UV_ENOSYS); + ASSERT_EQ(err, UV_ENOSYS); #else - ASSERT(err == 0); - ASSERT(uptime > 0); + ASSERT_OK(err); + ASSERT_GT(uptime, 0); printf("uv_uptime: %f\n", uptime); #endif err = uv_getrusage(&rusage); - ASSERT(err == 0); - ASSERT(rusage.ru_utime.tv_sec >= 0); - ASSERT(rusage.ru_utime.tv_usec >= 0); - ASSERT(rusage.ru_stime.tv_sec >= 0); - ASSERT(rusage.ru_stime.tv_usec >= 0); + ASSERT_OK(err); + ASSERT_GE(rusage.ru_utime.tv_sec, 0); + ASSERT_GE(rusage.ru_utime.tv_usec, 0); + ASSERT_GE(rusage.ru_stime.tv_sec, 0); + ASSERT_GE(rusage.ru_stime.tv_usec, 0); printf("uv_getrusage:\n"); printf(" user: %llu sec %llu microsec\n", (unsigned long long) rusage.ru_utime.tv_sec, @@ -92,9 +92,9 @@ TEST_IMPL(platform_output) { err = uv_cpu_info(&cpus, &count); #if defined(__CYGWIN__) || defined(__MSYS__) - ASSERT(err == UV_ENOSYS); + ASSERT_EQ(err, UV_ENOSYS); #else - ASSERT(err == 0); + ASSERT_OK(err); printf("uv_cpu_info:\n"); for (i = 0; i < count; i++) { @@ -113,7 +113,7 @@ TEST_IMPL(platform_output) { uv_free_cpu_info(cpus, count); err = uv_interface_addresses(&interfaces, &count); - ASSERT(err == 0); + ASSERT_OK(err); printf("uv_interface_addresses:\n"); for (i = 0; i < count; i++) { @@ -149,7 +149,7 @@ TEST_IMPL(platform_output) { uv_free_interface_addresses(interfaces, count); err = uv_os_get_passwd(&pwd); - ASSERT_EQ(err, 0); + ASSERT_OK(err); err = uv_os_get_group(&grp, pwd.gid); #if defined(_WIN32) @@ -159,7 +159,7 @@ TEST_IMPL(platform_output) { (void) member; grp.groupname = "ENOTSUP"; #else - ASSERT_EQ(err, 0); + ASSERT_OK(err); ASSERT_EQ(pwd.gid, grp.gid); #endif @@ -183,14 +183,14 @@ TEST_IMPL(platform_output) { #endif pid = uv_os_getpid(); - ASSERT(pid > 0); + ASSERT_GT(pid, 0); printf("uv_os_getpid: %d\n", (int) pid); ppid = uv_os_getppid(); - ASSERT(ppid > 0); + ASSERT_GT(ppid, 0); printf("uv_os_getppid: %d\n", (int) ppid); err = uv_os_uname(&uname); - ASSERT(err == 0); + ASSERT_OK(err); printf("uv_os_uname:\n"); printf(" sysname: %s\n", uname.sysname); printf(" release: %s\n", uname.release); diff --git a/test/test-poll-close-doesnt-corrupt-stack.c b/test/test-poll-close-doesnt-corrupt-stack.c index a19f42769b5..0acb452a78b 100644 --- a/test/test-poll-close-doesnt-corrupt-stack.c +++ b/test/test-poll-close-doesnt-corrupt-stack.c @@ -59,12 +59,12 @@ static void NO_INLINE close_socket_and_verify_stack(void) { data[i] = MARKER; r = closesocket(sock); - ASSERT(r == 0); + ASSERT_OK(r); uv_sleep(VERIFY_AFTER); for (i = 0; i < ARRAY_SIZE(data); i++) - ASSERT(data[i] == MARKER); + ASSERT_EQ(data[i], MARKER); } #endif @@ -79,34 +79,34 @@ TEST_IMPL(poll_close_doesnt_corrupt_stack) { struct sockaddr_in addr; r = WSAStartup(MAKEWORD(2, 2), &wsa_data); - ASSERT(r == 0); + ASSERT_OK(r); sock = socket(AF_INET, SOCK_STREAM, 0); - ASSERT(sock != INVALID_SOCKET); + ASSERT_NE(sock, INVALID_SOCKET); on = 1; r = ioctlsocket(sock, FIONBIO, &on); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr); - ASSERT(r == 0); + ASSERT_OK(r); r = connect(sock, (const struct sockaddr*) &addr, sizeof addr); - ASSERT(r != 0); - ASSERT(WSAGetLastError() == WSAEWOULDBLOCK); + ASSERT(r); + ASSERT_EQ(WSAGetLastError(), WSAEWOULDBLOCK); r = uv_poll_init_socket(uv_default_loop(), &handle, sock); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_poll_start(&handle, UV_READABLE | UV_WRITABLE, poll_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &handle, close_cb); close_socket_and_verify_stack(); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-poll-close.c b/test/test-poll-close.c index b4ad4c78346..5843bf4516d 100644 --- a/test/test-poll-close.c +++ b/test/test-poll-close.c @@ -50,7 +50,7 @@ TEST_IMPL(poll_close) { { struct WSAData wsa_data; int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); - ASSERT(r == 0); + ASSERT_OK(r); } #endif @@ -66,7 +66,7 @@ TEST_IMPL(poll_close) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == NUM_SOCKETS); + ASSERT_EQ(close_cb_called, NUM_SOCKETS); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-poll-closesocket.c b/test/test-poll-closesocket.c index a81d0b09ff8..01f8f741018 100644 --- a/test/test-poll-closesocket.c +++ b/test/test-poll-closesocket.c @@ -39,11 +39,11 @@ static void close_cb(uv_handle_t* h) { static void poll_cb(uv_poll_t* h, int status, int events) { int r; - ASSERT(status == 0); - ASSERT(h == &handle); + ASSERT_OK(status); + ASSERT_PTR_EQ(h, &handle); r = uv_poll_start(&handle, UV_READABLE, poll_cb); - ASSERT(r == 0); + ASSERT_OK(r); closesocket(sock); uv_close((uv_handle_t*) &handle, close_cb); @@ -62,29 +62,29 @@ TEST_IMPL(poll_closesocket) { struct sockaddr_in addr; r = WSAStartup(MAKEWORD(2, 2), &wsa_data); - ASSERT(r == 0); + ASSERT_OK(r); sock = socket(AF_INET, SOCK_STREAM, 0); - ASSERT(sock != INVALID_SOCKET); + ASSERT_NE(sock, INVALID_SOCKET); on = 1; r = ioctlsocket(sock, FIONBIO, &on); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr); - ASSERT(r == 0); + ASSERT_OK(r); r = connect(sock, (const struct sockaddr*) &addr, sizeof addr); - ASSERT(r != 0); - ASSERT(WSAGetLastError() == WSAEWOULDBLOCK); + ASSERT(r); + ASSERT_EQ(WSAGetLastError(), WSAEWOULDBLOCK); r = uv_poll_init_socket(uv_default_loop(), &handle, sock); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_poll_start(&handle, UV_WRITABLE, poll_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-poll-multiple-handles.c b/test/test-poll-multiple-handles.c index 1aad1ef2106..d9c4924dbfe 100644 --- a/test/test-poll-multiple-handles.c +++ b/test/test-poll-multiple-handles.c @@ -40,7 +40,7 @@ static void close_cb(uv_handle_t* handle) { static void poll_cb(uv_poll_t* handle, int status, int events) { /* Not a bound socket, linux immediately reports UV_READABLE, other OS do not */ - ASSERT(events == UV_READABLE); + ASSERT_EQ(events, UV_READABLE); } TEST_IMPL(poll_multiple_handles) { @@ -51,20 +51,24 @@ TEST_IMPL(poll_multiple_handles) { { struct WSAData wsa_data; int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); - ASSERT(r == 0); + ASSERT_OK(r); } #endif sock = socket(AF_INET, SOCK_STREAM, 0); #ifdef _WIN32 - ASSERT(sock != INVALID_SOCKET); + ASSERT_NE(sock, INVALID_SOCKET); #else - ASSERT(sock != -1); + ASSERT_NE(sock, -1); #endif - ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &first_poll_handle, sock)); - ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &second_poll_handle, sock)); + ASSERT_OK(uv_poll_init_socket(uv_default_loop(), + &first_poll_handle, + sock)); + ASSERT_OK(uv_poll_init_socket(uv_default_loop(), + &second_poll_handle, + sock)); - ASSERT(0 == uv_poll_start(&first_poll_handle, UV_READABLE, poll_cb)); + ASSERT_OK(uv_poll_start(&first_poll_handle, UV_READABLE, poll_cb)); /* We may not start polling while another polling handle is active * on that fd. @@ -73,26 +77,27 @@ TEST_IMPL(poll_multiple_handles) { /* We do not track handles in an O(1) lookupable way on Windows, * so not checking that here. */ - ASSERT(uv_poll_start(&second_poll_handle, UV_READABLE, poll_cb) == UV_EEXIST); + ASSERT_EQ(uv_poll_start(&second_poll_handle, UV_READABLE, poll_cb), + UV_EEXIST); #endif /* After stopping the other polling handle, we now should be able to poll */ - ASSERT(0 == uv_poll_stop(&first_poll_handle)); - ASSERT(0 == uv_poll_start(&second_poll_handle, UV_READABLE, poll_cb)); + ASSERT_OK(uv_poll_stop(&first_poll_handle)); + ASSERT_OK(uv_poll_start(&second_poll_handle, UV_READABLE, poll_cb)); /* Closing an already stopped polling handle is safe in any case */ uv_close((uv_handle_t*) &first_poll_handle, close_cb); uv_unref((uv_handle_t*) &second_poll_handle); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(close_cb_called == 1); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, close_cb_called); uv_ref((uv_handle_t*) &second_poll_handle); ASSERT(uv_is_active((uv_handle_t*) &second_poll_handle)); uv_close((uv_handle_t*) &second_poll_handle, close_cb); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(close_cb_called == 2); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-poll-oob.c b/test/test-poll-oob.c index b1ff41f5b8a..b40c93c3708 100644 --- a/test/test-poll-oob.c +++ b/test/test-poll-oob.c @@ -70,7 +70,7 @@ static void poll_cb(uv_poll_t* handle, int status, int events) { int n; int fd; - ASSERT(0 == uv_fileno((uv_handle_t*)handle, &fd)); + ASSERT_OK(uv_fileno((uv_handle_t*)handle, &fd)); memset(buffer, 0, 5); if (events & UV_PRIORITIZED) { @@ -79,10 +79,10 @@ static void poll_cb(uv_poll_t* handle, int status, int events) { while (n == -1 && errno == EINTR); ASSERT(n >= 0 || errno != EINVAL); cli_pr_check = 1; - ASSERT(0 == uv_poll_stop(&poll_req[0])); - ASSERT(0 == uv_poll_start(&poll_req[0], - UV_READABLE | UV_WRITABLE, - poll_cb)); + ASSERT_OK(uv_poll_stop(&poll_req[0])); + ASSERT_OK(uv_poll_start(&poll_req[0], + UV_READABLE | UV_WRITABLE, + poll_cb)); } if (events & UV_READABLE) { if (fd == client_fd) { @@ -91,21 +91,21 @@ static void poll_cb(uv_poll_t* handle, int status, int events) { while (n == -1 && errno == EINTR); ASSERT(n >= 0 || errno != EINVAL); if (cli_rd_check == 1) { - ASSERT(strncmp(buffer, "world", n) == 0); - ASSERT(5 == n); + ASSERT_OK(strncmp(buffer, "world", n)); + ASSERT_EQ(5, n); cli_rd_check = 2; } if (cli_rd_check == 0) { - ASSERT(n == 4); - ASSERT(strncmp(buffer, "hello", n) == 0); + ASSERT_EQ(4, n); + ASSERT_OK(strncmp(buffer, "hello", n)); cli_rd_check = 1; do { do n = recv(server_fd, &buffer, 5, 0); while (n == -1 && errno == EINTR); if (n > 0) { - ASSERT(n == 5); - ASSERT(strncmp(buffer, "world", n) == 0); + ASSERT_EQ(5, n); + ASSERT_OK(strncmp(buffer, "world", n)); cli_rd_check = 2; } } while (n > 0); @@ -118,8 +118,8 @@ static void poll_cb(uv_poll_t* handle, int status, int events) { n = recv(server_fd, &buffer, 3, 0); while (n == -1 && errno == EINTR); ASSERT(n >= 0 || errno != EINVAL); - ASSERT(3 == n); - ASSERT(strncmp(buffer, "foo", n) == 0); + ASSERT_EQ(3, n); + ASSERT_OK(strncmp(buffer, "foo", n)); srv_rd_check = 1; uv_poll_stop(&poll_req[1]); } @@ -128,35 +128,39 @@ static void poll_cb(uv_poll_t* handle, int status, int events) { do { n = send(client_fd, "foo", 3, 0); } while (n < 0 && errno == EINTR); - ASSERT(3 == n); + ASSERT_EQ(3, n); } } static void connection_cb(uv_stream_t* handle, int status) { int r; - ASSERT(0 == status); - ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle)); - ASSERT(0 == uv_fileno((uv_handle_t*) &peer_handle, &server_fd)); - ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &poll_req[0], client_fd)); - ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &poll_req[1], server_fd)); - ASSERT(0 == uv_poll_start(&poll_req[0], - UV_PRIORITIZED | UV_READABLE | UV_WRITABLE, - poll_cb)); - ASSERT(0 == uv_poll_start(&poll_req[1], - UV_READABLE, - poll_cb)); + ASSERT_OK(status); + ASSERT_OK(uv_accept(handle, (uv_stream_t*) &peer_handle)); + ASSERT_OK(uv_fileno((uv_handle_t*) &peer_handle, &server_fd)); + ASSERT_OK(uv_poll_init_socket(uv_default_loop(), + &poll_req[0], + client_fd)); + ASSERT_OK(uv_poll_init_socket(uv_default_loop(), + &poll_req[1], + server_fd)); + ASSERT_OK(uv_poll_start(&poll_req[0], + UV_PRIORITIZED | UV_READABLE | UV_WRITABLE, + poll_cb)); + ASSERT_OK(uv_poll_start(&poll_req[1], + UV_READABLE, + poll_cb)); do { r = send(server_fd, "hello", 5, MSG_OOB); } while (r < 0 && errno == EINTR); - ASSERT(5 == r); + ASSERT_EQ(5, r); do { r = send(server_fd, "world", 5, 0); } while (r < 0 && errno == EINTR); - ASSERT(5 == r); + ASSERT_EQ(5, r); - ASSERT(0 == uv_idle_start(&idle, idle_cb)); + ASSERT_OK(uv_idle_start(&idle, idle_cb)); } @@ -165,39 +169,39 @@ TEST_IMPL(poll_oob) { int r = 0; uv_loop_t* loop; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); loop = uv_default_loop(); - ASSERT(0 == uv_tcp_init(loop, &server_handle)); - ASSERT(0 == uv_tcp_init(loop, &client_handle)); - ASSERT(0 == uv_tcp_init(loop, &peer_handle)); - ASSERT(0 == uv_idle_init(loop, &idle)); - ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); - ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); + ASSERT_OK(uv_tcp_init(loop, &server_handle)); + ASSERT_OK(uv_tcp_init(loop, &client_handle)); + ASSERT_OK(uv_tcp_init(loop, &peer_handle)); + ASSERT_OK(uv_idle_init(loop, &idle)); + ASSERT_OK(uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); /* Ensure two separate packets */ - ASSERT(0 == uv_tcp_nodelay(&client_handle, 1)); + ASSERT_OK(uv_tcp_nodelay(&client_handle, 1)); client_fd = socket(PF_INET, SOCK_STREAM, 0); - ASSERT(client_fd >= 0); + ASSERT_GE(client_fd, 0); do { errno = 0; r = connect(client_fd, (const struct sockaddr*)&addr, sizeof(addr)); } while (r == -1 && errno == EINTR); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(ticks == kMaxTicks); + ASSERT_EQ(ticks, kMaxTicks); /* Did client receive the POLLPRI message */ - ASSERT(cli_pr_check == 1); + ASSERT_EQ(1, cli_pr_check); /* Did client receive the POLLIN message */ - ASSERT(cli_rd_check == 2); + ASSERT_EQ(2, cli_rd_check); /* Could we write with POLLOUT and did the server receive our POLLOUT message * through POLLIN. */ - ASSERT(srv_rd_check == 1); + ASSERT_EQ(1, srv_rd_check); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-poll.c b/test/test-poll.c index a0f28324e2f..f5a30e9a6b2 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -106,9 +106,9 @@ static uv_os_sock_t create_bound_socket (struct sockaddr_in bind_addr) { sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); #ifdef _WIN32 - ASSERT(sock != INVALID_SOCKET); + ASSERT_NE(sock, INVALID_SOCKET); #else - ASSERT(sock >= 0); + ASSERT_GE(sock, 0); #endif #ifndef _WIN32 @@ -116,12 +116,12 @@ static uv_os_sock_t create_bound_socket (struct sockaddr_in bind_addr) { /* Allow reuse of the port. */ int yes = 1; r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - ASSERT(r == 0); + ASSERT_OK(r); } #endif r = bind(sock, (const struct sockaddr*) &bind_addr, sizeof bind_addr); - ASSERT(r == 0); + ASSERT_OK(r); return sock; } @@ -163,12 +163,12 @@ static connection_context_t* create_connection_context( r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock); context->open_handles++; context->poll_handle.data = context; - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(uv_default_loop(), &context->timer_handle); context->open_handles++; context->timer_handle.data = context; - ASSERT(r == 0); + ASSERT_OK(r); return context; } @@ -179,15 +179,15 @@ static void connection_close_cb(uv_handle_t* handle) { if (--context->open_handles == 0) { if (test_mode == DUPLEX || context->is_server_connection) { - ASSERT(context->read == TRANSFER_BYTES); + ASSERT_EQ(context->read, TRANSFER_BYTES); } else { - ASSERT(context->read == 0); + ASSERT_OK(context->read); } if (test_mode == DUPLEX || !context->is_server_connection) { - ASSERT(context->sent == TRANSFER_BYTES); + ASSERT_EQ(context->sent, TRANSFER_BYTES); } else { - ASSERT(context->sent == 0); + ASSERT_OK(context->sent); } closed_connections++; @@ -208,7 +208,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { unsigned int new_events; int r; - ASSERT(status == 0); + ASSERT_OK(status); ASSERT(events & context->events); ASSERT(!(events & ~context->events)); @@ -226,7 +226,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { do r = recv(context->sock, buffer, sizeof buffer, 0); while (r == -1 && errno == EINTR); - ASSERT(r >= 0); + ASSERT_GE(r, 0); if (r > 0) { context->read += r; @@ -306,7 +306,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { static char buffer[103]; int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer); - ASSERT(send_bytes > 0); + ASSERT_GT(send_bytes, 0); do r = send(context->sock, buffer, send_bytes, 0); @@ -318,7 +318,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { break; } - ASSERT(r > 0); + ASSERT_GT(r, 0); context->sent += r; valid_writable_wakeups++; break; @@ -330,7 +330,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { static char buffer[1234]; int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer); - ASSERT(send_bytes > 0); + ASSERT_GT(send_bytes, 0); do r = send(context->sock, buffer, send_bytes, 0); @@ -342,18 +342,18 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { break; } - ASSERT(r > 0); + ASSERT_GT(r, 0); valid_writable_wakeups++; context->sent += r; while (context->sent < TRANSFER_BYTES) { send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer); - ASSERT(send_bytes > 0); + ASSERT_GT(send_bytes, 0); do r = send(context->sock, buffer, send_bytes, 0); while (r == -1 && errno == EINTR); - ASSERT(r != 0); + ASSERT(r); if (r < 0) { ASSERT(got_eagain()); @@ -403,7 +403,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { #else r = shutdown(context->sock, SHUT_WR); #endif - ASSERT(r == 0); + ASSERT_OK(r); context->sent_fin = 1; new_events &= ~UV_WRITABLE; } @@ -432,9 +432,9 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { /* Assert that uv_is_active works correctly for poll handles. */ if (context->events != 0) { - ASSERT(1 == uv_is_active((uv_handle_t*) handle)); + ASSERT_EQ(1, uv_is_active((uv_handle_t*) handle)); } else { - ASSERT(0 == uv_is_active((uv_handle_t*) handle)); + ASSERT_OK(uv_is_active((uv_handle_t*) handle)); } } @@ -444,7 +444,7 @@ static void delay_timer_cb(uv_timer_t* timer) { int r; /* Timer should auto stop. */ - ASSERT(0 == uv_is_active((uv_handle_t*) timer)); + ASSERT_OK(uv_is_active((uv_handle_t*) timer)); /* Add the requested events to the poll mask. */ ASSERT(context->delayed_events != 0); @@ -454,7 +454,7 @@ static void delay_timer_cb(uv_timer_t* timer) { r = uv_poll_start(&context->poll_handle, context->events, connection_poll_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -471,7 +471,7 @@ static server_context_t* create_server_context( r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock); context->poll_handle.data = context; - ASSERT(r == 0); + ASSERT_OK(r); return context; } @@ -500,9 +500,9 @@ static void server_poll_cb(uv_poll_t* handle, int status, int events) { addr_len = sizeof addr; sock = accept(server_context->sock, (struct sockaddr*) &addr, &addr_len); #ifdef _WIN32 - ASSERT(sock != INVALID_SOCKET); + ASSERT_NE(sock, INVALID_SOCKET); #else - ASSERT(sock >= 0); + ASSERT_GE(sock, 0); #endif connection_context = create_connection_context(sock, 1); @@ -510,7 +510,7 @@ static void server_poll_cb(uv_poll_t* handle, int status, int events) { r = uv_poll_start(&connection_context->poll_handle, UV_READABLE | UV_WRITABLE | UV_DISCONNECT, connection_poll_cb); - ASSERT(r == 0); + ASSERT_OK(r); if (++server_context->connections == NUM_CLIENTS) { close_socket(server_context->sock); @@ -525,15 +525,15 @@ static void start_server(void) { uv_os_sock_t sock; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); sock = create_bound_socket(addr); context = create_server_context(sock); r = listen(sock, 100); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_poll_start(&context->poll_handle, UV_READABLE, server_poll_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -544,8 +544,8 @@ static void start_client(void) { struct sockaddr_in addr; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); - ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", 0, &addr)); sock = create_bound_socket(addr); context = create_connection_context(sock, 0); @@ -554,7 +554,7 @@ static void start_client(void) { r = uv_poll_start(&context->poll_handle, UV_READABLE | UV_WRITABLE | UV_DISCONNECT, connection_poll_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = connect(sock, (struct sockaddr*) &server_addr, sizeof server_addr); ASSERT(r == 0 || got_eagain()); @@ -568,7 +568,7 @@ static void start_poll_test(void) { { struct WSAData wsa_data; int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); - ASSERT(r == 0); + ASSERT_OK(r); } #endif @@ -578,16 +578,16 @@ static void start_poll_test(void) { start_client(); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); /* Assert that at most five percent of the writable wakeups was spurious. */ - ASSERT(spurious_writable_wakeups == 0 || - (valid_writable_wakeups + spurious_writable_wakeups) / - spurious_writable_wakeups > 20); + ASSERT_NE(spurious_writable_wakeups == 0 || + (valid_writable_wakeups + spurious_writable_wakeups) / + spurious_writable_wakeups > 20, 0); - ASSERT(closed_connections == NUM_CLIENTS * 2); + ASSERT_EQ(closed_connections, NUM_CLIENTS * 2); #if !defined(__sun) && !defined(_AIX) && !defined(__MVS__) - ASSERT(disconnects == NUM_CLIENTS * 2); + ASSERT_EQ(disconnects, NUM_CLIENTS * 2); #endif MAKE_VALGRIND_HAPPY(uv_default_loop()); } @@ -642,9 +642,9 @@ TEST_IMPL(poll_bad_fdtype) { #else fd = open(".", O_RDONLY); #endif - ASSERT(fd != -1); - ASSERT(0 != uv_poll_init(uv_default_loop(), &poll_handle, fd)); - ASSERT(0 == close(fd)); + ASSERT_NE(fd, -1); + ASSERT_NE(0, uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT_OK(close(fd)); #endif MAKE_VALGRIND_HAPPY(uv_default_loop()); @@ -658,15 +658,15 @@ TEST_IMPL(poll_nested_epoll) { int fd; fd = epoll_create(1); - ASSERT(fd != -1); + ASSERT_NE(fd, -1); - ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd)); - ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort)); - ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + ASSERT_OK(uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT_OK(uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort)); + ASSERT_NE(0, uv_run(uv_default_loop(), UV_RUN_NOWAIT)); uv_close((uv_handle_t*) &poll_handle, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(0 == close(fd)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(close(fd)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -680,15 +680,15 @@ TEST_IMPL(poll_nested_kqueue) { int fd; fd = kqueue(); - ASSERT(fd != -1); + ASSERT_NE(fd, -1); - ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, fd)); - ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort)); - ASSERT(0 != uv_run(uv_default_loop(), UV_RUN_NOWAIT)); + ASSERT_OK(uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT_OK(uv_poll_start(&poll_handle, UV_READABLE, (uv_poll_cb) abort)); + ASSERT_NE(0, uv_run(uv_default_loop(), UV_RUN_NOWAIT)); uv_close((uv_handle_t*) &poll_handle, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(0 == close(fd)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(close(fd)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-process-priority.c b/test/test-process-priority.c index b3d0a85bdd7..941e4b36391 100644 --- a/test/test-process-priority.c +++ b/test/test-process-priority.c @@ -35,7 +35,7 @@ TEST_IMPL(process_priority) { /* Verify that passing a NULL pointer returns UV_EINVAL. */ r = uv_os_getpriority(0, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); /* Verify that all valid values work. */ for (i = UV_PRIORITY_HIGHEST; i <= UV_PRIORITY_LOW; i++) { @@ -46,38 +46,38 @@ TEST_IMPL(process_priority) { if (r == UV_EACCES) continue; - ASSERT(r == 0); - ASSERT(uv_os_getpriority(0, &priority) == 0); + ASSERT_OK(r); + ASSERT_OK(uv_os_getpriority(0, &priority)); /* Verify that the priority values match on Unix, and are range mapped on Windows. */ #ifndef _WIN32 - ASSERT(priority == i); + ASSERT_EQ(priority, i); #else /* On Windows, only elevated users can set UV_PRIORITY_HIGHEST. Other users will silently be set to UV_PRIORITY_HIGH. */ if (i < UV_PRIORITY_HIGH) ASSERT(priority == UV_PRIORITY_HIGHEST || priority == UV_PRIORITY_HIGH); else if (i < UV_PRIORITY_ABOVE_NORMAL) - ASSERT(priority == UV_PRIORITY_HIGH); + ASSERT_EQ(priority, UV_PRIORITY_HIGH); else if (i < UV_PRIORITY_NORMAL) - ASSERT(priority == UV_PRIORITY_ABOVE_NORMAL); + ASSERT_EQ(priority, UV_PRIORITY_ABOVE_NORMAL); else if (i < UV_PRIORITY_BELOW_NORMAL) - ASSERT(priority == UV_PRIORITY_NORMAL); + ASSERT_EQ(priority, UV_PRIORITY_NORMAL); else if (i < UV_PRIORITY_LOW) - ASSERT(priority == UV_PRIORITY_BELOW_NORMAL); + ASSERT_EQ(priority, UV_PRIORITY_BELOW_NORMAL); else - ASSERT(priority == UV_PRIORITY_LOW); + ASSERT_EQ(priority, UV_PRIORITY_LOW); #endif /* Verify that the current PID and 0 are equivalent. */ - ASSERT(uv_os_getpriority(uv_os_getpid(), &r) == 0); - ASSERT(priority == r); + ASSERT_OK(uv_os_getpriority(uv_os_getpid(), &r)); + ASSERT_EQ(priority, r); } /* Verify that invalid priorities return UV_EINVAL. */ - ASSERT(uv_os_setpriority(0, UV_PRIORITY_HIGHEST - 1) == UV_EINVAL); - ASSERT(uv_os_setpriority(0, UV_PRIORITY_LOW + 1) == UV_EINVAL); + ASSERT_EQ(uv_os_setpriority(0, UV_PRIORITY_HIGHEST - 1), UV_EINVAL); + ASSERT_EQ(uv_os_setpriority(0, UV_PRIORITY_LOW + 1), UV_EINVAL); return 0; } diff --git a/test/test-process-title-threadsafe.c b/test/test-process-title-threadsafe.c index 927643cc8c9..05baaf44a45 100644 --- a/test/test-process-title-threadsafe.c +++ b/test/test-process-title-threadsafe.c @@ -46,7 +46,7 @@ static void getter_thread_body(void* arg) { getter_sem = arg; while (UV_EAGAIN == uv_sem_trywait(getter_sem)) { - ASSERT(0 == uv_get_process_title(buffer, sizeof(buffer))); + ASSERT_OK(uv_get_process_title(buffer, sizeof(buffer))); /* The maximum size of the process title on some platforms depends on * the total size of the argv vector. It's therefore possible to read @@ -70,10 +70,10 @@ static void setter_thread_body(void* arg) { int i; for (i = 0; i < NUM_ITERATIONS; i++) { - ASSERT(0 == uv_set_process_title(titles[0])); - ASSERT(0 == uv_set_process_title(titles[1])); - ASSERT(0 == uv_set_process_title(titles[2])); - ASSERT(0 == uv_set_process_title(titles[3])); + ASSERT_OK(uv_set_process_title(titles[0])); + ASSERT_OK(uv_set_process_title(titles[1])); + ASSERT_OK(uv_set_process_title(titles[2])); + ASSERT_OK(uv_set_process_title(titles[3])); } } @@ -89,20 +89,19 @@ TEST_IMPL(process_title_threadsafe) { RETURN_SKIP("uv_(get|set)_process_title is not implemented."); #endif - ASSERT(0 == uv_set_process_title(titles[0])); + ASSERT_OK(uv_set_process_title(titles[0])); - ASSERT_EQ(0, uv_sem_init(&getter_sem, 0)); - ASSERT_EQ(0, - uv_thread_create(&getter_thread, getter_thread_body, &getter_sem)); + ASSERT_OK(uv_sem_init(&getter_sem, 0)); + ASSERT_OK(uv_thread_create(&getter_thread, getter_thread_body, &getter_sem)); for (i = 0; i < (int) ARRAY_SIZE(setter_threads); i++) - ASSERT(0 == uv_thread_create(&setter_threads[i], setter_thread_body, NULL)); + ASSERT_OK(uv_thread_create(&setter_threads[i], setter_thread_body, NULL)); for (i = 0; i < (int) ARRAY_SIZE(setter_threads); i++) - ASSERT(0 == uv_thread_join(&setter_threads[i])); + ASSERT_OK(uv_thread_join(&setter_threads[i])); uv_sem_post(&getter_sem); - ASSERT_EQ(0, uv_thread_join(&getter_thread)); + ASSERT_OK(uv_thread_join(&getter_thread)); uv_sem_destroy(&getter_sem); return 0; diff --git a/test/test-process-title.c b/test/test-process-title.c index c5cff9723da..7178cf87da4 100644 --- a/test/test-process-title.c +++ b/test/test-process-title.c @@ -29,15 +29,15 @@ static void set_title(const char* title) { int err; err = uv_get_process_title(buffer, sizeof(buffer)); - ASSERT(err == 0); + ASSERT_OK(err); err = uv_set_process_title(title); - ASSERT(err == 0); + ASSERT_OK(err); err = uv_get_process_title(buffer, sizeof(buffer)); - ASSERT(err == 0); + ASSERT_OK(err); - ASSERT(strcmp(buffer, title) == 0); + ASSERT_OK(strcmp(buffer, title)); } @@ -47,15 +47,15 @@ static void uv_get_process_title_edge_cases(void) { /* Test a NULL buffer */ r = uv_get_process_title(NULL, 100); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); /* Test size of zero */ r = uv_get_process_title(buffer, 0); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); /* Test for insufficient buffer size */ r = uv_get_process_title(buffer, 1); - ASSERT(r == UV_ENOBUFS); + ASSERT_EQ(r, UV_ENOBUFS); } @@ -77,8 +77,8 @@ TEST_IMPL(process_title) { static void exit_cb(uv_process_t* process, int64_t status, int signo) { - ASSERT(status == 0); - ASSERT(signo == 0); + ASSERT_OK(status); + ASSERT_OK(signo); uv_close((uv_handle_t*) process, NULL); } @@ -97,7 +97,7 @@ TEST_IMPL(process_title_big_argv) { #endif exepath_size = sizeof(exepath) - 1; - ASSERT(0 == uv_exepath(exepath, &exepath_size)); + ASSERT_OK(uv_exepath(exepath, &exepath_size)); exepath[exepath_size] = '\0'; memset(jumbo, 'x', sizeof(jumbo) - 1); @@ -117,8 +117,8 @@ TEST_IMPL(process_title_big_argv) { options.args = args; options.exit_cb = exit_cb; - ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -131,5 +131,5 @@ void process_title_big_argv(void) { /* Return value deliberately ignored. */ uv_get_process_title(buf, sizeof(buf)); - ASSERT(0 != strcmp(buf, "fail")); + ASSERT_NE(0, strcmp(buf, "fail")); } diff --git a/test/test-queue-foreach-delete.c b/test/test-queue-foreach-delete.c index 4fe8aecee5f..b3a2d19c408 100644 --- a/test/test-queue-foreach-delete.c +++ b/test/test-queue-foreach-delete.c @@ -71,7 +71,7 @@ static const unsigned first_handle_number_fs_event = 0; static unsigned name##_cb_calls[3]; \ \ static void name##2_cb(__VA_ARGS__) { \ - ASSERT(handle == &(name)[2]); \ + ASSERT_PTR_EQ(handle, &(name)[2]); \ if (first_handle_number_##name == 2) { \ uv_close((uv_handle_t*)&(name)[2], NULL); \ uv_close((uv_handle_t*)&(name)[1], NULL); \ @@ -80,12 +80,12 @@ static const unsigned first_handle_number_fs_event = 0; } \ \ static void name##1_cb(__VA_ARGS__) { \ - ASSERT(handle == &(name)[1]); \ + ASSERT_PTR_EQ(handle, &(name)[1]); \ ASSERT(0 && "Shouldn't be called" && (&name[0])); \ } \ \ static void name##0_cb(__VA_ARGS__) { \ - ASSERT(handle == &(name)[0]); \ + ASSERT_PTR_EQ(handle, &(name)[0]); \ if (first_handle_number_##name == 0) { \ uv_close((uv_handle_t*)&(name)[0], NULL); \ uv_close((uv_handle_t*)&(name)[1], NULL); \ @@ -105,18 +105,18 @@ static const unsigned first_handle_number_fs_event = 0; for (i = 0; i < ARRAY_SIZE(name); i++) { \ int r; \ r = uv_##name##_init((loop), &(name)[i]); \ - ASSERT(r == 0); \ + ASSERT_OK(r); \ \ r = uv_##name##_start(&(name)[i], name##_cbs[i]); \ - ASSERT(r == 0); \ + ASSERT_OK(r); \ } \ } while (0) #define END_ASSERTS(name) \ do { \ - ASSERT(name##_cb_calls[0] == 1); \ - ASSERT(name##_cb_calls[1] == 0); \ - ASSERT(name##_cb_calls[2] == 1); \ + ASSERT_EQ(1, name##_cb_calls[0]); \ + ASSERT_OK(name##_cb_calls[1]); \ + ASSERT_EQ(1, name##_cb_calls[2]); \ } while (0) DEFINE_GLOBALS_AND_CBS(idle, uv_idle_t* handle) @@ -140,13 +140,13 @@ static void init_and_start_fs_events(uv_loop_t* loop) { for (i = 0; i < ARRAY_SIZE(fs_event); i++) { int r; r = uv_fs_event_init(loop, &fs_event[i]); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fs_event_start(&fs_event[i], (uv_fs_event_cb)fs_event_cbs[i], watched_dir, 0); - ASSERT(r == 0); + ASSERT_OK(r); } } @@ -156,10 +156,10 @@ static void helper_timer_cb(uv_timer_t* thandle) { /* fire all fs_events */ r = uv_fs_utime(thandle->loop, &fs_req, watched_dir, 0, 0, NULL); - ASSERT(r == 0); - ASSERT(fs_req.result == 0); - ASSERT(fs_req.fs_type == UV_FS_UTIME); - ASSERT(strcmp(fs_req.path, watched_dir) == 0); + ASSERT_OK(r); + ASSERT_OK(fs_req.result); + ASSERT_EQ(fs_req.fs_type, UV_FS_UTIME); + ASSERT_OK(strcmp(fs_req.path, watched_dir)); uv_fs_req_cleanup(&fs_req); helper_timer_cb_calls++; @@ -182,21 +182,21 @@ TEST_IMPL(queue_foreach_delete) { /* helper timer to trigger async and fs_event callbacks */ r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, helper_timer_cb, 0, 0); - ASSERT(r == 0); + ASSERT_OK(r); #endif r = uv_run(loop, UV_RUN_NOWAIT); - ASSERT(r == 1); + ASSERT_EQ(1, r); END_ASSERTS(idle); END_ASSERTS(prepare); END_ASSERTS(check); #ifdef __linux__ - ASSERT(helper_timer_cb_calls == 1); + ASSERT_EQ(1, helper_timer_cb_calls); #endif MAKE_VALGRIND_HAPPY(loop); diff --git a/test/test-random.c b/test/test-random.c index 3ff3fa8b364..d82d05782c0 100644 --- a/test/test-random.c +++ b/test/test-random.c @@ -33,16 +33,16 @@ static void random_cb(uv_random_t* req, int status, void* buf, size_t buflen) { memset(zero, 0, sizeof(zero)); - ASSERT(0 == status); - ASSERT(buf == (void*) scratch); + ASSERT_OK(status); + ASSERT_PTR_EQ(buf, (void*) scratch); if (random_cb_called == 0) { - ASSERT(buflen == 0); - ASSERT(0 == memcmp(scratch, zero, sizeof(zero))); + ASSERT_OK(buflen); + ASSERT_OK(memcmp(scratch, zero, sizeof(zero))); } else { - ASSERT(buflen == sizeof(scratch)); + ASSERT_EQ(buflen, sizeof(scratch)); /* Buy a lottery ticket if you manage to trip this assertion. */ - ASSERT(0 != memcmp(scratch, zero, sizeof(zero))); + ASSERT_NE(0, memcmp(scratch, zero, sizeof(zero))); } random_cb_called++; @@ -54,21 +54,21 @@ TEST_IMPL(random_async) { uv_loop_t* loop; loop = uv_default_loop(); - ASSERT(UV_EINVAL == uv_random(loop, &req, scratch, sizeof(scratch), -1, - random_cb)); - ASSERT(UV_E2BIG == uv_random(loop, &req, scratch, -1, -1, random_cb)); + ASSERT_EQ(UV_EINVAL, uv_random(loop, &req, scratch, sizeof(scratch), -1, + random_cb)); + ASSERT_EQ(UV_E2BIG, uv_random(loop, &req, scratch, -1, -1, random_cb)); - ASSERT(0 == uv_random(loop, &req, scratch, 0, 0, random_cb)); - ASSERT(0 == random_cb_called); + ASSERT_OK(uv_random(loop, &req, scratch, 0, 0, random_cb)); + ASSERT_OK(random_cb_called); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(1 == random_cb_called); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, random_cb_called); - ASSERT(0 == uv_random(loop, &req, scratch, sizeof(scratch), 0, random_cb)); - ASSERT(1 == random_cb_called); + ASSERT_OK(uv_random(loop, &req, scratch, sizeof(scratch), 0, random_cb)); + ASSERT_EQ(1, random_cb_called); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(2 == random_cb_called); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(2, random_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -79,15 +79,15 @@ TEST_IMPL(random_sync) { char zero[256]; char buf[256]; - ASSERT(UV_EINVAL == uv_random(NULL, NULL, buf, sizeof(buf), -1, NULL)); - ASSERT(UV_E2BIG == uv_random(NULL, NULL, buf, -1, -1, NULL)); + ASSERT_EQ(UV_EINVAL, uv_random(NULL, NULL, buf, sizeof(buf), -1, NULL)); + ASSERT_EQ(UV_E2BIG, uv_random(NULL, NULL, buf, -1, -1, NULL)); memset(buf, 0, sizeof(buf)); - ASSERT(0 == uv_random(NULL, NULL, buf, sizeof(buf), 0, NULL)); + ASSERT_OK(uv_random(NULL, NULL, buf, sizeof(buf), 0, NULL)); /* Buy a lottery ticket if you manage to trip this assertion. */ memset(zero, 0, sizeof(zero)); - ASSERT(0 != memcmp(buf, zero, sizeof(zero))); + ASSERT_NE(0, memcmp(buf, zero, sizeof(zero))); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-readable-on-eof.c b/test/test-readable-on-eof.c index 1162f8db1d0..2137ac5947f 100644 --- a/test/test-readable-on-eof.c +++ b/test/test-readable-on-eof.c @@ -35,7 +35,7 @@ static int close_cb_called; static void write_cb(uv_write_t* req, int status) { write_cb_called++; - ASSERT_EQ(status, 0); + ASSERT_OK(status); } static void alloc_cb(uv_handle_t* handle, @@ -54,16 +54,16 @@ static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { int r; ASSERT_EQ(nread, UV_EOF); - ASSERT_EQ(uv_is_readable(handle), 1); - ASSERT_EQ(uv_is_writable(handle), 1); + ASSERT_EQ(1, uv_is_readable(handle)); + ASSERT_EQ(1, uv_is_writable(handle)); if (++read_cb_called == 3) { uv_close((uv_handle_t*) handle, close_cb); - ASSERT_EQ(uv_is_readable(handle), 0); - ASSERT_EQ(uv_is_writable(handle), 0); + ASSERT_OK(uv_is_readable(handle)); + ASSERT_OK(uv_is_writable(handle)); } else { r = uv_read_start((uv_stream_t*) &tcp_client, alloc_cb, read_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } } @@ -72,7 +72,7 @@ static void connect_cb(uv_connect_t* req, int status) { uv_buf_t close_me; connect_cb_called++; - ASSERT_EQ(status, 0); + ASSERT_OK(status); read_cb((uv_stream_t*) &tcp_client, UV_EOF, NULL); @@ -84,27 +84,26 @@ static void connect_cb(uv_connect_t* req, int status) { 1, write_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } TEST_IMPL(readable_on_eof) { struct sockaddr_in sa; - ASSERT_EQ(uv_ip4_addr("127.0.0.1", TEST_PORT, &sa), 0); - ASSERT_EQ(uv_loop_init(&loop), 0); - ASSERT_EQ(uv_tcp_init(&loop, &tcp_client), 0); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &sa)); + ASSERT_OK(uv_loop_init(&loop)); + ASSERT_OK(uv_tcp_init(&loop, &tcp_client)); - ASSERT_EQ(uv_tcp_connect(&connect_req, + ASSERT_OK(uv_tcp_connect(&connect_req, &tcp_client, (const struct sockaddr*) &sa, - connect_cb), - 0); + connect_cb)); - ASSERT_EQ(uv_run(&loop, UV_RUN_DEFAULT), 0); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); - ASSERT_EQ(connect_cb_called, 1); - ASSERT_EQ(read_cb_called, 3); - ASSERT_EQ(write_cb_called, 1); - ASSERT_EQ(close_cb_called, 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(3, read_cb_called); + ASSERT_EQ(1, write_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(&loop); return 0; diff --git a/test/test-ref.c b/test/test-ref.c index 7a9a0b9315b..dbe94f7168b 100644 --- a/test/test-ref.c +++ b/test/test-ref.c @@ -47,9 +47,9 @@ static void close_cb(uv_handle_t* handle) { static void do_close(void* handle) { close_cb_called = 0; uv_close((uv_handle_t*)handle, close_cb); - ASSERT(close_cb_called == 0); + ASSERT_OK(close_cb_called); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); } @@ -69,13 +69,13 @@ static void req_cb(uv_handle_t* req, int status) { static void shutdown_cb(uv_shutdown_t* req, int status) { - ASSERT(req == &shutdown_req); + ASSERT_PTR_EQ(req, &shutdown_req); shutdown_cb_called++; } static void write_cb(uv_write_t* req, int status) { - ASSERT(req == &write_req); + ASSERT_PTR_EQ(req, &write_req); uv_shutdown(&shutdown_req, req->handle, shutdown_cb); write_cb_called++; } @@ -83,8 +83,8 @@ static void write_cb(uv_write_t* req, int status) { static void connect_and_write(uv_connect_t* req, int status) { uv_buf_t buf = uv_buf_init(buffer, sizeof buffer); - ASSERT(req == &connect_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &connect_req); + ASSERT_OK(status); uv_write(&write_req, req->handle, &buf, 1, write_cb); connect_cb_called++; } @@ -92,8 +92,8 @@ static void connect_and_write(uv_connect_t* req, int status) { static void connect_and_shutdown(uv_connect_t* req, int status) { - ASSERT(req == &connect_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &connect_req); + ASSERT_OK(status); uv_shutdown(&shutdown_req, req->handle, shutdown_cb); connect_cb_called++; } @@ -250,7 +250,7 @@ TEST_IMPL(tcp_ref2b) { uv_unref((uv_handle_t*)&h); uv_close((uv_handle_t*)&h, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -259,7 +259,7 @@ TEST_IMPL(tcp_ref2b) { TEST_IMPL(tcp_ref3) { struct sockaddr_in addr; uv_tcp_t h; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); uv_tcp_init(uv_default_loop(), &h); uv_tcp_connect(&connect_req, &h, @@ -267,8 +267,8 @@ TEST_IMPL(tcp_ref3) { connect_and_shutdown); uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(connect_cb_called == 1); - ASSERT(shutdown_cb_called == 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, shutdown_cb_called); do_close(&h); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -278,7 +278,7 @@ TEST_IMPL(tcp_ref3) { TEST_IMPL(tcp_ref4) { struct sockaddr_in addr; uv_tcp_t h; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); uv_tcp_init(uv_default_loop(), &h); uv_tcp_connect(&connect_req, &h, @@ -286,9 +286,9 @@ TEST_IMPL(tcp_ref4) { connect_and_write); uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(connect_cb_called == 1); - ASSERT(write_cb_called == 1); - ASSERT(shutdown_cb_called == 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, write_cb_called); + ASSERT_EQ(1, shutdown_cb_called); do_close(&h); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -309,7 +309,7 @@ TEST_IMPL(udp_ref) { TEST_IMPL(udp_ref2) { struct sockaddr_in addr; uv_udp_t h; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); uv_udp_init(uv_default_loop(), &h); uv_udp_bind(&h, (const struct sockaddr*) &addr, 0); uv_udp_recv_start(&h, (uv_alloc_cb)fail_cb, (uv_udp_recv_cb)fail_cb); @@ -327,7 +327,7 @@ TEST_IMPL(udp_ref3) { uv_udp_send_t req; uv_udp_t h; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); uv_udp_init(uv_default_loop(), &h); uv_udp_send(&req, &h, @@ -337,7 +337,7 @@ TEST_IMPL(udp_ref3) { (uv_udp_send_cb) req_cb); uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(req_cb_called == 1); + ASSERT_EQ(1, req_cb_called); do_close(&h); MAKE_VALGRIND_HAPPY(uv_default_loop()); @@ -374,8 +374,8 @@ TEST_IMPL(pipe_ref3) { uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_shutdown); uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(connect_cb_called == 1); - ASSERT(shutdown_cb_called == 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, shutdown_cb_called); do_close(&h); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -388,9 +388,9 @@ TEST_IMPL(pipe_ref4) { uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_write); uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(connect_cb_called == 1); - ASSERT(write_cb_called == 1); - ASSERT(shutdown_cb_called == 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, write_cb_called); + ASSERT_EQ(1, shutdown_cb_called); do_close(&h); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -410,7 +410,7 @@ TEST_IMPL(process_ref) { exepath_size = sizeof(exepath); r = uv_exepath(exepath, &exepath_size); - ASSERT(r == 0); + ASSERT_OK(r); argv[0] = exepath; options.file = exepath; @@ -418,13 +418,13 @@ TEST_IMPL(process_ref) { options.exit_cb = NULL; r = uv_spawn(uv_default_loop(), &h, &options); - ASSERT(r == 0); + ASSERT_OK(r); uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); r = uv_process_kill(&h, /* SIGTERM */ 15); - ASSERT(r == 0); + ASSERT_OK(r); do_close(&h); @@ -437,9 +437,9 @@ TEST_IMPL(has_ref) { uv_idle_t h; uv_idle_init(uv_default_loop(), &h); uv_ref((uv_handle_t*)&h); - ASSERT(uv_has_ref((uv_handle_t*)&h) == 1); + ASSERT_EQ(1, uv_has_ref((uv_handle_t*)&h)); uv_unref((uv_handle_t*)&h); - ASSERT(uv_has_ref((uv_handle_t*)&h) == 0); + ASSERT_OK(uv_has_ref((uv_handle_t*)&h)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-run-nowait.c b/test/test-run-nowait.c index 704105376fa..89f5f55b18a 100644 --- a/test/test-run-nowait.c +++ b/test/test-run-nowait.c @@ -27,7 +27,7 @@ static int timer_called = 0; static void timer_cb(uv_timer_t* handle) { - ASSERT(handle == &timer_handle); + ASSERT_PTR_EQ(handle, &timer_handle); timer_called = 1; } @@ -38,8 +38,8 @@ TEST_IMPL(run_nowait) { uv_timer_start(&timer_handle, timer_cb, 100, 100); r = uv_run(uv_default_loop(), UV_RUN_NOWAIT); - ASSERT(r != 0); - ASSERT(timer_called == 0); + ASSERT(r); + ASSERT_OK(timer_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-run-once.c b/test/test-run-once.c index ee332fa1a05..0ae0082c637 100644 --- a/test/test-run-once.c +++ b/test/test-run-once.c @@ -29,7 +29,7 @@ static int idle_counter; static void idle_cb(uv_idle_t* handle) { - ASSERT(handle == &idle_handle); + ASSERT_PTR_EQ(handle, &idle_handle); if (++idle_counter == NUM_TICKS) uv_idle_stop(handle); @@ -41,7 +41,7 @@ TEST_IMPL(run_once) { uv_idle_start(&idle_handle, idle_cb); while (uv_run(uv_default_loop(), UV_RUN_ONCE)); - ASSERT(idle_counter == NUM_TICKS); + ASSERT_EQ(idle_counter, NUM_TICKS); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-semaphore.c b/test/test-semaphore.c index ac03bb08f17..ad54808d623 100644 --- a/test/test-semaphore.c +++ b/test/test-semaphore.c @@ -40,7 +40,7 @@ static void worker(void* arg) { uv_sleep(c->delay); uv_mutex_lock(&c->mutex); - ASSERT(c->posted == 0); + ASSERT_OK(c->posted); uv_sem_post(&c->sem); c->posted = 1; uv_mutex_unlock(&c->mutex); @@ -53,17 +53,17 @@ TEST_IMPL(semaphore_1) { memset(&wc, 0, sizeof(wc)); - ASSERT(0 == uv_sem_init(&wc.sem, 0)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + ASSERT_OK(uv_sem_init(&wc.sem, 0)); + ASSERT_OK(uv_mutex_init(&wc.mutex)); + ASSERT_OK(uv_thread_create(&thread, worker, &wc)); uv_sleep(100); uv_mutex_lock(&wc.mutex); - ASSERT(wc.posted == 1); + ASSERT_EQ(1, wc.posted); uv_sem_wait(&wc.sem); /* should not block */ uv_mutex_unlock(&wc.mutex); /* ergo, it should be ok to unlock after wait */ - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); uv_sem_destroy(&wc.sem); @@ -78,13 +78,13 @@ TEST_IMPL(semaphore_2) { memset(&wc, 0, sizeof(wc)); wc.delay = 100; - ASSERT(0 == uv_sem_init(&wc.sem, 0)); - ASSERT(0 == uv_mutex_init(&wc.mutex)); - ASSERT(0 == uv_thread_create(&thread, worker, &wc)); + ASSERT_OK(uv_sem_init(&wc.sem, 0)); + ASSERT_OK(uv_mutex_init(&wc.mutex)); + ASSERT_OK(uv_thread_create(&thread, worker, &wc)); uv_sem_wait(&wc.sem); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); uv_sem_destroy(&wc.sem); @@ -95,15 +95,15 @@ TEST_IMPL(semaphore_2) { TEST_IMPL(semaphore_3) { uv_sem_t sem; - ASSERT(0 == uv_sem_init(&sem, 3)); + ASSERT_OK(uv_sem_init(&sem, 3)); uv_sem_wait(&sem); /* should not block */ uv_sem_wait(&sem); /* should not block */ - ASSERT(0 == uv_sem_trywait(&sem)); - ASSERT(UV_EAGAIN == uv_sem_trywait(&sem)); + ASSERT_OK(uv_sem_trywait(&sem)); + ASSERT_EQ(UV_EAGAIN, uv_sem_trywait(&sem)); uv_sem_post(&sem); - ASSERT(0 == uv_sem_trywait(&sem)); - ASSERT(UV_EAGAIN == uv_sem_trywait(&sem)); + ASSERT_OK(uv_sem_trywait(&sem)); + ASSERT_EQ(UV_EAGAIN, uv_sem_trywait(&sem)); uv_sem_destroy(&sem); diff --git a/test/test-shutdown-close.c b/test/test-shutdown-close.c index cb478b5fdd2..306404afb45 100644 --- a/test/test-shutdown-close.c +++ b/test/test-shutdown-close.c @@ -37,7 +37,7 @@ static int close_cb_called = 0; static void shutdown_cb(uv_shutdown_t* req, int status) { - ASSERT(req == &shutdown_req); + ASSERT_PTR_EQ(req, &shutdown_req); ASSERT(status == 0 || status == UV_ECANCELED); shutdown_cb_called++; } @@ -51,14 +51,14 @@ static void close_cb(uv_handle_t* handle) { static void connect_cb(uv_connect_t* req, int status) { int r; - ASSERT(req == &connect_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &connect_req); + ASSERT_OK(status); r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb); - ASSERT(r == 0); - ASSERT(0 == uv_is_closing((uv_handle_t*) req->handle)); + ASSERT_OK(r); + ASSERT_OK(uv_is_closing((uv_handle_t*) req->handle)); uv_close((uv_handle_t*) req->handle, close_cb); - ASSERT(1 == uv_is_closing((uv_handle_t*) req->handle)); + ASSERT_EQ(1, uv_is_closing((uv_handle_t*) req->handle)); connect_cb_called++; } @@ -69,20 +69,20 @@ TEST_IMPL(shutdown_close_tcp) { uv_tcp_t h; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &h); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &h, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(connect_cb_called == 1); - ASSERT(shutdown_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, shutdown_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -94,14 +94,14 @@ TEST_IMPL(shutdown_close_pipe) { int r; r = uv_pipe_init(uv_default_loop(), &h, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_cb); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(connect_cb_called == 1); - ASSERT(shutdown_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, shutdown_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-shutdown-eof.c b/test/test-shutdown-eof.c index 9c0b85652ae..6669c29769b 100644 --- a/test/test-shutdown-eof.c +++ b/test/test-shutdown-eof.c @@ -46,7 +46,7 @@ static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) { - ASSERT((uv_tcp_t*)t == &tcp); + ASSERT_PTR_EQ((uv_tcp_t*)t, &tcp); if (nread == 0) { free(buf->base); @@ -54,14 +54,14 @@ static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) { } if (!got_q) { - ASSERT(nread == 1); + ASSERT_EQ(1, nread); ASSERT(!got_eof); - ASSERT(buf->base[0] == 'Q'); + ASSERT_EQ(buf->base[0], 'Q'); free(buf->base); got_q = 1; puts("got Q"); } else { - ASSERT(nread == UV_EOF); + ASSERT_EQ(nread, UV_EOF); if (buf->base) { free(buf->base); } @@ -72,24 +72,24 @@ static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) { static void shutdown_cb(uv_shutdown_t *req, int status) { - ASSERT(req == &shutdown_req); + ASSERT_PTR_EQ(req, &shutdown_req); - ASSERT(called_connect_cb == 1); + ASSERT_EQ(1, called_connect_cb); ASSERT(!got_eof); - ASSERT(called_tcp_close_cb == 0); - ASSERT(called_timer_close_cb == 0); - ASSERT(called_timer_cb == 0); + ASSERT_OK(called_tcp_close_cb); + ASSERT_OK(called_timer_close_cb); + ASSERT_OK(called_timer_cb); called_shutdown_cb++; } static void connect_cb(uv_connect_t *req, int status) { - ASSERT(status == 0); - ASSERT(req == &connect_req); + ASSERT_OK(status); + ASSERT_PTR_EQ(req, &connect_req); /* Start reading from our connection so we can receive the EOF. */ - ASSERT_EQ(0, uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb)); + ASSERT_OK(uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb)); /* Check error handling. */ ASSERT_EQ(UV_EALREADY, uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb)); @@ -107,37 +107,37 @@ static void connect_cb(uv_connect_t *req, int status) { uv_shutdown(&shutdown_req, (uv_stream_t*) &tcp, shutdown_cb); called_connect_cb++; - ASSERT(called_shutdown_cb == 0); + ASSERT_OK(called_shutdown_cb); } static void tcp_close_cb(uv_handle_t* handle) { - ASSERT(handle == (uv_handle_t*) &tcp); + ASSERT_PTR_EQ(handle, (uv_handle_t*) &tcp); - ASSERT(called_connect_cb == 1); + ASSERT_EQ(1, called_connect_cb); ASSERT(got_q); ASSERT(got_eof); - ASSERT(called_timer_cb == 1); + ASSERT_EQ(1, called_timer_cb); called_tcp_close_cb++; } static void timer_close_cb(uv_handle_t* handle) { - ASSERT(handle == (uv_handle_t*) &timer); + ASSERT_PTR_EQ(handle, (uv_handle_t*) &timer); called_timer_close_cb++; } static void timer_cb(uv_timer_t* handle) { - ASSERT(handle == &timer); + ASSERT_PTR_EQ(handle, &timer); uv_close((uv_handle_t*) handle, timer_close_cb); /* * The most important assert of the test: we have not received * tcp_close_cb yet. */ - ASSERT(called_tcp_close_cb == 0); + ASSERT_OK(called_tcp_close_cb); uv_close((uv_handle_t*) &tcp, tcp_close_cb); called_timer_cb++; @@ -158,11 +158,11 @@ TEST_IMPL(shutdown_eof) { qbuf.len = 1; r = uv_timer_init(uv_default_loop(), &timer); - ASSERT(r == 0); + ASSERT_OK(r); uv_timer_start(&timer, timer_cb, 100, 0); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); r = uv_tcp_init(uv_default_loop(), &tcp); ASSERT(!r); @@ -174,13 +174,13 @@ TEST_IMPL(shutdown_eof) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(called_connect_cb == 1); - ASSERT(called_shutdown_cb == 1); + ASSERT_EQ(1, called_connect_cb); + ASSERT_EQ(1, called_shutdown_cb); ASSERT(got_eof); ASSERT(got_q); - ASSERT(called_tcp_close_cb == 1); - ASSERT(called_timer_close_cb == 1); - ASSERT(called_timer_cb == 1); + ASSERT_EQ(1, called_tcp_close_cb); + ASSERT_EQ(1, called_timer_close_cb); + ASSERT_EQ(1, called_timer_cb); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-shutdown-simultaneous.c b/test/test-shutdown-simultaneous.c index 14cc443730d..0dd8e353c86 100644 --- a/test/test-shutdown-simultaneous.c +++ b/test/test-shutdown-simultaneous.c @@ -44,8 +44,8 @@ static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { static void shutdown_cb(uv_shutdown_t *req, int status) { ASSERT_PTR_EQ(req, &shutdown_req); - ASSERT_EQ(called_connect_cb, 1); - ASSERT_EQ(called_tcp_close_cb, 0); + ASSERT_EQ(1, called_connect_cb); + ASSERT_OK(called_tcp_close_cb); } @@ -58,8 +58,8 @@ static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) { } if (!got_q) { - ASSERT_EQ(nread, 4); - ASSERT_EQ(got_eof, 0); + ASSERT_EQ(4, nread); + ASSERT_OK(got_eof); ASSERT_MEM_EQ(buf->base, "QQSS", 4); free(buf->base); got_q = 1; @@ -79,11 +79,11 @@ static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) { static void connect_cb(uv_connect_t *req, int status) { - ASSERT_EQ(status, 0); + ASSERT_OK(status); ASSERT_PTR_EQ(req, &connect_req); /* Start reading from our connection so we can receive the EOF. */ - ASSERT_EQ(0, uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb)); + ASSERT_OK(uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb)); /* Check error handling. */ ASSERT_EQ(UV_EALREADY, uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb)); @@ -98,7 +98,7 @@ static void connect_cb(uv_connect_t *req, int status) { ASSERT_EQ(qbuf.len, uv_try_write((uv_stream_t*) &tcp, &qbuf, 1)); called_connect_cb++; - ASSERT_EQ(called_shutdown_cb, 0); + ASSERT_OK(called_shutdown_cb); } @@ -113,22 +113,22 @@ TEST_IMPL(shutdown_simultaneous) { qbuf.base = "QQSS"; qbuf.len = 4; - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); r = uv_tcp_init(uv_default_loop(), &tcp); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &tcp, (const struct sockaddr*) &server_addr, connect_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(called_connect_cb, 1); - ASSERT_EQ(called_shutdown_cb, 1); - ASSERT_EQ(got_eof, 1); - ASSERT_EQ(got_q, 1); + ASSERT_EQ(1, called_connect_cb); + ASSERT_EQ(1, called_shutdown_cb); + ASSERT_EQ(1, got_eof); + ASSERT_EQ(1, got_q); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-shutdown-twice.c b/test/test-shutdown-twice.c index d936a70cb7d..c21a98340bd 100644 --- a/test/test-shutdown-twice.c +++ b/test/test-shutdown-twice.c @@ -37,8 +37,8 @@ static void close_cb(uv_handle_t* handle) { } static void shutdown_cb(uv_shutdown_t* req, int status) { - ASSERT(req == &req1); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &req1); + ASSERT_OK(status); shutdown_cb_called++; uv_close((uv_handle_t*) req->handle, close_cb); } @@ -46,12 +46,12 @@ static void shutdown_cb(uv_shutdown_t* req, int status) { static void connect_cb(uv_connect_t* req, int status) { int r; - ASSERT(status == 0); + ASSERT_OK(status); r = uv_shutdown(&req1, req->handle, shutdown_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_shutdown(&req2, req->handle, shutdown_cb); - ASSERT(r != 0); + ASSERT(r); } @@ -63,22 +63,22 @@ TEST_IMPL(shutdown_twice) { uv_connect_t connect_req; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); loop = uv_default_loop(); r = uv_tcp_init(loop, &h); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &h, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(shutdown_cb_called == 1); + ASSERT_EQ(1, shutdown_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-signal-multiple-loops.c b/test/test-signal-multiple-loops.c index de511fc0680..e68eabf6fc2 100644 --- a/test/test-signal-multiple-loops.c +++ b/test/test-signal-multiple-loops.c @@ -66,14 +66,14 @@ static void increment_counter(int* counter) { static void signal1_cb(uv_signal_t* handle, int signum) { - ASSERT(signum == SIGUSR1); + ASSERT_EQ(signum, SIGUSR1); increment_counter(&signal1_cb_counter); uv_signal_stop(handle); } static void signal2_cb(uv_signal_t* handle, int signum) { - ASSERT(signum == SIGUSR2); + ASSERT_EQ(signum, SIGUSR2); increment_counter(&signal2_cb_counter); uv_signal_stop(handle); } @@ -89,25 +89,25 @@ static void signal_handling_worker(void* context) { action = (enum signal_action) (uintptr_t) context; - ASSERT(0 == uv_loop_init(&loop)); + ASSERT_OK(uv_loop_init(&loop)); /* Setup the signal watchers and start them. */ if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) { r = uv_signal_init(&loop, &signal1a); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_signal_init(&loop, &signal1b); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1); - ASSERT(r == 0); + ASSERT_OK(r); } if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) { r = uv_signal_init(&loop, &signal2); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_signal_start(&signal2, signal2_cb, SIGUSR2); - ASSERT(r == 0); + ASSERT_OK(r); } /* Signal watchers are now set up. */ @@ -117,26 +117,26 @@ static void signal_handling_worker(void* context) { * will return when all signal watchers caught a signal. */ r = uv_run(&loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); /* Restart the signal watchers. */ if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) { r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1); - ASSERT(r == 0); + ASSERT_OK(r); } if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) { r = uv_signal_start(&signal2, signal2_cb, SIGUSR2); - ASSERT(r == 0); + ASSERT_OK(r); } /* Wait for signals once more. */ uv_sem_post(&sem); r = uv_run(&loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); /* Close the watchers. */ if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) { @@ -150,7 +150,7 @@ static void signal_handling_worker(void* context) { /* Wait for the signal watchers to close. */ r = uv_run(&loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); uv_loop_close(&loop); } @@ -173,18 +173,18 @@ static void loop_creating_worker(void* context) { loop = malloc(sizeof(*loop)); ASSERT_NOT_NULL(loop); - ASSERT(0 == uv_loop_init(loop)); + ASSERT_OK(uv_loop_init(loop)); r = uv_signal_init(loop, &signal); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_signal_start(&signal, signal_unexpected_cb, SIGTERM); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &signal, NULL); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); uv_loop_close(loop); free(loop); @@ -229,17 +229,17 @@ TEST_IMPL(signal_multiple_loops) { int r; r = uv_sem_init(&sem, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_mutex_init(&lock); - ASSERT(r == 0); + ASSERT_OK(r); /* Create a couple of threads that create a destroy loops continuously. */ for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) { r = uv_thread_create(&loop_creating_threads[i], loop_creating_worker, NULL); - ASSERT(r == 0); + ASSERT_OK(r); } /* Create a couple of threads that actually handle signals. */ @@ -253,7 +253,7 @@ TEST_IMPL(signal_multiple_loops) { r = uv_thread_create(&signal_handling_threads[i], signal_handling_worker, (void*) (uintptr_t) action); - ASSERT(r == 0); + ASSERT_OK(r); } /* Wait until all threads have started and set up their signal watchers. */ @@ -261,9 +261,9 @@ TEST_IMPL(signal_multiple_loops) { uv_sem_wait(&sem); r = kill(getpid(), SIGUSR1); - ASSERT(r == 0); + ASSERT_OK(r); r = kill(getpid(), SIGUSR2); - ASSERT(r == 0); + ASSERT_OK(r); /* Wait for all threads to handle these signals. */ for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) @@ -277,14 +277,14 @@ TEST_IMPL(signal_multiple_loops) { pthread_sigmask(SIG_SETMASK, &sigset, NULL); r = kill(getpid(), SIGUSR1); - ASSERT(r == 0); + ASSERT_OK(r); r = kill(getpid(), SIGUSR2); - ASSERT(r == 0); + ASSERT_OK(r); /* Wait for all signal handling threads to exit. */ for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) { r = uv_thread_join(&signal_handling_threads[i]); - ASSERT(r == 0); + ASSERT_OK(r); } /* Tell all loop creating threads to stop. */ @@ -295,7 +295,7 @@ TEST_IMPL(signal_multiple_loops) { /* Wait for all loop creating threads to exit. */ for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) { r = uv_thread_join(&loop_creating_threads[i]); - ASSERT(r == 0); + ASSERT_OK(r); } uv_sem_destroy(&sem); @@ -306,13 +306,13 @@ TEST_IMPL(signal_multiple_loops) { /* The division by three reflects the fact that we spawn three different * thread groups of (NUM_SIGNAL_HANDLING_THREADS / 3) threads each. */ - ASSERT(signal1_cb_counter == 8 * (NUM_SIGNAL_HANDLING_THREADS / 3)); - ASSERT(signal2_cb_counter == 4 * (NUM_SIGNAL_HANDLING_THREADS / 3)); + ASSERT_EQ(signal1_cb_counter, 8 * (NUM_SIGNAL_HANDLING_THREADS / 3)); + ASSERT_EQ(signal2_cb_counter, 4 * (NUM_SIGNAL_HANDLING_THREADS / 3)); /* We don't know exactly how much loops will be created and destroyed, but at * least there should be 1 for every loop creating thread. */ - ASSERT(loop_creation_counter >= NUM_LOOP_CREATING_THREADS); + ASSERT_GE(loop_creation_counter, NUM_LOOP_CREATING_THREADS); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-signal-pending-on-close.c b/test/test-signal-pending-on-close.c index e0b9bc300b1..42a4296704b 100644 --- a/test/test-signal-pending-on-close.c +++ b/test/test-signal-pending-on-close.c @@ -35,7 +35,7 @@ static int close_cb_called; static void stop_loop_cb(uv_signal_t* signal, int signum) { - ASSERT(signum == SIGPIPE); + ASSERT_EQ(signum, SIGPIPE); uv_stop(signal->loop); } @@ -50,7 +50,7 @@ static void close_cb(uv_handle_t *handle) { static void write_cb(uv_write_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status == UV_EPIPE); + ASSERT_EQ(status, UV_EPIPE); free(buf); uv_close((uv_handle_t *) &pipe_hdl, close_cb); uv_close((uv_handle_t *) &signal_hdl, close_cb); @@ -62,17 +62,17 @@ TEST_IMPL(signal_pending_on_close) { uv_buf_t buffer; int r; - ASSERT(0 == uv_loop_init(&loop)); + ASSERT_OK(uv_loop_init(&loop)); - ASSERT(0 == uv_signal_init(&loop, &signal_hdl)); + ASSERT_OK(uv_signal_init(&loop, &signal_hdl)); - ASSERT(0 == uv_signal_start(&signal_hdl, signal_cb, SIGPIPE)); + ASSERT_OK(uv_signal_start(&signal_hdl, signal_cb, SIGPIPE)); - ASSERT(0 == pipe(pipefds)); + ASSERT_OK(pipe(pipefds)); - ASSERT(0 == uv_pipe_init(&loop, &pipe_hdl, 0)); + ASSERT_OK(uv_pipe_init(&loop, &pipe_hdl, 0)); - ASSERT(0 == uv_pipe_open(&pipe_hdl, pipefds[1])); + ASSERT_OK(uv_pipe_open(&pipe_hdl, pipefds[1])); /* Write data large enough so it needs loop iteration */ buf = malloc(1<<24); @@ -81,14 +81,14 @@ TEST_IMPL(signal_pending_on_close) { buffer = uv_buf_init(buf, 1<<24); r = uv_write(&write_req, (uv_stream_t *) &pipe_hdl, &buffer, 1, write_cb); - ASSERT(0 == r); + ASSERT_OK(r); /* cause a SIGPIPE on write in next iteration */ close(pipefds[0]); - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); - ASSERT(2 == close_cb_called); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(&loop); return 0; @@ -96,18 +96,18 @@ TEST_IMPL(signal_pending_on_close) { TEST_IMPL(signal_close_loop_alive) { - ASSERT(0 == uv_loop_init(&loop)); - ASSERT(0 == uv_signal_init(&loop, &signal_hdl)); - ASSERT(0 == uv_signal_start(&signal_hdl, stop_loop_cb, SIGPIPE)); + ASSERT_OK(uv_loop_init(&loop)); + ASSERT_OK(uv_signal_init(&loop, &signal_hdl)); + ASSERT_OK(uv_signal_start(&signal_hdl, stop_loop_cb, SIGPIPE)); uv_unref((uv_handle_t*) &signal_hdl); - ASSERT(0 == uv_kill(uv_os_getpid(), SIGPIPE)); - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_kill(uv_os_getpid(), SIGPIPE)); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); uv_close((uv_handle_t*) &signal_hdl, close_cb); - ASSERT(1 == uv_loop_alive(&loop)); + ASSERT_EQ(1, uv_loop_alive(&loop)); - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); - ASSERT(1 == close_cb_called); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(&loop); return 0; diff --git a/test/test-signal.c b/test/test-signal.c index f8222d14b4e..b1e24bb01a1 100644 --- a/test/test-signal.c +++ b/test/test-signal.c @@ -31,12 +31,12 @@ TEST_IMPL(kill_invalid_signum) { pid = uv_os_getpid(); - ASSERT(uv_kill(pid, -1) == UV_EINVAL); + ASSERT_EQ(uv_kill(pid, -1), UV_EINVAL); #ifdef _WIN32 /* NSIG is not available on all platforms. */ - ASSERT(uv_kill(pid, NSIG) == UV_EINVAL); + ASSERT_EQ(uv_kill(pid, NSIG), UV_EINVAL); #endif - ASSERT(uv_kill(pid, 4096) == UV_EINVAL); + ASSERT_EQ(uv_kill(pid, 4096), UV_EINVAL); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -55,20 +55,20 @@ TEST_IMPL(win32_signum_number) { loop = uv_default_loop(); uv_signal_init(loop, &signal); - ASSERT(uv_signal_start(&signal, signum_test_cb, 0) == UV_EINVAL); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGINT) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGBREAK) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGHUP) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGWINCH) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGILL) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGABRT_COMPAT) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGFPE) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGSEGV) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGTERM) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, SIGABRT) == 0); - ASSERT(uv_signal_start(&signal, signum_test_cb, -1) == UV_EINVAL); - ASSERT(uv_signal_start(&signal, signum_test_cb, NSIG) == UV_EINVAL); - ASSERT(uv_signal_start(&signal, signum_test_cb, 1024) == UV_EINVAL); + ASSERT_EQ(uv_signal_start(&signal, signum_test_cb, 0), UV_EINVAL); + ASSERT_OK(uv_signal_start(&signal, signum_test_cb, SIGINT)); + ASSERT_OK(uv_signal_start(&signal, signum_test_cb, SIGBREAK)); + ASSERT_OK(uv_signal_start(&signal, signum_test_cb, SIGHUP)); + ASSERT_OK(uv_signal_start(&signal, signum_test_cb, SIGWINCH)); + ASSERT_OK(uv_signal_start(&signal, signum_test_cb, SIGILL)); + ASSERT_OK(uv_signal_start(&signal, signum_test_cb, SIGABRT_COMPAT)); + ASSERT_OK(uv_signal_start(&signal, signum_test_cb, SIGFPE)); + ASSERT_OK(uv_signal_start(&signal, signum_test_cb, SIGSEGV)); + ASSERT_OK(uv_signal_start(&signal, signum_test_cb, SIGTERM)); + ASSERT_OK(uv_signal_start(&signal, signum_test_cb, SIGABRT)); + ASSERT_EQ(uv_signal_start(&signal, signum_test_cb, -1), UV_EINVAL); + ASSERT_EQ(uv_signal_start(&signal, signum_test_cb, NSIG), UV_EINVAL); + ASSERT_EQ(uv_signal_start(&signal, signum_test_cb, 1024), UV_EINVAL); MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -100,7 +100,7 @@ struct signal_ctx { static void signal_cb(uv_signal_t* handle, int signum) { struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle); - ASSERT(signum == ctx->signum); + ASSERT_EQ(signum, ctx->signum); if (++ctx->ncalls == NSIGNALS) { if (ctx->stop_or_close == STOP) uv_signal_stop(handle); @@ -113,8 +113,8 @@ static void signal_cb(uv_signal_t* handle, int signum) { static void signal_cb_one_shot(uv_signal_t* handle, int signum) { struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle); - ASSERT(signum == ctx->signum); - ASSERT(++ctx->ncalls == 1); + ASSERT_EQ(signum, ctx->signum); + ASSERT_EQ(1, ++ctx->ncalls); if (ctx->stop_or_close == CLOSE) uv_close((uv_handle_t*)handle, NULL); } @@ -138,18 +138,18 @@ static void start_watcher(uv_loop_t* loop, ctx->signum = signum; ctx->stop_or_close = CLOSE; ctx->one_shot = one_shot; - ASSERT(0 == uv_signal_init(loop, &ctx->handle)); + ASSERT_OK(uv_signal_init(loop, &ctx->handle)); if (one_shot) - ASSERT(0 == uv_signal_start_oneshot(&ctx->handle, signal_cb_one_shot, signum)); + ASSERT_OK(uv_signal_start_oneshot(&ctx->handle, signal_cb_one_shot, signum)); else - ASSERT(0 == uv_signal_start(&ctx->handle, signal_cb, signum)); + ASSERT_OK(uv_signal_start(&ctx->handle, signal_cb, signum)); } static void start_timer(uv_loop_t* loop, int signum, struct timer_ctx* ctx) { ctx->ncalls = 0; ctx->signum = signum; - ASSERT(0 == uv_timer_init(loop, &ctx->handle)); - ASSERT(0 == uv_timer_start(&ctx->handle, timer_cb, 5, 5)); + ASSERT_OK(uv_timer_init(loop, &ctx->handle)); + ASSERT_OK(uv_timer_start(&ctx->handle, timer_cb, 5, 5)); } @@ -162,23 +162,23 @@ TEST_IMPL(we_get_signal) { start_timer(loop, SIGCHLD, &tc); start_watcher(loop, SIGCHLD, &sc, 0); sc.stop_or_close = STOP; /* stop, don't close the signal handle */ - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc.ncalls == NSIGNALS); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(tc.ncalls, NSIGNALS); + ASSERT_EQ(sc.ncalls, NSIGNALS); start_timer(loop, SIGCHLD, &tc); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc.ncalls == NSIGNALS); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(tc.ncalls, NSIGNALS); + ASSERT_EQ(sc.ncalls, NSIGNALS); sc.ncalls = 0; sc.stop_or_close = CLOSE; /* now close it when it's done */ uv_signal_start(&sc.handle, signal_cb, SIGCHLD); start_timer(loop, SIGCHLD, &tc); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc.ncalls == NSIGNALS); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(tc.ncalls, NSIGNALS); + ASSERT_EQ(sc.ncalls, NSIGNALS); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -198,13 +198,13 @@ TEST_IMPL(we_get_signals) { start_watcher(loop, SIGUSR2, sc + 3, 0); start_timer(loop, SIGUSR1, tc + 0); start_timer(loop, SIGUSR2, tc + 1); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); for (i = 0; i < ARRAY_SIZE(sc); i++) - ASSERT(sc[i].ncalls == NSIGNALS); + ASSERT_EQ(sc[i].ncalls, NSIGNALS); for (i = 0; i < ARRAY_SIZE(tc); i++) - ASSERT(tc[i].ncalls == NSIGNALS); + ASSERT_EQ(tc[i].ncalls, NSIGNALS); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -219,21 +219,21 @@ TEST_IMPL(we_get_signal_one_shot) { start_timer(loop, SIGCHLD, &tc); start_watcher(loop, SIGCHLD, &sc, 1); sc.stop_or_close = NOOP; - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc.ncalls == 1); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(tc.ncalls, NSIGNALS); + ASSERT_EQ(1, sc.ncalls); start_timer(loop, SIGCHLD, &tc); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(sc.ncalls == 1); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, sc.ncalls); sc.ncalls = 0; sc.stop_or_close = CLOSE; /* now close it when it's done */ uv_signal_start_oneshot(&sc.handle, signal_cb_one_shot, SIGCHLD); start_timer(loop, SIGCHLD, &tc); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc.ncalls == 1); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(tc.ncalls, NSIGNALS); + ASSERT_EQ(1, sc.ncalls); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -252,10 +252,10 @@ TEST_IMPL(we_get_signals_mixed) { start_watcher(loop, SIGCHLD, sc + 1, 1); sc[0].stop_or_close = CLOSE; sc[1].stop_or_close = CLOSE; - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc[0].ncalls == 1); - ASSERT(sc[1].ncalls == 1); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(tc.ncalls, NSIGNALS); + ASSERT_EQ(1, sc[0].ncalls); + ASSERT_EQ(1, sc[1].ncalls); /* 2 one-shot, 1 normal then remove normal */ start_timer(loop, SIGCHLD, &tc); @@ -265,11 +265,11 @@ TEST_IMPL(we_get_signals_mixed) { sc[1].stop_or_close = CLOSE; start_watcher(loop, SIGCHLD, sc + 2, 0); uv_close((uv_handle_t*)&(sc[2]).handle, NULL); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc[0].ncalls == 1); - ASSERT(sc[1].ncalls == 1); - ASSERT(sc[2].ncalls == 0); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(tc.ncalls, NSIGNALS); + ASSERT_EQ(1, sc[0].ncalls); + ASSERT_EQ(1, sc[1].ncalls); + ASSERT_OK(sc[2].ncalls); /* 2 normal, 1 one-shot then remove one-shot */ start_timer(loop, SIGCHLD, &tc); @@ -279,11 +279,11 @@ TEST_IMPL(we_get_signals_mixed) { sc[1].stop_or_close = CLOSE; start_watcher(loop, SIGCHLD, sc + 2, 1); uv_close((uv_handle_t*)&(sc[2]).handle, NULL); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc[0].ncalls == NSIGNALS); - ASSERT(sc[1].ncalls == NSIGNALS); - ASSERT(sc[2].ncalls == 0); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(tc.ncalls, NSIGNALS); + ASSERT_EQ(sc[0].ncalls, NSIGNALS); + ASSERT_EQ(sc[1].ncalls, NSIGNALS); + ASSERT_OK(sc[2].ncalls); /* 2 normal, 2 one-shot then remove 2 normal */ start_timer(loop, SIGCHLD, &tc); @@ -295,12 +295,12 @@ TEST_IMPL(we_get_signals_mixed) { sc[3].stop_or_close = CLOSE; uv_close((uv_handle_t*)&(sc[0]).handle, NULL); uv_close((uv_handle_t*)&(sc[1]).handle, NULL); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc[0].ncalls == 0); - ASSERT(sc[1].ncalls == 0); - ASSERT(sc[2].ncalls == 1); - ASSERT(sc[2].ncalls == 1); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(tc.ncalls, NSIGNALS); + ASSERT_OK(sc[0].ncalls); + ASSERT_OK(sc[1].ncalls); + ASSERT_EQ(1, sc[2].ncalls); + ASSERT_EQ(1, sc[2].ncalls); /* 1 normal, 1 one-shot, 2 normal then remove 1st normal, 2nd normal */ start_timer(loop, SIGCHLD, &tc); @@ -311,12 +311,12 @@ TEST_IMPL(we_get_signals_mixed) { sc[3].stop_or_close = CLOSE; uv_close((uv_handle_t*)&(sc[0]).handle, NULL); uv_close((uv_handle_t*)&(sc[2]).handle, NULL); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(tc.ncalls == NSIGNALS); - ASSERT(sc[0].ncalls == 0); - ASSERT(sc[1].ncalls == 1); - ASSERT(sc[2].ncalls == 0); - ASSERT(sc[3].ncalls == NSIGNALS); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(tc.ncalls, NSIGNALS); + ASSERT_OK(sc[0].ncalls); + ASSERT_EQ(1, sc[1].ncalls); + ASSERT_OK(sc[2].ncalls); + ASSERT_EQ(sc[3].ncalls, NSIGNALS); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-socket-buffer-size.c b/test/test-socket-buffer-size.c index 5f072cb02be..64904e93d50 100644 --- a/test/test-socket-buffer-size.c +++ b/test/test-socket-buffer-size.c @@ -40,14 +40,14 @@ static void check_buffer_size(uv_handle_t* handle) { int value; value = 0; - ASSERT(0 == uv_recv_buffer_size(handle, &value)); - ASSERT(value > 0); + ASSERT_OK(uv_recv_buffer_size(handle, &value)); + ASSERT_GT(value, 0); value = 10000; - ASSERT(0 == uv_recv_buffer_size(handle, &value)); + ASSERT_OK(uv_recv_buffer_size(handle, &value)); value = 0; - ASSERT(0 == uv_recv_buffer_size(handle, &value)); + ASSERT_OK(uv_recv_buffer_size(handle, &value)); /* linux sets double the value */ ASSERT(value == 10000 || value == 20000); } @@ -56,21 +56,21 @@ static void check_buffer_size(uv_handle_t* handle) { TEST_IMPL(socket_buffer_size) { struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(uv_default_loop(), &tcp)); - ASSERT(0 == uv_tcp_bind(&tcp, (struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &tcp)); + ASSERT_OK(uv_tcp_bind(&tcp, (struct sockaddr*) &addr, 0)); check_buffer_size((uv_handle_t*) &tcp); uv_close((uv_handle_t*) &tcp, close_cb); - ASSERT(0 == uv_udp_init(uv_default_loop(), &udp)); - ASSERT(0 == uv_udp_bind(&udp, (struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_udp_init(uv_default_loop(), &udp)); + ASSERT_OK(uv_udp_bind(&udp, (struct sockaddr*) &addr, 0)); check_buffer_size((uv_handle_t*) &udp); uv_close((uv_handle_t*) &udp, close_cb); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(close_cb_called == 2); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-spawn.c b/test/test-spawn.c index 066d5d62cec..a5022d9eac7 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -65,8 +65,8 @@ static void exit_cb(uv_process_t* process, int term_signal) { printf("exit_cb\n"); exit_cb_called++; - ASSERT(exit_status == 1); - ASSERT(term_signal == 0); + ASSERT_EQ(1, exit_status); + ASSERT_OK(term_signal); uv_close((uv_handle_t*) process, close_cb); } @@ -86,9 +86,9 @@ static void kill_cb(uv_process_t* process, printf("exit_cb\n"); exit_cb_called++; #ifdef _WIN32 - ASSERT(exit_status == 1); + ASSERT_EQ(1, exit_status); #else - ASSERT(exit_status == 0); + ASSERT_OK(exit_status); #endif #if defined(__APPLE__) || defined(__MVS__) /* @@ -108,7 +108,7 @@ static void kill_cb(uv_process_t* process, * This process should be dead. */ err = uv_kill(process->pid, 0); - ASSERT(err == UV_ESRCH); + ASSERT_EQ(err, UV_ESRCH); } static void detach_failure_cb(uv_process_t* process, @@ -130,7 +130,7 @@ static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { if (nread > 0) { output_used += nread; } else if (nread < 0) { - ASSERT(nread == UV_EOF); + ASSERT_EQ(nread, UV_EOF); uv_close((uv_handle_t*) tcp, close_cb); } } @@ -143,20 +143,20 @@ static void on_read_once(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { static void write_cb(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); uv_close((uv_handle_t*) req->handle, close_cb); } static void write_null_cb(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); } static void init_process_options(char* test, uv_exit_cb exit_cb) { /* Note spawn_helper1 defined in test/run-tests.c */ int r = uv_exepath(exepath, &exepath_size); - ASSERT(r == 0); + ASSERT_OK(r); exepath[exepath_size] = '\0'; args[0] = exepath; args[1] = test; @@ -189,9 +189,9 @@ TEST_IMPL(spawn_fails) { r = uv_spawn(uv_default_loop(), &process, &options); ASSERT(r == UV_ENOENT || r == UV_EACCES); - ASSERT(0 == uv_is_active((uv_handle_t*) &process)); + ASSERT_OK(uv_is_active((uv_handle_t*) &process)); uv_close((uv_handle_t*) &process, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -209,19 +209,19 @@ TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) { r = uv_spawn(uv_default_loop(), &process, &options); ASSERT(r == UV_ENOENT || r == UV_EACCES); - ASSERT(0 == uv_is_active((uv_handle_t*) &process)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_is_active((uv_handle_t*) &process)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); /* verify the child is successfully cleaned up within libuv */ do err = waitpid(process.pid, &status, 0); while (err == -1 && errno == EINTR); - ASSERT(err == -1); - ASSERT(errno == ECHILD); + ASSERT_EQ(err, -1); + ASSERT_EQ(errno, ECHILD); uv_close((uv_handle_t*) &process, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -247,11 +247,11 @@ TEST_IMPL(spawn_empty_env) { options.env = env; env[0] = NULL; - ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -264,13 +264,13 @@ TEST_IMPL(spawn_exit_code) { init_process_options("spawn_helper1", exit_cb); r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -292,18 +292,18 @@ TEST_IMPL(spawn_stdout) { options.stdio_count = 2; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */ + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(2, close_cb_called); /* Once for process once for the pipe. */ printf("output is: %s", output); - ASSERT(strcmp("hello world\n", output) == 0); + ASSERT_OK(strcmp("hello world\n", output)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -324,7 +324,7 @@ TEST_IMPL(spawn_stdout_to_file) { r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, NULL); - ASSERT(r != -1); + ASSERT_NE(r, -1); uv_fs_req_cleanup(&fs_req); file = r; @@ -336,25 +336,25 @@ TEST_IMPL(spawn_stdout_to_file) { options.stdio_count = 2; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); buf = uv_buf_init(output, sizeof(output)); r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL); - ASSERT(r == 12); + ASSERT_EQ(12, r); uv_fs_req_cleanup(&fs_req); r = uv_fs_close(NULL, &fs_req, file, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&fs_req); printf("output is: %s", output); - ASSERT(strcmp("hello world\n", output) == 0); + ASSERT_OK(strcmp("hello world\n", output)); /* Cleanup. */ unlink("stdout_file"); @@ -378,7 +378,7 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) { r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, NULL); - ASSERT(r != -1); + ASSERT_NE(r, -1); uv_fs_req_cleanup(&fs_req); file = r; @@ -392,25 +392,25 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) { options.stdio_count = 3; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); buf = uv_buf_init(output, sizeof(output)); r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL); - ASSERT(r == 27); + ASSERT_EQ(27, r); uv_fs_req_cleanup(&fs_req); r = uv_fs_close(NULL, &fs_req, file, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&fs_req); printf("output is: %s", output); - ASSERT(strcmp("hello world\nhello errworld\n", output) == 0); + ASSERT_OK(strcmp("hello world\nhello errworld\n", output)); /* Cleanup. */ unlink("stdout_file"); @@ -440,10 +440,10 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file2) { O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, NULL); - ASSERT(r != -1); + ASSERT_NE(r, -1); uv_fs_req_cleanup(&fs_req); file = dup2(r, STDERR_FILENO); - ASSERT(file != -1); + ASSERT_NE(file, -1); options.stdio = stdio; options.stdio[0].flags = UV_IGNORE; @@ -454,25 +454,25 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file2) { options.stdio_count = 3; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); buf = uv_buf_init(output, sizeof(output)); r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL); - ASSERT(r == 27); + ASSERT_EQ(27, r); uv_fs_req_cleanup(&fs_req); r = uv_fs_close(NULL, &fs_req, file, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&fs_req); printf("output is: %s", output); - ASSERT(strcmp("hello world\nhello errworld\n", output) == 0); + ASSERT_OK(strcmp("hello world\nhello errworld\n", output)); /* Cleanup. */ unlink("stdout_file"); @@ -507,18 +507,18 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) { O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, NULL); - ASSERT(r != -1); + ASSERT_NE(r, -1); uv_fs_req_cleanup(&fs_req); stdout_file = dup2(r, STDOUT_FILENO); - ASSERT(stdout_file != -1); + ASSERT_NE(stdout_file, -1); /* open 'stderr_file' and replace STDERR_FILENO with it */ r = uv_fs_open(NULL, &fs_req, "stderr_file", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, NULL); - ASSERT(r != -1); + ASSERT_NE(r, -1); uv_fs_req_cleanup(&fs_req); stderr_file = dup2(r, STDERR_FILENO); - ASSERT(stderr_file != -1); + ASSERT_NE(stderr_file, -1); /* now we're going to swap them: the child process' stdout will be our * stderr_file and vice versa */ @@ -531,39 +531,39 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) { options.stdio_count = 3; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); buf = uv_buf_init(output, sizeof(output)); /* check the content of stdout_file */ r = uv_fs_read(NULL, &fs_req, stdout_file, &buf, 1, 0, NULL); - ASSERT(r >= 15); + ASSERT_GE(r, 15); uv_fs_req_cleanup(&fs_req); r = uv_fs_close(NULL, &fs_req, stdout_file, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&fs_req); printf("output is: %s", output); - ASSERT(strncmp("hello errworld\n", output, 15) == 0); + ASSERT_OK(strncmp("hello errworld\n", output, 15)); /* check the content of stderr_file */ r = uv_fs_read(NULL, &fs_req, stderr_file, &buf, 1, 0, NULL); - ASSERT(r >= 12); + ASSERT_GE(r, 12); uv_fs_req_cleanup(&fs_req); r = uv_fs_close(NULL, &fs_req, stderr_file, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_fs_req_cleanup(&fs_req); printf("output is: %s", output); - ASSERT(strncmp("hello world\n", output, 12) == 0); + ASSERT_OK(strncmp("hello world\n", output, 12)); /* Cleanup. */ unlink("stdout_file"); @@ -598,22 +598,22 @@ TEST_IMPL(spawn_stdin) { options.stdio_count = 2; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); buf.base = buffer; buf.len = sizeof(buffer); r = uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 3); /* Once for process twice for the pipe. */ - ASSERT(strcmp(buffer, output) == 0); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(3, close_cb_called); /* Once for process twice for the pipe. */ + ASSERT_OK(strcmp(buffer, output)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -637,18 +637,18 @@ TEST_IMPL(spawn_stdio_greater_than_3) { options.stdio_count = 4; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &pipe, on_alloc, on_read); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */ + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(2, close_cb_called); /* Once for process once for the pipe. */ printf("output from stdio[3] is: %s", output); - ASSERT(strcmp("fourth stdio!\n", output) == 0); + ASSERT_OK(strcmp("fourth stdio!\n", output)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -661,7 +661,7 @@ int spawn_tcp_server_helper(void) { int r; r = uv_tcp_init(uv_default_loop(), &tcp); - ASSERT(r == 0); + ASSERT_OK(r); #ifdef _WIN32 handle = _get_osfhandle(3); @@ -669,13 +669,13 @@ int spawn_tcp_server_helper(void) { handle = 3; #endif r = uv_tcp_open(&tcp, handle); - ASSERT(r == 0); + ASSERT_OK(r); /* Make sure that we can listen on a socket that was * passed down from the parent process */ r = uv_listen((uv_stream_t*) &tcp, SOMAXCONN, NULL); - ASSERT(r == 0); + ASSERT_OK(r); return 1; } @@ -692,21 +692,21 @@ TEST_IMPL(spawn_tcp_server) { init_process_options("spawn_tcp_server_helper", exit_cb); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); fd = -1; r = uv_tcp_init_ex(uv_default_loop(), &tcp_server, AF_INET); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); #ifdef _WIN32 r = uv_fileno((uv_handle_t*) &tcp_server, &handle); fd = _open_osfhandle((intptr_t) handle, 0); #else r = uv_fileno((uv_handle_t*) &tcp_server, &fd); #endif - ASSERT(r == 0); - ASSERT(fd > 0); + ASSERT_OK(r); + ASSERT_GT(fd, 0); options.stdio = stdio; options.stdio[0].flags = UV_INHERIT_FD; @@ -720,13 +720,13 @@ TEST_IMPL(spawn_tcp_server) { options.stdio_count = 4; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -742,13 +742,13 @@ TEST_IMPL(spawn_ignored_stdio) { options.stdio_count = 0; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -761,19 +761,19 @@ TEST_IMPL(spawn_and_kill) { init_process_options("spawn_helper4", kill_cb); r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(uv_default_loop(), &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, timer_cb, 500, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 2); /* Once for process and once for timer. */ + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(2, close_cb_called); /* Once for process and once for timer. */ MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -795,25 +795,25 @@ TEST_IMPL(spawn_preserve_env) { options.stdio_count = 2; r = putenv("ENV_TEST=testval"); - ASSERT(r == 0); + ASSERT_OK(r); /* Explicitly set options.env to NULL to test for env clobbering. */ options.env = NULL; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 2); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(2, close_cb_called); printf("output is: %s", output); - ASSERT(strcmp("testval", output) == 0); + ASSERT_OK(strcmp("testval", output)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -828,22 +828,22 @@ TEST_IMPL(spawn_detached) { options.flags |= UV_PROCESS_DETACHED; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); uv_unref((uv_handle_t*) &process); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 0); + ASSERT_OK(exit_cb_called); - ASSERT(process.pid == uv_process_get_pid(&process)); + ASSERT_EQ(process.pid, uv_process_get_pid(&process)); r = uv_kill(process.pid, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_kill(process.pid, SIGTERM); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -861,13 +861,13 @@ TEST_IMPL(spawn_and_kill_with_std) { init_process_options("spawn_helper4", kill_cb); r = uv_pipe_init(uv_default_loop(), &in, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_init(uv_default_loop(), &out, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_init(uv_default_loop(), &err, 0); - ASSERT(r == 0); + ASSERT_OK(r); options.stdio = stdio; options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; @@ -879,29 +879,29 @@ TEST_IMPL(spawn_and_kill_with_std) { options.stdio_count = 3; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); buf = uv_buf_init(message, sizeof message); r = uv_write(&write, (uv_stream_t*) &in, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &err, on_alloc, on_read); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_init(uv_default_loop(), &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, timer_cb, 500, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 5); /* process x 1, timer x 1, stdio x 3. */ + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(5, close_cb_called); /* process x 1, timer x 1, stdio x 3. */ MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -928,27 +928,27 @@ TEST_IMPL(spawn_and_ping) { options.stdio_count = 2; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); /* Sending signum == 0 should check if the * child process is still alive, not kill it. */ r = uv_process_kill(&process, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 0); + ASSERT_OK(exit_cb_called); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(strcmp(output, "TEST") == 0); + ASSERT_EQ(1, exit_cb_called); + ASSERT_OK(strcmp(output, "TEST")); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -975,27 +975,27 @@ TEST_IMPL(spawn_same_stdout_stderr) { options.stdio_count = 2; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); /* Sending signum == 0 should check if the * child process is still alive, not kill it. */ r = uv_process_kill(&process, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 0); + ASSERT_OK(exit_cb_called); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(strcmp(output, "TEST") == 0); + ASSERT_EQ(1, exit_cb_called); + ASSERT_OK(strcmp(output, "TEST")); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1019,15 +1019,15 @@ TEST_IMPL(spawn_closed_process_io) { close(0); /* Close process stdin. */ - ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); + ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); buf = uv_buf_init(buffer, sizeof(buffer)); - ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb)); + ASSERT_OK(uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 2); /* process, child stdin */ + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(2, close_cb_called); /* process, child stdin */ MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1049,39 +1049,39 @@ TEST_IMPL(kill) { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGTERM); - ASSERT(0 == pthread_sigmask(SIG_BLOCK, &set, NULL)); + ASSERT_OK(pthread_sigmask(SIG_BLOCK, &set, NULL)); } - ASSERT(SIG_ERR != signal(SIGTERM, SIG_IGN)); + ASSERT_NE(SIG_ERR, signal(SIGTERM, SIG_IGN)); #endif r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); #ifndef _WIN32 { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGTERM); - ASSERT(0 == pthread_sigmask(SIG_UNBLOCK, &set, NULL)); + ASSERT_OK(pthread_sigmask(SIG_UNBLOCK, &set, NULL)); } - ASSERT(SIG_ERR != signal(SIGTERM, SIG_DFL)); + ASSERT_NE(SIG_ERR, signal(SIGTERM, SIG_DFL)); #endif /* Sending signum == 0 should check if the * child process is still alive, not kill it. */ r = uv_kill(process.pid, 0); - ASSERT(r == 0); + ASSERT_OK(r); /* Kill the process. */ r = uv_kill(process.pid, SIGTERM); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1119,21 +1119,21 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) { 65536, 0, NULL); - ASSERT(pipe_handle != INVALID_HANDLE_VALUE); + ASSERT_NE(pipe_handle, INVALID_HANDLE_VALUE); r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */ + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(2, close_cb_called); /* Once for process once for the pipe. */ printf("output is: %s", output); - ASSERT(strcmp("hello world\n", output) == 0); + ASSERT_OK(strcmp("hello world\n", output)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1197,7 +1197,7 @@ TEST_IMPL(argument_escaping) { cracked = CommandLineToArgvW(command_line, &num_args); for (i = 0; i < num_args; ++i) { wprintf(L"%d: %s\t%s\n", i, test_str[i], cracked[i]); - ASSERT(wcscmp(test_str[i], cracked[i]) == 0); + ASSERT_OK(wcscmp(test_str[i], cracked[i])); } LocalFree(cracked); @@ -1207,19 +1207,19 @@ TEST_IMPL(argument_escaping) { free(test_output); result = make_program_args(verbatim, 1, &verbatim_output); - ASSERT(result == 0); + ASSERT_OK(result); result = make_program_args(verbatim, 0, &non_verbatim_output); - ASSERT(result == 0); + ASSERT_OK(result); wprintf(L" verbatim_output: %s\n", verbatim_output); wprintf(L"non_verbatim_output: %s\n", non_verbatim_output); - ASSERT(wcscmp(verbatim_output, - L"cmd.exe /c c:\\path\\to\\node.exe --eval " - L"\"require('c:\\\\path\\\\to\\\\test.js')\"") == 0); - ASSERT(wcscmp(non_verbatim_output, - L"cmd.exe /c \"c:\\path\\to\\node.exe --eval " - L"\\\"require('c:\\\\path\\\\to\\\\test.js')\\\"\"") == 0); + ASSERT_OK(wcscmp(verbatim_output, + L"cmd.exe /c c:\\path\\to\\node.exe --eval " + L"\"require('c:\\\\path\\\\to\\\\test.js')\"")); + ASSERT_OK(wcscmp(non_verbatim_output, + L"cmd.exe /c \"c:\\path\\to\\node.exe --eval " + L"\\\"require('c:\\\\path\\\\to\\\\test.js')\\\"\"")); free(verbatim_output); free(non_verbatim_output); @@ -1303,7 +1303,7 @@ TEST_IMPL(environment_creation) { } result = make_program_env(environment, &env); - ASSERT(result == 0); + ASSERT_OK(result); for (str = env, prev = NULL; *str; prev = str, str += wcslen(str) + 1) { int found = 0; @@ -1327,7 +1327,7 @@ TEST_IMPL(environment_creation) { } if (prev) { /* verify sort order */ #if !defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR) - ASSERT(CompareStringOrdinal(prev, -1, str, -1, TRUE) == 1); + ASSERT_EQ(1, CompareStringOrdinal(prev, -1, str, -1, TRUE)); #endif } ASSERT(found); /* verify that we expected this variable */ @@ -1359,9 +1359,9 @@ TEST_IMPL(spawn_with_an_odd_path) { options.file = options.args[0] = "program-that-had-better-not-exist"; r = uv_spawn(uv_default_loop(), &process, &options); ASSERT(r == UV_ENOENT || r == UV_EACCES); - ASSERT(0 == uv_is_active((uv_handle_t*) &process)); + ASSERT_OK(uv_is_active((uv_handle_t*) &process)); uv_close((uv_handle_t*) &process, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1383,11 +1383,11 @@ TEST_IMPL(spawn_no_path) { options.env = env; env[0] = NULL; - ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); SetEnvironmentVariableW(L"PATH", old_path); @@ -1426,13 +1426,13 @@ TEST_IMPL(spawn_setuid_setgid) { if (r == UV_EACCES) RETURN_SKIP("user 'nobody' cannot access the test runner"); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1452,8 +1452,8 @@ TEST_IMPL(spawn_setuid_fails) { struct passwd* pw; pw = getpwnam("nobody"); ASSERT_NOT_NULL(pw); - ASSERT(0 == setgid(pw->pw_gid)); - ASSERT(0 == setuid(pw->pw_uid)); + ASSERT_OK(setgid(pw->pw_gid)); + ASSERT_OK(setuid(pw->pw_uid)); } #endif /* !__PASE__ */ @@ -1477,15 +1477,15 @@ TEST_IMPL(spawn_setuid_fails) { r = uv_spawn(uv_default_loop(), &process, &options); #if defined(__CYGWIN__) - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); #else - ASSERT(r == UV_EPERM); + ASSERT_EQ(r, UV_EPERM); #endif r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); + ASSERT_OK(close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1503,8 +1503,8 @@ TEST_IMPL(spawn_setgid_fails) { struct passwd* pw; pw = getpwnam("nobody"); ASSERT_NOT_NULL(pw); - ASSERT(0 == setgid(pw->pw_gid)); - ASSERT(0 == setuid(pw->pw_uid)); + ASSERT_OK(setgid(pw->pw_gid)); + ASSERT_OK(setuid(pw->pw_uid)); } #endif /* !__PASE__ */ @@ -1522,15 +1522,15 @@ TEST_IMPL(spawn_setgid_fails) { r = uv_spawn(uv_default_loop(), &process, &options); #if defined(__CYGWIN__) || defined(__MVS__) - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); #else - ASSERT(r == UV_EPERM); + ASSERT_EQ(r, UV_EPERM); #endif r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); + ASSERT_OK(close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1556,12 +1556,12 @@ TEST_IMPL(spawn_setuid_fails) { options.uid = (uv_uid_t) -42424242; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == UV_ENOTSUP); + ASSERT_EQ(r, UV_ENOTSUP); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); + ASSERT_OK(close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1577,12 +1577,12 @@ TEST_IMPL(spawn_setgid_fails) { options.gid = (uv_gid_t) -42424242; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == UV_ENOTSUP); + ASSERT_EQ(r, UV_ENOTSUP); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); + ASSERT_OK(close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1592,12 +1592,12 @@ TEST_IMPL(spawn_setgid_fails) { TEST_IMPL(spawn_auto_unref) { init_process_options("spawn_helper1", NULL); - ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(0 == uv_is_closing((uv_handle_t*) &process)); + ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_is_closing((uv_handle_t*) &process)); uv_close((uv_handle_t*) &process, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(1 == uv_is_closing((uv_handle_t*) &process)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, uv_is_closing((uv_handle_t*) &process)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1622,13 +1622,13 @@ TEST_IMPL(spawn_fs_open) { #endif r = uv_fs_open(NULL, &fs_req, dev_null, O_RDWR, 0, NULL); - ASSERT(r != -1); + ASSERT_NE(r, -1); fd = uv_get_osfhandle((uv_file) fs_req.result); uv_fs_req_cleanup(&fs_req); init_process_options("spawn_helper8", exit_cb); - ASSERT(0 == uv_pipe_init(uv_default_loop(), &in, 0)); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &in, 0)); options.stdio = stdio; options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; @@ -1637,29 +1637,35 @@ TEST_IMPL(spawn_fs_open) { /* make an inheritable copy */ #ifdef _WIN32 - ASSERT(0 != DuplicateHandle(GetCurrentProcess(), fd, GetCurrentProcess(), &dup_fd, - 0, /* inherit */ TRUE, DUPLICATE_SAME_ACCESS)); + ASSERT_NE(0, DuplicateHandle(GetCurrentProcess(), fd, GetCurrentProcess(), &dup_fd, + 0, /* inherit */ TRUE, DUPLICATE_SAME_ACCESS)); kernelbase_module = GetModuleHandleA("kernelbase.dll"); pCompareObjectHandles = (sCompareObjectHandles) GetProcAddress(kernelbase_module, "CompareObjectHandles"); - ASSERT(pCompareObjectHandles == NULL || pCompareObjectHandles(fd, dup_fd)); + ASSERT_NE(pCompareObjectHandles == NULL || + pCompareObjectHandles(fd, dup_fd), + 0); #else dup_fd = dup(fd); #endif - ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); + ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); buf = uv_buf_init((char*) &fd, sizeof(fd)); - ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_null_cb)); + ASSERT_OK(uv_write(&write_req, + (uv_stream_t*) &in, + &buf, + 1, + write_null_cb)); buf = uv_buf_init((char*) &dup_fd, sizeof(fd)); - ASSERT(0 == uv_write(&write_req2, (uv_stream_t*) &in, &buf, 1, write_cb)); + ASSERT_OK(uv_write(&write_req2, (uv_stream_t*) &in, &buf, 1, write_cb)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(0 == uv_fs_close(NULL, &fs_req, r, NULL)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_fs_close(NULL, &fs_req, r, NULL)); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 2); /* One for `in`, one for process */ + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(2, close_cb_called); /* One for `in`, one for process */ MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1675,9 +1681,9 @@ TEST_IMPL(closed_fd_events) { bufs[0] = uv_buf_init("", 1); /* create a pipe and share it with a child process */ - ASSERT(0 == uv_pipe(fd, 0, 0)); - ASSERT(fd[0] > 2); - ASSERT(fd[1] > 2); + ASSERT_OK(uv_pipe(fd, 0, 0)); + ASSERT_GT(fd[0], 2); + ASSERT_GT(fd[1], 2); /* spawn_helper4 blocks indefinitely. */ init_process_options("spawn_helper4", exit_cb); @@ -1688,49 +1694,51 @@ TEST_IMPL(closed_fd_events) { options.stdio[1].flags = UV_IGNORE; options.stdio[2].flags = UV_IGNORE; - ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options)); + ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); uv_unref((uv_handle_t*) &process); /* read from the pipe with uv */ - ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0)); - ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0])); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_handle, 0)); + ASSERT_OK(uv_pipe_open(&pipe_handle, fd[0])); /* uv_pipe_open() takes ownership of the file descriptor. */ fd[0] = -1; - ASSERT(0 == uv_read_start((uv_stream_t*) &pipe_handle, on_alloc, on_read_once)); + ASSERT_OK(uv_read_start((uv_stream_t*) &pipe_handle, + on_alloc, + on_read_once)); - ASSERT(1 == uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL)); - ASSERT(req.result == 1); + ASSERT_EQ(1, uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL)); + ASSERT_EQ(1, req.result); uv_fs_req_cleanup(&req); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); /* should have received just one byte */ - ASSERT(output_used == 1); + ASSERT_EQ(1, output_used); /* close the pipe and see if we still get events */ uv_close((uv_handle_t*) &pipe_handle, close_cb); - ASSERT(1 == uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL)); - ASSERT(req.result == 1); + ASSERT_EQ(1, uv_fs_write(NULL, &req, fd[1], bufs, 1, -1, NULL)); + ASSERT_EQ(1, req.result); uv_fs_req_cleanup(&req); - ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); - ASSERT(0 == uv_timer_start(&timer, timer_counter_cb, 10, 0)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer)); + ASSERT_OK(uv_timer_start(&timer, timer_counter_cb, 10, 0)); /* see if any spurious events interrupt the timer */ if (1 == uv_run(uv_default_loop(), UV_RUN_ONCE)) /* have to run again to really trigger the timer */ - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); - ASSERT(timer_counter == 1); + ASSERT_EQ(1, timer_counter); /* cleanup */ - ASSERT(0 == uv_process_kill(&process, SIGTERM)); + ASSERT_OK(uv_process_kill(&process, SIGTERM)); #ifdef _WIN32 - ASSERT(0 == _close(fd[1])); + ASSERT_OK(_close(fd[1])); #else - ASSERT(0 == close(fd[1])); + ASSERT_OK(close(fd[1])); #endif MAKE_VALGRIND_HAPPY(uv_default_loop()); @@ -1795,13 +1803,13 @@ TEST_IMPL(spawn_reads_child_path) { options.env = env; r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1827,27 +1835,27 @@ TEST_IMPL(spawn_inherit_streams) { init_process_options("spawn_helper9", exit_cb); loop = uv_default_loop(); - ASSERT(uv_pipe_init(loop, &pipe_stdin_child, 0) == 0); - ASSERT(uv_pipe_init(loop, &pipe_stdout_child, 0) == 0); - ASSERT(uv_pipe_init(loop, &pipe_stdin_parent, 0) == 0); - ASSERT(uv_pipe_init(loop, &pipe_stdout_parent, 0) == 0); - - ASSERT(uv_pipe(fds_stdin, 0, 0) == 0); - ASSERT(uv_pipe(fds_stdout, 0, 0) == 0); - - ASSERT(uv_pipe_open(&pipe_stdin_child, fds_stdin[0]) == 0); - ASSERT(uv_pipe_open(&pipe_stdout_child, fds_stdout[1]) == 0); - ASSERT(uv_pipe_open(&pipe_stdin_parent, fds_stdin[1]) == 0); - ASSERT(uv_pipe_open(&pipe_stdout_parent, fds_stdout[0]) == 0); + ASSERT_OK(uv_pipe_init(loop, &pipe_stdin_child, 0)); + ASSERT_OK(uv_pipe_init(loop, &pipe_stdout_child, 0)); + ASSERT_OK(uv_pipe_init(loop, &pipe_stdin_parent, 0)); + ASSERT_OK(uv_pipe_init(loop, &pipe_stdout_parent, 0)); + + ASSERT_OK(uv_pipe(fds_stdin, 0, 0)); + ASSERT_OK(uv_pipe(fds_stdout, 0, 0)); + + ASSERT_OK(uv_pipe_open(&pipe_stdin_child, fds_stdin[0])); + ASSERT_OK(uv_pipe_open(&pipe_stdout_child, fds_stdout[1])); + ASSERT_OK(uv_pipe_open(&pipe_stdin_parent, fds_stdin[1])); + ASSERT_OK(uv_pipe_open(&pipe_stdout_parent, fds_stdout[0])); ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_child)); ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_child)); ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdin_parent)); ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_parent)); /* Some systems (SVR4) open a bidirectional pipe, most don't. */ bidir = uv_is_writable((uv_stream_t*) &pipe_stdin_child); - ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdout_child) == bidir); - ASSERT(uv_is_readable((uv_stream_t*) &pipe_stdin_parent) == bidir); - ASSERT(uv_is_writable((uv_stream_t*) &pipe_stdout_parent) == bidir); + ASSERT_EQ(uv_is_readable((uv_stream_t*) &pipe_stdout_child), bidir); + ASSERT_EQ(uv_is_readable((uv_stream_t*) &pipe_stdin_parent), bidir); + ASSERT_EQ(uv_is_writable((uv_stream_t*) &pipe_stdout_parent), bidir); child_stdio[0].flags = UV_INHERIT_STREAM; child_stdio[0].data.stream = (uv_stream_t *) &pipe_stdin_child; @@ -1858,7 +1866,7 @@ TEST_IMPL(spawn_inherit_streams) { options.stdio = child_stdio; options.stdio_count = 2; - ASSERT(uv_spawn(loop, &child_req, &options) == 0); + ASSERT_OK(uv_spawn(loop, &child_req, &options)); uv_close((uv_handle_t*) &pipe_stdin_child, NULL); uv_close((uv_handle_t*) &pipe_stdout_child, NULL); @@ -1873,19 +1881,19 @@ TEST_IMPL(spawn_inherit_streams) { &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &pipe_stdout_parent, on_alloc, on_read); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 3); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(3, close_cb_called); r = memcmp(ubuf, output, sizeof ubuf); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -1926,7 +1934,7 @@ TEST_IMPL(spawn_exercise_sigchld_issue) { init_process_options("spawn_helper1", exit_cb); r = uv_spawn(uv_default_loop(), &process, &options); - ASSERT_EQ(r, 0); + ASSERT_OK(r); // This test exercises a bug in the darwin kernel that causes SIGCHLD not to // be delivered sometimes. Calling posix_spawn many times increases the @@ -1945,10 +1953,10 @@ TEST_IMPL(spawn_exercise_sigchld_issue) { } r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(r, 0); + ASSERT_OK(r); - ASSERT_EQ(exit_cb_called, 1); - ASSERT_EQ(close_cb_called, 101); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(101, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -1967,14 +1975,14 @@ void spawn_stdin_stdout(void) { if (r == 0) { return; } - ASSERT(r > 0); + ASSERT_GT(r, 0); c = r; pbuf = buf; while (c) { do { w = write(1, pbuf, (size_t)c); } while (w == -1 && errno == EINTR); - ASSERT(w >= 0); + ASSERT_GE(w, 0); pbuf = pbuf + w; c = c - w; } @@ -1986,14 +1994,14 @@ void spawn_stdin_stdout(void) { char* pbuf; HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE); HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); - ASSERT(h_stdin != INVALID_HANDLE_VALUE); - ASSERT(h_stdout != INVALID_HANDLE_VALUE); + ASSERT_NE(h_stdin, INVALID_HANDLE_VALUE); + ASSERT_NE(h_stdout, INVALID_HANDLE_VALUE); for (;;) { DWORD n_read; DWORD n_written; DWORD to_write; if (!ReadFile(h_stdin, buf, sizeof buf, &n_read, NULL)) { - ASSERT(GetLastError() == ERROR_BROKEN_PIPE); + ASSERT_EQ(GetLastError(), ERROR_BROKEN_PIPE); return; } to_write = n_read; @@ -2013,7 +2021,7 @@ TEST_IMPL(spawn_relative_path) { init_process_options("spawn_helper1", exit_cb); exepath_size = sizeof(exepath) - 2; - ASSERT_EQ(0, uv_exepath(exepath, &exepath_size)); + ASSERT_OK(uv_exepath(exepath, &exepath_size)); exepath[exepath_size] = '\0'; /* Poor man's basename(3). */ @@ -2031,8 +2039,8 @@ TEST_IMPL(spawn_relative_path) { options.cwd = exepath; options.file = options.args[0] = sep + 1; - ASSERT_EQ(0, uv_spawn(uv_default_loop(), &process, &options)); - ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT_EQ(1, exit_cb_called); ASSERT_EQ(1, close_cb_called); diff --git a/test/test-stdio-over-pipes.c b/test/test-stdio-over-pipes.c index 1b7f17297ca..c41040ee2fd 100644 --- a/test/test-stdio-over-pipes.c +++ b/test/test-stdio-over-pipes.c @@ -52,8 +52,8 @@ static void exit_cb(uv_process_t* process, int term_signal) { printf("exit_cb\n"); exit_cb_called++; - ASSERT(exit_status == 0); - ASSERT(term_signal == 0); + ASSERT_OK(exit_status); + ASSERT_OK(term_signal); uv_close((uv_handle_t*)process, close_cb); uv_close((uv_handle_t*)&in, close_cb); uv_close((uv_handle_t*)&out, close_cb); @@ -62,7 +62,7 @@ static void exit_cb(uv_process_t* process, static void init_process_options(char* test, uv_exit_cb exit_cb) { int r = uv_exepath(exepath, &exepath_size); - ASSERT(r == 0); + ASSERT_OK(r); exepath[exepath_size] = '\0'; args[0] = exepath; args[1] = test; @@ -104,11 +104,11 @@ static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* rdbuf) { if (nread > 0) { output_used += nread; if (output_used % 12 == 0) { - ASSERT(memcmp("hello world\n", output, 12) == 0); + ASSERT_OK(memcmp("hello world\n", output, 12)); wrbuf = uv_buf_init(output, 12); req = malloc(sizeof(*req)); r = uv_write(req, (uv_stream_t*) &in, &wrbuf, 1, after_write); - ASSERT(r == 0); + ASSERT_OK(r); } } @@ -140,20 +140,20 @@ static void test_stdio_over_pipes(int overlapped) { options.stdio_count = 3; r = uv_spawn(loop, &process, &options); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(on_read_cb_called > 1); - ASSERT(after_write_cb_called == 2); - ASSERT(exit_cb_called == 1); - ASSERT(close_cb_called == 3); - ASSERT(memcmp("hello world\nhello world\n", output, 24) == 0); - ASSERT(output_used == 24); + ASSERT_GT(on_read_cb_called, 1); + ASSERT_EQ(2, after_write_cb_called); + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(3, close_cb_called); + ASSERT_OK(memcmp("hello world\nhello world\n", output, 24)); + ASSERT_EQ(24, output_used); MAKE_VALGRIND_HAPPY(loop); } @@ -179,8 +179,8 @@ static uv_pipe_t stdin_pipe2; static uv_pipe_t stdout_pipe2; static void on_pipe_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) { - ASSERT(nread > 0); - ASSERT(memcmp("hello world\n", buf->base, nread) == 0); + ASSERT_GT(nread, 0); + ASSERT_OK(memcmp("hello world\n", buf->base, nread)); on_pipe_read_called++; free(buf->base); @@ -190,7 +190,7 @@ static void on_pipe_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) static void after_pipe_write(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); after_write_called++; } @@ -222,17 +222,17 @@ int stdio_over_pipes_helper(void) { int r; uv_loop_t* loop = uv_default_loop(); - ASSERT(UV_NAMED_PIPE == uv_guess_handle(0)); - ASSERT(UV_NAMED_PIPE == uv_guess_handle(1)); + ASSERT_EQ(UV_NAMED_PIPE, uv_guess_handle(0)); + ASSERT_EQ(UV_NAMED_PIPE, uv_guess_handle(1)); r = uv_pipe_init(loop, &stdin_pipe1, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_init(loop, &stdout_pipe1, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_init(loop, &stdin_pipe2, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_pipe_init(loop, &stdout_pipe2, 0); - ASSERT(r == 0); + ASSERT_OK(r); uv_pipe_open(&stdin_pipe1, 0); uv_pipe_open(&stdout_pipe1, 1); @@ -256,15 +256,15 @@ int stdio_over_pipes_helper(void) { &buf[i], 1, after_pipe_write); - ASSERT(r == 0); + ASSERT_OK(r); } notify_parent_process(); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(after_write_called == 7 * (j + 1)); - ASSERT(on_pipe_read_called == j); - ASSERT(close_cb_called == 0); + ASSERT_EQ(after_write_called, 7 * (j + 1)); + ASSERT_EQ(on_pipe_read_called, j); + ASSERT_OK(close_cb_called); uv_ref((uv_handle_t*) &stdout_pipe1); uv_ref((uv_handle_t*) &stdin_pipe1); @@ -274,13 +274,13 @@ int stdio_over_pipes_helper(void) { r = uv_read_start((uv_stream_t*) (j == 0 ? &stdin_pipe1 : &stdin_pipe2), on_read_alloc, on_pipe_read); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(after_write_called == 7 * (j + 1)); - ASSERT(on_pipe_read_called == j + 1); - ASSERT(close_cb_called == 0); + ASSERT_EQ(after_write_called, 7 * (j + 1)); + ASSERT_EQ(on_pipe_read_called, j + 1); + ASSERT_OK(close_cb_called); } uv_close((uv_handle_t*)&stdin_pipe1, close_cb); @@ -290,9 +290,9 @@ int stdio_over_pipes_helper(void) { uv_run(loop, UV_RUN_DEFAULT); - ASSERT(after_write_called == 14); - ASSERT(on_pipe_read_called == 2); - ASSERT(close_cb_called == 4); + ASSERT_EQ(14, after_write_called); + ASSERT_EQ(2, on_pipe_read_called); + ASSERT_EQ(4, close_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-strscpy.c b/test/test-strscpy.c index 4e7db6ffec8..b4699cff056 100644 --- a/test/test-strscpy.c +++ b/test/test-strscpy.c @@ -29,25 +29,25 @@ TEST_IMPL(strscpy) { char d[4]; - ASSERT(0 == uv__strscpy(d, "", 0)); - ASSERT(0 == uv__strscpy(d, "x", 0)); + ASSERT_OK(uv__strscpy(d, "", 0)); + ASSERT_OK(uv__strscpy(d, "x", 0)); memset(d, 0, sizeof(d)); - ASSERT(1 == uv__strscpy(d, "x", sizeof(d))); - ASSERT(0 == memcmp(d, "x\0\0", sizeof(d))); + ASSERT_EQ(1, uv__strscpy(d, "x", sizeof(d))); + ASSERT_OK(memcmp(d, "x\0\0", sizeof(d))); memset(d, 0, sizeof(d)); - ASSERT(2 == uv__strscpy(d, "xy", sizeof(d))); - ASSERT(0 == memcmp(d, "xy\0", sizeof(d))); + ASSERT_EQ(2, uv__strscpy(d, "xy", sizeof(d))); + ASSERT_OK(memcmp(d, "xy\0", sizeof(d))); - ASSERT(3 == uv__strscpy(d, "xyz", sizeof(d))); - ASSERT(0 == memcmp(d, "xyz", sizeof(d))); + ASSERT_EQ(3, uv__strscpy(d, "xyz", sizeof(d))); + ASSERT_OK(memcmp(d, "xyz", sizeof(d))); - ASSERT(UV_E2BIG == uv__strscpy(d, "xyzz", sizeof(d))); - ASSERT(0 == memcmp(d, "xyz", sizeof(d))); + ASSERT_EQ(UV_E2BIG, uv__strscpy(d, "xyzz", sizeof(d))); + ASSERT_OK(memcmp(d, "xyz", sizeof(d))); - ASSERT(UV_E2BIG == uv__strscpy(d, "xyzzy", sizeof(d))); - ASSERT(0 == memcmp(d, "xyz", sizeof(d))); + ASSERT_EQ(UV_E2BIG, uv__strscpy(d, "xyzzy", sizeof(d))); + ASSERT_OK(memcmp(d, "xyz", sizeof(d))); return 0; } diff --git a/test/test-strtok.c b/test/test-strtok.c index 6c3d835914c..f4e6cdf8b75 100644 --- a/test/test-strtok.c +++ b/test/test-strtok.c @@ -56,7 +56,7 @@ const char* tokens[] = { }; #define ASSERT_STRCMP(x, y) \ - ASSERT((x != NULL && y != NULL && strcmp(x, y) == 0) || (x == y && x == NULL)) + ASSERT_NE((x != NULL && y != NULL && strcmp(x, y) == 0) || (x == y && x == NULL), 0) TEST_IMPL(strtok) { struct strtok_test_case tests[] = { @@ -74,13 +74,13 @@ TEST_IMPL(strtok) { char current_test[2048]; for (i = 0, j = 0; i < tests_len; i += 1) { - ASSERT(j < tokens_len); + ASSERT_LT(j, tokens_len); snprintf(current_test, sizeof(current_test), "%s", tests[i].str); tok_r = uv__strtok(current_test, tests[i].sep, &itr); ASSERT_STRCMP(tok_r, tokens[j]); j++; while (tok_r) { - ASSERT(j < tokens_len); + ASSERT_LT(j, tokens_len); tok_r = uv__strtok(NULL, tests[i].sep, &itr); ASSERT_STRCMP(tok_r, tokens[j]); j++; diff --git a/test/test-tcp-alloc-cb-fail.c b/test/test-tcp-alloc-cb-fail.c index a1b5e84d3b1..ff1cfcb844a 100644 --- a/test/test-tcp-alloc-cb-fail.c +++ b/test/test-tcp-alloc-cb-fail.c @@ -42,7 +42,7 @@ static void close_cb(uv_handle_t* handle) { } static void write_cb(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); } static void conn_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { @@ -52,9 +52,9 @@ static void conn_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { static void conn_read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { - ASSERT(nread == UV_ENOBUFS); + ASSERT_EQ(nread, UV_ENOBUFS); ASSERT_NULL(buf->base); - ASSERT(buf->len == 0); + ASSERT_OK(buf->len); uv_close((uv_handle_t*) &incoming, close_cb); uv_close((uv_handle_t*) &client, close_cb); @@ -65,23 +65,23 @@ static void connect_cb(uv_connect_t* req, int status) { int r; uv_buf_t buf; - ASSERT(status == 0); + ASSERT_OK(status); connect_cb_called++; buf = uv_buf_init(hello, sizeof(hello)); r = uv_write(&write_req, req->handle, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static void connection_cb(uv_stream_t* tcp, int status) { - ASSERT(status == 0); + ASSERT_OK(status); - ASSERT(0 == uv_tcp_init(tcp->loop, &incoming)); - ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming)); - ASSERT(0 == uv_read_start((uv_stream_t*) &incoming, - conn_alloc_cb, - conn_read_cb)); + ASSERT_OK(uv_tcp_init(tcp->loop, &incoming)); + ASSERT_OK(uv_accept(tcp, (uv_stream_t*) &incoming)); + ASSERT_OK(uv_read_start((uv_stream_t*) &incoming, + conn_alloc_cb, + conn_read_cb)); connection_cb_called++; } @@ -90,11 +90,11 @@ static void connection_cb(uv_stream_t* tcp, int status) { static void start_server(void) { struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); - ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); - ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &server)); + ASSERT_OK(uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_listen((uv_stream_t*) &server, 128, connection_cb)); } @@ -104,19 +104,19 @@ TEST_IMPL(tcp_alloc_cb_fail) { start_server(); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); - ASSERT(0 == uv_tcp_connect(&connect_req, - &client, - (struct sockaddr*) &addr, - connect_cb)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &client)); + ASSERT_OK(uv_tcp_connect(&connect_req, + &client, + (struct sockaddr*) &addr, + connect_cb)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(connect_cb_called == 1); - ASSERT(connection_cb_called == 1); - ASSERT(close_cb_called == 3); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, connection_cb_called); + ASSERT_EQ(3, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-bind-error.c b/test/test-tcp-bind-error.c index edb44c21459..89e4e33993f 100644 --- a/test/test-tcp-bind-error.c +++ b/test/test-tcp-bind-error.c @@ -36,7 +36,7 @@ static void close_cb(uv_handle_t* handle) { static void connect_cb(uv_connect_t* req, int status) { - ASSERT(status == UV_EADDRINUSE); + ASSERT_EQ(status, UV_EADDRINUSE); uv_close((uv_handle_t*) req->handle, close_cb); connect_cb_called++; } @@ -53,24 +53,24 @@ TEST_IMPL(tcp_bind_error_addrinuse_connect) { * (greatest common denominator across platforms) but the connect callback * should receive an UV_EADDRINUSE error. */ - ASSERT(0 == uv_tcp_init(uv_default_loop(), &conn)); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_bind(&conn, (const struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &conn)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_tcp_bind(&conn, (const struct sockaddr*) &addr, 0)); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT + 1, &addr)); - ASSERT(0 == uv_tcp_connect(&req, - &conn, - (const struct sockaddr*) &addr, - connect_cb)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT + 1, &addr)); + ASSERT_OK(uv_tcp_connect(&req, + &conn, + (const struct sockaddr*) &addr, + connect_cb)); addrlen = sizeof(addr); - ASSERT(UV_EADDRINUSE == uv_tcp_getsockname(&conn, - (struct sockaddr*) &addr, - &addrlen)); + ASSERT_EQ(UV_EADDRINUSE, uv_tcp_getsockname(&conn, + (struct sockaddr*) &addr, + &addrlen)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(connect_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -82,28 +82,28 @@ TEST_IMPL(tcp_bind_error_addrinuse_listen) { uv_tcp_t server1, server2; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_init(uv_default_loop(), &server2); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server1, 128, NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server2, 128, NULL); - ASSERT(r == UV_EADDRINUSE); + ASSERT_EQ(r, UV_EADDRINUSE); uv_close((uv_handle_t*)&server1, close_cb); uv_close((uv_handle_t*)&server2, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 2); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -115,10 +115,10 @@ TEST_IMPL(tcp_bind_error_addrnotavail_1) { uv_tcp_t server; int r; - ASSERT(0 == uv_ip4_addr("127.255.255.255", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.255.255.255", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); /* It seems that Linux is broken here - bind succeeds. */ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); @@ -128,7 +128,7 @@ TEST_IMPL(tcp_bind_error_addrnotavail_1) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -140,18 +140,18 @@ TEST_IMPL(tcp_bind_error_addrnotavail_2) { uv_tcp_t server; int r; - ASSERT(0 == uv_ip4_addr("4.4.4.4", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("4.4.4.4", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == UV_EADDRNOTAVAIL); + ASSERT_EQ(r, UV_EADDRNOTAVAIL); uv_close((uv_handle_t*)&server, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -168,15 +168,15 @@ TEST_IMPL(tcp_bind_error_fault) { garbage_addr = (struct sockaddr_in*) &garbage; r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr, 0); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_close((uv_handle_t*)&server, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -190,21 +190,21 @@ TEST_IMPL(tcp_bind_error_inval) { uv_tcp_t server; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr1)); - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT_2, &addr2)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr1)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT_2, &addr2)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2, 0); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_close((uv_handle_t*)&server, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -216,12 +216,12 @@ TEST_IMPL(tcp_bind_localhost_ok) { uv_tcp_t server; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -233,12 +233,12 @@ TEST_IMPL(tcp_bind_invalid_flags) { uv_tcp_t server; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, UV_TCP_IPV6ONLY); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -250,9 +250,9 @@ TEST_IMPL(tcp_listen_without_bind) { uv_tcp_t server; r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server, 128, NULL); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -267,32 +267,32 @@ TEST_IMPL(tcp_bind_writable_flags) { uv_shutdown_t shutdown_req; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server, 128, NULL); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_is_writable((uv_stream_t*) &server)); - ASSERT(0 == uv_is_readable((uv_stream_t*) &server)); + ASSERT_OK(uv_is_writable((uv_stream_t*) &server)); + ASSERT_OK(uv_is_readable((uv_stream_t*) &server)); buf = uv_buf_init("PING", 4); r = uv_write(&write_req, (uv_stream_t*) &server, &buf, 1, NULL); - ASSERT(r == UV_EPIPE); + ASSERT_EQ(r, UV_EPIPE); r = uv_shutdown(&shutdown_req, (uv_stream_t*) &server, NULL); - ASSERT(r == UV_ENOTCONN); + ASSERT_EQ(r, UV_ENOTCONN); r = uv_read_start((uv_stream_t*) &server, (uv_alloc_cb) abort, (uv_read_cb) abort); - ASSERT(r == UV_ENOTCONN); + ASSERT_EQ(r, UV_ENOTCONN); uv_close((uv_handle_t*)&server, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -307,11 +307,11 @@ TEST_IMPL(tcp_bind_or_listen_error_after_close) { addr.sin_port = htons(9999); addr.sin_family = AF_INET; - ASSERT_EQ(uv_tcp_init(uv_default_loop(), &tcp), 0); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &tcp)); uv_close((uv_handle_t*) &tcp, NULL); ASSERT_EQ(uv_tcp_bind(&tcp, (struct sockaddr*) &addr, 0), UV_EINVAL); ASSERT_EQ(uv_listen((uv_stream_t*) &tcp, 5, NULL), UV_EINVAL); - ASSERT_EQ(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-tcp-bind6-error.c b/test/test-tcp-bind6-error.c index 656ebe34e29..f44d3b7ee9a 100644 --- a/test/test-tcp-bind6-error.c +++ b/test/test-tcp-bind6-error.c @@ -42,29 +42,29 @@ TEST_IMPL(tcp_bind6_error_addrinuse) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); - ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr)); + ASSERT_OK(uv_ip6_addr("::", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_init(uv_default_loop(), &server2); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server1, 128, NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&server2, 128, NULL); - ASSERT(r == UV_EADDRINUSE); + ASSERT_EQ(r, UV_EADDRINUSE); uv_close((uv_handle_t*)&server1, close_cb); uv_close((uv_handle_t*)&server2, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 2); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -79,18 +79,18 @@ TEST_IMPL(tcp_bind6_error_addrnotavail) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); - ASSERT(0 == uv_ip6_addr("4:4:4:4:4:4:4:4", TEST_PORT, &addr)); + ASSERT_OK(uv_ip6_addr("4:4:4:4:4:4:4:4", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == UV_EADDRNOTAVAIL); + ASSERT_EQ(r, UV_EADDRNOTAVAIL); uv_close((uv_handle_t*)&server, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -110,15 +110,15 @@ TEST_IMPL(tcp_bind6_error_fault) { garbage_addr = (struct sockaddr_in6*) &garbage; r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr, 0); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_close((uv_handle_t*)&server, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -135,21 +135,21 @@ TEST_IMPL(tcp_bind6_error_inval) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); - ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr1)); - ASSERT(0 == uv_ip6_addr("::", TEST_PORT_2, &addr2)); + ASSERT_OK(uv_ip6_addr("::", TEST_PORT, &addr1)); + ASSERT_OK(uv_ip6_addr("::", TEST_PORT_2, &addr2)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2, 0); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_close((uv_handle_t*)&server, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -164,12 +164,12 @@ TEST_IMPL(tcp_bind6_localhost_ok) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); - ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip6_addr("::1", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-close-accept.c b/test/test-tcp-close-accept.c index b255cfbd9f3..4988dd13275 100644 --- a/test/test-tcp-close-accept.c +++ b/test/test-tcp-close-accept.c @@ -47,7 +47,7 @@ static void close_cb(uv_handle_t* handle) { } static void write_cb(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); write_cb_called++; } @@ -57,7 +57,7 @@ static void connect_cb(uv_connect_t* req, int status) { uv_stream_t* outgoing; if (req == &tcp_check_req) { - ASSERT(status != 0); + ASSERT(status); /* * Time to finish the test: close both the check and pending incoming @@ -68,14 +68,14 @@ static void connect_cb(uv_connect_t* req, int status) { return; } - ASSERT(status == 0); - ASSERT(connect_reqs <= req); - ASSERT(req <= connect_reqs + ARRAY_SIZE(connect_reqs)); + ASSERT_OK(status); + ASSERT_LE(connect_reqs, req); + ASSERT_LE(req, connect_reqs + ARRAY_SIZE(connect_reqs)); i = req - connect_reqs; buf = uv_buf_init("x", 1); outgoing = (uv_stream_t*) &tcp_outgoing[i]; - ASSERT(0 == uv_write(&write_reqs[i], outgoing, &buf, 1, write_cb)); + ASSERT_OK(uv_write(&write_reqs[i], outgoing, &buf, 1, write_cb)); } static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { @@ -89,9 +89,9 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { unsigned int i; pending_incoming = (uv_tcp_t*) stream - &tcp_incoming[0]; - ASSERT(pending_incoming < got_connections); - ASSERT(0 == uv_read_stop(stream)); - ASSERT(1 == nread); + ASSERT_LT(pending_incoming, got_connections); + ASSERT_OK(uv_read_stop(stream)); + ASSERT_EQ(1, nread); loop = stream->loop; read_cb_called++; @@ -106,19 +106,19 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { uv_close((uv_handle_t*) &tcp_server, close_cb); /* Create new fd that should be one of the closed incomings */ - ASSERT(0 == uv_tcp_init(loop, &tcp_check)); - ASSERT(0 == uv_tcp_connect(&tcp_check_req, - &tcp_check, - (const struct sockaddr*) &addr, - connect_cb)); - ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb)); + ASSERT_OK(uv_tcp_init(loop, &tcp_check)); + ASSERT_OK(uv_tcp_connect(&tcp_check_req, + &tcp_check, + (const struct sockaddr*) &addr, + connect_cb)); + ASSERT_OK(uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb)); } static void connection_cb(uv_stream_t* server, int status) { unsigned int i; uv_tcp_t* incoming; - ASSERT(server == (uv_stream_t*) &tcp_server); + ASSERT_PTR_EQ(server, (uv_stream_t*) &tcp_server); /* Ignore tcp_check connection */ if (got_connections == ARRAY_SIZE(tcp_incoming)) @@ -126,8 +126,8 @@ static void connection_cb(uv_stream_t* server, int status) { /* Accept everyone */ incoming = &tcp_incoming[got_connections++]; - ASSERT(0 == uv_tcp_init(server->loop, incoming)); - ASSERT(0 == uv_accept(server, (uv_stream_t*) incoming)); + ASSERT_OK(uv_tcp_init(server->loop, incoming)); + ASSERT_OK(uv_accept(server, (uv_stream_t*) incoming)); if (got_connections != ARRAY_SIZE(tcp_incoming)) return; @@ -135,7 +135,7 @@ static void connection_cb(uv_stream_t* server, int status) { /* Once all clients are accepted - start reading */ for (i = 0; i < ARRAY_SIZE(tcp_incoming); i++) { incoming = &tcp_incoming[i]; - ASSERT(0 == uv_read_start((uv_stream_t*) incoming, alloc_cb, read_cb)); + ASSERT_OK(uv_read_start((uv_stream_t*) incoming, alloc_cb, read_cb)); } } @@ -162,30 +162,30 @@ TEST_IMPL(tcp_close_accept) { */ loop = uv_default_loop(); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(loop, &tcp_server)); - ASSERT(0 == uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0)); - ASSERT(0 == uv_listen((uv_stream_t*) &tcp_server, - ARRAY_SIZE(tcp_outgoing), - connection_cb)); + ASSERT_OK(uv_tcp_init(loop, &tcp_server)); + ASSERT_OK(uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_listen((uv_stream_t*) &tcp_server, + ARRAY_SIZE(tcp_outgoing), + connection_cb)); for (i = 0; i < ARRAY_SIZE(tcp_outgoing); i++) { client = tcp_outgoing + i; - ASSERT(0 == uv_tcp_init(loop, client)); - ASSERT(0 == uv_tcp_connect(&connect_reqs[i], - client, - (const struct sockaddr*) &addr, - connect_cb)); + ASSERT_OK(uv_tcp_init(loop, client)); + ASSERT_OK(uv_tcp_connect(&connect_reqs[i], + client, + (const struct sockaddr*) &addr, + connect_cb)); } uv_run(loop, UV_RUN_DEFAULT); - ASSERT(ARRAY_SIZE(tcp_outgoing) == got_connections); - ASSERT((ARRAY_SIZE(tcp_outgoing) + 2) == close_cb_called); - ASSERT(ARRAY_SIZE(tcp_outgoing) == write_cb_called); - ASSERT(1 == read_cb_called); + ASSERT_EQ(ARRAY_SIZE(tcp_outgoing), got_connections); + ASSERT_EQ((ARRAY_SIZE(tcp_outgoing) + 2), close_cb_called); + ASSERT_EQ(ARRAY_SIZE(tcp_outgoing), write_cb_called); + ASSERT_EQ(1, read_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-tcp-close-after-read-timeout.c b/test/test-tcp-close-after-read-timeout.c index 098e405a875..d5b54c2759e 100644 --- a/test/test-tcp-close-after-read-timeout.c +++ b/test/test-tcp-close-after-read-timeout.c @@ -48,10 +48,10 @@ static void on_client_connect(uv_connect_t* conn_req, int status) { int r; r = uv_read_start((uv_stream_t*) &client, on_client_alloc, on_client_read); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_timer_start(&timer, on_client_timeout, 1000, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } @@ -73,7 +73,7 @@ static void on_client_read(uv_stream_t* stream, ssize_t nread, static void on_client_timeout(uv_timer_t* handle) { ASSERT_EQ(handle, &timer); - ASSERT_EQ(read_cb_called, 0); + ASSERT_OK(read_cb_called); uv_read_stop((uv_stream_t*) &client); uv_close((uv_handle_t*) &client, on_close); uv_close((uv_handle_t*) &timer, on_close); @@ -101,20 +101,20 @@ static void on_connection_read(uv_stream_t* stream, static void on_connection(uv_stream_t* server, int status) { int r; - ASSERT_EQ(status, 0); - ASSERT_EQ(uv_accept(server, (uv_stream_t*) &connection), 0); + ASSERT_OK(status); + ASSERT_OK(uv_accept(server, (uv_stream_t*) &connection)); r = uv_read_start((uv_stream_t*) &connection, on_connection_alloc, on_connection_read); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } static void on_close(uv_handle_t* handle) { - ASSERT(handle == (uv_handle_t*) &client || - handle == (uv_handle_t*) &connection || - handle == (uv_handle_t*) &timer); + ASSERT_NE(handle == (uv_handle_t*) &client || + handle == (uv_handle_t*) &connection || + handle == (uv_handle_t*) &timer, 0); on_close_called++; } @@ -123,16 +123,16 @@ static void start_server(uv_loop_t* loop, uv_tcp_t* handle) { struct sockaddr_in addr; int r; - ASSERT_EQ(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr), 0); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init(loop, handle); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*) handle, 128, on_connection); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_unref((uv_handle_t*) handle); } @@ -147,7 +147,7 @@ TEST_IMPL(tcp_close_after_read_timeout) { uv_loop_t* loop; int r; - ASSERT_EQ(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr), 0); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); loop = uv_default_loop(); @@ -155,28 +155,28 @@ TEST_IMPL(tcp_close_after_read_timeout) { start_server(loop, &tcp_server); r = uv_tcp_init(loop, &client); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &client, (const struct sockaddr*) &addr, on_client_connect); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_init(loop, &connection); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_timer_init(loop, &timer); - ASSERT_EQ(r, 0); + ASSERT_OK(r); - ASSERT_EQ(read_cb_called, 0); - ASSERT_EQ(on_close_called, 0); + ASSERT_OK(read_cb_called); + ASSERT_OK(on_close_called); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT_EQ(r, 0); + ASSERT_OK(r); - ASSERT_EQ(read_cb_called, 1); - ASSERT_EQ(on_close_called, 3); + ASSERT_EQ(1, read_cb_called); + ASSERT_EQ(3, on_close_called); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-tcp-close-reset.c b/test/test-tcp-close-reset.c index 7415646996c..549b870199a 100644 --- a/test/test-tcp-close-reset.c +++ b/test/test-tcp-close-reset.c @@ -62,7 +62,7 @@ static void do_write(uv_tcp_t* handle) { buf = uv_buf_init("PING", 4); for (i = 0; i < ARRAY_SIZE(write_reqs); i++) { r = uv_write(&write_reqs[i], (uv_stream_t*) handle, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); } } @@ -72,21 +72,24 @@ static void do_close(uv_tcp_t* handle) { int r; if (shutdown_before_close == 1) { - ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) handle, shutdown_cb)); - ASSERT(UV_EINVAL == uv_tcp_close_reset(handle, close_cb)); + ASSERT_OK(uv_shutdown(&shutdown_req, + (uv_stream_t*) handle, + shutdown_cb)); + ASSERT_EQ(UV_EINVAL, uv_tcp_close_reset(handle, close_cb)); } else if (shutdown_before_close == 2) { r = uv_fileno((const uv_handle_t*) handle, &fd); - ASSERT_EQ(r, 0); + ASSERT_OK(r); ASSERT_NE(fd, INVALID_FD); #ifdef _WIN32 - ASSERT_EQ(0, shutdown(fd, SD_BOTH)); + ASSERT_OK(shutdown(fd, SD_BOTH)); #else - ASSERT_EQ(0, shutdown(fd, SHUT_RDWR)); + ASSERT_OK(shutdown(fd, SHUT_RDWR)); #endif - ASSERT_EQ(0, uv_tcp_close_reset(handle, close_cb)); + ASSERT_OK(uv_tcp_close_reset(handle, close_cb)); } else { - ASSERT(0 == uv_tcp_close_reset(handle, close_cb)); - ASSERT(UV_ENOTCONN == uv_shutdown(&shutdown_req, (uv_stream_t*) handle, shutdown_cb)); + ASSERT_OK(uv_tcp_close_reset(handle, close_cb)); + ASSERT_EQ(UV_ENOTCONN, uv_shutdown(&shutdown_req, (uv_stream_t*) handle, + shutdown_cb)); } uv_close((uv_handle_t*) &tcp_server, NULL); @@ -99,14 +102,14 @@ static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { } static void read_cb2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { - ASSERT((uv_tcp_t*)stream == &tcp_client); + ASSERT_PTR_EQ((uv_tcp_t*)stream, &tcp_client); if (nread == UV_EOF) uv_close((uv_handle_t*) stream, NULL); } static void connect_cb(uv_connect_t* conn_req, int status) { - ASSERT(conn_req == &connect_req); + ASSERT_PTR_EQ(conn_req, &connect_req); uv_read_start((uv_stream_t*) &tcp_client, alloc_cb, read_cb2); do_write(&tcp_client); if (client_close) @@ -116,33 +119,33 @@ static void connect_cb(uv_connect_t* conn_req, int status) { static void write_cb(uv_write_t* req, int status) { /* write callbacks should run before the close callback */ - ASSERT(close_cb_called == 0); - ASSERT(req->handle == (uv_stream_t*)&tcp_client); + ASSERT_OK(close_cb_called); + ASSERT_PTR_EQ(req->handle, (uv_stream_t*)&tcp_client); write_cb_called++; } static void close_cb(uv_handle_t* handle) { if (client_close) - ASSERT(handle == (uv_handle_t*) &tcp_client); + ASSERT_PTR_EQ(handle, (uv_handle_t*) &tcp_client); else - ASSERT(handle == (uv_handle_t*) &tcp_accepted); + ASSERT_PTR_EQ(handle, (uv_handle_t*) &tcp_accepted); close_cb_called++; } static void shutdown_cb(uv_shutdown_t* req, int status) { if (client_close) - ASSERT(req->handle == (uv_stream_t*) &tcp_client); + ASSERT_PTR_EQ(req->handle, (uv_stream_t*) &tcp_client); else - ASSERT(req->handle == (uv_stream_t*) &tcp_accepted); + ASSERT_PTR_EQ(req->handle, (uv_stream_t*) &tcp_accepted); shutdown_cb_called++; } static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { - ASSERT((uv_tcp_t*)stream == &tcp_accepted); + ASSERT_PTR_EQ((uv_tcp_t*)stream, &tcp_accepted); if (nread < 0) { uv_close((uv_handle_t*) stream, NULL); } else { @@ -154,10 +157,10 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { static void connection_cb(uv_stream_t* server, int status) { - ASSERT(status == 0); + ASSERT_OK(status); - ASSERT(0 == uv_tcp_init(loop, &tcp_accepted)); - ASSERT(0 == uv_accept(server, (uv_stream_t*) &tcp_accepted)); + ASSERT_OK(uv_tcp_init(loop, &tcp_accepted)); + ASSERT_OK(uv_accept(server, (uv_stream_t*) &tcp_accepted)); uv_read_start((uv_stream_t*) &tcp_accepted, alloc_cb, read_cb); } @@ -167,16 +170,16 @@ static void start_server(uv_loop_t* loop, uv_tcp_t* handle) { struct sockaddr_in addr; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init(loop, handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)handle, 128, connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -184,16 +187,16 @@ static void do_connect(uv_loop_t* loop, uv_tcp_t* tcp_client) { struct sockaddr_in addr; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init(loop, tcp_client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, tcp_client, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -212,16 +215,16 @@ TEST_IMPL(tcp_close_reset_client) { do_connect(loop, &tcp_client); - ASSERT(write_cb_called == 0); - ASSERT(close_cb_called == 0); - ASSERT(shutdown_cb_called == 0); + ASSERT_OK(write_cb_called); + ASSERT_OK(close_cb_called); + ASSERT_OK(shutdown_cb_called); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(write_cb_called == 4); - ASSERT(close_cb_called == 1); - ASSERT(shutdown_cb_called == 0); + ASSERT_EQ(4, write_cb_called); + ASSERT_EQ(1, close_cb_called); + ASSERT_OK(shutdown_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -239,16 +242,16 @@ TEST_IMPL(tcp_close_reset_client_after_shutdown) { do_connect(loop, &tcp_client); - ASSERT(write_cb_called == 0); - ASSERT(close_cb_called == 0); - ASSERT(shutdown_cb_called == 0); + ASSERT_OK(write_cb_called); + ASSERT_OK(close_cb_called); + ASSERT_OK(shutdown_cb_called); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(write_cb_called == 4); - ASSERT(close_cb_called == 0); - ASSERT(shutdown_cb_called == 1); + ASSERT_EQ(4, write_cb_called); + ASSERT_OK(close_cb_called); + ASSERT_EQ(1, shutdown_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -266,16 +269,16 @@ TEST_IMPL(tcp_close_reset_accepted) { do_connect(loop, &tcp_client); - ASSERT(write_cb_called == 0); - ASSERT(close_cb_called == 0); - ASSERT(shutdown_cb_called == 0); + ASSERT_OK(write_cb_called); + ASSERT_OK(close_cb_called); + ASSERT_OK(shutdown_cb_called); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(write_cb_called == 4); - ASSERT(close_cb_called == 1); - ASSERT(shutdown_cb_called == 0); + ASSERT_EQ(4, write_cb_called); + ASSERT_EQ(1, close_cb_called); + ASSERT_OK(shutdown_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -293,16 +296,16 @@ TEST_IMPL(tcp_close_reset_accepted_after_shutdown) { do_connect(loop, &tcp_client); - ASSERT(write_cb_called == 0); - ASSERT(close_cb_called == 0); - ASSERT(shutdown_cb_called == 0); + ASSERT_OK(write_cb_called); + ASSERT_OK(close_cb_called); + ASSERT_OK(shutdown_cb_called); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(write_cb_called == 4); - ASSERT(close_cb_called == 0); - ASSERT(shutdown_cb_called == 1); + ASSERT_EQ(4, write_cb_called); + ASSERT_OK(close_cb_called); + ASSERT_EQ(1, shutdown_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -320,16 +323,16 @@ TEST_IMPL(tcp_close_reset_accepted_after_socket_shutdown) { do_connect(loop, &tcp_client); - ASSERT_EQ(write_cb_called, 0); - ASSERT_EQ(close_cb_called, 0); - ASSERT_EQ(shutdown_cb_called, 0); + ASSERT_OK(write_cb_called); + ASSERT_OK(close_cb_called); + ASSERT_OK(shutdown_cb_called); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT_EQ(r, 0); + ASSERT_OK(r); - ASSERT_EQ(write_cb_called, 4); - ASSERT_EQ(close_cb_called, 1); - ASSERT_EQ(shutdown_cb_called, 0); + ASSERT_EQ(4, write_cb_called); + ASSERT_EQ(1, close_cb_called); + ASSERT_OK(shutdown_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-tcp-close-while-connecting.c b/test/test-tcp-close-while-connecting.c index 490413891bb..ba5e46901a4 100644 --- a/test/test-tcp-close-while-connecting.c +++ b/test/test-tcp-close-while-connecting.c @@ -69,24 +69,24 @@ TEST_IMPL(tcp_close_while_connecting) { int r; loop = uv_default_loop(); - ASSERT(0 == uv_ip4_addr("1.2.3.4", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(loop, &tcp_handle)); + ASSERT_OK(uv_ip4_addr("1.2.3.4", TEST_PORT, &addr)); + ASSERT_OK(uv_tcp_init(loop, &tcp_handle)); r = uv_tcp_connect(&connect_req, &tcp_handle, (const struct sockaddr*) &addr, connect_cb); if (r == UV_ENETUNREACH) RETURN_SKIP("Network unreachable."); - ASSERT(r == 0); - ASSERT(0 == uv_timer_init(loop, &timer1_handle)); - ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 1, 0)); - ASSERT(0 == uv_timer_init(loop, &timer2_handle)); - ASSERT(0 == uv_timer_start(&timer2_handle, timer2_cb, 86400 * 1000, 0)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - - ASSERT(connect_cb_called == 1); - ASSERT(timer1_cb_called == 1); - ASSERT(close_cb_called == 2); + ASSERT_OK(r); + ASSERT_OK(uv_timer_init(loop, &timer1_handle)); + ASSERT_OK(uv_timer_start(&timer1_handle, timer1_cb, 1, 0)); + ASSERT_OK(uv_timer_init(loop, &timer2_handle)); + ASSERT_OK(uv_timer_start(&timer2_handle, timer2_cb, 86400 * 1000, 0)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, timer1_cb_called); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(loop); diff --git a/test/test-tcp-close.c b/test/test-tcp-close.c index 6879bae20f8..ed19da6f783 100644 --- a/test/test-tcp-close.c +++ b/test/test-tcp-close.c @@ -49,7 +49,7 @@ static void connect_cb(uv_connect_t* conn_req, int status) { ASSERT_NOT_NULL(req); r = uv_write(req, (uv_stream_t*)&tcp_handle, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); } uv_close((uv_handle_t*)&tcp_handle, close_cb); @@ -58,21 +58,21 @@ static void connect_cb(uv_connect_t* conn_req, int status) { static void write_cb(uv_write_t* req, int status) { /* write callbacks should run before the close callback */ - ASSERT(close_cb_called == 0); - ASSERT(req->handle == (uv_stream_t*)&tcp_handle); + ASSERT_OK(close_cb_called); + ASSERT_PTR_EQ(req->handle, (uv_stream_t*)&tcp_handle); write_cb_called++; free(req); } static void close_cb(uv_handle_t* handle) { - ASSERT(handle == (uv_handle_t*)&tcp_handle); + ASSERT_PTR_EQ(handle, (uv_handle_t*)&tcp_handle); close_cb_called++; } static void connection_cb(uv_stream_t* server, int status) { - ASSERT(status == 0); + ASSERT_OK(status); } @@ -80,16 +80,16 @@ static void start_server(uv_loop_t* loop, uv_tcp_t* handle) { struct sockaddr_in addr; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init(loop, handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)handle, 128, connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_unref((uv_handle_t*)handle); } @@ -104,7 +104,7 @@ TEST_IMPL(tcp_close) { uv_loop_t* loop; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); loop = uv_default_loop(); @@ -112,24 +112,24 @@ TEST_IMPL(tcp_close) { start_server(loop, &tcp_server); r = uv_tcp_init(loop, &tcp_handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &tcp_handle, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(write_cb_called == 0); - ASSERT(close_cb_called == 0); + ASSERT_OK(write_cb_called); + ASSERT_OK(close_cb_called); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); printf("%d of %d write reqs seen\n", write_cb_called, NUM_WRITE_REQS); - ASSERT(write_cb_called == NUM_WRITE_REQS); - ASSERT(close_cb_called == 1); + ASSERT_EQ(write_cb_called, NUM_WRITE_REQS); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-tcp-connect-error-after-write.c b/test/test-tcp-connect-error-after-write.c index 1800b4d6ed0..7321259628d 100644 --- a/test/test-tcp-connect-error-after-write.c +++ b/test/test-tcp-connect-error-after-write.c @@ -37,14 +37,14 @@ static void close_cb(uv_handle_t* handle) { static void connect_cb(uv_connect_t* req, int status) { - ASSERT(status < 0); + ASSERT_LT(status, 0); connect_cb_called++; uv_close((uv_handle_t*)req->handle, close_cb); } static void write_cb(uv_write_t* req, int status) { - ASSERT(status < 0); + ASSERT_LT(status, 0); write_cb_called++; } @@ -67,30 +67,30 @@ TEST_IMPL(tcp_connect_error_after_write) { uv_buf_t buf; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); buf = uv_buf_init("TEST", 4); r = uv_tcp_init(uv_default_loop(), &conn); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb); - ASSERT(r == UV_EBADF); + ASSERT_EQ(r, UV_EBADF); r = uv_tcp_connect(&connect_req, &conn, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(connect_cb_called == 1); - ASSERT(write_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, write_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-connect-error.c b/test/test-tcp-connect-error.c index 9384ebce57c..ee0f9ee5ce6 100644 --- a/test/test-tcp-connect-error.c +++ b/test/test-tcp-connect-error.c @@ -54,19 +54,19 @@ TEST_IMPL(tcp_connect_error_fault) { garbage_addr = (const struct sockaddr_in*) &garbage; r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&req, &server, (const struct sockaddr*) garbage_addr, connect_cb); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_close((uv_handle_t*)&server, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(connect_cb_called == 0); - ASSERT(close_cb_called == 1); + ASSERT_OK(connect_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-connect-timeout.c b/test/test-tcp-connect-timeout.c index 4cd83e1d38b..4eb834e1afa 100644 --- a/test/test-tcp-connect-timeout.c +++ b/test/test-tcp-connect-timeout.c @@ -38,14 +38,14 @@ static void close_cb(uv_handle_t* handle); static void connect_cb(uv_connect_t* req, int status) { - ASSERT(req == &connect_req); - ASSERT(status == UV_ECANCELED); + ASSERT_PTR_EQ(req, &connect_req); + ASSERT_EQ(status, UV_ECANCELED); connect_cb_called++; } static void timer_cb(uv_timer_t* handle) { - ASSERT(handle == &timer); + ASSERT_PTR_EQ(handle, &timer); uv_close((uv_handle_t*)&conn, close_cb); uv_close((uv_handle_t*)&timer, close_cb); } @@ -64,16 +64,16 @@ TEST_IMPL(tcp_connect_timeout) { struct sockaddr_in addr; int r; - ASSERT(0 == uv_ip4_addr("8.8.8.8", 9999, &addr)); + ASSERT_OK(uv_ip4_addr("8.8.8.8", 9999, &addr)); r = uv_timer_init(uv_default_loop(), &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, timer_cb, 50, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_init(uv_default_loop(), &conn); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &conn, @@ -81,10 +81,10 @@ TEST_IMPL(tcp_connect_timeout) { connect_cb); if (r == UV_ENETUNREACH) RETURN_SKIP("Network unreachable."); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -105,7 +105,7 @@ static int is_supported_system(void) { int min_semver[3] = {10, 0, 16299}; int cnt; uv_utsname_t uname; - ASSERT_EQ(uv_os_uname(&uname), 0); + ASSERT_OK(uv_os_uname(&uname)); if (strcmp(uname.sysname, "Windows_NT") == 0) { cnt = sscanf(uname.release, "%d.%d.%d", &semver[0], &semver[1], &semver[2]); if (cnt != 3) { @@ -130,17 +130,17 @@ TEST_IMPL(tcp_local_connect_timeout) { if (!is_supported_system()) { RETURN_SKIP("Unsupported system"); } - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_timer_init(uv_default_loop(), &timer); - ASSERT_EQ(r, 0); + ASSERT_OK(r); /* Give it 1s to timeout. */ r = uv_timer_start(&timer, timer_cb, 1000, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_init(uv_default_loop(), &conn); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &conn, @@ -148,10 +148,10 @@ TEST_IMPL(tcp_local_connect_timeout) { connect_local_cb); if (r == UV_ENETUNREACH) RETURN_SKIP("Network unreachable."); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -168,17 +168,17 @@ TEST_IMPL(tcp6_local_connect_timeout) { RETURN_SKIP("IPv6 not supported"); } - ASSERT_EQ(0, uv_ip6_addr("::1", 9999, &addr)); + ASSERT_OK(uv_ip6_addr("::1", 9999, &addr)); r = uv_timer_init(uv_default_loop(), &timer); - ASSERT_EQ(r, 0); + ASSERT_OK(r); /* Give it 1s to timeout. */ r = uv_timer_start(&timer, timer_cb, 1000, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_init(uv_default_loop(), &conn); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &conn, @@ -186,10 +186,10 @@ TEST_IMPL(tcp6_local_connect_timeout) { connect_local_cb); if (r == UV_ENETUNREACH) RETURN_SKIP("Network unreachable."); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(r, 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-connect6-error.c b/test/test-tcp-connect6-error.c index 70faf32378e..1e6d7c78da9 100644 --- a/test/test-tcp-connect6-error.c +++ b/test/test-tcp-connect6-error.c @@ -55,19 +55,19 @@ TEST_IMPL(tcp_connect6_error_fault) { garbage_addr = (const struct sockaddr_in6*) &garbage; r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&req, &server, (const struct sockaddr*) garbage_addr, connect_cb); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_close((uv_handle_t*)&server, close_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(connect_cb_called == 0); - ASSERT(close_cb_called == 1); + ASSERT_OK(connect_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-create-socket-early.c b/test/test-tcp-create-socket-early.c index c84882dad21..13e80ad5dc0 100644 --- a/test/test-tcp-create-socket-early.c +++ b/test/test-tcp-create-socket-early.c @@ -32,7 +32,7 @@ static void on_connect(uv_connect_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); uv_close((uv_handle_t*) req->handle, NULL); } @@ -41,16 +41,16 @@ static void on_connection(uv_stream_t* server, int status) { uv_tcp_t* handle; int r; - ASSERT(status == 0); + ASSERT_OK(status); handle = malloc(sizeof(*handle)); ASSERT_NOT_NULL(handle); r = uv_tcp_init_ex(server->loop, handle, AF_INET); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_accept(server, (uv_stream_t*)handle); - ASSERT(r == UV_EBUSY); + ASSERT_EQ(r, UV_EBUSY); uv_close((uv_handle_t*) server, NULL); uv_close((uv_handle_t*) handle, (uv_close_cb)free); @@ -61,16 +61,16 @@ static void tcp_listener(uv_loop_t* loop, uv_tcp_t* server) { struct sockaddr_in addr; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_tcp_init(loop, server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*) server, 128, on_connection); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -78,16 +78,16 @@ static void tcp_connector(uv_loop_t* loop, uv_tcp_t* client, uv_connect_t* req) struct sockaddr_in server_addr; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); r = uv_tcp_init(loop, client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(req, client, (const struct sockaddr*) &server_addr, on_connect); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -98,32 +98,32 @@ TEST_IMPL(tcp_create_early) { uv_os_fd_t fd; int r, namelen; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fileno((const uv_handle_t*) &client, &fd); - ASSERT(r == 0); - ASSERT(fd != INVALID_FD); + ASSERT_OK(r); + ASSERT_NE(fd, INVALID_FD); /* Windows returns WSAEINVAL if the socket is not bound */ #ifndef _WIN32 namelen = sizeof sockname; r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen); - ASSERT(r == 0); - ASSERT(sockname.sin_family == AF_INET); + ASSERT_OK(r); + ASSERT_EQ(sockname.sin_family, AF_INET); #endif r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); namelen = sizeof sockname; r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen); - ASSERT(r == 0); - ASSERT(memcmp(&addr.sin_addr, - &sockname.sin_addr, - sizeof(addr.sin_addr)) == 0); + ASSERT_OK(r); + ASSERT_OK(memcmp(&addr.sin_addr, + &sockname.sin_addr, + sizeof(addr.sin_addr))); uv_close((uv_handle_t*) &client, NULL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); @@ -142,14 +142,14 @@ TEST_IMPL(tcp_create_early_bad_bind) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET6); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fileno((const uv_handle_t*) &client, &fd); - ASSERT(r == 0); - ASSERT(fd != INVALID_FD); + ASSERT_OK(r); + ASSERT_NE(fd, INVALID_FD); /* Windows returns WSAEINVAL if the socket is not bound */ #ifndef _WIN32 @@ -158,16 +158,16 @@ TEST_IMPL(tcp_create_early_bad_bind) { struct sockaddr_in6 sockname; namelen = sizeof sockname; r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen); - ASSERT(r == 0); - ASSERT(sockname.sin6_family == AF_INET6); + ASSERT_OK(r); + ASSERT_EQ(sockname.sin6_family, AF_INET6); } #endif r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0); #if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MSYS__) - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); #else - ASSERT(r == UV_EFAULT); + ASSERT_EQ(r, UV_EFAULT); #endif uv_close((uv_handle_t*) &client, NULL); @@ -183,10 +183,10 @@ TEST_IMPL(tcp_create_early_bad_domain) { int r; r = uv_tcp_init_ex(uv_default_loop(), &client, 47); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_tcp_init_ex(uv_default_loop(), &client, 1024); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); diff --git a/test/test-tcp-flags.c b/test/test-tcp-flags.c index 6856429aa1d..30178d706d9 100644 --- a/test/test-tcp-flags.c +++ b/test/test-tcp-flags.c @@ -34,18 +34,18 @@ TEST_IMPL(tcp_flags) { loop = uv_default_loop(); r = uv_tcp_init(loop, &handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_nodelay(&handle, 1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_keepalive(&handle, 1, 60); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*)&handle, NULL); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-tcp-oob.c b/test/test-tcp-oob.c index 989454ed878..7962fa93448 100644 --- a/test/test-tcp-oob.c +++ b/test/test-tcp-oob.c @@ -61,22 +61,22 @@ static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { #endif uv_os_fd_t fd; - ASSERT(nread >= 0); - ASSERT(0 == uv_fileno((uv_handle_t*)handle, &fd)); - ASSERT(0 == uv_idle_start(&idle, idle_cb)); + ASSERT_GE(nread, 0); + ASSERT_OK(uv_fileno((uv_handle_t*)handle, &fd)); + ASSERT_OK(uv_idle_start(&idle, idle_cb)); #ifdef __MVS__ /* Need to flush out the OOB data. Otherwise, this callback will get * triggered on every poll with nread = 0. */ - ASSERT(-1 != recv(fd, lbuf, sizeof(lbuf), MSG_OOB)); + ASSERT_NE(-1, recv(fd, lbuf, sizeof(lbuf), MSG_OOB)); #endif } static void connect_cb(uv_connect_t* req, int status) { - ASSERT(req->handle == (uv_stream_t*) &client_handle); - ASSERT(0 == status); + ASSERT_PTR_EQ(req->handle, (uv_stream_t*) &client_handle); + ASSERT_OK(status); } @@ -84,14 +84,14 @@ static void connection_cb(uv_stream_t* handle, int status) { int r; uv_os_fd_t fd; - ASSERT(0 == status); - ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle)); - ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb)); + ASSERT_OK(status); + ASSERT_OK(uv_accept(handle, (uv_stream_t*) &peer_handle)); + ASSERT_OK(uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb)); /* Send some OOB data */ - ASSERT(0 == uv_fileno((uv_handle_t*) &client_handle, &fd)); + ASSERT_OK(uv_fileno((uv_handle_t*) &client_handle, &fd)); - ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &client_handle, 1)); + ASSERT_OK(uv_stream_set_blocking((uv_stream_t*) &client_handle, 1)); /* The problem triggers only on a second message, it seem that xnu is not * triggering `kevent()` for the first one @@ -99,14 +99,14 @@ static void connection_cb(uv_stream_t* handle, int status) { do { r = send(fd, "hello", 5, MSG_OOB); } while (r < 0 && errno == EINTR); - ASSERT(5 == r); + ASSERT_EQ(5, r); do { r = send(fd, "hello", 5, MSG_OOB); } while (r < 0 && errno == EINTR); - ASSERT(5 == r); + ASSERT_EQ(5, r); - ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &client_handle, 0)); + ASSERT_OK(uv_stream_set_blocking((uv_stream_t*) &client_handle, 0)); } @@ -114,26 +114,26 @@ TEST_IMPL(tcp_oob) { struct sockaddr_in addr; uv_loop_t* loop; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); loop = uv_default_loop(); - ASSERT(0 == uv_tcp_init(loop, &server_handle)); - ASSERT(0 == uv_tcp_init(loop, &client_handle)); - ASSERT(0 == uv_tcp_init(loop, &peer_handle)); - ASSERT(0 == uv_idle_init(loop, &idle)); - ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); - ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); + ASSERT_OK(uv_tcp_init(loop, &server_handle)); + ASSERT_OK(uv_tcp_init(loop, &client_handle)); + ASSERT_OK(uv_tcp_init(loop, &peer_handle)); + ASSERT_OK(uv_idle_init(loop, &idle)); + ASSERT_OK(uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); /* Ensure two separate packets */ - ASSERT(0 == uv_tcp_nodelay(&client_handle, 1)); + ASSERT_OK(uv_tcp_nodelay(&client_handle, 1)); - ASSERT(0 == uv_tcp_connect(&connect_req, - &client_handle, - (const struct sockaddr*) &addr, - connect_cb)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_tcp_connect(&connect_req, + &client_handle, + (const struct sockaddr*) &addr, + connect_cb)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(ticks == kMaxTicks); + ASSERT_EQ(ticks, kMaxTicks); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-tcp-open.c b/test/test-tcp-open.c index b5c5621a793..3fbcf2a5f23 100644 --- a/test/test-tcp-open.c +++ b/test/test-tcp-open.c @@ -46,7 +46,7 @@ static void startup(void) { #ifdef _WIN32 struct WSAData wsa_data; int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); - ASSERT(r == 0); + ASSERT_OK(r); #endif } @@ -56,9 +56,9 @@ static uv_os_sock_t create_tcp_socket(void) { sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); #ifdef _WIN32 - ASSERT(sock != INVALID_SOCKET); + ASSERT_NE(sock, INVALID_SOCKET); #else - ASSERT(sock >= 0); + ASSERT_GE(sock, 0); #endif #ifndef _WIN32 @@ -66,7 +66,7 @@ static uv_os_sock_t create_tcp_socket(void) { /* Allow reuse of the port. */ int yes = 1; int r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - ASSERT(r == 0); + ASSERT_OK(r); } #endif @@ -81,7 +81,7 @@ static void close_socket(uv_os_sock_t sock) { #else r = close(sock); #endif - ASSERT(r == 0); + ASSERT_OK(r); } @@ -89,7 +89,7 @@ static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { static char slab[65536]; - ASSERT(suggested_size <= sizeof(slab)); + ASSERT_LE(suggested_size, sizeof(slab)); buf->base = slab; buf->len = sizeof(slab); } @@ -102,8 +102,8 @@ static void close_cb(uv_handle_t* handle) { static void shutdown_cb(uv_shutdown_t* req, int status) { - ASSERT(req == &shutdown_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &shutdown_req); + ASSERT_OK(status); /* Now we wait for the EOF */ shutdown_cb_called++; @@ -114,11 +114,11 @@ static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { ASSERT_NOT_NULL(tcp); if (nread >= 0) { - ASSERT(nread == 4); - ASSERT(memcmp("PING", buf->base, nread) == 0); + ASSERT_EQ(4, nread); + ASSERT_OK(memcmp("PING", buf->base, nread)); } else { - ASSERT(nread == UV_EOF); + ASSERT_EQ(nread, UV_EOF); uv_close((uv_handle_t*)tcp, close_cb); } } @@ -130,9 +130,9 @@ static void read1_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { if (nread >= 0) { for (i = 0; i < nread; ++i) - ASSERT(buf->base[i] == 'P'); + ASSERT_EQ(buf->base[i], 'P'); } else { - ASSERT(nread == UV_EOF); + ASSERT_EQ(nread, UV_EOF); printf("GOT EOF\n"); uv_close((uv_handle_t*)tcp, close_cb); } @@ -166,7 +166,7 @@ static void write1_cb(uv_write_t* req, int status) { buf = uv_buf_init("P", 1); r = uv_write(&write_req, req->handle, &buf, 1, write1_cb); - ASSERT(r == 0); + ASSERT_OK(r); write_cb_called++; } @@ -177,7 +177,7 @@ static void timer_cb(uv_timer_t* handle) { /* Shutdown on drain. */ r = uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb); - ASSERT(r == 0); + ASSERT_OK(r); shutdown_requested++; } @@ -187,22 +187,22 @@ static void connect_cb(uv_connect_t* req, int status) { uv_stream_t* stream; int r; - ASSERT(req == &connect_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &connect_req); + ASSERT_OK(status); stream = req->handle; connect_cb_called++; r = uv_write(&write_req, stream, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); /* Shutdown on drain. */ r = uv_shutdown(&shutdown_req, stream, shutdown_cb); - ASSERT(r == 0); + ASSERT_OK(r); /* Start reading */ r = uv_read_start(stream, alloc_cb, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -211,25 +211,25 @@ static void connect1_cb(uv_connect_t* req, int status) { uv_stream_t* stream; int r; - ASSERT(req == &connect_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &connect_req); + ASSERT_OK(status); stream = req->handle; connect_cb_called++; r = uv_timer_init(uv_default_loop(), &tm); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&tm, timer_cb, 2000, 0); - ASSERT(r == 0); + ASSERT_OK(r); buf = uv_buf_init("P", 1); r = uv_write(&write_req, stream, &buf, 1, write1_cb); - ASSERT(r == 0); + ASSERT_OK(r); /* Start reading */ r = uv_read_start(stream, alloc_cb, read1_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -239,30 +239,30 @@ TEST_IMPL(tcp_open) { int r; uv_tcp_t client2; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); startup(); sock = create_tcp_socket(); r = uv_tcp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_open(&client, sock); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &client, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); #ifndef _WIN32 { r = uv_tcp_init(uv_default_loop(), &client2); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_open(&client2, sock); - ASSERT(r == UV_EEXIST); + ASSERT_EQ(r, UV_EEXIST); uv_close((uv_handle_t*) &client2, NULL); } @@ -272,10 +272,10 @@ TEST_IMPL(tcp_open) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(shutdown_cb_called == 1); - ASSERT(connect_cb_called == 1); - ASSERT(write_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, shutdown_cb_called); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, write_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -292,13 +292,13 @@ TEST_IMPL(tcp_open_twice) { sock2 = create_tcp_socket(); r = uv_tcp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_open(&client, sock1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_open(&client, sock2); - ASSERT(r == UV_EBUSY); + ASSERT_EQ(r, UV_EBUSY); close_socket(sock2); uv_close((uv_handle_t*) &client, NULL); @@ -317,15 +317,15 @@ TEST_IMPL(tcp_open_bound) { startup(); sock = create_tcp_socket(); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &server)); - ASSERT(0 == bind(sock, (struct sockaddr*) &addr, sizeof(addr))); + ASSERT_OK(bind(sock, (struct sockaddr*) &addr, sizeof(addr))); - ASSERT(0 == uv_tcp_open(&server, sock)); + ASSERT_OK(uv_tcp_open(&server, sock)); - ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, NULL)); + ASSERT_OK(uv_listen((uv_stream_t*) &server, 128, NULL)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -338,28 +338,34 @@ TEST_IMPL(tcp_open_connected) { uv_os_sock_t sock; uv_buf_t buf = uv_buf_init("PING", 4); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); startup(); sock = create_tcp_socket(); - ASSERT(0 == connect(sock, (struct sockaddr*) &addr, sizeof(addr))); + ASSERT_OK(connect(sock, (struct sockaddr*) &addr, sizeof(addr))); - ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &client)); - ASSERT(0 == uv_tcp_open(&client, sock)); + ASSERT_OK(uv_tcp_open(&client, sock)); - ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &client, &buf, 1, write_cb)); + ASSERT_OK(uv_write(&write_req, + (uv_stream_t*) &client, + &buf, + 1, + write_cb)); - ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb)); + ASSERT_OK(uv_shutdown(&shutdown_req, + (uv_stream_t*) &client, + shutdown_cb)); - ASSERT(0 == uv_read_start((uv_stream_t*) &client, alloc_cb, read_cb)); + ASSERT_OK(uv_read_start((uv_stream_t*) &client, alloc_cb, read_cb)); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(shutdown_cb_called == 1); - ASSERT(write_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, shutdown_cb_called); + ASSERT_EQ(1, write_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -371,30 +377,30 @@ TEST_IMPL(tcp_write_ready) { uv_os_sock_t sock; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); startup(); sock = create_tcp_socket(); r = uv_tcp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_open(&client, sock); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &client, (const struct sockaddr*) &addr, connect1_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(shutdown_cb_called == 1); - ASSERT(shutdown_requested == 1); - ASSERT(connect_cb_called == 1); - ASSERT(write_cb_called > 0); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, shutdown_cb_called); + ASSERT_EQ(1, shutdown_requested); + ASSERT_EQ(1, connect_cb_called); + ASSERT_GT(write_cb_called, 0); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-read-stop-start.c b/test/test-tcp-read-stop-start.c index 9be12bb75b0..68d6f7c2ab5 100644 --- a/test/test-tcp-read-stop-start.c +++ b/test/test-tcp-read-stop-start.c @@ -33,14 +33,14 @@ static uv_connect_t connect_req; static void on_read2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); static void on_write_close_immediately(uv_write_t* req, int status) { - ASSERT(0 == status); + ASSERT_OK(status); uv_close((uv_handle_t*)req->handle, NULL); /* Close immediately */ free(req); } static void on_write(uv_write_t* req, int status) { - ASSERT(0 == status); + ASSERT_OK(status); free(req); } @@ -50,7 +50,7 @@ static void do_write(uv_stream_t* stream, uv_write_cb cb) { uv_buf_t buf; buf.base = "1234578"; buf.len = 8; - ASSERT(0 == uv_write(req, stream, &buf, 1, cb)); + ASSERT_OK(uv_write(req, stream, &buf, 1, cb)); } static void on_alloc(uv_handle_t* handle, @@ -62,22 +62,22 @@ static void on_alloc(uv_handle_t* handle, } static void on_read1(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { - ASSERT(nread >= 0); + ASSERT_GE(nread, 0); /* Do write on a half open connection to force WSAECONNABORTED (on Windows) * in the subsequent uv_read_start() */ do_write(stream, on_write); - ASSERT(0 == uv_read_stop(stream)); + ASSERT_OK(uv_read_stop(stream)); - ASSERT(0 == uv_read_start(stream, on_alloc, on_read2)); + ASSERT_OK(uv_read_start(stream, on_alloc, on_read2)); read_cb_called++; } static void on_read2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { - ASSERT(nread < 0); + ASSERT_LT(nread, 0); uv_close((uv_handle_t*)stream, NULL); uv_close((uv_handle_t*)&server, NULL); @@ -86,17 +86,17 @@ static void on_read2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { } static void on_connection(uv_stream_t* server, int status) { - ASSERT(0 == status); + ASSERT_OK(status); - ASSERT(0 == uv_tcp_init(server->loop, &connection)); + ASSERT_OK(uv_tcp_init(server->loop, &connection)); - ASSERT(0 == uv_accept(server, (uv_stream_t* )&connection)); + ASSERT_OK(uv_accept(server, (uv_stream_t* )&connection)); - ASSERT(0 == uv_read_start((uv_stream_t*)&connection, on_alloc, on_read1)); + ASSERT_OK(uv_read_start((uv_stream_t*)&connection, on_alloc, on_read1)); } static void on_connect(uv_connect_t* req, int status) { - ASSERT(0 == status); + ASSERT_OK(status); do_write((uv_stream_t*)&client, on_write_close_immediately); } @@ -107,29 +107,29 @@ TEST_IMPL(tcp_read_stop_start) { { /* Server */ struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(loop, &server)); + ASSERT_OK(uv_tcp_init(loop, &server)); - ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) & addr, 0)); + ASSERT_OK(uv_tcp_bind(&server, (struct sockaddr*) & addr, 0)); - ASSERT(0 == uv_listen((uv_stream_t*)&server, 10, on_connection)); + ASSERT_OK(uv_listen((uv_stream_t*)&server, 10, on_connection)); } { /* Client */ struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(loop, &client)); + ASSERT_OK(uv_tcp_init(loop, &client)); - ASSERT(0 == uv_tcp_connect(&connect_req, &client, - (const struct sockaddr*) & addr, on_connect)); + ASSERT_OK(uv_tcp_connect(&connect_req, &client, + (const struct sockaddr*) & addr, on_connect)); } - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(read_cb_called >= 2); + ASSERT_GE(read_cb_called, 2); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-tcp-read-stop.c b/test/test-tcp-read-stop.c index 1754876d4f1..114c5ec135a 100644 --- a/test/test-tcp-read-stop.c +++ b/test/test-tcp-read-stop.c @@ -40,21 +40,21 @@ static void write_cb(uv_write_t* req, int status) { static void timer_cb(uv_timer_t* handle) { uv_buf_t buf = uv_buf_init("PING", 4); - ASSERT(0 == uv_write(&write_req, - (uv_stream_t*) &tcp_handle, - &buf, - 1, - write_cb)); - ASSERT(0 == uv_read_stop((uv_stream_t*) &tcp_handle)); + ASSERT_OK(uv_write(&write_req, + (uv_stream_t*) &tcp_handle, + &buf, + 1, + write_cb)); + ASSERT_OK(uv_read_stop((uv_stream_t*) &tcp_handle)); } static void connect_cb(uv_connect_t* req, int status) { - ASSERT(0 == status); - ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0)); - ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_handle, - (uv_alloc_cb) fail_cb, - (uv_read_cb) fail_cb)); + ASSERT_OK(status); + ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, 50, 0)); + ASSERT_OK(uv_read_start((uv_stream_t*) &tcp_handle, + (uv_alloc_cb) fail_cb, + (uv_read_cb) fail_cb)); } @@ -62,14 +62,14 @@ TEST_IMPL(tcp_read_stop) { uv_connect_t connect_req; struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); - ASSERT(0 == uv_tcp_init(uv_default_loop(), &tcp_handle)); - ASSERT(0 == uv_tcp_connect(&connect_req, - &tcp_handle, - (const struct sockaddr*) &addr, - connect_cb)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &tcp_handle)); + ASSERT_OK(uv_tcp_connect(&connect_req, + &tcp_handle, + (const struct sockaddr*) &addr, + connect_cb)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-rst.c b/test/test-tcp-rst.c index b5d216ce7e8..7729f03e607 100644 --- a/test/test-tcp-rst.c +++ b/test/test-tcp-rst.c @@ -31,7 +31,7 @@ static int called_close_cb; static void close_cb(uv_handle_t* handle) { - ASSERT(handle == (uv_handle_t*) &tcp); + ASSERT_PTR_EQ(handle, (uv_handle_t*) &tcp); called_close_cb++; } @@ -48,7 +48,7 @@ static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) { ASSERT_EQ(nread, UV_ECONNRESET); int fd; - ASSERT_EQ(0, uv_fileno((uv_handle_t*) t, &fd)); + ASSERT_OK(uv_fileno((uv_handle_t*) t, &fd)); uv_handle_type type = uv_guess_handle(fd); ASSERT_EQ(type, UV_TCP); @@ -58,11 +58,11 @@ static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) { static void connect_cb(uv_connect_t *req, int status) { - ASSERT_EQ(status, 0); + ASSERT_OK(status); ASSERT_PTR_EQ(req, &connect_req); /* Start reading from the connection so we receive the RST in uv__read. */ - ASSERT_EQ(0, uv_read_start((uv_stream_t*) &tcp, alloc_cb, read_cb)); + ASSERT_OK(uv_read_start((uv_stream_t*) &tcp, alloc_cb, read_cb)); /* Write 'QSH' to receive RST from the echo server. */ ASSERT_EQ(qbuf.len, uv_try_write((uv_stream_t*) &tcp, &qbuf, 1)); @@ -86,21 +86,21 @@ TEST_IMPL(tcp_rst) { qbuf.base = "QSH"; qbuf.len = 3; - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr)); r = uv_tcp_init(uv_default_loop(), &tcp); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &tcp, (const struct sockaddr*) &server_addr, connect_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(called_alloc_cb, 1); - ASSERT_EQ(called_connect_cb, 1); - ASSERT_EQ(called_close_cb, 1); + ASSERT_EQ(1, called_alloc_cb); + ASSERT_EQ(1, called_connect_cb); + ASSERT_EQ(1, called_close_cb); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-shutdown-after-write.c b/test/test-tcp-shutdown-after-write.c index d2401e8fdb3..cd8c24dd66b 100644 --- a/test/test-tcp-shutdown-after-write.c +++ b/test/test-tcp-shutdown-after-write.c @@ -66,10 +66,10 @@ static void timer_cb(uv_timer_t* handle) { buf = uv_buf_init("TEST", 4); r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_shutdown(&shutdown_req, (uv_stream_t*)&conn, shutdown_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -80,22 +80,22 @@ static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { static void connect_cb(uv_connect_t* req, int status) { int r; - ASSERT(status == 0); + ASSERT_OK(status); connect_cb_called++; r = uv_read_start((uv_stream_t*)&conn, alloc_cb, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); } static void write_cb(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); write_cb_called++; } static void shutdown_cb(uv_shutdown_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); shutdown_cb_called++; uv_close((uv_handle_t*)&conn, close_cb); } @@ -106,32 +106,32 @@ TEST_IMPL(tcp_shutdown_after_write) { uv_loop_t* loop; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); loop = uv_default_loop(); r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, timer_cb, 125, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_init(loop, &conn); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &conn, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(connect_cb_called == 1); - ASSERT(write_cb_called == 1); - ASSERT(shutdown_cb_called == 1); - ASSERT(conn_close_cb_called == 1); - ASSERT(timer_close_cb_called == 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, write_cb_called); + ASSERT_EQ(1, shutdown_cb_called); + ASSERT_EQ(1, conn_close_cb_called); + ASSERT_EQ(1, timer_close_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-tcp-try-write-error.c b/test/test-tcp-try-write-error.c index 97deccaa0dd..80a23ed7379 100644 --- a/test/test-tcp-try-write-error.c +++ b/test/test-tcp-try-write-error.c @@ -49,21 +49,21 @@ static void incoming_close_cb(uv_handle_t* handle) { r = uv_try_write((uv_stream_t*) &client, &buf, 1); fprintf(stderr, "uv_try_write error: %d %s\n", r, uv_strerror(r)); ASSERT(r == UV_EPIPE || r == UV_ECONNABORTED || r == UV_ECONNRESET); - ASSERT(client.write_queue_size == 0); + ASSERT_OK(client.write_queue_size); } static void connect_cb(uv_connect_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); connect_cb_called++; } static void connection_cb(uv_stream_t* tcp, int status) { - ASSERT(status == 0); + ASSERT_OK(status); - ASSERT(0 == uv_tcp_init(tcp->loop, &incoming)); - ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming)); + ASSERT_OK(uv_tcp_init(tcp->loop, &incoming)); + ASSERT_OK(uv_accept(tcp, (uv_stream_t*) &incoming)); connection_cb_called++; uv_close((uv_handle_t*) &incoming, incoming_close_cb); @@ -74,11 +74,11 @@ static void connection_cb(uv_stream_t* tcp, int status) { static void start_server(void) { struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); - ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); - ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &server)); + ASSERT_OK(uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_listen((uv_stream_t*) &server, 128, connection_cb)); } @@ -88,21 +88,21 @@ TEST_IMPL(tcp_try_write_error) { start_server(); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); - ASSERT(0 == uv_tcp_connect(&connect_req, - &client, - (struct sockaddr*) &addr, - connect_cb)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &client)); + ASSERT_OK(uv_tcp_connect(&connect_req, + &client, + (struct sockaddr*) &addr, + connect_cb)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); uv_close((uv_handle_t*) &client, close_cb); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(connect_cb_called == 1); - ASSERT(close_cb_called == 3); - ASSERT(connection_cb_called == 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(3, close_cb_called); + ASSERT_EQ(1, connection_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-try-write.c b/test/test-tcp-try-write.c index 6458857a85c..afb20ec7df6 100644 --- a/test/test-tcp-try-write.c +++ b/test/test-tcp-try-write.c @@ -46,7 +46,7 @@ static void close_cb(uv_handle_t* handle) { static void connect_cb(uv_connect_t* req, int status) { int r; uv_buf_t buf; - ASSERT(status == 0); + ASSERT_OK(status); connect_cb_called++; do { @@ -87,24 +87,24 @@ static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { static void connection_cb(uv_stream_t* tcp, int status) { - ASSERT(status == 0); + ASSERT_OK(status); - ASSERT(0 == uv_tcp_init(tcp->loop, &incoming)); - ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming)); + ASSERT_OK(uv_tcp_init(tcp->loop, &incoming)); + ASSERT_OK(uv_accept(tcp, (uv_stream_t*) &incoming)); connection_cb_called++; - ASSERT(0 == uv_read_start((uv_stream_t*) &incoming, alloc_cb, read_cb)); + ASSERT_OK(uv_read_start((uv_stream_t*) &incoming, alloc_cb, read_cb)); } static void start_server(void) { struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); - ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); - ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &server)); + ASSERT_OK(uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_listen((uv_stream_t*) &server, 128, connection_cb)); } @@ -114,21 +114,21 @@ TEST_IMPL(tcp_try_write) { start_server(); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); - ASSERT(0 == uv_tcp_connect(&connect_req, - &client, - (struct sockaddr*) &addr, - connect_cb)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &client)); + ASSERT_OK(uv_tcp_connect(&connect_req, + &client, + (struct sockaddr*) &addr, + connect_cb)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(connect_cb_called == 1); - ASSERT(close_cb_called == 3); - ASSERT(connection_cb_called == 1); - ASSERT(bytes_read == bytes_written); - ASSERT(bytes_written > 0); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(3, close_cb_called); + ASSERT_EQ(1, connection_cb_called); + ASSERT_EQ(bytes_read, bytes_written); + ASSERT_GT(bytes_written, 0); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-unexpected-read.c b/test/test-tcp-unexpected-read.c index e11f77473f4..aef7a2f75d2 100644 --- a/test/test-tcp-unexpected-read.c +++ b/test/test-tcp-unexpected-read.c @@ -60,14 +60,14 @@ static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { static void connect_cb(uv_connect_t* req, int status) { - ASSERT(req->handle == (uv_stream_t*) &client_handle); - ASSERT(0 == status); + ASSERT_PTR_EQ(req->handle, (uv_stream_t*) &client_handle); + ASSERT_OK(status); } static void write_cb(uv_write_t* req, int status) { - ASSERT(req->handle == (uv_stream_t*) &peer_handle); - ASSERT(0 == status); + ASSERT_PTR_EQ(req->handle, (uv_stream_t*) &peer_handle); + ASSERT_OK(status); } @@ -76,11 +76,11 @@ static void connection_cb(uv_stream_t* handle, int status) { buf = uv_buf_init("PING", 4); - ASSERT(0 == status); - ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle)); - ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb)); - ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &peer_handle, - &buf, 1, write_cb)); + ASSERT_OK(status); + ASSERT_OK(uv_accept(handle, (uv_stream_t*) &peer_handle)); + ASSERT_OK(uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb)); + ASSERT_OK(uv_write(&write_req, (uv_stream_t*) &peer_handle, + &buf, 1, write_cb)); } @@ -88,29 +88,29 @@ TEST_IMPL(tcp_unexpected_read) { struct sockaddr_in addr; uv_loop_t* loop; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); loop = uv_default_loop(); - ASSERT(0 == uv_timer_init(loop, &timer_handle)); - ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1000, 0)); - ASSERT(0 == uv_check_init(loop, &check_handle)); - ASSERT(0 == uv_check_start(&check_handle, check_cb)); - ASSERT(0 == uv_tcp_init(loop, &server_handle)); - ASSERT(0 == uv_tcp_init(loop, &client_handle)); - ASSERT(0 == uv_tcp_init(loop, &peer_handle)); - ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); - ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); - ASSERT(0 == uv_tcp_connect(&connect_req, - &client_handle, - (const struct sockaddr*) &addr, - connect_cb)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_timer_init(loop, &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, 1000, 0)); + ASSERT_OK(uv_check_init(loop, &check_handle)); + ASSERT_OK(uv_check_start(&check_handle, check_cb)); + ASSERT_OK(uv_tcp_init(loop, &server_handle)); + ASSERT_OK(uv_tcp_init(loop, &client_handle)); + ASSERT_OK(uv_tcp_init(loop, &peer_handle)); + ASSERT_OK(uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); + ASSERT_OK(uv_tcp_connect(&connect_req, + &client_handle, + (const struct sockaddr*) &addr, + connect_cb)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); /* This is somewhat inexact but the idea is that the event loop should not * start busy looping when the server sends a message and the client isn't * reading. */ - ASSERT(ticks <= 20); + ASSERT_LE(ticks, 20); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-tcp-write-after-connect.c b/test/test-tcp-write-after-connect.c index 4a786995ff1..63845bc4525 100644 --- a/test/test-tcp-write-after-connect.c +++ b/test/test-tcp-write-after-connect.c @@ -32,13 +32,13 @@ uv_buf_t buf = { "HELLO", 4 }; static void write_cb(uv_write_t *req, int status) { - ASSERT(status == UV_ECANCELED); + ASSERT_EQ(status, UV_ECANCELED); uv_close((uv_handle_t*) req->handle, NULL); } static void connect_cb(uv_connect_t *req, int status) { - ASSERT(status == UV_ECONNREFUSED); + ASSERT_EQ(status, UV_ECONNREFUSED); } @@ -49,20 +49,20 @@ TEST_IMPL(tcp_write_after_connect) { #endif struct sockaddr_in sa; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &sa)); - ASSERT(0 == uv_loop_init(&loop)); - ASSERT(0 == uv_tcp_init(&loop, &tcp_client)); - - ASSERT(0 == uv_tcp_connect(&connection_request, - &tcp_client, - (const struct sockaddr *) - &sa, - connect_cb)); - - ASSERT(0 == uv_write(&write_request, - (uv_stream_t *)&tcp_client, - &buf, 1, - write_cb)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &sa)); + ASSERT_OK(uv_loop_init(&loop)); + ASSERT_OK(uv_tcp_init(&loop, &tcp_client)); + + ASSERT_OK(uv_tcp_connect(&connection_request, + &tcp_client, + (const struct sockaddr *) + &sa, + connect_cb)); + + ASSERT_OK(uv_write(&write_request, + (uv_stream_t *)&tcp_client, + &buf, 1, + write_cb)); uv_run(&loop, UV_RUN_DEFAULT); diff --git a/test/test-tcp-write-fail.c b/test/test-tcp-write-fail.c index 2912e7c5068..530329a3ac6 100644 --- a/test/test-tcp-write-fail.c +++ b/test/test-tcp-write-fail.c @@ -41,13 +41,13 @@ static void close_socket(uv_tcp_t* sock) { int r; r = uv_fileno((uv_handle_t*)sock, &fd); - ASSERT(r == 0); + ASSERT_OK(r); #ifdef _WIN32 r = closesocket((uv_os_sock_t)fd); #else r = close(fd); #endif - ASSERT(r == 0); + ASSERT_OK(r); } @@ -60,7 +60,7 @@ static void close_cb(uv_handle_t* handle) { static void write_cb(uv_write_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status != 0); + ASSERT(status); fprintf(stderr, "uv_write error: %s\n", uv_strerror(status)); write_cb_called++; @@ -73,8 +73,8 @@ static void connect_cb(uv_connect_t* req, int status) { uv_stream_t* stream; int r; - ASSERT(req == &connect_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &connect_req); + ASSERT_OK(status); stream = req->handle; connect_cb_called++; @@ -84,7 +84,7 @@ static void connect_cb(uv_connect_t* req, int status) { buf = uv_buf_init("hello\n", 6); r = uv_write(&write_req, stream, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -93,22 +93,22 @@ TEST_IMPL(tcp_write_fail) { uv_tcp_t client; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &client, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(connect_cb_called == 1); - ASSERT(write_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, write_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-write-in-a-row.c b/test/test-tcp-write-in-a-row.c index 99f4dee125e..89304eb5a34 100644 --- a/test/test-tcp-write-in-a-row.c +++ b/test/test-tcp-write-in-a-row.c @@ -45,7 +45,7 @@ static void close_cb(uv_handle_t* handle) { static void write_cb(uv_write_t* w, int status) { /* the small write should finish immediately after the big write */ - ASSERT_EQ(0, uv_stream_get_write_queue_size((uv_stream_t*) &client)); + ASSERT_OK(uv_stream_get_write_queue_size((uv_stream_t*) &client)); write_cb_called++; @@ -62,13 +62,13 @@ static void connect_cb(uv_connect_t* _, int status) { uv_buf_t buf; size_t write_queue_size0, write_queue_size1; - ASSERT_EQ(0, status); + ASSERT_OK(status); connect_cb_called++; /* fire a big write */ buf = uv_buf_init(data, sizeof(data)); r = uv_write(&small_write, (uv_stream_t*) &client, &buf, 1, write_cb); - ASSERT_EQ(0, r); + ASSERT_OK(r); /* check that the write process gets stuck */ write_queue_size0 = uv_stream_get_write_queue_size((uv_stream_t*) &client); @@ -77,7 +77,7 @@ static void connect_cb(uv_connect_t* _, int status) { /* fire a small write, which should be queued */ buf = uv_buf_init("A", 1); r = uv_write(&big_write, (uv_stream_t*) &client, &buf, 1, write_cb); - ASSERT_EQ(0, r); + ASSERT_OK(r); write_queue_size1 = uv_stream_get_write_queue_size((uv_stream_t*) &client); ASSERT_EQ(write_queue_size1, write_queue_size0 + 1); @@ -93,22 +93,22 @@ static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {} static void connection_cb(uv_stream_t* tcp, int status) { - ASSERT_EQ(0, status); + ASSERT_OK(status); connection_cb_called++; - ASSERT_EQ(0, uv_tcp_init(tcp->loop, &incoming)); - ASSERT_EQ(0, uv_accept(tcp, (uv_stream_t*) &incoming)); - ASSERT_EQ(0, uv_read_start((uv_stream_t*) &incoming, alloc_cb, read_cb)); + ASSERT_OK(uv_tcp_init(tcp->loop, &incoming)); + ASSERT_OK(uv_accept(tcp, (uv_stream_t*) &incoming)); + ASSERT_OK(uv_read_start((uv_stream_t*) &incoming, alloc_cb, read_cb)); } static void start_server(void) { struct sockaddr_in addr; - ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); - ASSERT_EQ(0, uv_tcp_init(uv_default_loop(), &server)); - ASSERT_EQ(0, uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); - ASSERT_EQ(0, uv_listen((uv_stream_t*) &server, 128, connection_cb)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &server)); + ASSERT_OK(uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_listen((uv_stream_t*) &server, 128, connection_cb)); } TEST_IMPL(tcp_write_in_a_row) { @@ -121,15 +121,15 @@ TEST_IMPL(tcp_write_in_a_row) { start_server(); - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT_EQ(0, uv_tcp_init(uv_default_loop(), &client)); - ASSERT_EQ(0, uv_tcp_connect(&connect_req, - &client, - (struct sockaddr*) &addr, - connect_cb)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &client)); + ASSERT_OK(uv_tcp_connect(&connect_req, + &client, + (struct sockaddr*) &addr, + connect_cb)); - ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT_EQ(1, connect_cb_called); ASSERT_EQ(3, close_cb_called); diff --git a/test/test-tcp-write-queue-order.c b/test/test-tcp-write-queue-order.c index 7562c41d3de..e838c88a6a2 100644 --- a/test/test-tcp-write-queue-order.c +++ b/test/test-tcp-write-queue-order.c @@ -67,7 +67,7 @@ static void connect_cb(uv_connect_t* req, int status) { int i; uv_buf_t buf; - ASSERT(status == 0); + ASSERT_OK(status); connect_cb_called++; buf = uv_buf_init(base, sizeof(base)); @@ -78,19 +78,19 @@ static void connect_cb(uv_connect_t* req, int status) { &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); } } static void connection_cb(uv_stream_t* tcp, int status) { - ASSERT(status == 0); + ASSERT_OK(status); - ASSERT(0 == uv_tcp_init(tcp->loop, &incoming)); - ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming)); + ASSERT_OK(uv_tcp_init(tcp->loop, &incoming)); + ASSERT_OK(uv_accept(tcp, (uv_stream_t*) &incoming)); - ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); - ASSERT(0 == uv_timer_start(&timer, timer_cb, 1000, 0)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer)); + ASSERT_OK(uv_timer_start(&timer, timer_cb, 1000, 0)); connection_cb_called++; } @@ -99,11 +99,11 @@ static void connection_cb(uv_stream_t* tcp, int status) { static void start_server(void) { struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); - ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); - ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); - ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb)); + ASSERT_OK(uv_tcp_init(uv_default_loop(), &server)); + ASSERT_OK(uv_tcp_bind(&server, (struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_listen((uv_stream_t*) &server, 128, connection_cb)); } @@ -114,25 +114,25 @@ TEST_IMPL(tcp_write_queue_order) { start_server(); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - - ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); - ASSERT(0 == uv_tcp_connect(&connect_req, - &client, - (struct sockaddr*) &addr, - connect_cb)); - ASSERT(0 == uv_send_buffer_size((uv_handle_t*) &client, &buffer_size)); - - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - - ASSERT(connect_cb_called == 1); - ASSERT(connection_cb_called == 1); - ASSERT(write_callbacks > 0); - ASSERT(write_cancelled_callbacks > 0); - ASSERT(write_callbacks + - write_error_callbacks + - write_cancelled_callbacks == REQ_COUNT); - ASSERT(close_cb_called == 3); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT_OK(uv_tcp_init(uv_default_loop(), &client)); + ASSERT_OK(uv_tcp_connect(&connect_req, + &client, + (struct sockaddr*) &addr, + connect_cb)); + ASSERT_OK(uv_send_buffer_size((uv_handle_t*) &client, &buffer_size)); + + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, connection_cb_called); + ASSERT_GT(write_callbacks, 0); + ASSERT_GT(write_cancelled_callbacks, 0); + ASSERT_EQ(write_callbacks + + write_error_callbacks + + write_cancelled_callbacks, REQ_COUNT); + ASSERT_EQ(3, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tcp-write-to-half-open-connection.c b/test/test-tcp-write-to-half-open-connection.c index 8978211d2b7..2b2f5644e17 100644 --- a/test/test-tcp-write-to-half-open-connection.c +++ b/test/test-tcp-write-to-half-open-connection.c @@ -45,23 +45,23 @@ static void connection_cb(uv_stream_t* server, int status) { int r; uv_buf_t buf; - ASSERT(server == (uv_stream_t*)&tcp_server); - ASSERT(status == 0); + ASSERT_PTR_EQ(server, (uv_stream_t*)&tcp_server); + ASSERT_OK(status); r = uv_tcp_init(server->loop, &tcp_peer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_accept(server, (uv_stream_t*)&tcp_peer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*)&tcp_peer, alloc_cb, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); buf.base = "hello\n"; buf.len = 6; r = uv_write(&write_req, (uv_stream_t*)&tcp_peer, &buf, 1, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -88,8 +88,8 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { static void connect_cb(uv_connect_t* req, int status) { - ASSERT(req == &connect_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &connect_req); + ASSERT_OK(status); /* Close the client. */ uv_close((uv_handle_t*)&tcp_client, NULL); @@ -97,7 +97,7 @@ static void connect_cb(uv_connect_t* req, int status) { static void write_cb(uv_write_t* req, int status) { - ASSERT(status == 0); + ASSERT_OK(status); write_cb_called++; } @@ -107,34 +107,34 @@ TEST_IMPL(tcp_write_to_half_open_connection) { uv_loop_t* loop; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); loop = uv_default_loop(); ASSERT_NOT_NULL(loop); r = uv_tcp_init(loop, &tcp_server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_listen((uv_stream_t*)&tcp_server, 1, connection_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_init(loop, &tcp_client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &tcp_client, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(write_cb_called > 0); - ASSERT(read_cb_called > 0); + ASSERT_GT(write_cb_called, 0); + ASSERT_GT(read_cb_called, 0); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-tcp-writealot.c b/test/test-tcp-writealot.c index 3c6c149e92c..ebafb179632 100644 --- a/test/test-tcp-writealot.c +++ b/test/test-tcp-writealot.c @@ -65,19 +65,19 @@ static void close_cb(uv_handle_t* handle) { static void shutdown_cb(uv_shutdown_t* req, int status) { uv_tcp_t* tcp; - ASSERT(req == &shutdown_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &shutdown_req); + ASSERT_OK(status); tcp = (uv_tcp_t*)(req->handle); /* The write buffer should be empty by now. */ - ASSERT(tcp->write_queue_size == 0); + ASSERT_OK(tcp->write_queue_size); /* Now we wait for the EOF */ shutdown_cb_called++; /* We should have had all the writes called already. */ - ASSERT(write_cb_called == WRITES); + ASSERT_EQ(write_cb_called, WRITES); } @@ -88,7 +88,7 @@ static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { bytes_received_done += nread; } else { - ASSERT(nread == UV_EOF); + ASSERT_EQ(nread, UV_EOF); printf("GOT EOF\n"); uv_close((uv_handle_t*)tcp, close_cb); } @@ -115,8 +115,8 @@ static void connect_cb(uv_connect_t* req, int status) { uv_stream_t* stream; int i, j, r; - ASSERT(req == &connect_req); - ASSERT(status == 0); + ASSERT_PTR_EQ(req, &connect_req); + ASSERT_OK(status); stream = req->handle; connect_cb_called++; @@ -131,16 +131,16 @@ static void connect_cb(uv_connect_t* req, int status) { } r = uv_write(write_req, stream, send_bufs, CHUNKS_PER_WRITE, write_cb); - ASSERT(r == 0); + ASSERT_OK(r); } /* Shutdown on drain. */ r = uv_shutdown(&shutdown_req, stream, shutdown_cb); - ASSERT(r == 0); + ASSERT_OK(r); /* Start reading */ r = uv_read_start(stream, alloc_cb, read_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -153,29 +153,29 @@ TEST_IMPL(tcp_writealot) { RETURN_SKIP("Test is too slow to run under ThreadSanitizer"); #endif - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); send_buffer = calloc(1, TOTAL_BYTES); ASSERT_NOT_NULL(send_buffer); r = uv_tcp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tcp_connect(&connect_req, &client, (const struct sockaddr*) &addr, connect_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(shutdown_cb_called == 1); - ASSERT(connect_cb_called == 1); - ASSERT(write_cb_called == WRITES); - ASSERT(close_cb_called == 1); - ASSERT(bytes_sent == TOTAL_BYTES); - ASSERT(bytes_sent_done == TOTAL_BYTES); - ASSERT(bytes_received_done == TOTAL_BYTES); + ASSERT_EQ(1, shutdown_cb_called); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(write_cb_called, WRITES); + ASSERT_EQ(1, close_cb_called); + ASSERT_EQ(bytes_sent, TOTAL_BYTES); + ASSERT_EQ(bytes_sent_done, TOTAL_BYTES); + ASSERT_EQ(bytes_received_done, TOTAL_BYTES); free(send_buffer); diff --git a/test/test-thread-affinity.c b/test/test-thread-affinity.c index 239dce3cbc4..d21487d9937 100644 --- a/test/test-thread-affinity.c +++ b/test/test-thread-affinity.c @@ -34,12 +34,12 @@ static void check_affinity(void* arg) { cpumask = (char*)arg; cpumasksize = uv_cpumask_size(); - ASSERT(cpumasksize > 0); + ASSERT_GT(cpumasksize, 0); tid = uv_thread_self(); r = uv_thread_setaffinity(&tid, cpumask, NULL, cpumasksize); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_thread_setaffinity(&tid, cpumask + cpumasksize, cpumask, cpumasksize); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -63,13 +63,13 @@ TEST_IMPL(thread_affinity) { threads[0] = uv_thread_self(); #endif cpumasksize = uv_cpumask_size(); - ASSERT(cpumasksize > 0); + ASSERT_GT(cpumasksize, 0); cpumask = calloc(4 * cpumasksize, 1); ASSERT(cpumask); r = uv_thread_getaffinity(&threads[0], cpumask, cpumasksize); - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(cpumask[0] && "test must be run with cpu 0 affinity"); ncpus = 0; while (cpumask[++ncpus]) { } @@ -100,24 +100,24 @@ TEST_IMPL(thread_affinity) { } #endif - ASSERT(0 == uv_thread_create(threads + 1, - check_affinity, - &cpumask[t1first])); - ASSERT(0 == uv_thread_create(threads + 2, - check_affinity, - &cpumask[t2first])); - ASSERT(0 == uv_thread_join(threads + 1)); - ASSERT(0 == uv_thread_join(threads + 2)); + ASSERT_OK(uv_thread_create(threads + 1, + check_affinity, + &cpumask[t1first])); + ASSERT_OK(uv_thread_create(threads + 2, + check_affinity, + &cpumask[t2first])); + ASSERT_OK(uv_thread_join(threads + 1)); + ASSERT_OK(uv_thread_join(threads + 2)); ASSERT(cpumask[t1first + 0] == (ncpus == 1)); ASSERT(cpumask[t1first + 1] == (ncpus >= 2)); - ASSERT(cpumask[t1first + 2] == 0); + ASSERT_OK(cpumask[t1first + 2]); ASSERT(cpumask[t1first + 3] == (ncpus >= 4)); - ASSERT(cpumask[t2first + 0] == 1); - ASSERT(cpumask[t2first + 1] == 0); + ASSERT_EQ(1, cpumask[t2first + 0]); + ASSERT_OK(cpumask[t2first + 1]); ASSERT(cpumask[t2first + 2] == (ncpus >= 3)); - ASSERT(cpumask[t2first + 3] == 0); + ASSERT_OK(cpumask[t2first + 3]); c = uv_thread_getcpu(); ASSERT_GE(c, 0); @@ -125,16 +125,16 @@ TEST_IMPL(thread_affinity) { memset(cpumask, 0, cpumasksize); cpumask[c] = 1; r = uv_thread_setaffinity(&threads[0], cpumask, NULL, cpumasksize); - ASSERT_EQ(r, 0); + ASSERT_OK(r); memset(cpumask, 0, cpumasksize); r = uv_thread_getaffinity(&threads[0], cpumask, cpumasksize); - ASSERT_EQ(r, 0); + ASSERT_OK(r); for (i = 0; i < cpumasksize; i++) { if (i == c) ASSERT_EQ(1, cpumask[i]); else - ASSERT_EQ(0, cpumask[i]); + ASSERT_OK(cpumask[i]); } free(cpumask); @@ -147,7 +147,7 @@ TEST_IMPL(thread_affinity) { TEST_IMPL(thread_affinity) { int cpumasksize; cpumasksize = uv_cpumask_size(); - ASSERT(cpumasksize == UV_ENOTSUP); + ASSERT_EQ(cpumasksize, UV_ENOTSUP); return 0; } diff --git a/test/test-thread-equal.c b/test/test-thread-equal.c index f7bde71b3d9..3b2ba8df443 100644 --- a/test/test-thread-equal.c +++ b/test/test-thread-equal.c @@ -31,7 +31,7 @@ static void check_thread(void* arg) { #ifdef _WIN32 ASSERT_NOT_NULL(self_id); #endif - ASSERT(uv_thread_equal(&main_thread_id, &self_id) == 0); + ASSERT_OK(uv_thread_equal(&main_thread_id, &self_id)); *thread_id = uv_thread_self(); } @@ -41,11 +41,11 @@ TEST_IMPL(thread_equal) { #ifdef _WIN32 ASSERT_NOT_NULL(main_thread_id); #endif - ASSERT(0 != uv_thread_equal(&main_thread_id, &main_thread_id)); - ASSERT(0 == uv_thread_create(threads + 0, check_thread, subthreads + 0)); - ASSERT(0 == uv_thread_create(threads + 1, check_thread, subthreads + 1)); - ASSERT(0 == uv_thread_join(threads + 0)); - ASSERT(0 == uv_thread_join(threads + 1)); - ASSERT(0 == uv_thread_equal(subthreads + 0, subthreads + 1)); + ASSERT_NE(0, uv_thread_equal(&main_thread_id, &main_thread_id)); + ASSERT_OK(uv_thread_create(threads + 0, check_thread, subthreads + 0)); + ASSERT_OK(uv_thread_create(threads + 1, check_thread, subthreads + 1)); + ASSERT_OK(uv_thread_join(threads + 0)); + ASSERT_OK(uv_thread_join(threads + 1)); + ASSERT_OK(uv_thread_equal(subthreads + 0, subthreads + 1)); return 0; } diff --git a/test/test-thread.c b/test/test-thread.c index 82f80833ab1..449dce14338 100644 --- a/test/test-thread.c +++ b/test/test-thread.c @@ -71,7 +71,7 @@ static void getaddrinfo_do(struct getaddrinfo_req* req) { "localhost", NULL, NULL); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -80,7 +80,7 @@ static void getaddrinfo_cb(uv_getaddrinfo_t* handle, struct addrinfo* res) { struct getaddrinfo_req* req; - ASSERT(status == 0); + ASSERT_OK(status); req = container_of(handle, struct getaddrinfo_req, handle); uv_freeaddrinfo(res); @@ -94,7 +94,7 @@ static void fs_do(struct fs_req* req) { int r; r = uv_fs_stat(req->loop, &req->handle, ".", fs_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -115,7 +115,7 @@ static void do_work(void* arg) { size_t i; struct test_thread* thread = arg; - ASSERT(0 == uv_loop_init(&loop)); + ASSERT_OK(uv_loop_init(&loop)); for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) { struct getaddrinfo_req* req = getaddrinfo_reqs + i; @@ -131,14 +131,14 @@ static void do_work(void* arg) { fs_do(req); } - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); - ASSERT(0 == uv_loop_close(&loop)); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_loop_close(&loop)); thread->thread_called = 1; } static void thread_entry(void* arg) { - ASSERT(arg == (void *) 42); + ASSERT_PTR_EQ(arg, (void *) 42); thread_called++; } @@ -148,12 +148,12 @@ TEST_IMPL(thread_create) { int r; r = uv_thread_create(&tid, thread_entry, (void *) 42); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_thread_join(&tid); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(thread_called == 1); + ASSERT_EQ(1, thread_called); return 0; } @@ -176,13 +176,13 @@ TEST_IMPL(threadpool_multiple_event_loops) { for (i = 0; i < ARRAY_SIZE(threads); i++) { r = uv_thread_create(&threads[i].thread_id, do_work, &threads[i]); - ASSERT(r == 0); + ASSERT_OK(r); } for (i = 0; i < ARRAY_SIZE(threads); i++) { r = uv_thread_join(&threads[i].thread_id); - ASSERT(r == 0); - ASSERT(threads[i].thread_called == 1); + ASSERT_OK(r); + ASSERT_EQ(1, threads[i].thread_called); } return 0; @@ -192,7 +192,7 @@ TEST_IMPL(threadpool_multiple_event_loops) { static void tls_thread(void* arg) { ASSERT_NULL(uv_key_get(&tls_key)); uv_key_set(&tls_key, arg); - ASSERT(arg == uv_key_get(&tls_key)); + ASSERT_EQ(arg, uv_key_get(&tls_key)); uv_key_set(&tls_key, NULL); ASSERT_NULL(uv_key_get(&tls_key)); } @@ -201,14 +201,14 @@ static void tls_thread(void* arg) { TEST_IMPL(thread_local_storage) { char name[] = "main"; uv_thread_t threads[2]; - ASSERT(0 == uv_key_create(&tls_key)); + ASSERT_OK(uv_key_create(&tls_key)); ASSERT_NULL(uv_key_get(&tls_key)); uv_key_set(&tls_key, name); - ASSERT(name == uv_key_get(&tls_key)); - ASSERT(0 == uv_thread_create(threads + 0, tls_thread, threads + 0)); - ASSERT(0 == uv_thread_create(threads + 1, tls_thread, threads + 1)); - ASSERT(0 == uv_thread_join(threads + 0)); - ASSERT(0 == uv_thread_join(threads + 1)); + ASSERT_EQ(name, uv_key_get(&tls_key)); + ASSERT_OK(uv_thread_create(threads + 0, tls_thread, threads + 0)); + ASSERT_OK(uv_thread_create(threads + 1, tls_thread, threads + 1)); + ASSERT_OK(uv_thread_join(threads + 0)); + ASSERT_OK(uv_thread_join(threads + 1)); uv_key_delete(&tls_key); return 0; } @@ -222,30 +222,30 @@ static void thread_check_stack(void* arg) { * on MacOS. */ if (expected == 0) expected = 512 * 1024; - ASSERT(pthread_get_stacksize_np(pthread_self()) >= expected); + ASSERT_GE(pthread_get_stacksize_np(pthread_self()), expected); #elif defined(__linux__) && defined(__GLIBC__) size_t expected; struct rlimit lim; size_t stack_size; pthread_attr_t attr; - ASSERT(0 == getrlimit(RLIMIT_STACK, &lim)); + ASSERT_OK(getrlimit(RLIMIT_STACK, &lim)); if (lim.rlim_cur == RLIM_INFINITY) lim.rlim_cur = 2 << 20; /* glibc default. */ - ASSERT(0 == pthread_getattr_np(pthread_self(), &attr)); - ASSERT(0 == pthread_attr_getstacksize(&attr, &stack_size)); + ASSERT_OK(pthread_getattr_np(pthread_self(), &attr)); + ASSERT_OK(pthread_attr_getstacksize(&attr, &stack_size)); expected = arg == NULL ? 0 : ((uv_thread_options_t*)arg)->stack_size; if (expected == 0) expected = (size_t)lim.rlim_cur; - ASSERT(stack_size >= expected); - ASSERT(0 == pthread_attr_destroy(&attr)); + ASSERT_GE(stack_size, expected); + ASSERT_OK(pthread_attr_destroy(&attr)); #endif } TEST_IMPL(thread_stack_size) { uv_thread_t thread; - ASSERT(0 == uv_thread_create(&thread, thread_check_stack, NULL)); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_create(&thread, thread_check_stack, NULL)); + ASSERT_OK(uv_thread_join(&thread)); return 0; } @@ -255,42 +255,42 @@ TEST_IMPL(thread_stack_size_explicit) { options.flags = UV_THREAD_HAS_STACK_SIZE; options.stack_size = 1024 * 1024; - ASSERT(0 == uv_thread_create_ex(&thread, &options, - thread_check_stack, &options)); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_create_ex(&thread, &options, + thread_check_stack, &options)); + ASSERT_OK(uv_thread_join(&thread)); options.stack_size = 8 * 1024 * 1024; /* larger than most default os sizes */ - ASSERT(0 == uv_thread_create_ex(&thread, &options, - thread_check_stack, &options)); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_create_ex(&thread, &options, + thread_check_stack, &options)); + ASSERT_OK(uv_thread_join(&thread)); options.stack_size = 0; - ASSERT(0 == uv_thread_create_ex(&thread, &options, - thread_check_stack, &options)); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_create_ex(&thread, &options, + thread_check_stack, &options)); + ASSERT_OK(uv_thread_join(&thread)); options.stack_size = 42; - ASSERT(0 == uv_thread_create_ex(&thread, &options, - thread_check_stack, &options)); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_create_ex(&thread, &options, + thread_check_stack, &options)); + ASSERT_OK(uv_thread_join(&thread)); #ifdef PTHREAD_STACK_MIN options.stack_size = PTHREAD_STACK_MIN - 42; /* unaligned size */ - ASSERT(0 == uv_thread_create_ex(&thread, &options, - thread_check_stack, &options)); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_create_ex(&thread, &options, + thread_check_stack, &options)); + ASSERT_OK(uv_thread_join(&thread)); options.stack_size = PTHREAD_STACK_MIN / 2 - 42; /* unaligned size */ - ASSERT(0 == uv_thread_create_ex(&thread, &options, - thread_check_stack, &options)); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_create_ex(&thread, &options, + thread_check_stack, &options)); + ASSERT_OK(uv_thread_join(&thread)); #endif /* unaligned size, should be larger than PTHREAD_STACK_MIN */ options.stack_size = 1234567; - ASSERT(0 == uv_thread_create_ex(&thread, &options, - thread_check_stack, &options)); - ASSERT(0 == uv_thread_join(&thread)); + ASSERT_OK(uv_thread_create_ex(&thread, &options, + thread_check_stack, &options)); + ASSERT_OK(uv_thread_join(&thread)); return 0; } diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index fed0b07a3ca..b758ac4f6b6 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -73,8 +73,8 @@ static void saturate_threadpool(void) { loop = uv_default_loop(); for (i = 0; i < ARRAY_SIZE(pause_reqs); i += 1) { - ASSERT(0 == uv_sem_init(pause_sems + i, 0)); - ASSERT(0 == uv_queue_work(loop, pause_reqs + i, work_cb, done_cb)); + ASSERT_OK(uv_sem_init(pause_sems + i, 0)); + ASSERT_OK(uv_queue_work(loop, pause_reqs + i, work_cb, done_cb)); } } @@ -119,7 +119,8 @@ static int known_broken(uv_req_t* req) { static void fs_cb(uv_fs_t* req) { - ASSERT(known_broken((uv_req_t*) req) || req->result == UV_ECANCELED); + ASSERT_NE(known_broken((uv_req_t*) req) || \ + req->result == UV_ECANCELED, 0); uv_fs_req_cleanup(req); fs_cb_called++; } @@ -128,7 +129,7 @@ static void fs_cb(uv_fs_t* req) { static void getaddrinfo_cb(uv_getaddrinfo_t* req, int status, struct addrinfo* res) { - ASSERT(status == UV_EAI_CANCELED); + ASSERT_EQ(status, UV_EAI_CANCELED); ASSERT_NULL(res); uv_freeaddrinfo(res); /* Should not crash. */ } @@ -138,7 +139,7 @@ static void getnameinfo_cb(uv_getnameinfo_t* handle, int status, const char* hostname, const char* service) { - ASSERT(status == UV_EAI_CANCELED); + ASSERT_EQ(status, UV_EAI_CANCELED); ASSERT_NULL(hostname); ASSERT_NULL(service); } @@ -150,7 +151,7 @@ static void work2_cb(uv_work_t* req) { static void done2_cb(uv_work_t* req, int status) { - ASSERT(status == UV_ECANCELED); + ASSERT_EQ(status, UV_ECANCELED); done2_cb_called++; } @@ -174,7 +175,7 @@ static void timer_cb(uv_timer_t* handle) { static void nop_done_cb(uv_work_t* req, int status) { - ASSERT(status == UV_ECANCELED); + ASSERT_EQ(status, UV_ECANCELED); done_cb_called++; } @@ -184,9 +185,9 @@ static void nop_random_cb(uv_random_t* req, int status, void* buf, size_t len) { ri = container_of(req, struct random_info, random_req); - ASSERT(status == UV_ECANCELED); - ASSERT(buf == (void*) ri->buf); - ASSERT(len == sizeof(ri->buf)); + ASSERT_EQ(status, UV_ECANCELED); + ASSERT_PTR_EQ(buf, (void*) ri->buf); + ASSERT_EQ(len, sizeof(ri->buf)); done_cb_called++; } @@ -204,21 +205,21 @@ TEST_IMPL(threadpool_cancel_getaddrinfo) { saturate_threadpool(); r = uv_getaddrinfo(loop, reqs + 0, getaddrinfo_cb, "fail", NULL, NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_getaddrinfo(loop, reqs + 1, getaddrinfo_cb, NULL, "fail", NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_getaddrinfo(loop, reqs + 2, getaddrinfo_cb, "fail", "fail", NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_getaddrinfo(loop, reqs + 3, getaddrinfo_cb, "fail", NULL, &hints); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_timer_init(loop, &ci.timer_handle)); - ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(1 == timer_cb_called); + ASSERT_OK(uv_timer_init(loop, &ci.timer_handle)); + ASSERT_OK(uv_timer_start(&ci.timer_handle, timer_cb, 10, 0)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, timer_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -233,28 +234,28 @@ TEST_IMPL(threadpool_cancel_getnameinfo) { int r; r = uv_ip4_addr("127.0.0.1", 80, &addr4); - ASSERT(r == 0); + ASSERT_OK(r); INIT_CANCEL_INFO(&ci, reqs); loop = uv_default_loop(); saturate_threadpool(); r = uv_getnameinfo(loop, reqs + 0, getnameinfo_cb, (const struct sockaddr*)&addr4, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_getnameinfo(loop, reqs + 1, getnameinfo_cb, (const struct sockaddr*)&addr4, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_getnameinfo(loop, reqs + 2, getnameinfo_cb, (const struct sockaddr*)&addr4, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_getnameinfo(loop, reqs + 3, getnameinfo_cb, (const struct sockaddr*)&addr4, 0); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_timer_init(loop, &ci.timer_handle)); - ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(1 == timer_cb_called); + ASSERT_OK(uv_timer_init(loop, &ci.timer_handle)); + ASSERT_OK(uv_timer_start(&ci.timer_handle, timer_cb, 10, 0)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, timer_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -267,17 +268,17 @@ TEST_IMPL(threadpool_cancel_random) { saturate_threadpool(); loop = uv_default_loop(); - ASSERT(0 == uv_random(loop, - &req.random_req, - &req.buf, - sizeof(req.buf), - 0, - nop_random_cb)); - ASSERT(0 == uv_cancel((uv_req_t*) &req)); - ASSERT(0 == done_cb_called); + ASSERT_OK(uv_random(loop, + &req.random_req, + &req.buf, + sizeof(req.buf), + 0, + nop_random_cb)); + ASSERT_OK(uv_cancel((uv_req_t*) &req)); + ASSERT_OK(done_cb_called); unblock_threadpool(); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(1 == done_cb_called); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, done_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -295,13 +296,13 @@ TEST_IMPL(threadpool_cancel_work) { saturate_threadpool(); for (i = 0; i < ARRAY_SIZE(reqs); i++) - ASSERT(0 == uv_queue_work(loop, reqs + i, work2_cb, done2_cb)); + ASSERT_OK(uv_queue_work(loop, reqs + i, work2_cb, done2_cb)); - ASSERT(0 == uv_timer_init(loop, &ci.timer_handle)); - ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(1 == timer_cb_called); - ASSERT(ARRAY_SIZE(reqs) == done2_cb_called); + ASSERT_OK(uv_timer_init(loop, &ci.timer_handle)); + ASSERT_OK(uv_timer_start(&ci.timer_handle, timer_cb, 10, 0)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, timer_cb_called); + ASSERT_EQ(ARRAY_SIZE(reqs), done2_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -322,39 +323,39 @@ TEST_IMPL(threadpool_cancel_fs) { /* Needs to match ARRAY_SIZE(fs_reqs). */ n = 0; - ASSERT(0 == uv_fs_chmod(loop, reqs + n++, "/", 0, fs_cb)); - ASSERT(0 == uv_fs_chown(loop, reqs + n++, "/", 0, 0, fs_cb)); - ASSERT(0 == uv_fs_close(loop, reqs + n++, 0, fs_cb)); - ASSERT(0 == uv_fs_fchmod(loop, reqs + n++, 0, 0, fs_cb)); - ASSERT(0 == uv_fs_fchown(loop, reqs + n++, 0, 0, 0, fs_cb)); - ASSERT(0 == uv_fs_fdatasync(loop, reqs + n++, 0, fs_cb)); - ASSERT(0 == uv_fs_fstat(loop, reqs + n++, 0, fs_cb)); - ASSERT(0 == uv_fs_fsync(loop, reqs + n++, 0, fs_cb)); - ASSERT(0 == uv_fs_ftruncate(loop, reqs + n++, 0, 0, fs_cb)); - ASSERT(0 == uv_fs_futime(loop, reqs + n++, 0, 0, 0, fs_cb)); - ASSERT(0 == uv_fs_link(loop, reqs + n++, "/", "/", fs_cb)); - ASSERT(0 == uv_fs_lstat(loop, reqs + n++, "/", fs_cb)); - ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb)); - ASSERT(0 == uv_fs_open(loop, reqs + n++, "/", 0, 0, fs_cb)); - ASSERT(0 == uv_fs_read(loop, reqs + n++, -1, &iov, 1, 0, fs_cb)); - ASSERT(0 == uv_fs_scandir(loop, reqs + n++, "/", 0, fs_cb)); - ASSERT(0 == uv_fs_readlink(loop, reqs + n++, "/", fs_cb)); - ASSERT(0 == uv_fs_realpath(loop, reqs + n++, "/", fs_cb)); - ASSERT(0 == uv_fs_rename(loop, reqs + n++, "/", "/", fs_cb)); - ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb)); - ASSERT(0 == uv_fs_sendfile(loop, reqs + n++, 0, 0, 0, 0, fs_cb)); - ASSERT(0 == uv_fs_stat(loop, reqs + n++, "/", fs_cb)); - ASSERT(0 == uv_fs_symlink(loop, reqs + n++, "/", "/", 0, fs_cb)); - ASSERT(0 == uv_fs_unlink(loop, reqs + n++, "/", fs_cb)); - ASSERT(0 == uv_fs_utime(loop, reqs + n++, "/", 0, 0, fs_cb)); - ASSERT(0 == uv_fs_write(loop, reqs + n++, -1, &iov, 1, 0, fs_cb)); - ASSERT(n == ARRAY_SIZE(reqs)); - - ASSERT(0 == uv_timer_init(loop, &ci.timer_handle)); - ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(n == fs_cb_called); - ASSERT(1 == timer_cb_called); + ASSERT_OK(uv_fs_chmod(loop, reqs + n++, "/", 0, fs_cb)); + ASSERT_OK(uv_fs_chown(loop, reqs + n++, "/", 0, 0, fs_cb)); + ASSERT_OK(uv_fs_close(loop, reqs + n++, 0, fs_cb)); + ASSERT_OK(uv_fs_fchmod(loop, reqs + n++, 0, 0, fs_cb)); + ASSERT_OK(uv_fs_fchown(loop, reqs + n++, 0, 0, 0, fs_cb)); + ASSERT_OK(uv_fs_fdatasync(loop, reqs + n++, 0, fs_cb)); + ASSERT_OK(uv_fs_fstat(loop, reqs + n++, 0, fs_cb)); + ASSERT_OK(uv_fs_fsync(loop, reqs + n++, 0, fs_cb)); + ASSERT_OK(uv_fs_ftruncate(loop, reqs + n++, 0, 0, fs_cb)); + ASSERT_OK(uv_fs_futime(loop, reqs + n++, 0, 0, 0, fs_cb)); + ASSERT_OK(uv_fs_link(loop, reqs + n++, "/", "/", fs_cb)); + ASSERT_OK(uv_fs_lstat(loop, reqs + n++, "/", fs_cb)); + ASSERT_OK(uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb)); + ASSERT_OK(uv_fs_open(loop, reqs + n++, "/", 0, 0, fs_cb)); + ASSERT_OK(uv_fs_read(loop, reqs + n++, -1, &iov, 1, 0, fs_cb)); + ASSERT_OK(uv_fs_scandir(loop, reqs + n++, "/", 0, fs_cb)); + ASSERT_OK(uv_fs_readlink(loop, reqs + n++, "/", fs_cb)); + ASSERT_OK(uv_fs_realpath(loop, reqs + n++, "/", fs_cb)); + ASSERT_OK(uv_fs_rename(loop, reqs + n++, "/", "/", fs_cb)); + ASSERT_OK(uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb)); + ASSERT_OK(uv_fs_sendfile(loop, reqs + n++, 0, 0, 0, 0, fs_cb)); + ASSERT_OK(uv_fs_stat(loop, reqs + n++, "/", fs_cb)); + ASSERT_OK(uv_fs_symlink(loop, reqs + n++, "/", "/", 0, fs_cb)); + ASSERT_OK(uv_fs_unlink(loop, reqs + n++, "/", fs_cb)); + ASSERT_OK(uv_fs_utime(loop, reqs + n++, "/", 0, 0, fs_cb)); + ASSERT_OK(uv_fs_write(loop, reqs + n++, -1, &iov, 1, 0, fs_cb)); + ASSERT_EQ(n, ARRAY_SIZE(reqs)); + + ASSERT_OK(uv_timer_init(loop, &ci.timer_handle)); + ASSERT_OK(uv_timer_start(&ci.timer_handle, timer_cb, 10, 0)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(n, fs_cb_called); + ASSERT_EQ(1, timer_cb_called); MAKE_VALGRIND_HAPPY(loop); @@ -368,12 +369,12 @@ TEST_IMPL(threadpool_cancel_single) { saturate_threadpool(); loop = uv_default_loop(); - ASSERT(0 == uv_queue_work(loop, &req, (uv_work_cb) abort, nop_done_cb)); - ASSERT(0 == uv_cancel((uv_req_t*) &req)); - ASSERT(0 == done_cb_called); + ASSERT_OK(uv_queue_work(loop, &req, (uv_work_cb) abort, nop_done_cb)); + ASSERT_OK(uv_cancel((uv_req_t*) &req)); + ASSERT_OK(done_cb_called); unblock_threadpool(); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(1 == done_cb_called); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, done_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -404,7 +405,7 @@ TEST_IMPL(threadpool_cancel_when_busy) { ASSERT_EQ(uv_cancel((uv_req_t*) &req), UV_EBUSY); ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT_EQ(done_cb_called, 1); + ASSERT_EQ(1, done_cb_called); uv_sem_destroy(&sem_lock); diff --git a/test/test-threadpool.c b/test/test-threadpool.c index 5254131bce3..fb5e5732e6a 100644 --- a/test/test-threadpool.c +++ b/test/test-threadpool.c @@ -29,16 +29,16 @@ static char data; static void work_cb(uv_work_t* req) { - ASSERT(req == &work_req); - ASSERT(req->data == &data); + ASSERT_PTR_EQ(req, &work_req); + ASSERT_PTR_EQ(req->data, &data); work_cb_count++; } static void after_work_cb(uv_work_t* req, int status) { - ASSERT(status == 0); - ASSERT(req == &work_req); - ASSERT(req->data == &data); + ASSERT_OK(status); + ASSERT_PTR_EQ(req, &work_req); + ASSERT_PTR_EQ(req->data, &data); after_work_cb_count++; } @@ -48,11 +48,11 @@ TEST_IMPL(threadpool_queue_work_simple) { work_req.data = &data; r = uv_queue_work(uv_default_loop(), &work_req, work_cb, after_work_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(work_cb_count == 1); - ASSERT(after_work_cb_count == 1); + ASSERT_EQ(1, work_cb_count); + ASSERT_EQ(1, after_work_cb_count); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -64,12 +64,12 @@ TEST_IMPL(threadpool_queue_work_einval) { work_req.data = &data; r = uv_queue_work(uv_default_loop(), &work_req, NULL, after_work_cb); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(work_cb_count == 0); - ASSERT(after_work_cb_count == 0); + ASSERT_OK(work_cb_count); + ASSERT_OK(after_work_cb_count); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-timer-again.c b/test/test-timer-again.c index cb298956aa9..d7f0b83ab55 100644 --- a/test/test-timer-again.c +++ b/test/test-timer-again.c @@ -44,8 +44,8 @@ static void close_cb(uv_handle_t* handle) { static void repeat_1_cb(uv_timer_t* handle) { int r; - ASSERT(handle == &repeat_1); - ASSERT(uv_timer_get_repeat((uv_timer_t*)handle) == 50); + ASSERT_PTR_EQ(handle, &repeat_1); + ASSERT_EQ(50, uv_timer_get_repeat((uv_timer_t*)handle)); fprintf(stderr, "repeat_1_cb called after %ld ms\n", (long int)(uv_now(uv_default_loop()) - start_time)); @@ -54,7 +54,7 @@ static void repeat_1_cb(uv_timer_t* handle) { repeat_1_cb_called++; r = uv_timer_again(&repeat_2); - ASSERT(r == 0); + ASSERT_OK(r); if (repeat_1_cb_called == 10) { uv_close((uv_handle_t*)handle, close_cb); @@ -67,7 +67,7 @@ static void repeat_1_cb(uv_timer_t* handle) { static void repeat_2_cb(uv_timer_t* handle) { - ASSERT(handle == &repeat_2); + ASSERT_PTR_EQ(handle, &repeat_2); ASSERT(repeat_2_cb_allowed); fprintf(stderr, "repeat_2_cb called after %ld ms\n", @@ -77,7 +77,7 @@ static void repeat_2_cb(uv_timer_t* handle) { repeat_2_cb_called++; if (uv_timer_get_repeat(&repeat_2) == 0) { - ASSERT(0 == uv_is_active((uv_handle_t*) handle)); + ASSERT_OK(uv_is_active((uv_handle_t*) handle)); uv_close((uv_handle_t*)handle, close_cb); return; } @@ -85,7 +85,7 @@ static void repeat_2_cb(uv_timer_t* handle) { fprintf(stderr, "uv_timer_get_repeat %ld ms\n", (long int)uv_timer_get_repeat(&repeat_2)); fflush(stderr); - ASSERT(uv_timer_get_repeat(&repeat_2) == 100); + ASSERT_EQ(100, uv_timer_get_repeat(&repeat_2)); /* This shouldn't take effect immediately. */ uv_timer_set_repeat(&repeat_2, 0); @@ -96,41 +96,41 @@ TEST_IMPL(timer_again) { int r; start_time = uv_now(uv_default_loop()); - ASSERT(0 < start_time); + ASSERT_LT(0, start_time); /* Verify that it is not possible to uv_timer_again a never-started timer. */ r = uv_timer_init(uv_default_loop(), &dummy); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_again(&dummy); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_unref((uv_handle_t*)&dummy); /* Start timer repeat_1. */ r = uv_timer_init(uv_default_loop(), &repeat_1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&repeat_1, repeat_1_cb, 50, 0); - ASSERT(r == 0); - ASSERT(uv_timer_get_repeat(&repeat_1) == 0); + ASSERT_OK(r); + ASSERT_OK(uv_timer_get_repeat(&repeat_1)); /* Actually make repeat_1 repeating. */ uv_timer_set_repeat(&repeat_1, 50); - ASSERT(uv_timer_get_repeat(&repeat_1) == 50); + ASSERT_EQ(50, uv_timer_get_repeat(&repeat_1)); /* * Start another repeating timer. It'll be again()ed by the repeat_1 so * it should not time out until repeat_1 stops. */ r = uv_timer_init(uv_default_loop(), &repeat_2); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&repeat_2, repeat_2_cb, 100, 100); - ASSERT(r == 0); - ASSERT(uv_timer_get_repeat(&repeat_2) == 100); + ASSERT_OK(r); + ASSERT_EQ(100, uv_timer_get_repeat(&repeat_2)); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(repeat_1_cb_called == 10); - ASSERT(repeat_2_cb_called == 2); - ASSERT(close_cb_called == 2); + ASSERT_EQ(10, repeat_1_cb_called); + ASSERT_EQ(2, repeat_2_cb_called); + ASSERT_EQ(2, close_cb_called); fprintf(stderr, "Test took %ld ms (expected ~700 ms)\n", (long int)(uv_now(uv_default_loop()) - start_time)); diff --git a/test/test-timer-from-check.c b/test/test-timer-from-check.c index e1a002d8121..e5f5cb2f60a 100644 --- a/test/test-timer-from-check.c +++ b/test/test-timer-from-check.c @@ -32,49 +32,49 @@ static int timer_cb_called; static void prepare_cb(uv_prepare_t* handle) { - ASSERT(0 == uv_prepare_stop(&prepare_handle)); - ASSERT(0 == prepare_cb_called); - ASSERT(1 == check_cb_called); - ASSERT(0 == timer_cb_called); + ASSERT_OK(uv_prepare_stop(&prepare_handle)); + ASSERT_OK(prepare_cb_called); + ASSERT_EQ(1, check_cb_called); + ASSERT_OK(timer_cb_called); prepare_cb_called++; } static void timer_cb(uv_timer_t* handle) { - ASSERT(0 == uv_timer_stop(&timer_handle)); - ASSERT(1 == prepare_cb_called); - ASSERT(1 == check_cb_called); - ASSERT(0 == timer_cb_called); + ASSERT_OK(uv_timer_stop(&timer_handle)); + ASSERT_EQ(1, prepare_cb_called); + ASSERT_EQ(1, check_cb_called); + ASSERT_OK(timer_cb_called); timer_cb_called++; } static void check_cb(uv_check_t* handle) { - ASSERT(0 == uv_check_stop(&check_handle)); - ASSERT(0 == uv_timer_stop(&timer_handle)); /* Runs before timer_cb. */ - ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0)); - ASSERT(0 == uv_prepare_start(&prepare_handle, prepare_cb)); - ASSERT(0 == prepare_cb_called); - ASSERT(0 == check_cb_called); - ASSERT(0 == timer_cb_called); + ASSERT_OK(uv_check_stop(&check_handle)); + ASSERT_OK(uv_timer_stop(&timer_handle)); /* Runs before timer_cb. */ + ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, 50, 0)); + ASSERT_OK(uv_prepare_start(&prepare_handle, prepare_cb)); + ASSERT_OK(prepare_cb_called); + ASSERT_OK(check_cb_called); + ASSERT_OK(timer_cb_called); check_cb_called++; } TEST_IMPL(timer_from_check) { - ASSERT(0 == uv_prepare_init(uv_default_loop(), &prepare_handle)); - ASSERT(0 == uv_check_init(uv_default_loop(), &check_handle)); - ASSERT(0 == uv_check_start(&check_handle, check_cb)); - ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); - ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(1 == prepare_cb_called); - ASSERT(1 == check_cb_called); - ASSERT(1 == timer_cb_called); + ASSERT_OK(uv_prepare_init(uv_default_loop(), &prepare_handle)); + ASSERT_OK(uv_check_init(uv_default_loop(), &check_handle)); + ASSERT_OK(uv_check_start(&check_handle, check_cb)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, 50, 0)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, prepare_cb_called); + ASSERT_EQ(1, check_cb_called); + ASSERT_EQ(1, timer_cb_called); uv_close((uv_handle_t*) &prepare_handle, NULL); uv_close((uv_handle_t*) &check_handle, NULL); uv_close((uv_handle_t*) &timer_handle, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } diff --git a/test/test-timer.c b/test/test-timer.c index 2488f14c204..d889e707731 100644 --- a/test/test-timer.c +++ b/test/test-timer.c @@ -41,7 +41,7 @@ static void once_close_cb(uv_handle_t* handle) { printf("ONCE_CLOSE_CB\n"); ASSERT_NOT_NULL(handle); - ASSERT(0 == uv_is_active(handle)); + ASSERT_OK(uv_is_active(handle)); once_close_cb_called++; } @@ -51,7 +51,7 @@ static void once_cb(uv_timer_t* handle) { printf("ONCE_CB %d\n", once_cb_called); ASSERT_NOT_NULL(handle); - ASSERT(0 == uv_is_active((uv_handle_t*) handle)); + ASSERT_OK(uv_is_active((uv_handle_t*) handle)); once_cb_called++; @@ -65,7 +65,7 @@ static void twice_close_cb(uv_handle_t* handle) { printf("TWICE_CLOSE_CB\n"); ASSERT_NOT_NULL(handle); - ASSERT(0 == uv_is_active(handle)); + ASSERT_OK(uv_is_active(handle)); twice_close_cb_called++; } @@ -74,7 +74,7 @@ static void twice_cb(uv_timer_t* handle) { printf("TWICE_CB %d\n", twice_cb_called); ASSERT_NOT_NULL(handle); - ASSERT(0 == uv_is_active((uv_handle_t*) handle)); + ASSERT_OK(uv_is_active((uv_handle_t*) handle)); twice_cb_called++; @@ -96,7 +96,7 @@ static void repeat_cb(uv_timer_t* handle) { printf("REPEAT_CB\n"); ASSERT_NOT_NULL(handle); - ASSERT(1 == uv_is_active((uv_handle_t*) handle)); + ASSERT_EQ(1, uv_is_active((uv_handle_t*) handle)); repeat_cb_called++; @@ -119,41 +119,41 @@ TEST_IMPL(timer) { int r; start_time = uv_now(uv_default_loop()); - ASSERT(0 < start_time); + ASSERT_LT(0, start_time); /* Let 10 timers time out in 500 ms total. */ for (i = 0; i < ARRAY_SIZE(once_timers); i++) { once = once_timers + i; r = uv_timer_init(uv_default_loop(), once); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(once, once_cb, i * 50, 0); - ASSERT(r == 0); + ASSERT_OK(r); } /* The 11th timer is a repeating timer that runs 4 times */ r = uv_timer_init(uv_default_loop(), &repeat); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&repeat, repeat_cb, 100, 100); - ASSERT(r == 0); + ASSERT_OK(r); /* The 12th timer should not do anything. */ r = uv_timer_init(uv_default_loop(), &never); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&never, never_cb, 100, 100); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_stop(&never); - ASSERT(r == 0); + ASSERT_OK(r); uv_unref((uv_handle_t*)&never); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(once_cb_called == 10); - ASSERT(once_close_cb_called == 10); + ASSERT_EQ(10, once_cb_called); + ASSERT_EQ(10, once_close_cb_called); printf("repeat_cb_called %d\n", repeat_cb_called); - ASSERT(repeat_cb_called == 5); - ASSERT(repeat_close_cb_called == 1); + ASSERT_EQ(5, repeat_cb_called); + ASSERT_EQ(1, repeat_close_cb_called); - ASSERT(500 <= uv_now(uv_default_loop()) - start_time); + ASSERT_LE(500, uv_now(uv_default_loop()) - start_time); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -165,15 +165,15 @@ TEST_IMPL(timer_start_twice) { int r; r = uv_timer_init(uv_default_loop(), &once); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&once, never_cb, 86400 * 1000, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&once, twice_cb, 10, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(twice_cb_called == 1); + ASSERT_EQ(1, twice_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -183,10 +183,10 @@ TEST_IMPL(timer_start_twice) { TEST_IMPL(timer_init) { uv_timer_t handle; - ASSERT(0 == uv_timer_init(uv_default_loop(), &handle)); - ASSERT(0 == uv_timer_get_repeat(&handle)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &handle)); + ASSERT_OK(uv_timer_get_repeat(&handle)); ASSERT_UINT64_LE(0, uv_timer_get_due_in(&handle)); - ASSERT(0 == uv_is_active((uv_handle_t*) &handle)); + ASSERT_OK(uv_is_active((uv_handle_t*) &handle)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -194,12 +194,12 @@ TEST_IMPL(timer_init) { static void order_cb_a(uv_timer_t *handle) { - ASSERT(order_cb_called++ == *(int*)handle->data); + ASSERT_EQ(order_cb_called++, *(int*)handle->data); } static void order_cb_b(uv_timer_t *handle) { - ASSERT(order_cb_called++ == *(int*)handle->data); + ASSERT_EQ(order_cb_called++, *(int*)handle->data); } @@ -211,31 +211,31 @@ TEST_IMPL(timer_order) { first = 0; second = 1; - ASSERT(0 == uv_timer_init(uv_default_loop(), &handle_a)); - ASSERT(0 == uv_timer_init(uv_default_loop(), &handle_b)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &handle_a)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &handle_b)); /* Test for starting handle_a then handle_b */ handle_a.data = &first; - ASSERT(0 == uv_timer_start(&handle_a, order_cb_a, 0, 0)); + ASSERT_OK(uv_timer_start(&handle_a, order_cb_a, 0, 0)); handle_b.data = &second; - ASSERT(0 == uv_timer_start(&handle_b, order_cb_b, 0, 0)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_timer_start(&handle_b, order_cb_b, 0, 0)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(order_cb_called == 2); + ASSERT_EQ(2, order_cb_called); - ASSERT(0 == uv_timer_stop(&handle_a)); - ASSERT(0 == uv_timer_stop(&handle_b)); + ASSERT_OK(uv_timer_stop(&handle_a)); + ASSERT_OK(uv_timer_stop(&handle_b)); /* Test for starting handle_b then handle_a */ order_cb_called = 0; handle_b.data = &first; - ASSERT(0 == uv_timer_start(&handle_b, order_cb_b, 0, 0)); + ASSERT_OK(uv_timer_start(&handle_b, order_cb_b, 0, 0)); handle_a.data = &second; - ASSERT(0 == uv_timer_start(&handle_a, order_cb_a, 0, 0)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_timer_start(&handle_a, order_cb_a, 0, 0)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT(order_cb_called == 2); + ASSERT_EQ(2, order_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -243,7 +243,7 @@ TEST_IMPL(timer_order) { static void tiny_timer_cb(uv_timer_t* handle) { - ASSERT(handle == &tiny_timer); + ASSERT_PTR_EQ(handle, &tiny_timer); uv_close((uv_handle_t*) &tiny_timer, NULL); uv_close((uv_handle_t*) &huge_timer1, NULL); uv_close((uv_handle_t*) &huge_timer2, NULL); @@ -251,16 +251,19 @@ static void tiny_timer_cb(uv_timer_t* handle) { TEST_IMPL(timer_huge_timeout) { - ASSERT(0 == uv_timer_init(uv_default_loop(), &tiny_timer)); - ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer1)); - ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer2)); - ASSERT(0 == uv_timer_start(&tiny_timer, tiny_timer_cb, 1, 0)); - ASSERT(0 == uv_timer_start(&huge_timer1, tiny_timer_cb, 0xffffffffffffLL, 0)); - ASSERT(0 == uv_timer_start(&huge_timer2, tiny_timer_cb, (uint64_t) -1, 0)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &tiny_timer)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &huge_timer1)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &huge_timer2)); + ASSERT_OK(uv_timer_start(&tiny_timer, tiny_timer_cb, 1, 0)); + ASSERT_OK(uv_timer_start(&huge_timer1, + tiny_timer_cb, + 0xffffffffffffLL, + 0)); + ASSERT_OK(uv_timer_start(&huge_timer2, tiny_timer_cb, (uint64_t) -1, 0)); ASSERT_UINT64_EQ(1, uv_timer_get_due_in(&tiny_timer)); ASSERT_UINT64_EQ(281474976710655, uv_timer_get_due_in(&huge_timer1)); ASSERT_UINT64_LE(0, uv_timer_get_due_in(&huge_timer2)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -270,9 +273,9 @@ static void huge_repeat_cb(uv_timer_t* handle) { static int ncalls; if (ncalls == 0) - ASSERT(handle == &huge_timer1); + ASSERT_PTR_EQ(handle, &huge_timer1); else - ASSERT(handle == &tiny_timer); + ASSERT_PTR_EQ(handle, &tiny_timer); if (++ncalls == 10) { uv_close((uv_handle_t*) &tiny_timer, NULL); @@ -282,11 +285,11 @@ static void huge_repeat_cb(uv_timer_t* handle) { TEST_IMPL(timer_huge_repeat) { - ASSERT(0 == uv_timer_init(uv_default_loop(), &tiny_timer)); - ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer1)); - ASSERT(0 == uv_timer_start(&tiny_timer, huge_repeat_cb, 2, 2)); - ASSERT(0 == uv_timer_start(&huge_timer1, huge_repeat_cb, 1, (uint64_t) -1)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &tiny_timer)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &huge_timer1)); + ASSERT_OK(uv_timer_start(&tiny_timer, huge_repeat_cb, 2, 2)); + ASSERT_OK(uv_timer_start(&huge_timer1, huge_repeat_cb, 1, (uint64_t) -1)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -303,17 +306,17 @@ static void timer_run_once_timer_cb(uv_timer_t* handle) { TEST_IMPL(timer_run_once) { uv_timer_t timer_handle; - ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); - ASSERT(0 == uv_timer_start(&timer_handle, timer_run_once_timer_cb, 0, 0)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); - ASSERT(1 == timer_run_once_timer_cb_called); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, timer_run_once_timer_cb, 0, 0)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_EQ(1, timer_run_once_timer_cb_called); - ASSERT(0 == uv_timer_start(&timer_handle, timer_run_once_timer_cb, 1, 0)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); - ASSERT(2 == timer_run_once_timer_cb_called); + ASSERT_OK(uv_timer_start(&timer_handle, timer_run_once_timer_cb, 1, 0)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_EQ(2, timer_run_once_timer_cb_called); uv_close((uv_handle_t*) &timer_handle, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_ONCE)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -323,10 +326,10 @@ TEST_IMPL(timer_run_once) { TEST_IMPL(timer_is_closing) { uv_timer_t handle; - ASSERT(0 == uv_timer_init(uv_default_loop(), &handle)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &handle)); uv_close((uv_handle_t *)&handle, NULL); - ASSERT(UV_EINVAL == uv_timer_start(&handle, never_cb, 100, 100)); + ASSERT_EQ(UV_EINVAL, uv_timer_start(&handle, never_cb, 100, 100)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -336,8 +339,8 @@ TEST_IMPL(timer_is_closing) { TEST_IMPL(timer_null_callback) { uv_timer_t handle; - ASSERT(0 == uv_timer_init(uv_default_loop(), &handle)); - ASSERT(UV_EINVAL == uv_timer_start(&handle, NULL, 100, 100)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &handle)); + ASSERT_EQ(UV_EINVAL, uv_timer_start(&handle, NULL, 100, 100)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -349,7 +352,7 @@ static uint64_t timer_early_check_expected_time; static void timer_early_check_cb(uv_timer_t* handle) { uint64_t hrtime = uv_hrtime() / 1000000; - ASSERT(hrtime >= timer_early_check_expected_time); + ASSERT_GE(hrtime, timer_early_check_expected_time); } @@ -359,12 +362,15 @@ TEST_IMPL(timer_early_check) { timer_early_check_expected_time = uv_now(uv_default_loop()) + timeout_ms; - ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); - ASSERT(0 == uv_timer_start(&timer_handle, timer_early_check_cb, timeout_ms, 0)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, + timer_early_check_cb, + timeout_ms, + 0)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); uv_close((uv_handle_t*) &timer_handle, NULL); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -378,11 +384,11 @@ TEST_IMPL(timer_no_double_call_once) { uv_timer_t timer_handle; const uint64_t timeout_ms = 10; - ASSERT_EQ(0, uv_timer_init(uv_default_loop(), &timer_handle)); - ASSERT_EQ(0, uv_timer_start(&timer_handle, - timer_check_double_call, - timeout_ms, - timeout_ms)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, + timer_check_double_call, + timeout_ms, + timeout_ms)); uv_sleep(timeout_ms * 2); ASSERT_EQ(1, uv_run(uv_default_loop(), UV_RUN_ONCE)); ASSERT_EQ(1, timer_check_double_call_called); @@ -395,11 +401,11 @@ TEST_IMPL(timer_no_double_call_nowait) { uv_timer_t timer_handle; const uint64_t timeout_ms = 10; - ASSERT_EQ(0, uv_timer_init(uv_default_loop(), &timer_handle)); - ASSERT_EQ(0, uv_timer_start(&timer_handle, - timer_check_double_call, - timeout_ms, - timeout_ms)); + ASSERT_OK(uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT_OK(uv_timer_start(&timer_handle, + timer_check_double_call, + timeout_ms, + timeout_ms)); uv_sleep(timeout_ms * 2); ASSERT_EQ(1, uv_run(uv_default_loop(), UV_RUN_NOWAIT)); ASSERT_EQ(1, timer_check_double_call_called); @@ -414,7 +420,7 @@ TEST_IMPL(timer_no_run_on_unref) { ASSERT_OK(uv_timer_init(uv_default_loop(), &timer_handle)); ASSERT_OK(uv_timer_start(&timer_handle, (uv_timer_cb) abort, 0, 0)); uv_unref((uv_handle_t*) &timer_handle); - ASSERT_EQ(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-tmpdir.c b/test/test-tmpdir.c index 86f72e25431..a4e9ce950aa 100644 --- a/test/test-tmpdir.c +++ b/test/test-tmpdir.c @@ -36,46 +36,46 @@ TEST_IMPL(tmpdir) { len = sizeof tmpdir; tmpdir[0] = '\0'; - ASSERT(strlen(tmpdir) == 0); + ASSERT_OK(strlen(tmpdir)); r = uv_os_tmpdir(tmpdir, &len); - ASSERT(r == 0); - ASSERT(strlen(tmpdir) == len); - ASSERT(len > 0); - ASSERT(tmpdir[len] == '\0'); + ASSERT_OK(r); + ASSERT_EQ(strlen(tmpdir), len); + ASSERT_GT(len, 0); + ASSERT_EQ(tmpdir[len], '\0'); if (len > 1) { last = tmpdir[len - 1]; #ifdef _WIN32 - ASSERT(last != '\\'); + ASSERT_NE(last, '\\'); #else - ASSERT(last != '/'); + ASSERT_NE(last, '/'); #endif } /* Test the case where the buffer is too small */ len = SMALLPATH; r = uv_os_tmpdir(tmpdir, &len); - ASSERT(r == UV_ENOBUFS); - ASSERT(len > SMALLPATH); + ASSERT_EQ(r, UV_ENOBUFS); + ASSERT_GT(len, SMALLPATH); /* Test invalid inputs */ r = uv_os_tmpdir(NULL, &len); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_os_tmpdir(tmpdir, NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); len = 0; r = uv_os_tmpdir(tmpdir, &len); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); #ifdef _WIN32 const char *name = "TMP"; char tmpdir_win[] = "C:\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; r = uv_os_setenv(name, tmpdir_win); - ASSERT(r == 0); + ASSERT_OK(r); char tmpdirx[PATHMAX]; size_t lenx = sizeof tmpdirx; r = uv_os_tmpdir(tmpdirx, &lenx); - ASSERT(r == 0); + ASSERT_OK(r); #endif return 0; diff --git a/test/test-tty-duplicate-key.c b/test/test-tty-duplicate-key.c index 6ba96c81352..91d3075e130 100644 --- a/test/test-tty-duplicate-key.c +++ b/test/test-tty-duplicate-key.c @@ -73,7 +73,7 @@ static void tty_read(uv_stream_t* tty_in, ssize_t nread, const uv_buf_t* buf) { } uv_close((uv_handle_t*) tty_in, NULL); } else { - ASSERT(nread == 0); + ASSERT_OK(nread); } } @@ -150,25 +150,25 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT(handle != INVALID_HANDLE_VALUE); + ASSERT_NE(handle, INVALID_HANDLE_VALUE); ttyin_fd = _open_osfhandle((intptr_t) handle, 0); - ASSERT(ttyin_fd >= 0); - ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); + ASSERT_GE(ttyin_fd, 0); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read); - ASSERT(r == 0); + ASSERT_OK(r); expect_str = ESC"[[A"; expect_nread = strlen(expect_str); /* Turn on raw mode. */ r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); - ASSERT(r == 0); + ASSERT_OK(r); /* * Send F1 keystrokes. Test of issue cause by #2114 that vt100 fn key @@ -176,7 +176,7 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) { */ make_key_event_records(VK_F1, 0, TRUE, records); WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written); - ASSERT(written == ARRAY_SIZE(records)); + ASSERT_EQ(written, ARRAY_SIZE(records)); uv_run(loop, UV_RUN_DEFAULT); @@ -204,45 +204,45 @@ TEST_IMPL(tty_duplicate_alt_modifier_key) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT(handle != INVALID_HANDLE_VALUE); + ASSERT_NE(handle, INVALID_HANDLE_VALUE); ttyin_fd = _open_osfhandle((intptr_t) handle, 0); - ASSERT(ttyin_fd >= 0); - ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); + ASSERT_GE(ttyin_fd, 0); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read); - ASSERT(r == 0); + ASSERT_OK(r); expect_str = ESC"a"ESC"a"; expect_nread = strlen(expect_str); /* Turn on raw mode. */ r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); - ASSERT(r == 0); + ASSERT_OK(r); /* Emulate transmission of M-a at normal console */ make_key_event_records(VK_MENU, 0, TRUE, alt_records); WriteConsoleInputW(handle, &alt_records[0], 1, &written); - ASSERT(written == 1); + ASSERT_EQ(1, written); make_key_event_records(L'A', LEFT_ALT_PRESSED, FALSE, records); WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written); - ASSERT(written == 2); + ASSERT_EQ(2, written); WriteConsoleInputW(handle, &alt_records[1], 1, &written); - ASSERT(written == 1); + ASSERT_EQ(1, written); /* Emulate transmission of M-a at WSL(#2111) */ make_key_event_records(VK_MENU, 0, TRUE, alt_records); WriteConsoleInputW(handle, &alt_records[0], 1, &written); - ASSERT(written == 1); + ASSERT_EQ(1, written); make_key_event_records(L'A', LEFT_ALT_PRESSED, TRUE, records); WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written); - ASSERT(written == 2); + ASSERT_EQ(2, written); WriteConsoleInputW(handle, &alt_records[1], 1, &written); - ASSERT(written == 1); + ASSERT_EQ(1, written); uv_run(loop, UV_RUN_DEFAULT); @@ -270,25 +270,25 @@ TEST_IMPL(tty_composing_character) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT(handle != INVALID_HANDLE_VALUE); + ASSERT_NE(handle, INVALID_HANDLE_VALUE); ttyin_fd = _open_osfhandle((intptr_t) handle, 0); - ASSERT(ttyin_fd >= 0); - ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); + ASSERT_GE(ttyin_fd, 0); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read); - ASSERT(r == 0); + ASSERT_OK(r); expect_str = EUR_UTF8; expect_nread = strlen(expect_str); /* Turn on raw mode. */ r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); - ASSERT(r == 0); + ASSERT_OK(r); /* Emulate EUR inputs by LEFT ALT+NUMPAD ASCII KeyComos */ make_key_event_records(VK_MENU, 0, FALSE, alt_records); @@ -296,16 +296,16 @@ TEST_IMPL(tty_composing_character) { WriteConsoleInputW(handle, &alt_records[0], 1, &written); make_key_event_records(VK_NUMPAD0, LEFT_ALT_PRESSED, FALSE, records); WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written); - ASSERT(written == ARRAY_SIZE(records)); + ASSERT_EQ(written, ARRAY_SIZE(records)); make_key_event_records(VK_NUMPAD1, LEFT_ALT_PRESSED, FALSE, records); WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written); - ASSERT(written == ARRAY_SIZE(records)); + ASSERT_EQ(written, ARRAY_SIZE(records)); make_key_event_records(VK_NUMPAD2, LEFT_ALT_PRESSED, FALSE, records); WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written); - ASSERT(written == ARRAY_SIZE(records)); + ASSERT_EQ(written, ARRAY_SIZE(records)); make_key_event_records(VK_NUMPAD8, LEFT_ALT_PRESSED, FALSE, records); WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written); - ASSERT(written == ARRAY_SIZE(records)); + ASSERT_EQ(written, ARRAY_SIZE(records)); WriteConsoleInputW(handle, &alt_records[1], 1, &written); uv_run(loop, UV_RUN_DEFAULT); diff --git a/test/test-tty-escape-sequence-processing.c b/test/test-tty-escape-sequence-processing.c index 2f7d0364b8b..8bf906fdb47 100644 --- a/test/test-tty-escape-sequence-processing.c +++ b/test/test-tty-escape-sequence-processing.c @@ -165,8 +165,8 @@ static void write_console(uv_tty_t* tty_out, char* src) { buf.len = strlen(buf.base); r = uv_try_write((uv_stream_t*) tty_out, &buf, 1); - ASSERT(r >= 0); - ASSERT((unsigned int) r == buf.len); + ASSERT_GE(r, 0); + ASSERT_EQ((unsigned int) r, buf.len); } static void setup_screen(uv_tty_t* tty_out) { @@ -178,8 +178,8 @@ static void setup_screen(uv_tty_t* tty_out) { origin.X = 0; origin.Y = info.srWindow.Top; ASSERT(FillConsoleOutputCharacter( - tty_out->handle, '.', length, origin, &number_of_written)); - ASSERT(length == number_of_written); + tty_out->handle, '.', length, origin, &number_of_written)); + ASSERT_EQ(length, number_of_written); } static void clear_screen(uv_tty_t* tty_out, struct screen_info* si) { @@ -192,10 +192,10 @@ static void clear_screen(uv_tty_t* tty_out, struct screen_info* si) { origin.Y = info.srWindow.Top; FillConsoleOutputCharacterA( tty_out->handle, ' ', length, origin, &number_of_written); - ASSERT(length == number_of_written); + ASSERT_EQ(length, number_of_written); FillConsoleOutputAttribute( tty_out->handle, si->default_attr, length, origin, &number_of_written); - ASSERT(length == number_of_written); + ASSERT_EQ(length, number_of_written); } static void free_screen(struct captured_screen* cs) { @@ -216,11 +216,11 @@ static void capture_screen(uv_tty_t* tty_out, struct captured_screen* cs) { cs->attributes = (WORD*) malloc(cs->si.length * sizeof(*cs->attributes)); ASSERT_NOT_NULL(cs->attributes); ASSERT(ReadConsoleOutputCharacter( - tty_out->handle, cs->text, cs->si.length, origin, &length)); - ASSERT((unsigned int) cs->si.length == length); + tty_out->handle, cs->text, cs->si.length, origin, &length)); + ASSERT_EQ((unsigned int) cs->si.length, length); ASSERT(ReadConsoleOutputAttribute( - tty_out->handle, cs->attributes, cs->si.length, origin, &length)); - ASSERT((unsigned int) cs->si.length == length); + tty_out->handle, cs->attributes, cs->si.length, origin, &length)); + ASSERT_EQ((unsigned int) cs->si.length, length); } static void make_expect_screen_erase(struct captured_screen* cs, @@ -261,8 +261,8 @@ static void make_expect_screen_erase(struct captured_screen* cs, } else { ASSERT(FALSE); } - ASSERT(start < end); - ASSERT(end - cs->text <= cs->si.length); + ASSERT_LT(start, end); + ASSERT_LE(end - cs->text, cs->si.length); for (; start < end; start++) { *start = ' '; } @@ -360,13 +360,13 @@ static void initialize_tty(uv_tty_t* tty_out) { NULL, CONSOLE_TEXTMODE_BUFFER, NULL); - ASSERT(handle != INVALID_HANDLE_VALUE); + ASSERT_NE(handle, INVALID_HANDLE_VALUE); ttyout_fd = _open_osfhandle((intptr_t) handle, 0); - ASSERT(ttyout_fd >= 0); - ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + ASSERT_GE(ttyout_fd, 0); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyout_fd)); r = uv_tty_init(uv_default_loop(), tty_out, ttyout_fd, 0); /* Writable. */ - ASSERT(r == 0); + ASSERT_OK(r); } static void terminate_tty(uv_tty_t* tty_out) { @@ -394,16 +394,16 @@ TEST_IMPL(tty_cursor_up) { snprintf(buffer, sizeof(buffer), "%sA", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y - 1 == cursor_pos.Y); - ASSERT(cursor_pos_old.X == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y - 1, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X, cursor_pos.X); /* cursor up nth times */ cursor_pos_old = cursor_pos; snprintf(buffer, sizeof(buffer), "%s%dA", CSI, si.height / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y - si.height / 4 == cursor_pos.Y); - ASSERT(cursor_pos_old.X == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y - si.height / 4, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X, cursor_pos.X); /* cursor up from Window top does nothing */ cursor_pos_old.X = 1; @@ -412,8 +412,8 @@ TEST_IMPL(tty_cursor_up) { snprintf(buffer, sizeof(buffer), "%sA", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); - ASSERT(cursor_pos_old.X == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X, cursor_pos.X); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); @@ -445,16 +445,16 @@ TEST_IMPL(tty_cursor_down) { snprintf(buffer, sizeof(buffer), "%sB", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y + 1 == cursor_pos.Y); - ASSERT(cursor_pos_old.X == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y + 1, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X, cursor_pos.X); /* cursor down nth times */ cursor_pos_old = cursor_pos; snprintf(buffer, sizeof(buffer), "%s%dB", CSI, si.height / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y + si.height / 4 == cursor_pos.Y); - ASSERT(cursor_pos_old.X == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y + si.height / 4, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X, cursor_pos.X); /* cursor down from bottom line does nothing */ cursor_pos_old.X = si.width / 2; @@ -463,8 +463,8 @@ TEST_IMPL(tty_cursor_down) { snprintf(buffer, sizeof(buffer), "%sB", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); - ASSERT(cursor_pos_old.X == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X, cursor_pos.X); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); @@ -496,16 +496,16 @@ TEST_IMPL(tty_cursor_forward) { snprintf(buffer, sizeof(buffer), "%sC", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); - ASSERT(cursor_pos_old.X + 1 == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X + 1, cursor_pos.X); /* cursor forward nth times */ cursor_pos_old = cursor_pos; snprintf(buffer, sizeof(buffer), "%s%dC", CSI, si.width / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); - ASSERT(cursor_pos_old.X + si.width / 4 == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X + si.width / 4, cursor_pos.X); /* cursor forward from end of line does nothing*/ cursor_pos_old.X = si.width; @@ -514,8 +514,8 @@ TEST_IMPL(tty_cursor_forward) { snprintf(buffer, sizeof(buffer), "%sC", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); - ASSERT(cursor_pos_old.X == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X, cursor_pos.X); /* cursor forward from end of screen does nothing */ cursor_pos_old.X = si.width; @@ -524,8 +524,8 @@ TEST_IMPL(tty_cursor_forward) { snprintf(buffer, sizeof(buffer), "%sC", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); - ASSERT(cursor_pos_old.X == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X, cursor_pos.X); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); @@ -557,16 +557,16 @@ TEST_IMPL(tty_cursor_back) { snprintf(buffer, sizeof(buffer), "%sD", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); - ASSERT(cursor_pos_old.X - 1 == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X - 1, cursor_pos.X); /* cursor back nth times */ cursor_pos_old = cursor_pos; snprintf(buffer, sizeof(buffer), "%s%dD", CSI, si.width / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); - ASSERT(cursor_pos_old.X - si.width / 4 == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X - si.width / 4, cursor_pos.X); /* cursor back from beginning of line does nothing */ cursor_pos_old.X = 1; @@ -575,8 +575,8 @@ TEST_IMPL(tty_cursor_back) { snprintf(buffer, sizeof(buffer), "%sD", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); - ASSERT(cursor_pos_old.X == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); + ASSERT_EQ(cursor_pos_old.X, cursor_pos.X); /* cursor back from top of screen does nothing */ cursor_pos_old.X = 1; @@ -585,8 +585,8 @@ TEST_IMPL(tty_cursor_back) { snprintf(buffer, sizeof(buffer), "%sD", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(1 == cursor_pos.Y); - ASSERT(1 == cursor_pos.X); + ASSERT_EQ(1, cursor_pos.Y); + ASSERT_EQ(1, cursor_pos.X); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); @@ -618,16 +618,16 @@ TEST_IMPL(tty_cursor_next_line) { snprintf(buffer, sizeof(buffer), "%sE", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y + 1 == cursor_pos.Y); - ASSERT(1 == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y + 1, cursor_pos.Y); + ASSERT_EQ(1, cursor_pos.X); /* cursor next line nth times */ cursor_pos_old = cursor_pos; snprintf(buffer, sizeof(buffer), "%s%dE", CSI, si.height / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y + si.height / 4 == cursor_pos.Y); - ASSERT(1 == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y + si.height / 4, cursor_pos.Y); + ASSERT_EQ(1, cursor_pos.X); /* cursor next line from buttom row moves beginning of line */ cursor_pos_old.X = si.width / 2; @@ -636,8 +636,8 @@ TEST_IMPL(tty_cursor_next_line) { snprintf(buffer, sizeof(buffer), "%sE", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); - ASSERT(1 == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); + ASSERT_EQ(1, cursor_pos.X); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); @@ -669,16 +669,16 @@ TEST_IMPL(tty_cursor_previous_line) { snprintf(buffer, sizeof(buffer), "%sF", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y - 1 == cursor_pos.Y); - ASSERT(1 == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y - 1, cursor_pos.Y); + ASSERT_EQ(1, cursor_pos.X); /* cursor previous line nth times */ cursor_pos_old = cursor_pos; snprintf(buffer, sizeof(buffer), "%s%dF", CSI, si.height / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos_old.Y - si.height / 4 == cursor_pos.Y); - ASSERT(1 == cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y - si.height / 4, cursor_pos.Y); + ASSERT_EQ(1, cursor_pos.X); /* cursor previous line from top of screen does nothing */ cursor_pos_old.X = 1; @@ -687,8 +687,8 @@ TEST_IMPL(tty_cursor_previous_line) { snprintf(buffer, sizeof(buffer), "%sD", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(1 == cursor_pos.Y); - ASSERT(1 == cursor_pos.X); + ASSERT_EQ(1, cursor_pos.Y); + ASSERT_EQ(1, cursor_pos.X); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); @@ -720,22 +720,22 @@ TEST_IMPL(tty_cursor_horizontal_move_absolute) { snprintf(buffer, sizeof(buffer), "%sG", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(1 == cursor_pos.X); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT_EQ(1, cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); /* Move cursor to nth character */ snprintf(buffer, sizeof(buffer), "%s%dG", CSI, si.width / 4); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(si.width / 4 == cursor_pos.X); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT_EQ(si.width / 4, cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); /* Moving out of screen will fit within screen */ snprintf(buffer, sizeof(buffer), "%s%dG", CSI, si.width + 1); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(si.width == cursor_pos.X); - ASSERT(cursor_pos_old.Y == cursor_pos.Y); + ASSERT_EQ(si.width, cursor_pos.X); + ASSERT_EQ(cursor_pos_old.Y, cursor_pos.Y); terminate_tty(&tty_out); @@ -766,31 +766,31 @@ TEST_IMPL(tty_cursor_move_absolute) { snprintf(buffer, sizeof(buffer), "%sH", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(1 == cursor_pos.X); - ASSERT(1 == cursor_pos.Y); + ASSERT_EQ(1, cursor_pos.X); + ASSERT_EQ(1, cursor_pos.Y); /* Move the cursor to the middle of the screen */ snprintf( buffer, sizeof(buffer), "%s%d;%df", CSI, si.height / 2, si.width / 2); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(si.width / 2 == cursor_pos.X); - ASSERT(si.height / 2 == cursor_pos.Y); + ASSERT_EQ(si.width / 2, cursor_pos.X); + ASSERT_EQ(si.height / 2, cursor_pos.Y); /* Moving out of screen will fit within screen */ snprintf( buffer, sizeof(buffer), "%s%d;%df", CSI, si.height / 2, si.width + 1); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(si.width == cursor_pos.X); - ASSERT(si.height / 2 == cursor_pos.Y); + ASSERT_EQ(si.width, cursor_pos.X); + ASSERT_EQ(si.height / 2, cursor_pos.Y); snprintf( buffer, sizeof(buffer), "%s%d;%df", CSI, si.height + 1, si.width / 2); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(si.width / 2 == cursor_pos.X); - ASSERT(si.height == cursor_pos.Y); + ASSERT_EQ(si.width / 2, cursor_pos.X); + ASSERT_EQ(si.height, cursor_pos.Y); ASSERT(!is_scrolling(&tty_out, si)); terminate_tty(&tty_out); @@ -1000,38 +1000,38 @@ TEST_IMPL(tty_set_cursor_shape) { set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s q", CSI); write_console(&tty_out, buffer); - ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_LARGE); + ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_LARGE); /* cursor size large */ set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s1 q", CSI); write_console(&tty_out, buffer); - ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_LARGE); + ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_LARGE); set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s2 q", CSI); write_console(&tty_out, buffer); - ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_LARGE); + ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_LARGE); /* cursor size small */ set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s3 q", CSI); write_console(&tty_out, buffer); - ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_SMALL); + ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_SMALL); set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s6 q", CSI); write_console(&tty_out, buffer); - ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_SMALL); + ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_SMALL); /* Nothing occurs with arguments outside valid range */ set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s7 q", CSI); write_console(&tty_out, buffer); - ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE); + ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_MIDDLE); /* restore cursor size if arguments is zero */ snprintf(buffer, sizeof(buffer), "%s0 q", CSI); write_console(&tty_out, buffer); - ASSERT(get_cursor_size(&tty_out) == saved_cursor_size); + ASSERT_EQ(get_cursor_size(&tty_out), saved_cursor_size); terminate_tty(&tty_out); @@ -1122,7 +1122,7 @@ TEST_IMPL(tty_set_style) { } /* Set foreground and background color */ - ASSERT(ARRAY_SIZE(fg_attrs) == ARRAY_SIZE(bg_attrs)); + ASSERT_EQ(ARRAY_SIZE(fg_attrs), ARRAY_SIZE(bg_attrs)); length = ARRAY_SIZE(bg_attrs); for (i = 0; i < length; i++) { capture_screen(&tty_out, &expect); @@ -1271,8 +1271,8 @@ TEST_IMPL(tty_save_restore_cursor_position) { snprintf(buffer, sizeof(buffer), "%su", CSI); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos.X == cursor_pos_old.X); - ASSERT(cursor_pos.Y == cursor_pos_old.Y); + ASSERT_EQ(cursor_pos.X, cursor_pos_old.X); + ASSERT_EQ(cursor_pos.Y, cursor_pos_old.Y); cursor_pos_old.X = si.width / 2; cursor_pos_old.Y = si.height / 2; @@ -1290,8 +1290,8 @@ TEST_IMPL(tty_save_restore_cursor_position) { snprintf(buffer, sizeof(buffer), "%s8", ESC); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos.X == cursor_pos_old.X); - ASSERT(cursor_pos.Y == cursor_pos_old.Y); + ASSERT_EQ(cursor_pos.X, cursor_pos_old.X); + ASSERT_EQ(cursor_pos.Y, cursor_pos_old.Y); terminate_tty(&tty_out); @@ -1332,9 +1332,9 @@ TEST_IMPL(tty_full_reset) { write_console(&tty_out, buffer); capture_screen(&tty_out, &actual); ASSERT(compare_screen(&tty_out, &actual, &expect)); - ASSERT(get_cursor_size(&tty_out) == saved_cursor_size); - ASSERT(get_cursor_visibility(&tty_out) == saved_cursor_visibility); - ASSERT(actual.si.csbi.srWindow.Top == 0); + ASSERT_EQ(get_cursor_size(&tty_out), saved_cursor_size); + ASSERT_EQ(get_cursor_visibility(&tty_out), saved_cursor_visibility); + ASSERT_OK(actual.si.csbi.srWindow.Top); terminate_tty(&tty_out); @@ -1520,8 +1520,8 @@ TEST_IMPL(tty_escape_sequence_processing) { snprintf(buffer, sizeof(buffer), "%s1;%dH", CSI, UINT16_MAX + 1); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos.X == 1); - ASSERT(cursor_pos.Y == 1); + ASSERT_EQ(1, cursor_pos.X); + ASSERT_EQ(1, cursor_pos.Y); /* Too many argument are ignored */ cursor_pos.X = 1; @@ -1554,18 +1554,18 @@ TEST_IMPL(tty_escape_sequence_processing) { expect.si.width / 2); write_console(&tty_out, buffer); get_cursor_position(&tty_out, &cursor_pos); - ASSERT(cursor_pos.X == 1); - ASSERT(cursor_pos.Y == 1); + ASSERT_EQ(1, cursor_pos.X); + ASSERT_EQ(1, cursor_pos.Y); /* Invalid sequence are ignored */ saved_cursor_size = get_cursor_size(&tty_out); set_cursor_size(&tty_out, CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s 1q", CSI); write_console(&tty_out, buffer); - ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE); + ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_MIDDLE); snprintf(buffer, sizeof(buffer), "%s 1 q", CSI); write_console(&tty_out, buffer); - ASSERT(get_cursor_size(&tty_out) == CURSOR_SIZE_MIDDLE); + ASSERT_EQ(get_cursor_size(&tty_out), CURSOR_SIZE_MIDDLE); set_cursor_size(&tty_out, saved_cursor_size); /* #1874 2. */ diff --git a/test/test-tty.c b/test/test-tty.c index 418ec31e4b5..a9de924ae56 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -57,7 +57,7 @@ TEST_IMPL(tty) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT(handle != INVALID_HANDLE_VALUE); + ASSERT_NE(handle, INVALID_HANDLE_VALUE); ttyin_fd = _open_osfhandle((intptr_t) handle, 0); handle = CreateFileA("conout$", @@ -67,7 +67,7 @@ TEST_IMPL(tty) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT(handle != INVALID_HANDLE_VALUE); + ASSERT_NE(handle, INVALID_HANDLE_VALUE); ttyout_fd = _open_osfhandle((intptr_t) handle, 0); #else /* unix */ @@ -86,26 +86,26 @@ TEST_IMPL(tty) { } #endif - ASSERT(ttyin_fd >= 0); - ASSERT(ttyout_fd >= 0); + ASSERT_GE(ttyin_fd, 0); + ASSERT_GE(ttyout_fd, 0); - ASSERT(UV_UNKNOWN_HANDLE == uv_guess_handle(-1)); + ASSERT_EQ(UV_UNKNOWN_HANDLE, uv_guess_handle(-1)); - ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); - ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyout_fd)); r = uv_tty_init(loop, &tty_in, ttyin_fd, 1); /* Readable. */ - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); r = uv_tty_init(loop, &tty_out, ttyout_fd, 0); /* Writable. */ - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(!uv_is_readable((uv_stream_t*) &tty_out)); ASSERT(uv_is_writable((uv_stream_t*) &tty_out)); r = uv_tty_get_winsize(&tty_out, &width, &height); - ASSERT(r == 0); + ASSERT_OK(r); printf("width=%d height=%d\n", width, height); @@ -121,18 +121,18 @@ TEST_IMPL(tty) { /* Turn on raw mode. */ r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); - ASSERT(r == 0); + ASSERT_OK(r); /* Turn off raw mode. */ r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_NORMAL); - ASSERT(r == 0); + ASSERT_OK(r); /* Calling uv_tty_reset_mode() repeatedly should not clobber errno. */ errno = 0; - ASSERT(0 == uv_tty_reset_mode()); - ASSERT(0 == uv_tty_reset_mode()); - ASSERT(0 == uv_tty_reset_mode()); - ASSERT(0 == errno); + ASSERT_OK(uv_tty_reset_mode()); + ASSERT_OK(uv_tty_reset_mode()); + ASSERT_OK(uv_tty_reset_mode()); + ASSERT_OK(errno); /* TODO check the actual mode! */ @@ -154,11 +154,11 @@ static void tty_raw_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { static void tty_raw_read(uv_stream_t* tty_in, ssize_t nread, const uv_buf_t* buf) { if (nread > 0) { - ASSERT(nread == 1); - ASSERT(buf->base[0] == ' '); + ASSERT_EQ(1, nread ); + ASSERT_EQ(buf->base[0], ' '); uv_close((uv_handle_t*) tty_in, NULL); } else { - ASSERT(nread == 0); + ASSERT_OK(nread); } } @@ -179,25 +179,25 @@ TEST_IMPL(tty_raw) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT(handle != INVALID_HANDLE_VALUE); + ASSERT_NE(handle, INVALID_HANDLE_VALUE); ttyin_fd = _open_osfhandle((intptr_t) handle, 0); - ASSERT(ttyin_fd >= 0); - ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); + ASSERT_GE(ttyin_fd, 0); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); r = uv_tty_init(loop, &tty_in, ttyin_fd, 1); /* Readable. */ - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read); - ASSERT(r == 0); + ASSERT_OK(r); /* Give uv_tty_line_read_thread time to block on ReadConsoleW */ Sleep(100); /* Turn on raw mode. */ r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); - ASSERT(r == 0); + ASSERT_OK(r); /* Write ' ' that should be read in raw mode */ record.EventType = KEY_EVENT; @@ -235,15 +235,15 @@ TEST_IMPL(tty_empty_write) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT(handle != INVALID_HANDLE_VALUE); + ASSERT_NE(handle, INVALID_HANDLE_VALUE); ttyout_fd = _open_osfhandle((intptr_t) handle, 0); - ASSERT(ttyout_fd >= 0); + ASSERT_GE(ttyout_fd, 0); - ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyout_fd)); r = uv_tty_init(loop, &tty_out, ttyout_fd, 0); /* Writable. */ - ASSERT(r == 0); + ASSERT_OK(r); ASSERT(!uv_is_readable((uv_stream_t*) &tty_out)); ASSERT(uv_is_writable((uv_stream_t*) &tty_out)); @@ -251,7 +251,7 @@ TEST_IMPL(tty_empty_write) { bufs[0].base = &dummy[0]; r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &tty_out, NULL); @@ -281,15 +281,15 @@ TEST_IMPL(tty_large_write) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT(handle != INVALID_HANDLE_VALUE); + ASSERT_NE(handle, INVALID_HANDLE_VALUE); ttyout_fd = _open_osfhandle((intptr_t) handle, 0); - ASSERT(ttyout_fd >= 0); + ASSERT_GE(ttyout_fd, 0); - ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyout_fd)); r = uv_tty_init(loop, &tty_out, ttyout_fd, 0); /* Writable. */ - ASSERT(r == 0); + ASSERT_OK(r); memset(dummy, '.', sizeof(dummy) - 1); dummy[sizeof(dummy) - 1] = '\n'; @@ -297,7 +297,7 @@ TEST_IMPL(tty_large_write) { bufs[0] = uv_buf_init(dummy, sizeof(dummy)); r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); - ASSERT(r == 10000); + ASSERT_EQ(10000, r); uv_close((uv_handle_t*) &tty_out, NULL); @@ -321,20 +321,20 @@ TEST_IMPL(tty_raw_cancel) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT(handle != INVALID_HANDLE_VALUE); + ASSERT_NE(handle, INVALID_HANDLE_VALUE); ttyin_fd = _open_osfhandle((intptr_t) handle, 0); - ASSERT(ttyin_fd >= 0); - ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); + ASSERT_GE(ttyin_fd, 0); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ - ASSERT(r == 0); + ASSERT_OK(r); r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_read_stop((uv_stream_t*) &tty_in); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -350,35 +350,35 @@ TEST_IMPL(tty_file) { uv_tty_t tty_wo; int fd; - ASSERT(0 == uv_loop_init(&loop)); + ASSERT_OK(uv_loop_init(&loop)); fd = open("test/fixtures/empty_file", O_RDONLY); if (fd != -1) { - ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1)); - ASSERT(0 == close(fd)); + ASSERT_EQ(UV_EINVAL, uv_tty_init(&loop, &tty, fd, 1)); + ASSERT_OK(close(fd)); /* test EBADF handling */ - ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1)); + ASSERT_EQ(UV_EINVAL, uv_tty_init(&loop, &tty, fd, 1)); } /* Bug on AIX where '/dev/random' returns 1 from isatty() */ #ifndef _AIX fd = open("/dev/random", O_RDONLY); if (fd != -1) { - ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1)); - ASSERT(0 == close(fd)); + ASSERT_EQ(UV_EINVAL, uv_tty_init(&loop, &tty, fd, 1)); + ASSERT_OK(close(fd)); } #endif /* _AIX */ fd = open("/dev/zero", O_RDONLY); if (fd != -1) { - ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1)); - ASSERT(0 == close(fd)); + ASSERT_EQ(UV_EINVAL, uv_tty_init(&loop, &tty, fd, 1)); + ASSERT_OK(close(fd)); } fd = open("/dev/tty", O_RDWR); if (fd != -1) { - ASSERT(0 == uv_tty_init(&loop, &tty, fd, 1)); - ASSERT(0 == close(fd)); /* TODO: it's indeterminate who owns fd now */ + ASSERT_OK(uv_tty_init(&loop, &tty, fd, 1)); + ASSERT_OK(close(fd)); /* TODO: it's indeterminate who owns fd now */ ASSERT(uv_is_readable((uv_stream_t*) &tty)); ASSERT(uv_is_writable((uv_stream_t*) &tty)); uv_close((uv_handle_t*) &tty, NULL); @@ -388,8 +388,8 @@ TEST_IMPL(tty_file) { fd = open("/dev/tty", O_RDONLY); if (fd != -1) { - ASSERT(0 == uv_tty_init(&loop, &tty_ro, fd, 1)); - ASSERT(0 == close(fd)); /* TODO: it's indeterminate who owns fd now */ + ASSERT_OK(uv_tty_init(&loop, &tty_ro, fd, 1)); + ASSERT_OK(close(fd)); /* TODO: it's indeterminate who owns fd now */ ASSERT(uv_is_readable((uv_stream_t*) &tty_ro)); ASSERT(!uv_is_writable((uv_stream_t*) &tty_ro)); uv_close((uv_handle_t*) &tty_ro, NULL); @@ -399,8 +399,8 @@ TEST_IMPL(tty_file) { fd = open("/dev/tty", O_WRONLY); if (fd != -1) { - ASSERT(0 == uv_tty_init(&loop, &tty_wo, fd, 0)); - ASSERT(0 == close(fd)); /* TODO: it's indeterminate who owns fd now */ + ASSERT_OK(uv_tty_init(&loop, &tty_wo, fd, 0)); + ASSERT_OK(close(fd)); /* TODO: it's indeterminate who owns fd now */ ASSERT(!uv_is_readable((uv_stream_t*) &tty_wo)); ASSERT(uv_is_writable((uv_stream_t*) &tty_wo)); uv_close((uv_handle_t*) &tty_wo, NULL); @@ -409,7 +409,7 @@ TEST_IMPL(tty_file) { } - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(&loop); #endif @@ -436,14 +436,14 @@ TEST_IMPL(tty_pty) { uv_loop_t loop; uv_tty_t master_tty, slave_tty; - ASSERT(0 == uv_loop_init(&loop)); + ASSERT_OK(uv_loop_init(&loop)); r = openpty(&master_fd, &slave_fd, NULL, NULL, &w); if (r != 0) RETURN_SKIP("No pty available, skipping."); - ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0)); - ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0)); + ASSERT_OK(uv_tty_init(&loop, &slave_tty, slave_fd, 0)); + ASSERT_OK(uv_tty_init(&loop, &master_tty, master_fd, 0)); ASSERT(uv_is_readable((uv_stream_t*) &slave_tty)); ASSERT(uv_is_writable((uv_stream_t*) &slave_tty)); ASSERT(uv_is_readable((uv_stream_t*) &master_tty)); @@ -451,16 +451,16 @@ TEST_IMPL(tty_pty) { /* Check if the file descriptor was reopened. If it is, * UV_HANDLE_BLOCKING_WRITES (value 0x100000) isn't set on flags. */ - ASSERT(0 == (slave_tty.flags & 0x100000)); + ASSERT_OK((slave_tty.flags & 0x100000)); /* The master_fd of a pty should never be reopened. */ ASSERT(master_tty.flags & 0x100000); - ASSERT(0 == close(slave_fd)); + ASSERT_OK(close(slave_fd)); uv_close((uv_handle_t*) &slave_tty, NULL); - ASSERT(0 == close(master_fd)); + ASSERT_OK(close(master_fd)); uv_close((uv_handle_t*) &master_tty, NULL); - ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(&loop); #endif diff --git a/test/test-udp-alloc-cb-fail.c b/test/test-udp-alloc-cb-fail.c index 073dea97782..ae4bbee325e 100644 --- a/test/test-udp-alloc-cb-fail.c +++ b/test/test-udp-alloc-cb-fail.c @@ -27,7 +27,7 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0) static uv_udp_t server; static uv_udp_t client; @@ -60,7 +60,7 @@ static void cl_alloc_cb(uv_handle_t* handle, static void close_cb(uv_handle_t* handle) { CHECK_HANDLE(handle); - ASSERT(1 == uv_is_closing(handle)); + ASSERT_EQ(1, uv_is_closing(handle)); close_cb_called++; } @@ -71,8 +71,8 @@ static void cl_recv_cb(uv_udp_t* handle, const struct sockaddr* addr, unsigned flags) { CHECK_HANDLE(handle); - ASSERT(flags == 0); - ASSERT(nread == UV_ENOBUFS); + ASSERT_OK(flags); + ASSERT_EQ(nread, UV_ENOBUFS); cl_recv_cb_called++; @@ -84,11 +84,11 @@ static void cl_send_cb(uv_udp_send_t* req, int status) { int r; ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); CHECK_HANDLE(req->handle); r = uv_udp_recv_start(req->handle, cl_alloc_cb, cl_recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); cl_send_cb_called++; } @@ -96,7 +96,7 @@ static void cl_send_cb(uv_udp_send_t* req, int status) { static void sv_send_cb(uv_udp_send_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); CHECK_HANDLE(req->handle); uv_close((uv_handle_t*) req->handle, close_cb); @@ -126,21 +126,21 @@ static void sv_recv_cb(uv_udp_t* handle, } CHECK_HANDLE(handle); - ASSERT(flags == 0); + ASSERT_OK(flags); ASSERT_NOT_NULL(addr); - ASSERT(nread == 4); + ASSERT_EQ(4, nread); ASSERT(!memcmp("PING", rcvbuf->base, nread)); r = uv_udp_recv_stop(handle); - ASSERT(r == 0); + ASSERT_OK(r); req = malloc(sizeof *req); ASSERT_NOT_NULL(req); sndbuf = uv_buf_init("PONG", 4); r = uv_udp_send(req, handle, &sndbuf, 1, addr, sv_send_cb); - ASSERT(r == 0); + ASSERT_OK(r); sv_recv_cb_called++; } @@ -152,21 +152,21 @@ TEST_IMPL(udp_alloc_cb_fail) { uv_buf_t buf; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_recv_start(&server, sv_alloc_cb, sv_recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); buf = uv_buf_init("PING", 4); r = uv_udp_send(&req, @@ -175,21 +175,21 @@ TEST_IMPL(udp_alloc_cb_fail) { 1, (const struct sockaddr*) &addr, cl_send_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); - ASSERT(cl_send_cb_called == 0); - ASSERT(cl_recv_cb_called == 0); - ASSERT(sv_send_cb_called == 0); - ASSERT(sv_recv_cb_called == 0); + ASSERT_OK(close_cb_called); + ASSERT_OK(cl_send_cb_called); + ASSERT_OK(cl_recv_cb_called); + ASSERT_OK(sv_send_cb_called); + ASSERT_OK(sv_recv_cb_called); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(cl_send_cb_called == 1); - ASSERT(cl_recv_cb_called == 1); - ASSERT(sv_send_cb_called == 1); - ASSERT(sv_recv_cb_called == 1); - ASSERT(close_cb_called == 2); + ASSERT_EQ(1, cl_send_cb_called); + ASSERT_EQ(1, cl_recv_cb_called); + ASSERT_EQ(1, sv_send_cb_called); + ASSERT_EQ(1, sv_recv_cb_called); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-bind.c b/test/test-udp-bind.c index 200cdc7c927..519f9b02fa2 100644 --- a/test/test-udp-bind.c +++ b/test/test-udp-bind.c @@ -33,27 +33,27 @@ TEST_IMPL(udp_bind) { uv_udp_t h1, h2; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); loop = uv_default_loop(); r = uv_udp_init(loop, &h1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_init(loop, &h2); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&h1, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&h2, (const struct sockaddr*) &addr, 0); - ASSERT(r == UV_EADDRINUSE); + ASSERT_EQ(r, UV_EADDRINUSE); uv_close((uv_handle_t*) &h1, NULL); uv_close((uv_handle_t*) &h2, NULL); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -66,27 +66,27 @@ TEST_IMPL(udp_bind_reuseaddr) { uv_udp_t h1, h2; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); loop = uv_default_loop(); r = uv_udp_init(loop, &h1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_init(loop, &h2); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&h1, (const struct sockaddr*) &addr, UV_UDP_REUSEADDR); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&h2, (const struct sockaddr*) &addr, UV_UDP_REUSEADDR); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &h1, NULL); uv_close((uv_handle_t*) &h2, NULL); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-udp-connect.c b/test/test-udp-connect.c index c1e4064b94e..88314acc69b 100644 --- a/test/test-udp-connect.c +++ b/test/test-udp-connect.c @@ -27,7 +27,7 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0) static uv_udp_t server; static uv_udp_t client; @@ -45,7 +45,7 @@ static void alloc_cb(uv_handle_t* handle, uv_buf_t* buf) { static char slab[65536]; CHECK_HANDLE(handle); - ASSERT(suggested_size <= sizeof(slab)); + ASSERT_LE(suggested_size, sizeof(slab)); buf->base = slab; buf->len = sizeof(slab); } @@ -62,19 +62,19 @@ static void cl_send_cb(uv_udp_send_t* req, int status) { int r; ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); CHECK_HANDLE(req->handle); if (++cl_send_cb_called == 1) { uv_udp_connect(&client, NULL); r = uv_udp_send(req, &client, &buf, 1, NULL, cl_send_cb); - ASSERT(r == UV_EDESTADDRREQ); + ASSERT_EQ(r, UV_EDESTADDRREQ); r = uv_udp_send(req, &client, &buf, 1, (const struct sockaddr*) &lo_addr, cl_send_cb); - ASSERT(r == 0); + ASSERT_OK(r); } } @@ -86,9 +86,9 @@ static void sv_recv_cb(uv_udp_t* handle, const struct sockaddr* addr, unsigned flags) { if (nread > 0) { - ASSERT(nread == 4); + ASSERT_EQ(4, nread); ASSERT_NOT_NULL(addr); - ASSERT(memcmp("EXIT", rcvbuf->base, nread) == 0); + ASSERT_OK(memcmp("EXIT", rcvbuf->base, nread)); if (++sv_recv_cb_called == 4) { uv_close((uv_handle_t*) &server, close_cb); uv_close((uv_handle_t*) &client, close_cb); @@ -107,89 +107,89 @@ TEST_IMPL(udp_connect) { int r; int addrlen; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &lo_addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &lo_addr)); r = uv_udp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&server, (const struct sockaddr*) &lo_addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); buf = uv_buf_init("EXIT", 4); /* connect() to INADDR_ANY fails on Windows with WSAEADDRNOTAVAIL */ - ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &tmp_addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &tmp_addr)); r = uv_udp_connect(&client, (const struct sockaddr*) &tmp_addr); #ifdef _WIN32 ASSERT_EQ(r, UV_EADDRNOTAVAIL); #else - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_connect(&client, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); #endif - ASSERT(0 == uv_ip4_addr("8.8.8.8", TEST_PORT, &ext_addr)); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &lo_addr)); + ASSERT_OK(uv_ip4_addr("8.8.8.8", TEST_PORT, &ext_addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &lo_addr)); r = uv_udp_connect(&client, (const struct sockaddr*) &lo_addr); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_connect(&client, (const struct sockaddr*) &ext_addr); - ASSERT(r == UV_EISCONN); + ASSERT_EQ(r, UV_EISCONN); addrlen = sizeof(tmp_addr); r = uv_udp_getpeername(&client, (struct sockaddr*) &tmp_addr, &addrlen); - ASSERT(r == 0); + ASSERT_OK(r); /* To send messages in connected UDP sockets addr must be NULL */ r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &lo_addr); - ASSERT(r == UV_EISCONN); + ASSERT_EQ(r, UV_EISCONN); r = uv_udp_try_send(&client, &buf, 1, NULL); - ASSERT(r == 4); + ASSERT_EQ(4, r); r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &ext_addr); - ASSERT(r == UV_EISCONN); + ASSERT_EQ(r, UV_EISCONN); r = uv_udp_connect(&client, NULL); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_connect(&client, NULL); - ASSERT(r == UV_ENOTCONN); + ASSERT_EQ(r, UV_ENOTCONN); addrlen = sizeof(tmp_addr); r = uv_udp_getpeername(&client, (struct sockaddr*) &tmp_addr, &addrlen); - ASSERT(r == UV_ENOTCONN); + ASSERT_EQ(r, UV_ENOTCONN); /* To send messages in disconnected UDP sockets addr must be set */ r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &lo_addr); - ASSERT(r == 4); + ASSERT_EQ(4, r); r = uv_udp_try_send(&client, &buf, 1, NULL); - ASSERT(r == UV_EDESTADDRREQ); + ASSERT_EQ(r, UV_EDESTADDRREQ); r = uv_udp_connect(&client, (const struct sockaddr*) &lo_addr); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_send(&req, &client, &buf, 1, (const struct sockaddr*) &lo_addr, cl_send_cb); - ASSERT(r == UV_EISCONN); + ASSERT_EQ(r, UV_EISCONN); r = uv_udp_send(&req, &client, &buf, 1, NULL, cl_send_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 2); - ASSERT(sv_recv_cb_called == 4); - ASSERT(cl_send_cb_called == 2); + ASSERT_EQ(2, close_cb_called); + ASSERT_EQ(4, sv_recv_cb_called); + ASSERT_EQ(2, cl_send_cb_called); - ASSERT(client.send_queue_size == 0); - ASSERT(server.send_queue_size == 0); + ASSERT_OK(client.send_queue_size); + ASSERT_OK(server.send_queue_size); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-connect6.c b/test/test-udp-connect6.c index 076d8d77b92..bbc4033c55f 100644 --- a/test/test-udp-connect6.c +++ b/test/test-udp-connect6.c @@ -27,7 +27,7 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0) static uv_udp_t server; static uv_udp_t client; @@ -62,7 +62,7 @@ static void cl_send_cb(uv_udp_send_t* req, int status) { int r; ASSERT_NOT_NULL(req); - ASSERT_EQ(status, 0); + ASSERT_OK(status); CHECK_HANDLE(req->handle); if (++cl_send_cb_called == 1) { uv_udp_connect(&client, NULL); @@ -74,7 +74,7 @@ static void cl_send_cb(uv_udp_send_t* req, int status) { 1, (const struct sockaddr*) &lo_addr, cl_send_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } } @@ -86,9 +86,9 @@ static void sv_recv_cb(uv_udp_t* handle, const struct sockaddr* addr, unsigned flags) { if (nread > 0) { - ASSERT_EQ(nread, 4); + ASSERT_EQ(4, nread); ASSERT_NOT_NULL(addr); - ASSERT_EQ(memcmp("EXIT", rcvbuf->base, nread), 0); + ASSERT_OK(memcmp("EXIT", rcvbuf->base, nread)); if (++sv_recv_cb_called == 4) { uv_close((uv_handle_t*) &server, close_cb); uv_close((uv_handle_t*) &client, close_cb); @@ -110,55 +110,55 @@ TEST_IMPL(udp_connect6) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); - ASSERT_EQ(0, uv_ip6_addr("::", TEST_PORT, &lo_addr)); + ASSERT_OK(uv_ip6_addr("::", TEST_PORT, &lo_addr)); r = uv_udp_init(uv_default_loop(), &server); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_bind(&server, (const struct sockaddr*) &lo_addr, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_init(uv_default_loop(), &client); - ASSERT_EQ(r, 0); + ASSERT_OK(r); buf = uv_buf_init("EXIT", 4); /* connect() to INADDR_ANY fails on Windows wih WSAEADDRNOTAVAIL */ - ASSERT_EQ(0, uv_ip6_addr("::", TEST_PORT, &tmp_addr)); + ASSERT_OK(uv_ip6_addr("::", TEST_PORT, &tmp_addr)); r = uv_udp_connect(&client, (const struct sockaddr*) &tmp_addr); #ifdef _WIN32 ASSERT_EQ(r, UV_EADDRNOTAVAIL); #else - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_connect(&client, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); #endif - ASSERT_EQ(0, uv_ip6_addr("2001:4860:4860::8888", TEST_PORT, &ext_addr)); - ASSERT_EQ(0, uv_ip6_addr("::1", TEST_PORT, &lo_addr)); + ASSERT_OK(uv_ip6_addr("2001:4860:4860::8888", TEST_PORT, &ext_addr)); + ASSERT_OK(uv_ip6_addr("::1", TEST_PORT, &lo_addr)); r = uv_udp_connect(&client, (const struct sockaddr*) &lo_addr); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_connect(&client, (const struct sockaddr*) &ext_addr); ASSERT_EQ(r, UV_EISCONN); addrlen = sizeof(tmp_addr); r = uv_udp_getpeername(&client, (struct sockaddr*) &tmp_addr, &addrlen); - ASSERT_EQ(r, 0); + ASSERT_OK(r); /* To send messages in connected UDP sockets addr must be NULL */ r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &lo_addr); ASSERT_EQ(r, UV_EISCONN); r = uv_udp_try_send(&client, &buf, 1, NULL); - ASSERT_EQ(r, 4); + ASSERT_EQ(4, r); r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &ext_addr); ASSERT_EQ(r, UV_EISCONN); r = uv_udp_connect(&client, NULL); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_connect(&client, NULL); ASSERT_EQ(r, UV_ENOTCONN); @@ -168,13 +168,13 @@ TEST_IMPL(udp_connect6) { /* To send messages in disconnected UDP sockets addr must be set */ r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &lo_addr); - ASSERT_EQ(r, 4); + ASSERT_EQ(4, r); r = uv_udp_try_send(&client, &buf, 1, NULL); ASSERT_EQ(r, UV_EDESTADDRREQ); r = uv_udp_connect(&client, (const struct sockaddr*) &lo_addr); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_send(&req, &client, &buf, @@ -183,16 +183,16 @@ TEST_IMPL(udp_connect6) { cl_send_cb); ASSERT_EQ(r, UV_EISCONN); r = uv_udp_send(&req, &client, &buf, 1, NULL, cl_send_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT_EQ(close_cb_called, 2); - ASSERT_EQ(sv_recv_cb_called, 4); - ASSERT_EQ(cl_send_cb_called, 2); + ASSERT_EQ(2, close_cb_called); + ASSERT_EQ(4, sv_recv_cb_called); + ASSERT_EQ(2, cl_send_cb_called); - ASSERT_EQ(client.send_queue_size, 0); - ASSERT_EQ(server.send_queue_size, 0); + ASSERT_OK(client.send_queue_size); + ASSERT_OK(server.send_queue_size); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-create-socket-early.c b/test/test-udp-create-socket-early.c index f51e275ba1e..4111d6ef01d 100644 --- a/test/test-udp-create-socket-early.c +++ b/test/test-udp-create-socket-early.c @@ -38,32 +38,32 @@ TEST_IMPL(udp_create_early) { uv_os_fd_t fd; int r, namelen; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fileno((const uv_handle_t*) &client, &fd); - ASSERT(r == 0); - ASSERT(fd != INVALID_FD); + ASSERT_OK(r); + ASSERT_NE(fd, INVALID_FD); /* Windows returns WSAEINVAL if the socket is not bound */ #ifndef _WIN32 namelen = sizeof sockname; r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen); - ASSERT(r == 0); - ASSERT(sockname.sin_family == AF_INET); + ASSERT_OK(r); + ASSERT_EQ(sockname.sin_family, AF_INET); #endif r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); namelen = sizeof sockname; r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen); - ASSERT(r == 0); - ASSERT(memcmp(&addr.sin_addr, - &sockname.sin_addr, - sizeof(addr.sin_addr)) == 0); + ASSERT_OK(r); + ASSERT_OK(memcmp(&addr.sin_addr, + &sockname.sin_addr, + sizeof(addr.sin_addr))); uv_close((uv_handle_t*) &client, NULL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); @@ -82,14 +82,14 @@ TEST_IMPL(udp_create_early_bad_bind) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET6); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_fileno((const uv_handle_t*) &client, &fd); - ASSERT(r == 0); - ASSERT(fd != INVALID_FD); + ASSERT_OK(r); + ASSERT_NE(fd, INVALID_FD); /* Windows returns WSAEINVAL if the socket is not bound */ #ifndef _WIN32 @@ -98,16 +98,16 @@ TEST_IMPL(udp_create_early_bad_bind) { struct sockaddr_in6 sockname; namelen = sizeof sockname; r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen); - ASSERT(r == 0); - ASSERT(sockname.sin6_family == AF_INET6); + ASSERT_OK(r); + ASSERT_EQ(sockname.sin6_family, AF_INET6); } #endif r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); #if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MSYS__) - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); #else - ASSERT(r == UV_EFAULT); + ASSERT_EQ(r, UV_EFAULT); #endif uv_close((uv_handle_t*) &client, NULL); @@ -123,10 +123,10 @@ TEST_IMPL(udp_create_early_bad_domain) { int r; r = uv_udp_init_ex(uv_default_loop(), &client, 47); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); r = uv_udp_init_ex(uv_default_loop(), &client, 1024); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); diff --git a/test/test-udp-dgram-too-big.c b/test/test-udp-dgram-too-big.c index 9db8b47be18..8fae756e5c4 100644 --- a/test/test-udp-dgram-too-big.c +++ b/test/test-udp-dgram-too-big.c @@ -27,10 +27,10 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &handle_) + ASSERT_PTR_EQ((uv_udp_t*)(handle), &handle_) #define CHECK_REQ(req) \ - ASSERT((req) == &req_); + ASSERT_PTR_EQ((req), &req_); static uv_udp_t handle_; static uv_udp_send_t req_; @@ -49,7 +49,7 @@ static void send_cb(uv_udp_send_t* req, int status) { CHECK_REQ(req); CHECK_HANDLE(req->handle); - ASSERT(status == UV_EMSGSIZE); + ASSERT_EQ(status, UV_EMSGSIZE); uv_close((uv_handle_t*)req->handle, close_cb); send_cb_called++; @@ -65,10 +65,10 @@ TEST_IMPL(udp_dgram_too_big) { memset(dgram, 42, sizeof dgram); /* silence valgrind */ r = uv_udp_init(uv_default_loop(), &handle_); - ASSERT(r == 0); + ASSERT_OK(r); buf = uv_buf_init(dgram, sizeof dgram); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_udp_send(&req_, &handle_, @@ -76,15 +76,15 @@ TEST_IMPL(udp_dgram_too_big) { 1, (const struct sockaddr*) &addr, send_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); - ASSERT(send_cb_called == 0); + ASSERT_OK(close_cb_called); + ASSERT_OK(send_cb_called); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(send_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, send_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-ipv6.c b/test/test-udp-ipv6.c index ae55cd01b0b..8ad80b9b5a9 100644 --- a/test/test-udp-ipv6.c +++ b/test/test-udp-ipv6.c @@ -30,13 +30,13 @@ #include #endif -#define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &server \ - || (uv_udp_t*)(handle) == &client \ - || (uv_timer_t*)(handle) == &timeout) +#define CHECK_HANDLE(handle) \ + ASSERT_NE((uv_udp_t*)(handle) == &server \ + || (uv_udp_t*)(handle) == &client \ + || (uv_timer_t*)(handle) == &timeout, 0) #define CHECK_REQ(req) \ - ASSERT((req) == &req_); + ASSERT_PTR_EQ((req), &req_); static uv_udp_t client; static uv_udp_t server; @@ -81,7 +81,7 @@ static void close_cb(uv_handle_t* handle) { static void send_cb(uv_udp_send_t* req, int status) { CHECK_REQ(req); CHECK_HANDLE(req->handle); - ASSERT(status == 0); + ASSERT_OK(status); send_cb_called++; } @@ -92,7 +92,7 @@ static int is_from_client(const struct sockaddr* addr) { /* Debugging output, and filter out unwanted network traffic */ if (addr != NULL) { - ASSERT(addr->sa_family == AF_INET6); + ASSERT_EQ(addr->sa_family, AF_INET6); addr6 = (struct sockaddr_in6*) addr; r = uv_inet_ntop(addr->sa_family, &addr6->sin6_addr, dst, sizeof(dst)); if (r == 0) @@ -129,7 +129,7 @@ static void ipv6_recv_ok(uv_udp_t* handle, if (!is_from_client(addr) || (nread == 0 && addr == NULL)) return; - ASSERT(nread == 9); + ASSERT_EQ(9, nread); ASSERT(!memcmp(buf->base, data, 9)); recv_cb_called++; } @@ -151,31 +151,39 @@ static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) { char dst[256]; int r; - ASSERT(0 == uv_ip6_addr("::0", TEST_PORT, &addr6)); + ASSERT_OK(uv_ip6_addr("::0", TEST_PORT, &addr6)); r = uv_udp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&server, (const struct sockaddr*) &addr6, bind_flags); - ASSERT(r == 0); + ASSERT_OK(r); addr6_len = sizeof(addr6); - ASSERT(uv_udp_getsockname(&server, (struct sockaddr*) &addr6, &addr6_len) == 0); - ASSERT(uv_inet_ntop(addr6.sin6_family, &addr6.sin6_addr, dst, sizeof(dst)) == 0); + ASSERT_OK(uv_udp_getsockname(&server, + (struct sockaddr*) &addr6, + &addr6_len)); + ASSERT_OK(uv_inet_ntop(addr6.sin6_family, + &addr6.sin6_addr, + dst, + sizeof(dst))); printf("on [%.*s]:%d\n", (int) sizeof(dst), dst, addr6.sin6_port); r = uv_udp_recv_start(&server, alloc_cb, recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT(uv_inet_ntop(addr.sin_family, &addr.sin_addr, dst, sizeof(dst)) == 0); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_inet_ntop(addr.sin_family, &addr.sin_addr, dst, sizeof(dst))); printf("to [%.*s]:%d\n", (int) sizeof(dst), dst, addr.sin_port); /* Create some unique data to send */ - ASSERT(9 == snprintf(data, sizeof(data), "PING%5u", uv_os_getpid() & 0xFFFF)); + ASSERT_EQ(9, snprintf(data, + sizeof(data), + "PING%5u", + uv_os_getpid() & 0xFFFF)); buf = uv_buf_init(data, 9); printf("sending %s\n", data); @@ -185,27 +193,27 @@ static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) { 1, (const struct sockaddr*) &addr, send_cb); - ASSERT(r == 0); + ASSERT_OK(r); addr_len = sizeof(addr); - ASSERT(uv_udp_getsockname(&client, (struct sockaddr*) &addr, &addr_len) == 0); - ASSERT(uv_inet_ntop(addr.sin_family, &addr.sin_addr, dst, sizeof(dst)) == 0); + ASSERT_OK(uv_udp_getsockname(&client, (struct sockaddr*) &addr, &addr_len)); + ASSERT_OK(uv_inet_ntop(addr.sin_family, &addr.sin_addr, dst, sizeof(dst))); printf("from [%.*s]:%d\n", (int) sizeof(dst), dst, addr.sin_port); client_port = addr.sin_port; r = uv_timer_init(uv_default_loop(), &timeout); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timeout, timeout_cb, 500, 0); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); - ASSERT(send_cb_called == 0); - ASSERT(recv_cb_called == 0); + ASSERT_OK(close_cb_called); + ASSERT_OK(send_cb_called); + ASSERT_OK(recv_cb_called); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 3); + ASSERT_EQ(3, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); } @@ -231,8 +239,8 @@ TEST_IMPL(udp_dual_stack) { printf("recv_cb_called %d\n", recv_cb_called); printf("send_cb_called %d\n", send_cb_called); - ASSERT(recv_cb_called == 1); - ASSERT(send_cb_called == 1); + ASSERT_EQ(1, recv_cb_called); + ASSERT_EQ(1, send_cb_called); return 0; } @@ -244,8 +252,8 @@ TEST_IMPL(udp_ipv6_only) { do_test(ipv6_recv_fail, UV_UDP_IPV6ONLY); - ASSERT(recv_cb_called == 0); - ASSERT(send_cb_called == 1); + ASSERT_OK(recv_cb_called); + ASSERT_EQ(1, send_cb_called); return 0; } diff --git a/test/test-udp-mmsg.c b/test/test-udp-mmsg.c index c37343f8c9f..c0e000b9d92 100644 --- a/test/test-udp-mmsg.c +++ b/test/test-udp-mmsg.c @@ -27,7 +27,7 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &recver || (uv_udp_t*)(handle) == &sender) + ASSERT_NE((uv_udp_t*)(handle) == &recver || (uv_udp_t*)(handle) == &sender, 0) #define BUFFER_MULTIPLIER 20 #define MAX_DGRAM_SIZE (64 * 1024) @@ -77,7 +77,7 @@ static void recv_cb(uv_udp_t* handle, /* free and return if this is a mmsg free-only callback invocation */ if (flags & UV_UDP_MMSG_FREE) { - ASSERT_EQ(nread, 0); + ASSERT_OK(nread); ASSERT_NULL(addr); free(rcvbuf->base); return; @@ -87,7 +87,7 @@ static void recv_cb(uv_udp_t* handle, /* There can be no more available data for the time being. */ ASSERT_NULL(addr); } else { - ASSERT_EQ(nread, 4); + ASSERT_EQ(4, nread); ASSERT_NOT_NULL(addr); ASSERT_MEM_EQ("PING", rcvbuf->base, nread); received_datagrams++; @@ -110,31 +110,31 @@ TEST_IMPL(udp_mmsg) { uv_buf_t buf; int i; - ASSERT_EQ(0, uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); - ASSERT_EQ(0, uv_udp_init_ex(uv_default_loop(), &recver, - AF_UNSPEC | UV_UDP_RECVMMSG)); + ASSERT_OK(uv_udp_init_ex(uv_default_loop(), &recver, + AF_UNSPEC | UV_UDP_RECVMMSG)); - ASSERT_EQ(0, uv_udp_bind(&recver, (const struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_udp_bind(&recver, (const struct sockaddr*) &addr, 0)); - ASSERT_EQ(0, uv_udp_recv_start(&recver, alloc_cb, recv_cb)); + ASSERT_OK(uv_udp_recv_start(&recver, alloc_cb, recv_cb)); - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT_EQ(0, uv_udp_init(uv_default_loop(), &sender)); + ASSERT_OK(uv_udp_init(uv_default_loop(), &sender)); buf = uv_buf_init("PING", 4); for (i = 0; i < NUM_SENDS; i++) { ASSERT_EQ(4, uv_udp_try_send(&sender, &buf, 1, (const struct sockaddr*) &addr)); } - ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - ASSERT_EQ(close_cb_called, 2); + ASSERT_EQ(2, close_cb_called); ASSERT_EQ(received_datagrams, NUM_SENDS); - ASSERT_EQ(sender.send_queue_size, 0); - ASSERT_EQ(recver.send_queue_size, 0); + ASSERT_OK(sender.send_queue_size); + ASSERT_OK(recver.send_queue_size); printf("%d allocs for %d recvs\n", alloc_cb_called, recv_cb_called); diff --git a/test/test-udp-multicast-interface.c b/test/test-udp-multicast-interface.c index 447d3487f5c..2c558c8b0f1 100644 --- a/test/test-udp-multicast-interface.c +++ b/test/test-udp-multicast-interface.c @@ -27,7 +27,7 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0) static uv_udp_t server; static uv_udp_t client; @@ -65,17 +65,17 @@ TEST_IMPL(udp_multicast_interface) { struct sockaddr_in addr; struct sockaddr_in baddr; - ASSERT(0 == uv_ip4_addr("239.255.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("239.255.0.1", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &baddr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", 0, &baddr)); r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_set_multicast_interface(&server, "0.0.0.0"); - ASSERT(r == 0); + ASSERT_OK(r); /* server sends "PING" */ buf = uv_buf_init("PING", 4); @@ -85,19 +85,19 @@ TEST_IMPL(udp_multicast_interface) { 1, (const struct sockaddr*)&addr, sv_send_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); - ASSERT(sv_send_cb_called == 0); + ASSERT_OK(close_cb_called); + ASSERT_OK(sv_send_cb_called); /* run the loop till all events are processed */ uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(sv_send_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, sv_send_cb_called); + ASSERT_EQ(1, close_cb_called); - ASSERT(client.send_queue_size == 0); - ASSERT(server.send_queue_size == 0); + ASSERT_OK(client.send_queue_size); + ASSERT_OK(server.send_queue_size); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-multicast-interface6.c b/test/test-udp-multicast-interface6.c index 1d40aefa8cb..54fc87ed4e9 100644 --- a/test/test-udp-multicast-interface6.c +++ b/test/test-udp-multicast-interface6.c @@ -27,7 +27,7 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0) static uv_udp_t server; static uv_udp_t client; @@ -44,7 +44,7 @@ static void close_cb(uv_handle_t* handle) { static void sv_send_cb(uv_udp_send_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); CHECK_HANDLE(req->handle); sv_send_cb_called++; @@ -68,21 +68,21 @@ TEST_IMPL(udp_multicast_interface6) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); - ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip6_addr("::1", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_ip6_addr("::", 0, &baddr)); + ASSERT_OK(uv_ip6_addr("::", 0, &baddr)); r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0); - ASSERT(r == 0); + ASSERT_OK(r); #if defined(__APPLE__) || defined(__FreeBSD__) r = uv_udp_set_multicast_interface(&server, "::1%lo0"); #else r = uv_udp_set_multicast_interface(&server, NULL); #endif - ASSERT(r == 0); + ASSERT_OK(r); /* server sends "PING" */ buf = uv_buf_init("PING", 4); @@ -92,16 +92,16 @@ TEST_IMPL(udp_multicast_interface6) { 1, (const struct sockaddr*)&addr, sv_send_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); - ASSERT(sv_send_cb_called == 0); + ASSERT_OK(close_cb_called); + ASSERT_OK(sv_send_cb_called); /* run the loop till all events are processed */ uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(sv_send_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, sv_send_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-multicast-join.c b/test/test-udp-multicast-join.c index dddcea4662f..7e8fbe39f08 100644 --- a/test/test-udp-multicast-join.c +++ b/test/test-udp-multicast-join.c @@ -27,7 +27,7 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0) #define MULTICAST_ADDR "239.255.0.1" @@ -47,7 +47,7 @@ static void alloc_cb(uv_handle_t* handle, uv_buf_t* buf) { static char slab[65536]; CHECK_HANDLE(handle); - ASSERT(suggested_size <= sizeof(slab)); + ASSERT_LE(suggested_size, sizeof(slab)); buf->base = slab; buf->len = sizeof(slab); } @@ -61,7 +61,7 @@ static void close_cb(uv_handle_t* handle) { static void sv_send_cb(uv_udp_send_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); CHECK_HANDLE(req->handle); sv_send_cb_called++; @@ -77,7 +77,7 @@ static int do_send(uv_udp_send_t* send_req) { buf = uv_buf_init("PING", 4); - ASSERT(0 == uv_ip4_addr(MULTICAST_ADDR, TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr(MULTICAST_ADDR, TEST_PORT, &addr)); /* client sends "PING" */ return uv_udp_send(send_req, @@ -95,7 +95,7 @@ static void cl_recv_cb(uv_udp_t* handle, const struct sockaddr* addr, unsigned flags) { CHECK_HANDLE(handle); - ASSERT(flags == 0); + ASSERT_OK(flags); if (nread < 0) { ASSERT(0 && "unexpected error"); @@ -108,7 +108,7 @@ static void cl_recv_cb(uv_udp_t* handle, } ASSERT_NOT_NULL(addr); - ASSERT(nread == 4); + ASSERT_EQ(4, nread); ASSERT(!memcmp("PING", buf->base, nread)); cl_recv_cb_called++; @@ -121,18 +121,18 @@ static void cl_recv_cb(uv_udp_t* handle, char source_addr[64]; r = uv_ip4_name((const struct sockaddr_in*)addr, source_addr, sizeof(source_addr)); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_set_membership(&server, MULTICAST_ADDR, NULL, UV_LEAVE_GROUP); - ASSERT(r == 0); + ASSERT_OK(r); #if !defined(__OpenBSD__) && !defined(__NetBSD__) r = uv_udp_set_source_membership(&server, MULTICAST_ADDR, NULL, source_addr, UV_JOIN_GROUP); - ASSERT(r == 0); + ASSERT_OK(r); #endif r = do_send(&req_ss); - ASSERT(r == 0); + ASSERT_OK(r); } } @@ -144,40 +144,40 @@ TEST_IMPL(udp_multicast_join) { int r; struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); /* bind to the desired port */ r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); /* join the multicast channel */ r = uv_udp_set_membership(&server, MULTICAST_ADDR, NULL, UV_JOIN_GROUP); if (r == UV_ENODEV) RETURN_SKIP("No multicast support."); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_recv_start(&server, alloc_cb, cl_recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = do_send(&req); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); - ASSERT(cl_recv_cb_called == 0); - ASSERT(sv_send_cb_called == 0); + ASSERT_OK(close_cb_called); + ASSERT_OK(cl_recv_cb_called); + ASSERT_OK(sv_send_cb_called); /* run the loop till all events are processed */ uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(cl_recv_cb_called == 2); - ASSERT(sv_send_cb_called == 2); - ASSERT(close_cb_called == 2); + ASSERT_EQ(2, cl_recv_cb_called); + ASSERT_EQ(2, sv_send_cb_called); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-multicast-join6.c b/test/test-udp-multicast-join6.c index d5262b6a9a0..11efb0a6f67 100644 --- a/test/test-udp-multicast-join6.c +++ b/test/test-udp-multicast-join6.c @@ -28,7 +28,7 @@ #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0) #if defined(__APPLE__) || \ defined(_AIX) || \ @@ -58,7 +58,7 @@ static void alloc_cb(uv_handle_t* handle, uv_buf_t* buf) { static char slab[65536]; CHECK_HANDLE(handle); - ASSERT(suggested_size <= sizeof(slab)); + ASSERT_LE(suggested_size, sizeof(slab)); buf->base = slab; buf->len = sizeof(slab); } @@ -72,7 +72,7 @@ static void close_cb(uv_handle_t* handle) { static void sv_send_cb(uv_udp_send_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); CHECK_HANDLE(req->handle); sv_send_cb_called++; @@ -88,7 +88,7 @@ static int do_send(uv_udp_send_t* send_req) { buf = uv_buf_init("PING", 4); - ASSERT(0 == uv_ip6_addr(MULTICAST_ADDR, TEST_PORT, &addr)); + ASSERT_OK(uv_ip6_addr(MULTICAST_ADDR, TEST_PORT, &addr)); /* client sends "PING" */ return uv_udp_send(send_req, @@ -106,7 +106,7 @@ static void cl_recv_cb(uv_udp_t* handle, const struct sockaddr* addr, unsigned flags) { CHECK_HANDLE(handle); - ASSERT(flags == 0); + ASSERT_OK(flags); if (nread < 0) { ASSERT(0 && "unexpected error"); @@ -119,7 +119,7 @@ static void cl_recv_cb(uv_udp_t* handle, } ASSERT_NOT_NULL(addr); - ASSERT(nread == 4); + ASSERT_EQ(4, nread); ASSERT(!memcmp("PING", buf->base, nread)); cl_recv_cb_called++; @@ -132,16 +132,16 @@ static void cl_recv_cb(uv_udp_t* handle, char source_addr[64]; r = uv_ip6_name((const struct sockaddr_in6*)addr, source_addr, sizeof(source_addr)); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_set_membership(&server, MULTICAST_ADDR, INTERFACE_ADDR, UV_LEAVE_GROUP); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_set_source_membership(&server, MULTICAST_ADDR, INTERFACE_ADDR, source_addr, UV_JOIN_GROUP); - ASSERT(r == 0); + ASSERT_OK(r); r = do_send(&req_ss); - ASSERT(r == 0); + ASSERT_OK(r); } } @@ -172,17 +172,17 @@ TEST_IMPL(udp_multicast_join6) { if (!can_ipv6_external()) RETURN_SKIP("No external IPv6 interface available"); - ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr)); + ASSERT_OK(uv_ip6_addr("::", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); /* bind to the desired port */ r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_set_membership(&server, MULTICAST_ADDR, INTERFACE_ADDR, UV_JOIN_GROUP); if (r == UV_ENODEV) { @@ -190,28 +190,28 @@ TEST_IMPL(udp_multicast_join6) { RETURN_SKIP("No ipv6 multicast route"); } - ASSERT(r == 0); + ASSERT_OK(r); /* TODO(gengjiawen): Fix test on QEMU. */ #if defined(__QEMU__) RETURN_SKIP("Test does not currently work in QEMU"); #endif r = uv_udp_recv_start(&server, alloc_cb, cl_recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = do_send(&req); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); - ASSERT(cl_recv_cb_called == 0); - ASSERT(sv_send_cb_called == 0); + ASSERT_OK(close_cb_called); + ASSERT_OK(cl_recv_cb_called); + ASSERT_OK(sv_send_cb_called); /* run the loop till all events are processed */ uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(cl_recv_cb_called == 2); - ASSERT(sv_send_cb_called == 2); - ASSERT(close_cb_called == 2); + ASSERT_EQ(2, cl_recv_cb_called); + ASSERT_EQ(2, sv_send_cb_called); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-multicast-ttl.c b/test/test-udp-multicast-ttl.c index 9aa5bb9147f..50bc54a066f 100644 --- a/test/test-udp-multicast-ttl.c +++ b/test/test-udp-multicast-ttl.c @@ -27,7 +27,7 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0) static uv_udp_t server; static uv_udp_t client; @@ -60,34 +60,34 @@ TEST_IMPL(udp_multicast_ttl) { struct sockaddr_in addr; r = uv_udp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", 0, &addr)); r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_set_multicast_ttl(&server, 32); - ASSERT(r == 0); + ASSERT_OK(r); /* server sends "PING" */ buf = uv_buf_init("PING", 4); - ASSERT(0 == uv_ip4_addr("239.255.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("239.255.0.1", TEST_PORT, &addr)); r = uv_udp_send(&req, &server, &buf, 1, (const struct sockaddr*) &addr, sv_send_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); - ASSERT(sv_send_cb_called == 0); + ASSERT_OK(close_cb_called); + ASSERT_OK(sv_send_cb_called); /* run the loop till all events are processed */ uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(sv_send_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, sv_send_cb_called); + ASSERT_EQ(1, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-open.c b/test/test-udp-open.c index 0e09f56a49f..6fddc93717b 100644 --- a/test/test-udp-open.c +++ b/test/test-udp-open.c @@ -41,7 +41,7 @@ static void startup(void) { #ifdef _WIN32 struct WSAData wsa_data; int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); - ASSERT(r == 0); + ASSERT_OK(r); #endif } @@ -51,9 +51,9 @@ static uv_os_sock_t create_udp_socket(void) { sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); #ifdef _WIN32 - ASSERT(sock != INVALID_SOCKET); + ASSERT_NE(sock, INVALID_SOCKET); #else - ASSERT(sock >= 0); + ASSERT_GE(sock, 0); #endif #ifndef _WIN32 @@ -61,7 +61,7 @@ static uv_os_sock_t create_udp_socket(void) { /* Allow reuse of the port. */ int yes = 1; int r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - ASSERT(r == 0); + ASSERT_OK(r); } #endif @@ -76,7 +76,7 @@ static void close_socket(uv_os_sock_t sock) { #else r = close(sock); #endif - ASSERT(r == 0); + ASSERT_OK(r); } @@ -84,7 +84,7 @@ static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { static char slab[65536]; - ASSERT(suggested_size <= sizeof(slab)); + ASSERT_LE(suggested_size, sizeof(slab)); buf->base = slab; buf->len = sizeof(slab); } @@ -113,14 +113,14 @@ static void recv_cb(uv_udp_t* handle, return; } - ASSERT(flags == 0); + ASSERT_OK(flags); ASSERT_NOT_NULL(addr); - ASSERT(nread == 4); - ASSERT(memcmp("PING", buf->base, nread) == 0); + ASSERT_EQ(4, nread); + ASSERT_OK(memcmp("PING", buf->base, nread)); r = uv_udp_recv_stop(handle); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) handle, close_cb); } @@ -128,7 +128,7 @@ static void recv_cb(uv_udp_t* handle, static void send_cb(uv_udp_send_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); send_cb_called++; uv_close((uv_handle_t*)req->handle, close_cb); @@ -142,22 +142,22 @@ TEST_IMPL(udp_open) { uv_os_sock_t sock; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); startup(); sock = create_udp_socket(); r = uv_udp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_open(&client, sock); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_recv_start(&client, alloc_cb, recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_send(&send_req, &client, @@ -165,15 +165,15 @@ TEST_IMPL(udp_open) { 1, (const struct sockaddr*) &addr, send_cb); - ASSERT(r == 0); + ASSERT_OK(r); #ifndef _WIN32 { r = uv_udp_init(uv_default_loop(), &client2); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_open(&client2, sock); - ASSERT(r == UV_EEXIST); + ASSERT_EQ(r, UV_EEXIST); uv_close((uv_handle_t*) &client2, NULL); } @@ -183,10 +183,10 @@ TEST_IMPL(udp_open) { uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(send_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT_EQ(1, send_cb_called); + ASSERT_EQ(1, close_cb_called); - ASSERT(client.send_queue_size == 0); + ASSERT_OK(client.send_queue_size); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -203,13 +203,13 @@ TEST_IMPL(udp_open_twice) { sock2 = create_udp_socket(); r = uv_udp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_open(&client, sock1); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_open(&client, sock2); - ASSERT(r == UV_EBUSY); + ASSERT_EQ(r, UV_EBUSY); close_socket(sock2); uv_close((uv_handle_t*) &client, NULL); @@ -225,22 +225,22 @@ TEST_IMPL(udp_open_bound) { uv_os_sock_t sock; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); startup(); sock = create_udp_socket(); r = bind(sock, (struct sockaddr*) &addr, sizeof(addr)); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_open(&client, sock); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_recv_start(&client, alloc_cb, recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*) &client, NULL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); @@ -257,28 +257,28 @@ TEST_IMPL(udp_open_connect) { uv_os_sock_t sock; int r; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); startup(); sock = create_udp_socket(); r = uv_udp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); r = connect(sock, (const struct sockaddr*) &addr, sizeof(addr)); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_open(&client, sock); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_recv_start(&server, alloc_cb, recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_send(&send_req, &client, @@ -286,14 +286,14 @@ TEST_IMPL(udp_open_connect) { 1, NULL, send_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(send_cb_called == 1); - ASSERT(close_cb_called == 2); + ASSERT_EQ(1, send_cb_called); + ASSERT_EQ(2, close_cb_called); - ASSERT(client.send_queue_size == 0); + ASSERT_OK(client.send_queue_size); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; @@ -315,20 +315,20 @@ TEST_IMPL(udp_send_unix) { memset(&addr, 0, sizeof addr); addr.sun_family = AF_UNIX; - ASSERT(strlen(TEST_PIPENAME) < sizeof(addr.sun_path)); + ASSERT_LT(strlen(TEST_PIPENAME), sizeof(addr.sun_path)); memcpy(addr.sun_path, TEST_PIPENAME, strlen(TEST_PIPENAME)); fd = socket(AF_UNIX, SOCK_STREAM, 0); - ASSERT(fd >= 0); + ASSERT_GE(fd, 0); unlink(TEST_PIPENAME); - ASSERT(0 == bind(fd, (const struct sockaddr*)&addr, sizeof addr)); - ASSERT(0 == listen(fd, 1)); + ASSERT_OK(bind(fd, (const struct sockaddr*)&addr, sizeof addr)); + ASSERT_OK(listen(fd, 1)); r = uv_udp_init(loop, &handle); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_open(&handle, fd); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); r = uv_udp_send(&req, @@ -337,7 +337,7 @@ TEST_IMPL(udp_send_unix) { 1, (const struct sockaddr*) &addr, NULL); - ASSERT(r == 0); + ASSERT_OK(r); uv_close((uv_handle_t*)&handle, NULL); uv_run(loop, UV_RUN_DEFAULT); diff --git a/test/test-udp-options.c b/test/test-udp-options.c index 11e58b996a1..bb4a24ca7d1 100644 --- a/test/test-udp-options.c +++ b/test/test-udp-options.c @@ -36,56 +36,56 @@ static int udp_options_test(const struct sockaddr* addr) { loop = uv_default_loop(); r = uv_udp_init(loop, &h); - ASSERT(r == 0); + ASSERT_OK(r); uv_unref((uv_handle_t*)&h); /* don't keep the loop alive */ r = uv_udp_bind(&h, addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_set_broadcast(&h, 1); r |= uv_udp_set_broadcast(&h, 1); r |= uv_udp_set_broadcast(&h, 0); r |= uv_udp_set_broadcast(&h, 0); - ASSERT(r == 0); + ASSERT_OK(r); /* values 1-255 should work */ for (i = 1; i <= 255; i++) { r = uv_udp_set_ttl(&h, i); #if defined(__MVS__) if (addr->sa_family == AF_INET6) - ASSERT(r == 0); + ASSERT_OK(r); else - ASSERT(r == UV_ENOTSUP); + ASSERT_EQ(r, UV_ENOTSUP); #else - ASSERT(r == 0); + ASSERT_OK(r); #endif } for (i = 0; i < (int) ARRAY_SIZE(invalid_ttls); i++) { r = uv_udp_set_ttl(&h, invalid_ttls[i]); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); } r = uv_udp_set_multicast_loop(&h, 1); r |= uv_udp_set_multicast_loop(&h, 1); r |= uv_udp_set_multicast_loop(&h, 0); r |= uv_udp_set_multicast_loop(&h, 0); - ASSERT(r == 0); + ASSERT_OK(r); /* values 0-255 should work */ for (i = 0; i <= 255; i++) { r = uv_udp_set_multicast_ttl(&h, i); - ASSERT(r == 0); + ASSERT_OK(r); } /* anything >255 should fail */ r = uv_udp_set_multicast_ttl(&h, 256); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); /* don't test ttl=-1, it's a valid value on some platforms */ r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); + ASSERT_OK(r); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -95,7 +95,7 @@ static int udp_options_test(const struct sockaddr* addr) { TEST_IMPL(udp_options) { struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); return udp_options_test((const struct sockaddr*) &addr); } @@ -106,7 +106,7 @@ TEST_IMPL(udp_options6) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); - ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr)); + ASSERT_OK(uv_ip6_addr("::", TEST_PORT, &addr)); return udp_options_test((const struct sockaddr*) &addr); } @@ -119,41 +119,41 @@ TEST_IMPL(udp_no_autobind) { loop = uv_default_loop(); /* Test a lazy initialized socket. */ - ASSERT(0 == uv_udp_init(loop, &h)); - ASSERT(UV_EBADF == uv_udp_set_multicast_ttl(&h, 32)); - ASSERT(UV_EBADF == uv_udp_set_broadcast(&h, 1)); + ASSERT_OK(uv_udp_init(loop, &h)); + ASSERT_EQ(UV_EBADF, uv_udp_set_multicast_ttl(&h, 32)); + ASSERT_EQ(UV_EBADF, uv_udp_set_broadcast(&h, 1)); #if defined(__MVS__) - ASSERT(UV_ENOTSUP == uv_udp_set_ttl(&h, 1)); + ASSERT_EQ(UV_ENOTSUP, uv_udp_set_ttl(&h, 1)); #else - ASSERT(UV_EBADF == uv_udp_set_ttl(&h, 1)); + ASSERT_EQ(UV_EBADF, uv_udp_set_ttl(&h, 1)); #endif - ASSERT(UV_EBADF == uv_udp_set_multicast_loop(&h, 1)); + ASSERT_EQ(UV_EBADF, uv_udp_set_multicast_loop(&h, 1)); /* TODO(gengjiawen): Fix test on QEMU. */ #if defined(__QEMU__) RETURN_SKIP("Test does not currently work in QEMU"); #endif - ASSERT(UV_EBADF == uv_udp_set_multicast_interface(&h, "0.0.0.0")); + ASSERT_EQ(UV_EBADF, uv_udp_set_multicast_interface(&h, "0.0.0.0")); uv_close((uv_handle_t*) &h, NULL); /* Test a non-lazily initialized socket. */ - ASSERT(0 == uv_udp_init_ex(loop, &h2, AF_INET | UV_UDP_RECVMMSG)); - ASSERT(0 == uv_udp_set_multicast_ttl(&h2, 32)); - ASSERT(0 == uv_udp_set_broadcast(&h2, 1)); + ASSERT_OK(uv_udp_init_ex(loop, &h2, AF_INET | UV_UDP_RECVMMSG)); + ASSERT_OK(uv_udp_set_multicast_ttl(&h2, 32)); + ASSERT_OK(uv_udp_set_broadcast(&h2, 1)); #if defined(__MVS__) /* zOS only supports setting ttl for IPv6 sockets. */ - ASSERT(UV_ENOTSUP == uv_udp_set_ttl(&h2, 1)); + ASSERT_EQ(UV_ENOTSUP, uv_udp_set_ttl(&h2, 1)); #else - ASSERT(0 == uv_udp_set_ttl(&h2, 1)); + ASSERT_OK(uv_udp_set_ttl(&h2, 1)); #endif - ASSERT(0 == uv_udp_set_multicast_loop(&h2, 1)); - ASSERT(0 == uv_udp_set_multicast_interface(&h2, "0.0.0.0")); + ASSERT_OK(uv_udp_set_multicast_loop(&h2, 1)); + ASSERT_OK(uv_udp_set_multicast_interface(&h2, "0.0.0.0")); uv_close((uv_handle_t*) &h2, NULL); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-udp-recv-in-a-row.c b/test/test-udp-recv-in-a-row.c index 98aca28e193..30745def0f6 100644 --- a/test/test-udp-recv-in-a-row.c +++ b/test/test-udp-recv-in-a-row.c @@ -53,7 +53,7 @@ static void sv_recv_cb(uv_udp_t* handle, if (++ recv_cnt < N) { ASSERT_EQ(sizeof(send_data), nread); } else { - ASSERT_EQ(0, nread); + ASSERT_OK(nread); } } @@ -69,7 +69,7 @@ static void check_cb(uv_check_t* handle) { check_cb_called = 1; /* we are done */ - ASSERT_EQ(0, uv_check_stop(handle)); + ASSERT_OK(uv_check_stop(handle)); uv_close((uv_handle_t*) &client, NULL); uv_close((uv_handle_t*) &check_handle, NULL); uv_close((uv_handle_t*) &server, NULL); @@ -79,16 +79,16 @@ static void check_cb(uv_check_t* handle) { TEST_IMPL(udp_recv_in_a_row) { int i, r; - ASSERT_EQ(0, uv_check_init(uv_default_loop(), &check_handle)); - ASSERT_EQ(0, uv_check_start(&check_handle, check_cb)); + ASSERT_OK(uv_check_init(uv_default_loop(), &check_handle)); + ASSERT_OK(uv_check_start(&check_handle, check_cb)); - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT_EQ(0, uv_udp_init(uv_default_loop(), &server)); - ASSERT_EQ(0, uv_udp_bind(&server, (const struct sockaddr*) &addr, 0)); - ASSERT_EQ(0, uv_udp_recv_start(&server, alloc_cb, sv_recv_cb)); + ASSERT_OK(uv_udp_init(uv_default_loop(), &server)); + ASSERT_OK(uv_udp_bind(&server, (const struct sockaddr*) &addr, 0)); + ASSERT_OK(uv_udp_recv_start(&server, alloc_cb, sv_recv_cb)); - ASSERT_EQ(0, uv_udp_init(uv_default_loop(), &client)); + ASSERT_OK(uv_udp_init(uv_default_loop(), &client)); /* send N-1 udp packets */ buf = uv_buf_init(send_data, sizeof(send_data)); @@ -106,13 +106,13 @@ TEST_IMPL(udp_recv_in_a_row) { &buf, 1, (const struct sockaddr*) &addr); - ASSERT_EQ(0, r); + ASSERT_OK(r); /* check_cb() asserts that the N packets can be received * before it gets called. */ - ASSERT_EQ(0, uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT(check_cb_called); diff --git a/test/test-udp-send-and-recv.c b/test/test-udp-send-and-recv.c index ab60e84a138..b24fe1d0532 100644 --- a/test/test-udp-send-and-recv.c +++ b/test/test-udp-send-and-recv.c @@ -27,7 +27,7 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0) static uv_udp_t server; static uv_udp_t client; @@ -46,7 +46,7 @@ static void alloc_cb(uv_handle_t* handle, uv_buf_t* buf) { static char slab[65536]; CHECK_HANDLE(handle); - ASSERT(suggested_size <= sizeof(slab)); + ASSERT_LE(suggested_size, sizeof(slab)); buf->base = slab; buf->len = sizeof(slab); } @@ -54,7 +54,7 @@ static void alloc_cb(uv_handle_t* handle, static void close_cb(uv_handle_t* handle) { CHECK_HANDLE(handle); - ASSERT(1 == uv_is_closing(handle)); + ASSERT_EQ(1, uv_is_closing(handle)); close_cb_called++; } @@ -65,7 +65,7 @@ static void cl_recv_cb(uv_udp_t* handle, const struct sockaddr* addr, unsigned flags) { CHECK_HANDLE(handle); - ASSERT(flags == 0); + ASSERT_OK(flags); if (nread < 0) { ASSERT(0 && "unexpected error"); @@ -78,7 +78,7 @@ static void cl_recv_cb(uv_udp_t* handle, } ASSERT_NOT_NULL(addr); - ASSERT(nread == 4); + ASSERT_EQ(4, nread); ASSERT(!memcmp("PONG", buf->base, nread)); cl_recv_cb_called++; @@ -91,11 +91,11 @@ static void cl_send_cb(uv_udp_send_t* req, int status) { int r; ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); CHECK_HANDLE(req->handle); r = uv_udp_recv_start(req->handle, alloc_cb, cl_recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); cl_send_cb_called++; } @@ -103,7 +103,7 @@ static void cl_send_cb(uv_udp_send_t* req, int status) { static void sv_send_cb(uv_udp_send_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); CHECK_HANDLE(req->handle); uv_close((uv_handle_t*) req->handle, close_cb); @@ -133,10 +133,10 @@ static void sv_recv_cb(uv_udp_t* handle, } CHECK_HANDLE(handle); - ASSERT(flags == 0); + ASSERT_OK(flags); ASSERT_NOT_NULL(addr); - ASSERT(nread == 4); + ASSERT_EQ(4, nread); ASSERT(!memcmp("PING", rcvbuf->base, nread)); /* FIXME? `uv_udp_recv_stop` does what it says: recv_cb is not called @@ -144,14 +144,14 @@ static void sv_recv_cb(uv_udp_t* handle, * either... Not sure I like that but it's consistent with `uv_read_stop`. */ r = uv_udp_recv_stop(handle); - ASSERT(r == 0); + ASSERT_OK(r); req = malloc(sizeof *req); ASSERT_NOT_NULL(req); sndbuf = uv_buf_init("PONG", 4); r = uv_udp_send(req, handle, &sndbuf, 1, addr, sv_send_cb); - ASSERT(r == 0); + ASSERT_OK(r); sv_recv_cb_called++; } @@ -163,21 +163,21 @@ TEST_IMPL(udp_send_and_recv) { uv_buf_t buf; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); /* client sends "PING", expects "PONG" */ buf = uv_buf_init("PING", 4); @@ -188,24 +188,24 @@ TEST_IMPL(udp_send_and_recv) { 1, (const struct sockaddr*) &addr, cl_send_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(close_cb_called == 0); - ASSERT(cl_send_cb_called == 0); - ASSERT(cl_recv_cb_called == 0); - ASSERT(sv_send_cb_called == 0); - ASSERT(sv_recv_cb_called == 0); + ASSERT_OK(close_cb_called); + ASSERT_OK(cl_send_cb_called); + ASSERT_OK(cl_recv_cb_called); + ASSERT_OK(sv_send_cb_called); + ASSERT_OK(sv_recv_cb_called); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(cl_send_cb_called == 1); - ASSERT(cl_recv_cb_called == 1); - ASSERT(sv_send_cb_called == 1); - ASSERT(sv_recv_cb_called == 1); - ASSERT(close_cb_called == 2); + ASSERT_EQ(1, cl_send_cb_called); + ASSERT_EQ(1, cl_recv_cb_called); + ASSERT_EQ(1, sv_send_cb_called); + ASSERT_EQ(1, sv_recv_cb_called); + ASSERT_EQ(2, close_cb_called); - ASSERT(client.send_queue_size == 0); - ASSERT(server.send_queue_size == 0); + ASSERT_OK(client.send_queue_size); + ASSERT_OK(server.send_queue_size); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-send-hang-loop.c b/test/test-udp-send-hang-loop.c index b1e02263d3c..706f6621ed1 100644 --- a/test/test-udp-send-hang-loop.c +++ b/test/test-udp-send-hang-loop.c @@ -27,7 +27,7 @@ #include #define CHECK_OBJECT(handle, type, parent) \ - ASSERT((type*)(handle) == &(parent)) + ASSERT_PTR_EQ((type*)(handle), &(parent)) static uv_udp_t client; static uv_idle_t idle_handle; @@ -46,7 +46,7 @@ static void idle_cb(uv_idle_t* handle) { ASSERT_NULL(send_req.handle); CHECK_OBJECT(handle, uv_idle_t, idle_handle); - ASSERT(0 == uv_idle_stop(handle)); + ASSERT_OK(uv_idle_stop(handle)); /* It probably would have stalled by now if it's going to stall at all. */ if (++loop_hang_called > 1000) { @@ -61,7 +61,7 @@ static void idle_cb(uv_idle_t* handle) { 1, (const struct sockaddr*) &addr, send_cb); - ASSERT(r == 0); + ASSERT_OK(r); } @@ -72,27 +72,27 @@ static void send_cb(uv_udp_send_t* req, int status) { CHECK_OBJECT(req, uv_udp_send_t, send_req); req->handle = NULL; - ASSERT(0 == uv_idle_start(&idle_handle, idle_cb)); + ASSERT_OK(uv_idle_start(&idle_handle, idle_cb)); } TEST_IMPL(udp_send_hang_loop) { - ASSERT(0 == uv_idle_init(uv_default_loop(), &idle_handle)); + ASSERT_OK(uv_idle_init(uv_default_loop(), &idle_handle)); /* 192.0.2.0/8 is "TEST-NET" and reserved for documentation. * Good for us, though. Since we want to have something unreachable. */ - ASSERT(0 == uv_ip4_addr("192.0.2.3", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("192.0.2.3", TEST_PORT, &addr)); - ASSERT(0 == uv_udp_init(uv_default_loop(), &client)); + ASSERT_OK(uv_udp_init(uv_default_loop(), &client)); buf = uv_buf_init(send_data, sizeof(send_data)); - ASSERT(0 == uv_idle_start(&idle_handle, idle_cb)); + ASSERT_OK(uv_idle_start(&idle_handle, idle_cb)); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(loop_hang_called > 1000); + ASSERT_GT(loop_hang_called, 1000); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-send-immediate.c b/test/test-udp-send-immediate.c index ee70a6165a2..8e7f83ff05b 100644 --- a/test/test-udp-send-immediate.c +++ b/test/test-udp-send-immediate.c @@ -27,7 +27,7 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0) static uv_udp_t server; static uv_udp_t client; @@ -42,7 +42,7 @@ static void alloc_cb(uv_handle_t* handle, uv_buf_t* buf) { static char slab[65536]; CHECK_HANDLE(handle); - ASSERT(suggested_size <= sizeof(slab)); + ASSERT_LE(suggested_size, sizeof(slab)); buf->base = slab; buf->len = sizeof(slab); } @@ -50,14 +50,14 @@ static void alloc_cb(uv_handle_t* handle, static void close_cb(uv_handle_t* handle) { CHECK_HANDLE(handle); - ASSERT(1 == uv_is_closing(handle)); + ASSERT_EQ(1, uv_is_closing(handle)); close_cb_called++; } static void cl_send_cb(uv_udp_send_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status == 0); + ASSERT_OK(status); CHECK_HANDLE(req->handle); cl_send_cb_called++; @@ -80,10 +80,10 @@ static void sv_recv_cb(uv_udp_t* handle, } CHECK_HANDLE(handle); - ASSERT(flags == 0); + ASSERT_OK(flags); ASSERT_NOT_NULL(addr); - ASSERT(nread == 4); + ASSERT_EQ(4, nread); ASSERT(memcmp("PING", rcvbuf->base, nread) == 0 || memcmp("PANG", rcvbuf->base, nread) == 0); @@ -100,21 +100,21 @@ TEST_IMPL(udp_send_immediate) { uv_buf_t buf; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); /* client sends "PING", then "PANG" */ buf = uv_buf_init("PING", 4); @@ -125,7 +125,7 @@ TEST_IMPL(udp_send_immediate) { 1, (const struct sockaddr*) &addr, cl_send_cb); - ASSERT(r == 0); + ASSERT_OK(r); buf = uv_buf_init("PANG", 4); @@ -135,13 +135,13 @@ TEST_IMPL(udp_send_immediate) { 1, (const struct sockaddr*) &addr, cl_send_cb); - ASSERT(r == 0); + ASSERT_OK(r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(cl_send_cb_called == 2); - ASSERT(sv_recv_cb_called == 2); - ASSERT(close_cb_called == 2); + ASSERT_EQ(2, cl_send_cb_called); + ASSERT_EQ(2, sv_recv_cb_called); + ASSERT_EQ(2, close_cb_called); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-send-unreachable.c b/test/test-udp-send-unreachable.c index 7075deb1896..0a2f4a47a97 100644 --- a/test/test-udp-send-unreachable.c +++ b/test/test-udp-send-unreachable.c @@ -27,7 +27,7 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &client || (uv_udp_t*)(handle) == &client2) + ASSERT_NE((uv_udp_t*)(handle) == &client || (uv_udp_t*)(handle) == &client2, 0) static uv_udp_t client; static uv_udp_t client2; @@ -61,8 +61,8 @@ static void close_cb(uv_handle_t* handle) { static void send_cb(uv_udp_send_t* req, int status) { ASSERT_NOT_NULL(req); - ASSERT(status == 0); - ASSERT_EQ(status, 0); + ASSERT_OK(status); + ASSERT_OK(status); CHECK_HANDLE(req->handle); send_cb_called++; } @@ -115,24 +115,24 @@ TEST_IMPL(udp_send_unreachable) { can_recverr = 1; #endif - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT_2, &addr2)); - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT_3, &addr3)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT_2, &addr2)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT_3, &addr3)); r = uv_timer_init( uv_default_loop(), &timer ); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_timer_start( &timer, timer_cb, 1000, 0 ); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_init(uv_default_loop(), &client); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_bind(&client, (const struct sockaddr*) &addr2, 0); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_recv_start(&client, alloc_cb, recv_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); /* client sends "PING", then "PANG" */ buf = uv_buf_init("PING", 4); @@ -143,7 +143,7 @@ TEST_IMPL(udp_send_unreachable) { 1, (const struct sockaddr*) &addr, send_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); buf = uv_buf_init("PANG", 4); @@ -153,19 +153,19 @@ TEST_IMPL(udp_send_unreachable) { 1, (const struct sockaddr*) &addr, send_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); if (can_recverr) { r = uv_udp_init(uv_default_loop(), &client2); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_bind(&client2, (const struct sockaddr*) &addr3, UV_UDP_LINUX_RECVERR); - ASSERT_EQ(r, 0); + ASSERT_OK(r); r = uv_udp_recv_start(&client2, alloc_cb, recv_cb); - ASSERT_EQ(r, 0); + ASSERT_OK(r); /* client sends "PING", then "PANG" */ buf = uv_buf_init("PING", 4); @@ -176,7 +176,7 @@ TEST_IMPL(udp_send_unreachable) { 1, (const struct sockaddr*) &addr, send_cb_recverr); - ASSERT_EQ(r, 0); + ASSERT_OK(r); buf = uv_buf_init("PANG", 4); @@ -186,14 +186,14 @@ TEST_IMPL(udp_send_unreachable) { 1, (const struct sockaddr*) &addr, send_cb_recverr); - ASSERT_EQ(r, 0); + ASSERT_OK(r); } uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT_EQ(send_cb_called, (long)(can_recverr ? 4 : 2)); ASSERT_EQ(recv_cb_called, alloc_cb_called); - ASSERT_EQ(timer_cb_called, 1); + ASSERT_EQ(1, timer_cb_called); ASSERT_EQ(close_cb_called, (long)(can_recverr ? 3 : 2)); MAKE_VALGRIND_HAPPY(uv_default_loop()); diff --git a/test/test-udp-sendmmsg-error.c b/test/test-udp-sendmmsg-error.c index 7b1741a3e04..0b647585e4f 100644 --- a/test/test-udp-sendmmsg-error.c +++ b/test/test-udp-sendmmsg-error.c @@ -55,20 +55,20 @@ TEST_IMPL(udp_sendmmsg_error) { uv_buf_t buf; int i; - ASSERT_EQ(0, uv_udp_init(uv_default_loop(), &client)); - ASSERT_EQ(0, uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - ASSERT_EQ(0, uv_udp_connect(&client, (const struct sockaddr*)&addr)); + ASSERT_OK(uv_udp_init(uv_default_loop(), &client)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_udp_connect(&client, (const struct sockaddr*)&addr)); buf = uv_buf_init("TEST", 4); for (i = 0; i < DATAGRAMS; ++i) - ASSERT_EQ(0, uv_udp_send(&req[i], &client, &buf, 1, NULL, send_cb)); + ASSERT_OK(uv_udp_send(&req[i], &client, &buf, 1, NULL, send_cb)); uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT_EQ(1, close_cb_called); ASSERT_EQ(DATAGRAMS, send_cb_called); - ASSERT_EQ(0, client.send_queue_size); + ASSERT_OK(client.send_queue_size); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-udp-try-send.c b/test/test-udp-try-send.c index b81506cc39f..0c76fb1c84d 100644 --- a/test/test-udp-try-send.c +++ b/test/test-udp-try-send.c @@ -27,7 +27,7 @@ #include #define CHECK_HANDLE(handle) \ - ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + ASSERT_NE((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client, 0) static uv_udp_t server; static uv_udp_t client; @@ -42,7 +42,7 @@ static void alloc_cb(uv_handle_t* handle, uv_buf_t* buf) { static char slab[65536]; CHECK_HANDLE(handle); - ASSERT(suggested_size <= sizeof(slab)); + ASSERT_LE(suggested_size, sizeof(slab)); buf->base = slab; buf->len = sizeof(slab); } @@ -60,17 +60,17 @@ static void sv_recv_cb(uv_udp_t* handle, const uv_buf_t* rcvbuf, const struct sockaddr* addr, unsigned flags) { - ASSERT(nread > 0); + ASSERT_GT(nread, 0); if (nread == 0) { ASSERT_NULL(addr); return; } - ASSERT(nread == 4); + ASSERT_EQ(4, nread); ASSERT_NOT_NULL(addr); - ASSERT(memcmp("EXIT", rcvbuf->base, nread) == 0); + ASSERT_OK(memcmp("EXIT", rcvbuf->base, nread)); uv_close((uv_handle_t*) handle, close_cb); uv_close((uv_handle_t*) &client, close_cb); @@ -84,37 +84,37 @@ TEST_IMPL(udp_try_send) { uv_buf_t buf; int r; - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &server); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); - ASSERT(r == 0); + ASSERT_OK(r); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &client); - ASSERT(r == 0); + ASSERT_OK(r); buf = uv_buf_init(buffer, sizeof(buffer)); r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr); - ASSERT(r == UV_EMSGSIZE); + ASSERT_EQ(r, UV_EMSGSIZE); buf = uv_buf_init("EXIT", 4); r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr); - ASSERT(r == 4); + ASSERT_EQ(4, r); uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(close_cb_called == 2); - ASSERT(sv_recv_cb_called == 1); + ASSERT_EQ(2, close_cb_called); + ASSERT_EQ(1, sv_recv_cb_called); - ASSERT(client.send_queue_size == 0); - ASSERT(server.send_queue_size == 0); + ASSERT_OK(client.send_queue_size); + ASSERT_OK(server.send_queue_size); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-uname.c b/test/test-uname.c index 105a17fe677..a384e9f8422 100644 --- a/test/test-uname.c +++ b/test/test-uname.c @@ -39,28 +39,28 @@ TEST_IMPL(uname) { /* Verify that NULL is handled properly. */ r = uv_os_uname(NULL); - ASSERT(r == UV_EINVAL); + ASSERT_EQ(r, UV_EINVAL); /* Verify the happy path. */ r = uv_os_uname(&buffer); - ASSERT(r == 0); + ASSERT_OK(r); #ifndef _WIN32 - ASSERT(uname(&buf) != -1); - ASSERT(strcmp(buffer.sysname, buf.sysname) == 0); - ASSERT(strcmp(buffer.version, buf.version) == 0); + ASSERT_NE(uname(&buf), -1); + ASSERT_OK(strcmp(buffer.sysname, buf.sysname)); + ASSERT_OK(strcmp(buffer.version, buf.version)); # ifdef _AIX snprintf(temp, sizeof(temp), "%s.%s", buf.version, buf.release); - ASSERT(strcmp(buffer.release, temp) == 0); + ASSERT_OK(strcmp(buffer.release, temp)); # else - ASSERT(strcmp(buffer.release, buf.release) == 0); + ASSERT_OK(strcmp(buffer.release, buf.release)); # endif /* _AIX */ # if defined(_AIX) || defined(__PASE__) - ASSERT(strcmp(buffer.machine, "ppc64") == 0); + ASSERT_OK(strcmp(buffer.machine, "ppc64")); # else - ASSERT(strcmp(buffer.machine, buf.machine) == 0); + ASSERT_OK(strcmp(buffer.machine, buf.machine)); # endif /* defined(_AIX) || defined(__PASE__) */ #endif /* _WIN32 */ diff --git a/test/test-walk-handles.c b/test/test-walk-handles.c index 50f0ce84f1e..86fcb04907e 100644 --- a/test/test-walk-handles.c +++ b/test/test-walk-handles.c @@ -31,7 +31,7 @@ static uv_timer_t timer; static void walk_cb(uv_handle_t* handle, void* arg) { - ASSERT(arg == (void*)magic_cookie); + ASSERT_PTR_EQ(arg, (void*)magic_cookie); if (handle == (uv_handle_t*)&timer) { seen_timer_handle++; @@ -42,7 +42,7 @@ static void walk_cb(uv_handle_t* handle, void* arg) { static void timer_cb(uv_timer_t* handle) { - ASSERT(handle == &timer); + ASSERT_PTR_EQ(handle, &timer); uv_walk(handle->loop, walk_cb, magic_cookie); uv_close((uv_handle_t*)handle, NULL); @@ -56,21 +56,21 @@ TEST_IMPL(walk_handles) { loop = uv_default_loop(); r = uv_timer_init(loop, &timer); - ASSERT(r == 0); + ASSERT_OK(r); r = uv_timer_start(&timer, timer_cb, 1, 0); - ASSERT(r == 0); + ASSERT_OK(r); /* Start event loop, expect to see the timer handle in walk_cb. */ - ASSERT(seen_timer_handle == 0); + ASSERT_OK(seen_timer_handle); r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); - ASSERT(seen_timer_handle == 1); + ASSERT_OK(r); + ASSERT_EQ(1, seen_timer_handle); /* Loop is finished, walk_cb should not see our timer handle. */ seen_timer_handle = 0; uv_walk(loop, walk_cb, magic_cookie); - ASSERT(seen_timer_handle == 0); + ASSERT_OK(seen_timer_handle); MAKE_VALGRIND_HAPPY(loop); return 0; diff --git a/test/test-watcher-cross-stop.c b/test/test-watcher-cross-stop.c index bbc0c30574a..8f79abb7b03 100644 --- a/test/test-watcher-cross-stop.c +++ b/test/test-watcher-cross-stop.c @@ -76,22 +76,22 @@ TEST_IMPL(watcher_cross_stop) { TEST_FILE_LIMIT(ARRAY_SIZE(sockets) + 32); - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); memset(big_string, 'A', sizeof(big_string)); buf = uv_buf_init(big_string, sizeof(big_string)); for (i = 0; i < ARRAY_SIZE(sockets); i++) { - ASSERT(0 == uv_udp_init(loop, &sockets[i])); - ASSERT(0 == uv_udp_bind(&sockets[i], - (const struct sockaddr*) &addr, - UV_UDP_REUSEADDR)); - ASSERT(0 == uv_udp_recv_start(&sockets[i], alloc_cb, recv_cb)); - ASSERT(0 == uv_udp_send(&reqs[i], - &sockets[i], - &buf, - 1, - (const struct sockaddr*) &addr, - send_cb)); + ASSERT_OK(uv_udp_init(loop, &sockets[i])); + ASSERT_OK(uv_udp_bind(&sockets[i], + (const struct sockaddr*) &addr, + UV_UDP_REUSEADDR)); + ASSERT_OK(uv_udp_recv_start(&sockets[i], alloc_cb, recv_cb)); + ASSERT_OK(uv_udp_send(&reqs[i], + &sockets[i], + &buf, + 1, + (const struct sockaddr*) &addr, + send_cb)); } while (recv_cb_called == 0) @@ -100,12 +100,12 @@ TEST_IMPL(watcher_cross_stop) { for (i = 0; i < ARRAY_SIZE(sockets); i++) uv_close((uv_handle_t*) &sockets[i], close_cb); - ASSERT(recv_cb_called > 0); + ASSERT_GT(recv_cb_called, 0); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(ARRAY_SIZE(sockets) == send_cb_called); - ASSERT(ARRAY_SIZE(sockets) == close_cb_called); + ASSERT_EQ(ARRAY_SIZE(sockets), send_cb_called); + ASSERT_EQ(ARRAY_SIZE(sockets), close_cb_called); MAKE_VALGRIND_HAPPY(loop); return 0; From fc4840ebc9ad62231a98e1070b39aee86a16b9ca Mon Sep 17 00:00:00 2001 From: jolai <58589285+laijonathan@users.noreply.github.com> Date: Fri, 6 Oct 2023 13:53:38 -0400 Subject: [PATCH 436/713] zos: correctly get cpu model in uv_cpu_info() (#4136) The previous implementation using si11v1cpcmodel did not return a valid cpu model on z/OS. So use PCCA instead to correctly get the cpu model. Co-authored-by: Wayne Zhang Co-authored-by: Gaby Baghdadi Co-authored-by: Jonathan Lai Fixes: https://github.com/libuv/libuv/issues/4102 --- src/unix/os390.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index bbd37692d1d..1b277292aeb 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -19,6 +19,7 @@ * IN THE SOFTWARE. */ +#include "uv.h" #include "internal.h" #include #include @@ -30,6 +31,7 @@ #include #include #include "zos-base.h" +#include "zos-sys-info.h" #if defined(__clang__) #include "csrsic.h" #else @@ -66,9 +68,6 @@ /* Total number of frames currently on all available frame queues. */ #define RCEAFC_OFFSET 0x088 -/* CPC model length from the CSRSI Service. */ -#define CPCMODEL_LENGTH 16 - /* Pointer to the home (current) ASCB. */ #define PSAAOLD 0x224 @@ -258,9 +257,12 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { idx = 0; while (idx < *count) { cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability); - cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1); - memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1); - memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH); + cpu_info->model = uv__malloc(ZOSCPU_MODEL_LENGTH + 1); + if (cpu_info->model == NULL) { + uv_free_cpu_info(*cpu_infos, idx); + return UV_ENOMEM; + } + __get_cpu_model(cpu_info->model, ZOSCPU_MODEL_LENGTH + 1); cpu_info->cpu_times.user = cpu_usage_avg; /* TODO: implement the following */ cpu_info->cpu_times.sys = 0; From 75f7de4010cbc80e310ca41dd453874d17282593 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Fri, 6 Oct 2023 18:25:40 +0000 Subject: [PATCH 437/713] test: fix get_passwd2 on IBM i (#4154) uid 0 is `qsecofr` on IBM i. Refs: https://github.com/libuv/libuv/issues/4143 --- test/test-get-passwd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/test-get-passwd.c b/test/test-get-passwd.c index c70c69a9b81..b1e76200975 100644 --- a/test/test-get-passwd.c +++ b/test/test-get-passwd.c @@ -135,11 +135,16 @@ TEST_IMPL(get_passwd2) { len = strlen(pwd2.username); ASSERT_GT(len, 0); +#if defined(__PASE__) + // uid 0 is qsecofr on IBM i + ASSERT_STR_EQ(pwd2.username, "qsecofr"); +#else ASSERT_STR_EQ(pwd2.username, "root"); - +#endif len = strlen(pwd2.homedir); +# ifndef __PASE__ ASSERT_GT(len, 0); - +#endif len = strlen(pwd2.shell); # ifndef __PASE__ ASSERT_GT(len, 0); From 13148457a952092414a6c912b351a5e056816881 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 12 Oct 2023 20:40:18 +0200 Subject: [PATCH 438/713] unix: don't malloc on sync uv_fs_read (#4162) We can use the |bufs| argument directly instead of always copying it and sometimes heap-allocating it. The same trick doesn't work for uv_fs_write() because the iterator mutates the buffers in the list and that's visible to the caller. Fixes: https://github.com/libuv/libuv/issues/4038 --- src/unix/fs.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 56c660b456e..595fc2c3a78 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -441,9 +441,10 @@ static ssize_t uv__fs_read(uv_fs_t* req) { iov = (const struct iovec*) req->bufs; result = uv__fs_read_do(req->file, iov, req->nbufs, req->off); - /* Early cleanup of bufs allocation, since we're done with it. */ - if (req->bufs != req->bufsml) - uv__free(req->bufs); + /* We don't own the buffer list in the synchronous case. */ + if (req->cb != NULL) + if (req->bufs != req->bufsml) + uv__free(req->bufs); req->bufs = NULL; req->nbufs = 0; @@ -1871,9 +1872,14 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, if (bufs == NULL || nbufs == 0) return UV_EINVAL; + req->off = off; req->file = file; - + req->bufs = (uv_buf_t*) bufs; /* Safe, doesn't mutate |bufs| */ req->nbufs = nbufs; + + if (cb == NULL) + goto post; + req->bufs = req->bufsml; if (nbufs > ARRAY_SIZE(req->bufsml)) req->bufs = uv__malloc(nbufs * sizeof(*bufs)); @@ -1883,12 +1889,10 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); - req->off = off; - - if (cb != NULL) - if (uv__iou_fs_read_or_write(loop, req, /* is_read */ 1)) - return 0; + if (uv__iou_fs_read_or_write(loop, req, /* is_read */ 1)) + return 0; +post: POST; } From 004dfd2d4b2bc3c3f2ddda7ac72c9dd579ca4194 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Thu, 12 Oct 2023 19:43:11 +0100 Subject: [PATCH 439/713] freebsd: get fs event path with fcntl(F_KINFO) --- src/unix/kqueue.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 6cb0ef2aa75..94ace58680c 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -30,6 +30,9 @@ #include #include #include +#if defined(__FreeBSD__) +#include +#endif #include #include #include @@ -480,6 +483,16 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) { */ if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0) path = uv__basename_r(pathbuf); +#elif defined(F_KINFO) + /* We try to get the file info reference from the file descriptor. + * the struct's kf_structsize must be initialised beforehand + * whether with the KINFO_FILE_SIZE constant or this way. + */ + struct kinfo_file kf; + kf.kf_structsize = sizeof(kf); + + if (fcntl(handle->event_watcher.fd, F_KINFO, &kf) == 0) + path = uv__basename_r(kf.kf_path); #endif handle->cb(handle, path, events, 0); From d8669609d802e0bb27a9d6816eaaadb9aa4ad0fb Mon Sep 17 00:00:00 2001 From: Pleuvens Date: Thu, 12 Oct 2023 20:47:44 +0200 Subject: [PATCH 440/713] test: switch from ASSERT_* to ASSERT_PTR_* (#4163) Also introduce a new ASSERT_PTR_LT macro. --- test/benchmark-pump.c | 2 +- test/run-tests.c | 2 +- test/task.h | 3 +++ test/test-fs-readdir.c | 2 +- test/test-fs.c | 8 +++--- test/test-getters-setters.c | 4 +-- test/test-idna.c | 30 +++++++++++----------- test/test-ipc-send-recv.c | 4 +-- test/test-spawn.c | 6 ++--- test/test-tcp-close-after-read-timeout.c | 2 +- test/test-tcp-close-reset.c | 3 ++- test/test-tcp-create-socket-early.c | 8 ++++-- test/test-thread.c | 4 +-- test/test-tty-duplicate-key.c | 6 ++--- test/test-tty-escape-sequence-processing.c | 4 +-- test/test-tty.c | 12 ++++----- test/test-udp-create-socket-early.c | 12 ++++++--- 17 files changed, 62 insertions(+), 50 deletions(-) diff --git a/test/benchmark-pump.c b/test/benchmark-pump.c index 8ab4bc8046f..8797668ee93 100644 --- a/test/benchmark-pump.c +++ b/test/benchmark-pump.c @@ -278,7 +278,7 @@ static void connection_cb(uv_stream_t* s, int status) { uv_stream_t* stream; int r; - ASSERT_EQ(server, s); + ASSERT_PTR_EQ(server, s); ASSERT_OK(status); if (type == TCP) { diff --git a/test/run-tests.c b/test/run-tests.c index ce1c0ef0665..97fec52f1d8 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -145,7 +145,7 @@ static int maybe_run_test(int argc, char **argv) { if (strcmp(argv[1], "spawn_helper3") == 0) { char buffer[256]; notify_parent_process(); - ASSERT_EQ(buffer, fgets(buffer, sizeof(buffer) - 1, stdin)); + ASSERT_PTR_EQ(buffer, fgets(buffer, sizeof(buffer) - 1, stdin)); buffer[sizeof(buffer) - 1] = '\0'; fputs(buffer, stdout); return 1; diff --git a/test/task.h b/test/task.h index b93b4a98d09..8b8353263da 100644 --- a/test/task.h +++ b/test/task.h @@ -244,6 +244,9 @@ typedef enum { #define ASSERT_PTR_NE(a, b) \ ASSERT_BASE(a, !=, b, void*, "p") +#define ASSERT_PTR_LT(a, b) \ + ASSERT_BASE(a, <, b, void*, "p") + /* This macro cleans up the event loop. This is used to avoid valgrind * warnings about memory being "leaked" by the event loop. */ diff --git a/test/test-fs-readdir.c b/test/test-fs-readdir.c index 7eaca6f89c4..b6b5b7ff2c1 100644 --- a/test/test-fs-readdir.c +++ b/test/test-fs-readdir.c @@ -295,7 +295,7 @@ static void non_empty_readdir_cb(uv_fs_t* req) { non_empty_closedir_cb); } else { ASSERT_EQ(1, req->result); - ASSERT_EQ(dir->dirents, dirents); + ASSERT_PTR_EQ(dir->dirents, dirents); ASSERT(strcmp(dirents[0].name, "file1") == 0 || strcmp(dirents[0].name, "file2") == 0 || strcmp(dirents[0].name, "test_subdir") == 0); diff --git a/test/test-fs.c b/test/test-fs.c index 5be48dd5c3a..1acdc5c6708 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2483,7 +2483,7 @@ TEST_IMPL(fs_non_symlink_reparse_point) { FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); - ASSERT_NE(file_handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(file_handle, INVALID_HANDLE_VALUE); memset(&reparse_buffer, 0, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE); reparse_buffer.ReparseTag = REPARSE_TAG; @@ -3915,7 +3915,7 @@ TEST_IMPL(get_osfhandle_valid_handle) { fd = uv_get_osfhandle(open_req1.result); #ifdef _WIN32 - ASSERT_NE(fd, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(fd, INVALID_HANDLE_VALUE); #else ASSERT_GE(fd, 0); #endif @@ -3954,7 +3954,7 @@ TEST_IMPL(open_osfhandle_valid_handle) { handle = uv_get_osfhandle(open_req1.result); #ifdef _WIN32 - ASSERT_NE(handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); #else ASSERT_GE(handle, 0); #endif @@ -4604,7 +4604,7 @@ TEST_IMPL(fs_wtf) { FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); - ASSERT_NE(file_handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(file_handle, INVALID_HANDLE_VALUE); CloseHandle(file_handle); diff --git a/test/test-getters-setters.c b/test/test-getters-setters.c index 57cbfedc131..e4c6717d3bc 100644 --- a/test/test-getters-setters.c +++ b/test/test-getters-setters.c @@ -71,7 +71,7 @@ TEST_IMPL(getters_setters) { ASSERT_OK(r); ASSERT_EQ(uv_handle_get_type((uv_handle_t*)pipe), UV_NAMED_PIPE); - ASSERT_EQ(uv_handle_get_loop((uv_handle_t*)pipe), loop); + ASSERT_PTR_EQ(uv_handle_get_loop((uv_handle_t*)pipe), loop); pipe->data = &cookie2; ASSERT_PTR_EQ(uv_handle_get_data((uv_handle_t*)pipe), &cookie2); uv_handle_set_data((uv_handle_t*)pipe, &cookie1); @@ -95,7 +95,7 @@ TEST_IMPL(getters_setters) { ASSERT_EQ(uv_fs_get_type(fs), UV_FS_STAT); ASSERT_OK(uv_fs_get_result(fs)); - ASSERT_EQ(uv_fs_get_ptr(fs), uv_fs_get_statbuf(fs)); + ASSERT_PTR_EQ(uv_fs_get_ptr(fs), uv_fs_get_statbuf(fs)); ASSERT(uv_fs_get_statbuf(fs)->st_mode & S_IFDIR); ASSERT_OK(strcmp(uv_fs_get_path(fs), ".")); uv_fs_req_cleanup(fs); diff --git a/test/test-idna.c b/test/test-idna.c index e6ebfe824e4..371b2d58775 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -32,57 +32,57 @@ TEST_IMPL(utf8_decode1) { p = b; snprintf(b, sizeof(b), "%c\x7F", 0x00); ASSERT_OK(uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 1); + ASSERT_PTR_EQ(p, b + 1); ASSERT_EQ(127, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 2); + ASSERT_PTR_EQ(p, b + 2); /* Two-byte sequences. */ p = b; snprintf(b, sizeof(b), "\xC2\x80\xDF\xBF"); ASSERT_EQ(128, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 2); + ASSERT_PTR_EQ(p, b + 2); ASSERT_EQ(0x7FF, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 4); + ASSERT_PTR_EQ(p, b + 4); /* Three-byte sequences. */ p = b; snprintf(b, sizeof(b), "\xE0\xA0\x80\xEF\xBF\xBF"); ASSERT_EQ(0x800, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 3); + ASSERT_PTR_EQ(p, b + 3); ASSERT_EQ(0xFFFF, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 6); + ASSERT_PTR_EQ(p, b + 6); /* Four-byte sequences. */ p = b; snprintf(b, sizeof(b), "\xF0\x90\x80\x80\xF4\x8F\xBF\xBF"); ASSERT_EQ(0x10000, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 4); + ASSERT_PTR_EQ(p, b + 4); ASSERT_EQ(0x10FFFF, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 8); + ASSERT_PTR_EQ(p, b + 8); /* Four-byte sequences > U+10FFFF; disallowed. */ p = b; snprintf(b, sizeof(b), "\xF4\x90\xC0\xC0\xF7\xBF\xBF\xBF"); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 4); + ASSERT_PTR_EQ(p, b + 4); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 8); + ASSERT_PTR_EQ(p, b + 8); /* Overlong; disallowed. */ p = b; snprintf(b, sizeof(b), "\xC0\x80\xC1\x80"); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 2); + ASSERT_PTR_EQ(p, b + 2); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 4); + ASSERT_PTR_EQ(p, b + 4); /* Surrogate pairs; disallowed. */ p = b; snprintf(b, sizeof(b), "\xED\xA0\x80\xED\xA3\xBF"); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 3); + ASSERT_PTR_EQ(p, b + 3); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + 6); + ASSERT_PTR_EQ(p, b + 6); /* Simply illegal. */ p = b; @@ -90,7 +90,7 @@ TEST_IMPL(utf8_decode1) { for (i = 1; i <= 8; i++) { ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); - ASSERT_EQ(p, b + i); + ASSERT_PTR_EQ(p, b + i); } return 0; diff --git a/test/test-ipc-send-recv.c b/test/test-ipc-send-recv.c index f24cc99fe8d..0cdd881be05 100644 --- a/test/test-ipc-send-recv.c +++ b/test/test-ipc-send-recv.c @@ -96,7 +96,7 @@ static void recv_cb(uv_stream_t* handle, free(buf->base); pipe = (uv_pipe_t*) handle; - ASSERT_EQ(pipe, &ctx.channel); + ASSERT_PTR_EQ(pipe, &ctx.channel); do { if (++recv_cb_count == 1) { @@ -317,7 +317,7 @@ static void read_cb(uv_stream_t* handle, ASSERT_GE(nread, 0); pipe = (uv_pipe_t*) handle; - ASSERT_EQ(pipe, &ctx2.channel); + ASSERT_PTR_EQ(pipe, &ctx2.channel); while (uv_pipe_pending_count(pipe) > 0) { if (++read_cb_count == 2) { diff --git a/test/test-spawn.c b/test/test-spawn.c index a5022d9eac7..bbb7cb498ba 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1119,7 +1119,7 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) { 65536, 0, NULL); - ASSERT_NE(pipe_handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(pipe_handle, INVALID_HANDLE_VALUE); r = uv_spawn(uv_default_loop(), &process, &options); ASSERT_OK(r); @@ -1994,8 +1994,8 @@ void spawn_stdin_stdout(void) { char* pbuf; HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE); HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE); - ASSERT_NE(h_stdin, INVALID_HANDLE_VALUE); - ASSERT_NE(h_stdout, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(h_stdin, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(h_stdout, INVALID_HANDLE_VALUE); for (;;) { DWORD n_read; DWORD n_written; diff --git a/test/test-tcp-close-after-read-timeout.c b/test/test-tcp-close-after-read-timeout.c index d5b54c2759e..1b81630157d 100644 --- a/test/test-tcp-close-after-read-timeout.c +++ b/test/test-tcp-close-after-read-timeout.c @@ -72,7 +72,7 @@ static void on_client_read(uv_stream_t* stream, ssize_t nread, static void on_client_timeout(uv_timer_t* handle) { - ASSERT_EQ(handle, &timer); + ASSERT_PTR_EQ(handle, &timer); ASSERT_OK(read_cb_called); uv_read_stop((uv_stream_t*) &client); uv_close((uv_handle_t*) &client, on_close); diff --git a/test/test-tcp-close-reset.c b/test/test-tcp-close-reset.c index 549b870199a..c9ac4d48055 100644 --- a/test/test-tcp-close-reset.c +++ b/test/test-tcp-close-reset.c @@ -79,10 +79,11 @@ static void do_close(uv_tcp_t* handle) { } else if (shutdown_before_close == 2) { r = uv_fileno((const uv_handle_t*) handle, &fd); ASSERT_OK(r); - ASSERT_NE(fd, INVALID_FD); #ifdef _WIN32 + ASSERT_PTR_NE(fd, INVALID_FD); ASSERT_OK(shutdown(fd, SD_BOTH)); #else + ASSERT_NE(fd, INVALID_FD); ASSERT_OK(shutdown(fd, SHUT_RDWR)); #endif ASSERT_OK(uv_tcp_close_reset(handle, close_cb)); diff --git a/test/test-tcp-create-socket-early.c b/test/test-tcp-create-socket-early.c index 13e80ad5dc0..e8c1aaab276 100644 --- a/test/test-tcp-create-socket-early.c +++ b/test/test-tcp-create-socket-early.c @@ -105,14 +105,16 @@ TEST_IMPL(tcp_create_early) { r = uv_fileno((const uv_handle_t*) &client, &fd); ASSERT_OK(r); - ASSERT_NE(fd, INVALID_FD); /* Windows returns WSAEINVAL if the socket is not bound */ #ifndef _WIN32 + ASSERT_NE(fd, INVALID_FD); namelen = sizeof sockname; r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen); ASSERT_OK(r); ASSERT_EQ(sockname.sin_family, AF_INET); +#else + ASSERT_PTR_NE(fd, INVALID_FD); #endif r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0); @@ -149,10 +151,10 @@ TEST_IMPL(tcp_create_early_bad_bind) { r = uv_fileno((const uv_handle_t*) &client, &fd); ASSERT_OK(r); - ASSERT_NE(fd, INVALID_FD); /* Windows returns WSAEINVAL if the socket is not bound */ #ifndef _WIN32 + ASSERT_NE(fd, INVALID_FD); { int namelen; struct sockaddr_in6 sockname; @@ -161,6 +163,8 @@ TEST_IMPL(tcp_create_early_bad_bind) { ASSERT_OK(r); ASSERT_EQ(sockname.sin6_family, AF_INET6); } +#else + ASSERT_PTR_NE(fd, INVALID_FD); #endif r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0); diff --git a/test/test-thread.c b/test/test-thread.c index 449dce14338..d0094e30443 100644 --- a/test/test-thread.c +++ b/test/test-thread.c @@ -192,7 +192,7 @@ TEST_IMPL(threadpool_multiple_event_loops) { static void tls_thread(void* arg) { ASSERT_NULL(uv_key_get(&tls_key)); uv_key_set(&tls_key, arg); - ASSERT_EQ(arg, uv_key_get(&tls_key)); + ASSERT_PTR_EQ(arg, uv_key_get(&tls_key)); uv_key_set(&tls_key, NULL); ASSERT_NULL(uv_key_get(&tls_key)); } @@ -204,7 +204,7 @@ TEST_IMPL(thread_local_storage) { ASSERT_OK(uv_key_create(&tls_key)); ASSERT_NULL(uv_key_get(&tls_key)); uv_key_set(&tls_key, name); - ASSERT_EQ(name, uv_key_get(&tls_key)); + ASSERT_PTR_EQ(name, uv_key_get(&tls_key)); ASSERT_OK(uv_thread_create(threads + 0, tls_thread, threads + 0)); ASSERT_OK(uv_thread_create(threads + 1, tls_thread, threads + 1)); ASSERT_OK(uv_thread_join(threads + 0)); diff --git a/test/test-tty-duplicate-key.c b/test/test-tty-duplicate-key.c index 91d3075e130..871d580266a 100644 --- a/test/test-tty-duplicate-key.c +++ b/test/test-tty-duplicate-key.c @@ -150,7 +150,7 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT_NE(handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); ttyin_fd = _open_osfhandle((intptr_t) handle, 0); ASSERT_GE(ttyin_fd, 0); ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); @@ -204,7 +204,7 @@ TEST_IMPL(tty_duplicate_alt_modifier_key) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT_NE(handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); ttyin_fd = _open_osfhandle((intptr_t) handle, 0); ASSERT_GE(ttyin_fd, 0); ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); @@ -270,7 +270,7 @@ TEST_IMPL(tty_composing_character) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT_NE(handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); ttyin_fd = _open_osfhandle((intptr_t) handle, 0); ASSERT_GE(ttyin_fd, 0); ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); diff --git a/test/test-tty-escape-sequence-processing.c b/test/test-tty-escape-sequence-processing.c index 8bf906fdb47..4a041db11df 100644 --- a/test/test-tty-escape-sequence-processing.c +++ b/test/test-tty-escape-sequence-processing.c @@ -261,7 +261,7 @@ static void make_expect_screen_erase(struct captured_screen* cs, } else { ASSERT(FALSE); } - ASSERT_LT(start, end); + ASSERT_PTR_LT(start, end); ASSERT_LE(end - cs->text, cs->si.length); for (; start < end; start++) { *start = ' '; @@ -360,7 +360,7 @@ static void initialize_tty(uv_tty_t* tty_out) { NULL, CONSOLE_TEXTMODE_BUFFER, NULL); - ASSERT_NE(handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); ttyout_fd = _open_osfhandle((intptr_t) handle, 0); ASSERT_GE(ttyout_fd, 0); diff --git a/test/test-tty.c b/test/test-tty.c index a9de924ae56..1b11303829a 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -57,7 +57,7 @@ TEST_IMPL(tty) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT_NE(handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); ttyin_fd = _open_osfhandle((intptr_t) handle, 0); handle = CreateFileA("conout$", @@ -67,7 +67,7 @@ TEST_IMPL(tty) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT_NE(handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); ttyout_fd = _open_osfhandle((intptr_t) handle, 0); #else /* unix */ @@ -179,7 +179,7 @@ TEST_IMPL(tty_raw) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT_NE(handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); ttyin_fd = _open_osfhandle((intptr_t) handle, 0); ASSERT_GE(ttyin_fd, 0); ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); @@ -235,7 +235,7 @@ TEST_IMPL(tty_empty_write) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT_NE(handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); ttyout_fd = _open_osfhandle((intptr_t) handle, 0); ASSERT_GE(ttyout_fd, 0); @@ -281,7 +281,7 @@ TEST_IMPL(tty_large_write) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT_NE(handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); ttyout_fd = _open_osfhandle((intptr_t) handle, 0); ASSERT_GE(ttyout_fd, 0); @@ -321,7 +321,7 @@ TEST_IMPL(tty_raw_cancel) { OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT_NE(handle, INVALID_HANDLE_VALUE); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); ttyin_fd = _open_osfhandle((intptr_t) handle, 0); ASSERT_GE(ttyin_fd, 0); ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); diff --git a/test/test-udp-create-socket-early.c b/test/test-udp-create-socket-early.c index 4111d6ef01d..f2e166af9c2 100644 --- a/test/test-udp-create-socket-early.c +++ b/test/test-udp-create-socket-early.c @@ -45,14 +45,16 @@ TEST_IMPL(udp_create_early) { r = uv_fileno((const uv_handle_t*) &client, &fd); ASSERT_OK(r); - ASSERT_NE(fd, INVALID_FD); /* Windows returns WSAEINVAL if the socket is not bound */ #ifndef _WIN32 + ASSERT_NE(fd, INVALID_FD); namelen = sizeof sockname; r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen); ASSERT_OK(r); ASSERT_EQ(sockname.sin_family, AF_INET); +#else + ASSERT_PTR_NE(fd, INVALID_FD); #endif r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); @@ -89,11 +91,11 @@ TEST_IMPL(udp_create_early_bad_bind) { r = uv_fileno((const uv_handle_t*) &client, &fd); ASSERT_OK(r); - ASSERT_NE(fd, INVALID_FD); /* Windows returns WSAEINVAL if the socket is not bound */ -#ifndef _WIN32 - { +#ifndef _WIN32 + ASSERT_NE(fd, INVALID_FD); + { int namelen; struct sockaddr_in6 sockname; namelen = sizeof sockname; @@ -101,6 +103,8 @@ TEST_IMPL(udp_create_early_bad_bind) { ASSERT_OK(r); ASSERT_EQ(sockname.sin6_family, AF_INET6); } +#else + ASSERT_PTR_NE(fd, INVALID_FD); #endif r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); From 197f453b76e2eada48c640a91318cdc7fe820f56 Mon Sep 17 00:00:00 2001 From: Julien Roncaglia Date: Fri, 13 Oct 2023 21:32:46 +0200 Subject: [PATCH 441/713] darwin: workaround apple pthread_cond_wait bug (#4166) Under heavy workloads pthread_cond_wait on macOS can return EINVAL while all the input parameters are correct. As it happens due to a syscall having an errno of EBUSY we can detect it and work around it. Fixes: https://github.com/libuv/libuv/issues/4165 --- src/unix/thread.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/unix/thread.c b/src/unix/thread.c index 4d6f4b8232e..f05e6fe0f7d 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -789,11 +789,33 @@ void uv_cond_broadcast(uv_cond_t* cond) { abort(); } +#if defined(__APPLE__) && defined(__MACH__) + +void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { + int r; + + errno = 0; + r = pthread_cond_wait(cond, mutex); + + /* Workaround for a bug in OS X at least up to 13.6 + * See https://github.com/libuv/libuv/issues/4165 + */ + if (r == EINVAL) + if (errno == EBUSY) + return; + + if (r) + abort(); +} + +#else /* !(defined(__APPLE__) && defined(__MACH__)) */ + void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { if (pthread_cond_wait(cond, mutex)) abort(); } +#endif int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { int r; From dc1bb0088e8fbb92c81beb55341dcb7b4079717f Mon Sep 17 00:00:00 2001 From: Pleuvens Date: Sat, 14 Oct 2023 13:07:05 +0200 Subject: [PATCH 442/713] doc: uv_close should be called after exit callback (#4164) Fixes: https://github.com/libuv/libuv/issues/1911 --- docs/src/guide/processes.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/src/guide/processes.rst b/docs/src/guide/processes.rst index c1278f17f13..99d65c40735 100644 --- a/docs/src/guide/processes.rst +++ b/docs/src/guide/processes.rst @@ -53,6 +53,8 @@ ID of the child process. The exit callback will be invoked with the *exit status* and the type of *signal* which caused the exit. +Note that it is important **not** to call ``uv_close`` before the exit callback. + .. rubric:: spawn/main.c .. literalinclude:: ../../code/spawn/main.c :language: c @@ -126,7 +128,8 @@ of ``uv_kill`` is:: For processes started using libuv, you may use ``uv_process_kill`` instead, which accepts the ``uv_process_t`` watcher as the first argument, rather than -the pid. In this case, **remember to call** ``uv_close`` on the watcher. +the pid. In this case, **remember to call** ``uv_close`` on the watcher _after_ +the exit callback has been called. Signals ------- From 815dd8a25c3c395c42e596454ac6190e31322d5b Mon Sep 17 00:00:00 2001 From: prubel Date: Tue, 17 Oct 2023 22:24:34 +0000 Subject: [PATCH 443/713] test: 192.0.2.0/24 is the actual -TEST-NET-1 (#4133) Section 3 of rfc 5737 lists 192.0.2.0/24 as TEST-NET-1, fix confusion about /8 and /24. --- test/test-udp-send-hang-loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-udp-send-hang-loop.c b/test/test-udp-send-hang-loop.c index 706f6621ed1..763bb28bdb0 100644 --- a/test/test-udp-send-hang-loop.c +++ b/test/test-udp-send-hang-loop.c @@ -79,7 +79,7 @@ static void send_cb(uv_udp_send_t* req, int status) { TEST_IMPL(udp_send_hang_loop) { ASSERT_OK(uv_idle_init(uv_default_loop(), &idle_handle)); - /* 192.0.2.0/8 is "TEST-NET" and reserved for documentation. + /* 192.0.2.0/24 is "TEST-NET" and reserved for documentation. * Good for us, though. Since we want to have something unreachable. */ ASSERT_OK(uv_ip4_addr("192.0.2.3", TEST_PORT, &addr)); From 8d69f256d18d4a2fc8295399224d433748b8a466 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 21 Oct 2023 13:57:25 +0200 Subject: [PATCH 444/713] unix: add back preadv/pwritev fallback Implement in terms of pread/pwrite and only try to read/write the first buffer. Callers are supposed to handle partial reads and libuv takes care of partial writes. (Our own fs_read_bufs test doesn't but that's fine because this commit is a fix-up for unsupported platforms that aren't in our CI matrix.) Fixes: https://github.com/libuv/libuv/issues/4176 --- src/unix/fs.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 595fc2c3a78..0403e2682b1 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -82,6 +82,13 @@ # include #endif +#if defined(__CYGWIN__) || defined(__HAIKU__) || defined(__sun) +#define preadv(fd, bufs, nbufs, off) \ + pread(fd, (bufs)->iov_base, (bufs)->iov_len, off) +#define pwritev(fd, bufs, nbufs, off) \ + pwrite(fd, (bufs)->iov_base, (bufs)->iov_len, off) +#endif + #if defined(_AIX) && _XOPEN_SOURCE <= 600 extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */ #endif @@ -406,15 +413,16 @@ static ssize_t uv__fs_read_do(int fd, if (nbufs > iovmax) nbufs = iovmax; + result = 0; if (off < 0) { if (nbufs == 1) result = read(fd, bufs->iov_base, bufs->iov_len); - else + else if (nbufs > 1) result = readv(fd, bufs, nbufs); } else { if (nbufs == 1) result = pread(fd, bufs->iov_base, bufs->iov_len, off); - else + else if (nbufs > 1) result = preadv(fd, bufs, nbufs, off); } @@ -1089,15 +1097,16 @@ static ssize_t uv__fs_write_do(int fd, int64_t off) { ssize_t r; + r = 0; if (off < 0) { if (nbufs == 1) r = write(fd, bufs->iov_base, bufs->iov_len); - else + else if (nbufs > 1) r = writev(fd, bufs, nbufs); } else { if (nbufs == 1) r = pwrite(fd, bufs->iov_base, bufs->iov_len, off); - else + else if (nbufs > 1) r = pwritev(fd, bufs, nbufs, off); } From 8ac649e2aabf196e57478df6f1bcfc1754adfc62 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 21 Oct 2023 13:57:25 +0200 Subject: [PATCH 445/713] unix: rename variable for consistency uv__fs_write_do() calls it `r` so call it that in `uv__fs_read_do()` too. --- src/unix/fs.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 0403e2682b1..3081cb24aab 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -407,28 +407,28 @@ static ssize_t uv__fs_read_do(int fd, unsigned int nbufs, int64_t off) { unsigned int iovmax; - ssize_t result; + ssize_t r; iovmax = uv__getiovmax(); if (nbufs > iovmax) nbufs = iovmax; - result = 0; + r = 0; if (off < 0) { if (nbufs == 1) - result = read(fd, bufs->iov_base, bufs->iov_len); + r = read(fd, bufs->iov_base, bufs->iov_len); else if (nbufs > 1) - result = readv(fd, bufs, nbufs); + r = readv(fd, bufs, nbufs); } else { if (nbufs == 1) - result = pread(fd, bufs->iov_base, bufs->iov_len, off); + r = pread(fd, bufs->iov_base, bufs->iov_len, off); else if (nbufs > 1) - result = preadv(fd, bufs, nbufs, off); + r = preadv(fd, bufs, nbufs, off); } #ifdef __PASE__ /* PASE returns EOPNOTSUPP when reading a directory, convert to EISDIR */ - if (result == -1 && errno == EOPNOTSUPP) { + if (r == -1 && errno == EOPNOTSUPP) { struct stat buf; ssize_t rc; rc = uv__fstat(fd, &buf); @@ -438,7 +438,7 @@ static ssize_t uv__fs_read_do(int fd, } #endif - return result; + return r; } From 9956da15670d8793b4f1d5b4bfe0c64169421f27 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 21 Oct 2023 13:57:25 +0200 Subject: [PATCH 446/713] unix: merge read/write code into single functions I split those out in a previous commit in anticipation of changes that never came. Let's merge them back. --- src/unix/fs.c | 49 +++++++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 3081cb24aab..be2c5512216 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -402,12 +402,18 @@ static ssize_t uv__fs_open(uv_fs_t* req) { } -static ssize_t uv__fs_read_do(int fd, - const struct iovec* bufs, - unsigned int nbufs, - int64_t off) { +static ssize_t uv__fs_read(uv_fs_t* req) { + const struct iovec* bufs; unsigned int iovmax; + size_t nbufs; ssize_t r; + off_t off; + int fd; + + fd = req->file; + off = req->off; + bufs = (const struct iovec*) req->bufs; + nbufs = req->nbufs; iovmax = uv__getiovmax(); if (nbufs > iovmax) @@ -438,17 +444,6 @@ static ssize_t uv__fs_read_do(int fd, } #endif - return r; -} - - -static ssize_t uv__fs_read(uv_fs_t* req) { - const struct iovec* iov; - ssize_t result; - - iov = (const struct iovec*) req->bufs; - result = uv__fs_read_do(req->file, iov, req->nbufs, req->off); - /* We don't own the buffer list in the synchronous case. */ if (req->cb != NULL) if (req->bufs != req->bufsml) @@ -457,7 +452,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) { req->bufs = NULL; req->nbufs = 0; - return result; + return r; } @@ -1091,11 +1086,17 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) { } -static ssize_t uv__fs_write_do(int fd, - const struct iovec* bufs, - unsigned int nbufs, - int64_t off) { +static ssize_t uv__fs_write(uv_fs_t* req) { + const struct iovec* bufs; + size_t nbufs; ssize_t r; + off_t off; + int fd; + + fd = req->file; + off = req->off; + bufs = (const struct iovec*) req->bufs; + nbufs = req->nbufs; r = 0; if (off < 0) { @@ -1114,14 +1115,6 @@ static ssize_t uv__fs_write_do(int fd, } -static ssize_t uv__fs_write(uv_fs_t* req) { - const struct iovec* iov; - - iov = (const struct iovec*) req->bufs; - return uv__fs_write_do(req->file, iov, req->nbufs, req->off); -} - - static ssize_t uv__fs_copyfile(uv_fs_t* req) { uv_fs_t fs_req; uv_file srcfd; From c5f027d6be3fbe6bf8ea9b3e9ff2a773fe94048c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 22 Oct 2023 11:55:07 +0200 Subject: [PATCH 447/713] doc: filename arg to uv_fs_event_cb can be NULL (#4177) Refs: https://github.com/libuv/libuv/issues/4160 --- docs/src/fs_event.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/src/fs_event.rst b/docs/src/fs_event.rst index e28ec625ed6..54a776ae6f1 100644 --- a/docs/src/fs_event.rst +++ b/docs/src/fs_event.rst @@ -39,8 +39,12 @@ Data types .. c:type:: void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename, int events, int status) Callback passed to :c:func:`uv_fs_event_start` which will be called repeatedly - after the handle is started. If the handle was started with a directory the - `filename` parameter will be a relative path to a file contained in the directory. + after the handle is started. + + If the handle was started with a directory the `filename` parameter will + be a relative path to a file contained in the directory, or `NULL` if the + file name cannot be determined. + The `events` parameter is an ORed mask of :c:type:`uv_fs_event` elements. .. c:type:: uv_fs_event From b8368a1441fd4ebdaaae70b67136c80b1a98be32 Mon Sep 17 00:00:00 2001 From: Per Allansson <65364157+per-allansson@users.noreply.github.com> Date: Wed, 25 Oct 2023 21:48:57 +0200 Subject: [PATCH 448/713] build,win: we need to link against shell32.lib (#4182) The recently added support for minidumps use SHGetKnownFolderPath which requires shell32.lib - for some reason the builds work without that on x64, while failing on arm. --- CMakeLists.txt | 3 ++- configure.ac | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e1797f514d..ec2cb9b8df2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,7 +186,8 @@ if(WIN32) ws2_32 dbghelp ole32 - uuid) + uuid + shell32) list(APPEND uv_sources src/win/async.c src/win/core.c diff --git a/configure.ac b/configure.ac index a2c025851ac..24afba7bd61 100644 --- a/configure.ac +++ b/configure.ac @@ -74,7 +74,7 @@ AM_CONDITIONAL([OS400], [AS_CASE([$host_os],[os400], [true], [false]) AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])]) AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])]) AS_CASE([$host_os],[mingw*], [ - LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32 -ldbghelp -lole32 -luuid" + LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32 -ldbghelp -lole32 -luuid -lshell32" ]) AS_CASE([$host_os], [solaris2.10], [ CFLAGS="$CFLAGS -DSUNOS_NO_IFADDRS" From da527d8d2a908b824def74382761566371439003 Mon Sep 17 00:00:00 2001 From: "Jeffrey H. Johnson" Date: Thu, 26 Oct 2023 14:23:36 -0400 Subject: [PATCH 449/713] unix: no preadv/pwritev workaround if not needed (#4180) The workaround for preadv/pwritev is needed only for Solaris, not illumos, so avoid it on illumos. Haiku R1/prebeta5 (and later) provide preadv and pwritev, so only use workaround on lower versions. Signed-off-by: Jeffrey H. Johnson --- src/unix/fs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index be2c5512216..891306daedc 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -82,7 +82,9 @@ # include #endif -#if defined(__CYGWIN__) || defined(__HAIKU__) || defined(__sun) +#if defined(__CYGWIN__) || \ + (defined(__HAIKU__) && B_HAIKU_VERSION < B_HAIKU_VERSION_1_PRE_BETA_5) || \ + (defined(__sun) && !defined(__illumos__)) #define preadv(fd, bufs, nbufs, off) \ pread(fd, (bufs)->iov_base, (bufs)->iov_len, off) #define pwritev(fd, bufs, nbufs, off) \ From 7b34154cf265473c036c200a3d5c8155f5e7eaf8 Mon Sep 17 00:00:00 2001 From: Per Allansson <65364157+per-allansson@users.noreply.github.com> Date: Sat, 28 Oct 2023 00:53:45 +0200 Subject: [PATCH 450/713] build: add CI for Windows ARM64 (build only) (#4184) --- .github/workflows/CI-win.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index a8810eade49..a96e250aa69 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -26,6 +26,7 @@ jobs: - {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN} + - {toolchain: Visual Studio 17 2022, arch: arm64, server: 2022} steps: - uses: actions/checkout@v2 - name: Envinfo @@ -41,24 +42,26 @@ jobs: ls -l build - name: platform_output + if: ${{ matrix.config.arch != 'arm64' }} shell: cmd run: build\\RelWithDebInfo\\uv_run_tests.exe platform_output - name: platform_output_a + if: ${{ matrix.config.arch != 'arm64' }} shell: cmd run: build\\RelWithDebInfo\\uv_run_tests_a.exe platform_output - name: Test # only valid with libuv-master with the fix for # https://github.com/libuv/leps/blob/master/005-windows-handles-not-fd.md - if: ${{ matrix.config.config != 'ASAN' }} + if: ${{ matrix.config.config != 'ASAN' && matrix.config.arch != 'arm64' }} shell: cmd run: cd build ctest -C RelWithDebInfo -V - name: Test only static - if: ${{ matrix.config.config == 'ASAN' }} + if: ${{ matrix.config.config == 'ASAN' && matrix.config.arch != 'arm64' }} shell: cmd run: build\\RelWithDebInfo\\uv_run_tests_a.exe From a389393ffa731e0f6c32c0fb24268637b7c572a1 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 28 Oct 2023 13:18:42 +0200 Subject: [PATCH 451/713] linux: disable io_uring on 32 bits arm systems (#4187) It's been reported that no released kernels are bug-free enough to use io_uring without causing regressions. Fixes: https://github.com/libuv/libuv/issues/4158 --- src/unix/linux.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/unix/linux.c b/src/unix/linux.c index e71bdb3377b..8eeb352e623 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -475,6 +475,9 @@ int uv__io_uring_register(int fd, unsigned opcode, void* arg, unsigned nargs) { static int uv__use_io_uring(void) { #if defined(__ANDROID_API__) return 0; /* Possibly available but blocked by seccomp. */ +#elif defined(__arm__) && __SIZEOF_POINTER__ == 4 + /* See https://github.com/libuv/libuv/issues/4158. */ + return 0; /* All 32 bits kernels appear buggy. */ #else /* Ternary: unknown=0, yes=1, no=-1 */ static _Atomic int use_io_uring; From 56fca44a4bc4819a1c64d0435f8383f9c42ceab3 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 28 Oct 2023 15:05:42 +0200 Subject: [PATCH 452/713] build: run sanitizers on macos ci (#4189) Skip three fs_event tests that time out under Thread Sanitizer. --- .github/workflows/sanitizer.yml | 37 ++++++++++++++++++++++++++++++++- test/test-fs-event.c | 8 ++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 8173c8222c5..78052d0c553 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -13,7 +13,7 @@ on: - master jobs: - sanitizers: + sanitizers-linux: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 @@ -60,3 +60,38 @@ jobs: - name: UBSAN Test run: | ./build-ubsan/uv_run_tests_a + + sanitizers-macos: + runs-on: macos-11 + steps: + - uses: actions/checkout@v2 + + - name: Envinfo + run: npx envinfo + + - name: ASAN Build + run: | + mkdir build-asan + (cd build-asan && cmake .. -DBUILD_TESTING=ON -DASAN=ON -DCMAKE_BUILD_TYPE=Debug) + cmake --build build-asan + - name: ASAN Test + run: | + ./build-asan/uv_run_tests_a + + - name: TSAN Build + run: | + mkdir build-tsan + (cd build-tsan && cmake .. -DBUILD_TESTING=ON -DTSAN=ON -DCMAKE_BUILD_TYPE=Release) + cmake --build build-tsan + - name: TSAN Test + run: | + ./build-tsan/uv_run_tests_a + + - name: UBSAN Build + run: | + mkdir build-ubsan + (cd build-ubsan && cmake .. -DBUILD_TESTING=ON -DUBSAN=ON -DCMAKE_BUILD_TYPE=Debug) + cmake --build build-ubsan + - name: UBSAN Test + run: | + ./build-ubsan/uv_run_tests_a diff --git a/test/test-fs-event.c b/test/test-fs-event.c index b5c888d690f..7b5c0d8eb3d 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -405,6 +405,8 @@ TEST_IMPL(fs_event_watch_dir) { RETURN_SKIP(NO_FS_EVENTS); #elif defined(__MVS__) RETURN_SKIP("Directory watching not supported on this platform."); +#elif defined(__APPLE__) && defined(__TSAN__) + RETURN_SKIP("Times out under TSAN."); #endif uv_loop_t* loop = uv_default_loop(); @@ -443,7 +445,9 @@ TEST_IMPL(fs_event_watch_dir) { TEST_IMPL(fs_event_watch_dir_recursive) { -#if defined(__APPLE__) || defined(_WIN32) +#if defined(__APPLE__) && defined(__TSAN__) + RETURN_SKIP("Times out under TSAN."); +#elif defined(__APPLE__) || defined(_WIN32) uv_loop_t* loop; int r; uv_fs_event_t fs_event_root; @@ -946,6 +950,8 @@ TEST_IMPL(fs_event_close_in_callback) { RETURN_SKIP(NO_FS_EVENTS); #elif defined(__MVS__) RETURN_SKIP("Directory watching not supported on this platform."); +#elif defined(__APPLE__) && defined(__TSAN__) + RETURN_SKIP("Times out under TSAN."); #endif uv_loop_t* loop; int r; From f38890859365750f5e375f2c05680a5252efcf15 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 28 Oct 2023 21:04:57 -0400 Subject: [PATCH 453/713] misc: export WTF8 conversion utilities (#4021) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As promised in #2970, this attempts to migrate code to a common set of utilities in a common place in the code and use them everywhere. This also exports the functionality, since the Windows API with WideCharToMultiByte is fairly verbose relative to what libuv and libuv's clients typically need, so it is useful not to require clients to reimplement this conversion logic unnecessarily (and because Windows is not 64-bit ready here, but this implementation is.) --- docs/src/misc.rst | 47 +++++ include/uv.h | 12 ++ src/idna.c | 244 ++++++++++++++++++++++++- src/idna.h | 4 +- src/win/dl.c | 15 +- src/win/fs-event.c | 28 +-- src/win/fs.c | 376 ++++++++++---------------------------- src/win/getaddrinfo.c | 156 ++++------------ src/win/getnameinfo.c | 29 +-- src/win/internal.h | 5 +- src/win/pipe.c | 146 +++------------ src/win/process.c | 131 +++++--------- src/win/tty.c | 62 +++---- src/win/util.c | 410 +++++++++++------------------------------- test/test-idna.c | 1 + 15 files changed, 667 insertions(+), 999 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 8c3a00e934c..989618304d1 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -839,3 +839,50 @@ API Causes the calling thread to sleep for `msec` milliseconds. .. versionadded:: 1.34.0 + +String manipulation functions +----------------------------- + +These string utilities are needed internally for dealing with Windows, and are +exported to allow clients to work uniformly with this data when the libuv API +is not complete. + +.. c:function:: size_t uv_utf16_length_as_wtf8(const uint16_t* utf16, ssize_t utf16_len) + + Get the length of a UTF-16 (or UCS-2) `utf16` value after converting it to + WTF-8. If `utf16` is NUL terminated, `utf16_len` can be set to -1, + otherwise it must be specified. + + .. versionadded:: 1.47.0 + +.. c:function:: int uv_utf16_to_wtf8(const uint16_t* utf16, ssize_t utf16_len, char** wtf8_ptr, size_t* wtf8_len_ptr) + + Convert UTF-16 (or UCS-2) data in `utf16` to WTF-8 data in `*wtf8_ptr`. The + `utf16_len` count (in characters) gives the length of `utf16`. If `utf16` + is NUL terminated, `utf16_len` can be set to -1, otherwise it must be + specified. If `wtf8_ptr` is `NULL`, no result will be computed, but the + length (equal to `uv_utf16_length_as_wtf8`) will be stored in `wtf8_ptr`. + If `*wtf8_ptr` is `NULL`, space for the conversion will be allocated and + returned in `wtf8_ptr` and the length will be returned in `wtf8_len_ptr`. + Otherwise, the length of `*wtf8_ptr` must be passed in `wtf8_len_ptr`. The + `wtf8_ptr` must contain an extra space for an extra NUL after the result. + If the result is truncated, `UV_ENOBUFS` will be returned and + `wtf8_len_ptr` will be the length of the required `wtf8_ptr` to contain the + whole result. + + .. versionadded:: 1.47.0 + +.. c:function:: ssize_t uv_wtf8_length_as_utf16(const char* wtf8) + + Get the length in characters of a NUL-terminated WTF-8 `wtf8` value + after converting it to UTF-16 (or UCS-2), including NUL terminator. + + .. versionadded:: 1.47.0 + +.. c:function:: void uv_wtf8_to_utf16(const char* utf8, uint16_t* utf16, size_t utf16_len) + + Convert NUL-terminated WTF-8 data in `wtf8` to UTF-16 (or UCS-2) data + in `utf16`. The `utf16_len` count (in characters) must include space + for the NUL terminator. + + .. versionadded:: 1.47.0 diff --git a/include/uv.h b/include/uv.h index 02397dd0fdd..5642101c10c 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1885,6 +1885,18 @@ struct uv_loop_s { UV_EXTERN void* uv_loop_get_data(const uv_loop_t*); UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data); +/* String utilities needed internally for dealing with Windows. */ +size_t uv_utf16_length_as_wtf8(const uint16_t* utf16, + ssize_t utf16_len); +int uv_utf16_to_wtf8(const uint16_t* utf16, + ssize_t utf16_len, + char** wtf8_ptr, + size_t* wtf8_len_ptr); +ssize_t uv_wtf8_length_as_utf16(const char* wtf8); +void uv_wtf8_to_utf16(const char* wtf8, + uint16_t* utf16, + size_t utf16_len); + /* Don't export the private CPP symbols. */ #undef UV_HANDLE_TYPE_PRIVATE #undef UV_REQ_TYPE_PRIVATE diff --git a/src/idna.c b/src/idna.c index 93d982ca018..1c0a60cf3e3 100644 --- a/src/idna.c +++ b/src/idna.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, 2018 Ben Noordhuis +/* Copyright libuv contributors. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,11 +18,56 @@ */ #include "uv.h" +#include "uv-common.h" #include "idna.h" #include #include #include /* UINT_MAX */ + +static int32_t uv__wtf8_decode1(const char** input) { + uint32_t code_point; + uint8_t b1; + uint8_t b2; + uint8_t b3; + uint8_t b4; + + b1 = **input; + if (b1 <= 0x7F) + return b1; /* ASCII code point */ + if (b1 < 0xC2) + return -1; /* invalid: continuation byte */ + code_point = b1; + + b2 = *++*input; + if ((b2 & 0xC0) != 0x80) + return -1; /* invalid: not a continuation byte */ + code_point = (code_point << 6) | (b2 & 0x3F); + if (b1 <= 0xDF) + return 0x7FF & code_point; /* two-byte character */ + + b3 = *++*input; + if ((b3 & 0xC0) != 0x80) + return -1; /* invalid: not a continuation byte */ + code_point = (code_point << 6) | (b3 & 0x3F); + if (b1 <= 0xEF) + return 0xFFFF & code_point; /* three-byte character */ + + b4 = *++*input; + if ((b4 & 0xC0) != 0x80) + return -1; /* invalid: not a continuation byte */ + code_point = (code_point << 6) | (b4 & 0x3F); + if (b1 <= 0xF4) { + code_point &= 0x1FFFFF; + if (code_point <= 0x10FFFF) + return code_point; /* four-byte character */ + } + + /* code point too large */ + return -1; +} + + static unsigned uv__utf8_decode1_slow(const char** p, const char* pe, unsigned a) { @@ -89,6 +134,7 @@ static unsigned uv__utf8_decode1_slow(const char** p, return a; } + unsigned uv__utf8_decode1(const char** p, const char* pe) { unsigned a; @@ -102,6 +148,7 @@ unsigned uv__utf8_decode1(const char** p, const char* pe) { return uv__utf8_decode1_slow(p, pe, a); } + static int uv__idna_toascii_label(const char* s, const char* se, char** d, char* de) { static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789"; @@ -267,7 +314,8 @@ static int uv__idna_toascii_label(const char* s, const char* se, return 0; } -long uv__idna_toascii(const char* s, const char* se, char* d, char* de) { + +ssize_t uv__idna_toascii(const char* s, const char* se, char* d, char* de) { const char* si; const char* st; unsigned c; @@ -313,3 +361,195 @@ long uv__idna_toascii(const char* s, const char* se, char* d, char* de) { return d - ds; /* Number of bytes written. */ } + + +ssize_t uv_wtf8_length_as_utf16(const char* source_ptr) { + size_t w_target_len = 0; + int32_t code_point; + + do { + code_point = uv__wtf8_decode1(&source_ptr); + if (code_point < 0) + return -1; + if (code_point > 0xFFFF) + w_target_len++; + w_target_len++; + } while (*source_ptr++); + + return w_target_len; +} + + +void uv_wtf8_to_utf16(const char* source_ptr, + uint16_t* w_target, + size_t w_target_len) { + int32_t code_point; + + do { + 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) { + assert(code_point < 0x10FFFF); + *w_target++ = (((code_point - 0x10000) >> 10) + 0xD800); + *w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00; + w_target_len -= 2; + } else { + *w_target++ = code_point; + w_target_len -= 1; + } + } while (*source_ptr++); + + assert(w_target_len == 0); +} + + +static int32_t uv__get_surrogate_value(const uint16_t* w_source_ptr, + ssize_t w_source_len) { + uint16_t u; + uint16_t next; + + u = w_source_ptr[0]; + if (u >= 0xD800 && u <= 0xDBFF && w_source_len != 1) { + next = w_source_ptr[1]; + if (next >= 0xDC00 && next <= 0xDFFF) + return 0x10000 + ((u - 0xD800) << 10) + (next - 0xDC00); + } + return u; +} + + +size_t uv_utf16_length_as_wtf8(const uint16_t* w_source_ptr, + ssize_t w_source_len) { + size_t target_len; + int32_t code_point; + + target_len = 0; + while (w_source_len) { + code_point = uv__get_surrogate_value(w_source_ptr, w_source_len); + /* Can be invalid UTF-8 but must be valid WTF-8. */ + assert(code_point >= 0); + if (w_source_len < 0 && code_point == 0) + break; + if (code_point < 0x80) + target_len += 1; + else if (code_point < 0x800) + target_len += 2; + else if (code_point < 0x10000) + target_len += 3; + else { + target_len += 4; + w_source_ptr++; + if (w_source_len > 0) + w_source_len--; + } + w_source_ptr++; + if (w_source_len > 0) + w_source_len--; + } + + return target_len; +} + + +int uv_utf16_to_wtf8(const uint16_t* w_source_ptr, + ssize_t w_source_len, + char** target_ptr, + size_t* target_len_ptr) { + size_t target_len; + char* target; + char* target_end; + int32_t code_point; + + /* If *target_ptr is provided, then *target_len_ptr must be its length + * (excluding space for NUL), otherwise we will compute the target_len_ptr + * length and may return a new allocation in *target_ptr if target_ptr is + * provided. */ + if (target_ptr == NULL || *target_ptr == NULL) { + target_len = uv_utf16_length_as_wtf8(w_source_ptr, w_source_len); + if (target_len_ptr != NULL) + *target_len_ptr = target_len; + } else { + target_len = *target_len_ptr; + } + + if (target_ptr == NULL) + return 0; + + if (*target_ptr == NULL) { + target = uv__malloc(target_len + 1); + if (target == NULL) { + return UV_ENOMEM; + } + *target_ptr = target; + } else { + target = *target_ptr; + } + + target_end = target + target_len; + + while (target != target_end && w_source_len) { + code_point = uv__get_surrogate_value(w_source_ptr, w_source_len); + /* Can be invalid UTF-8 but must be valid WTF-8. */ + assert(code_point >= 0); + if (w_source_len < 0 && code_point == 0) { + w_source_len = 0; + break; + } + if (code_point < 0x80) { + *target++ = code_point; + } else if (code_point < 0x800) { + *target++ = 0xC0 | (code_point >> 6); + if (target == target_end) + break; + *target++ = 0x80 | (code_point & 0x3F); + } else if (code_point < 0x10000) { + *target++ = 0xE0 | (code_point >> 12); + if (target == target_end) + break; + *target++ = 0x80 | ((code_point >> 6) & 0x3F); + if (target == target_end) + break; + *target++ = 0x80 | (code_point & 0x3F); + } else { + *target++ = 0xF0 | (code_point >> 18); + if (target == target_end) + break; + *target++ = 0x80 | ((code_point >> 12) & 0x3F); + if (target == target_end) + break; + *target++ = 0x80 | ((code_point >> 6) & 0x3F); + if (target == target_end) + break; + *target++ = 0x80 | (code_point & 0x3F); + /* uv__get_surrogate_value consumed 2 input characters */ + w_source_ptr++; + if (w_source_len > 0) + w_source_len--; + } + target_len = target - *target_ptr; + w_source_ptr++; + if (w_source_len > 0) + w_source_len--; + } + + if (target != target_end && target_len_ptr != NULL) + /* Did not fill all of the provided buffer, so update the target_len_ptr + * output with the space used. */ + *target_len_ptr = target - *target_ptr; + + /* Check if input fit into target exactly. */ + if (w_source_len < 0 && target == target_end && w_source_ptr[0] == 0) + w_source_len = 0; + + *target++ = '\0'; + + /* Characters remained after filling the buffer, compute the remaining length now. */ + if (w_source_len) { + if (target_len_ptr != NULL) + *target_len_ptr = target_len + uv_utf16_length_as_wtf8(w_source_ptr, w_source_len); + return UV_ENOBUFS; + } + + return 0; +} diff --git a/src/idna.h b/src/idna.h index 8e0c592fe13..ea6b4df9671 100644 --- a/src/idna.h +++ b/src/idna.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, 2018 Ben Noordhuis +/* Copyright libuv contributors. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -26,6 +26,6 @@ unsigned uv__utf8_decode1(const char** p, const char* pe); * is the number of bytes written to |d|, including the trailing nul byte. * A return value < 0 is a libuv error code. |s| and |d| can not overlap. */ -long uv__idna_toascii(const char* s, const char* se, char* d, char* de); +ssize_t uv__idna_toascii(const char* s, const char* se, char* d, char* de); #endif /* UV_SRC_IDNA_H_ */ diff --git a/src/win/dl.c b/src/win/dl.c index 676be4dc7b5..7880c9595be 100644 --- a/src/win/dl.c +++ b/src/win/dl.c @@ -27,18 +27,17 @@ static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno); int uv_dlopen(const char* filename, uv_lib_t* lib) { WCHAR filename_w[32768]; + ssize_t r; lib->handle = NULL; lib->errmsg = NULL; - if (!MultiByteToWideChar(CP_UTF8, - 0, - filename, - -1, - filename_w, - ARRAY_SIZE(filename_w))) { - return uv__dlerror(lib, filename, GetLastError()); - } + r = uv_wtf8_length_as_utf16(filename); + if (r < 0) + return uv__dlerror(lib, filename, ERROR_NO_UNICODE_TRANSLATION); + if ((size_t) r > ARRAY_SIZE(filename_w)) + return uv__dlerror(lib, filename, ERROR_INSUFFICIENT_BUFFER); + uv_wtf8_to_utf16(filename, filename_w, r); lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (lib->handle == NULL) { diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 6758c7c78bc..4a0ca1f70a2 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -157,7 +157,8 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags) { - int name_size, is_path_dir, size; + int is_path_dir; + size_t size; DWORD attr, last_error; WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL; DWORD short_path_buffer_len; @@ -176,23 +177,9 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv__handle_start(handle); - /* Convert name to UTF16. */ - - name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) * - sizeof(WCHAR); - pathw = (WCHAR*)uv__malloc(name_size); - if (!pathw) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - if (!MultiByteToWideChar(CP_UTF8, - 0, - path, - -1, - pathw, - name_size / sizeof(WCHAR))) { - return uv_translate_sys_error(GetLastError()); - } + last_error = uv__convert_utf8_to_utf16(path, &pathw); + if (last_error) + goto error_uv; /* Determine whether path is a file or a directory. */ attr = GetFileAttributesW(pathw); @@ -333,6 +320,9 @@ int uv_fs_event_start(uv_fs_event_t* handle, return 0; error: + last_error = uv_translate_sys_error(last_error); + +error_uv: if (handle->path) { uv__free(handle->path); handle->path = NULL; @@ -365,7 +355,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv__free(short_path); - return uv_translate_sys_error(last_error); + return last_error; } diff --git a/src/win/fs.c b/src/win/fs.c index 314a3543496..99c8a2bf8bf 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -147,281 +147,6 @@ void uv__fs_init(void) { } -static int32_t fs__decode_wtf8_char(const char** input) { - uint32_t code_point; - uint8_t b1; - uint8_t b2; - uint8_t b3; - uint8_t b4; - - b1 = **input; - if (b1 <= 0x7F) - return b1; /* ASCII code point */ - if (b1 < 0xC2) - return -1; /* invalid: continuation byte */ - code_point = b1; - - b2 = *++*input; - if ((b2 & 0xC0) != 0x80) - return -1; /* invalid: not a continuation byte */ - code_point = (code_point << 6) | (b2 & 0x3F); - if (b1 <= 0xDF) - return 0x7FF & code_point; /* two-byte character */ - - b3 = *++*input; - if ((b3 & 0xC0) != 0x80) - return -1; /* invalid: not a continuation byte */ - code_point = (code_point << 6) | (b3 & 0x3F); - if (b1 <= 0xEF) - return 0xFFFF & code_point; /* three-byte character */ - - b4 = *++*input; - if ((b4 & 0xC0) != 0x80) - return -1; /* invalid: not a continuation byte */ - code_point = (code_point << 6) | (b4 & 0x3F); - if (b1 <= 0xF4) { - code_point &= 0x1FFFFF; - if (code_point <= 0x10FFFF) - return code_point; /* four-byte character */ - } - - /* code point too large */ - return -1; -} - - -static ssize_t fs__get_length_wtf8(const char* source_ptr) { - size_t w_target_len = 0; - int32_t code_point; - - do { - code_point = fs__decode_wtf8_char(&source_ptr); - if (code_point < 0) - return -1; - if (code_point > 0xFFFF) - w_target_len++; - w_target_len++; - } while (*source_ptr++); - return w_target_len; -} - - -static void fs__wtf8_to_wide(const char* source_ptr, WCHAR* w_target) { - int32_t code_point; - - do { - code_point = fs__decode_wtf8_char(&source_ptr); - /* fs__get_length_wtf8 should have been called and checked first. */ - assert(code_point >= 0); - if (code_point > 0x10000) { - assert(code_point < 0x10FFFF); - *w_target++ = (((code_point - 0x10000) >> 10) + 0xD800); - *w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00; - } else { - *w_target++ = code_point; - } - } while (*source_ptr++); -} - - -INLINE static int fs__capture_path(uv_fs_t* req, const char* path, - const char* new_path, const int copy_path) { - WCHAR* buf; - WCHAR* pos; - size_t buf_sz = 0; - size_t path_len = 0; - ssize_t pathw_len = 0; - ssize_t new_pathw_len = 0; - - /* new_path can only be set if path is also set. */ - assert(new_path == NULL || path != NULL); - - if (path != NULL) { - pathw_len = fs__get_length_wtf8(path); - if (pathw_len < 0) - return ERROR_INVALID_NAME; - buf_sz += pathw_len * sizeof(WCHAR); - } - - if (path != NULL && copy_path) { - path_len = 1 + strlen(path); - buf_sz += path_len; - } - - if (new_path != NULL) { - new_pathw_len = fs__get_length_wtf8(new_path); - if (new_pathw_len < 0) - return ERROR_INVALID_NAME; - buf_sz += new_pathw_len * sizeof(WCHAR); - } - - - if (buf_sz == 0) { - req->file.pathw = NULL; - req->fs.info.new_pathw = NULL; - req->path = NULL; - return 0; - } - - buf = uv__malloc(buf_sz); - if (buf == NULL) { - return ERROR_OUTOFMEMORY; - } - - pos = buf; - - if (path != NULL) { - fs__wtf8_to_wide(path, pos); - req->file.pathw = pos; - pos += pathw_len; - } else { - req->file.pathw = NULL; - } - - if (new_path != NULL) { - fs__wtf8_to_wide(new_path, pos); - req->fs.info.new_pathw = pos; - pos += new_pathw_len; - } else { - req->fs.info.new_pathw = NULL; - } - - req->path = path; - if (path != NULL && copy_path) { - memcpy(pos, path, path_len); - assert(path_len == buf_sz - (pos - buf) * sizeof(WCHAR)); - req->path = (char*) pos; - } - - req->flags |= UV_FS_FREE_PATHS; - - return 0; -} - - - -INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req, - uv_fs_type fs_type, const uv_fs_cb cb) { - uv__once_init(); - UV_REQ_INIT(req, UV_FS); - req->loop = loop; - req->flags = 0; - req->fs_type = fs_type; - req->sys_errno_ = 0; - req->result = 0; - req->ptr = NULL; - req->path = NULL; - req->cb = cb; - memset(&req->fs, 0, sizeof(req->fs)); -} - - -static int32_t fs__get_surrogate_value(const WCHAR* w_source_ptr, - size_t w_source_len) { - WCHAR u; - WCHAR next; - - u = w_source_ptr[0]; - if (u >= 0xD800 && u <= 0xDBFF && w_source_len > 1) { - next = w_source_ptr[1]; - if (next >= 0xDC00 && next <= 0xDFFF) - return 0x10000 + ((u - 0xD800) << 10) + (next - 0xDC00); - } - return u; -} - - -static size_t fs__get_length_wide(const WCHAR* w_source_ptr, - size_t w_source_len) { - size_t target_len; - int32_t code_point; - - target_len = 0; - for (; w_source_len; w_source_len--, w_source_ptr++) { - code_point = fs__get_surrogate_value(w_source_ptr, w_source_len); - /* Can be invalid UTF-8 but must be valid WTF-8. */ - assert(code_point >= 0); - if (code_point < 0x80) - target_len += 1; - else if (code_point < 0x800) - target_len += 2; - else if (code_point < 0x10000) - target_len += 3; - else { - target_len += 4; - w_source_ptr++; - w_source_len--; - } - } - return target_len; -} - - -static int fs__wide_to_wtf8(WCHAR* w_source_ptr, - size_t w_source_len, - char** target_ptr, - size_t* target_len_ptr) { - size_t target_len; - char* target; - int32_t code_point; - - /* If *target_ptr is provided, then *target_len_ptr must be its length - * (excluding space for null), otherwise we will compute the target_len_ptr - * length and may return a new allocation in *target_ptr if target_ptr is - * provided. */ - if (target_ptr == NULL || *target_ptr == NULL) { - target_len = fs__get_length_wide(w_source_ptr, w_source_len); - if (target_len_ptr != NULL) - *target_len_ptr = target_len; - } else { - target_len = *target_len_ptr; - } - - if (target_ptr == NULL) - return 0; - - if (*target_ptr == NULL) { - target = uv__malloc(target_len + 1); - if (target == NULL) { - SetLastError(ERROR_OUTOFMEMORY); - return -1; - } - *target_ptr = target; - } else { - target = *target_ptr; - } - - for (; w_source_len; w_source_len--, w_source_ptr++) { - code_point = fs__get_surrogate_value(w_source_ptr, w_source_len); - /* Can be invalid UTF-8 but must be valid WTF-8. */ - assert(code_point >= 0); - - if (code_point < 0x80) { - *target++ = code_point; - } else if (code_point < 0x800) { - *target++ = 0xC0 | (code_point >> 6); - *target++ = 0x80 | (code_point & 0x3F); - } else if (code_point < 0x10000) { - *target++ = 0xE0 | (code_point >> 12); - *target++ = 0x80 | ((code_point >> 6) & 0x3F); - *target++ = 0x80 | (code_point & 0x3F); - } else { - *target++ = 0xF0 | (code_point >> 18); - *target++ = 0x80 | ((code_point >> 12) & 0x3F); - *target++ = 0x80 | ((code_point >> 6) & 0x3F); - *target++ = 0x80 | (code_point & 0x3F); - w_source_ptr++; - w_source_len--; - } - } - assert((size_t) (target - *target_ptr) == target_len); - - *target++ = '\0'; - - return 0; -} - - INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, size_t* target_len_ptr) { @@ -555,7 +280,98 @@ INLINE static int fs__readlink_handle(HANDLE handle, } assert(target_ptr == NULL || *target_ptr == NULL); - return fs__wide_to_wtf8(w_target, w_target_len, target_ptr, target_len_ptr); + return uv_utf16_to_wtf8(w_target, w_target_len, target_ptr, target_len_ptr); +} + + +INLINE static int fs__capture_path(uv_fs_t* req, const char* path, + const char* new_path, const int copy_path) { + WCHAR* buf; + WCHAR* pos; + size_t buf_sz = 0; + size_t path_len = 0; + ssize_t pathw_len = 0; + ssize_t new_pathw_len = 0; + + /* new_path can only be set if path is also set. */ + assert(new_path == NULL || path != NULL); + + if (path != NULL) { + pathw_len = uv_wtf8_length_as_utf16(path); + if (pathw_len < 0) + return ERROR_INVALID_NAME; + buf_sz += pathw_len * sizeof(WCHAR); + } + + if (path != NULL && copy_path) { + path_len = 1 + strlen(path); + buf_sz += path_len; + } + + if (new_path != NULL) { + new_pathw_len = uv_wtf8_length_as_utf16(new_path); + if (new_pathw_len < 0) + return ERROR_INVALID_NAME; + buf_sz += new_pathw_len * sizeof(WCHAR); + } + + + if (buf_sz == 0) { + req->file.pathw = NULL; + req->fs.info.new_pathw = NULL; + req->path = NULL; + return 0; + } + + buf = uv__malloc(buf_sz); + if (buf == NULL) { + return ERROR_OUTOFMEMORY; + } + + pos = buf; + + if (path != NULL) { + uv_wtf8_to_utf16(path, pos, pathw_len); + req->file.pathw = pos; + pos += pathw_len; + } else { + req->file.pathw = NULL; + } + + if (new_path != NULL) { + uv_wtf8_to_utf16(new_path, pos, new_pathw_len); + req->fs.info.new_pathw = pos; + pos += new_pathw_len; + } else { + req->fs.info.new_pathw = NULL; + } + + req->path = path; + if (path != NULL && copy_path) { + memcpy(pos, path, path_len); + assert(path_len == buf_sz - (pos - buf) * sizeof(WCHAR)); + req->path = (char*) pos; + } + + req->flags |= UV_FS_FREE_PATHS; + + return 0; +} + + +INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req, + uv_fs_type fs_type, const uv_fs_cb cb) { + uv__once_init(); + UV_REQ_INIT(req, UV_FS); + req->loop = loop; + req->flags = 0; + req->fs_type = fs_type; + req->sys_errno_ = 0; + req->result = 0; + req->ptr = NULL; + req->path = NULL; + req->cb = cb; + memset(&req->fs, 0, sizeof(req->fs)); } @@ -1574,7 +1390,7 @@ void fs__scandir(uv_fs_t* req) { continue; /* Compute the space required to store the filename as WTF-8. */ - wtf8_len = fs__get_length_wide(&info->FileName[0], wchar_len); + wtf8_len = uv_utf16_length_as_wtf8(&info->FileName[0], wchar_len); /* Resize the dirent array if needed. */ if (dirents_used >= dirents_size) { @@ -1602,8 +1418,8 @@ void fs__scandir(uv_fs_t* req) { /* Convert file name to UTF-8. */ wtf8 = &dirent->d_name[0]; - if (fs__wide_to_wtf8(&info->FileName[0], wchar_len, &wtf8, &wtf8_len) == -1) - goto win32_error; + if (uv_utf16_to_wtf8(&info->FileName[0], wchar_len, &wtf8, &wtf8_len) != 0) + goto out_of_memory_error; /* Fill out the type field. */ if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE) @@ -2829,7 +2645,7 @@ static ssize_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { } assert(*realpath_ptr == NULL); - r = fs__wide_to_wtf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); + r = uv_utf16_to_wtf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); uv__free(w_realpath_buf); return r; } diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index dfab860a735..8b8406ada8e 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -104,13 +104,14 @@ static void uv__getaddrinfo_work(struct uv__work* w) { */ static void uv__getaddrinfo_done(struct uv__work* w, int status) { uv_getaddrinfo_t* req; - int addrinfo_len = 0; - int name_len = 0; + size_t addrinfo_len = 0; + ssize_t name_len = 0; size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); struct addrinfoW* addrinfow_ptr; struct addrinfo* addrinfo_ptr; char* alloc_ptr = NULL; char* cur_ptr = NULL; + int r; req = container_of(w, uv_getaddrinfo_t, work_req); @@ -131,19 +132,12 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); if (addrinfow_ptr->ai_canonname != NULL) { - name_len = WideCharToMultiByte(CP_UTF8, - 0, - addrinfow_ptr->ai_canonname, - -1, - NULL, - 0, - NULL, - NULL); - if (name_len == 0) { - req->retcode = uv_translate_sys_error(GetLastError()); + name_len = uv_utf16_length_as_wtf8(addrinfow_ptr->ai_canonname, -1); + if (name_len < 0) { + req->retcode = name_len; goto complete; } - addrinfo_len += ALIGNED_SIZE(name_len); + addrinfo_len += ALIGNED_SIZE(name_len + 1); } addrinfow_ptr = addrinfow_ptr->ai_next; } @@ -182,27 +176,14 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { /* convert canonical name to UTF-8 */ if (addrinfow_ptr->ai_canonname != NULL) { - name_len = WideCharToMultiByte(CP_UTF8, - 0, - addrinfow_ptr->ai_canonname, - -1, - NULL, - 0, - NULL, - NULL); - assert(name_len > 0); - assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); - name_len = WideCharToMultiByte(CP_UTF8, - 0, - addrinfow_ptr->ai_canonname, - -1, - cur_ptr, - name_len, - NULL, - NULL); - assert(name_len > 0); + name_len = alloc_ptr + addrinfo_len - cur_ptr; + r = uv__copy_utf16_to_utf8(addrinfow_ptr->ai_canonname, + -1, + cur_ptr, + (size_t*)&name_len); + assert(r == 0); addrinfo_ptr->ai_canonname = cur_ptr; - cur_ptr += ALIGNED_SIZE(name_len); + cur_ptr += ALIGNED_SIZE(name_len + 1); } assert(cur_ptr <= alloc_ptr + addrinfo_len); @@ -261,12 +242,11 @@ int uv_getaddrinfo(uv_loop_t* loop, const char* service, const struct addrinfo* hints) { char hostname_ascii[256]; - int nodesize = 0; - int servicesize = 0; - int hintssize = 0; + size_t nodesize = 0; + size_t servicesize = 0; + size_t hintssize = 0; char* alloc_ptr = NULL; - int err; - long rc; + ssize_t rc; if (req == NULL || (node == NULL && service == NULL)) { return UV_EINVAL; @@ -286,56 +266,36 @@ int uv_getaddrinfo(uv_loop_t* loop, hostname_ascii + sizeof(hostname_ascii)); if (rc < 0) return rc; - nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii, - -1, NULL, 0) * sizeof(WCHAR)); - if (nodesize == 0) { - err = GetLastError(); - goto error; - } + nodesize = strlen(hostname_ascii) + 1; node = hostname_ascii; } if (service != NULL) { - servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, - 0, - service, - -1, - NULL, - 0) * - sizeof(WCHAR)); - if (servicesize == 0) { - err = GetLastError(); - goto error; - } + rc = uv_wtf8_length_as_utf16(service); + if (rc < 0) + return rc; + servicesize = rc; } if (hints != NULL) { hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW)); } /* allocate memory for inputs, and partition it as needed */ - alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize); - if (!alloc_ptr) { - err = WSAENOBUFS; - goto error; - } + alloc_ptr = uv__malloc(ALIGNED_SIZE(nodesize * sizeof(WCHAR)) + + ALIGNED_SIZE(servicesize * sizeof(WCHAR)) + + hintssize); + if (!alloc_ptr) + return UV_ENOMEM; /* save alloc_ptr now so we can free if error */ - req->alloc = (void*)alloc_ptr; + req->alloc = (void*) alloc_ptr; /* Convert node string to UTF16 into allocated memory and save pointer in the - * request. */ + * request. The node here has been converted to ascii. */ if (node != NULL) { - req->node = (WCHAR*)alloc_ptr; - if (MultiByteToWideChar(CP_UTF8, - 0, - node, - -1, - (WCHAR*) alloc_ptr, - nodesize / sizeof(WCHAR)) == 0) { - err = GetLastError(); - goto error; - } - alloc_ptr += nodesize; + req->node = (WCHAR*) alloc_ptr; + uv_wtf8_to_utf16(node, (WCHAR*) alloc_ptr, nodesize); + alloc_ptr += ALIGNED_SIZE(nodesize * sizeof(WCHAR)); } else { req->node = NULL; } @@ -343,24 +303,16 @@ int uv_getaddrinfo(uv_loop_t* loop, /* Convert service string to UTF16 into allocated memory and save pointer in * the req. */ if (service != NULL) { - req->service = (WCHAR*)alloc_ptr; - if (MultiByteToWideChar(CP_UTF8, - 0, - service, - -1, - (WCHAR*) alloc_ptr, - servicesize / sizeof(WCHAR)) == 0) { - err = GetLastError(); - goto error; - } - alloc_ptr += servicesize; + req->service = (WCHAR*) alloc_ptr; + uv_wtf8_to_utf16(service, (WCHAR*) alloc_ptr, servicesize); + alloc_ptr += ALIGNED_SIZE(servicesize * sizeof(WCHAR)); } else { req->service = NULL; } /* copy hints to allocated memory and save pointer in req */ if (hints != NULL) { - req->addrinfow = (struct addrinfoW*)alloc_ptr; + req->addrinfow = (struct addrinfoW*) alloc_ptr; req->addrinfow->ai_family = hints->ai_family; req->addrinfow->ai_socktype = hints->ai_socktype; req->addrinfow->ai_protocol = hints->ai_protocol; @@ -387,19 +339,11 @@ int uv_getaddrinfo(uv_loop_t* loop, uv__getaddrinfo_done(&req->work_req, 0); return req->retcode; } - -error: - if (req != NULL) { - uv__free(req->alloc); - req->alloc = NULL; - } - return uv_translate_sys_error(err); } int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { NET_LUID luid; wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */ - DWORD bufsize; int r; if (buffer == NULL || size == NULL || *size == 0) @@ -415,31 +359,7 @@ int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { if (r != 0) return uv_translate_sys_error(r); - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL); - - if (bufsize == 0) { - return uv_translate_sys_error(GetLastError()); - } else if (bufsize > *size) { - *size = bufsize; - return UV_ENOBUFS; - } - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - wname, - -1, - buffer, - *size, - NULL, - NULL); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - *size = bufsize - 1; - return 0; + return uv__copy_utf16_to_utf8(wname, -1, buffer, size); } int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { diff --git a/src/win/getnameinfo.c b/src/win/getnameinfo.c index b3773380c21..32863176ef6 100644 --- a/src/win/getnameinfo.c +++ b/src/win/getnameinfo.c @@ -42,6 +42,7 @@ static void uv__getnameinfo_work(struct uv__work* w) { uv_getnameinfo_t* req; WCHAR host[NI_MAXHOST]; WCHAR service[NI_MAXSERV]; + size_t size; int ret; req = container_of(w, uv_getnameinfo_t, work_req); @@ -57,29 +58,17 @@ static void uv__getnameinfo_work(struct uv__work* w) { return; } - ret = WideCharToMultiByte(CP_UTF8, - 0, - host, - -1, - req->host, - sizeof(req->host), - NULL, - NULL); - if (ret == 0) { - req->retcode = uv_translate_sys_error(GetLastError()); + size = sizeof(req->host); + ret = uv__copy_utf16_to_utf8(host, -1, req->host, &size); + if (ret < 0) { + req->retcode = ret; return; } - ret = WideCharToMultiByte(CP_UTF8, - 0, - service, - -1, - req->service, - sizeof(req->service), - NULL, - NULL); - if (ret == 0) { - req->retcode = uv_translate_sys_error(GetLastError()); + size = sizeof(req->service); + ret = uv__copy_utf16_to_utf8(service, -1, req->service, &size); + if (ret < 0) { + req->retcode = ret; } } diff --git a/src/win/internal.h b/src/win/internal.h index 9672fbc6826..867dea5e0ed 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -257,8 +257,9 @@ void uv__util_init(void); uint64_t uv__hrtime(unsigned int scale); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); -int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); -int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16); +int uv__convert_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char** utf8); +int uv__copy_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char* utf8, size_t *size); +int uv__convert_utf8_to_utf16(const char* utf8, WCHAR** utf16); typedef int (WINAPI *uv__peersockfunc)(SOCKET, struct sockaddr*, int*); diff --git a/src/win/pipe.c b/src/win/pipe.c index f0cac382256..cec72ff750b 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -49,7 +49,7 @@ static const int default_pending_pipe_instances = 4; /* Pipe prefix */ static char pipe_prefix[] = "\\\\?\\pipe"; -static const int pipe_prefix_len = sizeof(pipe_prefix) - 1; +static const size_t pipe_prefix_len = sizeof(pipe_prefix) - 1; /* IPC incoming xfer queue item. */ typedef struct { @@ -703,7 +703,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, size_t namelen, unsigned int flags) { uv_loop_t* loop = handle->loop; - int i, err, nameSize; + int i, err; uv_pipe_accept_t* req; if (flags & ~UV_PIPE_NO_TRUNCATE) { @@ -742,9 +742,8 @@ int uv_pipe_bind2(uv_pipe_t* handle, handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*) uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances); - if (!handle->pipe.serv.accept_reqs) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } + if (!handle->pipe.serv.accept_reqs) + return UV_ENOMEM; for (i = 0; i < handle->pipe.serv.pending_instances; i++) { req = &handle->pipe.serv.accept_reqs[i]; @@ -754,22 +753,9 @@ int uv_pipe_bind2(uv_pipe_t* handle, req->next_pending = NULL; } - /* Convert name to UTF16. */ - nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); - handle->name = uv__malloc(nameSize); - if (!handle->name) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - if (!MultiByteToWideChar(CP_UTF8, - 0, - name, - -1, - handle->name, - nameSize / sizeof(WCHAR))) { - err = GetLastError(); - goto error; - } + err = uv__convert_utf8_to_utf16(name, &handle->name); + if (err) + return err; /* * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE. @@ -795,10 +781,8 @@ int uv_pipe_bind2(uv_pipe_t* handle, return 0; error: - if (handle->name) { - uv__free(handle->name); - handle->name = NULL; - } + uv__free(handle->name); + handle->name = NULL; return uv_translate_sys_error(err); } @@ -861,7 +845,8 @@ int uv_pipe_connect2(uv_connect_t* req, unsigned int flags, uv_connect_cb cb) { uv_loop_t* loop = handle->loop; - int err, nameSize; + int err; + size_t nameSize; HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; @@ -904,26 +889,16 @@ int uv_pipe_connect2(uv_connect_t* req, } uv__pipe_connection_init(handle); - /* Convert name to UTF16. */ - nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); - handle->name = uv__malloc(nameSize); - if (!handle->name) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - if (!MultiByteToWideChar(CP_UTF8, - 0, - name, - -1, - handle->name, - nameSize / sizeof(WCHAR))) { - err = GetLastError(); + err = uv__convert_utf8_to_utf16(name, &handle->name); + if (err) { + err = ERROR_NO_UNICODE_TRANSLATION; goto error; } pipeHandle = open_named_pipe(handle->name, &duplex_flags); if (pipeHandle == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_PIPE_BUSY) { + nameSize = (wcslen(handle->name) + 1) * sizeof(WCHAR); req->u.connect.name = uv__malloc(nameSize); if (!req->u.connect.name) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); @@ -2439,7 +2414,6 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) FILE_NAME_INFORMATION tmp_name_info; FILE_NAME_INFORMATION* name_info; WCHAR* name_buf; - unsigned int addrlen; unsigned int name_size; unsigned int name_len; int err; @@ -2450,46 +2424,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) if (handle->name != NULL) { /* The user might try to query the name before we are connected, * and this is just easier to return the cached value if we have it. */ - name_buf = handle->name; - name_len = wcslen(name_buf); - - /* check how much space we need */ - addrlen = WideCharToMultiByte(CP_UTF8, - 0, - name_buf, - name_len, - NULL, - 0, - NULL, - NULL); - if (!addrlen) { - *size = 0; - err = uv_translate_sys_error(GetLastError()); - return err; - } else if (addrlen >= *size) { - *size = addrlen + 1; - err = UV_ENOBUFS; - goto error; - } - - addrlen = WideCharToMultiByte(CP_UTF8, - 0, - name_buf, - name_len, - buffer, - addrlen, - NULL, - NULL); - if (!addrlen) { - *size = 0; - err = uv_translate_sys_error(GetLastError()); - return err; - } - - *size = addrlen; - buffer[addrlen] = '\0'; - - return 0; + return uv__copy_utf16_to_utf8(handle->name, -1, buffer, size); } if (handle->handle == INVALID_HANDLE_VALUE) { @@ -2517,8 +2452,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) name_info = uv__malloc(name_size); if (!name_info) { *size = 0; - err = UV_ENOMEM; - goto cleanup; + return UV_ENOMEM; } nt_status = pNtQueryInformationFile(handle->handle, @@ -2551,51 +2485,19 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) name_len /= sizeof(WCHAR); - /* check how much space we need */ - addrlen = WideCharToMultiByte(CP_UTF8, - 0, - name_buf, - name_len, - NULL, - 0, - NULL, - NULL); - if (!addrlen) { + /* "\\\\.\\pipe" + name */ + if (*size < pipe_prefix_len) { *size = 0; - err = uv_translate_sys_error(GetLastError()); - goto error; - } else if (pipe_prefix_len + addrlen >= *size) { - /* "\\\\.\\pipe" + name */ - *size = pipe_prefix_len + addrlen + 1; - err = UV_ENOBUFS; - goto error; } - - memcpy(buffer, pipe_prefix, pipe_prefix_len); - addrlen = WideCharToMultiByte(CP_UTF8, - 0, - name_buf, - name_len, - buffer+pipe_prefix_len, - *size-pipe_prefix_len, - NULL, - NULL); - if (!addrlen) { - *size = 0; - err = uv_translate_sys_error(GetLastError()); - goto error; + else { + memcpy(buffer, pipe_prefix, pipe_prefix_len); + *size -= pipe_prefix_len; } - - addrlen += pipe_prefix_len; - *size = addrlen; - buffer[addrlen] = '\0'; - - err = 0; + err = uv__copy_utf16_to_utf8(name_buf, name_len, buffer+pipe_prefix_len, size); + *size += pipe_prefix_len; error: uv__free(name_info); - -cleanup: return err; } diff --git a/src/win/process.c b/src/win/process.c index 8f1b665ab74..43059858f31 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -124,34 +124,7 @@ static void uv__init_global_job_handle(void) { static int uv__utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) { - int ws_len, r; - WCHAR* ws; - - ws_len = MultiByteToWideChar(CP_UTF8, - 0, - s, - -1, - NULL, - 0); - if (ws_len <= 0) { - return GetLastError(); - } - - ws = (WCHAR*) uv__malloc(ws_len * sizeof(WCHAR)); - if (ws == NULL) { - return ERROR_OUTOFMEMORY; - } - - r = MultiByteToWideChar(CP_UTF8, - 0, - s, - -1, - ws, - ws_len); - assert(r == ws_len); - - *ws_ptr = ws; - return 0; + return uv__convert_utf8_to_utf16(s, ws_ptr); } @@ -554,21 +527,15 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { /* Count the required size. */ for (arg = args; *arg; arg++) { - DWORD arg_len; - - arg_len = MultiByteToWideChar(CP_UTF8, - 0, - *arg, - -1, - NULL, - 0); - if (arg_len == 0) { - return GetLastError(); - } + ssize_t arg_len; + + arg_len = uv_wtf8_length_as_utf16(*arg); + if (arg_len < 0) + return arg_len; dst_len += arg_len; - if (arg_len > temp_buffer_len) + if ((size_t) arg_len > temp_buffer_len) temp_buffer_len = arg_len; arg_count++; @@ -579,34 +546,28 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { dst_len = dst_len * 2 + arg_count * 2; /* Allocate buffer for the final command line. */ - dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR)); + dst = uv__malloc(dst_len * sizeof(WCHAR)); if (dst == NULL) { - err = ERROR_OUTOFMEMORY; + err = UV_ENOMEM; goto error; } /* Allocate temporary working buffer. */ - temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR)); + temp_buffer = uv__malloc(temp_buffer_len * sizeof(WCHAR)); if (temp_buffer == NULL) { - err = ERROR_OUTOFMEMORY; + err = UV_ENOMEM; goto error; } pos = dst; for (arg = args; *arg; arg++) { - DWORD arg_len; + ssize_t arg_len; /* Convert argument to wide char. */ - arg_len = MultiByteToWideChar(CP_UTF8, - 0, - *arg, - -1, - temp_buffer, - (int) (dst + dst_len - pos)); - if (arg_len == 0) { - err = GetLastError(); - goto error; - } + arg_len = uv_wtf8_length_as_utf16(*arg); + assert(arg_len > 0); + assert(temp_buffer_len >= (size_t) arg_len); + uv_wtf8_to_utf16(*arg, temp_buffer, arg_len); if (verbatim_arguments) { /* Copy verbatim. */ @@ -618,6 +579,7 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { } *pos++ = *(arg + 1) ? L' ' : L'\0'; + assert(pos <= dst + dst_len); } uv__free(temp_buffer); @@ -703,55 +665,43 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { WCHAR* ptr; char** env; size_t env_len = 0; - int len; + size_t len; size_t i; - DWORD var_size; + size_t var_size; size_t env_block_count = 1; /* 1 for null-terminator */ WCHAR* dst_copy; WCHAR** ptr_copy; WCHAR** env_copy; - DWORD required_vars_value_len[ARRAY_SIZE(required_vars)]; + size_t required_vars_value_len[ARRAY_SIZE(required_vars)]; /* first pass: determine size in UTF-16 */ for (env = env_block; *env; env++) { - int len; + ssize_t len; if (strchr(*env, '=')) { - len = MultiByteToWideChar(CP_UTF8, - 0, - *env, - -1, - NULL, - 0); - if (len <= 0) { - return GetLastError(); - } + len = uv_wtf8_length_as_utf16(*env); + if (len < 0) + return len; env_len += len; env_block_count++; } } /* second pass: copy to UTF-16 environment block */ - dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR)); + dst_copy = uv__malloc(env_len * sizeof(WCHAR)); if (dst_copy == NULL && env_len > 0) { - return ERROR_OUTOFMEMORY; + return UV_ENOMEM; } env_copy = alloca(env_block_count * sizeof(WCHAR*)); ptr = dst_copy; ptr_copy = env_copy; for (env = env_block; *env; env++) { + ssize_t len; if (strchr(*env, '=')) { - len = MultiByteToWideChar(CP_UTF8, - 0, - *env, - -1, - ptr, - (int) (env_len - (ptr - dst_copy))); - if (len <= 0) { - DWORD err = GetLastError(); - uv__free(dst_copy); - return err; - } + len = uv_wtf8_length_as_utf16(*env); + assert(len > 0); + assert((size_t) len <= env_len - (ptr - dst_copy)); + uv_wtf8_to_utf16(*env, ptr, len); *ptr_copy++ = ptr; ptr += len; } @@ -769,7 +719,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { cmp = -1; } else { cmp = env_strncmp(required_vars[i].wide_eq, - required_vars[i].len, + required_vars[i].len, *ptr_copy); } if (cmp < 0) { @@ -792,7 +742,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { dst = uv__malloc((1+env_len) * sizeof(WCHAR)); if (!dst) { uv__free(dst_copy); - return ERROR_OUTOFMEMORY; + return UV_ENOMEM; } for (ptr = dst, ptr_copy = env_copy, i = 0; @@ -990,26 +940,26 @@ int uv_spawn(uv_loop_t* loop, err = uv__utf8_to_utf16_alloc(options->file, &application); if (err) - goto done; + goto done_uv; err = make_program_args( options->args, options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, &arguments); if (err) - goto done; + goto done_uv; if (options->env) { err = make_program_env(options->env, &env); if (err) - goto done; + goto done_uv; } if (options->cwd) { /* Explicit cwd */ err = uv__utf8_to_utf16_alloc(options->cwd, &cwd); if (err) - goto done; + goto done_uv; } else { /* Inherit cwd */ @@ -1194,8 +1144,13 @@ int uv_spawn(uv_loop_t* loop, * made or the handle is closed, whichever happens first. */ uv__handle_start(process); + goto done_uv; + /* Cleanup, whether we succeeded or failed. */ done: + err = uv_translate_sys_error(err); + + done_uv: uv__free(application); uv__free(application_path); uv__free(arguments); @@ -1209,7 +1164,7 @@ int uv_spawn(uv_loop_t* loop, child_stdio_buffer = NULL; } - return uv_translate_sys_error(err); + return err; } diff --git a/src/win/tty.c b/src/win/tty.c index 7e1f15544b1..ac836930d6f 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -482,9 +482,11 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { uv_loop_t* loop; uv_tty_t* handle; uv_req_t* req; - DWORD bytes, read_bytes; + DWORD bytes; + size_t read_bytes; WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3]; - DWORD chars, read_chars; + DWORD chars; + DWORD read_chars; LONG status; COORD pos; BOOL read_console_success; @@ -525,16 +527,13 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { NULL); if (read_console_success) { - read_bytes = WideCharToMultiByte(CP_UTF8, - 0, - utf16, - read_chars, - handle->tty.rd.read_line_buffer.base, - bytes, - NULL, - NULL); + read_bytes = bytes; + uv_utf16_to_wtf8(utf16, + read_chars, + &handle->tty.rd.read_line_buffer.base, + &read_bytes); SET_REQ_SUCCESS(req); - req->u.io.overlapped.InternalHigh = read_bytes; + req->u.io.overlapped.InternalHigh = (DWORD) read_bytes; } else { SET_REQ_ERROR(req, GetLastError()); } @@ -798,7 +797,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, } if (KEV.uChar.UnicodeChar != 0) { - int prefix_len, char_len; + int prefix_len; + size_t char_len; + char* last_key_buf; /* Character key pressed */ if (KEV.uChar.UnicodeChar >= 0xD800 && @@ -819,38 +820,31 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, prefix_len = 0; } - if (KEV.uChar.UnicodeChar >= 0xDC00 && - KEV.uChar.UnicodeChar < 0xE000) { + char_len = sizeof handle->tty.rd.last_key; + last_key_buf = &handle->tty.rd.last_key[prefix_len]; + if (handle->tty.rd.last_utf16_high_surrogate) { /* UTF-16 surrogate pair */ WCHAR utf16_buffer[2]; utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate; utf16_buffer[1] = KEV.uChar.UnicodeChar; - char_len = WideCharToMultiByte(CP_UTF8, - 0, - utf16_buffer, - 2, - &handle->tty.rd.last_key[prefix_len], - sizeof handle->tty.rd.last_key, - NULL, - NULL); + if (uv_utf16_to_wtf8(utf16_buffer, + 2, + &last_key_buf, + &char_len)) + char_len = 0; + handle->tty.rd.last_utf16_high_surrogate = 0; } else { /* Single UTF-16 character */ - char_len = WideCharToMultiByte(CP_UTF8, - 0, - &KEV.uChar.UnicodeChar, - 1, - &handle->tty.rd.last_key[prefix_len], - sizeof handle->tty.rd.last_key, - NULL, - NULL); + if (uv_utf16_to_wtf8(&KEV.uChar.UnicodeChar, + 1, + &last_key_buf, + &char_len)) + char_len = 0; } - /* Whatever happened, the last character wasn't a high surrogate. */ - handle->tty.rd.last_utf16_high_surrogate = 0; - /* If the utf16 character(s) couldn't be converted something must be * wrong. */ - if (!char_len) { + if (char_len == 0) { handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(loop, handle); handle->read_cb((uv_stream_t*) handle, diff --git a/src/win/util.c b/src/win/util.c index f6ec79cd57b..58b8e106c99 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -95,7 +95,7 @@ void uv__util_init(void) { int uv_exepath(char* buffer, size_t* size_ptr) { - int utf8_len, utf16_buffer_len, utf16_len; + size_t utf8_len, utf16_buffer_len, utf16_len; WCHAR* utf16_buffer; int err; @@ -123,25 +123,17 @@ int uv_exepath(char* buffer, size_t* size_ptr) { } /* Convert to UTF-8 */ - utf8_len = WideCharToMultiByte(CP_UTF8, - 0, - utf16_buffer, - -1, - buffer, - (int) *size_ptr, - NULL, - NULL); - if (utf8_len == 0) { - err = GetLastError(); - goto error; + utf8_len = *size_ptr - 1; /* Reserve space for NUL */ + err = uv_utf16_to_wtf8(utf16_buffer, utf16_len, &buffer, &utf8_len); + if (err == UV_ENOBUFS) { + utf8_len = *size_ptr - 1; + err = 0; } + *size_ptr = utf8_len; uv__free(utf16_buffer); - /* utf8_len *does* include the terminating null at this point, but the - * returned size shouldn't. */ - *size_ptr = utf8_len - 1; - return 0; + return err; error: uv__free(utf16_buffer); @@ -204,45 +196,14 @@ int uv_cwd(char* buffer, size_t* size) { } r = uv__cwd(&utf16_buffer, &utf16_len); - if (r < 0) { + if (r < 0) return r; - } - /* Check how much space we need */ - r = WideCharToMultiByte(CP_UTF8, - 0, - utf16_buffer, - -1, - NULL, - 0, - NULL, - NULL); - if (r == 0) { - uv__free(utf16_buffer); - return uv_translate_sys_error(GetLastError()); - } else if (r > (int) *size) { - uv__free(utf16_buffer); - *size = r; - return UV_ENOBUFS; - } + r = uv__copy_utf16_to_utf8(utf16_buffer, utf16_len, buffer, size); - /* Convert to UTF-8 */ - r = WideCharToMultiByte(CP_UTF8, - 0, - utf16_buffer, - -1, - buffer, - *size > INT_MAX ? INT_MAX : (int) *size, - NULL, - NULL); uv__free(utf16_buffer); - if (r == 0) { - return uv_translate_sys_error(GetLastError()); - } - - *size = r - 1; - return 0; + return r; } @@ -252,33 +213,10 @@ int uv_chdir(const char* dir) { WCHAR drive_letter, env_var[4]; int r; - if (dir == NULL) { - return UV_EINVAL; - } - - utf16_len = MultiByteToWideChar(CP_UTF8, - 0, - dir, - -1, - NULL, - 0); - if (utf16_len == 0) { - return uv_translate_sys_error(GetLastError()); - } - utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR)); - if (utf16_buffer == NULL) { - return UV_ENOMEM; - } - - if (MultiByteToWideChar(CP_UTF8, - 0, - dir, - -1, - utf16_buffer, - utf16_len) == 0) { - uv__free(utf16_buffer); - return uv_translate_sys_error(GetLastError()); - } + /* Convert to UTF-16 */ + r = uv__convert_utf8_to_utf16(dir, &utf16_buffer); + if (r) + return r; if (!SetCurrentDirectoryW(utf16_buffer)) { uv__free(utf16_buffer); @@ -416,29 +354,14 @@ int uv_set_process_title(const char* title) { uv__once_init(); - /* Find out how big the buffer for the wide-char title must be */ - length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0); - if (!length) { - err = GetLastError(); - goto done; - } - - /* Convert to wide-char string */ - title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length); - if (!title_w) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length); - if (!length) { - err = GetLastError(); - goto done; - } + err = uv__convert_utf8_to_utf16(title, &title_w); + if (err) + return err; /* If the title must be truncated insert a \0 terminator there */ - if (length > MAX_TITLE_LENGTH) { + length = wcslen(title_w); + if (length >= MAX_TITLE_LENGTH) title_w[MAX_TITLE_LENGTH - 1] = L'\0'; - } if (!SetConsoleTitleW(title_w)) { err = GetLastError(); @@ -460,20 +383,19 @@ int uv_set_process_title(const char* title) { static int uv__get_process_title(void) { WCHAR title_w[MAX_TITLE_LENGTH]; + DWORD wlen; - if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { - return -1; - } - - if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0) - return -1; + wlen = GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR)); + if (wlen == 0) + return uv_translate_sys_error(GetLastError()); - return 0; + return uv__convert_utf16_to_utf8(title_w, wlen, &process_title); } int uv_get_process_title(char* buffer, size_t size) { size_t len; + int r; if (buffer == NULL || size == 0) return UV_EINVAL; @@ -485,9 +407,12 @@ int uv_get_process_title(char* buffer, size_t size) { * If the process_title was never read before nor explicitly set, * we must query it with getConsoleTitleW */ - if (!process_title && uv__get_process_title() == -1) { - LeaveCriticalSection(&process_title_lock); - return uv_translate_sys_error(GetLastError()); + if (process_title == NULL) { + r = uv__get_process_title(); + if (r) { + LeaveCriticalSection(&process_title_lock); + return r; + } } assert(process_title); @@ -833,19 +758,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, continue; /* Compute the size of the interface name. */ - name_size = WideCharToMultiByte(CP_UTF8, - 0, - adapter->FriendlyName, - -1, - NULL, - 0, - NULL, - FALSE); - if (name_size <= 0) { - uv__free(win_address_buf); - return uv_translate_sys_error(GetLastError()); - } - uv_address_buf_size += name_size; + name_size = uv_utf16_length_as_wtf8(adapter->FriendlyName, -1); + uv_address_buf_size += name_size + 1; /* Count the number of addresses associated with this interface, and * compute the size. */ @@ -875,30 +789,25 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, adapter != NULL; adapter = adapter->Next) { IP_ADAPTER_UNICAST_ADDRESS* unicast_address; - int name_size; - size_t max_name_size; + size_t name_size; + int r; if (adapter->OperStatus != IfOperStatusUp || adapter->FirstUnicastAddress == NULL) continue; /* Convert the interface name to UTF8. */ - max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf; - if (max_name_size > (size_t) INT_MAX) - max_name_size = INT_MAX; - name_size = WideCharToMultiByte(CP_UTF8, - 0, - adapter->FriendlyName, - -1, - name_buf, - (int) max_name_size, - NULL, - FALSE); - if (name_size <= 0) { + name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf; + r = uv__copy_utf16_to_utf8(adapter->FriendlyName, + -1, + name_buf, + &name_size); + if (r) { uv__free(win_address_buf); uv__free(uv_address_buf); - return uv_translate_sys_error(GetLastError()); + return r; } + name_size += 1; /* Add NUL byte. */ /* Add an uv_interface_address_t element for every unicast address. */ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*) @@ -1061,7 +970,6 @@ int uv_os_homedir(char* buffer, size_t* size) { int uv_os_tmpdir(char* buffer, size_t* size) { wchar_t *path; - DWORD bufsize; size_t len; if (buffer == NULL || size == NULL || *size == 0) @@ -1078,7 +986,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) { if (path == NULL) { return UV_ENOMEM; } - len = GetTempPathW(len, path); + len = GetTempPathW(len, path); if (len == 0) { uv__free(path); @@ -1093,34 +1001,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) { path[len] = L'\0'; } - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); - - if (bufsize == 0) { - uv__free(path); - return uv_translate_sys_error(GetLastError()); - } else if (bufsize > *size) { - uv__free(path); - *size = bufsize; - return UV_ENOBUFS; - } - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - path, - -1, - buffer, - *size, - NULL, - NULL); - uv__free(path); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - *size = bufsize - 1; - return 0; + return uv__copy_utf16_to_utf8(path, len, buffer, size); } @@ -1131,95 +1012,71 @@ int uv_os_tmpdir(char* buffer, size_t* size) { * If utf16 is null terminated, utf16len can be set to -1, otherwise it must * be specified. */ -int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) { - DWORD bufsize; +int uv__convert_utf16_to_utf8(const WCHAR* utf16, size_t utf16len, char** utf8) { + size_t utf8_len = 0; if (utf16 == NULL) return UV_EINVAL; - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - utf16, - utf16len, - NULL, - 0, - NULL, - NULL); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - /* Allocate the destination buffer adding an extra byte for the terminating - * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so - * we do it ourselves always, just in case. */ - *utf8 = uv__malloc(bufsize + 1); - - if (*utf8 == NULL) - return UV_ENOMEM; - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - utf16, - utf16len, - *utf8, - bufsize, - NULL, - NULL); - - if (bufsize == 0) { - uv__free(*utf8); - *utf8 = NULL; - return uv_translate_sys_error(GetLastError()); - } - - (*utf8)[bufsize] = '\0'; - return 0; + *utf8 = NULL; + return uv_utf16_to_wtf8(utf16, utf16len, utf8, &utf8_len); } /* * Converts a UTF-8 string into a UTF-16 one. The resulting string is * null-terminated. - * - * If utf8 is null terminated, utf8len can be set to -1, otherwise it must - * be specified. */ -int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) { +int uv__convert_utf8_to_utf16(const char* utf8, WCHAR** utf16) { int bufsize; if (utf8 == NULL) return UV_EINVAL; - /* Check how much space we need */ - bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); + /* Check how much space we need (including NUL). */ + bufsize = uv_wtf8_length_as_utf16(utf8); + if (bufsize < 0) + return UV__EINVAL; - /* Allocate the destination buffer adding an extra byte for the terminating - * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so - * we do it ourselves always, just in case. */ - *utf16 = uv__malloc(sizeof(WCHAR) * (bufsize + 1)); + /* Allocate the destination buffer. */ + *utf16 = uv__malloc(sizeof(WCHAR) * bufsize); if (*utf16 == NULL) return UV_ENOMEM; /* Convert to UTF-16 */ - bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize); + uv_wtf8_to_utf16(utf8, *utf16, bufsize); - if (bufsize == 0) { - uv__free(*utf16); - *utf16 = NULL; - return uv_translate_sys_error(GetLastError()); - } - - (*utf16)[bufsize] = L'\0'; return 0; } +/* + * Converts a UTF-16 string into a UTF-8 one in an existing buffer. The + * resulting string is null-terminated. + * + * If utf16 is null terminated, utf16len can be set to -1, otherwise it must + * be specified. + */ +int uv__copy_utf16_to_utf8(const WCHAR* utf16buffer, size_t utf16len, char* utf8, size_t *size) { + int r; + + if (utf8 == NULL || size == NULL) + return UV_EINVAL; + + if (*size == 0) { + *size = uv_utf16_length_as_wtf8(utf16buffer, utf16len); + r = UV_ENOBUFS; + } else { + *size -= 1; /* Reserve space for NUL. */ + r = uv_utf16_to_wtf8(utf16buffer, utf16len, &utf8, size); + } + if (r == UV_ENOBUFS) + *size += 1; /* Add space for NUL. */ + return r; +} + + static int uv__getpwuid_r(uv_passwd_t* pwd) { HANDLE token; wchar_t username[UNLEN + 1]; @@ -1384,14 +1241,13 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { wchar_t* var; DWORD varlen; wchar_t* name_w; - DWORD bufsize; size_t len; int r; if (name == NULL || buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; - r = uv__convert_utf8_to_utf16(name, -1, &name_w); + r = uv__convert_utf8_to_utf16(name, &name_w); if (r != 0) return r; @@ -1432,35 +1288,7 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { } } - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL); - - if (bufsize == 0) { - r = uv_translate_sys_error(GetLastError()); - goto fail; - } else if (bufsize > *size) { - *size = bufsize; - r = UV_ENOBUFS; - goto fail; - } - - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - var, - -1, - buffer, - *size, - NULL, - NULL); - - if (bufsize == 0) { - r = uv_translate_sys_error(GetLastError()); - goto fail; - } - - *size = bufsize - 1; - r = 0; + r = uv__copy_utf16_to_utf8(var, len, buffer, size); fail: @@ -1482,12 +1310,12 @@ int uv_os_setenv(const char* name, const char* value) { if (name == NULL || value == NULL) return UV_EINVAL; - r = uv__convert_utf8_to_utf16(name, -1, &name_w); + r = uv__convert_utf8_to_utf16(name, &name_w); if (r != 0) return r; - r = uv__convert_utf8_to_utf16(value, -1, &value_w); + r = uv__convert_utf8_to_utf16(value, &value_w); if (r != 0) { uv__free(name_w); @@ -1512,7 +1340,7 @@ int uv_os_unsetenv(const char* name) { if (name == NULL) return UV_EINVAL; - r = uv__convert_utf8_to_utf16(name, -1, &name_w); + r = uv__convert_utf8_to_utf16(name, &name_w); if (r != 0) return r; @@ -1529,9 +1357,6 @@ int uv_os_unsetenv(const char* name) { int uv_os_gethostname(char* buffer, size_t* size) { WCHAR buf[UV_MAXHOSTNAMESIZE]; - size_t len; - char* utf8_str; - int convert_result; if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; @@ -1544,22 +1369,7 @@ int uv_os_gethostname(char* buffer, size_t* size) { if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0) return uv_translate_sys_error(WSAGetLastError()); - convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str); - - if (convert_result != 0) - return convert_result; - - len = strlen(utf8_str); - if (len >= *size) { - *size = len + 1; - uv__free(utf8_str); - return UV_ENOBUFS; - } - - memcpy(buffer, utf8_str, len + 1); - uv__free(utf8_str); - *size = len; - return 0; + return uv__copy_utf16_to_utf8(buf, -1, buffer, size); } @@ -1665,7 +1475,7 @@ int uv_os_uname(uv_utsname_t* buffer) { HKEY registry_key; WCHAR product_name_w[256]; DWORD product_name_w_size; - int version_size; + size_t version_size; int processor_level; int r; @@ -1727,37 +1537,29 @@ int uv_os_uname(uv_utsname_t* buffer) { } } - version_size = WideCharToMultiByte(CP_UTF8, - 0, - product_name_w, - -1, - buffer->version, - sizeof(buffer->version), - NULL, - NULL); - if (version_size == 0) { - r = uv_translate_sys_error(GetLastError()); + version_size = sizeof(buffer->version); + r = uv__copy_utf16_to_utf8(product_name_w, + -1, + buffer->version, + &version_size); + if (r) goto error; - } } } /* Append service pack information to the version if present. */ if (os_info.szCSDVersion[0] != L'\0') { if (version_size > 0) - buffer->version[version_size - 1] = ' '; - - if (WideCharToMultiByte(CP_UTF8, - 0, - os_info.szCSDVersion, - -1, - buffer->version + version_size, - sizeof(buffer->version) - version_size, - NULL, - NULL) == 0) { - r = uv_translate_sys_error(GetLastError()); + buffer->version[version_size++] = ' '; + + version_size = sizeof(buffer->version) - version_size; + r = uv__copy_utf16_to_utf8(os_info.szCSDVersion, + -1, + buffer->version + + sizeof(buffer->version) - version_size, + &version_size); + if (r) goto error; - } } /* Populate the sysname field. */ diff --git a/test/test-idna.c b/test/test-idna.c index 371b2d58775..bcacfc8a3ad 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -20,6 +20,7 @@ */ #include "task.h" +#define uv__malloc malloc #include "../src/idna.c" #include From 77991a0761d62f9d3f79d778ee962c01b97bdfc8 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 28 Oct 2023 21:05:42 -0400 Subject: [PATCH 454/713] build: fix libuv.a file name for cmake (#4185) This makes cmake more consistent about how to name this file, otherwise sometimes it names it uv.lib and sometimes libuv.a depending on which compiler is selected or if ./configure is used. Refs: https://github.com/libuv/libuv/pull/2085#issuecomment-1735276640 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec2cb9b8df2..72377851b69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -478,7 +478,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OS390") endif() target_link_libraries(uv_a ${uv_libraries}) set_target_properties(uv_a PROPERTIES OUTPUT_NAME "uv") -if(MSVC) +if(WIN32) set_target_properties(uv_a PROPERTIES PREFIX "lib") endif() From 93efccf4ee1ed3c740d10660b4bfb08edc68a1b5 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Mon, 30 Oct 2023 20:16:57 +0100 Subject: [PATCH 455/713] build: add windows ubsan and clang ci (#4138) Fixes a detected error: incompatible pointer to integer conversion passing 'uv_os_fd_t' (aka 'void *') to parameter of type 'SOCKET' (aka 'unsigned long long'). Use upstream llvm to work-around broken VS2022 clang unable to link. --- .github/workflows/CI-win.yml | 4 +++- .github/workflows/sanitizer.yml | 26 ++++++++++++++++++++++++++ test/test-tcp-close-reset.c | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index a96e250aa69..149f9ca0487 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -26,6 +26,7 @@ jobs: - {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN} + - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: UBSAN} - {toolchain: Visual Studio 17 2022, arch: arm64, server: 2022} steps: - uses: actions/checkout@v2 @@ -36,7 +37,8 @@ jobs: run: cmake -S . -B build -DBUILD_TESTING=ON -G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }} - ${{ matrix.config.config == 'ASAN' && '-DASAN=on -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded' || '' }} + ${{ matrix.config.config == 'ASAN' && '-DASAN=on -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded' || + matrix.config.config == 'UBSAN' && '-DUBSAN=on' || '' }} cmake --build build --config RelWithDebInfo diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 78052d0c553..4fca161d9ee 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -95,3 +95,29 @@ jobs: - name: UBSAN Test run: | ./build-ubsan/uv_run_tests_a + + sanitizers-windows: + runs-on: windows-2022 + steps: + - uses: actions/checkout@v2 + - name: Setup + run: | + choco install ninja + + # Note: clang shipped with VS2022 has an issue where the UBSAN runtime doesn't link. + - name: Install LLVM and Clang + uses: KyleMayes/install-llvm-action@v1 + with: + version: "17" + + - name: Envinfo + run: npx envinfo + + - name: UBSAN Build + run: | + mkdir build-ubsan + cmake -B build-ubsan -G Ninja -DBUILD_TESTING=ON -DUBSAN=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang + cmake --build build-ubsan + - name: UBSAN Test + run: | + ./build-ubsan/uv_run_tests_a diff --git a/test/test-tcp-close-reset.c b/test/test-tcp-close-reset.c index c9ac4d48055..74941789420 100644 --- a/test/test-tcp-close-reset.c +++ b/test/test-tcp-close-reset.c @@ -81,7 +81,7 @@ static void do_close(uv_tcp_t* handle) { ASSERT_OK(r); #ifdef _WIN32 ASSERT_PTR_NE(fd, INVALID_FD); - ASSERT_OK(shutdown(fd, SD_BOTH)); + ASSERT_OK(shutdown((SOCKET)fd, SD_BOTH)); #else ASSERT_NE(fd, INVALID_FD); ASSERT_OK(shutdown(fd, SHUT_RDWR)); From 66160d6973b41040f6b2066a84359147258f60c3 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Tue, 31 Oct 2023 21:30:10 -0400 Subject: [PATCH 456/713] win: improve accuracy of ProductName between arch (#4191) uv_os_uname() on Windows queries the registry value "HKEY_LOCAL_MACHINE\ SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName" to fill uv_utsname_t. If calling application was compiled for x86 and run on a x86_64 host, that query is redirected to "Computer\HKEY_LOCAL_MACHINE\ SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\ProductName" instead. For whatever reason, the value of 'ProductName' in the 32-bit registry section on 64-bit Windows sometimes differs from the 64-bit equivalent value and is inaccurate (e.g. containing the data "Windows 10 Enterprise" while the 64-bit value accurately contains "Windows 10 Pro"). Adds the 'KEY_WOW64_64KEY' security descriptor when opening the appropriate registry key so that the value of ProductName is always taken from the primary registry on 64-bit systems, regardless of compiled architecture. The descriptor is safely ignored on 32-bit hosts. --- src/win/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/util.c b/src/win/util.c index 58b8e106c99..91d88a54fb2 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1506,7 +1506,7 @@ int uv_os_uname(uv_utsname_t* buffer) { r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, - KEY_QUERY_VALUE, + KEY_QUERY_VALUE | KEY_WOW64_64KEY, ®istry_key); if (r == ERROR_SUCCESS) { From be6b81a352d17513c95be153afcb3148f1a451cd Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 6 Nov 2023 13:17:17 -0500 Subject: [PATCH 457/713] 2023.11.06, Version 1.47.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.46.0: * test: fix license blurb (Ben Noordhuis) * linux: fix harmless warn_unused_result warning (Shuduo Sang) * darwin: fix build warnings (小明) * linux: don't use io_uring on pre-5.10.186 kernels (Ben Noordhuis) * fs: fix WTF-8 decoding issue (Jameson Nash) * test: enable disabled tcp_connect6_error_fault (Ben Noordhuis) * test: enable disabled fs_link (Ben Noordhuis) * test: enable disabled spawn_same_stdout_stderr (Ben Noordhuis) * linux: handle UNAME26 personality (Ben Noordhuis) * build: move cmake_minimum_required version to 3.9 (Keith Winstein) * unix: set ipv6 scope id for link-local addresses (Ben Noordhuis) * unix: match kqueue and epoll code (Trevor Norris) * win,spawn: allow `%PATH%` to be unset (Kyle Edwards) * doc: switch to Furo, a more modern Sphinx theme (Saúl Ibarra Corretgé) * darwin: make TCP_KEEPINTVL and TCP_KEEPCNT available (小明) * win,fs: avoid winapi macro redefinition (Brad King) * linux: add missing riscv syscall numbers (michalbiesek) * doc: fix broken "Shared library" Wikipedia link (Alois Klink) * unix: get mainline kernel version in Ubuntu (Santiago Gimeno) * unix: get mainline kernel version in Debian (Ben Noordhuis) * build: fix qemu install in CI-unix workflow (Santiago Gimeno) * unix: disable io_uring close on selected kernels (Santiago Gimeno) * test: skip tests when ipv6 is not available (Santiago Gimeno) * ibmi: implement ifaddrs, getifaddrs, freeifaddrs (Abdirahim Musse) * unix: reset signal counters after fork (SmorkalovG) * win,process: avoid assert after spawning Store app (Jameson Nash) * unix: remove pread/preadv conditionals (Ben Noordhuis) * unix: remove pwrite/pwritev conditionals (Ben Noordhuis) * darwin: remove workaround for data corruption bug (Ben Noordhuis) * src: default to stream=stderr in handle printer (Ben Noordhuis) * test: switch to new-style ASSERT_EQ macros (Pleuvens) * zos: correctly get cpu model in uv_cpu_info() (jolai) * test: fix get_passwd2 on IBM i (Abdirahim Musse) * unix: don't malloc on sync uv_fs_read (Ben Noordhuis) * freebsd: get fs event path with fcntl(F_KINFO) (David Carlier) * test: switch from ASSERT_* to ASSERT_PTR_* (Pleuvens) * darwin: workaround apple pthread_cond_wait bug (Julien Roncaglia) * doc: uv_close should be called after exit callback (Pleuvens) * test: 192.0.2.0/24 is the actual -TEST-NET-1 (prubel) * unix: add back preadv/pwritev fallback (Ben Noordhuis) * unix: rename variable for consistency (Ben Noordhuis) * unix: merge read/write code into single functions (Ben Noordhuis) * doc: filename arg to uv_fs_event_cb can be NULL (Ben Noordhuis) * build,win: we need to link against shell32.lib (Per Allansson) * unix: no preadv/pwritev workaround if not needed (Jeffrey H. Johnson) * build: add CI for Windows ARM64 (build only) (Per Allansson) * linux: disable io_uring on 32 bits arm systems (Ben Noordhuis) * build: run sanitizers on macos ci (Ben Noordhuis) * misc: export WTF8 conversion utilities (Jameson Nash) * build: fix libuv.a file name for cmake (Jameson Nash) * build: add windows ubsan and clang ci (Matheus Izvekov) * win: improve accuracy of ProductName between arch (Christian Heimlich) --- AUTHORS | 12 +++++ ChangeLog | 109 +++++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 8 ++-- 4 files changed, 126 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 9b89421c428..6bf1a9fa2f9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -548,3 +548,15 @@ liuxiang88 <94350585+liuxiang88@users.noreply.github.com> Jeffrey H. Johnson Abdirahim Musse <33973272+abmusse@users.noreply.github.com> 小明 <7737673+caobug@users.noreply.github.com> +Shuduo Sang +Keith Winstein +michalbiesek +Alois Klink +SmorkalovG +Pleuvens +jolai <58589285+laijonathan@users.noreply.github.com> +Julien Roncaglia +prubel +Per Allansson <65364157+per-allansson@users.noreply.github.com> +Matheus Izvekov +Christian Heimlich diff --git a/ChangeLog b/ChangeLog index ea597f66346..f40fcc600bb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,112 @@ +2023.11.06, Version 1.47.0 (Stable) + +Changes since version 1.46.0: + +* test: fix license blurb (Ben Noordhuis) + +* linux: fix harmless warn_unused_result warning (Shuduo Sang) + +* darwin: fix build warnings (小明) + +* linux: don't use io_uring on pre-5.10.186 kernels (Ben Noordhuis) + +* fs: fix WTF-8 decoding issue (Jameson Nash) + +* test: enable disabled tcp_connect6_error_fault (Ben Noordhuis) + +* test: enable disabled fs_link (Ben Noordhuis) + +* test: enable disabled spawn_same_stdout_stderr (Ben Noordhuis) + +* linux: handle UNAME26 personality (Ben Noordhuis) + +* build: move cmake_minimum_required version to 3.9 (Keith Winstein) + +* unix: set ipv6 scope id for link-local addresses (Ben Noordhuis) + +* unix: match kqueue and epoll code (Trevor Norris) + +* win,spawn: allow `%PATH%` to be unset (Kyle Edwards) + +* doc: switch to Furo, a more modern Sphinx theme (Saúl Ibarra Corretgé) + +* darwin: make TCP_KEEPINTVL and TCP_KEEPCNT available (小明) + +* win,fs: avoid winapi macro redefinition (Brad King) + +* linux: add missing riscv syscall numbers (michalbiesek) + +* doc: fix broken "Shared library" Wikipedia link (Alois Klink) + +* unix: get mainline kernel version in Ubuntu (Santiago Gimeno) + +* unix: get mainline kernel version in Debian (Ben Noordhuis) + +* build: fix qemu install in CI-unix workflow (Santiago Gimeno) + +* unix: disable io_uring close on selected kernels (Santiago Gimeno) + +* test: skip tests when ipv6 is not available (Santiago Gimeno) + +* ibmi: implement ifaddrs, getifaddrs, freeifaddrs (Abdirahim Musse) + +* unix: reset signal counters after fork (SmorkalovG) + +* win,process: avoid assert after spawning Store app (Jameson Nash) + +* unix: remove pread/preadv conditionals (Ben Noordhuis) + +* unix: remove pwrite/pwritev conditionals (Ben Noordhuis) + +* darwin: remove workaround for data corruption bug (Ben Noordhuis) + +* src: default to stream=stderr in handle printer (Ben Noordhuis) + +* test: switch to new-style ASSERT_EQ macros (Pleuvens) + +* zos: correctly get cpu model in uv_cpu_info() (jolai) + +* test: fix get_passwd2 on IBM i (Abdirahim Musse) + +* unix: don't malloc on sync uv_fs_read (Ben Noordhuis) + +* freebsd: get fs event path with fcntl(F_KINFO) (David Carlier) + +* test: switch from ASSERT_* to ASSERT_PTR_* (Pleuvens) + +* darwin: workaround apple pthread_cond_wait bug (Julien Roncaglia) + +* doc: uv_close should be called after exit callback (Pleuvens) + +* test: 192.0.2.0/24 is the actual -TEST-NET-1 (prubel) + +* unix: add back preadv/pwritev fallback (Ben Noordhuis) + +* unix: rename variable for consistency (Ben Noordhuis) + +* unix: merge read/write code into single functions (Ben Noordhuis) + +* doc: filename arg to uv_fs_event_cb can be NULL (Ben Noordhuis) + +* build,win: we need to link against shell32.lib (Per Allansson) + +* unix: no preadv/pwritev workaround if not needed (Jeffrey H. Johnson) + +* build: add CI for Windows ARM64 (build only) (Per Allansson) + +* linux: disable io_uring on 32 bits arm systems (Ben Noordhuis) + +* build: run sanitizers on macos ci (Ben Noordhuis) + +* misc: export WTF8 conversion utilities (Jameson Nash) + +* build: fix libuv.a file name for cmake (Jameson Nash) + +* build: add windows ubsan and clang ci (Matheus Izvekov) + +* win: improve accuracy of ProductName between arch (Christian Heimlich) + + 2023.06.30, Version 1.46.0 (Stable), f0bb7e40f0508bedf6fad33769b3f87bb8aedfa6 Changes since version 1.45.0: diff --git a/configure.ac b/configure.ac index 24afba7bd61..0a1042ce3d3 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.46.1-dev], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.47.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index e586d037f1c..b17220fcf90 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 46 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 47 +#define UV_VERSION_PATCH 0 +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 97b7873cba1ffd7e467cc7159a9bf6cf519994ac Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 6 Nov 2023 13:17:32 -0500 Subject: [PATCH 458/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index f40fcc600bb..0a3905b29ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2023.11.06, Version 1.47.0 (Stable) +2023.11.06, Version 1.47.0 (Stable), be6b81a352d17513c95be153afcb3148f1a451cd Changes since version 1.46.0: From 815693f71523175f577e3cbdb9cf576d30ea9250 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 6 Nov 2023 13:24:46 -0500 Subject: [PATCH 459/713] Now working on version 1.47.1 Fixes: https://github.com/libuv/libuv/issues/4186 --- configure.ac | 2 +- include/uv/version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 0a1042ce3d3..1bdcab3f697 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.47.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.47.1-dev], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index b17220fcf90..8a5e3c09dbb 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 47 -#define UV_VERSION_PATCH 0 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 1 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 4107b8d4db8011beed2cc36e7f92cd5738a1c254 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 7 Nov 2023 10:53:16 -0500 Subject: [PATCH 460/713] misc: remove deprecated stalebot file (#4199) Refs: https://github.com/probot/stale/pull/430 --- .github/stale.yml | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index 6f2fb663c62..00000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,23 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 28 -# Number of days of inactivity before a stale issue is closed -# Set to false to disable. If disabled, issues still need to be closed -# manually, but will remain marked as stale. -daysUntilClose: false -# Issues with these labels will never be considered stale -exemptLabels: - - v2 - - enhancement - - good first issue - - feature-request - - doc - - bug - - not-stale -# Label to use when marking an issue as stale -staleLabel: stale -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. Thank you for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false From f067f50ae47293bf24c8b6232f16e927f1eaf15a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 10 Nov 2023 18:56:46 +0100 Subject: [PATCH 461/713] build: disable windows asan buildbot (#4215) uv_run_tests.exe fails to start up with exit code 0xC0000135 a.k.a. STATUS_DLL_NOT_FOUND, suggesting it cannot find the ASAN runtime libraries. Disable the buildbot until we figure out how to fix that. Refs: https://github.com/libuv/libuv/issues/4210 --- .github/workflows/CI-win.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index 149f9ca0487..e66b107d4cb 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -25,7 +25,8 @@ jobs: - {toolchain: Visual Studio 16 2019, arch: x64, server: 2019} - {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022} - - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN} + # Currently broken, see https://github.com/libuv/libuv/issues/4210 + #- {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: UBSAN} - {toolchain: Visual Studio 17 2022, arch: arm64, server: 2022} steps: From f01219dfb716ceac9cc7dbc70022a197b20d27b3 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 10 Nov 2023 20:17:31 +0100 Subject: [PATCH 462/713] test: don't run tcp_writealot under msan (#4214) The test is prone to time out at the best of times, never mind when running under MemorySanitizer. --- test/test-tcp-writealot.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/test-tcp-writealot.c b/test/test-tcp-writealot.c index ebafb179632..fbfa498403c 100644 --- a/test/test-tcp-writealot.c +++ b/test/test-tcp-writealot.c @@ -149,8 +149,9 @@ TEST_IMPL(tcp_writealot) { uv_tcp_t client; int r; -#ifdef __TSAN__ - RETURN_SKIP("Test is too slow to run under ThreadSanitizer"); +#if defined(__MSAN__) || defined(__TSAN__) + RETURN_SKIP("Test is too slow to run under " + "MemorySanitizer or ThreadSanitizer"); #endif ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); From 874363f652f0aafb3ed58a4da65940258e5ee713 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 13 Nov 2023 19:25:41 +0100 Subject: [PATCH 463/713] build,win: remove extraneous -lshell32 (#4213) I suggested in https://github.com/libuv/libuv/pull/4182 to add the flag to configure.ac as well but seems we already link to it. I've removed the first one, not the second one, in case libuv is linked with --as-needed. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 1bdcab3f697..e556bcc8db4 100644 --- a/configure.ac +++ b/configure.ac @@ -74,7 +74,7 @@ AM_CONDITIONAL([OS400], [AS_CASE([$host_os],[os400], [true], [false]) AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])]) AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])]) AS_CASE([$host_os],[mingw*], [ - LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32 -ldbghelp -lole32 -luuid -lshell32" + LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -luserenv -luser32 -ldbghelp -lole32 -luuid -lshell32" ]) AS_CASE([$host_os], [solaris2.10], [ CFLAGS="$CFLAGS -DSUNOS_NO_IFADDRS" From 31e4b90c3c45370e21293a984dd59bda70af0494 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Tue, 14 Nov 2023 04:23:28 -0500 Subject: [PATCH 464/713] unix: ignore ifaddrs with NULL ifa_addr (#4218) Passing this to uv__is_ipv6_link_local() is causing a segmentation fault. Note that the documentation for getifaddrs() explicitly states that this value may be NULL. Signed-off-by: Stephen Gallagher --- src/unix/tcp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index a6b53e59132..29f4532e747 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -233,8 +233,9 @@ static int uv__ipv6_link_local_scope_id(void) { return 0; for (p = ifa; p != NULL; p = p->ifa_next) - if (uv__is_ipv6_link_local(p->ifa_addr)) - break; + if (p->ifa_addr != NULL) + if (uv__is_ipv6_link_local(p->ifa_addr)) + break; rv = 0; if (p != NULL) { From e135dfe18342c5bdb573964ecf2c5b81613a4b34 Mon Sep 17 00:00:00 2001 From: Hao Hu <33607772+hhu8@users.noreply.github.com> Date: Tue, 14 Nov 2023 18:30:46 +0800 Subject: [PATCH 465/713] unix,win: utility for setting priority for thread (#4075) Add uv_thread_setpriority for setting priority for threads created by uv_thread_create. Add uv_thread_getpriority for getting thread priority. For Linux by default, if the scheduling policy is SCHED_OTHER and the priority is 0, we need to set the nice value. Fixes: https://github.com/libuv/libuv/issues/4051 --- .gitignore | 1 + CMakeLists.txt | 1 + Makefile.am | 1 + docs/src/threading.rst | 15 +++++ include/uv.h | 11 ++++ src/unix/core.c | 125 ++++++++++++++++++++++++++++++++++++ src/win/util.c | 42 ++++++++++++ test/test-list.h | 2 + test/test-thread-priority.c | 105 ++++++++++++++++++++++++++++++ 9 files changed, 303 insertions(+) create mode 100644 test/test-thread-priority.c diff --git a/.gitignore b/.gitignore index 7eb49322af0..e6a04ec6253 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.sdf *.suo .vs/ +.vscode/ *.VC.db *.VC.opendb core diff --git a/CMakeLists.txt b/CMakeLists.txt index 72377851b69..f7f42773bf6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -655,6 +655,7 @@ if(LIBUV_BUILD_TESTS) test/test-thread-affinity.c test/test-thread-equal.c test/test-thread.c + test/test-thread-priority.c test/test-threadpool-cancel.c test/test-threadpool.c test/test-timer-again.c diff --git a/Makefile.am b/Makefile.am index 1dca3dd1f8a..ff6f1b8a6d2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -286,6 +286,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-priority.c \ test/test-threadpool-cancel.c \ test/test-threadpool.c \ test/test-timer-again.c \ diff --git a/docs/src/threading.rst b/docs/src/threading.rst index d379677a211..883218fa829 100644 --- a/docs/src/threading.rst +++ b/docs/src/threading.rst @@ -132,6 +132,21 @@ 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_setpriority(uv_thread_t tid, int priority) + If the function succeeds, the return value is 0. + If the function fails, the return value is less than zero. + Sets the scheduling priority of the thread specified by tid. It requires elevated + privilege to set specific priorities on some platforms. + The priority can be set to the following constants. UV_THREAD_PRIORITY_HIGHEST, + UV_THREAD_PRIORITY_ABOVE_NORMAL, UV_THREAD_PRIORITY_NORMAL, + UV_THREAD_PRIORITY_BELOW_NORMAL, UV_THREAD_PRIORITY_LOWEST. +.. c:function:: int uv_thread_getpriority(uv_thread_t tid, int* priority) + If the function succeeds, the return value is 0. + If the function fails, the return value is less than zero. + Retrieves the scheduling priority of the thread specified by tid. The value in the + output parameter priority is platform dependent. + For Linux, when schedule policy is SCHED_OTHER (default), priority is 0. + Thread-local storage ^^^^^^^^^^^^^^^^^^^^ diff --git a/include/uv.h b/include/uv.h index 5642101c10c..b1e58e6cbfa 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1284,6 +1284,17 @@ UV_EXTERN uv_pid_t uv_os_getppid(void); UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority); UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority); +enum { + UV_THREAD_PRIORITY_HIGHEST = 2, + UV_THREAD_PRIORITY_ABOVE_NORMAL = 1, + UV_THREAD_PRIORITY_NORMAL = 0, + UV_THREAD_PRIORITY_BELOW_NORMAL = -1, + UV_THREAD_PRIORITY_LOWEST = -2, +}; + +UV_EXTERN int uv_thread_getpriority(uv_thread_t tid, int* priority); +UV_EXTERN int uv_thread_setpriority(uv_thread_t tid, int priority); + UV_EXTERN unsigned int uv_available_parallelism(void); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); diff --git a/src/unix/core.c b/src/unix/core.c index 25c5181f370..965e7f77525 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -90,6 +90,7 @@ extern char** environ; #if defined(__linux__) # include # include +# define gettid() syscall(SYS_gettid) # define uv__accept4 accept4 #endif @@ -1557,6 +1558,130 @@ int uv_os_setpriority(uv_pid_t pid, int priority) { return 0; } +/** + * If the function succeeds, the return value is 0. + * If the function fails, the return value is non-zero. + * for Linux, when schedule policy is SCHED_OTHER (default), priority is 0. + * So the output parameter priority is actually the nice value. +*/ +int uv_thread_getpriority(uv_thread_t tid, int* priority) { + int r; + int policy; + struct sched_param param; +#ifdef __linux__ + pid_t pid = gettid(); +#endif + + if (priority == NULL) + return UV_EINVAL; + + r = pthread_getschedparam(tid, &policy, ¶m); + if (r != 0) + return UV__ERR(errno); + +#ifdef __linux__ + if (SCHED_OTHER == policy && pthread_equal(tid, pthread_self())) { + errno = 0; + r = getpriority(PRIO_PROCESS, pid); + if (r == -1 && errno != 0) + return UV__ERR(errno); + *priority = r; + return 0; + } +#endif + + *priority = param.sched_priority; + return 0; +} + +#ifdef __linux__ +static int set_nice_for_calling_thread(int priority) { + int r; + int nice; + + if (priority < UV_THREAD_PRIORITY_LOWEST || priority > UV_THREAD_PRIORITY_HIGHEST) + return UV_EINVAL; + + pid_t pid = gettid(); + nice = 0 - priority * 2; + r = setpriority(PRIO_PROCESS, pid, nice); + if (r != 0) + return UV__ERR(errno); + return 0; +} +#endif + +/** + * If the function succeeds, the return value is 0. + * If the function fails, the return value is non-zero. +*/ +int uv_thread_setpriority(uv_thread_t tid, int priority) { + int r; + int min; + int max; + int range; + int prio; + int policy; + struct sched_param param; + + if (priority < UV_THREAD_PRIORITY_LOWEST || priority > UV_THREAD_PRIORITY_HIGHEST) + return UV_EINVAL; + + r = pthread_getschedparam(tid, &policy, ¶m); + if (r != 0) + return UV__ERR(errno); + +#ifdef __linux__ +/** + * for Linux, when schedule policy is SCHED_OTHER (default), priority must be 0, + * we should set the nice value in this case. +*/ + if (SCHED_OTHER == policy && pthread_equal(tid, pthread_self())) + return set_nice_for_calling_thread(priority); +#endif + +#ifdef __PASE__ + min = 1; + max = 127; +#else + min = sched_get_priority_min(policy); + max = sched_get_priority_max(policy); +#endif + + if (min == -1 || max == -1) + return UV__ERR(errno); + + range = max - min; + + switch (priority) { + case UV_THREAD_PRIORITY_HIGHEST: + prio = max; + break; + case UV_THREAD_PRIORITY_ABOVE_NORMAL: + prio = min + range * 3 / 4; + break; + case UV_THREAD_PRIORITY_NORMAL: + prio = min + range / 2; + break; + case UV_THREAD_PRIORITY_BELOW_NORMAL: + prio = min + range / 4; + break; + case UV_THREAD_PRIORITY_LOWEST: + prio = min; + break; + default: + return 0; + } + + if (param.sched_priority != prio) { + param.sched_priority = prio; + r = pthread_setschedparam(tid, policy, ¶m); + if (r != 0) + return UV__ERR(errno); + } + + return 0; +} int uv_os_uname(uv_utsname_t* buffer) { struct utsname buf; diff --git a/src/win/util.c b/src/win/util.c index 91d88a54fb2..a96cb915930 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1466,6 +1466,48 @@ int uv_os_setpriority(uv_pid_t pid, int priority) { return r; } +int uv_thread_getpriority(uv_thread_t tid, int* priority) { + int r; + + if (priority == NULL) + return UV_EINVAL; + + r = GetThreadPriority(tid); + if (r == THREAD_PRIORITY_ERROR_RETURN) + return uv_translate_sys_error(GetLastError()); + + *priority = r; + return 0; +} + +int uv_thread_setpriority(uv_thread_t tid, int priority) { + int r; + + switch (priority) { + case UV_THREAD_PRIORITY_HIGHEST: + r = SetThreadPriority(tid, THREAD_PRIORITY_HIGHEST); + break; + case UV_THREAD_PRIORITY_ABOVE_NORMAL: + r = SetThreadPriority(tid, THREAD_PRIORITY_ABOVE_NORMAL); + break; + case UV_THREAD_PRIORITY_NORMAL: + r = SetThreadPriority(tid, THREAD_PRIORITY_NORMAL); + break; + case UV_THREAD_PRIORITY_BELOW_NORMAL: + r = SetThreadPriority(tid, THREAD_PRIORITY_BELOW_NORMAL); + break; + case UV_THREAD_PRIORITY_LOWEST: + r = SetThreadPriority(tid, THREAD_PRIORITY_LOWEST); + break; + default: + return 0; + } + + if (r == 0) + return uv_translate_sys_error(GetLastError()); + + return 0; +} int uv_os_uname(uv_utsname_t* buffer) { /* Implementation loosely based on diff --git a/test/test-list.h b/test/test-list.h index d112d07a29a..f042bc29f7c 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -468,6 +468,7 @@ TEST_DECLARE (thread_rwlock_trylock) TEST_DECLARE (thread_create) TEST_DECLARE (thread_equal) TEST_DECLARE (thread_affinity) +TEST_DECLARE (thread_priority) TEST_DECLARE (dlerror) #if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ !defined(__sun) @@ -1165,6 +1166,7 @@ TASK_LIST_START TEST_ENTRY (thread_create) TEST_ENTRY (thread_equal) TEST_ENTRY (thread_affinity) + TEST_ENTRY (thread_priority) TEST_ENTRY (dlerror) TEST_ENTRY (ip4_addr) TEST_ENTRY (ip6_addr_link_local) diff --git a/test/test-thread-priority.c b/test/test-thread-priority.c new file mode 100644 index 00000000000..0aaf297722b --- /dev/null +++ b/test/test-thread-priority.c @@ -0,0 +1,105 @@ +/* Copyright libuv contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include /* memset */ + +#ifdef __POSIX__ +#include +#include +#endif + +#ifdef _WIN32 +#include +#else +#include +#endif + +uv_sem_t sem; + +static void simple_task(void *args) { + uv_sem_wait(&sem); + printf("in simple_task\n"); +} + +TEST_IMPL(thread_priority) { + int priority; +#ifndef _WIN32 + int min; + int max; + int policy; + struct sched_param param; +#endif + uv_thread_t task_id; + + /* Verify that passing a NULL pointer returns UV_EINVAL. */ + ASSERT_EQ(UV_EINVAL, uv_thread_getpriority(0, NULL)); + ASSERT_OK(uv_sem_init(&sem, 1)); + uv_sem_wait(&sem); + ASSERT_OK(uv_thread_create(&task_id, simple_task, NULL)); + ASSERT_OK(uv_thread_getpriority(task_id, &priority)); + +#ifdef _WIN32 + ASSERT_EQ(priority, THREAD_PRIORITY_NORMAL); +#else + ASSERT_OK(pthread_getschedparam(task_id, &policy, ¶m)); +#ifdef __PASE__ + min = 1; + max = 127; +#else + min = sched_get_priority_min(policy); + max = sched_get_priority_max(policy); +#endif + ASSERT(priority >= min && priority <= max); +#endif + + ASSERT_OK(uv_thread_setpriority(task_id, UV_THREAD_PRIORITY_LOWEST)); + ASSERT_OK(uv_thread_getpriority(task_id, &priority)); + +#ifdef _WIN32 + ASSERT_EQ(priority, THREAD_PRIORITY_LOWEST); +#else + ASSERT_EQ(priority, min); +#endif + +/** + * test set nice value for the calling thread with default schedule policy +*/ +#ifdef __linux__ + ASSERT_OK(uv_thread_getpriority(pthread_self(), &priority)); + ASSERT_EQ(priority, 0); + ASSERT_OK(uv_thread_setpriority(pthread_self(), UV_THREAD_PRIORITY_LOWEST)); + ASSERT_OK(uv_thread_getpriority(pthread_self(), &priority)); + ASSERT_EQ(priority, (0 - UV_THREAD_PRIORITY_LOWEST * 2)); +#endif + + uv_sem_post(&sem); + + ASSERT_OK(uv_thread_join(&task_id)); + + uv_sem_destroy(&sem); + + return 0; +} \ No newline at end of file From d843b7cf7fe77ff2c134e7de9f1ce79fbecda7a6 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 14 Nov 2023 09:26:53 -0500 Subject: [PATCH 466/713] pipe: add back error handling to connect / bind (#4202) This was incorrectly dropped by #4030, where previously connecting to "" might fail eventually, now instead it would return EINVAL and then fail to initialize the struct or call the callback. --- src/unix/pipe.c | 19 +++++++++++++++++-- src/win/pipe.c | 31 ++++++++++++++++++++++--------- test/test-pipe-bind-error.c | 19 ++++++++++++++++++- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index d332f351830..117b8ee52fc 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -210,7 +210,22 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { - uv_pipe_connect2(req, handle, name, strlen(name), 0, cb); + int err; + + err = uv_pipe_connect2(req, handle, name, strlen(name), 0, cb); + + if (err) { + handle->delayed_error = err; + handle->connect_req = req; + + uv__req_init(handle->loop, req, UV_CONNECT); + req->handle = (uv_stream_t*) handle; + req->cb = cb; + uv__queue_init(&req->queue); + + /* Force callback to run on next tick in case of error. */ + uv__io_feed(handle->loop, &handle->io_watcher); + } } @@ -295,7 +310,7 @@ int uv_pipe_connect2(uv_connect_t* req, handle->connect_req = req; uv__req_init(handle->loop, req, UV_CONNECT); - req->handle = (uv_stream_t*)handle; + req->handle = (uv_stream_t*) handle; req->cb = cb; uv__queue_init(&req->queue); diff --git a/src/win/pipe.c b/src/win/pipe.c index cec72ff750b..c5749418546 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -834,7 +834,19 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { - uv_pipe_connect2(req, handle, name, strlen(name), 0, cb); + uv_loop_t* loop; + int err; + + err = uv_pipe_connect2(req, handle, name, strlen(name), 0, cb); + + if (err) { + loop = handle->loop; + /* Make this req pending reporting an error. */ + SET_REQ_ERROR(req, err); + uv__insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); + } } @@ -844,12 +856,20 @@ int uv_pipe_connect2(uv_connect_t* req, size_t namelen, unsigned int flags, uv_connect_cb cb) { - uv_loop_t* loop = handle->loop; + uv_loop_t* loop; int err; size_t nameSize; HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; + loop = handle->loop; + UV_REQ_INIT(req, UV_CONNECT); + req->handle = (uv_stream_t*) handle; + req->cb = cb; + req->u.connect.pipeHandle = INVALID_HANDLE_VALUE; + req->u.connect.duplex_flags = 0; + req->u.connect.name = NULL; + if (flags & ~UV_PIPE_NO_TRUNCATE) { return UV_EINVAL; } @@ -872,13 +892,6 @@ int uv_pipe_connect2(uv_connect_t* req, } } - UV_REQ_INIT(req, UV_CONNECT); - req->handle = (uv_stream_t*) handle; - req->cb = cb; - req->u.connect.pipeHandle = INVALID_HANDLE_VALUE; - req->u.connect.duplex_flags = 0; - req->u.connect.name = NULL; - if (handle->flags & UV_HANDLE_PIPESERVER) { err = ERROR_INVALID_PARAMETER; goto error; diff --git a/test/test-pipe-bind-error.c b/test/test-pipe-bind-error.c index 381a0084dec..1dc99e5bc0b 100644 --- a/test/test-pipe-bind-error.c +++ b/test/test-pipe-bind-error.c @@ -33,6 +33,7 @@ static int close_cb_called = 0; +static int connect_cb_called = 0; static void close_cb(uv_handle_t* handle) { @@ -154,6 +155,14 @@ TEST_IMPL(pipe_bind_or_listen_error_after_close) { return 0; } + +static void connect_overlong_cb(uv_connect_t* connect_req, int status) { + ASSERT_EQ(status, UV_EINVAL); + connect_cb_called++; + uv_close((uv_handle_t*) connect_req->handle, close_cb); +} + + TEST_IMPL(pipe_overlong_path) { char path[512]; uv_pipe_t pipe; @@ -170,9 +179,17 @@ TEST_IMPL(pipe_overlong_path) { sizeof(path), UV_PIPE_NO_TRUNCATE, (uv_connect_cb) abort)); - uv_close((uv_handle_t*) &pipe, NULL); ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(UV_EINVAL, uv_pipe_bind(&pipe, "")); + uv_pipe_connect(&req, + &pipe, + "", + (uv_connect_cb) connect_overlong_cb); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, connect_cb_called); + ASSERT_EQ(1, close_cb_called); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; From 54d8364c2406758b572621af381f1d83e01ae46c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 14 Nov 2023 22:09:30 +0100 Subject: [PATCH 467/713] test: check if ipv6 link-local traffic is routable (#4220) Fixes: https://github.com/libuv/libuv/issues/4211 --- test/test-tcp-connect6-error.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/test-tcp-connect6-error.c b/test/test-tcp-connect6-error.c index 1e6d7c78da9..dc2fce82f89 100644 --- a/test/test-tcp-connect6-error.c +++ b/test/test-tcp-connect6-error.c @@ -23,6 +23,7 @@ #include "task.h" #include #include +#include static int connect_cb_called = 0; @@ -75,9 +76,13 @@ TEST_IMPL(tcp_connect6_error_fault) { TEST_IMPL(tcp_connect6_link_local) { + uv_interface_address_t* ifs; + uv_interface_address_t* p; struct sockaddr_in6 addr; uv_connect_t req; uv_tcp_t server; + int ok; + int n; if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); @@ -90,6 +95,18 @@ TEST_IMPL(tcp_connect6_link_local) { RETURN_SKIP("Test does not currently work in QEMU"); #endif /* defined(__QEMU__) */ + /* Check there's an interface that routes link-local (fe80::/10) traffic. */ + ASSERT_OK(uv_interface_addresses(&ifs, &n)); + for (p = ifs; p < &ifs[n]; p++) + if (p->address.address6.sin6_family == AF_INET6) + if (!memcmp(&p->address.address6.sin6_addr, "\xfe\x80", 2)) + break; + ok = (p < &ifs[n]); + uv_free_interface_addresses(ifs, n); + + if (!ok) + RETURN_SKIP("IPv6 link-local traffic not supported"); + ASSERT_OK(uv_ip6_addr("fe80::0bad:babe", 1337, &addr)); ASSERT_OK(uv_tcp_init(uv_default_loop(), &server)); From b9421d70665352138557d2d2338656a38ac70691 Mon Sep 17 00:00:00 2001 From: Viacheslav Muravyev Date: Wed, 15 Nov 2023 20:39:17 +0700 Subject: [PATCH 468/713] unix: restore signal disposition to previous one (#4216) Fixes: https://github.com/libuv/libuv/issues/2435 --- src/unix/signal.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/unix/signal.c b/src/unix/signal.c index bc4206e6d86..2b5567081a4 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -32,11 +32,18 @@ # define SA_RESTART 0 #endif +#define UV__NSIG 128 + typedef struct { uv_signal_t* handle; int signum; } uv__signal_msg_t; +typedef struct { + struct sigaction acts[UV__NSIG]; + char acts_presented_flags[UV__NSIG]; +} uv__sigactions_t; + RB_HEAD(uv__signal_tree_s, uv_signal_s); @@ -50,11 +57,23 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2); static void uv__signal_stop(uv_signal_t* handle); static void uv__signal_unregister_handler(int signum); +static void uv__sigaction_set(int signum, struct sigaction *sa); +static int uv__sigaction_isset(int signum); static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT; static struct uv__signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); static int uv__signal_lock_pipefd[2] = { -1, -1 }; +static uv__sigactions_t uv__sigactions; + +static void uv__sigaction_set(int signum, struct sigaction *sa) { + uv__sigactions.acts[signum] = *sa; + uv__sigactions.acts_presented_flags[signum] = 1; +} + +static int uv__sigaction_isset(int signum) { + return uv__sigactions.acts_presented_flags[signum] == 0 ? 0 : 1; +} RB_GENERATE_STATIC(uv__signal_tree_s, uv_signal_s, tree_entry, @@ -224,6 +243,7 @@ static void uv__signal_handler(int signum) { static int uv__signal_register_handler(int signum, int oneshot) { /* When this function is called, the signal lock must be held. */ struct sigaction sa; + struct sigaction sa_old; /* XXX use a separate signal stack? */ memset(&sa, 0, sizeof(sa)); @@ -234,10 +254,11 @@ static int uv__signal_register_handler(int signum, int oneshot) { if (oneshot) sa.sa_flags |= SA_RESETHAND; - /* XXX save old action so we can restore it later on? */ - if (sigaction(signum, &sa, NULL)) + if (sigaction(signum, &sa, &sa_old)) return UV__ERR(errno); + uv__sigaction_set(signum, &sa_old); + return 0; } @@ -245,9 +266,10 @@ static int uv__signal_register_handler(int signum, int oneshot) { static void uv__signal_unregister_handler(int signum) { /* When this function is called, the signal lock must be held. */ struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_DFL; + + assert(uv__sigaction_isset(signum)); + + sa = uv__sigactions.acts[signum]; /* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a * signal implies that it was successfully registered earlier, so EINVAL From 35da5ded3bd7cc6d21c2a6f3d796299f7e2123b9 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 15 Nov 2023 09:08:49 -0500 Subject: [PATCH 469/713] win: remove check for UV_PIPE_NO_TRUNCATE (#4221) There is no length at which this gets truncated on Windows. The underlying file system will just not successfully connect to a longer path (in WTF-16 characters), which will return an error asynchronously with the existing API. Refs: #4040 --- src/win/pipe.c | 12 ------------ test/test-pipe-bind-error.c | 7 +++++-- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index c5749418546..17e4a520caf 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -722,12 +722,6 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; } - if (flags & UV_PIPE_NO_TRUNCATE) { - if (namelen > 256) { - return UV_EINVAL; - } - } - if (handle->flags & UV_HANDLE_BOUND) { return UV_EINVAL; } @@ -886,12 +880,6 @@ int uv_pipe_connect2(uv_connect_t* req, return UV_EINVAL; } - if (flags & UV_PIPE_NO_TRUNCATE) { - if (namelen > 256) { - return UV_EINVAL; - } - } - if (handle->flags & UV_HANDLE_PIPESERVER) { err = ERROR_INVALID_PARAMETER; goto error; diff --git a/test/test-pipe-bind-error.c b/test/test-pipe-bind-error.c index 1dc99e5bc0b..412f23aedb0 100644 --- a/test/test-pipe-bind-error.c +++ b/test/test-pipe-bind-error.c @@ -164,12 +164,14 @@ static void connect_overlong_cb(uv_connect_t* connect_req, int status) { TEST_IMPL(pipe_overlong_path) { - char path[512]; uv_pipe_t pipe; uv_connect_t req; - memset(path, '@', sizeof(path)); ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe, 0)); + +#ifndef _WIN32 + char path[512]; + memset(path, '@', sizeof(path)); ASSERT_EQ(UV_EINVAL, uv_pipe_bind2(&pipe, path, sizeof(path), UV_PIPE_NO_TRUNCATE)); ASSERT_EQ(UV_EINVAL, @@ -180,6 +182,7 @@ TEST_IMPL(pipe_overlong_path) { UV_PIPE_NO_TRUNCATE, (uv_connect_cb) abort)); ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); +#endif ASSERT_EQ(UV_EINVAL, uv_pipe_bind(&pipe, "")); uv_pipe_connect(&req, From f1444293652cf5478a67b9305271d73ad6d36232 Mon Sep 17 00:00:00 2001 From: matoro <12038583+matoro@users.noreply.github.com> Date: Wed, 15 Nov 2023 17:57:06 -0500 Subject: [PATCH 470/713] linux: disable io_uring on hppa below kernel 6.1.51 (#4224) First kernel with support is 6.1, was only fully functional from .51 onwards: https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/ Co-authored-by: matoro --- src/unix/linux.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 8eeb352e623..91409bb5781 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -487,8 +487,16 @@ static int uv__use_io_uring(void) { 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. */ - use = uv__kernel_version() >= /* 5.10.186 */ 0x050ABA ? 1 : -1; + /* 5.10.186 */ 0x050ABA +#endif + ? 1 : -1; /* But users can still enable it if they so desire. */ val = getenv("UV_USE_IO_URING"); From 6be130e1b865af62e6509d4ead9da5c911af5e12 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 16 Nov 2023 09:05:51 +0100 Subject: [PATCH 471/713] unix,win: fix read past end of pipe name buffer (#4209) Passing a socket name without a trailing nul byte to uv_pipe_bind2() or (on Windows) uv_pipe_connect2() resulted in reading beyond the end of the name buffer when copying or converting it. Fix that by copying the socket name to temporary storage first and add the trailing nul byte explicitly. Add a check for embedded nul bytes in the socket name. Fix a small memory leak in the Windows error path of uv_pipe_bind2(). --- src/unix/pipe.c | 29 ++++++++++------ src/win/pipe.c | 66 ++++++++++++++++++++++++++++++------ test/test-pipe-getsockname.c | 26 +++++++++++--- 3 files changed, 96 insertions(+), 25 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 117b8ee52fc..bb2806f579a 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -30,6 +30,19 @@ #include +/* Does the file path contain embedded nul bytes? */ +static int includes_nul(const char *s, size_t n) { + if (n == 0) + return 0; +#ifdef __linux__ + /* Accept abstract socket namespace path ("\0/virtual/path"). */ + s++; + n--; +#endif + return NULL != memchr(s, '\0', n); +} + + int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); handle->shutdown_req = NULL; @@ -65,11 +78,8 @@ int uv_pipe_bind2(uv_pipe_t* handle, if (namelen == 0) return UV_EINVAL; -#ifndef __linux__ - /* Abstract socket namespace only works on Linux. */ - if (*name == '\0') + if (includes_nul(name, namelen)) return UV_EINVAL; -#endif if (flags & UV_PIPE_NO_TRUNCATE) if (namelen > sizeof(saddr.sun_path)) @@ -91,9 +101,11 @@ int uv_pipe_bind2(uv_pipe_t* handle, * automatically since they're not real file system entities. */ if (*name != '\0') { - pipe_fname = uv__strdup(name); + pipe_fname = uv__malloc(namelen + 1); if (pipe_fname == NULL) return UV_ENOMEM; + memcpy(pipe_fname, name, namelen); + pipe_fname[namelen] = '\0'; } err = uv__socket(AF_UNIX, SOCK_STREAM, 0); @@ -117,7 +129,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, /* Success. */ handle->flags |= UV_HANDLE_BOUND; - handle->pipe_fname = pipe_fname; /* NULL or a strdup'ed copy. */ + handle->pipe_fname = pipe_fname; /* NULL or a copy of |name| */ handle->io_watcher.fd = sockfd; return 0; @@ -249,11 +261,8 @@ int uv_pipe_connect2(uv_connect_t* req, if (namelen == 0) return UV_EINVAL; -#ifndef __linux__ - /* Abstract socket namespace only works on Linux. */ - if (*name == '\0') + if (includes_nul(name, namelen)) return UV_EINVAL; -#endif if (flags & UV_PIPE_NO_TRUNCATE) if (namelen > sizeof(saddr.sun_path)) diff --git a/src/win/pipe.c b/src/win/pipe.c index 17e4a520caf..d5102ed5c44 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -98,6 +98,14 @@ static void eof_timer_destroy(uv_pipe_t* pipe); static void eof_timer_close_cb(uv_handle_t* handle); +/* Does the file path contain embedded nul bytes? */ +static int includes_nul(const char *s, size_t n) { + if (n == 0) + return 0; + return NULL != memchr(s, '\0', n); +} + + static void uv__unique_pipe_name(char* ptr, char* name, size_t size) { snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId()); } @@ -705,6 +713,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, uv_loop_t* loop = handle->loop; int i, err; uv_pipe_accept_t* req; + char* name_copy; if (flags & ~UV_PIPE_NO_TRUNCATE) { return UV_EINVAL; @@ -718,7 +727,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; } - if (*name == '\0') { + if (includes_nul(name, namelen)) { return UV_EINVAL; } @@ -730,14 +739,24 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; } + name_copy = uv__malloc(namelen + 1); + if (name_copy == NULL) { + return UV_ENOMEM; + } + + memcpy(name_copy, name, namelen); + name_copy[namelen] = '\0'; + if (!(handle->flags & UV_HANDLE_PIPESERVER)) { handle->pipe.serv.pending_instances = default_pending_pipe_instances; } + err = UV_ENOMEM; handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*) uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances); - if (!handle->pipe.serv.accept_reqs) - return UV_ENOMEM; + if (handle->pipe.serv.accept_reqs == NULL) { + goto error; + } for (i = 0; i < handle->pipe.serv.pending_instances; i++) { req = &handle->pipe.serv.accept_reqs[i]; @@ -747,9 +766,14 @@ int uv_pipe_bind2(uv_pipe_t* handle, req->next_pending = NULL; } - err = uv__convert_utf8_to_utf16(name, &handle->name); - if (err) - return err; + /* TODO(bnoordhuis) Add converters that take a |length| parameter. */ + err = uv__convert_utf8_to_utf16(name_copy, &handle->name); + uv__free(name_copy); + name_copy = NULL; + + if (err) { + goto error; + } /* * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE. @@ -761,9 +785,11 @@ int uv_pipe_bind2(uv_pipe_t* handle, TRUE)) { err = GetLastError(); if (err == ERROR_ACCESS_DENIED) { - err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */ + err = UV_EADDRINUSE; } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) { - err = WSAEACCES; /* Translates to UV_EACCES. */ + err = UV_EACCES; + } else { + err = uv_translate_sys_error(err); } goto error; } @@ -775,10 +801,13 @@ int uv_pipe_bind2(uv_pipe_t* handle, return 0; error: + uv__free(handle->pipe.serv.accept_reqs); uv__free(handle->name); + uv__free(name_copy); + handle->pipe.serv.accept_reqs = NULL; handle->name = NULL; - return uv_translate_sys_error(err); + return err; } @@ -855,6 +884,7 @@ int uv_pipe_connect2(uv_connect_t* req, size_t nameSize; HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; + char* name_copy; loop = handle->loop; UV_REQ_INIT(req, UV_CONNECT); @@ -876,10 +906,18 @@ int uv_pipe_connect2(uv_connect_t* req, return UV_EINVAL; } - if (*name == '\0') { + if (includes_nul(name, namelen)) { return UV_EINVAL; } + name_copy = uv__malloc(namelen + 1); + if (name_copy == NULL) { + return UV_ENOMEM; + } + + memcpy(name_copy, name, namelen); + name_copy[namelen] = '\0'; + if (handle->flags & UV_HANDLE_PIPESERVER) { err = ERROR_INVALID_PARAMETER; goto error; @@ -890,7 +928,11 @@ int uv_pipe_connect2(uv_connect_t* req, } uv__pipe_connection_init(handle); - err = uv__convert_utf8_to_utf16(name, &handle->name); + /* TODO(bnoordhuis) Add converters that take a |length| parameter. */ + err = uv__convert_utf8_to_utf16(name_copy, &handle->name); + uv__free(name_copy); + name_copy = NULL; + if (err) { err = ERROR_NO_UNICODE_TRANSLATION; goto error; @@ -936,6 +978,8 @@ int uv_pipe_connect2(uv_connect_t* req, return 0; error: + uv__free(name_copy); + if (handle->name) { uv__free(handle->name); handle->name = NULL; diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index eb09d88fd2b..bac723c6c07 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -91,16 +91,24 @@ TEST_IMPL(pipe_getsockname) { RETURN_SKIP(NO_SELF_CONNECT); #endif uv_loop_t* loop; + char namebuf[256]; char buf[1024]; + size_t namelen; size_t len; int r; + snprintf(namebuf, sizeof(namebuf), "%s-oob", TEST_PIPENAME); + namelen = sizeof(TEST_PIPENAME) - 1; + loop = uv_default_loop(); ASSERT_NOT_NULL(loop); r = uv_pipe_init(loop, &pipe_server, 0); ASSERT_OK(r); + r = uv_pipe_bind2(&pipe_server, "bad\0path", 8, 0); + ASSERT_EQ(r, UV_EINVAL); + len = sizeof buf; r = uv_pipe_getsockname(&pipe_server, buf, &len); ASSERT_EQ(r, UV_EBADF); @@ -109,9 +117,13 @@ TEST_IMPL(pipe_getsockname) { r = uv_pipe_getpeername(&pipe_server, buf, &len); ASSERT_EQ(r, UV_EBADF); - r = uv_pipe_bind(&pipe_server, TEST_PIPENAME); + r = uv_pipe_bind2(&pipe_server, namebuf, namelen, 0); ASSERT_OK(r); +#ifndef _WIN32 + ASSERT_STR_EQ(pipe_server.pipe_fname, TEST_PIPENAME); +#endif + len = sizeof buf; r = uv_pipe_getsockname(&pipe_server, buf, &len); ASSERT_OK(r); @@ -138,7 +150,13 @@ TEST_IMPL(pipe_getsockname) { r = uv_pipe_getpeername(&pipe_client, buf, &len); ASSERT_EQ(r, UV_EBADF); - uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb); + r = uv_pipe_connect2(&connect_req, + &pipe_client, + namebuf, + namelen, + 0, + pipe_client_connect_cb); + ASSERT_OK(r); len = sizeof buf; r = uv_pipe_getsockname(&pipe_client, buf, &len); @@ -171,7 +189,7 @@ TEST_IMPL(pipe_getsockname_abstract) { buflen = sizeof(buf); memset(buf, 0, sizeof(buf)); ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0)); - ASSERT_OK(uv_pipe_bind2(&pipe_server, name, sizeof(name), 0)); + ASSERT_OK(uv_pipe_bind2(&pipe_server, name, sizeof(name) - 1, 0)); ASSERT_OK(uv_pipe_getsockname(&pipe_server, buf, &buflen)); ASSERT_MEM_EQ(name, buf, sizeof(name)); ASSERT_OK(uv_listen((uv_stream_t*) &pipe_server, @@ -181,7 +199,7 @@ TEST_IMPL(pipe_getsockname_abstract) { ASSERT_OK(uv_pipe_connect2(&connect_req, &pipe_client, name, - sizeof(name), + sizeof(name) - 1, 0, pipe_client_connect_cb)); ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); From 4785ad6337aac8b78224291f0848f25fc8cb41c9 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Sat, 18 Nov 2023 16:57:40 +0800 Subject: [PATCH 472/713] unix: unbreak macOS < 10.14 (#4230) --- src/unix/fs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 891306daedc..4de0643a6c3 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -84,7 +84,8 @@ #if defined(__CYGWIN__) || \ (defined(__HAIKU__) && B_HAIKU_VERSION < B_HAIKU_VERSION_1_PRE_BETA_5) || \ - (defined(__sun) && !defined(__illumos__)) + (defined(__sun) && !defined(__illumos__)) || \ + (defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED <= 101300) #define preadv(fd, bufs, nbufs, off) \ pread(fd, (bufs)->iov_base, (bufs)->iov_len, off) #define pwritev(fd, bufs, nbufs, off) \ From bfbe4e38d7253ed5cfa87bfa44ae66fd7bf1957f Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Sat, 18 Nov 2023 18:19:16 +0000 Subject: [PATCH 473/713] aix: disable ipv6 link local (#4229) AIX does not implement ifaddrs and when retrieving the network interfaces with uv_interface_addresses there was a test failure in tcp_connect6_link_local. For now disable ipv6 link local on aix to: 1) fix broken aix build 2) stop blocking libuv upgrade in node Refs: https://github.com/libuv/libuv/pull/4222#issuecomment-1812962233 Refs: https://github.com/nodejs/node/pull/50650 --- src/unix/tcp.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 29f4532e747..f455c53f1bd 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -30,12 +30,8 @@ #include #include -#if defined(__PASE__) -#include -#define ifaddrs ifaddrs_pase -#define getifaddrs Qp2getifaddrs -#define freeifaddrs Qp2freeifaddrs -#else +/* ifaddrs is not implemented on AIX and IBM i PASE */ +#if !defined(_AIX) #include #endif @@ -224,6 +220,10 @@ static int uv__is_ipv6_link_local(const struct sockaddr* addr) { static int uv__ipv6_link_local_scope_id(void) { +/* disable link local on AIX & PASE for now */ +#if defined(_AIX) + return 0; +#else struct sockaddr_in6* a6; struct ifaddrs* ifa; struct ifaddrs* p; @@ -245,6 +245,7 @@ static int uv__ipv6_link_local_scope_id(void) { freeifaddrs(ifa); return rv; +#endif } From 7ba94d39096e54e54c52f813325aa01202eb6acf Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Sun, 19 Nov 2023 08:47:23 -0500 Subject: [PATCH 474/713] doc: move cjihrig to emeriti (#4234) --- MAINTAINERS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index ff8be88b7b7..41c60cb383c 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -4,9 +4,6 @@ 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) @@ -27,6 +24,9 @@ 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)) From fc70430b09c49032d41ae97db26da10e20941e75 Mon Sep 17 00:00:00 2001 From: Bo Anderson Date: Fri, 24 Nov 2023 10:17:52 +0000 Subject: [PATCH 475/713] unix: correct pwritev conditional (#4233) --- src/unix/fs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 4de0643a6c3..9671f0dda12 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -85,7 +85,8 @@ #if defined(__CYGWIN__) || \ (defined(__HAIKU__) && B_HAIKU_VERSION < B_HAIKU_VERSION_1_PRE_BETA_5) || \ (defined(__sun) && !defined(__illumos__)) || \ - (defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED <= 101300) + (defined(__APPLE__) && !TARGET_OS_IPHONE && \ + MAC_OS_X_VERSION_MIN_REQUIRED < 110000) #define preadv(fd, bufs, nbufs, off) \ pread(fd, (bufs)->iov_base, (bufs)->iov_len, off) #define pwritev(fd, bufs, nbufs, off) \ From de43f42735700453169efd9bea03f11f96a59dcb Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Fri, 24 Nov 2023 05:18:51 -0500 Subject: [PATCH 476/713] test_fs.c: Fix issue on 32-bit systems using btrfs (#4227) On Fedora's build system, the build environment runs on btrfs. This revealed a bug in the test on i686 systems, where this comparison was being performed as a comparison of two signed integers, but the filesystem type of btrfs happens to use the higher-order bits, resulting in it appearing as a negative value. BTRFS_SUPER_MAGIC 0x9123683e Signed-off-by: Stephen Gallagher --- test/test-fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-fs.c b/test/test-fs.c index 1acdc5c6708..ab8a9e07cce 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -343,7 +343,7 @@ static void statfs_cb(uv_fs_t* req) { defined(__OpenBSD__) || defined(__NetBSD__) ASSERT_OK(stats->f_type); #else - ASSERT_GT(stats->f_type, 0); + ASSERT_UINT64_GT(stats->f_type, 0); #endif ASSERT_GT(stats->f_bsize, 0); From a5c01d4de3695e9d9da34cfd643b5ff0ba582ea7 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 24 Nov 2023 05:22:25 -0500 Subject: [PATCH 477/713] misc: ignore libuv-release-tool files (#4201) --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e6a04ec6253..d184d21cb9f 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,5 @@ cmake-build-debug/ # make dist output libuv-*.tar.* +/dist.libuv.org/ +/libuv-release-tool/ From 5e302730cd29cfeb15d32369dd2edfd9d3c82c11 Mon Sep 17 00:00:00 2001 From: Ardi Nugraha <33378542+ardi-nugraha@users.noreply.github.com> Date: Fri, 1 Dec 2023 04:54:41 +0700 Subject: [PATCH 478/713] win: honor NoDefaultCurrentDirectoryInExePath env var (#4238) Fixes: https://github.com/libuv/libuv/issues/3888 Refs: https://github.com/nodejs/node/issues/46264 --- src/win/process.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index 43059858f31..117054d49e0 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -377,11 +377,13 @@ static WCHAR* search_path(const WCHAR *file, } else { dir_end = path; - /* The file is really only a name; look in cwd first, then scan path */ - result = path_search_walk_ext(L"", 0, - file, file_len, - cwd, cwd_len, - name_has_ext); + if (NeedCurrentDirectoryForExePathW(L"")) { + /* The file is really only a name; look in cwd first, then scan path */ + result = path_search_walk_ext(L"", 0, + file, file_len, + cwd, cwd_len, + name_has_ext); + } while (result == NULL) { if (dir_end == NULL || *dir_end == L'\0') { From 12bd89bbc3955f5df5c0a71d32a6cefb2a0d3cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 11 Dec 2023 09:18:50 +0100 Subject: [PATCH 479/713] idna: fix compilation warning w_target_len is set but unsued in release mode. --- src/idna.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/idna.c b/src/idna.c index 1c0a60cf3e3..3cf79ca94b1 100644 --- a/src/idna.c +++ b/src/idna.c @@ -400,6 +400,7 @@ void uv_wtf8_to_utf16(const char* source_ptr, } } while (*source_ptr++); + (void)w_target_len; assert(w_target_len == 0); } From a7d5255122ebdf60fd209e1f7201c5dac175677b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 12 Dec 2023 21:13:31 +0100 Subject: [PATCH 480/713] linux: remove HAVE_IFADDRS_H macro (#4243) Introduced long ago for old Linux/libc flavors libuv no longer supports. We include unconditionally elsewhere so there is no point in special-casing it here. Fixes: https://github.com/libuv/libuv/issues/4242 --- src/unix/linux.c | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 91409bb5781..7402a6fae07 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -37,12 +37,16 @@ #include #include +#include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -120,25 +124,6 @@ # endif #endif /* __NR_getrandom */ -#define HAVE_IFADDRS_H 1 - -# if defined(__ANDROID_API__) && __ANDROID_API__ < 24 -# undef HAVE_IFADDRS_H -#endif - -#ifdef __UCLIBC__ -# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32 -# undef HAVE_IFADDRS_H -# endif -#endif - -#ifdef HAVE_IFADDRS_H -# include -# include -# include -# include -#endif /* HAVE_IFADDRS_H */ - enum { UV__IORING_SETUP_SQPOLL = 2u, }; @@ -1916,7 +1901,6 @@ int uv_cpu_info(uv_cpu_info_t** ci, int* count) { } -#ifdef HAVE_IFADDRS_H static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) return 1; @@ -1930,14 +1914,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return exclude_type; return !exclude_type; } -#endif int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { -#ifndef HAVE_IFADDRS_H - *count = 0; - *addresses = NULL; - return UV_ENOSYS; -#else struct ifaddrs *addrs, *ent; uv_interface_address_t* address; int i; @@ -2016,7 +1994,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { freeifaddrs(addrs); return 0; -#endif } From 1479b76310a38d98eda94db2b7f8a40e04b3ff32 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Tue, 12 Dec 2023 20:19:02 +0000 Subject: [PATCH 481/713] test: skip tcp-write-in-a-row on IBM i (#4197) On IBM i this test fails asserting the write queue size. The test expects the queue size to be greater than 0 but the queue size is 0 on IBM i. https://github.com/libuv/libuv/blob/66160d6973b41040f6b2066a84359147258f60c3/test/test-tcp-write-in-a-row.c#L75 The test expects the write to get queued because the size of the data is larger than the send and receive buffers. https://github.com/libuv/libuv/blob/66160d6973b41040f6b2066a84359147258f60c3/test/test-tcp-write-in-a-row.c#L39-L40 For some reason the request does not seem to get queued on IBM i. The root cause of the issue will need further investigation. Part of #4143 --- test/test-tcp-write-in-a-row.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test-tcp-write-in-a-row.c b/test/test-tcp-write-in-a-row.c index 89304eb5a34..5c17ed49613 100644 --- a/test/test-tcp-write-in-a-row.c +++ b/test/test-tcp-write-in-a-row.c @@ -114,8 +114,9 @@ static void start_server(void) { TEST_IMPL(tcp_write_in_a_row) { #if defined(_WIN32) RETURN_SKIP("tcp_write_in_a_row does not work on Windows"); +#elif defined(__PASE__) + RETURN_SKIP("tcp_write_in_a_row does not work on IBM i PASE"); #else - uv_connect_t connect_req; struct sockaddr_in addr; From 34db4c21b1f3182a74091d927b10bb9830ef6717 Mon Sep 17 00:00:00 2001 From: Anton Bachin Date: Wed, 20 Dec 2023 16:27:13 +0300 Subject: [PATCH 482/713] build,win: work around missing uuid.dll on MinGW (#4261) --- CMakeLists.txt | 1 - configure.ac | 2 +- src/win/process.c | 11 ++++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f7f42773bf6..f3d1642b193 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,7 +186,6 @@ if(WIN32) ws2_32 dbghelp ole32 - uuid shell32) list(APPEND uv_sources src/win/async.c diff --git a/configure.ac b/configure.ac index e556bcc8db4..f9b5aa53d51 100644 --- a/configure.ac +++ b/configure.ac @@ -74,7 +74,7 @@ AM_CONDITIONAL([OS400], [AS_CASE([$host_os],[os400], [true], [false]) AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])]) AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])]) AS_CASE([$host_os],[mingw*], [ - LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -luserenv -luser32 -ldbghelp -lole32 -luuid -lshell32" + LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -luserenv -luser32 -ldbghelp -lole32 -lshell32" ]) AS_CASE([$host_os], [solaris2.10], [ CFLAGS="$CFLAGS -DSUNOS_NO_IFADDRS" diff --git a/src/win/process.c b/src/win/process.c index 117054d49e0..6123ea264ca 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -1212,9 +1212,18 @@ static int uv__kill(HANDLE process_handle, int signum) { (PVOID) dump_folder, &dump_folder_len); if (ret != ERROR_SUCCESS) { + /* Workaround for missing uuid.dll on MinGW. */ + static const GUID FOLDERID_LocalAppData_libuv = { + 0xf1b32785, 0x6fba, 0x4fcf, + {0x9d, 0x55, 0x7b, 0x8e, 0x7f, 0x15, 0x70, 0x91} + }; + /* Default value for `dump_folder` is `%LOCALAPPDATA%\CrashDumps`. */ WCHAR* localappdata; - SHGetKnownFolderPath(&FOLDERID_LocalAppData, 0, NULL, &localappdata); + SHGetKnownFolderPath(&FOLDERID_LocalAppData_libuv, + 0, + NULL, + &localappdata); _snwprintf_s(dump_folder, sizeof(dump_folder), _TRUNCATE, From 8a499e13319f4f02193cf5f3d22ee2c3e247f0a8 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Fri, 22 Dec 2023 08:30:48 -0300 Subject: [PATCH 483/713] win: stop using deprecated names (#4253) --- CMakeLists.txt | 7 +- src/win/fs-event.c | 2 +- src/win/fs.c | 4 +- src/win/pipe.c | 2 +- src/win/process.c | 10 +- src/win/tty.c | 4 +- test/run-tests.c | 1 + test/runner-win.c | 2 +- test/test-fs-copyfile.c | 3 +- test/test-fs-event.c | 6 +- test/test-fs-readdir.c | 4 +- test/test-fs.c | 181 ++++++++++++++++++---------------- test/test-getters-setters.c | 4 + test/test-metrics.c | 6 +- test/test-poll.c | 5 +- test/test-spawn.c | 9 +- test/test-threadpool-cancel.c | 4 + 17 files changed, 142 insertions(+), 112 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f3d1642b193..0a4d80699c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,6 +161,11 @@ list(APPEND uv_cflags ${lint-utf8-msvc} ) check_c_compiler_flag(-fno-strict-aliasing UV_F_STRICT_ALIASING) list(APPEND uv_cflags $<$:-fno-strict-aliasing>) +if (MSVC) + # Error on calling undeclared functions. + list(APPEND uv_cflags "/we4013") +endif() + set(uv_sources src/fs-poll.c src/idna.c @@ -176,7 +181,7 @@ set(uv_sources src/version.c) if(WIN32) - list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602) + list(APPEND uv_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602 _CRT_DECLARE_NONSTDC_NAMES=0) list(APPEND uv_libraries psapi user32 diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 4a0ca1f70a2..fce411813e9 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -114,7 +114,7 @@ static int uv__split_path(const WCHAR* filename, WCHAR** dir, } } - *file = wcsdup(filename); + *file = _wcsdup(filename); } else { if (dir) { *dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR)); diff --git a/src/win/fs.c b/src/win/fs.c index 99c8a2bf8bf..b73c17d8c1c 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -407,8 +407,8 @@ void fs__open(uv_fs_t* req) { /* Obtain the active umask. umask() never fails and returns the previous * umask. */ - current_umask = umask(0); - umask(current_umask); + current_umask = _umask(0); + _umask(current_umask); /* convert flags and mode to CreateFile parameters */ switch (flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) { diff --git a/src/win/pipe.c b/src/win/pipe.c index d5102ed5c44..3c8abe1c28c 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -199,7 +199,7 @@ static void close_pipe(uv_pipe_t* pipe) { if (pipe->u.fd == -1) CloseHandle(pipe->handle); else - close(pipe->u.fd); + _close(pipe->u.fd); pipe->u.fd = -1; pipe->handle = INVALID_HANDLE_VALUE; diff --git a/src/win/process.c b/src/win/process.c index 6123ea264ca..50161b14bd0 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -26,7 +26,7 @@ #include #include #include -#include /* alloca */ +#include /* _alloca */ #include "uv.h" #include "internal.h" @@ -511,7 +511,7 @@ WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) { } } target[0] = L'\0'; - wcsrev(start); + _wcsrev(start); *(target++) = L'"'; return target; } @@ -615,8 +615,8 @@ int env_strncmp(const wchar_t* a, int na, const wchar_t* b) { assert(b_eq); nb = b_eq - b; - A = alloca((na+1) * sizeof(wchar_t)); - B = alloca((nb+1) * sizeof(wchar_t)); + A = _alloca((na+1) * sizeof(wchar_t)); + B = _alloca((nb+1) * sizeof(wchar_t)); r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na); assert(r==na); @@ -693,7 +693,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { if (dst_copy == NULL && env_len > 0) { return UV_ENOMEM; } - env_copy = alloca(env_block_count * sizeof(WCHAR*)); + env_copy = _alloca(env_block_count * sizeof(WCHAR*)); ptr = dst_copy; ptr_copy = env_copy; diff --git a/src/win/tty.c b/src/win/tty.c index ac836930d6f..9f8dd698d76 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -695,7 +695,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, DWORD records_left, records_read; uv_buf_t buf; - off_t buf_used; + _off_t buf_used; assert(handle->type == UV_TTY); assert(handle->flags & UV_HANDLE_TTY_READABLE); @@ -2246,7 +2246,7 @@ void uv__tty_close(uv_tty_t* handle) { if (handle->u.fd == -1) CloseHandle(handle->handle); else - close(handle->u.fd); + _close(handle->u.fd); handle->u.fd = -1; handle->handle = INVALID_HANDLE_VALUE; diff --git a/test/run-tests.c b/test/run-tests.c index 97fec52f1d8..17fb0e0cf73 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -25,6 +25,7 @@ #ifdef _WIN32 # include +# define read _read #else # include #endif diff --git a/test/runner-win.c b/test/runner-win.c index 61d6f1431be..6c6e35f7731 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -310,7 +310,7 @@ static int clear_line(void) { COORD coord; DWORD written; - handle = (HANDLE)_get_osfhandle(fileno(stderr)); + handle = (HANDLE)_get_osfhandle(_fileno(stderr)); if (handle == INVALID_HANDLE_VALUE) return -1; diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index 3f159aeb68f..3aacf12596f 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -74,7 +74,8 @@ static void touch_file(const char* name, unsigned int size) { int r; unsigned int i; - r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT | O_TRUNC, + r = uv_fs_open(NULL, &req, name, + UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_TRUNC, S_IWUSR | S_IRUSR, NULL); uv_fs_req_cleanup(&req); ASSERT_GE(r, 0); diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 7b5c0d8eb3d..0ef51180dbd 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -80,7 +80,9 @@ static void create_file(const char* name) { uv_file file; uv_fs_t req; - r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); + r = uv_fs_open(NULL, &req, name, UV_FS_O_WRONLY | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); file = r; uv_fs_req_cleanup(&req); @@ -95,7 +97,7 @@ static void touch_file(const char* name) { uv_fs_t req; uv_buf_t buf; - r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &req, name, UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); file = r; uv_fs_req_cleanup(&req); diff --git a/test/test-fs-readdir.c b/test/test-fs-readdir.c index b6b5b7ff2c1..0f2b4afa58c 100644 --- a/test/test-fs-readdir.c +++ b/test/test-fs-readdir.c @@ -359,7 +359,7 @@ TEST_IMPL(fs_readdir_non_empty_dir) { r = uv_fs_open(uv_default_loop(), &create_req, "test_dir/file1", - O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); uv_fs_req_cleanup(&create_req); @@ -373,7 +373,7 @@ TEST_IMPL(fs_readdir_non_empty_dir) { r = uv_fs_open(uv_default_loop(), &create_req, "test_dir/file2", - O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); uv_fs_req_cleanup(&create_req); diff --git a/test/test-fs.c b/test/test-fs.c index ab8a9e07cce..fe78117bbed 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -51,6 +51,9 @@ # ifndef lseek # define lseek _lseek # endif +# define S_IFDIR _S_IFDIR +# define S_IFCHR _S_IFCHR +# define S_IFREG _S_IFREG #endif #define TOO_LONG_NAME_LENGTH 65536 @@ -227,7 +230,7 @@ static void realpath_cb(uv_fs_t* req) { uv_cwd(test_file_abs_buf, &test_file_abs_size); #ifdef _WIN32 strcat(test_file_abs_buf, "\\test_file"); - ASSERT_OK(stricmp(req->ptr, test_file_abs_buf)); + ASSERT_OK(_stricmp(req->ptr, test_file_abs_buf)); #else strcat(test_file_abs_buf, "/test_file"); ASSERT_OK(strcmp(req->ptr, test_file_abs_buf)); @@ -718,12 +721,13 @@ TEST_IMPL(fs_file_noent) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, "does_not_exist", O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &req, "does_not_exist", UV_FS_O_RDONLY, 0, NULL); ASSERT_EQ(r, UV_ENOENT); ASSERT_EQ(req.result, UV_ENOENT); uv_fs_req_cleanup(&req); - r = uv_fs_open(loop, &req, "does_not_exist", O_RDONLY, 0, open_noent_cb); + r = uv_fs_open(loop, &req, "does_not_exist", UV_FS_O_RDONLY, 0, + open_noent_cb); ASSERT_OK(r); ASSERT_OK(open_cb_count); @@ -746,12 +750,12 @@ TEST_IMPL(fs_file_nametoolong) { memset(name, 'a', TOO_LONG_NAME_LENGTH); name[TOO_LONG_NAME_LENGTH] = 0; - r = uv_fs_open(NULL, &req, name, O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &req, name, UV_FS_O_RDONLY, 0, NULL); ASSERT_EQ(r, UV_ENAMETOOLONG); ASSERT_EQ(req.result, UV_ENAMETOOLONG); uv_fs_req_cleanup(&req); - r = uv_fs_open(loop, &req, name, O_RDONLY, 0, open_nametoolong_cb); + r = uv_fs_open(loop, &req, name, UV_FS_O_RDONLY, 0, open_nametoolong_cb); ASSERT_OK(r); ASSERT_OK(open_cb_count); @@ -786,12 +790,12 @@ TEST_IMPL(fs_file_loop) { ASSERT_OK(r); uv_fs_req_cleanup(&req); - r = uv_fs_open(NULL, &req, "test_symlink", O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &req, "test_symlink", UV_FS_O_RDONLY, 0, NULL); ASSERT_EQ(r, UV_ELOOP); ASSERT_EQ(req.result, UV_ELOOP); uv_fs_req_cleanup(&req); - r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, open_loop_cb); + r = uv_fs_open(loop, &req, "test_symlink", UV_FS_O_RDONLY, 0, open_loop_cb); ASSERT_OK(r); ASSERT_OK(open_cb_count); @@ -918,7 +922,7 @@ TEST_IMPL(fs_file_async) { loop = uv_default_loop(); - r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT, + r = uv_fs_open(loop, &open_req1, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IRUSR | S_IWUSR, create_cb); ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); @@ -938,7 +942,7 @@ TEST_IMPL(fs_file_async) { ASSERT_EQ(1, close_cb_count); ASSERT_EQ(1, rename_cb_count); - r = uv_fs_open(loop, &open_req1, "test_file2", O_RDWR, 0, open_cb); + r = uv_fs_open(loop, &open_req1, "test_file2", UV_FS_O_RDWR, 0, open_cb); ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); @@ -950,7 +954,7 @@ TEST_IMPL(fs_file_async) { ASSERT_EQ(1, write_cb_count); ASSERT_EQ(1, ftruncate_cb_count); - r = uv_fs_open(loop, &open_req1, "test_file2", O_RDONLY, 0, open_cb); + r = uv_fs_open(loop, &open_req1, "test_file2", UV_FS_O_RDONLY, 0, open_cb); ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); @@ -982,7 +986,8 @@ static void fs_file_sync(int add_flags) { loop = uv_default_loop(); r = uv_fs_open(loop, &open_req1, "test_file", - O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); + UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -998,7 +1003,8 @@ static void fs_file_sync(int add_flags) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR | add_flags, 0, NULL); + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDWR | add_flags, 0, + NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -1025,7 +1031,7 @@ static void fs_file_sync(int add_flags) { ASSERT_OK(rename_req.result); uv_fs_req_cleanup(&rename_req); - r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY | add_flags, 0, + r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_RDONLY | add_flags, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -1071,7 +1077,8 @@ static void fs_file_write_null_buffer(int add_flags) { loop = uv_default_loop(); r = uv_fs_open(NULL, &open_req1, "test_file", - O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); + UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -1116,7 +1123,8 @@ TEST_IMPL(fs_async_dir) { ASSERT_EQ(1, mkdir_cb_count); /* Create 2 files synchronously. */ - r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req1, "test_dir/file1", + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); @@ -1124,7 +1132,8 @@ TEST_IMPL(fs_async_dir) { ASSERT_OK(r); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req1, "test_dir/file2", + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); @@ -1193,7 +1202,7 @@ TEST_IMPL(fs_async_dir) { } -static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) { +static int test_sendfile(void (*setup)(int), uv_fs_cb cb, size_t expected_size) { int f, r; struct stat s1, s2; uv_fs_t req; @@ -1205,7 +1214,7 @@ static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) { unlink("test_file"); unlink("test_file2"); - f = open("test_file", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR); + f = open("test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR); ASSERT_NE(f, -1); if (setup != NULL) @@ -1215,12 +1224,12 @@ static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) { ASSERT_OK(r); /* Test starts here. */ - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); - r = uv_fs_open(NULL, &open_req2, "test_file2", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req2, "test_file2", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req2.result, 0); @@ -1248,7 +1257,7 @@ static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) { if (expected_size > 0) { ASSERT_UINT64_EQ(s1.st_size, s2.st_size + 1); - r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -1364,7 +1373,7 @@ TEST_IMPL(fs_mkstemp) { uv_fs_close(NULL, &req, mkstemp_req2.result, NULL); uv_fs_req_cleanup(&req); - fd = uv_fs_open(NULL, &req, mkstemp_req1.path , O_RDONLY, 0, NULL); + fd = uv_fs_open(NULL, &req, mkstemp_req1.path, UV_FS_O_RDONLY, 0, NULL); ASSERT_GE(fd, 0); uv_fs_req_cleanup(&req); @@ -1410,7 +1419,7 @@ TEST_IMPL(fs_fstat) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -1617,7 +1626,7 @@ TEST_IMPL(fs_access) { access_cb_count = 0; /* reset for the next test */ /* Create file */ - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -1678,7 +1687,7 @@ TEST_IMPL(fs_chmod) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -1777,9 +1786,7 @@ TEST_IMPL(fs_unlink_readonly) { loop = uv_default_loop(); r = uv_fs_open(NULL, - &req, - "test_file", - O_RDWR | O_CREAT, + &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -1836,9 +1843,7 @@ TEST_IMPL(fs_unlink_archive_readonly) { loop = uv_default_loop(); r = uv_fs_open(NULL, - &req, - "test_file", - O_RDWR | O_CREAT, + &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -1894,7 +1899,7 @@ TEST_IMPL(fs_chown) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -1989,7 +1994,7 @@ TEST_IMPL(fs_link) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -2010,7 +2015,7 @@ TEST_IMPL(fs_link) { ASSERT_OK(req.result); uv_fs_req_cleanup(&req); - r = uv_fs_open(NULL, &req, "test_file_link", O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &req, "test_file_link", UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); link = req.result; @@ -2031,7 +2036,7 @@ TEST_IMPL(fs_link) { uv_run(loop, UV_RUN_DEFAULT); ASSERT_EQ(1, link_cb_count); - r = uv_fs_open(NULL, &req, "test_file_link2", O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &req, "test_file_link2", UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); link = req.result; @@ -2090,7 +2095,7 @@ TEST_IMPL(fs_readlink) { /* Setup */ /* Create a non-symlink file */ - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -2162,7 +2167,7 @@ TEST_IMPL(fs_symlink) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT, + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); @@ -2200,7 +2205,7 @@ TEST_IMPL(fs_symlink) { ASSERT_OK(req.result); uv_fs_req_cleanup(&req); - r = uv_fs_open(NULL, &req, "test_file_symlink", O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &req, "test_file_symlink", UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); link = req.result; @@ -2236,7 +2241,7 @@ TEST_IMPL(fs_symlink) { r = uv_fs_realpath(NULL, &req, "test_file_symlink_symlink", NULL); ASSERT_OK(r); #ifdef _WIN32 - ASSERT_OK(stricmp(req.ptr, test_file_abs_buf)); + ASSERT_OK(_stricmp(req.ptr, test_file_abs_buf)); #else ASSERT_OK(strcmp(req.ptr, test_file_abs_buf)); #endif @@ -2253,7 +2258,7 @@ TEST_IMPL(fs_symlink) { uv_run(loop, UV_RUN_DEFAULT); ASSERT_EQ(1, symlink_cb_count); - r = uv_fs_open(NULL, &req, "test_file_symlink2", O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &req, "test_file_symlink2", UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); link = req.result; @@ -2386,13 +2391,14 @@ int test_symlink_dir_impl(int type) { ASSERT_OK(r); #ifdef _WIN32 ASSERT_EQ(strlen(req.ptr), test_dir_abs_size - 5); - ASSERT_OK(strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5)); + ASSERT_OK(_strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5)); #else ASSERT_OK(strcmp(req.ptr, test_dir_abs_buf)); #endif uv_fs_req_cleanup(&req); - r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req1, "test_dir/file1", + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); @@ -2400,7 +2406,8 @@ int test_symlink_dir_impl(int type) { ASSERT_OK(r); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req1, "test_dir/file2", + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); uv_fs_req_cleanup(&open_req1); @@ -2622,7 +2629,9 @@ TEST_IMPL(fs_utime) { /* Setup. */ loop = uv_default_loop(); unlink(path); - r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); + r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); uv_fs_req_cleanup(&req); @@ -2666,7 +2675,9 @@ TEST_IMPL(fs_utime_round) { loop = uv_default_loop(); unlink(path); - r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); + r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); uv_fs_req_cleanup(&req); @@ -2743,7 +2754,9 @@ TEST_IMPL(fs_futime) { /* Setup. */ loop = uv_default_loop(); unlink(path); - r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); + r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); uv_fs_req_cleanup(&req); @@ -2751,7 +2764,7 @@ TEST_IMPL(fs_futime) { atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */ - r = uv_fs_open(NULL, &req, path, O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); file = req.result; /* FIXME probably not how it's supposed to be used */ @@ -2803,7 +2816,9 @@ TEST_IMPL(fs_lutime) { /* Setup */ loop = uv_default_loop(); unlink(path); - r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL); + r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); uv_fs_req_cleanup(&req); @@ -2999,7 +3014,7 @@ TEST_IMPL(fs_open_dir) { path = "."; loop = uv_default_loop(); - r = uv_fs_open(NULL, &req, path, O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &req, path, UV_FS_O_RDONLY, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); ASSERT_NULL(req.ptr); @@ -3009,7 +3024,7 @@ TEST_IMPL(fs_open_dir) { r = uv_fs_close(NULL, &req, file, NULL); ASSERT_OK(r); - r = uv_fs_open(loop, &req, path, O_RDONLY, 0, open_cb_simple); + r = uv_fs_open(loop, &req, path, UV_FS_O_RDONLY, 0, open_cb_simple); ASSERT_OK(r); ASSERT_OK(open_cb_count); @@ -3030,7 +3045,8 @@ static void fs_file_open_append(int add_flags) { loop = uv_default_loop(); r = uv_fs_open(NULL, &open_req1, "test_file", - O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); + UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -3047,7 +3063,7 @@ static void fs_file_open_append(int add_flags) { uv_fs_req_cleanup(&close_req); r = uv_fs_open(NULL, &open_req1, "test_file", - O_RDWR | O_APPEND | add_flags, 0, NULL); + UV_FS_O_RDWR | UV_FS_O_APPEND | add_flags, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -3063,7 +3079,7 @@ static void fs_file_open_append(int add_flags) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -3105,7 +3121,7 @@ TEST_IMPL(fs_rename_to_existing_file) { loop = uv_default_loop(); - r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -3122,7 +3138,7 @@ TEST_IMPL(fs_rename_to_existing_file) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_file2", O_WRONLY | O_CREAT, + r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -3138,7 +3154,7 @@ TEST_IMPL(fs_rename_to_existing_file) { ASSERT_OK(rename_req.result); uv_fs_req_cleanup(&rename_req); - r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_RDONLY, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -3171,7 +3187,7 @@ static void fs_read_bufs(int add_flags) { ASSERT_LE(0, uv_fs_open(NULL, &open_req1, "test/fixtures/lorem_ipsum.txt", - O_RDONLY | add_flags, 0, NULL)); + UV_FS_O_RDONLY | add_flags, 0, NULL)); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -3235,7 +3251,8 @@ static void fs_read_file_eof(int add_flags) { loop = uv_default_loop(); r = uv_fs_open(NULL, &open_req1, "test_file", - O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); + UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -3251,7 +3268,7 @@ static void fs_read_file_eof(int add_flags) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0, + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -3299,7 +3316,8 @@ static void fs_write_multiple_bufs(int add_flags) { loop = uv_default_loop(); r = uv_fs_open(NULL, &open_req1, "test_file", - O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); + UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, + NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -3316,7 +3334,7 @@ static void fs_write_multiple_bufs(int add_flags) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0, + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -3405,7 +3423,7 @@ static void fs_write_alotof_bufs(int add_flags) { r = uv_fs_open(NULL, &open_req1, "test_file", - O_RDWR | O_CREAT | add_flags, + UV_FS_O_RDWR | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -3439,7 +3457,7 @@ static void fs_write_alotof_bufs(int add_flags) { ASSERT_OK(close_req.result); uv_fs_req_cleanup(&close_req); - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0, + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); @@ -3518,7 +3536,7 @@ static void fs_write_alotof_bufs_with_offset(int add_flags) { r = uv_fs_open(NULL, &open_req1, "test_file", - O_RDWR | O_CREAT | add_flags, + UV_FS_O_RDWR | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -3904,9 +3922,7 @@ TEST_IMPL(get_osfhandle_valid_handle) { loop = uv_default_loop(); r = uv_fs_open(NULL, - &open_req1, - "test_file", - O_RDWR | O_CREAT, + &open_req1, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -3945,7 +3961,7 @@ TEST_IMPL(open_osfhandle_valid_handle) { r = uv_fs_open(NULL, &open_req1, "test_file", - O_RDWR | O_CREAT, + UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -3986,9 +4002,7 @@ TEST_IMPL(fs_file_pos_after_op_with_offset) { loop = uv_default_loop(); r = uv_fs_open(loop, - &open_req1, - "test_file", - O_RDWR | O_CREAT, + &open_req1, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GT(r, 0); @@ -4060,7 +4074,7 @@ static void fs_file_pos_close_check(const char *contents, int size) { uv_fs_req_cleanup(&close_req); /* Confirm file contents */ - r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(open_req1.result, 0); uv_fs_req_cleanup(&open_req1); @@ -4088,7 +4102,7 @@ static void fs_file_pos_write(int add_flags) { r = uv_fs_open(NULL, &open_req1, "test_file", - O_TRUNC | O_CREAT | O_RDWR | add_flags, + UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_RDWR | add_flags, S_IWUSR | S_IRUSR, NULL); ASSERT_GT(r, 0); @@ -4126,7 +4140,7 @@ static void fs_file_pos_append(int add_flags) { r = uv_fs_open(NULL, &open_req1, "test_file", - O_APPEND | O_CREAT | O_RDWR | add_flags, + UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR | add_flags, S_IWUSR | S_IRUSR, NULL); ASSERT_GT(r, 0); @@ -4273,7 +4287,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) { r = uv_fs_open(NULL, &open_req1, "test_file", - O_RDWR | O_CREAT | UV_FS_O_EXLOCK, + UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_EXLOCK, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -4282,8 +4296,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) { r = uv_fs_open(NULL, &open_req2, - "test_file", - O_RDONLY | UV_FS_O_EXLOCK, + "test_file", UV_FS_O_RDONLY | UV_FS_O_EXLOCK, S_IWUSR | S_IRUSR, NULL); ASSERT_LT(r, 0); @@ -4297,8 +4310,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) { r = uv_fs_open(NULL, &open_req2, - "test_file", - O_RDONLY | UV_FS_O_EXLOCK, + "test_file", UV_FS_O_RDONLY | UV_FS_O_EXLOCK, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -4405,7 +4417,7 @@ TEST_IMPL(fs_open_readonly_acl) { r = uv_fs_open(loop, &open_req1, "test_file_icacls", - O_RDONLY | O_CREAT, + UV_FS_O_RDONLY | UV_FS_O_CREAT, S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -4428,7 +4440,8 @@ TEST_IMPL(fs_open_readonly_acl) { } /* Try opening the file */ - r = uv_fs_open(NULL, &open_req1, "test_file_icacls", O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &open_req1, "test_file_icacls", UV_FS_O_RDONLY, 0, + NULL); if (r < 0) { goto acl_cleanup; } @@ -4461,9 +4474,7 @@ TEST_IMPL(fs_fchmod_archive_readonly) { /* Setup*/ unlink("test_file"); r = uv_fs_open(NULL, - &req, - "test_file", - O_WRONLY | O_CREAT, + &req, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT_GE(r, 0); @@ -4478,7 +4489,7 @@ TEST_IMPL(fs_fchmod_archive_readonly) { ASSERT(r); check_permission("test_file", 0400); /* Try fchmod */ - r = uv_fs_open(NULL, &req, "test_file", O_RDONLY, 0, NULL); + r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDONLY, 0, NULL); ASSERT_GE(r, 0); ASSERT_GE(req.result, 0); file = req.result; diff --git a/test/test-getters-setters.c b/test/test-getters-setters.c index e4c6717d3bc..3b9e89e1fe0 100644 --- a/test/test-getters-setters.c +++ b/test/test-getters-setters.c @@ -24,6 +24,10 @@ #include #include +#ifdef _WIN32 +# define S_IFDIR _S_IFDIR +#endif + int cookie1; int cookie2; int cookie3; diff --git a/test/test-metrics.c b/test/test-metrics.c index c7c73aa53d7..361fcef5ced 100644 --- a/test/test-metrics.c +++ b/test/test-metrics.c @@ -217,7 +217,7 @@ static void prepare_cb(uv_prepare_t* handle) { ASSERT_OK(uv_fs_open(uv_default_loop(), &fs_reqs.open_req, "test_file", - O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR, + UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IRUSR | S_IWUSR, create_cb)); } @@ -329,9 +329,7 @@ TEST_IMPL(metrics_pool_events) { pool_events_counter = 0; fd = uv_fs_open(NULL, - &open_req, - "test_file", - O_WRONLY | O_CREAT, + &open_req, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IRUSR | S_IWUSR, NULL); ASSERT_GT(fd, 0); diff --git a/test/test-poll.c b/test/test-poll.c index f5a30e9a6b2..fcd644f2c25 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -23,6 +23,7 @@ #ifdef _WIN32 # include +# define close _close #else # include # include @@ -638,9 +639,9 @@ TEST_IMPL(poll_bad_fdtype) { int fd; #if defined(_WIN32) - fd = open("test/fixtures/empty_file", O_RDONLY); + fd = _open("test/fixtures/empty_file", UV_FS_O_RDONLY); #else - fd = open(".", O_RDONLY); + fd = open(".", UV_FS_O_RDONLY); #endif ASSERT_NE(fd, -1); ASSERT_NE(0, uv_poll_init(uv_default_loop(), &poll_handle, fd)); diff --git a/test/test-spawn.c b/test/test-spawn.c index bbb7cb498ba..33552717fc3 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -32,6 +32,9 @@ # include # include typedef BOOL (WINAPI *sCompareObjectHandles)(_In_ HANDLE, _In_ HANDLE); +# define unlink _unlink +# define putenv _putenv +# define close _close #else # include # include @@ -322,7 +325,7 @@ TEST_IMPL(spawn_stdout_to_file) { init_process_options("spawn_helper2", exit_cb); - r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR, + r = uv_fs_open(NULL, &fs_req, "stdout_file", UV_FS_O_CREAT | UV_FS_O_RDWR, S_IRUSR | S_IWUSR, NULL); ASSERT_NE(r, -1); uv_fs_req_cleanup(&fs_req); @@ -376,7 +379,7 @@ TEST_IMPL(spawn_stdout_and_stderr_to_file) { init_process_options("spawn_helper6", exit_cb); - r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR, + r = uv_fs_open(NULL, &fs_req, "stdout_file", UV_FS_O_CREAT | UV_FS_O_RDWR, S_IRUSR | S_IWUSR, NULL); ASSERT_NE(r, -1); uv_fs_req_cleanup(&fs_req); @@ -1621,7 +1624,7 @@ TEST_IMPL(spawn_fs_open) { const char dev_null[] = "/dev/null"; #endif - r = uv_fs_open(NULL, &fs_req, dev_null, O_RDWR, 0, NULL); + r = uv_fs_open(NULL, &fs_req, dev_null, UV_FS_O_RDWR, 0, NULL); ASSERT_NE(r, -1); fd = uv_get_osfhandle((uv_file) fs_req.result); uv_fs_req_cleanup(&fs_req); diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index b758ac4f6b6..544fbbc348a 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -22,6 +22,10 @@ #include "uv.h" #include "task.h" +#ifdef _WIN32 +# define putenv _putenv +#endif + #define INIT_CANCEL_INFO(ci, what) \ do { \ (ci)->reqs = (what); \ From 51a22f60d6f41a92b68def1f048e53b593037d11 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Fri, 22 Dec 2023 08:40:50 -0300 Subject: [PATCH 484/713] unix,win: fix busy loop with zero timeout timers (#4250) Calling `uv_timer_start(h, cb, 0, 0)` from a timer callback resulted in the timer running immediately because it was inserted at the front of the timer heap. If the callback did that every time, libuv would effectively busy-loop in `uv__run_timers()` and never make forward progress. Work around that by collecting all expired timers into a queue and only running their callback afterwards. Fixes: https://github.com/libuv/libuv/issues/4245 Co-authored-by: Ben Noordhuis --- include/uv/unix.h | 5 ++++- include/uv/win.h | 5 ++++- src/timer.c | 45 +++++++++++++++++++++++++++++++-------------- test/test-list.h | 2 ++ test/test-timer.c | 26 ++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/include/uv/unix.h b/include/uv/unix.h index 09f88a56742..538f98b6c5d 100644 --- a/include/uv/unix.h +++ b/include/uv/unix.h @@ -328,7 +328,10 @@ typedef struct { #define UV_TIMER_PRIVATE_FIELDS \ uv_timer_cb timer_cb; \ - void* heap_node[3]; \ + union { \ + void* heap[3]; \ + struct uv__queue queue; \ + } node; \ uint64_t timeout; \ uint64_t repeat; \ uint64_t start_id; diff --git a/include/uv/win.h b/include/uv/win.h index 6f8c47298e4..ad7b3e9a38f 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -550,7 +550,10 @@ typedef struct { unsigned char events; #define UV_TIMER_PRIVATE_FIELDS \ - void* heap_node[3]; \ + union { \ + void* heap[3]; \ + struct uv__queue queue; \ + } node; \ int unused; \ uint64_t timeout; \ uint64_t repeat; \ diff --git a/src/timer.c b/src/timer.c index bc680e71a9e..b57d642776b 100644 --- a/src/timer.c +++ b/src/timer.c @@ -40,8 +40,8 @@ static int timer_less_than(const struct heap_node* ha, const uv_timer_t* a; const uv_timer_t* b; - a = container_of(ha, uv_timer_t, heap_node); - b = container_of(hb, uv_timer_t, heap_node); + a = container_of(ha, uv_timer_t, node.heap); + b = container_of(hb, uv_timer_t, node.heap); if (a->timeout < b->timeout) return 1; @@ -60,6 +60,7 @@ int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { handle->timer_cb = NULL; handle->timeout = 0; handle->repeat = 0; + uv__queue_init(&handle->node.queue); return 0; } @@ -73,8 +74,7 @@ int uv_timer_start(uv_timer_t* handle, if (uv__is_closing(handle) || cb == NULL) return UV_EINVAL; - if (uv__is_active(handle)) - uv_timer_stop(handle); + uv_timer_stop(handle); clamped_timeout = handle->loop->time + timeout; if (clamped_timeout < timeout) @@ -87,23 +87,27 @@ int uv_timer_start(uv_timer_t* handle, handle->start_id = handle->loop->timer_counter++; heap_insert(timer_heap(handle->loop), - (struct heap_node*) &handle->heap_node, + (struct heap_node*) &handle->node.heap, timer_less_than); uv__handle_start(handle); return 0; } - -int uv_timer_stop(uv_timer_t* handle) { - if (!uv__is_active(handle)) - return 0; - +static void timer_stop(uv_timer_t* handle) { heap_remove(timer_heap(handle->loop), - (struct heap_node*) &handle->heap_node, + (struct heap_node*) &handle->node.heap, timer_less_than); uv__handle_stop(handle); + uv__queue_init(&handle->node.queue); +} + +int uv_timer_stop(uv_timer_t* handle) { + if (uv__is_active(handle)) + timer_stop(handle); + else + uv__queue_remove(&handle->node.queue); return 0; } @@ -148,7 +152,7 @@ int uv__next_timeout(const uv_loop_t* loop) { if (heap_node == NULL) return -1; /* block indefinitely */ - handle = container_of(heap_node, uv_timer_t, heap_node); + handle = container_of(heap_node, uv_timer_t, node.heap); if (handle->timeout <= loop->time) return 0; @@ -163,17 +167,30 @@ int uv__next_timeout(const uv_loop_t* loop) { void uv__run_timers(uv_loop_t* loop) { struct heap_node* heap_node; uv_timer_t* handle; + struct uv__queue* queue_node; + struct uv__queue ready_queue; + + uv__queue_init(&ready_queue); for (;;) { heap_node = heap_min(timer_heap(loop)); if (heap_node == NULL) break; - handle = container_of(heap_node, uv_timer_t, heap_node); + handle = container_of(heap_node, uv_timer_t, node.heap); if (handle->timeout > loop->time) break; - uv_timer_stop(handle); + timer_stop(handle); + uv__queue_insert_tail(&ready_queue, &handle->node.queue); + } + + while (!uv__queue_empty(&ready_queue)) { + queue_node = uv__queue_head(&ready_queue); + uv__queue_remove(queue_node); + uv__queue_init(queue_node); + handle = container_of(queue_node, uv_timer_t, node.queue); + uv_timer_again(handle); handle->timer_cb(handle); } diff --git a/test/test-list.h b/test/test-list.h index f042bc29f7c..e97b941f6dd 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -227,6 +227,7 @@ TEST_DECLARE (timer_init) TEST_DECLARE (timer_again) TEST_DECLARE (timer_start_twice) TEST_DECLARE (timer_order) +TEST_DECLARE (timer_zero_timeout) TEST_DECLARE (timer_huge_timeout) TEST_DECLARE (timer_huge_repeat) TEST_DECLARE (timer_run_once) @@ -849,6 +850,7 @@ TASK_LIST_START TEST_ENTRY (timer_again) TEST_ENTRY (timer_start_twice) TEST_ENTRY (timer_order) + TEST_ENTRY (timer_zero_timeout) TEST_ENTRY (timer_huge_timeout) TEST_ENTRY (timer_huge_repeat) TEST_ENTRY (timer_run_once) diff --git a/test/test-timer.c b/test/test-timer.c index d889e707731..641d3a90775 100644 --- a/test/test-timer.c +++ b/test/test-timer.c @@ -31,6 +31,7 @@ static int repeat_cb_called = 0; static int repeat_close_cb_called = 0; static int order_cb_called = 0; static int timer_check_double_call_called = 0; +static int zero_timeout_cb_calls = 0; static uint64_t start_time; static uv_timer_t tiny_timer; static uv_timer_t huge_timer1; @@ -242,6 +243,31 @@ TEST_IMPL(timer_order) { } +static void zero_timeout_cb(uv_timer_t* handle) { + ASSERT_OK(uv_timer_start(handle, zero_timeout_cb, 0, 0)); + uv_stop(handle->loop); + zero_timeout_cb_calls++; +} + + +TEST_IMPL(timer_zero_timeout) { + uv_timer_t timer; + uv_loop_t* loop; + + loop = uv_default_loop(); + ASSERT_OK(uv_timer_init(loop, &timer)); + ASSERT_OK(uv_timer_start(&timer, zero_timeout_cb, 0, 0)); + ASSERT_EQ(1, uv_run(loop, UV_RUN_DEFAULT)); /* because of uv_stop() */ + ASSERT_EQ(1, zero_timeout_cb_calls); + uv_close((uv_handle_t*) &timer, NULL); + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + ASSERT_EQ(1, zero_timeout_cb_calls); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + + static void tiny_timer_cb(uv_timer_t* handle) { ASSERT_PTR_EQ(handle, &tiny_timer); uv_close((uv_handle_t*) &tiny_timer, NULL); From 8861a97efac54a9ab17e8174cc826a0ca1804e41 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Fri, 22 Dec 2023 23:58:49 +0000 Subject: [PATCH 485/713] aix,ibmi: use uv_interface_addresses instead of getifaddrs (#4222) AIX and IBM i don't have getifaddrs but we do have code in `uv_interface_addresses` to get the interface addresses. Refs: https://github.com/libuv/libuv/issues/4117 --- src/unix/tcp.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index f455c53f1bd..a4ef71b55d6 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -220,14 +220,32 @@ static int uv__is_ipv6_link_local(const struct sockaddr* addr) { static int uv__ipv6_link_local_scope_id(void) { -/* disable link local on AIX & PASE for now */ + struct sockaddr_in6* a6; + int rv; #if defined(_AIX) - return 0; + /* AIX & IBM i do not have ifaddrs + * so fallback to use uv_interface_addresses */ + uv_interface_address_t* interfaces; + uv_interface_address_t* ifa; + int count, i; + + if (uv_interface_addresses(&interfaces, &count)) + return 0; + + rv = 0; + + for (ifa = interfaces; ifa != &interfaces[count]; ifa++) { + if (uv__is_ipv6_link_local((struct sockaddr*) &ifa->address)) { + rv = ifa->address.address6.sin6_scope_id; + break; + } + } + + uv_free_interface_addresses(interfaces, count); + #else - struct sockaddr_in6* a6; struct ifaddrs* ifa; struct ifaddrs* p; - int rv; if (getifaddrs(&ifa)) return 0; @@ -244,8 +262,9 @@ static int uv__ipv6_link_local_scope_id(void) { } freeifaddrs(ifa); +#endif /* defined(_AIX) */ + return rv; -#endif } From 1dd0ab13154ccad38839807fe4909469f7164e25 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 25 Dec 2023 23:35:14 +0100 Subject: [PATCH 486/713] linux: fix bind/connect for abstract sockets (#4266) The `\0` character has no special significance in abstract sockets, so the addrlen field in both `bind()` and `connect()` should take that into account. --- src/unix/pipe.c | 17 +++++++++++++---- test/test-pipe-getsockname.c | 7 ++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index bb2806f579a..fca364426f8 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -66,6 +66,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, char* pipe_fname; int sockfd; int err; + socklen_t addrlen; pipe_fname = NULL; @@ -100,12 +101,15 @@ int uv_pipe_bind2(uv_pipe_t* handle, * We unlink the file later but abstract sockets disappear * automatically since they're not real file system entities. */ - if (*name != '\0') { + if (*name == '\0') { + addrlen = offsetof(struct sockaddr_un, sun_path) + namelen; + } else { pipe_fname = uv__malloc(namelen + 1); if (pipe_fname == NULL) return UV_ENOMEM; memcpy(pipe_fname, name, namelen); pipe_fname[namelen] = '\0'; + addrlen = sizeof saddr; } err = uv__socket(AF_UNIX, SOCK_STREAM, 0); @@ -117,7 +121,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, memcpy(&saddr.sun_path, name, namelen); saddr.sun_family = AF_UNIX; - if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { + if (bind(sockfd, (struct sockaddr*)&saddr, addrlen)) { err = UV__ERR(errno); /* Convert ENOENT to EACCES for compatibility with Windows. */ if (err == UV_ENOENT) @@ -251,6 +255,7 @@ int uv_pipe_connect2(uv_connect_t* req, int new_sock; int err; int r; + socklen_t addrlen; if (flags & ~UV_PIPE_NO_TRUNCATE) return UV_EINVAL; @@ -285,9 +290,13 @@ int uv_pipe_connect2(uv_connect_t* req, memcpy(&saddr.sun_path, name, namelen); saddr.sun_family = AF_UNIX; + if (*name == '\0') + addrlen = offsetof(struct sockaddr_un, sun_path) + namelen; + else + addrlen = sizeof saddr; + do { - r = connect(uv__stream_fd(handle), - (struct sockaddr*)&saddr, sizeof saddr); + r = connect(uv__stream_fd(handle), (struct sockaddr*)&saddr, addrlen); } while (r == -1 && errno == EINTR); diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index bac723c6c07..d76b6ad4917 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -60,8 +60,8 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) { if (*buf == '\0') { /* Linux abstract socket. */ const char expected[] = "\0" TEST_PIPENAME; - ASSERT_GE(len, sizeof(expected)); - ASSERT_MEM_EQ(buf, expected, sizeof(expected)); + ASSERT_EQ(len, sizeof(expected) - 1); + ASSERT_MEM_EQ(buf, expected, len); } else { ASSERT_NE(0, buf[len - 1]); ASSERT_MEM_EQ(buf, TEST_PIPENAME, len); @@ -191,7 +191,8 @@ TEST_IMPL(pipe_getsockname_abstract) { ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0)); ASSERT_OK(uv_pipe_bind2(&pipe_server, name, sizeof(name) - 1, 0)); ASSERT_OK(uv_pipe_getsockname(&pipe_server, buf, &buflen)); - ASSERT_MEM_EQ(name, buf, sizeof(name)); + ASSERT_UINT64_EQ(sizeof(name) - 1, buflen); + ASSERT_MEM_EQ(name, buf, buflen); ASSERT_OK(uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb)); From 64bd28f5ba86a9c85fcbcd10a52811369925fc69 Mon Sep 17 00:00:00 2001 From: Trevor Flynn Date: Fri, 5 Jan 2024 00:34:33 -0900 Subject: [PATCH 487/713] win: replace c99 comments with c89 comments (#4270) --- include/uv/win.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uv/win.h b/include/uv/win.h index ad7b3e9a38f..f4adaa216c6 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -45,7 +45,7 @@ typedef struct pollfd { #endif #include -// Disable the typedef in mstcpip.h of MinGW. +/* Disable the typedef in mstcpip.h of MinGW. */ #define _TCP_INITIAL_RTO_PARAMETERS _TCP_INITIAL_RTO_PARAMETERS__AVOID #define TCP_INITIAL_RTO_PARAMETERS TCP_INITIAL_RTO_PARAMETERS__AVOID #define PTCP_INITIAL_RTO_PARAMETERS PTCP_INITIAL_RTO_PARAMETERS__AVOID @@ -70,7 +70,7 @@ typedef struct pollfd { # define S_IFLNK 0xA000 #endif -// Define missing in Windows Kit Include\{VERSION}\ucrt\sys\stat.h +/* Define missing in Windows Kit Include\{VERSION}\ucrt\sys\stat.h */ #if defined(_CRT_INTERNAL_NONSTDC_NAMES) && _CRT_INTERNAL_NONSTDC_NAMES && !defined(S_IFIFO) # define S_IFIFO _S_IFIFO #endif From e72a91e0636f0dc68ee8518786d8776270cd1dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Fri, 5 Jan 2024 04:38:15 -0500 Subject: [PATCH 488/713] build: add .cache clangd folder to .gitignore (#4257) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The clangd index, before creating the `compile_commands.json` file will create the indexes under a `.cache` folder. This does not need to be tracked by the repo. Signed-off-by: Juan José Arboleda --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d184d21cb9f..6d396efb49f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ *.VC.db *.VC.opendb core +.cache vgcore.* .buildstamp .dirstamp From a9381cdb03f756cc42307584aeec084fd31fee3d Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Sat, 6 Jan 2024 17:46:47 +0800 Subject: [PATCH 489/713] unix: support full TCP keep-alive on Solaris (#4272) Solaris claimed it supported the TCP-Alives mechanism, but TCP_KEEPIDLE, TCP_KEEPINTVL, and TCP_KEEPCNT were not available on Solaris until the latest version 11.4. Therefore, we need to simulate the TCP-Alives mechanism on other platforms via TCP_KEEPALIVE_THRESHOLD + TCP_KEEPALIVE_ABORT_THRESHOLD. --- src/unix/tcp.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index a4ef71b55d6..31ecf5bd3fb 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -453,26 +453,89 @@ int uv__tcp_nodelay(int fd, int on) { int uv__tcp_keepalive(int fd, int on, unsigned int delay) { + int idle; int intvl; int cnt; + (void) &idle; (void) &intvl; (void) &cnt; - + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) return UV__ERR(errno); if (!on) return 0; + if (delay == 0) + return -1; + + /* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual + * compared to other Unix-like systems. + * Thus, we need to specialize it on Solaris. */ +#ifdef __sun + /* There are two keep-alive mechanisms on Solaris: + * - By default, the first keep-alive probe is sent out after a TCP connection is idle for two hours. + * If the peer does not respond to the probe within eight minutes, the TCP connection is aborted. + * You can alter the interval for sending out the first probe using the socket option TCP_KEEPALIVE_THRESHOLD + * in milliseconds or TCP_KEEPIDLE in seconds. + * The system default is controlled by the TCP ndd parameter tcp_keepalive_interval. The minimum value is ten seconds. + * The maximum is ten days, while the default is two hours. If you receive no response to the probe, + * you can use the TCP_KEEPALIVE_ABORT_THRESHOLD socket option to change the time threshold for aborting a TCP connection. + * The option value is an unsigned integer in milliseconds. The value zero indicates that TCP should never time out and + * abort the connection when probing. The system default is controlled by the TCP ndd parameter tcp_keepalive_abort_interval. + * The default is eight minutes. + * + * - The second implementation is activated if socket option TCP_KEEPINTVL and/or TCP_KEEPCNT are set. + * The time between each consequent probes is set by TCP_KEEPINTVL in seconds. + * The minimum value is ten seconds. The maximum is ten days, while the default is two hours. + * The TCP connection will be aborted after certain amount of probes, which is set by TCP_KEEPCNT, without receiving response. + */ + + idle = delay; + /* Kernel expects at least 10 seconds. */ + if (idle < 10) + idle = 10; + /* Kernel expects at most 10 days. */ + if (idle > 10*24*60*60) + idle = 10*24*60*60; + + /* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris + * until version 11.4, but let's take a chance here. */ +#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT) + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) + return UV__ERR(errno); + intvl = idle/3; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) + return UV__ERR(errno); + cnt = 3; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) + return UV__ERR(errno); + return 0; +#endif + + /* Fall back to the first implementation of tcp-alive mechanism for older Solaris, + * simulate the tcp-alive mechanism on other platforms via `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`. + */ + idle *= 1000; /* kernel expects milliseconds */ + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &idle, sizeof(idle))) + return UV__ERR(errno); + + /* Note that the consequent probes will not be sent at equal intervals on Solaris, + * but will be sent using the exponential backoff algorithm. */ + intvl = idle/3; + cnt = 3; + int time_to_abort = intvl * cnt; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort))) + return UV__ERR(errno); + + return 0; +#endif + #ifdef TCP_KEEPIDLE if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) return UV__ERR(errno); -/* Solaris/SmartOS, if you don't support keep-alive, - * then don't advertise it in your system headers... - */ -/* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */ -#elif defined(TCP_KEEPALIVE) && !defined(__sun) +#elif defined(TCP_KEEPALIVE) if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) return UV__ERR(errno); #endif From 7d092913b37f6211375e0c16fff19e4f9a011b2b Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 7 Jan 2024 11:58:32 +0000 Subject: [PATCH 490/713] freebsd: fix F_KINFO file path handling (#4256) The new F_KINFO flag does not seem to work with directories nor with deleted entries. Fixes: https://github.com/libuv/libuv/issues/4255 --- src/unix/kqueue.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 94ace58680c..d7aa60e77ce 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -488,11 +488,15 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) { * the struct's kf_structsize must be initialised beforehand * whether with the KINFO_FILE_SIZE constant or this way. */ + struct stat statbuf; struct kinfo_file kf; - kf.kf_structsize = sizeof(kf); - if (fcntl(handle->event_watcher.fd, F_KINFO, &kf) == 0) - path = uv__basename_r(kf.kf_path); + if (handle->event_watcher.fd != -1 && + (!uv__fstat(handle->event_watcher.fd, &statbuf) && !(statbuf.st_mode & S_IFDIR))) { + kf.kf_structsize = KINFO_FILE_SIZE; + if (fcntl(handle->event_watcher.fd, F_KINFO, &kf) == 0) + path = uv__basename_r(kf.kf_path); + } #endif handle->cb(handle, path, events, 0); From 160cd5629e4da7e86783873b0777d8a2ca414d39 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 8 Jan 2024 22:25:44 +0100 Subject: [PATCH 491/713] linux: retry fs op if unsupported by io_uring (#4268) Fallback to the threadpool if it returns `EOPNOTSUPP`. Fixes: https://github.com/nodejs/node/issues/50876 --- src/unix/fs.c | 10 ++++++++++ src/unix/internal.h | 1 + src/unix/linux.c | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index 9671f0dda12..3a74350f0e5 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1630,6 +1630,16 @@ static void uv__fs_done(struct uv__work* w, int status) { } +void uv__fs_post(uv_loop_t* loop, uv_fs_t* req) { + uv__req_register(loop, req); + uv__work_submit(loop, + &req->work_req, + UV__WORK_FAST_IO, + uv__fs_work, + uv__fs_done); +} + + int uv_fs_access(uv_loop_t* loop, uv_fs_t* req, const char* path, diff --git a/src/unix/internal.h b/src/unix/internal.h index fe588513603..bcb3be577e5 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -425,6 +425,7 @@ UV_UNUSED(static int uv__stat(const char* path, struct stat* s)) { } #if defined(__linux__) +void uv__fs_post(uv_loop_t* loop, uv_fs_t* req); ssize_t uv__fs_copy_file_range(int fd_in, off_t* off_in, diff --git a/src/unix/linux.c b/src/unix/linux.c index 7402a6fae07..3c1313e7efc 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1155,6 +1155,12 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { uv__req_unregister(loop, req); iou->in_flight--; + /* If the op is not supported by the kernel retry using the thread pool */ + if (e->res == -EOPNOTSUPP) { + uv__fs_post(loop, req); + continue; + } + /* io_uring stores error codes as negative numbers, same as libuv. */ req->result = e->res; From a407b232f06aa2f6d1031bf2d126725a4e9e2a54 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Tue, 9 Jan 2024 10:10:35 +0000 Subject: [PATCH 492/713] freebsd: fix build on non-intel archs (#4276) KINFO_FILE_SIZE is only defined on Intel archs. Fixes: https://github.com/libuv/libuv/issues/4274 --- src/unix/kqueue.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index d7aa60e77ce..4d09edc06a0 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -493,7 +493,13 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) { if (handle->event_watcher.fd != -1 && (!uv__fstat(handle->event_watcher.fd, &statbuf) && !(statbuf.st_mode & S_IFDIR))) { - kf.kf_structsize = KINFO_FILE_SIZE; + /* we are purposely not using KINFO_FILE_SIZE here + * as it is not available on non intl archs + * and here it gives 1392 too on intel. + * anyway, the man page also mentions we can proceed + * this way. + */ + kf.kf_structsize = sizeof(kf); if (fcntl(handle->event_watcher.fd, F_KINFO, &kf) == 0) path = uv__basename_r(kf.kf_path); } From a7cbda92b69947f0a60df58d6d1520c84196476f Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Fri, 12 Jan 2024 18:54:51 +0800 Subject: [PATCH 493/713] unix: optimize uv__tcp_keepalive cpp directives (#4275) Reduce the amount of code being compiled and trim trailing whitespace in passing. --- src/unix/tcp.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 31ecf5bd3fb..799fca77aa5 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -469,12 +469,13 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { if (delay == 0) return -1; - + +#ifdef __sun /* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual * compared to other Unix-like systems. - * Thus, we need to specialize it on Solaris. */ -#ifdef __sun - /* There are two keep-alive mechanisms on Solaris: + * Thus, we need to specialize it on Solaris. + * + * There are two keep-alive mechanisms on Solaris: * - By default, the first keep-alive probe is sent out after a TCP connection is idle for two hours. * If the peer does not respond to the probe within eight minutes, the TCP connection is aborted. * You can alter the interval for sending out the first probe using the socket option TCP_KEEPALIVE_THRESHOLD @@ -485,7 +486,7 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { * The option value is an unsigned integer in milliseconds. The value zero indicates that TCP should never time out and * abort the connection when probing. The system default is controlled by the TCP ndd parameter tcp_keepalive_abort_interval. * The default is eight minutes. - * + * * - The second implementation is activated if socket option TCP_KEEPINTVL and/or TCP_KEEPCNT are set. * The time between each consequent probes is set by TCP_KEEPINTVL in seconds. * The minimum value is ten seconds. The maximum is ten days, while the default is two hours. @@ -499,43 +500,44 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { /* Kernel expects at most 10 days. */ if (idle > 10*24*60*60) idle = 10*24*60*60; - - /* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris + + /* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris * until version 11.4, but let's take a chance here. */ #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT) if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) return UV__ERR(errno); + intvl = idle/3; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) return UV__ERR(errno); + cnt = 3; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) return UV__ERR(errno); - return 0; -#endif - - /* Fall back to the first implementation of tcp-alive mechanism for older Solaris, +#else + /* Fall back to the first implementation of tcp-alive mechanism for older Solaris, * simulate the tcp-alive mechanism on other platforms via `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`. */ idle *= 1000; /* kernel expects milliseconds */ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &idle, sizeof(idle))) return UV__ERR(errno); - /* Note that the consequent probes will not be sent at equal intervals on Solaris, + /* Note that the consequent probes will not be sent at equal intervals on Solaris, * but will be sent using the exponential backoff algorithm. */ intvl = idle/3; cnt = 3; int time_to_abort = intvl * cnt; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort))) return UV__ERR(errno); - - return 0; #endif +#else /* !defined(__sun) */ + #ifdef TCP_KEEPIDLE if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) return UV__ERR(errno); #elif defined(TCP_KEEPALIVE) + /* Darwin/macOS uses TCP_KEEPALIVE in place of TCP_KEEPIDLE. */ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) return UV__ERR(errno); #endif @@ -552,6 +554,7 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { return UV__ERR(errno); #endif +#endif /* !defined(__sun) */ return 0; } From 3b6a1a14caeeeaf5510f2939a8e28ed9ba0ad968 Mon Sep 17 00:00:00 2001 From: Brad King Date: Sat, 13 Jan 2024 06:04:01 -0500 Subject: [PATCH 494/713] linux: disable io_uring on ppc64 and ppc64le (#4285) Since `io_uring` support was added, libuv's signal handler randomly segfaults on ppc64 when interrupting `epoll_pwait`. Disable it pending further investigation. Issue: https://github.com/libuv/libuv/issues/4283 --- src/unix/linux.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/unix/linux.c b/src/unix/linux.c index 3c1313e7efc..4164e90dbb0 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -463,6 +463,9 @@ static int uv__use_io_uring(void) { #elif defined(__arm__) && __SIZEOF_POINTER__ == 4 /* See https://github.com/libuv/libuv/issues/4158. */ return 0; /* All 32 bits kernels appear buggy. */ +#elif defined(__powerpc64__) || defined(__ppc64__) + /* See https://github.com/libuv/libuv/issues/4283. */ + return 0; /* Random SIGSEGV in signal handler. */ #else /* Ternary: unknown=0, yes=1, no=-1 */ static _Atomic int use_io_uring; From f98516ddd5bf9dcffcc7a28b3b0d42d68a561ca1 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 19 Jan 2024 19:09:39 +0100 Subject: [PATCH 495/713] doc: add very basic Security Policy document (#4290) --- SECURITY.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..32abba81544 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security Policy + +## Supported Versions + +Currently, we are providing security updates for the latest release in the v1.x series: + +| Version | Supported | +| ------- | ------------------ | +| Latest v1.x | :white_check_mark: | + +## Reporting a Vulnerability + +If you believe you have found a security vulnerability in `libuv`, please use the [GitHub's private vulnerability reporting feature](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) in the [libuv repository](https://github.com/libuv/libuv) to report it to us. + +This will allow us to assess the risk, and make a fix available before we add a bug report to the GitHub repository. + +Please do: + +* Provide as much information as you can about the vulnerability. +* Provide details about your configuration and environment, if applicable. + +Please do not: + +* Post any information about the vulnerability in public places. +* Attempt to exploit the vulnerability yourself. + +We take all security bugs seriously. Thank you for improving the security of `libuv`. We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions. \ No newline at end of file From 535efdf319ab719fbd3a7a4663339801d57b49c5 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 21 Jan 2024 10:44:34 -0500 Subject: [PATCH 496/713] build: re-enable msvc-asan job on CI (#4289) --- .github/workflows/CI-win.yml | 20 +++++++++++--------- CMakeLists.txt | 6 ++++++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index e66b107d4cb..7dc3fdcab70 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -25,16 +25,12 @@ jobs: - {toolchain: Visual Studio 16 2019, arch: x64, server: 2019} - {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022} - # Currently broken, see https://github.com/libuv/libuv/issues/4210 - #- {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN} + - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: UBSAN} - {toolchain: Visual Studio 17 2022, arch: arm64, server: 2022} steps: - uses: actions/checkout@v2 - - name: Envinfo - run: npx envinfo - name: Build - shell: cmd run: cmake -S . -B build -DBUILD_TESTING=ON -G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }} @@ -43,17 +39,23 @@ jobs: cmake --build build --config RelWithDebInfo + ${{ matrix.config.config == 'ASAN' && 'Copy-Item -Path "build\\*.exe" -Destination "build\\RelWithDebInfo\\"' || '' }} + + ${{ matrix.config.config == 'ASAN' && 'Copy-Item -Path "build\\*.dll" -Destination "build\\RelWithDebInfo\\"' || '' }} + ls -l build - - name: platform_output + + ls -l build\\RelWithDebInfo + - name: platform_output_a if: ${{ matrix.config.arch != 'arm64' }} shell: cmd run: - build\\RelWithDebInfo\\uv_run_tests.exe platform_output - - name: platform_output_a + build\\RelWithDebInfo\\uv_run_tests_a.exe platform_output + - name: platform_output if: ${{ matrix.config.arch != 'arm64' }} shell: cmd run: - build\\RelWithDebInfo\\uv_run_tests_a.exe platform_output + build\\RelWithDebInfo\\uv_run_tests.exe platform_output - name: Test # only valid with libuv-master with the fix for # https://github.com/libuv/leps/blob/master/005-windows-handles-not-fd.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a4d80699c5..3914f0d6844 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -767,6 +767,12 @@ endif() if(MSVC) set(CMAKE_DEBUG_POSTFIX d) + get_filename_component(CMAKE_C_COMPILER_DIR ${CMAKE_C_COMPILER} DIRECTORY) + if(ASAN) + file(INSTALL "${CMAKE_C_COMPILER_DIR}/llvm-symbolizer.exe" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(INSTALL "${CMAKE_C_COMPILER_DIR}/clang_rt.asan_dynamic-x86_64.dll" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + file(INSTALL "${CMAKE_C_COMPILER_DIR}/clang_rt.asan_dbg_dynamic-x86_64.dll" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + endif() endif() message(STATUS "summary of build options: From 3f7191e5c27a0e1852fe046a5ec0512a47e4a409 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 5 Feb 2024 11:04:05 -0500 Subject: [PATCH 497/713] win/spawn: optionally run executable paths with no file extension (#4292) Add a process options flag to enable the optional behavior. Most users are likely recommended to set this flag by default, but it was deemed potentially breaking to set it by default in libuv. Co-authored-by: Kyle Edwards --- .github/workflows/CI-win.yml | 2 +- CMakeLists.txt | 12 +++++++ Makefile.am | 6 ++++ docs/src/process.rst | 12 ++++++- include/uv.h | 9 +++++- src/unix/process.c | 1 + src/win/process.c | 14 ++++++--- test/test-list.h | 4 +++ test/test-spawn.c | 61 ++++++++++++++++++++++++++++++++++++ 9 files changed, 113 insertions(+), 8 deletions(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index 7dc3fdcab70..79a5abf4f00 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -93,7 +93,7 @@ jobs: cmake --install build --prefix "`pwd`/build/usr" mkdir -p build/usr/test build/usr/bin cp -av test/fixtures build/usr/test - cp -av build/uv_run_tests_a.exe build/uv_run_tests.exe \ + cp -av build/uv_run_tests_a.exe build/uv_run_tests.exe build/uv_run_tests_a_no_ext build/uv_run_tests_no_ext \ `${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libgcc_s_${{ matrix.config.libgcc }}-1.dll` \ `${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libwinpthread-1.dll` \ `${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libatomic-1.dll` \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 3914f0d6844..5e8e0166d74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -707,6 +707,12 @@ if(LIBUV_BUILD_TESTS) set_tests_properties(uv_test PROPERTIES ENVIRONMENT "LIBPATH=${CMAKE_BINARY_DIR}:$ENV{LIBPATH}") endif() + if(WIN32) + add_custom_command(TARGET uv_run_tests POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy + "$" + "$/uv_run_tests_no_ext") + endif() add_executable(uv_run_tests_a ${uv_test_sources} uv_win_longpath.manifest) target_compile_definitions(uv_run_tests_a PRIVATE ${uv_defines}) target_compile_options(uv_run_tests_a PRIVATE ${uv_cflags}) @@ -723,6 +729,12 @@ if(LIBUV_BUILD_TESTS) set_target_properties(uv_run_tests PROPERTIES LINKER_LANGUAGE CXX) set_target_properties(uv_run_tests_a PROPERTIES LINKER_LANGUAGE CXX) endif() + if(WIN32) + add_custom_command(TARGET uv_run_tests_a POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy + "$" + "$/uv_run_tests_a_no_ext") + endif() endif() # Now for some gibbering horrors from beyond the stars... diff --git a/Makefile.am b/Makefile.am index ff6f1b8a6d2..a14228da3bf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -136,6 +136,12 @@ TESTS = test/run-tests check_PROGRAMS = test/run-tests test_run_tests_CFLAGS = $(AM_CFLAGS) +if WINNT +check-am: test/run-tests_no_ext +test/run-tests_no_ext: test/run-tests$(EXEEXT) + cp test/run-tests$(EXEEXT) test/run-tests_no_ext +endif + if SUNOS # Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers # on other platforms complain that the argument is unused during compilation. diff --git a/docs/src/process.rst b/docs/src/process.rst index 8acf7db3df3..8d2fdb3e479 100644 --- a/docs/src/process.rst +++ b/docs/src/process.rst @@ -85,7 +85,14 @@ Data types * option is only meaningful on Windows systems. On Unix it is silently * ignored. */ - UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6) + UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6), + /* + * On Windows, if the path to the program to execute, specified in + * uv_process_options_t's file field, has a directory component, + * search for the exact file name before trying variants with + * extensions like '.exe' or '.cmd'. + */ + UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7) }; .. c:type:: uv_stdio_container_t @@ -262,6 +269,9 @@ API .. versionchanged:: 1.24.0 Added `UV_PROCESS_WINDOWS_HIDE_CONSOLE` and `UV_PROCESS_WINDOWS_HIDE_GUI` flags. + .. versionchanged:: 1.48.0 Added the + `UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME` flag. + .. c:function:: int uv_process_kill(uv_process_t* handle, int signum) Sends the specified signal to the given process handle. Check the documentation diff --git a/include/uv.h b/include/uv.h index b1e58e6cbfa..a62b3fa69b1 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1106,7 +1106,14 @@ enum uv_process_flags { * option is only meaningful on Windows systems. On Unix it is silently * ignored. */ - UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6) + UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6), + /* + * On Windows, if the path to the program to execute, specified in + * uv_process_options_t's file field, has a directory component, + * search for the exact file name before trying variants with + * extensions like '.exe' or '.cmd'. + */ + UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME = (1 << 7) }; /* diff --git a/src/unix/process.c b/src/unix/process.c index dd58c18d9b9..4812a90f2f5 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -972,6 +972,7 @@ int uv_spawn(uv_loop_t* loop, assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID | + UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME | UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_HIDE_CONSOLE | UV_PROCESS_WINDOWS_HIDE_GUI | diff --git a/src/win/process.c b/src/win/process.c index 50161b14bd0..400722bd47d 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -304,8 +304,9 @@ static WCHAR* path_search_walk_ext(const WCHAR *dir, * - If there's really only a filename, check the current directory for file, * then search all path directories. * - * - If filename specified has *any* extension, search for the file with the - * specified extension first. + * - If filename specified has *any* extension, or already contains a path + * and the UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME flag is specified, + * search for the file with the exact specified filename first. * * - If the literal filename is not found in a directory, try *appending* * (not replacing) .com first and then .exe. @@ -331,7 +332,8 @@ static WCHAR* path_search_walk_ext(const WCHAR *dir, */ static WCHAR* search_path(const WCHAR *file, WCHAR *cwd, - const WCHAR *path) { + const WCHAR *path, + unsigned int flags) { int file_has_dir; WCHAR* result = NULL; WCHAR *file_name_start; @@ -372,7 +374,7 @@ static WCHAR* search_path(const WCHAR *file, file, file_name_start - file, file_name_start, file_len - (file_name_start - file), cwd, cwd_len, - name_has_ext); + name_has_ext || (flags & UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME)); } else { dir_end = path; @@ -935,6 +937,7 @@ int uv_spawn(uv_loop_t* loop, assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID | + UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME | UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_HIDE_CONSOLE | UV_PROCESS_WINDOWS_HIDE_GUI | @@ -1014,7 +1017,8 @@ int uv_spawn(uv_loop_t* loop, application_path = search_path(application, cwd, - path); + path, + options->flags); if (application_path == NULL) { /* Not found. */ err = ERROR_FILE_NOT_FOUND; diff --git a/test/test-list.h b/test/test-list.h index e97b941f6dd..d30f02faa85 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -507,6 +507,8 @@ TEST_DECLARE (listen_no_simultaneous_accepts) TEST_DECLARE (fs_stat_root) TEST_DECLARE (spawn_with_an_odd_path) TEST_DECLARE (spawn_no_path) +TEST_DECLARE (spawn_no_ext) +TEST_DECLARE (spawn_path_no_ext) TEST_DECLARE (ipc_listen_after_bind_twice) TEST_DECLARE (win32_signum_number) #else @@ -1027,6 +1029,8 @@ TASK_LIST_START TEST_ENTRY (fs_stat_root) TEST_ENTRY (spawn_with_an_odd_path) TEST_ENTRY (spawn_no_path) + TEST_ENTRY (spawn_no_ext) + TEST_ENTRY (spawn_path_no_ext) TEST_ENTRY (ipc_listen_after_bind_twice) TEST_ENTRY (win32_signum_number) #else diff --git a/test/test-spawn.c b/test/test-spawn.c index 33552717fc3..6a848747036 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1397,6 +1397,67 @@ TEST_IMPL(spawn_no_path) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } + + +TEST_IMPL(spawn_no_ext) { + char new_exepath[1024]; + + init_process_options("spawn_helper1", exit_cb); + options.flags |= UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME; + snprintf(new_exepath, sizeof(new_exepath), "%.*s_no_ext", + (int) (exepath_size - sizeof(".exe") + 1), + exepath); + options.file = options.args[0] = new_exepath; + + ASSERT_OK(uv_spawn(uv_default_loop(), &process, &options)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT_EQ(1, exit_cb_called); + ASSERT_EQ(1, close_cb_called); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} + + +TEST_IMPL(spawn_path_no_ext) { + int r; + int len; + int file_len; + char file[64]; + char path[1024]; + char* env[2]; + + /* Set up the process, but make sure that the file to run is relative and + * requires a lookup into PATH. */ + init_process_options("spawn_helper1", exit_cb); + options.flags |= UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME; + + /* Set up the PATH env variable */ + for (len = strlen(exepath), file_len = 0; + exepath[len - 1] != '/' && exepath[len - 1] != '\\'; + len--, file_len++); + snprintf(file, sizeof(file), "%.*s_no_ext", + (int) (file_len - sizeof(".exe") + 1), + exepath + len); + exepath[len] = 0; + snprintf(path, sizeof(path), "PATH=%s", exepath); + + env[0] = path; + env[1] = NULL; + + options.file = options.args[0] = file; + options.env = env; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == UV_ENOENT || r == UV_EACCES); + ASSERT_OK(uv_is_active((uv_handle_t*) &process)); + uv_close((uv_handle_t*) &process, NULL); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} #endif #ifndef _WIN32 From 129362f35648a61ab19ab665014d2013731a986b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 5 Feb 2024 15:24:07 -0500 Subject: [PATCH 498/713] win: fix ESRCH implementation (#4301) Per documentation, this was the wrong way to test for ESRCH. This hopefully fixes it. Fixes: https://github.com/libuv/libuv/issues/4300 --- src/win/process.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index 400722bd47d..4e94dee90e1 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -1307,7 +1307,6 @@ static int uv__kill(HANDLE process_handle, int signum) { case SIGINT: { /* Unconditionally terminate the process. On Windows, killed processes * normally return 1. */ - DWORD status; int err; if (TerminateProcess(process_handle, 1)) @@ -1317,8 +1316,7 @@ static int uv__kill(HANDLE process_handle, int signum) { * TerminateProcess will fail with ERROR_ACCESS_DENIED. */ err = GetLastError(); if (err == ERROR_ACCESS_DENIED && - GetExitCodeProcess(process_handle, &status) && - status != STILL_ACTIVE) { + WaitForSingleObject(process_handle, 0) == WAIT_OBJECT_0) { return UV_ESRCH; } @@ -1327,15 +1325,16 @@ static int uv__kill(HANDLE process_handle, int signum) { case 0: { /* Health check: is the process still alive? */ - DWORD status; - - if (!GetExitCodeProcess(process_handle, &status)) - return uv_translate_sys_error(GetLastError()); - - if (status != STILL_ACTIVE) - return UV_ESRCH; - - return 0; + switch (WaitForSingleObject(process_handle, 0)) { + case WAIT_OBJECT_0: + return UV_ESRCH; + case WAIT_FAILED: + return uv_translate_sys_error(GetLastError()); + case WAIT_TIMEOUT: + return 0; + default: + return UV_UNKNOWN; + } } default: @@ -1370,7 +1369,7 @@ int uv_kill(int pid, int signum) { if (pid == 0) { process_handle = GetCurrentProcess(); } else { - process_handle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, + process_handle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pid); } From 10f313631c10ee508e17b35bdebf5adf0fff90fd Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 6 Feb 2024 07:52:21 +0100 Subject: [PATCH 499/713] Revert "unix: restore signal disposition to previous one (#4216)" (#4302) This reverts commit b9421d70665352138557d2d2338656a38ac70691. Refs: https://github.com/libuv/libuv/issues/4299 Refs: https://github.com/libuv/libuv/issues/4248 --- src/unix/signal.c | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/src/unix/signal.c b/src/unix/signal.c index 2b5567081a4..bc4206e6d86 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -32,18 +32,11 @@ # define SA_RESTART 0 #endif -#define UV__NSIG 128 - typedef struct { uv_signal_t* handle; int signum; } uv__signal_msg_t; -typedef struct { - struct sigaction acts[UV__NSIG]; - char acts_presented_flags[UV__NSIG]; -} uv__sigactions_t; - RB_HEAD(uv__signal_tree_s, uv_signal_s); @@ -57,23 +50,11 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2); static void uv__signal_stop(uv_signal_t* handle); static void uv__signal_unregister_handler(int signum); -static void uv__sigaction_set(int signum, struct sigaction *sa); -static int uv__sigaction_isset(int signum); static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT; static struct uv__signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); static int uv__signal_lock_pipefd[2] = { -1, -1 }; -static uv__sigactions_t uv__sigactions; - -static void uv__sigaction_set(int signum, struct sigaction *sa) { - uv__sigactions.acts[signum] = *sa; - uv__sigactions.acts_presented_flags[signum] = 1; -} - -static int uv__sigaction_isset(int signum) { - return uv__sigactions.acts_presented_flags[signum] == 0 ? 0 : 1; -} RB_GENERATE_STATIC(uv__signal_tree_s, uv_signal_s, tree_entry, @@ -243,7 +224,6 @@ static void uv__signal_handler(int signum) { static int uv__signal_register_handler(int signum, int oneshot) { /* When this function is called, the signal lock must be held. */ struct sigaction sa; - struct sigaction sa_old; /* XXX use a separate signal stack? */ memset(&sa, 0, sizeof(sa)); @@ -254,11 +234,10 @@ static int uv__signal_register_handler(int signum, int oneshot) { if (oneshot) sa.sa_flags |= SA_RESETHAND; - if (sigaction(signum, &sa, &sa_old)) + /* XXX save old action so we can restore it later on? */ + if (sigaction(signum, &sa, NULL)) return UV__ERR(errno); - uv__sigaction_set(signum, &sa_old); - return 0; } @@ -266,10 +245,9 @@ static int uv__signal_register_handler(int signum, int oneshot) { static void uv__signal_unregister_handler(int signum) { /* When this function is called, the signal lock must be held. */ struct sigaction sa; - - assert(uv__sigaction_isset(signum)); - - sa = uv__sigactions.acts[signum]; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; /* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a * signal implies that it was successfully registered earlier, so EINVAL From bb6fbcf6e75201cebac30220366d4aff620b8765 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 7 Feb 2024 10:43:29 +0100 Subject: [PATCH 500/713] unix,win: reset the timer queue on stop (#4304) As there were instances where this didn't happen and could cause memory corruption issues. Refs: https://github.com/libuv/libuv/issues/4248 --- src/timer.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/timer.c b/src/timer.c index b57d642776b..4525199ddc1 100644 --- a/src/timer.c +++ b/src/timer.c @@ -94,20 +94,18 @@ int uv_timer_start(uv_timer_t* handle, return 0; } -static void timer_stop(uv_timer_t* handle) { - heap_remove(timer_heap(handle->loop), - (struct heap_node*) &handle->node.heap, - timer_less_than); - uv__handle_stop(handle); - uv__queue_init(&handle->node.queue); -} - int uv_timer_stop(uv_timer_t* handle) { - if (uv__is_active(handle)) - timer_stop(handle); - else + if (uv__is_active(handle)) { + heap_remove(timer_heap(handle->loop), + (struct heap_node*) &handle->node.heap, + timer_less_than); + uv__handle_stop(handle); + } else { uv__queue_remove(&handle->node.queue); + } + + uv__queue_init(&handle->node.queue); return 0; } @@ -181,7 +179,7 @@ void uv__run_timers(uv_loop_t* loop) { if (handle->timeout > loop->time) break; - timer_stop(handle); + uv_timer_stop(handle); uv__queue_insert_tail(&ready_queue, &handle->node.queue); } From 0f2d7e784a256b54b2385043438848047bc2a629 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 18 Jan 2024 14:51:40 +0100 Subject: [PATCH 501/713] fix: always zero-terminate idna output Fixes: https://github.com/libuv/libuv/security/advisories/GHSA-f74f-cvh7-c6q6 --- src/idna.c | 5 +++-- test/test-idna.c | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/idna.c b/src/idna.c index 3cf79ca94b1..4638546d020 100644 --- a/src/idna.c +++ b/src/idna.c @@ -356,9 +356,10 @@ ssize_t uv__idna_toascii(const char* s, const char* se, char* d, char* de) { return rc; } - if (d < de) - *d++ = '\0'; + if (d >= de) + return UV_EINVAL; + *d++ = '\0'; return d - ds; /* Number of bytes written. */ } diff --git a/test/test-idna.c b/test/test-idna.c index bcacfc8a3ad..5f8d696a7f0 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -100,6 +100,7 @@ TEST_IMPL(utf8_decode1) { TEST_IMPL(utf8_decode1_overrun) { const char* p; char b[1]; + char c[1]; /* Single byte. */ p = b; @@ -113,6 +114,9 @@ TEST_IMPL(utf8_decode1_overrun) { ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + 1)); ASSERT_PTR_EQ(p, b + 1); + b[0] = 0x7F; + ASSERT_EQ(UV_EINVAL, uv__idna_toascii(b, b + 1, c, c + 1)); + return 0; } From 3530bcc30350d4a6ccf35d2f7b33e23292b9de70 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 18 Jan 2024 14:52:38 +0100 Subject: [PATCH 502/713] fix: reject zero-length idna inputs Fixes: https://github.com/libuv/libuv/security/advisories/GHSA-f74f-cvh7-c6q6 --- src/idna.c | 3 +++ test/test-idna.c | 1 + 2 files changed, 4 insertions(+) diff --git a/src/idna.c b/src/idna.c index 4638546d020..efc5f283ce2 100644 --- a/src/idna.c +++ b/src/idna.c @@ -322,6 +322,9 @@ ssize_t uv__idna_toascii(const char* s, const char* se, char* d, char* de) { char* ds; int rc; + if (s == se) + return UV_EINVAL; + ds = d; si = s; diff --git a/test/test-idna.c b/test/test-idna.c index 5f8d696a7f0..3c4820f7659 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -115,6 +115,7 @@ TEST_IMPL(utf8_decode1_overrun) { ASSERT_PTR_EQ(p, b + 1); b[0] = 0x7F; + ASSERT_EQ(UV_EINVAL, uv__idna_toascii(b, b + 0, c, c + 1)); ASSERT_EQ(UV_EINVAL, uv__idna_toascii(b, b + 1, c, c + 1)); return 0; From e0327e1d508b8207c9150b6e582f0adf26213c39 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 7 Feb 2024 20:27:58 +0100 Subject: [PATCH 503/713] test: empty strings are not valid IDNA Fixes: https://github.com/libuv/libuv/security/advisories/GHSA-f74f-cvh7-c6q6 --- test/test-idna.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-idna.c b/test/test-idna.c index 3c4820f7659..28f9eaaae9e 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -151,8 +151,8 @@ TEST_IMPL(idna_toascii) { /* Illegal inputs. */ F("\xC0\x80\xC1\x80", UV_EINVAL); /* Overlong UTF-8 sequence. */ F("\xC0\x80\xC1\x80.com", UV_EINVAL); /* Overlong UTF-8 sequence. */ + F("", UV_EINVAL); /* No conversion. */ - T("", ""); T(".", "."); T(".com", ".com"); T("example", "example"); From c858a147643de38a09dd4164758ae5b685f2b488 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 7 Feb 2024 20:53:55 +0100 Subject: [PATCH 504/713] Merge pull request from GHSA-f74f-cvh7-c6q6 * fix: always zero-terminate idna output * fix: reject zero-length idna inputs * test: empty strings are not valid IDNA --------- Co-authored-by: Santiago Gimeno From e9f29cb984231524e3931aa0ae2c5dae1a32884e Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 7 Feb 2024 20:20:07 +0000 Subject: [PATCH 505/713] 2024.02.07, Version 1.48.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.47.0: * misc: remove deprecated stalebot file (Jameson Nash) * build: disable windows asan buildbot (Ben Noordhuis) * test: don't run tcp_writealot under msan (Ben Noordhuis) * build,win: remove extraneous -lshell32 (Ben Noordhuis) * unix: ignore ifaddrs with NULL ifa_addr (Stephen Gallagher) * unix,win: utility for setting priority for thread (Hao Hu) * pipe: add back error handling to connect / bind (Jameson Nash) * test: check if ipv6 link-local traffic is routable (Ben Noordhuis) * win: remove check for UV_PIPE_NO_TRUNCATE (Jameson Nash) * linux: disable io_uring on hppa below kernel 6.1.51 (matoro) * unix,win: fix read past end of pipe name buffer (Ben Noordhuis) * unix: unbreak macOS < 10.14 (Sergey Fedorov) * aix: disable ipv6 link local (Abdirahim Musse) * doc: move cjihrig to emeriti (cjihrig) * unix: correct pwritev conditional (Bo Anderson) * test_fs.c: Fix issue on 32-bit systems using btrfs (Stephen Gallagher) * misc: ignore libuv-release-tool files (Jameson Nash) * win: honor NoDefaultCurrentDirectoryInExePath env var (Ardi Nugraha) * idna: fix compilation warning (Saúl Ibarra Corretgé) * linux: remove HAVE_IFADDRS_H macro (Ben Noordhuis) * test: skip tcp-write-in-a-row on IBM i (Abdirahim Musse) * build,win: work around missing uuid.dll on MinGW (Anton Bachin) * win: stop using deprecated names (Matheus Izvekov) * unix,win: fix busy loop with zero timeout timers (Matheus Izvekov) * aix,ibmi: use uv_interface_addresses instead of getifaddrs (Abdirahim Musse) * linux: fix bind/connect for abstract sockets (Santiago Gimeno) * win: replace c99 comments with c89 comments (Trevor Flynn) * build: add .cache clangd folder to .gitignore (Juan José Arboleda) * unix: support full TCP keep-alive on Solaris (Andy Pan) * freebsd: fix F_KINFO file path handling (David Carlier) * linux: retry fs op if unsupported by io_uring (Santiago Gimeno) * freebsd: fix build on non-intel archs (David Carlier) * unix: optimize uv__tcp_keepalive cpp directives (Andy Pan) * linux: disable io_uring on ppc64 and ppc64le (Brad King) * doc: add very basic Security Policy document (Santiago Gimeno) * build: re-enable msvc-asan job on CI (Jameson Nash) * win/spawn: optionally run executable paths with no file extension (Brad King) * win: fix ESRCH implementation (Jameson Nash) * unix,win: reset the timer queue on stop (Santiago Gimeno) * fix: always zero-terminate idna output (Ben Noordhuis) * fix: reject zero-length idna inputs (Ben Noordhuis) * test: empty strings are not valid IDNA (Santiago Gimeno) * Merge pull request from GHSA-f74f-cvh7-c6q6 (Ben Noordhuis) --- AUTHORS | 7 ++++ ChangeLog | 91 ++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 8 ++-- 4 files changed, 103 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 6bf1a9fa2f9..f3942ced3c5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -560,3 +560,10 @@ prubel Per Allansson <65364157+per-allansson@users.noreply.github.com> Matheus Izvekov Christian Heimlich +Hao Hu <33607772+hhu8@users.noreply.github.com> +matoro <12038583+matoro@users.noreply.github.com> +Bo Anderson +Ardi Nugraha <33378542+ardi-nugraha@users.noreply.github.com> +Anton Bachin +Trevor Flynn +Andy Pan diff --git a/ChangeLog b/ChangeLog index 0a3905b29ac..05c1cb7e748 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,94 @@ +2024.02.07, Version 1.48.0 (Stable) + +Changes since version 1.47.0: + +* misc: remove deprecated stalebot file (Jameson Nash) + +* build: disable windows asan buildbot (Ben Noordhuis) + +* test: don't run tcp_writealot under msan (Ben Noordhuis) + +* build,win: remove extraneous -lshell32 (Ben Noordhuis) + +* unix: ignore ifaddrs with NULL ifa_addr (Stephen Gallagher) + +* unix,win: utility for setting priority for thread (Hao Hu) + +* pipe: add back error handling to connect / bind (Jameson Nash) + +* test: check if ipv6 link-local traffic is routable (Ben Noordhuis) + +* win: remove check for UV_PIPE_NO_TRUNCATE (Jameson Nash) + +* linux: disable io_uring on hppa below kernel 6.1.51 (matoro) + +* unix,win: fix read past end of pipe name buffer (Ben Noordhuis) + +* unix: unbreak macOS < 10.14 (Sergey Fedorov) + +* aix: disable ipv6 link local (Abdirahim Musse) + +* doc: move cjihrig to emeriti (cjihrig) + +* unix: correct pwritev conditional (Bo Anderson) + +* test_fs.c: Fix issue on 32-bit systems using btrfs (Stephen Gallagher) + +* misc: ignore libuv-release-tool files (Jameson Nash) + +* win: honor NoDefaultCurrentDirectoryInExePath env var (Ardi Nugraha) + +* idna: fix compilation warning (Saúl Ibarra Corretgé) + +* linux: remove HAVE_IFADDRS_H macro (Ben Noordhuis) + +* test: skip tcp-write-in-a-row on IBM i (Abdirahim Musse) + +* build,win: work around missing uuid.dll on MinGW (Anton Bachin) + +* win: stop using deprecated names (Matheus Izvekov) + +* unix,win: fix busy loop with zero timeout timers (Matheus Izvekov) + +* aix,ibmi: use uv_interface_addresses instead of getifaddrs (Abdirahim Musse) + +* linux: fix bind/connect for abstract sockets (Santiago Gimeno) + +* win: replace c99 comments with c89 comments (Trevor Flynn) + +* build: add .cache clangd folder to .gitignore (Juan José Arboleda) + +* unix: support full TCP keep-alive on Solaris (Andy Pan) + +* freebsd: fix F_KINFO file path handling (David Carlier) + +* linux: retry fs op if unsupported by io_uring (Santiago Gimeno) + +* freebsd: fix build on non-intel archs (David Carlier) + +* unix: optimize uv__tcp_keepalive cpp directives (Andy Pan) + +* linux: disable io_uring on ppc64 and ppc64le (Brad King) + +* doc: add very basic Security Policy document (Santiago Gimeno) + +* build: re-enable msvc-asan job on CI (Jameson Nash) + +* win/spawn: optionally run executable paths with no file extension (Brad King) + +* win: fix ESRCH implementation (Jameson Nash) + +* unix,win: reset the timer queue on stop (Santiago Gimeno) + +* fix: always zero-terminate idna output (Ben Noordhuis) + +* fix: reject zero-length idna inputs (Ben Noordhuis) + +* test: empty strings are not valid IDNA (Santiago Gimeno) + +* Merge pull request from GHSA-f74f-cvh7-c6q6 (Ben Noordhuis) + + 2023.11.06, Version 1.47.0 (Stable), be6b81a352d17513c95be153afcb3148f1a451cd Changes since version 1.46.0: diff --git a/configure.ac b/configure.ac index f9b5aa53d51..d4cc003e343 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.47.1-dev], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.48.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 8a5e3c09dbb..d6a61a10f7c 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 47 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 48 +#define UV_VERSION_PATCH 0 +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 99e576612d25656b69560ad2b3762743f84fbbd2 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 7 Feb 2024 21:20:12 +0100 Subject: [PATCH 506/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 05c1cb7e748..6c9e351a6e4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2024.02.07, Version 1.48.0 (Stable) +2024.02.07, Version 1.48.0 (Stable), e9f29cb984231524e3931aa0ae2c5dae1a32884e Changes since version 1.47.0: From 08a1e7fd23a9b8c893932c1a0083fc703dfe51c0 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 7 Feb 2024 22:44:51 +0100 Subject: [PATCH 507/713] Now working on version 1.48.1 Fixes: https://github.com/libuv/libuv/issues/4248 --- configure.ac | 2 +- include/uv/version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index d4cc003e343..7b67b480597 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.48.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.48.1-dev], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index d6a61a10f7c..8fec6b39b3a 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 48 -#define UV_VERSION_PATCH 0 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 1 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 009d7414bc51fe538f6745738b09d46e937007a1 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 9 Feb 2024 19:17:20 +0100 Subject: [PATCH 508/713] test: fix -Wpointer-to-int-cast on 32 bits systems (#4309) The return value from signal(2) is a pointer. Use the right macro. --- test/test-spawn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-spawn.c b/test/test-spawn.c index 6a848747036..efbb2395ff8 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1054,7 +1054,7 @@ TEST_IMPL(kill) { sigaddset(&set, SIGTERM); ASSERT_OK(pthread_sigmask(SIG_BLOCK, &set, NULL)); } - ASSERT_NE(SIG_ERR, signal(SIGTERM, SIG_IGN)); + ASSERT_PTR_NE(SIG_ERR, signal(SIGTERM, SIG_IGN)); #endif r = uv_spawn(uv_default_loop(), &process, &options); @@ -1067,7 +1067,7 @@ TEST_IMPL(kill) { sigaddset(&set, SIGTERM); ASSERT_OK(pthread_sigmask(SIG_UNBLOCK, &set, NULL)); } - ASSERT_NE(SIG_ERR, signal(SIGTERM, SIG_DFL)); + ASSERT_PTR_NE(SIG_ERR, signal(SIGTERM, SIG_DFL)); #endif /* Sending signum == 0 should check if the From 7b9e37c7da6730601edbf32f0ae6dae2a17ca03c Mon Sep 17 00:00:00 2001 From: Anthony Alayo Date: Fri, 9 Feb 2024 12:08:24 -0800 Subject: [PATCH 509/713] build: add alias for libuv to CMakeLists.txt (#4297) Fixes: https://github.com/libuv/libuv/issues/4282 --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e8e0166d74..62609708636 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -787,6 +787,14 @@ if(MSVC) endif() endif() +if(BUILD_SHARED_LIBS) + set(LIB_SELECTED uv) +else() + set(LIB_SELECTED uv_a) +endif() + +add_library(libuv::libuv ALIAS ${LIB_SELECTED}) + message(STATUS "summary of build options: Install prefix: ${CMAKE_INSTALL_PREFIX} Target system: ${CMAKE_SYSTEM_NAME} From 507f3046d104db2be2c33d5e8fc0d5322818a62c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 14 Feb 2024 11:20:44 +0100 Subject: [PATCH 510/713] linux: create io_uring sqpoll ring lazily (#4315) It's been reported that creating many event loops introduces measurable overhead now that libuv creates an sqpoll-enabled ring. I don't really see any change in CPU time with or without this change but deferring ring creation until it's actually used seems like a good idea, and comes with no downsides that I can think of, so let's do it. Fixes: https://github.com/libuv/libuv/issues/4308 --- src/unix/linux.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 4164e90dbb0..0dd11438fe6 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -622,7 +622,7 @@ static void uv__iou_init(int epollfd, static void uv__iou_delete(struct uv__iou* iou) { - if (iou->ringfd != -1) { + if (iou->ringfd > -1) { munmap(iou->sq, iou->maxlen); munmap(iou->sqe, iou->sqelen); uv__close(iou->ringfd); @@ -636,7 +636,7 @@ int uv__platform_loop_init(uv_loop_t* loop) { lfields = uv__get_internal_fields(loop); lfields->ctl.ringfd = -1; - lfields->iou.ringfd = -1; + lfields->iou.ringfd = -2; /* "uninitialized" */ loop->inotify_watchers = NULL; loop->inotify_fd = -1; @@ -645,7 +645,6 @@ int uv__platform_loop_init(uv_loop_t* loop) { if (loop->backend_fd == -1) return UV__ERR(errno); - uv__iou_init(loop->backend_fd, &lfields->iou, 64, UV__IORING_SETUP_SQPOLL); uv__iou_init(loop->backend_fd, &lfields->ctl, 256, 0); return 0; @@ -764,6 +763,15 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, uint32_t mask; uint32_t slot; + /* Lazily create the ring. State machine: -2 means uninitialized, -1 means + * initialization failed. Anything else is a valid ring file descriptor. + */ + if (iou->ringfd == -2) { + uv__iou_init(loop->backend_fd, iou, 64, UV__IORING_SETUP_SQPOLL); + if (iou->ringfd == -2) + iou->ringfd = -1; /* "failed" */ + } + if (iou->ringfd == -1) return NULL; From cc9e96147f5bc2135814f4aa786c90a06c5a105f Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 23 Feb 2024 14:15:03 -0500 Subject: [PATCH 511/713] misc: run sample CI when code changes (#4324) --- .github/workflows/CI-sample.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/CI-sample.yml b/.github/workflows/CI-sample.yml index 409ef56877e..4bd82f9f2eb 100644 --- a/.github/workflows/CI-sample.yml +++ b/.github/workflows/CI-sample.yml @@ -6,6 +6,7 @@ on: - '**' - '!docs/**' - '!.**' + - 'docs/code/**' - '.github/workflows/CI-sample.yml' push: branches: From 6b56200cc8e0d60d7662f0cb49eccbd23530a3e1 Mon Sep 17 00:00:00 2001 From: Thomas Walter <31201229+waltoss@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:23:23 +0100 Subject: [PATCH 512/713] linux: fix uv_available_parallelism using cgroup (#4278) uv_available_parallelism does not handle container cpu limit set by systems like Docker or Kubernetes. This patch fixes this limitation by comparing the amount of available cpus returned by syscall with the quota of cpus available defined in the cgroup. Fixes: https://github.com/libuv/libuv/issues/4146 --- src/unix/core.c | 11 ++- src/unix/internal.h | 10 +++ src/unix/linux.c | 130 ++++++++++++++++++++++++++++++++++++ test/test-platform-output.c | 39 +++++++++++ 4 files changed, 188 insertions(+), 2 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 965e7f77525..8ea606c7a8c 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1869,6 +1869,8 @@ unsigned int uv_available_parallelism(void) { #ifdef __linux__ cpu_set_t set; long rc; + double rc_with_cgroup; + uv__cpu_constraint c = {0, 0, 0.0}; memset(&set, 0, sizeof(set)); @@ -1880,8 +1882,13 @@ unsigned int uv_available_parallelism(void) { rc = CPU_COUNT(&set); else rc = sysconf(_SC_NPROCESSORS_ONLN); - - if (rc < 1) + + if (uv__get_constrained_cpu(&c) == 0 && c.period_length > 0) { + rc_with_cgroup = (double)c.quota_per_period / c.period_length * c.proportions; + if (rc_with_cgroup < rc) + rc = (long)rc_with_cgroup; /* Casting is safe since rc_with_cgroup < rc < LONG_MAX */ + } + if (rc < 1) rc = 1; return (unsigned) rc; diff --git a/src/unix/internal.h b/src/unix/internal.h index bcb3be577e5..3ad3705274f 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -472,4 +472,14 @@ uv__fs_copy_file_range(int fd_in, #define UV__CPU_AFFINITY_SUPPORTED 0 #endif +#ifdef __linux__ +typedef struct { + long long quota_per_period; + long long period_length; + double proportions; +} uv__cpu_constraint; + +int uv__get_constrained_cpu(uv__cpu_constraint* constraint); +#endif + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/src/unix/linux.c b/src/unix/linux.c index 0dd11438fe6..f0c65bbcce0 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -2278,6 +2278,136 @@ uint64_t uv_get_available_memory(void) { } +static int uv__get_cgroupv2_constrained_cpu(const char* cgroup, + uv__cpu_constraint* constraint) { + char path[256]; + char buf[1024]; + unsigned int weight; + int cgroup_size; + const char* cgroup_trimmed; + char quota_buf[16]; + + if (strncmp(cgroup, "0::/", 4) != 0) + return UV_EINVAL; + + /* Trim ending \n by replacing it with a 0 */ + cgroup_trimmed = cgroup + sizeof("0::/") - 1; /* Skip the prefix "0::/" */ + cgroup_size = (int)strcspn(cgroup_trimmed, "\n"); /* Find the first slash */ + + /* Construct the path to the cpu.max file */ + snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.max", cgroup_size, + cgroup_trimmed); + + /* Read cpu.max */ + if (uv__slurp(path, buf, sizeof(buf)) < 0) + return UV_EIO; + + if (sscanf(buf, "%15s %llu", quota_buf, &constraint->period_length) != 2) + return UV_EINVAL; + + if (strncmp(quota_buf, "max", 3) == 0) + constraint->quota_per_period = LLONG_MAX; + else if (sscanf(quota_buf, "%lld", &constraint->quota_per_period) != 1) + return UV_EINVAL; // conversion failed + + /* Construct the path to the cpu.weight file */ + snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.weight", cgroup_size, + cgroup_trimmed); + + /* Read cpu.weight */ + if (uv__slurp(path, buf, sizeof(buf)) < 0) + return UV_EIO; + + if (sscanf(buf, "%u", &weight) != 1) + return UV_EINVAL; + + constraint->proportions = (double)weight / 100.0; + + return 0; +} + +static char* uv__cgroup1_find_cpu_controller(const char* cgroup, + int* cgroup_size) { + /* Seek to the cpu controller line. */ + char* cgroup_cpu = strstr(cgroup, ":cpu,"); + + if (cgroup_cpu != NULL) { + /* Skip the controller prefix to the start of the cgroup path. */ + cgroup_cpu += sizeof(":cpu,") - 1; + /* Determine the length of the cgroup path, excluding the newline. */ + *cgroup_size = (int)strcspn(cgroup_cpu, "\n"); + } + + return cgroup_cpu; +} + +static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, + uv__cpu_constraint* constraint) { + char path[256]; + char buf[1024]; + unsigned int shares; + int cgroup_size; + char* cgroup_cpu; + + cgroup_cpu = uv__cgroup1_find_cpu_controller(cgroup, &cgroup_size); + + if (cgroup_cpu == NULL) + return UV_EIO; + + /* Construct the path to the cpu.cfs_quota_us file */ + snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.cfs_quota_us", + cgroup_size, cgroup_cpu); + + if (uv__slurp(path, buf, sizeof(buf)) < 0) + return UV_EIO; + + if (sscanf(buf, "%lld", &constraint->quota_per_period) != 1) + return UV_EINVAL; + + /* Construct the path to the cpu.cfs_period_us file */ + snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.cfs_period_us", + cgroup_size, cgroup_cpu); + + /* Read cpu.cfs_period_us */ + if (uv__slurp(path, buf, sizeof(buf)) < 0) + return UV_EIO; + + if (sscanf(buf, "%lld", &constraint->period_length) != 1) + return UV_EINVAL; + + /* Construct the path to the cpu.shares file */ + snprintf(path, sizeof(path), "/sys/fs/cgroup/%.*s/cpu.shares", cgroup_size, + cgroup_cpu); + + /* Read cpu.shares */ + if (uv__slurp(path, buf, sizeof(buf)) < 0) + return UV_EIO; + + if (sscanf(buf, "%u", &shares) != 1) + return UV_EINVAL; + + constraint->proportions = (double)shares / 1024.0; + + return 0; +} + +int uv__get_constrained_cpu(uv__cpu_constraint* constraint) { + char cgroup[1024]; + + /* Read the cgroup from /proc/self/cgroup */ + if (uv__slurp("/proc/self/cgroup", cgroup, sizeof(cgroup)) < 0) + return UV_EIO; + + /* Check if the system is using cgroup v2 by examining /proc/self/cgroup + * The entry for cgroup v2 is always in the format "0::$PATH" + * see https://docs.kernel.org/admin-guide/cgroup-v2.html */ + if (strncmp(cgroup, "0::/", 4) == 0) + return uv__get_cgroupv2_constrained_cpu(cgroup, constraint); + else + return uv__get_cgroupv1_constrained_cpu(cgroup, constraint); +} + + void uv_loadavg(double avg[3]) { struct sysinfo info; char buf[128]; /* Large enough to hold all of /proc/loadavg. */ diff --git a/test/test-platform-output.c b/test/test-platform-output.c index f18e097f913..f5218c581d1 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -90,6 +90,45 @@ TEST_IMPL(platform_output) { ASSERT_GE(par, 1); printf("uv_available_parallelism: %u\n", par); +#ifdef __linux__ + FILE* file; + int cgroup_version = 0; + unsigned int cgroup_par = 0; + uint64_t quota, period; + + // Attempt to parse cgroup v2 to deduce parallelism constraints + file = fopen("/sys/fs/cgroup/cpu.max", "r"); + if (file) { + if (fscanf(file, "%lu %lu", "a, &period) == 2 && quota > 0) { + cgroup_version = 2; + cgroup_par = (unsigned int)(quota / period); + } + fclose(file); + } + + // If cgroup v2 wasn't present, try parsing cgroup v1 + if (cgroup_version == 0) { + file = fopen("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us", "r"); + if (file) { + if (fscanf(file, "%lu", "a) == 1 && quota > 0) { + fclose(file); + file = fopen("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us", "r"); + if (file && fscanf(file, "%lu", &period) == 1) { + cgroup_version = 1; + cgroup_par = (unsigned int)(quota / period); + } + } + if (file) fclose(file); + } + } + + // If we found cgroup parallelism constraints, assert and print them + if (cgroup_par > 0) { + ASSERT_GE(par, cgroup_par); + printf("cgroup v%d available parallelism: %u\n", cgroup_version, cgroup_par); + } +#endif + err = uv_cpu_info(&cpus, &count); #if defined(__CYGWIN__) || defined(__MSYS__) ASSERT_EQ(err, UV_ENOSYS); From e8458b2402e7a068f25f01d0b72e6aed73ca2138 Mon Sep 17 00:00:00 2001 From: hiiizxf <385122613@qq.com> Date: Wed, 28 Feb 2024 19:32:24 +0800 Subject: [PATCH 513/713] doc: fix tty example segfault (#4322) Fixes: https://github.com/libuv/libuv/issues/4303 --- docs/code/tty/main.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/code/tty/main.c b/docs/code/tty/main.c index d44ec62ce98..ce3607982a5 100644 --- a/docs/code/tty/main.c +++ b/docs/code/tty/main.c @@ -5,25 +5,27 @@ uv_loop_t *loop; uv_tty_t tty; + int main() { - loop = uv_default_loop(); + uv_write_t req; + uv_buf_t buf; + uv_write_t req1; + uv_buf_t buf1; + loop = uv_default_loop(); uv_tty_init(loop, &tty, STDOUT_FILENO, 0); uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL); if (uv_guess_handle(1) == UV_TTY) { - uv_write_t req; - uv_buf_t buf; - buf.base = "\033[41;37m"; - buf.len = strlen(buf.base); - uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL); + buf1.base = "\033[41;37m"; + buf1.len = strlen(buf1.base); + uv_write(&req1, (uv_stream_t*) &tty, &buf1, 1, NULL); } - uv_write_t req; - uv_buf_t buf; buf.base = "Hello TTY\n"; buf.len = strlen(buf.base); uv_write(&req, (uv_stream_t*) &tty, &buf, 1, NULL); + uv_tty_reset_mode(); return uv_run(loop, UV_RUN_DEFAULT); } From a7c44d674833e8dec66b8730b5635fcad0f81162 Mon Sep 17 00:00:00 2001 From: Geddy Date: Thu, 29 Feb 2024 06:32:43 +0800 Subject: [PATCH 514/713] udp,unix: fix sendmsg use-after-free (#4321) Issue: 1. uv__io_poll calls uv__udp_io with revents == POLLIN + POLLOUT 2. uv__udp_io calls your recv_cb 3. you close the handle in callback 4. uv__udp_io calls uv__udp_sendmsg 5. uv__udp_sendmsg calls uv__io_feed 6. kaboom! --- src/unix/udp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index c2814512a5f..5dcd5a4da7d 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -141,7 +141,7 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { if (revents & POLLIN) uv__udp_recvmsg(handle); - if (revents & POLLOUT) { + if (revents & POLLOUT && !uv__is_closing(handle)) { uv__udp_sendmsg(handle); uv__udp_run_completed(handle); } From 625d3d275a4a92fff2408a3e0a7bae6db0dbb200 Mon Sep 17 00:00:00 2001 From: Farzin Monsef Date: Sat, 2 Mar 2024 13:54:57 +0330 Subject: [PATCH 515/713] cygwin: implement uv_resident_set_memory (#4333) According to the documentation for Cygwin, the penultimate field of /proc/pid/stat corresponds to the RSS, so the method is basically the same as in the Linux version. The only difference is that getpagesize() will return wincap.allocation_granularity(), but in this mapping, RSS is calculated using wincap.page_size(), which can be accessed by sysinfo.mem_unit. --- src/unix/cygwin.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/unix/cygwin.c b/src/unix/cygwin.c index 4e5413963d6..4913108223f 100644 --- a/src/unix/cygwin.c +++ b/src/unix/cygwin.c @@ -36,9 +36,45 @@ int uv_uptime(double* uptime) { } int uv_resident_set_memory(size_t* rss) { - /* FIXME: read /proc/meminfo? */ - *rss = 0; + char buf[1024]; + const char* s; + long val; + int rc; + int i; + struct sysinfo si; + + /* rss: 24th element */ + rc = uv__slurp("/proc/self/stat", buf, sizeof(buf)); + if (rc < 0) + return rc; + + /* find the last ')' */ + s = strrchr(buf, ')'); + if (s == NULL) + goto err; + + for (i = 1; i <= 22; i++) { + s = strchr(s + 1, ' '); + if (s == NULL) + goto err; + } + + errno = 0; + val = strtol(s, NULL, 10); + if (val < 0 || errno != 0) + goto err; + + do + rc = sysinfo(&si); + while (rc == -1 && errno == EINTR); + if (rc == -1) + return UV__ERR(errno); + + *rss = val * si.mem_unit; return 0; + +err: + return UV_EINVAL; } int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { From ff9587991f53a427c6e0e8e02df40ba3749d166c Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 5 Mar 2024 21:20:50 +0100 Subject: [PATCH 516/713] win: almost fix race detecting ESRCH in uv_kill (#4341) It might happen that only using `WaitForSingleObject()` with timeout 0 could return WAIT_TIMEOUT as the process might not have been signaled yet. To improve things, first use `GetExitCodeProcess()` and check that `status` is not `STILL_ACTIVE`. Then, to cover for the case that the exit code was actually `STILL_ACTIVE` use `WaitForSingleObject()`. This could still be prone to the race condition but only for that case. --- src/win/process.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index 4e94dee90e1..f46f34289e8 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -1308,16 +1308,34 @@ static int uv__kill(HANDLE process_handle, int signum) { /* Unconditionally terminate the process. On Windows, killed processes * normally return 1. */ int err; + DWORD status; if (TerminateProcess(process_handle, 1)) return 0; - /* If the process already exited before TerminateProcess was called,. + /* If the process already exited before TerminateProcess was called, * TerminateProcess will fail with ERROR_ACCESS_DENIED. */ err = GetLastError(); - if (err == ERROR_ACCESS_DENIED && - WaitForSingleObject(process_handle, 0) == WAIT_OBJECT_0) { - return UV_ESRCH; + if (err == ERROR_ACCESS_DENIED) { + /* First check using GetExitCodeProcess() with status different from + * STILL_ACTIVE (259). This check can be set incorrectly by the process, + * though that is uncommon. */ + if (GetExitCodeProcess(process_handle, &status) && + status != STILL_ACTIVE) { + return UV_ESRCH; + } + + /* But the process could have exited with code == STILL_ACTIVE, use then + * WaitForSingleObject with timeout zero. This is prone to a race + * condition as it could return WAIT_TIMEOUT because the handle might + * not have been signaled yet.That would result in returning the wrong + * error code here (UV_EACCES instead of UV_ESRCH), but we cannot fix + * the kernel synchronization issue that TerminateProcess is + * inconsistent with WaitForSingleObject with just the APIs available to + * us in user space. */ + if (WaitForSingleObject(process_handle, 0) == WAIT_OBJECT_0) { + return UV_ESRCH; + } } return uv_translate_sys_error(err); @@ -1325,6 +1343,14 @@ static int uv__kill(HANDLE process_handle, int signum) { case 0: { /* Health check: is the process still alive? */ + DWORD status; + + if (!GetExitCodeProcess(process_handle, &status)) + return uv_translate_sys_error(GetLastError()); + + if (status != STILL_ACTIVE) + return UV_ESRCH; + switch (WaitForSingleObject(process_handle, 0)) { case WAIT_OBJECT_0: return UV_ESRCH; From 2c153450162108a7f4105a5154592a2bb9e80ce1 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 7 Mar 2024 09:46:57 +0100 Subject: [PATCH 517/713] test: disable env var test under win32+asan (#4342) The test hits an honest-to-$deity compiler runtime bug, see the investigation in the linked issue. Fixes: https://github.com/libuv/libuv/issues/4338 --- test/test-env-vars.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test-env-vars.c b/test/test-env-vars.c index 016f0733c6e..fd25ea26e14 100644 --- a/test/test-env-vars.c +++ b/test/test-env-vars.c @@ -33,6 +33,11 @@ TEST_IMPL(env_vars) { int i, r, envcount, found, found_win_special; uv_env_item_t* envitems; +#if defined(_WIN32) && defined(__ASAN__) + /* See investigation in https://github.com/libuv/libuv/issues/4338 */ + RETURN_SKIP("Test does not currently work on Windows under ASAN"); +#endif + /* Reject invalid inputs when setting an environment variable */ r = uv_os_setenv(NULL, "foo"); ASSERT_EQ(r, UV_EINVAL); From 6912038d7281b8cd7f4647a7007771eff4b3fb39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 8 Mar 2024 09:38:22 +0100 Subject: [PATCH 518/713] unix,fs: fix realpath calls that use the system allocator Make sure we allocate the memory with uv__malloc so it's in turn freed with uv__free. Fixes: https://github.com/libuv/libuv/issues/4329 --- src/unix/fs.c | 13 +++++++++++-- src/unix/fsevents.c | 9 +++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 3a74350f0e5..7105f4cbea9 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -691,14 +691,23 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) { static ssize_t uv__fs_realpath(uv_fs_t* req) { char* buf; + char* tmp; #if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L - buf = realpath(req->path, NULL); - if (buf == NULL) + tmp = realpath(req->path, NULL); + if (tmp == NULL) return -1; + buf = uv__strdup(tmp); + free(tmp); /* _Not_ uv__free. */ + if (buf == NULL) { + errno = ENOMEM; + return -1; + } #else ssize_t len; + (void)tmp; + len = uv__fs_pathmax_size(req->path); buf = uv__malloc(len + 1); diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c index df703f3635f..5efe495e694 100644 --- a/src/unix/fsevents.c +++ b/src/unix/fsevents.c @@ -793,6 +793,7 @@ int uv__cf_loop_signal(uv_loop_t* loop, /* Runs in UV loop to initialize handle */ int uv__fsevents_init(uv_fs_event_t* handle) { + char* buf; int err; uv__cf_loop_state_t* state; @@ -801,9 +802,13 @@ int uv__fsevents_init(uv_fs_event_t* handle) { return err; /* Get absolute path to file */ - handle->realpath = realpath(handle->path, NULL); - if (handle->realpath == NULL) + buf = realpath(handle->path, NULL); + if (buf == NULL) return UV__ERR(errno); + handle->realpath = uv__strdup(buf); + free(buf); /* _Not_ uv__free. */ + if (handle->realpath == NULL) + return UV_ENOMEM; handle->realpath_len = strlen(handle->realpath); /* Initialize event queue */ From fa6745b4f26470dae5ee4fcbb1ee082f780277e0 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Tue, 12 Mar 2024 18:16:49 +0800 Subject: [PATCH 519/713] sunos: sync tcp keep-alive with other unices (#4337) --- src/unix/tcp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 799fca77aa5..56f2c04b328 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -507,11 +507,11 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) return UV__ERR(errno); - intvl = idle/3; + intvl = 10; /* required at least 10 seconds */ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) return UV__ERR(errno); - cnt = 3; + cnt = 1; /* 1 retry, ensure (TCP_KEEPINTVL * TCP_KEEPCNT) is 10 seconds */ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt))) return UV__ERR(errno); #else @@ -524,9 +524,7 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { /* Note that the consequent probes will not be sent at equal intervals on Solaris, * but will be sent using the exponential backoff algorithm. */ - intvl = idle/3; - cnt = 3; - int time_to_abort = intvl * cnt; + int time_to_abort = 10*1000; /* 10 seconds, kernel expects milliseconds */ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort))) return UV__ERR(errno); #endif @@ -543,7 +541,7 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { #endif #ifdef TCP_KEEPINTVL - intvl = 1; /* 1 second; same as default on Win32 */ + intvl = 1; /* 1 second; same as default on Win32 */ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) return UV__ERR(errno); #endif From b0816180e3bbf1499b15043703b1cbf1897debb1 Mon Sep 17 00:00:00 2001 From: Farzin Monsef Date: Thu, 14 Mar 2024 12:05:25 +0330 Subject: [PATCH 520/713] linux: fix /proc/self/stat executable name parsing (#4353) - The filename of the executable may contain both spaces and parentheses - Use uv__slurp instead of open/read/close --- src/unix/linux.c | 41 ++++++++++------------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index f0c65bbcce0..960af5c9af1 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1630,36 +1630,17 @@ uint64_t uv__hrtime(uv_clocktype_t type) { int uv_resident_set_memory(size_t* rss) { char buf[1024]; const char* s; - ssize_t n; long val; - int fd; + int rc; int i; - - do - fd = open("/proc/self/stat", O_RDONLY); - while (fd == -1 && errno == EINTR); - - if (fd == -1) - return UV__ERR(errno); - - do - n = read(fd, buf, sizeof(buf) - 1); - while (n == -1 && errno == EINTR); - - uv__close(fd); - if (n == -1) - return UV__ERR(errno); - buf[n] = '\0'; - - s = strchr(buf, ' '); - if (s == NULL) - goto err; - - s += 1; - if (*s != '(') - goto err; - - s = strchr(s, ')'); + + /* rss: 24th element */ + rc = uv__slurp("/proc/self/stat", buf, sizeof(buf)); + if (rc < 0) + return rc; + + /* find the last ')' */ + s = strrchr(buf, ')'); if (s == NULL) goto err; @@ -1671,9 +1652,7 @@ int uv_resident_set_memory(size_t* rss) { errno = 0; val = strtol(s, NULL, 10); - if (errno != 0) - goto err; - if (val < 0) + if (val < 0 || errno != 0) goto err; *rss = val * getpagesize(); From 91ba13054a47dd114c0f46ca54e75bc347cb058a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 17 Mar 2024 15:53:23 +0100 Subject: [PATCH 521/713] test,ci: fix [AM]San, disable ASLR (#4365) The kernel that ships with the new Ubuntu 22.04 CI image seems to have a PIE slide that is bigger than the sanitizer runtimes can handle. It makes ASan fail with thousands of "AddressSanitizer:DEADLYSIGNAL" warnings, and MSan error with complaints about memory accesses outside known ranges. Disabling address space layout randomization fixes both. This commit also fixes a small bug in the platform_output test where the cgroups v1 logic did not handle the "unlimited quota" special case properly. Ubuntu 20.04 still uses cgroups v1. --- .github/workflows/sanitizer.yml | 5 +++++ test/test-platform-output.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 4fca161d9ee..fb2f1eb2869 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -23,6 +23,11 @@ jobs: - name: Envinfo run: npx envinfo + # [AM]SAN fail on newer kernels due to a bigger PIE slide + - name: Disable ASLR + run: | + sudo sysctl -w kernel.randomize_va_space=0 + - name: ASAN Build run: | mkdir build-asan diff --git a/test/test-platform-output.c b/test/test-platform-output.c index f5218c581d1..4e5300da037 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -110,7 +110,7 @@ TEST_IMPL(platform_output) { if (cgroup_version == 0) { file = fopen("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us", "r"); if (file) { - if (fscanf(file, "%lu", "a) == 1 && quota > 0) { + if (fscanf(file, "%lu", "a) == 1 && quota > 0 && quota < ~0ULL) { fclose(file); file = fopen("/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us", "r"); if (file && fscanf(file, "%lu", &period) == 1) { From e0c5fc871428daba63df52a7dbe3c33850542f6f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 20 Mar 2024 12:09:37 +0100 Subject: [PATCH 522/713] win: remove _alloca usage (#4361) Remove it since it can cause stack overflows. Use heap allocation instead. Fixes: https://github.com/libuv/libuv/issues/4348 --- src/win/process.c | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index f46f34289e8..9d48ddc6f84 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -26,7 +26,6 @@ #include #include #include -#include /* _alloca */ #include "uv.h" #include "internal.h" @@ -598,11 +597,9 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { } -int env_strncmp(const wchar_t* a, int na, const wchar_t* b) { +static int env_strncmp(const wchar_t* a, int na, const wchar_t* b) { wchar_t* a_eq; wchar_t* b_eq; - wchar_t* A; - wchar_t* B; int nb; int r; @@ -617,27 +614,8 @@ int env_strncmp(const wchar_t* a, int na, const wchar_t* b) { assert(b_eq); nb = b_eq - b; - A = _alloca((na+1) * sizeof(wchar_t)); - B = _alloca((nb+1) * sizeof(wchar_t)); - - r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na); - assert(r==na); - A[na] = L'\0'; - r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb); - assert(r==nb); - B[nb] = L'\0'; - - for (;;) { - wchar_t AA = *A++; - wchar_t BB = *B++; - if (AA < BB) { - return -1; - } else if (AA > BB) { - return 1; - } else if (!AA && !BB) { - return 0; - } - } + r = CompareStringOrdinal(a, na, b, nb, /*case insensitive*/TRUE); + return r - CSTR_EQUAL; } @@ -676,6 +654,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { WCHAR* dst_copy; WCHAR** ptr_copy; WCHAR** env_copy; + char* p; size_t required_vars_value_len[ARRAY_SIZE(required_vars)]; /* first pass: determine size in UTF-16 */ @@ -691,11 +670,13 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { } /* second pass: copy to UTF-16 environment block */ - dst_copy = uv__malloc(env_len * sizeof(WCHAR)); - if (dst_copy == NULL && env_len > 0) { + len = env_block_count * sizeof(WCHAR*); + p = uv__malloc(len + env_len * sizeof(WCHAR)); + if (p == NULL) { return UV_ENOMEM; } - env_copy = _alloca(env_block_count * sizeof(WCHAR*)); + env_copy = (void*) &p[0]; + dst_copy = (void*) &p[len]; ptr = dst_copy; ptr_copy = env_copy; @@ -745,7 +726,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { /* final pass: copy, in sort order, and inserting required variables */ dst = uv__malloc((1+env_len) * sizeof(WCHAR)); if (!dst) { - uv__free(dst_copy); + uv__free(p); return UV_ENOMEM; } @@ -790,7 +771,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { assert(env_len == (size_t) (ptr - dst)); *ptr = L'\0'; - uv__free(dst_copy); + uv__free(p); *dst_ptr = dst; return 0; } From cc23e204d76688053c63fd1698435bc4b68aab6a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 20 Mar 2024 18:39:18 +0100 Subject: [PATCH 523/713] unix: reinstate preadv/pwritev fallback code (#4345) I removed the fallback code back in October but it prevents Node.js from upgrading libuv in their v20.x release line because they support systems older than we do. Bring back a dlsym-based fallback path. Fixes: https://github.com/libuv/libuv/issues/4332 --- src/unix/fs.c | 125 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 112 insertions(+), 13 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 7105f4cbea9..a6b2aa25c0b 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -82,17 +83,6 @@ # include #endif -#if defined(__CYGWIN__) || \ - (defined(__HAIKU__) && B_HAIKU_VERSION < B_HAIKU_VERSION_1_PRE_BETA_5) || \ - (defined(__sun) && !defined(__illumos__)) || \ - (defined(__APPLE__) && !TARGET_OS_IPHONE && \ - MAC_OS_X_VERSION_MIN_REQUIRED < 110000) -#define preadv(fd, bufs, nbufs, off) \ - pread(fd, (bufs)->iov_base, (bufs)->iov_len, off) -#define pwritev(fd, bufs, nbufs, off) \ - pwrite(fd, (bufs)->iov_base, (bufs)->iov_len, off) -#endif - #if defined(_AIX) && _XOPEN_SOURCE <= 600 extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */ #endif @@ -406,6 +396,115 @@ static ssize_t uv__fs_open(uv_fs_t* req) { } +static ssize_t uv__preadv_or_pwritev_emul(int fd, + const struct iovec* bufs, + size_t nbufs, + off_t off, + int is_pread) { + ssize_t total; + ssize_t r; + size_t i; + size_t n; + void* p; + + total = 0; + for (i = 0; i < (size_t) nbufs; i++) { + p = bufs[i].iov_base; + n = bufs[i].iov_len; + + do + if (is_pread) + r = pread(fd, p, n, off); + else + r = pwrite(fd, p, n, off); + while (r == -1 && errno == EINTR); + + if (r == -1) { + if (total > 0) + return total; + return -1; + } + + off += r; + total += r; + + if ((size_t) r < n) + return total; + } + + return total; +} + + +#ifdef __linux__ +typedef int uv__iovcnt; +#else +typedef size_t uv__iovcnt; +#endif + + +static ssize_t uv__preadv_emul(int fd, + const struct iovec* bufs, + uv__iovcnt nbufs, + off_t off) { + return uv__preadv_or_pwritev_emul(fd, bufs, nbufs, off, /*is_pread*/1); +} + + +static ssize_t uv__pwritev_emul(int fd, + const struct iovec* bufs, + uv__iovcnt nbufs, + off_t off) { + return uv__preadv_or_pwritev_emul(fd, bufs, nbufs, off, /*is_pread*/0); +} + + +/* The function pointer cache is an uintptr_t because _Atomic void* + * doesn't work on macos/ios/etc... + */ +static ssize_t uv__preadv_or_pwritev(int fd, + const struct iovec* bufs, + size_t nbufs, + off_t off, + _Atomic uintptr_t* cache, + int is_pread) { + ssize_t (*f)(int, const struct iovec*, uv__iovcnt, off_t); + void* p; + + p = (void*) atomic_load_explicit(cache, memory_order_relaxed); + if (p == NULL) { +#ifdef RTLD_DEFAULT + p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev"); + dlerror(); /* Clear errors. */ +#endif /* RTLD_DEFAULT */ + if (p == NULL) + p = is_pread ? uv__preadv_emul : uv__pwritev_emul; + atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed); + } + + f = p; + return f(fd, bufs, nbufs, off); +} + + +static ssize_t uv__preadv(int fd, + const struct iovec* bufs, + size_t nbufs, + off_t off) { + static _Atomic uintptr_t cache; + return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/1); +} + + +static ssize_t uv__pwritev(int fd, + const struct iovec* bufs, + size_t nbufs, + off_t off) { + static _Atomic uintptr_t cache; + return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/0); +} + + static ssize_t uv__fs_read(uv_fs_t* req) { const struct iovec* bufs; unsigned int iovmax; @@ -433,7 +532,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) { if (nbufs == 1) r = pread(fd, bufs->iov_base, bufs->iov_len, off); else if (nbufs > 1) - r = preadv(fd, bufs, nbufs, off); + r = uv__preadv(fd, bufs, nbufs, off); } #ifdef __PASE__ @@ -1121,7 +1220,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) { if (nbufs == 1) r = pwrite(fd, bufs->iov_base, bufs->iov_len, off); else if (nbufs > 1) - r = pwritev(fd, bufs, nbufs, off); + r = uv__pwritev(fd, bufs, nbufs, off); } return r; From 3ecce914105590e6112cd0c6d4f6b30ac6a6c24f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 21 Mar 2024 09:23:08 +0100 Subject: [PATCH 524/713] linux: don't delay EPOLL_CTL_DEL operations (#4328) Perform EPOLL_CTL_DEL immediately instead of going through io_uring's submit queue, otherwise the file descriptor may be closed by the time the kernel starts the operation. Fixes: https://github.com/libuv/libuv/issues/4323 --- CMakeLists.txt | 1 + Makefile.am | 1 + src/unix/linux.c | 93 +++++++++++++++--------------- test/test-iouring-pollhup.c | 111 ++++++++++++++++++++++++++++++++++++ test/test-list.h | 4 ++ 5 files changed, 163 insertions(+), 47 deletions(-) create mode 100644 test/test-iouring-pollhup.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 62609708636..f5bb871b533 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -566,6 +566,7 @@ if(LIBUV_BUILD_TESTS) test/test-hrtime.c test/test-idle.c test/test-idna.c + test/test-iouring-pollhup.c test/test-ip4-addr.c test/test-ip6-addr.c test/test-ip-name.c diff --git a/Makefile.am b/Makefile.am index a14228da3bf..c344f7dc9f4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -198,6 +198,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-hrtime.c \ test/test-idle.c \ test/test-idna.c \ + test/test-iouring-pollhup.c \ test/test-ip4-addr.c \ test/test-ip6-addr.c \ test/test-ip-name.c \ diff --git a/src/unix/linux.c b/src/unix/linux.c index 960af5c9af1..8fdcb12c7ea 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -712,23 +712,17 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { * This avoids a problem where the same file description remains open * in another process, causing repeated junk epoll events. * + * Perform EPOLL_CTL_DEL immediately instead of going through + * io_uring's submit queue, otherwise the file descriptor may + * be closed by the time the kernel starts the operation. + * * We pass in a dummy epoll_event, to work around a bug in old kernels. * * Work around a bug in kernels 3.10 to 3.19 where passing a struct that * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. */ memset(&dummy, 0, sizeof(dummy)); - - if (inv == NULL) { - epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy); - } else { - uv__epoll_ctl_prep(loop->backend_fd, - &lfields->ctl, - inv->prep, - EPOLL_CTL_DEL, - fd, - &dummy); - } + epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy); } @@ -1215,6 +1209,10 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { } +/* Only for EPOLL_CTL_ADD and EPOLL_CTL_MOD. EPOLL_CTL_DEL should always be + * executed immediately, otherwise the file descriptor may have been closed + * by the time the kernel starts the operation. + */ static void uv__epoll_ctl_prep(int epollfd, struct uv__iou* ctl, struct epoll_event (*events)[256], @@ -1226,45 +1224,28 @@ static void uv__epoll_ctl_prep(int epollfd, uint32_t mask; uint32_t slot; - if (ctl->ringfd == -1) { - if (!epoll_ctl(epollfd, op, fd, e)) - return; - - if (op == EPOLL_CTL_DEL) - return; /* Ignore errors, may be racing with another thread. */ - - if (op != EPOLL_CTL_ADD) - abort(); - - if (errno != EEXIST) - abort(); - - /* File descriptor that's been watched before, update event mask. */ - if (!epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, e)) - return; + assert(op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD); + assert(ctl->ringfd != -1); - abort(); - } else { - mask = ctl->sqmask; - slot = (*ctl->sqtail)++ & mask; + mask = ctl->sqmask; + slot = (*ctl->sqtail)++ & mask; - pe = &(*events)[slot]; - *pe = *e; + pe = &(*events)[slot]; + *pe = *e; - sqe = ctl->sqe; - sqe = &sqe[slot]; + sqe = ctl->sqe; + sqe = &sqe[slot]; - memset(sqe, 0, sizeof(*sqe)); - sqe->addr = (uintptr_t) pe; - sqe->fd = epollfd; - sqe->len = op; - sqe->off = fd; - sqe->opcode = UV__IORING_OP_EPOLL_CTL; - sqe->user_data = op | slot << 2 | (int64_t) fd << 32; + memset(sqe, 0, sizeof(*sqe)); + sqe->addr = (uintptr_t) pe; + sqe->fd = epollfd; + sqe->len = op; + sqe->off = fd; + sqe->opcode = UV__IORING_OP_EPOLL_CTL; + sqe->user_data = op | slot << 2 | (int64_t) fd << 32; - if ((*ctl->sqhead & mask) == (*ctl->sqtail & mask)) - uv__epoll_ctl_flush(epollfd, ctl, events); - } + if ((*ctl->sqhead & mask) == (*ctl->sqtail & mask)) + uv__epoll_ctl_flush(epollfd, ctl, events); } @@ -1405,8 +1386,22 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w->events = w->pevents; e.events = w->pevents; e.data.fd = w->fd; + fd = w->fd; + + if (ctl->ringfd != -1) { + uv__epoll_ctl_prep(epollfd, ctl, &prep, op, fd, &e); + continue; + } + + if (!epoll_ctl(epollfd, op, fd, &e)) + continue; - uv__epoll_ctl_prep(epollfd, ctl, &prep, op, w->fd, &e); + assert(op == EPOLL_CTL_ADD); + assert(errno == EEXIST); + + /* File descriptor that's been watched before, update event mask. */ + if (epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &e)) + abort(); } inv.events = events; @@ -1494,8 +1489,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * * Ignore all errors because we may be racing with another thread * when the file descriptor is closed. + * + * Perform EPOLL_CTL_DEL immediately instead of going through + * io_uring's submit queue, otherwise the file descriptor may + * be closed by the time the kernel starts the operation. */ - uv__epoll_ctl_prep(epollfd, ctl, &prep, EPOLL_CTL_DEL, fd, pe); + epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, pe); continue; } diff --git a/test/test-iouring-pollhup.c b/test/test-iouring-pollhup.c new file mode 100644 index 00000000000..342789aa7d9 --- /dev/null +++ b/test/test-iouring-pollhup.c @@ -0,0 +1,111 @@ +/* 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" + +#ifdef _WIN32 + +TEST_IMPL(iouring_pollhup) { + RETURN_SKIP("Not on Windows."); +} + +#else /* !_WIN32 */ + +#include /* close() */ + +static uv_pipe_t p1; +static uv_pipe_t p2; +static uv_idle_t idle_handle; +static int iters; +static int duped_fd; +static int newpipefds[2]; + +static void alloc_buffer(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[32]; + *buf = uv_buf_init(slab, sizeof(slab)); +} + +static void read_data2(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf) { + if (nread < 0) { + ASSERT_EQ(nread, UV_EOF); + ASSERT_OK(close(duped_fd)); + duped_fd = -1; + uv_close((uv_handle_t*) &p2, NULL); + uv_close((uv_handle_t*) &idle_handle, NULL); + } else { + /* If nread == 0 is because of POLLHUP received still from pipefds[0] file + * description which is still referenced in duped_fd. It should not happen + * if close(p1) was called after EPOLL_CTL_DEL. + */ + ASSERT_GT(nread, 0); + } +} + +static void idle_cb(uv_idle_t* handle) { + if (++iters == 1) { + ASSERT_OK(uv_pipe_open(&p2, newpipefds[0])); + ASSERT_OK(uv_read_start((uv_stream_t*) &p2, alloc_buffer, read_data2)); + } else { + ASSERT_OK(uv_idle_stop(handle)); + ASSERT_OK(close(newpipefds[1])); + newpipefds[1] = -1; + } +} + +static void read_data(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf) { + ASSERT_EQ(nread, UV_EOF); + uv_close((uv_handle_t*) stream, NULL); + ASSERT_OK(uv_idle_start(&idle_handle, idle_cb)); +} + +TEST_IMPL(iouring_pollhup) { + uv_loop_t* loop; + int pipefds[2]; + + loop = uv_default_loop(); + ASSERT_OK(uv_pipe_init(loop, &p1, 0)); + ASSERT_OK(uv_pipe_init(loop, &p2, 0)); + ASSERT_OK(uv_idle_init(loop, &idle_handle)); + ASSERT_OK(pipe(pipefds)); + ASSERT_OK(pipe(newpipefds)); + + ASSERT_OK(uv_pipe_open(&p1, pipefds[0])); + duped_fd = dup(pipefds[0]); + ASSERT_NE(duped_fd, -1); + + ASSERT_OK(uv_read_start((uv_stream_t*) &p1, alloc_buffer, read_data)); + ASSERT_OK(close(pipefds[1])); /* Close write end, generate POLLHUP. */ + pipefds[1] = -1; + + ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} + +#endif /* !_WIN32 */ diff --git a/test/test-list.h b/test/test-list.h index d30f02faa85..84c885ccc78 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -563,6 +563,8 @@ TEST_DECLARE (fork_threadpool_queue_work_simple) #endif #endif +TEST_DECLARE (iouring_pollhup) + TEST_DECLARE (idna_toascii) TEST_DECLARE (utf8_decode1) TEST_DECLARE (utf8_decode1_overrun) @@ -1204,6 +1206,8 @@ TASK_LIST_START #endif #endif + TEST_ENTRY (iouring_pollhup) + TEST_ENTRY (utf8_decode1) TEST_ENTRY (utf8_decode1_overrun) TEST_ENTRY (uname) From f55628eed00910f4c49551c54a58a074948c6bd1 Mon Sep 17 00:00:00 2001 From: tgolang <154592711+tgolang@users.noreply.github.com> Date: Sat, 23 Mar 2024 03:10:41 +0800 Subject: [PATCH 525/713] doc: fix typos in ChangeLog (#4355) Signed-off-by: tgolang --- ChangeLog | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6c9e351a6e4..f23fa226d31 100644 --- a/ChangeLog +++ b/ChangeLog @@ -911,7 +911,7 @@ Changes since version 1.41.0: * zos: treat __rfim_utok as binary (Shuowang (Wayne) Zhang) -* zos: use execvpe() to set environ explictly (Shuowang (Wayne) Zhang) +* zos: use execvpe() to set environ explicitly (Shuowang (Wayne) Zhang) * zos: use custom proctitle implementation (Shuowang (Wayne) Zhang) @@ -3417,7 +3417,7 @@ Changes since version 1.9.1: * zos: implement uv__io_check_fd (John Barboza) -* unix: unneccessary use const qualifier in container_of (John Barboza) +* unix: unnecessary use const qualifier in container_of (John Barboza) * win,tty: add support for ANSI codes in win10 v1511 (Imran Iqbal) @@ -5520,7 +5520,7 @@ Changes since version 0.11.8: is an int64_t, and no longer an int. (Bert Belder) * process: make uv_spawn() return some types of errors immediately on windows, - instead of passing the error code the the exit callback. This brings it on + instead of passing the error code the exit callback. This brings it on par with libuv's behavior on unix. (Bert Belder) From 6adeeacee7eb997d60552351b43d65b494745700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 22 Mar 2024 22:11:23 +0100 Subject: [PATCH 526/713] unix,win: error on zero delay tcp keepalive Closes: https://github.com/libuv/libuv/pull/4350 Closes: https://github.com/libuv/libuv/issues/3487 --- docs/src/tcp.rst | 4 ++++ src/unix/tcp.c | 4 ++-- src/win/tcp.c | 16 +++++++++++----- test/test-tcp-flags.c | 9 ++++++++- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/docs/src/tcp.rst b/docs/src/tcp.rst index cccc86bbfc0..f351214ff92 100644 --- a/docs/src/tcp.rst +++ b/docs/src/tcp.rst @@ -65,6 +65,10 @@ API at the end of this procedure, then the handle is destroyed with a ``UV_ETIMEDOUT`` error passed to the corresponding callback. + If `delay` is less than 1 then ``UV_EINVAL`` is returned. + + .. versionchanged:: 1.49.0 If `delay` is less than 1 then ``UV_EINVAL``` is returned. + .. c:function:: int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) Enable / disable simultaneous asynchronous accept requests that are diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 56f2c04b328..f3bef304bba 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -467,8 +467,8 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { if (!on) return 0; - if (delay == 0) - return -1; + if (delay < 1) + return UV_EINVAL; #ifdef __sun /* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual diff --git a/src/win/tcp.c b/src/win/tcp.c index 187f36e2a61..c2efc4815f4 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -58,11 +58,17 @@ static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsign return WSAGetLastError(); } - if (enable && setsockopt(socket, - IPPROTO_TCP, - TCP_KEEPALIVE, - (const char*)&delay, - sizeof delay) == -1) { + if (!enable) + return 0; + + if (delay < 1) + return UV_EINVAL; + + if (setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPALIVE, + (const char*)&delay, + sizeof delay) == -1) { return WSAGetLastError(); } diff --git a/test/test-tcp-flags.c b/test/test-tcp-flags.c index 30178d706d9..16218a27f0a 100644 --- a/test/test-tcp-flags.c +++ b/test/test-tcp-flags.c @@ -33,7 +33,8 @@ TEST_IMPL(tcp_flags) { loop = uv_default_loop(); - r = uv_tcp_init(loop, &handle); + /* Use _ex to make sure the socket is created. */ + r = uv_tcp_init_ex(loop, &handle, AF_INET); ASSERT_OK(r); r = uv_tcp_nodelay(&handle, 1); @@ -42,6 +43,12 @@ TEST_IMPL(tcp_flags) { r = uv_tcp_keepalive(&handle, 1, 60); ASSERT_OK(r); + r = uv_tcp_keepalive(&handle, 0, 0); + ASSERT_OK(r); + + r = uv_tcp_keepalive(&handle, 1, 0); + ASSERT_EQ(r, UV_EINVAL); + uv_close((uv_handle_t*)&handle, NULL); r = uv_run(loop, UV_RUN_DEFAULT); From abc9767034d7c065e6a861cc398a580d0f94e24f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 25 Mar 2024 11:57:52 +0100 Subject: [PATCH 527/713] win: simplify uv_once implementation * win: simplify uv_once implementation InitOnceExecuteOnce is available in Windows >= Vista. Ref: https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-initonceexecuteonce --- include/uv/win.h | 4 ++-- src/win/thread.c | 44 +++++++++++--------------------------------- 2 files changed, 13 insertions(+), 35 deletions(-) diff --git a/include/uv/win.h b/include/uv/win.h index f4adaa216c6..12ac53b4f21 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -290,8 +290,8 @@ typedef struct { #define UV_ONCE_INIT { 0, NULL } typedef struct uv_once_s { - unsigned char ran; - HANDLE event; + unsigned char unused; + INIT_ONCE init_once; } uv_once_t; /* Platform-specific definitions for uv_spawn support. */ diff --git a/src/win/thread.c b/src/win/thread.c index 57c25e8f5a8..bf39b88633b 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -32,45 +32,23 @@ #include "uv.h" #include "internal.h" -static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) { - DWORD result; - HANDLE existing_event, created_event; - - created_event = CreateEvent(NULL, 1, 0, NULL); - if (created_event == 0) { - /* Could fail in a low-memory situation? */ - uv_fatal_error(GetLastError(), "CreateEvent"); - } +typedef void (*uv__once_cb)(void); - existing_event = InterlockedCompareExchangePointer(&guard->event, - created_event, - NULL); +typedef struct { + uv__once_cb callback; +} uv__once_data_t; - if (existing_event == NULL) { - /* We won the race */ - callback(); +static BOOL WINAPI uv__once_inner(INIT_ONCE *once, void* param, void** context) { + uv__once_data_t* data = param; - result = SetEvent(created_event); - assert(result); - guard->ran = 1; + data->callback(); - } else { - /* We lost the race. Destroy the event we created and wait for the existing - * one to become signaled. */ - CloseHandle(created_event); - result = WaitForSingleObject(existing_event, INFINITE); - assert(result == WAIT_OBJECT_0); - } + return TRUE; } - -void uv_once(uv_once_t* guard, void (*callback)(void)) { - /* Fast case - avoid WaitForSingleObject. */ - if (guard->ran) { - return; - } - - uv__once_inner(guard, callback); +void uv_once(uv_once_t* guard, uv__once_cb callback) { + uv__once_data_t data = { .callback = callback }; + InitOnceExecuteOnce(&guard->init_once, uv__once_inner, (void*) &data, NULL); } From d05ed869bb4cea9ba703854dc0ee1f458153ff99 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 25 Mar 2024 12:44:52 +0100 Subject: [PATCH 528/713] doc: correct udp socket options documentation (#4371) uv_udp_init() creates the UDP socket lazily but to set socket options there must be, well, a socket to set the options on. Document how and when that requirement is met. Fixes: https://github.com/libuv/libuv/issues/4370 --- docs/src/udp.rst | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/src/udp.rst b/docs/src/udp.rst index d7da95edd50..9e075d7b5db 100644 --- a/docs/src/udp.rst +++ b/docs/src/udp.rst @@ -285,7 +285,9 @@ API local sockets. :param handle: UDP handle. Should have been initialized with - :c:func:`uv_udp_init`. + :c:func:`uv_udp_init_ex` as either ``AF_INET`` or ``AF_INET6``, or have + been bound to an address explicitly with :c:func:`uv_udp_bind`, or + implicitly with :c:func:`uv_udp_send()` or :c:func:`uv_udp_recv_start`. :param on: 1 for on, 0 for off. @@ -296,7 +298,9 @@ API Set the multicast ttl. :param handle: UDP handle. Should have been initialized with - :c:func:`uv_udp_init`. + :c:func:`uv_udp_init_ex` as either ``AF_INET`` or ``AF_INET6``, or have + been bound to an address explicitly with :c:func:`uv_udp_bind`, or + implicitly with :c:func:`uv_udp_send()` or :c:func:`uv_udp_recv_start`. :param ttl: 1 through 255. @@ -307,7 +311,9 @@ API Set the multicast interface to send or receive data on. :param handle: UDP handle. Should have been initialized with - :c:func:`uv_udp_init`. + :c:func:`uv_udp_init_ex` as either ``AF_INET`` or ``AF_INET6``, or have + been bound to an address explicitly with :c:func:`uv_udp_bind`, or + implicitly with :c:func:`uv_udp_send()` or :c:func:`uv_udp_recv_start`. :param interface_addr: interface address. @@ -318,7 +324,9 @@ API Set broadcast on or off. :param handle: UDP handle. Should have been initialized with - :c:func:`uv_udp_init`. + :c:func:`uv_udp_init_ex` as either ``AF_INET`` or ``AF_INET6``, or have + been bound to an address explicitly with :c:func:`uv_udp_bind`, or + implicitly with :c:func:`uv_udp_send()` or :c:func:`uv_udp_recv_start`. :param on: 1 for on, 0 for off. @@ -329,7 +337,9 @@ API Set the time to live. :param handle: UDP handle. Should have been initialized with - :c:func:`uv_udp_init`. + :c:func:`uv_udp_init_ex` as either ``AF_INET`` or ``AF_INET6``, or have + been bound to an address explicitly with :c:func:`uv_udp_bind`, or + implicitly with :c:func:`uv_udp_send()` or :c:func:`uv_udp_recv_start`. :param ttl: 1 through 255. From 77e4cd5b184faedec80378049fe5edba084d310b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 25 Mar 2024 12:45:23 +0100 Subject: [PATCH 529/713] linux: don't use sendmmsg() for single datagrams (#4366) Benchmarking shows that sendmsg() is persistently around 1% faster for single datagrams, and that kind of stands to reason because there is less setup overhead, and the kernel has to copy in less data. Fixes: https://github.com/libuv/libuv/issues/4320 --- src/unix/udp.c | 134 +++++++++++++++++++++++++++---------------------- 1 file changed, 73 insertions(+), 61 deletions(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index 5dcd5a4da7d..ae09f3a7f5a 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -275,8 +275,61 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { && handle->recv_cb != NULL); } -static void uv__udp_sendmsg(uv_udp_t* handle) { +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__) +static void uv__udp_sendmsg_many(uv_udp_t* handle) { uv_udp_send_t* req; struct mmsghdr h[20]; struct mmsghdr* p; @@ -285,16 +338,11 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { size_t pkts; size_t i; - if (uv__queue_empty(&handle->write_queue)) - return; - 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)) { - assert(q != NULL); req = uv__queue_data(q, uv_udp_send_t, queue); - assert(req != NULL); p = &h[pkts]; memset(p, 0, sizeof(*p)); @@ -328,10 +376,7 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { for (i = 0, q = uv__queue_head(&handle->write_queue); i < pkts && q != &handle->write_queue; ++i, q = uv__queue_head(&handle->write_queue)) { - assert(q != NULL); req = uv__queue_data(q, uv_udp_send_t, queue); - assert(req != NULL); - req->status = UV__ERR(errno); uv__queue_remove(&req->queue); uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); @@ -346,10 +391,7 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { 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)) { - assert(q != NULL); req = uv__queue_data(q, uv_udp_send_t, queue); - assert(req != NULL); - req->status = req->bufs[0].len; /* Sending a datagram is an atomic operation: either all data @@ -364,61 +406,31 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { /* 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); -#else /* __linux__ || ____FreeBSD__ */ - uv_udp_send_t* req; - struct msghdr h; - struct uv__queue* q; - ssize_t size; - - while (!uv__queue_empty(&handle->write_queue)) { - q = uv__queue_head(&handle->write_queue); - assert(q != NULL); - req = uv__queue_data(q, uv_udp_send_t, queue); - assert(req != NULL); + uv__io_feed(handle->loop, &handle->io_watcher); +} +#endif /* __linux__ || ____FreeBSD__ */ - 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; +static void uv__udp_sendmsg(uv_udp_t* handle) { + struct uv__queue* q; + uv_udp_send_t* req; - do { - size = sendmsg(handle->io_watcher.fd, &h, 0); - } while (size == -1 && errno == EINTR); + if (uv__queue_empty(&handle->write_queue)) + return; - if (size == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) - break; - } + q = uv__queue_head(&handle->write_queue); + req = uv__queue_data(q, uv_udp_send_t, queue); - req->status = (size == -1 ? UV__ERR(errno) : size); +#if defined(__linux__) || defined(__FreeBSD__) + /* 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 - /* 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); - } -#endif /* __linux__ || ____FreeBSD__ */ + return uv__udp_sendmsg_one(handle, req); } /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional From 4fce06ec96283225ceedbf181d7211830c173ee3 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 25 Mar 2024 12:45:40 +0100 Subject: [PATCH 530/713] unix: fix fd leaks in SCM_RIGHTS error path (#4358) The file descriptor leak in the inner path was pointed out by @theanarkh and I subsequently spotted another one in the outer loop. Rewrite the function to process all control messages. Refs: https://github.com/libuv/libuv/pull/4357 --- src/unix/stream.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 28c4d5463c4..e369ea69c59 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -979,11 +979,13 @@ static int uv__stream_queue_fd(uv_stream_t* stream, int fd) { static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { struct cmsghdr* cmsg; + char* p; + char* pe; int fd; int err; - size_t i; size_t count; + err = 0; for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { if (cmsg->cmsg_type != SCM_RIGHTS) { fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n", @@ -996,24 +998,26 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { assert(count % sizeof(fd) == 0); count /= sizeof(fd); - for (i = 0; i < count; i++) { - memcpy(&fd, (char*) CMSG_DATA(cmsg) + i * sizeof(fd), sizeof(fd)); - /* Already has accepted fd, queue now */ - if (stream->accepted_fd != -1) { - err = uv__stream_queue_fd(stream, fd); - if (err != 0) { - /* Close rest */ - for (; i < count; i++) - uv__close(fd); - return err; - } - } else { - stream->accepted_fd = fd; + p = (void*) CMSG_DATA(cmsg); + pe = p + count * sizeof(fd); + + while (p < pe) { + memcpy(&fd, p, sizeof(fd)); + p += sizeof(fd); + + if (err == 0) { + if (stream->accepted_fd == -1) + stream->accepted_fd = fd; + else + err = uv__stream_queue_fd(stream, fd); } + + if (err != 0) + uv__close(fd); } } - return 0; + return err; } From 46c0e1769bf24656be7add69562ea8617ab75265 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 31 Mar 2024 17:25:13 +0200 Subject: [PATCH 531/713] win: robustify uv_os_getenv() error checking (#4339) Make it less likely for the thread-local error value to get clobbered between performing the operation and checking the result. Refs: https://github.com/libuv/libuv/issues/4338 --- src/win/util.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/win/util.c b/src/win/util.c index a96cb915930..c4dd8bf741f 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1259,6 +1259,9 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { SetLastError(ERROR_SUCCESS); len = GetEnvironmentVariableW(name_w, var, varlen); + if (len == 0) + r = uv_translate_sys_error(GetLastError()); + if (len < varlen) break; @@ -1280,15 +1283,8 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { uv__free(name_w); name_w = NULL; - if (len == 0) { - r = GetLastError(); - if (r != ERROR_SUCCESS) { - r = uv_translate_sys_error(r); - goto fail; - } - } - - r = uv__copy_utf16_to_utf8(var, len, buffer, size); + if (r == 0) + r = uv__copy_utf16_to_utf8(var, len, buffer, size); fail: From 17219b8f39f7cd33472c94214010b603322bd0fa Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 31 Mar 2024 17:27:04 +0200 Subject: [PATCH 532/713] test: use newer ASSERT_MEM_EQ macro (#4346) Should hopefully make it easier to debug CI flakiness because currently the test sometimes fails without a clear indication why. Refs: https://github.com/libuv/libuv/issues/4106 --- test/test-fs-event.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 0ef51180dbd..8008cff4031 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -197,12 +197,13 @@ static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle, ASSERT_PTR_EQ(handle, &fs_event); ASSERT_OK(status); ASSERT(events == UV_CHANGE || events == UV_RENAME); - #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) - ASSERT_OK(strncmp(filename, file_prefix, sizeof(file_prefix) - 1)); - #else - ASSERT_NE(filename == NULL || - strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0, 0); - #endif +#if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) + ASSERT_NOT_NULL(filename); + ASSERT_MEM_EQ(filename, file_prefix, sizeof(file_prefix) - 1); +#else + if (filename != NULL) + ASSERT_MEM_EQ(filename, file_prefix, sizeof(file_prefix) - 1); +#endif if (fs_event_created + fs_event_removed == fs_event_file_count) { /* Once we've processed all create events, delete all files */ From f50ae53c422b6ec94e33ff1a8b3f6318469749bb Mon Sep 17 00:00:00 2001 From: Brad King Date: Sun, 14 Apr 2024 05:13:21 -0400 Subject: [PATCH 533/713] unix: de-duplicate conditions for using kqueue (#4378) Our platform-specific headers provide a dedicated indicator. --- src/unix/process.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index 4812a90f2f5..bc73cb694c6 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -63,11 +63,7 @@ extern char **environ; # include "zos-base.h" #endif -#if defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__NetBSD__) || \ - defined(__OpenBSD__) +#ifdef UV_HAVE_KQUEUE #include #else #define UV_USE_SIGCHLD From c0a61c3bb323724532fa9c1ac190afb36e4ae264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 14 Apr 2024 11:34:50 +0200 Subject: [PATCH 534/713] darwin: simplify uv_hrtime mach_continuous_time is available since macOS 10.12, but our minimum version is 11, so no need for a workaround. Also, prefer that to `clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)` which the documentation suggests (https://developer.apple.com/documentation/driverkit/3438077-mach_continuous_time) since the latter calls mach_timebase_info every time, unnecessarify: https://github.com/apple-open-source/macos/blob/49dcc07a40d19fa97384033a8398dae5d00d11a1/Libc/gen/clock_gettime.c#L107 --- src/unix/darwin.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/unix/darwin.c b/src/unix/darwin.c index 5e764a65ee4..009efbefaa7 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include /* _NSGetExecutablePath */ @@ -34,7 +33,6 @@ #include /* sysconf */ static uv_once_t once = UV_ONCE_INIT; -static uint64_t (*time_func)(void); static mach_timebase_info_data_t timebase; @@ -56,16 +54,12 @@ void uv__platform_loop_delete(uv_loop_t* loop) { static void uv__hrtime_init_once(void) { if (KERN_SUCCESS != mach_timebase_info(&timebase)) abort(); - - time_func = (uint64_t (*)(void)) dlsym(RTLD_DEFAULT, "mach_continuous_time"); - if (time_func == NULL) - time_func = mach_absolute_time; } uint64_t uv__hrtime(uv_clocktype_t type) { uv_once(&once, uv__hrtime_init_once); - return time_func() * timebase.numer / timebase.denom; + return mach_continuous_time() * timebase.numer / timebase.denom; } From 8083ab26e0f7c163d131a0509f876f50ed4c110d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 14 Apr 2024 11:46:35 +0200 Subject: [PATCH 535/713] mailmap: update saghul's main email address --- .mailmap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.mailmap b/.mailmap index bf12432495d..1386b6f5db8 100644 --- a/.mailmap +++ b/.mailmap @@ -47,8 +47,8 @@ Sakthipriyan Vairamani Sam Roberts San-Tai Hsu Santiago Gimeno -Saúl Ibarra Corretgé -Saúl Ibarra Corretgé +Saúl Ibarra Corretgé +Saúl Ibarra Corretgé Shigeki Ohtsu Shuowang (Wayne) Zhang TK-one From 497f3168d13ea9a92ad18c28e8282777ec2acf73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 22 Apr 2024 10:36:10 +0200 Subject: [PATCH 536/713] win: remove no longer needed define Windows 7 is no longer supported. --- src/win/tcp.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/win/tcp.c b/src/win/tcp.c index c2efc4815f4..53225e3ddc2 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -1557,11 +1557,6 @@ int uv__tcp_connect(uv_connect_t* req, return 0; } -#ifndef WSA_FLAG_NO_HANDLE_INHERIT -/* Added in Windows 7 SP1. Specify this to avoid race conditions, */ -/* but also manually clear the inherit flag in case this failed. */ -#define WSA_FLAG_NO_HANDLE_INHERIT 0x80 -#endif int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) { SOCKET server = INVALID_SOCKET; From 520eb622f012c4cc17410ba702f82aebdb93c518 Mon Sep 17 00:00:00 2001 From: josedelinux Date: Fri, 26 Apr 2024 19:57:26 +0800 Subject: [PATCH 537/713] doc: fix some typos --- docs/src/guide/processes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/guide/processes.rst b/docs/src/guide/processes.rst index 99d65c40735..024af1db486 100644 --- a/docs/src/guide/processes.rst +++ b/docs/src/guide/processes.rst @@ -333,7 +333,7 @@ to hand off their I/O to other processes. Applications include load-balancing servers, worker processes and other ways to make optimum use of CPU. libuv only supports sending **TCP sockets or other pipes** over pipes for now. -To demonstrate, we will look at a echo server implementation that hands of +To demonstrate, we will look at an echo server implementation that hands off clients to worker processes in a round-robin fashion. This program is a bit involved, and while only snippets are included in the book, it is recommended to read the full code to really understand it. From bf61390769068de603e6deec8e16623efcbe761a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Wed, 8 May 2024 04:30:30 -0500 Subject: [PATCH 538/713] linux,darwin: make `uv_fs_copyfile` behaves like `cp -r` (#4396) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit changes the timestamps in the file, the ownership and the group. Fixes: https://github.com/libuv/libuv/issues/3125 Signed-off-by: Juan José Arboleda --- src/unix/fs.c | 24 ++++++++++++++++++++++++ test/test-fs-copyfile.c | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index a6b2aa25c0b..0c6c585c6d6 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1233,6 +1233,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { uv_file dstfd; struct stat src_statsbuf; struct stat dst_statsbuf; + struct timespec times[2]; int dst_flags; int result; int err; @@ -1310,6 +1311,29 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { } } + /** + * Change the timestamps of the destination file to match the source file. + */ +#if defined(__APPLE__) + times[0] = src_statsbuf.st_atimespec; + times[1] = src_statsbuf.st_mtimespec; +#else + times[0] = src_statsbuf.st_atim; + times[1] = src_statsbuf.st_mtim; +#endif + + if (futimens(dstfd, times) == -1) { + err = UV__ERR(errno); + goto out; + } + + /* + * Change the ownership and permissions of the destination file to match the + * source file. + * `cp -p` does not care about errors here, so we don't either. + */ + fchown(dstfd, src_statsbuf.st_uid, src_statsbuf.st_gid); + if (fchmod(dstfd, src_statsbuf.st_mode) == -1) { err = UV__ERR(errno); #ifdef __linux__ diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index 3aacf12596f..f7a0c2363e8 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -46,6 +46,8 @@ static void handle_result(uv_fs_t* req) { uv_fs_t stat_req; uint64_t size; uint64_t mode; + uint64_t uid; + uint64_t gid; int r; ASSERT_EQ(req->fs_type, UV_FS_COPYFILE); @@ -56,11 +58,15 @@ static void handle_result(uv_fs_t* req) { ASSERT_OK(r); size = stat_req.statbuf.st_size; mode = stat_req.statbuf.st_mode; + uid = stat_req.statbuf.st_uid; + gid = stat_req.statbuf.st_gid; uv_fs_req_cleanup(&stat_req); r = uv_fs_stat(NULL, &stat_req, dst, NULL); ASSERT_OK(r); ASSERT_EQ(stat_req.statbuf.st_size, size); ASSERT_EQ(stat_req.statbuf.st_mode, mode); + ASSERT_EQ(stat_req.statbuf.st_uid, uid); + ASSERT_EQ(stat_req.statbuf.st_gid, gid); uv_fs_req_cleanup(&stat_req); uv_fs_req_cleanup(req); result_check_count++; From 10ccd084718f3a2e9e2776131405ee1d66cf1c29 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Mon, 20 May 2024 18:36:41 +0800 Subject: [PATCH 539/713] dragonfly: disable SO_REUSEPORT for UDP socket bindings (#4410) --------- Signed-off-by: Andy Pan --- src/unix/udp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index ae09f3a7f5a..e398509bbf2 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -436,10 +436,10 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional * refinements for programs that use multicast. * - * Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that - * are different from the BSDs: it _shares_ the port rather than steal it - * from the current listener. While useful, it's not something we can emulate - * on other platforms so we don't enable it. + * Linux as of 3.9 and DragonflyBSD 3.6 have the SO_REUSEPORT socket option but + * with semantics that are different from the BSDs: it _shares_ the port rather + * than steals it from the current listener. While useful, it's not something we + * can emulate on other platforms so we don't enable it. * * zOS does not support getsockname with SO_REUSEPORT option when using * AF_UNIX. @@ -461,7 +461,7 @@ static int uv__set_reuse(int fd) { return UV__ERR(errno); } #elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) && \ - !defined(__sun__) + !defined(__sun__) && !defined(__DragonFly__) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); #else From 287987b37c5f51797e25978212c07a7a185b0467 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Sat, 18 May 2024 21:49:37 +0800 Subject: [PATCH 540/713] test: remove the obsolete HAVE_KQUEUE macro --------- Signed-off-by: Andy Pan --- test/test-fs-event.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 8008cff4031..67910880a73 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -29,16 +29,6 @@ # include #endif -#ifndef HAVE_KQUEUE -# if defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) -# define HAVE_KQUEUE 1 -# endif -#endif - static uv_fs_event_t fs_event; static const char file_prefix[] = "fsevent-"; static const int fs_event_file_count = 16; From ab3ecf6565e29c9822d3c5edb553e606f894a854 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Sun, 19 May 2024 10:21:54 +0800 Subject: [PATCH 541/713] unix: use the presence of SOCK_* instead of OS macros for socketpair --------- Signed-off-by: Andy Pan --- src/unix/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index f3bef304bba..e4a65498eb5 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -610,7 +610,7 @@ void uv__tcp_close(uv_tcp_t* handle) { int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) { uv_os_sock_t temp[2]; int err; -#if defined(__FreeBSD__) || defined(__linux__) +#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) int flags; flags = type | SOCK_CLOEXEC; From c8d4a87f493d4fd1e63332d70823b57b7a27d21f Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Tue, 21 May 2024 16:07:38 +0800 Subject: [PATCH 542/713] bsd: support pipe2() on *BSD (#4412) --------- Signed-off-by: Andy Pan --- src/unix/pipe.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index fca364426f8..7238cd05d7f 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -487,7 +487,11 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { int uv_pipe(uv_os_fd_t fds[2], int read_flags, int write_flags) { uv_os_fd_t temp[2]; int err; -#if defined(__FreeBSD__) || defined(__linux__) +#if defined(__linux__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__DragonFly__) || \ + defined(__NetBSD__) int flags = O_CLOEXEC; if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE)) From d2d92b74a8327daf9652a9732454937f3529bd30 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Tue, 21 May 2024 19:36:49 +0800 Subject: [PATCH 543/713] unix: support SO_REUSEPORT with load balancing for TCP --- CMakeLists.txt | 1 + Makefile.am | 1 + docs/src/tcp.rst | 53 ++++++++-- include/uv.h | 13 ++- src/unix/tcp.c | 50 +++++++++ src/win/tcp.c | 6 ++ test/test-list.h | 3 + test/test-tcp-reuseport.c | 215 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 334 insertions(+), 8 deletions(-) create mode 100644 test/test-tcp-reuseport.c diff --git a/CMakeLists.txt b/CMakeLists.txt index f5bb871b533..ce086f4ae7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -644,6 +644,7 @@ if(LIBUV_BUILD_TESTS) test/test-tcp-oob.c test/test-tcp-open.c test/test-tcp-read-stop.c + test/test-tcp-reuseport.c test/test-tcp-read-stop-start.c test/test-tcp-rst.c test/test-tcp-shutdown-after-write.c diff --git a/Makefile.am b/Makefile.am index c344f7dc9f4..585934bd39c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -276,6 +276,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-tcp-flags.c \ test/test-tcp-open.c \ test/test-tcp-read-stop.c \ + test/test-tcp-reuseport.c \ test/test-tcp-read-stop-start.c \ test/test-tcp-rst.c \ test/test-tcp-shutdown-after-write.c \ diff --git a/docs/src/tcp.rst b/docs/src/tcp.rst index f351214ff92..5b5453b0591 100644 --- a/docs/src/tcp.rst +++ b/docs/src/tcp.rst @@ -16,6 +16,28 @@ Data types TCP handle type. +.. c:type:: uv_tcp_flags + + Flags used in :c:func:`uv_tcp_bind`. + + :: + + enum uv_tcp_flags { + /* Used with uv_tcp_bind, when an IPv6 address is used. */ + UV_TCP_IPV6ONLY = 1, + + /* Enable SO_REUSEPORT socket option when binding the handle. + * This allows completely duplicate bindings by multiple processes + * or threads if they all set SO_REUSEPORT before binding the port. + * Incoming connections are distributed across the participating + * listener sockets. + * + * This flag is available only on Linux 3.9+, DragonFlyBSD 3.6+, + * FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ for now. + */ + UV_TCP_REUSEPORT = 2, + }; + Public members ^^^^^^^^^^^^^^ @@ -81,16 +103,33 @@ API .. c:function:: int uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr, unsigned int flags) - Bind the handle to an address and port. `addr` should point to an - initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``. + Bind the handle to an address and port. When the port is already taken, you can expect to see an ``UV_EADDRINUSE`` - error from :c:func:`uv_listen` or :c:func:`uv_tcp_connect`. That is, - a successful call to this function does not guarantee that the call - to :c:func:`uv_listen` or :c:func:`uv_tcp_connect` will succeed as well. + error from :c:func:`uv_listen` or :c:func:`uv_tcp_connect` unless you specify + ``UV_TCP_REUSEPORT`` in `flags` for all the binding sockets. That is, a successful + call to this function does not guarantee that the call to :c:func:`uv_listen` or + :c:func:`uv_tcp_connect` will succeed as well. - `flags` can contain ``UV_TCP_IPV6ONLY``, in which case dual-stack support - is disabled and only IPv6 is used. + :param handle: TCP handle. It should have been initialized with :c:func:`uv_tcp_init`. + + :param addr: Address to bind to. It should point to an initialized ``struct sockaddr_in`` + or ``struct sockaddr_in6``. + + :param flags: Flags that control the behavior of binding the socket. + ``UV_TCP_IPV6ONLY`` can be contained in `flags` to disable dual-stack + support and only use IPv6. + ``UV_TCP_REUSEPORT`` can be contained in `flags` to enable the socket option + `SO_REUSEPORT` with the capability of load balancing that distribute incoming + connections across all listening sockets in multiple processes or threads. + + :returns: 0 on success, or an error code < 0 on failure. + + .. versionchanged:: 1.49.0 added the ``UV_TCP_REUSEPORT`` flag. + + .. note:: + ``UV_TCP_REUSEPORT`` flag is available only on Linux 3.9+, DragonFlyBSD 3.6+, + FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ at the moment. .. c:function:: int uv_tcp_getsockname(const uv_tcp_t* handle, struct sockaddr* name, int* namelen) diff --git a/include/uv.h b/include/uv.h index a62b3fa69b1..3b6b72246ac 100644 --- a/include/uv.h +++ b/include/uv.h @@ -604,7 +604,18 @@ UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable); enum uv_tcp_flags { /* Used with uv_tcp_bind, when an IPv6 address is used. */ - UV_TCP_IPV6ONLY = 1 + UV_TCP_IPV6ONLY = 1, + + /* Enable SO_REUSEPORT socket option when binding the handle. + * This allows completely duplicate bindings by multiple processes + * or threads if they all set SO_REUSEPORT before binding the port. + * Incoming connections are distributed across the participating + * listener sockets. + * + * This flag is available only on Linux 3.9+, DragonFlyBSD 3.6+, + * FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ for now. + */ + UV_TCP_REUSEPORT = 2, }; UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle, diff --git a/src/unix/tcp.c b/src/unix/tcp.c index e4a65498eb5..5b8df37ff25 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -148,6 +148,50 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) { } +static int uv__tcp_reuseport(int fd) { + int on = 1; +#if defined(__FreeBSD__) && __FreeBSD__ >= 12 && defined(SO_REUSEPORT_LB) + /* FreeBSD 12 introduced a new socket option named SO_REUSEPORT_LB + * with the capability of load balancing, it's the substitution of + * the SO_REUSEPORTs on Linux and DragonFlyBSD. */ + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, &on, sizeof(on))) + return UV__ERR(errno); +#elif (defined(__linux__) || \ + defined(_AIX73) || \ + (defined(__DragonFly__) && __DragonFly_version >= 300600) || \ + (defined(__sun) && defined(SO_FLOW_NAME))) && \ + defined(SO_REUSEPORT) + /* On Linux 3.9+, the SO_REUSEPORT implementation distributes connections + * evenly across all of the threads (or processes) that are blocked in + * accept() on the same port. + * + * DragonFlyBSD 3.6.0 extended SO_REUSEPORT to distribute workload to + * available sockets, which made it the equivalent of Linux's SO_REUSEPORT. + * + * AIX 7.2.5 added the feature that would add the capability to distribute + * incoming connections across all listening ports for SO_REUSEPORT. + * + * Solaris 11 supported SO_REUSEPORT, but it's implemented only for + * binding to the same address and port, without load balancing. + * Solaris 11.4 extended SO_REUSEPORT with the capability of load balancing. + * Since it's impossible to detect the Solaris 11.4 version via OS macros, + * so we check the presence of the socket option SO_FLOW_NAME that was first + * introduced to Solaris 11.4. */ + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) + return UV__ERR(errno); +#else + (void) (fd); + (void) (on); + /* SO_REUSEPORTs do not have the capability of load balancing on platforms + * other than those mentioned above. The semantics are completely different, + * therefore we shouldn't enable it, but fail this operation to indicate that + * UV_TCP_REUSEPORT is not supported on these platforms. */ + return UV_ENOTSUP; +#endif + + return 0; +} + int uv__tcp_bind(uv_tcp_t* tcp, const struct sockaddr* addr, unsigned int addrlen, @@ -167,6 +211,12 @@ int uv__tcp_bind(uv_tcp_t* tcp, if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) return UV__ERR(errno); + if (flags & UV_TCP_REUSEPORT) { + err = uv__tcp_reuseport(tcp->io_watcher.fd); + if (err) + return err; + } + #ifndef __OpenBSD__ #ifdef IPV6_V6ONLY if (addr->sa_family == AF_INET6) { diff --git a/src/win/tcp.c b/src/win/tcp.c index 53225e3ddc2..4ccfaff2405 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -292,6 +292,12 @@ static int uv__tcp_try_bind(uv_tcp_t* handle, DWORD err; int r; + /* There is no SO_REUSEPORT on Windows, Windows only knows SO_REUSEADDR. + * so we just return an error directly when UV_TCP_REUSEPORT is requested + * for binding the socket. */ + if (flags & UV_TCP_REUSEPORT) + return ERROR_NOT_SUPPORTED; + if (handle->socket == INVALID_SOCKET) { SOCKET sock; diff --git a/test/test-list.h b/test/test-list.h index 84c885ccc78..ad4593d86d4 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -153,6 +153,7 @@ TEST_DECLARE (tcp_write_to_half_open_connection) TEST_DECLARE (tcp_unexpected_read) TEST_DECLARE (tcp_read_stop) TEST_DECLARE (tcp_read_stop_start) +TEST_DECLARE (tcp_reuseport) TEST_DECLARE (tcp_rst) TEST_DECLARE (tcp_bind6_error_addrinuse) TEST_DECLARE (tcp_bind6_error_addrnotavail) @@ -765,6 +766,8 @@ TASK_LIST_START TEST_ENTRY (tcp_read_stop_start) + TEST_ENTRY (tcp_reuseport) + TEST_ENTRY (tcp_rst) TEST_HELPER (tcp_rst, tcp4_echo_server) diff --git a/test/test-tcp-reuseport.c b/test/test-tcp-reuseport.c new file mode 100644 index 00000000000..296301b82de --- /dev/null +++ b/test/test-tcp-reuseport.c @@ -0,0 +1,215 @@ +/* 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 +#include +#include + +#if !defined(__linux__) && !defined(__FreeBSD__) && \ + !defined(__DragonFly__) && !defined(__sun) && !defined(_AIX73) + +TEST_IMPL(tcp_reuseport) { + struct sockaddr_in addr; + uv_loop_t* loop; + uv_tcp_t handle; + int r; + + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + loop = uv_default_loop(); + ASSERT_NOT_NULL(loop); + + r = uv_tcp_init(loop, &handle); + ASSERT_OK(r); + + r = uv_tcp_bind(&handle, (const struct sockaddr*) &addr, UV_TCP_REUSEPORT); + ASSERT_EQ(r, UV_ENOTSUP); + + MAKE_VALGRIND_HAPPY(loop); + + return 0; +} + +#else + +#define MAX_TCP_CLIENTS 10 + +static uv_tcp_t tcp_connect_handles[MAX_TCP_CLIENTS]; +static uv_connect_t tcp_connect_requests[MAX_TCP_CLIENTS]; + +static unsigned int main_loop_accepted; +static unsigned int thread_loop_accepted; +static unsigned int connected; + +static uv_mutex_t mutex; +static unsigned int accepted; + +static uv_loop_t* main_loop; +static uv_loop_t* thread_loop; +static uv_tcp_t main_handle; +static uv_tcp_t thread_handle; +static uv_timer_t main_timer_handle; +static uv_timer_t thread_timer_handle; + +static void on_close(uv_handle_t* handle) { + free(handle); +} + +static void ticktack(uv_timer_t* timer) { + ASSERT(timer == &main_timer_handle || timer == &thread_timer_handle); + + int done = 0; + uv_mutex_lock(&mutex); + if (accepted == MAX_TCP_CLIENTS) { + done = 1; + } + uv_mutex_unlock(&mutex); + + if (done) { + uv_close((uv_handle_t*) timer, NULL); + if (timer->loop == main_loop) + uv_close((uv_handle_t*) &main_handle, NULL); + if (timer->loop == thread_loop) + uv_close((uv_handle_t*) &thread_handle, NULL); + } +} + +static void on_connection(uv_stream_t* server, int status) +{ + ASSERT_OK(status); + ASSERT(server == (uv_stream_t*) &main_handle || \ + server == (uv_stream_t*) &thread_handle); + + uv_tcp_t *client = malloc(sizeof(uv_tcp_t)); + ASSERT_OK(uv_tcp_init(server->loop, client)); + ASSERT_OK(uv_accept(server, (uv_stream_t*) client)); + uv_close((uv_handle_t*) client, on_close); + + if (server->loop == main_loop) + main_loop_accepted++; + + if (server->loop == thread_loop) + thread_loop_accepted++; + + uv_mutex_lock(&mutex); + accepted++; + uv_mutex_unlock(&mutex); +} + +static void on_connect(uv_connect_t* req, int status) { + ASSERT_OK(status); + ASSERT_NOT_NULL(req->handle); + ASSERT_PTR_EQ(req->handle->loop, main_loop); + + connected++; + uv_close((uv_handle_t*) req->handle, NULL); +} + +static void run_event_loop(void* arg) { + int r; + uv_loop_t* loop = (uv_loop_t*) arg; + ASSERT_PTR_EQ(loop, thread_loop); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT_OK(r); +} + +static void create_listener(uv_loop_t* loop, uv_tcp_t* handle) { + struct sockaddr_in addr; + int r; + + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_tcp_init(loop, handle); + ASSERT_OK(r); + + r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, UV_TCP_REUSEPORT); + ASSERT_OK(r); + + r = uv_listen((uv_stream_t*) handle, 128, on_connection); + ASSERT_OK(r); +} + +TEST_IMPL(tcp_reuseport) { + struct sockaddr_in addr; + int r; + + r = uv_mutex_init(&mutex); + + /* Create listener per event loop. */ + main_loop = uv_default_loop(); + ASSERT_NOT_NULL(main_loop); + create_listener(main_loop, &main_handle); + uv_timer_init(main_loop, &main_timer_handle); + uv_timer_start(&main_timer_handle, ticktack, 0, 10); + + thread_loop = uv_loop_new(); + ASSERT_NOT_NULL(thread_loop); + create_listener(thread_loop, &thread_handle); + uv_timer_init(thread_loop, &thread_timer_handle); + uv_timer_start(&thread_timer_handle, ticktack, 0, 10); + + /* Connect to the peers. */ + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + int i; + for (i = 0; i < MAX_TCP_CLIENTS; i++) { + r = uv_tcp_init(main_loop, &tcp_connect_handles[i]); + ASSERT_OK(r); + r = uv_tcp_connect(&tcp_connect_requests[i], + &tcp_connect_handles[i], + (const struct sockaddr*) &addr, + on_connect); + ASSERT_OK(r); + } + + /* Run event loops and wait for them to exit. */ + uv_thread_t thread_loop_id; + uv_thread_create(&thread_loop_id, run_event_loop, thread_loop); + + r = uv_run(main_loop, UV_RUN_DEFAULT); + ASSERT_OK(r); + + uv_thread_join(&thread_loop_id); + + /* Verify if each listener per event loop accepted connections + * and the amount of accepted connections matches the one of + * connected connections. + */ + ASSERT_EQ(accepted, MAX_TCP_CLIENTS); + ASSERT_EQ(connected, MAX_TCP_CLIENTS); + ASSERT_GT(main_loop_accepted, 0); + ASSERT_GT(thread_loop_accepted, 0); + ASSERT_EQ(main_loop_accepted + thread_loop_accepted, connected); + + /* Clean up. */ + uv_mutex_destroy(&mutex); + + uv_loop_delete(thread_loop); + MAKE_VALGRIND_HAPPY(main_loop); + + return 0; +} + +#endif From 541329d51f82bce83bd81ff7640edabfc32d149c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Arboleda?= Date: Mon, 27 May 2024 16:47:52 -0500 Subject: [PATCH 544/713] doc: add entries for extended getpw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds documentation for the introduced `uv_os_get_passwd2`, `uv_os_get_group`, `uv_os_free_group` methods in https://github.com/libuv/libuv/pull/3523 Fixes: https://github.com/libuv/libuv/issues/4007 Signed-off-by: Juan José Arboleda --- docs/src/misc.rst | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 989618304d1..239fc176e62 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -199,6 +199,18 @@ Data types char* homedir; } uv_passwd_t; +.. c:type:: uv_group_s + + Data type for group file information. + + :: + + typedef struct uv_group_s { + char* groupname; + unsigned long gid; + char** members; + }; + .. c:type:: uv_utsname_t Data type for operating system name and version information. @@ -566,6 +578,35 @@ API .. versionadded:: 1.9.0 +.. c:function:: int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid) + + Gets a subset of the password file entry for the provided uid. + The populated data includes the username, euid, gid, shell, + and home directory. On non-Windows systems, all data comes from + :man:`getpwuid_r(3)`. On Windows, uid and gid are set to -1 and have no + meaning, and shell is `NULL`. After successfully calling this function, the + memory allocated to `pwd` needs to be freed with + :c:func:`uv_os_free_passwd`. + + .. versionadded:: 1.45.0 + +.. c:function:: int uv_os_get_group(uv_group_s* group, uv_uid_t gid) + + Gets a subset of the group file entry for the provided uid. + The populated data includes the group name, gid, and members. On non-Windows + systems, all data comes from :man:`getgrgid_r(3)`. On Windows, uid and gid + are set to -1 and have no meaning. After successfully calling this function, + the memory allocated to `group` needs to be freed with + :c:func:`uv_os_free_group`. + + .. versionadded:: 1.45.0 + +.. c:function:: void uv_os_free_group(uv_passwd_t* pwd) + + Frees the memory previously allocated with :c:func:`uv_os_get_group`. + + .. versionadded:: 1.45.0 + .. c:function:: void uv_os_free_passwd(uv_passwd_t* pwd) Frees the `pwd` memory previously allocated with :c:func:`uv_os_get_passwd`. From 1ee1063402c7af60b26661bf16cb525e4a08dd0a Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Thu, 30 May 2024 15:53:44 +0800 Subject: [PATCH 545/713] test: fix the flaky test-tcp-reuseport Start connecting to the peers after all threads to poll for accepting connections. Ref: #4407 --- test/test-tcp-reuseport.c | 110 ++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 41 deletions(-) diff --git a/test/test-tcp-reuseport.c b/test/test-tcp-reuseport.c index 296301b82de..2e5adec2e08 100644 --- a/test/test-tcp-reuseport.c +++ b/test/test-tcp-reuseport.c @@ -53,31 +53,35 @@ TEST_IMPL(tcp_reuseport) { #else +#define NUM_LISTENING_THREADS 2 #define MAX_TCP_CLIENTS 10 static uv_tcp_t tcp_connect_handles[MAX_TCP_CLIENTS]; static uv_connect_t tcp_connect_requests[MAX_TCP_CLIENTS]; -static unsigned int main_loop_accepted; -static unsigned int thread_loop_accepted; -static unsigned int connected; +static uv_sem_t semaphore; static uv_mutex_t mutex; static unsigned int accepted; +static unsigned int thread_loop1_accepted; +static unsigned int thread_loop2_accepted; +static unsigned int connected; + static uv_loop_t* main_loop; -static uv_loop_t* thread_loop; -static uv_tcp_t main_handle; -static uv_tcp_t thread_handle; -static uv_timer_t main_timer_handle; -static uv_timer_t thread_timer_handle; +static uv_loop_t* thread_loop1; +static uv_loop_t* thread_loop2; +static uv_tcp_t thread_handle1; +static uv_tcp_t thread_handle2; +static uv_timer_t thread_timer_handle1; +static uv_timer_t thread_timer_handle2; static void on_close(uv_handle_t* handle) { free(handle); } static void ticktack(uv_timer_t* timer) { - ASSERT(timer == &main_timer_handle || timer == &thread_timer_handle); + ASSERT(timer == &thread_timer_handle1 || timer == &thread_timer_handle2); int done = 0; uv_mutex_lock(&mutex); @@ -88,29 +92,29 @@ static void ticktack(uv_timer_t* timer) { if (done) { uv_close((uv_handle_t*) timer, NULL); - if (timer->loop == main_loop) - uv_close((uv_handle_t*) &main_handle, NULL); - if (timer->loop == thread_loop) - uv_close((uv_handle_t*) &thread_handle, NULL); + if (timer->loop == thread_loop1) + uv_close((uv_handle_t*) &thread_handle1, NULL); + if (timer->loop == thread_loop2) + uv_close((uv_handle_t*) &thread_handle2, NULL); } } static void on_connection(uv_stream_t* server, int status) { ASSERT_OK(status); - ASSERT(server == (uv_stream_t*) &main_handle || \ - server == (uv_stream_t*) &thread_handle); + ASSERT(server == (uv_stream_t*) &thread_handle1 || \ + server == (uv_stream_t*) &thread_handle2); uv_tcp_t *client = malloc(sizeof(uv_tcp_t)); ASSERT_OK(uv_tcp_init(server->loop, client)); ASSERT_OK(uv_accept(server, (uv_stream_t*) client)); uv_close((uv_handle_t*) client, on_close); - if (server->loop == main_loop) - main_loop_accepted++; + if (server->loop == thread_loop1) + thread_loop1_accepted++; - if (server->loop == thread_loop) - thread_loop_accepted++; + if (server->loop == thread_loop2) + thread_loop2_accepted++; uv_mutex_lock(&mutex); accepted++; @@ -129,8 +133,10 @@ static void on_connect(uv_connect_t* req, int status) { static void run_event_loop(void* arg) { int r; uv_loop_t* loop = (uv_loop_t*) arg; - ASSERT_PTR_EQ(loop, thread_loop); + ASSERT(loop == thread_loop1 || loop == thread_loop2); + /* Notify the main thread to start connecting. */ + uv_sem_post(&semaphore); r = uv_run(loop, UV_RUN_DEFAULT); ASSERT_OK(r); } @@ -154,26 +160,47 @@ static void create_listener(uv_loop_t* loop, uv_tcp_t* handle) { TEST_IMPL(tcp_reuseport) { struct sockaddr_in addr; int r; + int i; r = uv_mutex_init(&mutex); - /* Create listener per event loop. */ + r = uv_sem_init(&semaphore, 0); + ASSERT_OK(r); + main_loop = uv_default_loop(); ASSERT_NOT_NULL(main_loop); - create_listener(main_loop, &main_handle); - uv_timer_init(main_loop, &main_timer_handle); - uv_timer_start(&main_timer_handle, ticktack, 0, 10); - thread_loop = uv_loop_new(); - ASSERT_NOT_NULL(thread_loop); - create_listener(thread_loop, &thread_handle); - uv_timer_init(thread_loop, &thread_timer_handle); - uv_timer_start(&thread_timer_handle, ticktack, 0, 10); + /* Create listener per event loop. */ - /* Connect to the peers. */ + thread_loop1 = uv_loop_new(); + ASSERT_NOT_NULL(thread_loop1); + create_listener(thread_loop1, &thread_handle1); + uv_timer_init(thread_loop1, &thread_timer_handle1); + uv_timer_start(&thread_timer_handle1, ticktack, 0, 10); + + thread_loop2 = uv_loop_new(); + ASSERT_NOT_NULL(thread_loop2); + create_listener(thread_loop2, &thread_handle2); + uv_timer_init(thread_loop2, &thread_timer_handle2); + uv_timer_start(&thread_timer_handle2, ticktack, 0, 10); + + /* Run event loops of listeners in separate threads. */ + uv_thread_t thread_loop_id1; + uv_thread_t thread_loop_id2; + uv_thread_create(&thread_loop_id1, run_event_loop, thread_loop1); + uv_thread_create(&thread_loop_id2, run_event_loop, thread_loop2); + + /* Wait until all threads to poll for accepting connections + * before we start to connect. Otherwise the incoming connections + * might not be distributed across all listening threads. */ + for (i = 0; i < NUM_LISTENING_THREADS; i++) + uv_sem_wait(&semaphore); + /* Now we know all threads are up and entering the uv_run(), + * but we still sleep a little bit just for dual fail-safe. */ + uv_sleep(100); + + /* Start connecting to the peers. */ ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); - - int i; for (i = 0; i < MAX_TCP_CLIENTS; i++) { r = uv_tcp_init(main_loop, &tcp_connect_handles[i]); ASSERT_OK(r); @@ -184,14 +211,12 @@ TEST_IMPL(tcp_reuseport) { ASSERT_OK(r); } - /* Run event loops and wait for them to exit. */ - uv_thread_t thread_loop_id; - uv_thread_create(&thread_loop_id, run_event_loop, thread_loop); - r = uv_run(main_loop, UV_RUN_DEFAULT); ASSERT_OK(r); - uv_thread_join(&thread_loop_id); + /* Wait for all threads to exit. */ + uv_thread_join(&thread_loop_id1); + uv_thread_join(&thread_loop_id2); /* Verify if each listener per event loop accepted connections * and the amount of accepted connections matches the one of @@ -199,14 +224,17 @@ TEST_IMPL(tcp_reuseport) { */ ASSERT_EQ(accepted, MAX_TCP_CLIENTS); ASSERT_EQ(connected, MAX_TCP_CLIENTS); - ASSERT_GT(main_loop_accepted, 0); - ASSERT_GT(thread_loop_accepted, 0); - ASSERT_EQ(main_loop_accepted + thread_loop_accepted, connected); + ASSERT_GT(thread_loop1_accepted, 0); + ASSERT_GT(thread_loop2_accepted, 0); + ASSERT_EQ(thread_loop1_accepted + thread_loop2_accepted, connected); /* Clean up. */ uv_mutex_destroy(&mutex); - uv_loop_delete(thread_loop); + uv_sem_destroy(&semaphore); + + uv_loop_delete(thread_loop1); + uv_loop_delete(thread_loop2); MAKE_VALGRIND_HAPPY(main_loop); return 0; From eb5af8e3c0ea19a6b0196d5db3212dae1785739b Mon Sep 17 00:00:00 2001 From: "Jeffrey H. Johnson" Date: Thu, 30 May 2024 16:31:15 -0400 Subject: [PATCH 546/713] aix,ibmi: fix compilation errors in fs_copyfile (#4404) On IBM AIX (and PASE for IBM i), use st_timespec_t when _XOPEN_SOURCE>=700 and _ALL_SOURCE is defined. Signed-off-by: Jeffrey H. Johnson --- src/unix/fs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index 0c6c585c6d6..c4eadd63d8e 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1317,6 +1317,11 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { #if defined(__APPLE__) times[0] = src_statsbuf.st_atimespec; times[1] = src_statsbuf.st_mtimespec; +#elif defined(_AIX) + times[0].tv_sec = src_statsbuf.st_atime; + times[0].tv_nsec = src_statsbuf.st_atime_n; + times[1].tv_sec = src_statsbuf.st_mtime; + times[1].tv_nsec = src_statsbuf.st_mtime_n; #else times[0] = src_statsbuf.st_atim; times[1] = src_statsbuf.st_mtim; From ba24986f8deda3a0228e1e06e4a5ee87451ede92 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Thu, 20 Jun 2024 23:17:17 +0800 Subject: [PATCH 547/713] unix: support SO_REUSEPORT with load balancing for UDP (#4419) Signed-off-by: Andy Pan --- CMakeLists.txt | 1 + Makefile.am | 1 + docs/src/tcp.rst | 3 +- docs/src/udp.rst | 57 ++++++-- include/uv.h | 23 ++- src/unix/core.c | 45 ++++++ src/unix/internal.h | 1 + src/unix/tcp.c | 46 +----- src/unix/udp.c | 30 ++-- src/win/udp.c | 6 + test/test-list.h | 2 + test/test-tcp-reuseport.c | 75 +++++----- test/test-udp-reuseport.c | 287 ++++++++++++++++++++++++++++++++++++++ 13 files changed, 467 insertions(+), 110 deletions(-) create mode 100644 test/test-udp-reuseport.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ce086f4ae7f..40c808b800d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -693,6 +693,7 @@ if(LIBUV_BUILD_TESTS) test/test-udp-send-unreachable.c test/test-udp-try-send.c test/test-udp-recv-in-a-row.c + test/test-udp-reuseport.c test/test-uname.c test/test-walk-handles.c test/test-watcher-cross-stop.c) diff --git a/Makefile.am b/Makefile.am index 585934bd39c..9379b671739 100644 --- a/Makefile.am +++ b/Makefile.am @@ -326,6 +326,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-udp-send-unreachable.c \ test/test-udp-try-send.c \ test/test-udp-recv-in-a-row.c \ + test/test-udp-reuseport.c \ test/test-uname.c \ test/test-walk-handles.c \ test/test-watcher-cross-stop.c diff --git a/docs/src/tcp.rst b/docs/src/tcp.rst index 5b5453b0591..571b293002e 100644 --- a/docs/src/tcp.rst +++ b/docs/src/tcp.rst @@ -129,7 +129,8 @@ API .. note:: ``UV_TCP_REUSEPORT`` flag is available only on Linux 3.9+, DragonFlyBSD 3.6+, - FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ at the moment. + FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ at the moment. On other platforms + this function will return an UV_ENOTSUP error. .. c:function:: int uv_tcp_getsockname(const uv_tcp_t* handle, struct sockaddr* name, int* namelen) diff --git a/docs/src/udp.rst b/docs/src/udp.rst index 9e075d7b5db..57d4c77e5e1 100644 --- a/docs/src/udp.rst +++ b/docs/src/udp.rst @@ -28,19 +28,21 @@ Data types /* Disables dual stack mode. */ UV_UDP_IPV6ONLY = 1, /* - * Indicates message was truncated because read buffer was too small. The - * remainder was discarded by the OS. Used in uv_udp_recv_cb. - */ + * Indicates message was truncated because read buffer was too small. The + * remainder was discarded by the OS. Used in uv_udp_recv_cb. + */ UV_UDP_PARTIAL = 2, /* - * Indicates if SO_REUSEADDR will be set when binding the handle in - * uv_udp_bind. - * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other - * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that - * multiple threads or processes can bind to the same address without error - * (provided they all set the flag) but only the last one to bind will receive - * any traffic, in effect "stealing" the port from the previous listener. - */ + * Indicates if SO_REUSEADDR will be set when binding the handle. + * This sets the SO_REUSEPORT socket flag on the BSDs (except for + * DragonFlyBSD), OS X, and other platforms where SO_REUSEPORTs don't + * have the capability of load balancing, as the opposite of what + * UV_UDP_REUSEPORT would do. On other Unix platforms, it sets the + * SO_REUSEADDR flag. What that means is that multiple threads or + * processes can bind to the same address without error (provided + * they all set the flag) but only the last one to bind will receive + * any traffic, in effect "stealing" the port from the previous listener. + */ UV_UDP_REUSEADDR = 4, /* * Indicates that the message was received by recvmmsg, so the buffer provided @@ -62,8 +64,20 @@ Data types */ UV_UDP_LINUX_RECVERR = 32, /* - * Indicates that recvmmsg should be used, if available. - */ + * Indicates if SO_REUSEPORT will be set when binding the handle. + * This sets the SO_REUSEPORT socket option on supported platforms. + * Unlike UV_UDP_REUSEADDR, this flag will make multiple threads or + * processes that are binding to the same address and port "share" + * the port, which means incoming datagrams are distributed across + * the receiving sockets among threads or processes. + * + * This flag is available only on Linux 3.9+, DragonFlyBSD 3.6+, + * FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ for now. + */ + UV_UDP_REUSEPORT = 64, + /* + * Indicates that recvmmsg should be used, if available. + */ UV_UDP_RECVMMSG = 256 }; @@ -186,11 +200,24 @@ API with the address and port to bind to. :param flags: Indicate how the socket will be bound, - ``UV_UDP_IPV6ONLY``, ``UV_UDP_REUSEADDR``, and ``UV_UDP_RECVERR`` - are supported. + ``UV_UDP_IPV6ONLY``, ``UV_UDP_REUSEADDR``, ``UV_UDP_REUSEPORT``, + and ``UV_UDP_RECVERR`` are supported. :returns: 0 on success, or an error code < 0 on failure. + .. versionchanged:: 1.49.0 added the ``UV_UDP_REUSEPORT`` flag. + + .. note:: + ``UV_UDP_REUSEPORT`` flag is available only on Linux 3.9+, DragonFlyBSD 3.6+, + FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ at the moment. On other platforms + this function will return an UV_ENOTSUP error. + For platforms where `SO_REUSEPORT`s have the capability of load balancing, + specifying both ``UV_UDP_REUSEADDR`` and ``UV_UDP_REUSEPORT`` in flags is allowed + and `SO_REUSEPORT` will always override the behavior of `SO_REUSEADDR`. + For platforms where `SO_REUSEPORT`s don't have the capability of load balancing, + specifying both ``UV_UDP_REUSEADDR`` and ``UV_UDP_REUSEPORT`` in flags will fail, + returning an UV_ENOTSUP error. + .. c:function:: int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr) Associate the UDP handle to a remote address and port, so every diff --git a/include/uv.h b/include/uv.h index 3b6b72246ac..f1d976ba733 100644 --- a/include/uv.h +++ b/include/uv.h @@ -656,10 +656,13 @@ enum uv_udp_flags { UV_UDP_PARTIAL = 2, /* * Indicates if SO_REUSEADDR will be set when binding the handle. - * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other - * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that - * multiple threads or processes can bind to the same address without error - * (provided they all set the flag) but only the last one to bind will receive + * This sets the SO_REUSEPORT socket flag on the BSDs (except for + * DragonFlyBSD), OS X, and other platforms where SO_REUSEPORTs don't + * have the capability of load balancing, as the opposite of what + * UV_UDP_REUSEPORT would do. On other Unix platforms, it sets the + * SO_REUSEADDR flag. What that means is that multiple threads or + * processes can bind to the same address without error (provided + * they all set the flag) but only the last one to bind will receive * any traffic, in effect "stealing" the port from the previous listener. */ UV_UDP_REUSEADDR = 4, @@ -682,6 +685,18 @@ enum uv_udp_flags { * This flag is no-op on platforms other than Linux. */ UV_UDP_LINUX_RECVERR = 32, + /* + * Indicates if SO_REUSEPORT will be set when binding the handle. + * This sets the SO_REUSEPORT socket option on supported platforms. + * Unlike UV_UDP_REUSEADDR, this flag will make multiple threads or + * processes that are binding to the same address and port "share" + * the port, which means incoming datagrams are distributed across + * the receiving sockets among threads or processes. + * + * This flag is available only on Linux 3.9+, DragonFlyBSD 3.6+, + * FreeBSD 12.0+, Solaris 11.4, and AIX 7.2.5+ for now. + */ + UV_UDP_REUSEPORT = 64, /* * Indicates that recvmmsg should be used, if available. */ diff --git a/src/unix/core.c b/src/unix/core.c index 8ea606c7a8c..25249bcbd30 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1910,3 +1910,48 @@ unsigned int uv_available_parallelism(void) { return (unsigned) rc; #endif /* __linux__ */ } + +int uv__sock_reuseport(int fd) { + int on = 1; +#if defined(__FreeBSD__) && __FreeBSD__ >= 12 && defined(SO_REUSEPORT_LB) + /* FreeBSD 12 introduced a new socket option named SO_REUSEPORT_LB + * with the capability of load balancing, it's the substitution of + * the SO_REUSEPORTs on Linux and DragonFlyBSD. */ + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, &on, sizeof(on))) + return UV__ERR(errno); +#elif (defined(__linux__) || \ + defined(_AIX73) || \ + (defined(__DragonFly__) && __DragonFly_version >= 300600) || \ + (defined(__sun) && defined(SO_FLOW_NAME))) && \ + defined(SO_REUSEPORT) + /* On Linux 3.9+, the SO_REUSEPORT implementation distributes connections + * evenly across all of the threads (or processes) that are blocked in + * accept() on the same port. As with TCP, SO_REUSEPORT distributes datagrams + * evenly across all of the receiving threads (or process). + * + * DragonFlyBSD 3.6.0 extended SO_REUSEPORT to distribute workload to + * available sockets, which made it the equivalent of Linux's SO_REUSEPORT. + * + * AIX 7.2.5 added the feature that would add the capability to distribute + * incoming connections or datagrams across all listening ports for SO_REUSEPORT. + * + * Solaris 11 supported SO_REUSEPORT, but it's implemented only for + * binding to the same address and port, without load balancing. + * Solaris 11.4 extended SO_REUSEPORT with the capability of load balancing. + * Since it's impossible to detect the Solaris 11.4 version via OS macros, + * so we check the presence of the socket option SO_FLOW_NAME that was first + * introduced to Solaris 11.4. */ + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) + return UV__ERR(errno); +#else + (void) (fd); + (void) (on); + /* SO_REUSEPORTs do not have the capability of load balancing on platforms + * other than those mentioned above. The semantics are completely different, + * therefore we shouldn't enable it, but fail this operation to indicate that + * UV_[TCP/UDP]_REUSEPORT is not supported on these platforms. */ + return UV_ENOTSUP; +#endif + + return 0; +} diff --git a/src/unix/internal.h b/src/unix/internal.h index 3ad3705274f..1c0c88c70c6 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -243,6 +243,7 @@ int uv__close(int fd); /* preserves errno */ int uv__close_nocheckstdio(int fd); int uv__close_nocancel(int fd); int uv__socket(int domain, int type, int protocol); +int uv__sock_reuseport(int fd); ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags); void uv__make_close_pending(uv_handle_t* handle); int uv__getiovmax(void); diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 5b8df37ff25..eba8c99fd00 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -148,50 +148,6 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) { } -static int uv__tcp_reuseport(int fd) { - int on = 1; -#if defined(__FreeBSD__) && __FreeBSD__ >= 12 && defined(SO_REUSEPORT_LB) - /* FreeBSD 12 introduced a new socket option named SO_REUSEPORT_LB - * with the capability of load balancing, it's the substitution of - * the SO_REUSEPORTs on Linux and DragonFlyBSD. */ - if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, &on, sizeof(on))) - return UV__ERR(errno); -#elif (defined(__linux__) || \ - defined(_AIX73) || \ - (defined(__DragonFly__) && __DragonFly_version >= 300600) || \ - (defined(__sun) && defined(SO_FLOW_NAME))) && \ - defined(SO_REUSEPORT) - /* On Linux 3.9+, the SO_REUSEPORT implementation distributes connections - * evenly across all of the threads (or processes) that are blocked in - * accept() on the same port. - * - * DragonFlyBSD 3.6.0 extended SO_REUSEPORT to distribute workload to - * available sockets, which made it the equivalent of Linux's SO_REUSEPORT. - * - * AIX 7.2.5 added the feature that would add the capability to distribute - * incoming connections across all listening ports for SO_REUSEPORT. - * - * Solaris 11 supported SO_REUSEPORT, but it's implemented only for - * binding to the same address and port, without load balancing. - * Solaris 11.4 extended SO_REUSEPORT with the capability of load balancing. - * Since it's impossible to detect the Solaris 11.4 version via OS macros, - * so we check the presence of the socket option SO_FLOW_NAME that was first - * introduced to Solaris 11.4. */ - if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) - return UV__ERR(errno); -#else - (void) (fd); - (void) (on); - /* SO_REUSEPORTs do not have the capability of load balancing on platforms - * other than those mentioned above. The semantics are completely different, - * therefore we shouldn't enable it, but fail this operation to indicate that - * UV_TCP_REUSEPORT is not supported on these platforms. */ - return UV_ENOTSUP; -#endif - - return 0; -} - int uv__tcp_bind(uv_tcp_t* tcp, const struct sockaddr* addr, unsigned int addrlen, @@ -212,7 +168,7 @@ int uv__tcp_bind(uv_tcp_t* tcp, return UV__ERR(errno); if (flags & UV_TCP_REUSEPORT) { - err = uv__tcp_reuseport(tcp->io_watcher.fd); + err = uv__sock_reuseport(tcp->io_watcher.fd); if (err) return err; } diff --git a/src/unix/udp.c b/src/unix/udp.c index e398509bbf2..4e75a019571 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -434,17 +434,20 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { } /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional - * refinements for programs that use multicast. + * refinements for programs that use multicast. Therefore we preferentially + * set SO_REUSEPORT over SO_REUSEADDR here, but we set SO_REUSEPORT only + * when that socket option doesn't have the capability of load balancing. + * Otherwise, we fall back to SO_REUSEADDR. * - * Linux as of 3.9 and DragonflyBSD 3.6 have the SO_REUSEPORT socket option but - * with semantics that are different from the BSDs: it _shares_ the port rather - * than steals it from the current listener. While useful, it's not something we - * can emulate on other platforms so we don't enable it. + * Linux as of 3.9, DragonflyBSD 3.6, AIX 7.2.5 have the SO_REUSEPORT socket + * option but with semantics that are different from the BSDs: it _shares_ + * the port rather than steals it from the current listener. While useful, + * it's not something we can emulate on other platforms so we don't enable it. * * zOS does not support getsockname with SO_REUSEPORT option when using * AF_UNIX. */ -static int uv__set_reuse(int fd) { +static int uv__sock_reuseaddr(int fd) { int yes; yes = 1; @@ -461,7 +464,7 @@ static int uv__set_reuse(int fd) { return UV__ERR(errno); } #elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) && \ - !defined(__sun__) && !defined(__DragonFly__) + !defined(__sun__) && !defined(__DragonFly__) && !defined(_AIX73) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); #else @@ -504,7 +507,8 @@ int uv__udp_bind(uv_udp_t* handle, int fd; /* Check for bad flags. */ - if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR | UV_UDP_LINUX_RECVERR)) + if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR | + UV_UDP_REUSEPORT | UV_UDP_LINUX_RECVERR)) return UV_EINVAL; /* Cannot set IPv6-only mode on non-IPv6 socket. */ @@ -527,7 +531,13 @@ int uv__udp_bind(uv_udp_t* handle, } if (flags & UV_UDP_REUSEADDR) { - err = uv__set_reuse(fd); + err = uv__sock_reuseaddr(fd); + if (err) + return err; + } + + if (flags & UV_UDP_REUSEPORT) { + err = uv__sock_reuseport(fd); if (err) return err; } @@ -1049,7 +1059,7 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { if (err) return err; - err = uv__set_reuse(sock); + err = uv__sock_reuseaddr(sock); if (err) return err; diff --git a/src/win/udp.c b/src/win/udp.c index eab53842d4f..165311957d3 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -200,6 +200,12 @@ static int uv__udp_maybe_bind(uv_udp_t* handle, if (handle->flags & UV_HANDLE_BOUND) return 0; + /* There is no SO_REUSEPORT on Windows, Windows only knows SO_REUSEADDR. + * so we just return an error directly when UV_UDP_REUSEPORT is requested + * for binding the socket. */ + if (flags & UV_UDP_REUSEPORT) + return ERROR_NOT_SUPPORTED; + if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) { /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */ return ERROR_INVALID_PARAMETER; diff --git a/test/test-list.h b/test/test-list.h index ad4593d86d4..d600aef29a8 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -190,6 +190,7 @@ TEST_DECLARE (udp_open_twice) TEST_DECLARE (udp_open_bound) TEST_DECLARE (udp_open_connect) TEST_DECLARE (udp_recv_in_a_row) +TEST_DECLARE (udp_reuseport) #ifndef _WIN32 TEST_DECLARE (udp_send_unix) #endif @@ -804,6 +805,7 @@ TASK_LIST_START TEST_ENTRY (udp_sendmmsg_error) TEST_ENTRY (udp_try_send) TEST_ENTRY (udp_recv_in_a_row) + TEST_ENTRY (udp_reuseport) TEST_ENTRY (udp_open) TEST_ENTRY (udp_open_twice) diff --git a/test/test-tcp-reuseport.c b/test/test-tcp-reuseport.c index 2e5adec2e08..f108b9bbe0f 100644 --- a/test/test-tcp-reuseport.c +++ b/test/test-tcp-reuseport.c @@ -69,8 +69,8 @@ static unsigned int thread_loop2_accepted; static unsigned int connected; static uv_loop_t* main_loop; -static uv_loop_t* thread_loop1; -static uv_loop_t* thread_loop2; +static uv_loop_t thread_loop1; +static uv_loop_t thread_loop2; static uv_tcp_t thread_handle1; static uv_tcp_t thread_handle2; static uv_timer_t thread_timer_handle1; @@ -92,9 +92,9 @@ static void ticktack(uv_timer_t* timer) { if (done) { uv_close((uv_handle_t*) timer, NULL); - if (timer->loop == thread_loop1) + if (timer->loop == &thread_loop1) uv_close((uv_handle_t*) &thread_handle1, NULL); - if (timer->loop == thread_loop2) + if (timer->loop == &thread_loop2) uv_close((uv_handle_t*) &thread_handle2, NULL); } } @@ -110,10 +110,10 @@ static void on_connection(uv_stream_t* server, int status) ASSERT_OK(uv_accept(server, (uv_stream_t*) client)); uv_close((uv_handle_t*) client, on_close); - if (server->loop == thread_loop1) + if (server->loop == &thread_loop1) thread_loop1_accepted++; - if (server->loop == thread_loop2) + if (server->loop == &thread_loop2) thread_loop2_accepted++; uv_mutex_lock(&mutex); @@ -130,17 +130,6 @@ static void on_connect(uv_connect_t* req, int status) { uv_close((uv_handle_t*) req->handle, NULL); } -static void run_event_loop(void* arg) { - int r; - uv_loop_t* loop = (uv_loop_t*) arg; - ASSERT(loop == thread_loop1 || loop == thread_loop2); - - /* Notify the main thread to start connecting. */ - uv_sem_post(&semaphore); - r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT_OK(r); -} - static void create_listener(uv_loop_t* loop, uv_tcp_t* handle) { struct sockaddr_in addr; int r; @@ -157,12 +146,40 @@ static void create_listener(uv_loop_t* loop, uv_tcp_t* handle) { ASSERT_OK(r); } +static void run_event_loop(void* arg) { + int r; + uv_tcp_t* handle; + uv_timer_t* timer; + uv_loop_t* loop = (uv_loop_t*) arg; + ASSERT(loop == &thread_loop1 || loop == &thread_loop2); + + if (loop == &thread_loop1) { + handle = &thread_handle1; + timer = &thread_timer_handle1; + } else { + handle = &thread_handle2; + timer = &thread_timer_handle2; + } + + create_listener(loop, handle); + r = uv_timer_init(loop, timer); + ASSERT_OK(r); + r = uv_timer_start(timer, ticktack, 0, 10); + ASSERT_OK(r); + + /* Notify the main thread to start connecting. */ + uv_sem_post(&semaphore); + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT_OK(r); +} + TEST_IMPL(tcp_reuseport) { struct sockaddr_in addr; int r; int i; r = uv_mutex_init(&mutex); + ASSERT_OK(r); r = uv_sem_init(&semaphore, 0); ASSERT_OK(r); @@ -170,25 +187,13 @@ TEST_IMPL(tcp_reuseport) { main_loop = uv_default_loop(); ASSERT_NOT_NULL(main_loop); - /* Create listener per event loop. */ - - thread_loop1 = uv_loop_new(); - ASSERT_NOT_NULL(thread_loop1); - create_listener(thread_loop1, &thread_handle1); - uv_timer_init(thread_loop1, &thread_timer_handle1); - uv_timer_start(&thread_timer_handle1, ticktack, 0, 10); - - thread_loop2 = uv_loop_new(); - ASSERT_NOT_NULL(thread_loop2); - create_listener(thread_loop2, &thread_handle2); - uv_timer_init(thread_loop2, &thread_timer_handle2); - uv_timer_start(&thread_timer_handle2, ticktack, 0, 10); - /* Run event loops of listeners in separate threads. */ + uv_loop_init(&thread_loop1); + uv_loop_init(&thread_loop2); uv_thread_t thread_loop_id1; uv_thread_t thread_loop_id2; - uv_thread_create(&thread_loop_id1, run_event_loop, thread_loop1); - uv_thread_create(&thread_loop_id2, run_event_loop, thread_loop2); + uv_thread_create(&thread_loop_id1, run_event_loop, &thread_loop1); + uv_thread_create(&thread_loop_id2, run_event_loop, &thread_loop2); /* Wait until all threads to poll for accepting connections * before we start to connect. Otherwise the incoming connections @@ -233,8 +238,8 @@ TEST_IMPL(tcp_reuseport) { uv_sem_destroy(&semaphore); - uv_loop_delete(thread_loop1); - uv_loop_delete(thread_loop2); + uv_loop_close(&thread_loop1); + uv_loop_close(&thread_loop2); MAKE_VALGRIND_HAPPY(main_loop); return 0; diff --git a/test/test-udp-reuseport.c b/test/test-udp-reuseport.c new file mode 100644 index 00000000000..7d4db40806f --- /dev/null +++ b/test/test-udp-reuseport.c @@ -0,0 +1,287 @@ +/* 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 +#include +#include + +#if !defined(__linux__) && !defined(__FreeBSD__) && \ + !defined(__DragonFly__) && !defined(__sun) && !defined(_AIX73) + +TEST_IMPL(udp_reuseport) { + struct sockaddr_in addr1, addr2, addr3; + uv_loop_t* loop; + uv_udp_t handle1, handle2, handle3; + int r; + + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr1)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT_2, &addr2)); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT_3, &addr3)); + + loop = uv_default_loop(); + ASSERT_NOT_NULL(loop); + + r = uv_udp_init(loop, &handle1); + ASSERT_OK(r); + + r = uv_udp_bind(&handle1, (const struct sockaddr*) &addr1, UV_UDP_REUSEADDR); + ASSERT_OK(r); + + r = uv_udp_init(loop, &handle2); + ASSERT_OK(r); + + r = uv_udp_bind(&handle2, (const struct sockaddr*) &addr2, UV_UDP_REUSEPORT); + ASSERT_EQ(r, UV_ENOTSUP); + + r = uv_udp_init(loop, &handle3); + ASSERT_OK(r); + + /* For platforms where SO_REUSEPORTs don't have the capability of + * load balancing, specifying both UV_UDP_REUSEADDR and UV_UDP_REUSEPORT + * in flags will fail, returning an UV_ENOTSUP error. */ + r = uv_udp_bind(&handle3, (const struct sockaddr*) &addr3, + UV_UDP_REUSEADDR | UV_UDP_REUSEPORT); + ASSERT_EQ(r, UV_ENOTSUP); + + MAKE_VALGRIND_HAPPY(loop); + + return 0; +} + +#else + +#define NUM_RECEIVING_THREADS 2 +#define MAX_UDP_DATAGRAMS 10 + +static uv_udp_t udp_send_handles[MAX_UDP_DATAGRAMS]; +static uv_udp_send_t udp_send_requests[MAX_UDP_DATAGRAMS]; + +static uv_sem_t semaphore; + +static uv_mutex_t mutex; +static unsigned int received; + +static unsigned int thread_loop1_recv; +static unsigned int thread_loop2_recv; +static unsigned int sent; + +static uv_loop_t* main_loop; +static uv_loop_t thread_loop1; +static uv_loop_t thread_loop2; +static uv_udp_t thread_handle1; +static uv_udp_t thread_handle2; +static uv_timer_t thread_timer_handle1; +static uv_timer_t thread_timer_handle2; + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = (int) suggested_size; +} + +static void ticktack(uv_timer_t* timer) { + int done = 0; + + ASSERT(timer == &thread_timer_handle1 || timer == &thread_timer_handle2); + + uv_mutex_lock(&mutex); + if (received == MAX_UDP_DATAGRAMS) { + done = 1; + } + uv_mutex_unlock(&mutex); + + if (done) { + uv_close((uv_handle_t*) timer, NULL); + if (timer->loop == &thread_loop1) + uv_close((uv_handle_t*) &thread_handle1, NULL); + if (timer->loop == &thread_loop2) + uv_close((uv_handle_t*) &thread_handle2, NULL); + } +} + +static void on_recv(uv_udp_t* handle, + ssize_t nr, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + ASSERT_OK(flags); + ASSERT(handle == &thread_handle1 || handle == &thread_handle2); + + ASSERT_GE(nr, 0); + + if (nr == 0) { + ASSERT_NULL(addr); + free(buf->base); + return; + } + + ASSERT_NOT_NULL(addr); + ASSERT_EQ(5, nr); + ASSERT(!memcmp("Hello", buf->base, nr)); + free(buf->base); + + if (handle->loop == &thread_loop1) + thread_loop1_recv++; + + if (handle->loop == &thread_loop2) + thread_loop2_recv++; + + uv_mutex_lock(&mutex); + received++; + uv_mutex_unlock(&mutex); +} + +static void on_send(uv_udp_send_t* req, int status) { + ASSERT_OK(status); + ASSERT_PTR_EQ(req->handle->loop, main_loop); + + if (++sent == MAX_UDP_DATAGRAMS) + uv_close((uv_handle_t*) req->handle, NULL); +} + +static void bind_socket_and_prepare_recv(uv_loop_t* loop, uv_udp_t* handle) { + struct sockaddr_in addr; + int r; + + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_udp_init(loop, handle); + ASSERT_OK(r); + + /* For platforms where SO_REUSEPORTs have the capability of + * load balancing, specifying both UV_UDP_REUSEADDR and + * UV_UDP_REUSEPORT in flags is allowed and SO_REUSEPORT will + * always override the behavior of SO_REUSEADDR. */ + r = uv_udp_bind(handle, (const struct sockaddr*) &addr, + UV_UDP_REUSEADDR | UV_UDP_REUSEPORT); + ASSERT_OK(r); + + r = uv_udp_recv_start(handle, alloc_cb, on_recv); + ASSERT_OK(r); +} + +static void run_event_loop(void* arg) { + int r; + uv_udp_t* handle; + uv_timer_t* timer; + uv_loop_t* loop = (uv_loop_t*) arg; + ASSERT(loop == &thread_loop1 || loop == &thread_loop2); + + if (loop == &thread_loop1) { + handle = &thread_handle1; + timer = &thread_timer_handle1; + } else { + handle = &thread_handle2; + timer = &thread_timer_handle2; + } + + bind_socket_and_prepare_recv(loop, handle); + r = uv_timer_init(loop, timer); + ASSERT_OK(r); + r = uv_timer_start(timer, ticktack, 0, 10); + ASSERT_OK(r); + + /* Notify the main thread to start sending data. */ + uv_sem_post(&semaphore); + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT_OK(r); +} + +TEST_IMPL(udp_reuseport) { + struct sockaddr_in addr; + uv_buf_t buf; + int r; + int i; + + r = uv_mutex_init(&mutex); + ASSERT_OK(r); + + r = uv_sem_init(&semaphore, 0); + ASSERT_OK(r); + + main_loop = uv_default_loop(); + ASSERT_NOT_NULL(main_loop); + + /* Run event loops of receiving sockets in separate threads. */ + uv_loop_init(&thread_loop1); + uv_loop_init(&thread_loop2); + uv_thread_t thread_loop_id1; + uv_thread_t thread_loop_id2; + uv_thread_create(&thread_loop_id1, run_event_loop, &thread_loop1); + uv_thread_create(&thread_loop_id2, run_event_loop, &thread_loop2); + + /* Wait until all threads to poll for receiving datagrams + * before we start to sending. Otherwise the incoming datagrams + * might not be distributed across all receiving threads. */ + for (i = 0; i < NUM_RECEIVING_THREADS; i++) + uv_sem_wait(&semaphore); + /* Now we know all threads are up and entering the uv_run(), + * but we still sleep a little bit just for dual fail-safe. */ + uv_sleep(100); + + /* Start sending datagrams to the peers. */ + buf = uv_buf_init("Hello", 5); + ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + for (i = 0; i < MAX_UDP_DATAGRAMS; i++) { + r = uv_udp_init(main_loop, &udp_send_handles[i]); + ASSERT_OK(r); + r = uv_udp_send(&udp_send_requests[i], + &udp_send_handles[i], + &buf, + 1, + (const struct sockaddr*) &addr, + on_send); + ASSERT_OK(r); + } + + r = uv_run(main_loop, UV_RUN_DEFAULT); + ASSERT_OK(r); + + /* Wait for all threads to exit. */ + uv_thread_join(&thread_loop_id1); + uv_thread_join(&thread_loop_id2); + + /* Verify if each receiving socket per event loop received datagrams + * and the amount of received datagrams matches the one of sent datagrams. + */ + ASSERT_EQ(received, MAX_UDP_DATAGRAMS); + ASSERT_EQ(sent, MAX_UDP_DATAGRAMS); + ASSERT_GT(thread_loop1_recv, 0); + ASSERT_GT(thread_loop2_recv, 0); + ASSERT_EQ(thread_loop1_recv + thread_loop2_recv, sent); + + /* Clean up. */ + uv_mutex_destroy(&mutex); + + uv_sem_destroy(&semaphore); + + uv_loop_close(&thread_loop1); + uv_loop_close(&thread_loop2); + MAKE_VALGRIND_HAPPY(main_loop); + + return 0; +} + +#endif From fedfa9893e09dfe92522ec9f4d5a4c3c343484dc Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Mon, 3 Jun 2024 11:51:34 +0800 Subject: [PATCH 548/713] tcpkeepalive: distinguish OS versions and use proper time units --------- Signed-off-by: Andy Pan --- src/unix/core.c | 6 ++---- src/unix/internal.h | 12 ++++++++++++ src/unix/tcp.c | 22 ++++++++++++++++++---- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 25249bcbd30..1611cba233e 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1922,7 +1922,7 @@ int uv__sock_reuseport(int fd) { #elif (defined(__linux__) || \ defined(_AIX73) || \ (defined(__DragonFly__) && __DragonFly_version >= 300600) || \ - (defined(__sun) && defined(SO_FLOW_NAME))) && \ + (defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4)) && \ defined(SO_REUSEPORT) /* On Linux 3.9+, the SO_REUSEPORT implementation distributes connections * evenly across all of the threads (or processes) that are blocked in @@ -1938,9 +1938,7 @@ int uv__sock_reuseport(int fd) { * Solaris 11 supported SO_REUSEPORT, but it's implemented only for * binding to the same address and port, without load balancing. * Solaris 11.4 extended SO_REUSEPORT with the capability of load balancing. - * Since it's impossible to detect the Solaris 11.4 version via OS macros, - * so we check the presence of the socket option SO_FLOW_NAME that was first - * introduced to Solaris 11.4. */ + */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) return UV__ERR(errno); #else diff --git a/src/unix/internal.h b/src/unix/internal.h index 1c0c88c70c6..a8ff39094f3 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -483,4 +483,16 @@ typedef struct { int uv__get_constrained_cpu(uv__cpu_constraint* constraint); #endif +#ifdef __sun +#ifdef SO_FLOW_NAME +/* Since it's impossible to detect the Solaris 11.4 version via OS macros, + * so we check the presence of the socket option SO_FLOW_NAME that was first + * introduced to Solaris 11.4 and define a custom macro for determining 11.4. + */ +#define UV__SOLARIS_11_4 (1) +#else +#define UV__SOLARIS_11_4 (0) +#endif +#endif + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/src/unix/tcp.c b/src/unix/tcp.c index eba8c99fd00..98970d75278 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -458,6 +458,14 @@ int uv__tcp_nodelay(int fd, int on) { } +#if (defined(UV__SOLARIS_11_4) && !UV__SOLARIS_11_4) || \ + (defined(__DragonFly__) && __DragonFly_version < 500702) +/* DragonFlyBSD <500702 and Solaris <11.4 require millisecond units + * for TCP keepalive options. */ +#define UV_KEEPALIVE_FACTOR(x) (x *= 1000) +#else +#define UV_KEEPALIVE_FACTOR(x) +#endif int uv__tcp_keepalive(int fd, int on, unsigned int delay) { int idle; int intvl; @@ -507,6 +515,8 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { if (idle > 10*24*60*60) idle = 10*24*60*60; + UV_KEEPALIVE_FACTOR(idle); + /* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris * until version 11.4, but let's take a chance here. */ #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT) @@ -514,6 +524,7 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { return UV__ERR(errno); intvl = 10; /* required at least 10 seconds */ + UV_KEEPALIVE_FACTOR(intvl); if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) return UV__ERR(errno); @@ -524,30 +535,33 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { /* Fall back to the first implementation of tcp-alive mechanism for older Solaris, * simulate the tcp-alive mechanism on other platforms via `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`. */ - idle *= 1000; /* kernel expects milliseconds */ if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &idle, sizeof(idle))) return UV__ERR(errno); /* Note that the consequent probes will not be sent at equal intervals on Solaris, * but will be sent using the exponential backoff algorithm. */ - int time_to_abort = 10*1000; /* 10 seconds, kernel expects milliseconds */ + int time_to_abort = 10; /* 10 seconds */ + UV_KEEPALIVE_FACTOR(time_to_abort); if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort))) return UV__ERR(errno); #endif #else /* !defined(__sun) */ + idle = delay; + UV_KEEPALIVE_FACTOR(idle); #ifdef TCP_KEEPIDLE - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) return UV__ERR(errno); #elif defined(TCP_KEEPALIVE) /* Darwin/macOS uses TCP_KEEPALIVE in place of TCP_KEEPIDLE. */ - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &idle, sizeof(idle))) return UV__ERR(errno); #endif #ifdef TCP_KEEPINTVL intvl = 1; /* 1 second; same as default on Win32 */ + UV_KEEPALIVE_FACTOR(intvl); if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl))) return UV__ERR(errno); #endif From 36f0789d83a862338a621d1a596f421c166898bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= <110401522+huseyinacacak-janea@users.noreply.github.com> Date: Thu, 11 Jul 2024 21:41:14 +0300 Subject: [PATCH 549/713] win: map ERROR_BAD_EXE_FORMAT to UV_EFTYPE (#4445) CreateProcessW() in uv_spawn() on Windows will fail with ERROR_BAD_EXE_FORMAT if attempting to run a file that is not an executable. Refs: https://github.com/libuv/libuv/issues/2348 --- src/win/error.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win/error.c b/src/win/error.c index 3a269da87a9..1490576c5da 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -168,6 +168,7 @@ int uv_translate_sys_error(int sys_errno) { case ERROR_INVALID_FUNCTION: return UV_EISDIR; case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG; case WSAESOCKTNOSUPPORT: return UV_ESOCKTNOSUPPORT; + case ERROR_BAD_EXE_FORMAT: return UV_EFTYPE; default: return UV_UNKNOWN; } } From 6621fe045a6585b09daeaa568563f0741b75d004 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Thu, 11 Jul 2024 21:08:48 +0200 Subject: [PATCH 550/713] doc: add instruction how to install with Conan (#4432) Update the README file with instructions on how to install libuv through the Conan package manager. Signed-off-by: Uilian Ries --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 09e9bf10b6d..12c3061a894 100644 --- a/README.md +++ b/README.md @@ -232,6 +232,18 @@ $ ./bootstrap-vcpkg.sh # for bash $ ./vcpkg install libuv ``` +### Install with Conan + +You can install pre-built binaries for libuv or build it from source using [Conan](https://conan.io/). Use the following command: + +```bash +conan install --requires="libuv/[*]" --build=missing +``` + +The libuv Conan recipe is kept up to date by Conan maintainers and community contributors. +If the version is out of date, please [create an issue or pull request](https://github.com/conan-io/conan-center-index) on the ConanCenterIndex repository. + + ### Running tests Some tests are timing sensitive. Relaxing test timeouts may be necessary From 7c491bde325ab89581bca999d6db8c7b8d5a79cf Mon Sep 17 00:00:00 2001 From: Viacheslav Muravyev Date: Fri, 12 Jul 2024 02:29:15 +0700 Subject: [PATCH 551/713] unix,win: remove unused req parameter from macros (#4435) Remove the unused `req` parameter from the uv__req_register and uv__req_unregister macros. --- src/random.c | 2 +- src/threadpool.c | 2 +- src/unix/fs.c | 6 +++--- src/unix/getaddrinfo.c | 2 +- src/unix/getnameinfo.c | 2 +- src/unix/linux.c | 4 ++-- src/unix/stream.c | 8 ++++---- src/unix/udp.c | 4 ++-- src/uv-common.h | 6 +++--- src/win/fs.c | 4 ++-- src/win/getaddrinfo.c | 4 ++-- src/win/getnameinfo.c | 4 ++-- src/win/pipe.c | 20 ++++++++++---------- src/win/req-inl.h | 8 ++++---- src/win/stream.c | 2 +- src/win/tcp.c | 18 +++++++++--------- src/win/tty.c | 6 +++--- src/win/udp.c | 6 +++--- 18 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/random.c b/src/random.c index e75f77deb2b..57fc0d911da 100644 --- a/src/random.c +++ b/src/random.c @@ -82,7 +82,7 @@ static void uv__random_done(struct uv__work* w, int status) { uv_random_t* req; req = container_of(w, uv_random_t, work_req); - uv__req_unregister(req->loop, req); + uv__req_unregister(req->loop); if (status == 0) status = req->status; diff --git a/src/threadpool.c b/src/threadpool.c index dbef67f2f10..45af50dcd04 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -356,7 +356,7 @@ static void uv__queue_done(struct uv__work* w, int err) { uv_work_t* req; req = container_of(w, uv_work_t, work_req); - uv__req_unregister(req->loop, req); + uv__req_unregister(req->loop); if (req->after_work_cb == NULL) return; diff --git a/src/unix/fs.c b/src/unix/fs.c index c4eadd63d8e..a2c8d7638bf 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -139,7 +139,7 @@ extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */ #define POST \ do { \ if (cb != NULL) { \ - uv__req_register(loop, req); \ + uv__req_register(loop); \ uv__work_submit(loop, \ &req->work_req, \ UV__WORK_FAST_IO, \ @@ -1756,7 +1756,7 @@ static void uv__fs_done(struct uv__work* w, int status) { uv_fs_t* req; req = container_of(w, uv_fs_t, work_req); - uv__req_unregister(req->loop, req); + uv__req_unregister(req->loop); if (status == UV_ECANCELED) { assert(req->result == 0); @@ -1768,7 +1768,7 @@ static void uv__fs_done(struct uv__work* w, int status) { void uv__fs_post(uv_loop_t* loop, uv_fs_t* req) { - uv__req_register(loop, req); + uv__req_register(loop); uv__work_submit(loop, &req->work_req, UV__WORK_FAST_IO, diff --git a/src/unix/getaddrinfo.c b/src/unix/getaddrinfo.c index 77337ace945..b7075343666 100644 --- a/src/unix/getaddrinfo.c +++ b/src/unix/getaddrinfo.c @@ -109,7 +109,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { uv_getaddrinfo_t* req; req = container_of(w, uv_getaddrinfo_t, work_req); - uv__req_unregister(req->loop, req); + uv__req_unregister(req->loop); /* See initialization in uv_getaddrinfo(). */ if (req->hints) diff --git a/src/unix/getnameinfo.c b/src/unix/getnameinfo.c index 991002a67d7..959b4c6a821 100644 --- a/src/unix/getnameinfo.c +++ b/src/unix/getnameinfo.c @@ -58,7 +58,7 @@ static void uv__getnameinfo_done(struct uv__work* w, int status) { char* service; req = container_of(w, uv_getnameinfo_t, work_req); - uv__req_unregister(req->loop, req); + uv__req_unregister(req->loop); host = service = NULL; if (status == UV_ECANCELED) { diff --git a/src/unix/linux.c b/src/unix/linux.c index 8fdcb12c7ea..ad881867b5c 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -789,7 +789,7 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, req->work_req.done = NULL; uv__queue_init(&req->work_req.wq); - uv__req_register(loop, req); + uv__req_register(loop); iou->in_flight++; return sqe; @@ -1157,7 +1157,7 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { req = (uv_fs_t*) (uintptr_t) e->user_data; assert(req->type == UV_FS); - uv__req_unregister(loop, req); + uv__req_unregister(loop); iou->in_flight--; /* If the op is not supported by the kernel retry using the thread pool */ diff --git a/src/unix/stream.c b/src/unix/stream.c index e369ea69c59..0eff79ffb15 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -457,7 +457,7 @@ void uv__stream_destroy(uv_stream_t* stream) { assert(stream->flags & UV_HANDLE_CLOSED); if (stream->connect_req) { - uv__req_unregister(stream->loop, stream->connect_req); + uv__req_unregister(stream->loop); stream->connect_req->cb(stream->connect_req, UV_ECANCELED); stream->connect_req = NULL; } @@ -642,7 +642,7 @@ static void uv__drain(uv_stream_t* stream) { if ((stream->flags & UV_HANDLE_CLOSING) || !(stream->flags & UV_HANDLE_SHUT)) { stream->shutdown_req = NULL; - uv__req_unregister(stream->loop, req); + uv__req_unregister(stream->loop); err = 0; if (stream->flags & UV_HANDLE_CLOSING) @@ -912,7 +912,7 @@ static void uv__write_callbacks(uv_stream_t* stream) { q = uv__queue_head(&pq); req = uv__queue_data(q, uv_write_t, queue); uv__queue_remove(q); - uv__req_unregister(stream->loop, req); + uv__req_unregister(stream->loop); if (req->bufs != NULL) { stream->write_queue_size -= uv__write_req_size(req); @@ -1272,7 +1272,7 @@ static void uv__stream_connect(uv_stream_t* stream) { return; stream->connect_req = NULL; - uv__req_unregister(stream->loop, req); + uv__req_unregister(stream->loop); if (error < 0 || uv__queue_empty(&stream->write_queue)) { uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); diff --git a/src/unix/udp.c b/src/unix/udp.c index 4e75a019571..aa214db03e9 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -100,7 +100,7 @@ static void uv__udp_run_completed(uv_udp_t* handle) { uv__queue_remove(q); req = uv__queue_data(q, uv_udp_send_t, queue); - uv__req_unregister(handle->loop, req); + uv__req_unregister(handle->loop); handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs); handle->send_queue_count--; @@ -744,7 +744,7 @@ int uv__udp_send(uv_udp_send_t* req, req->bufs = uv__malloc(nbufs * sizeof(bufs[0])); if (req->bufs == NULL) { - uv__req_unregister(handle->loop, req); + uv__req_unregister(handle->loop); return UV_ENOMEM; } diff --git a/src/uv-common.h b/src/uv-common.h index cd57e5a3515..339e5f37323 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -233,13 +233,13 @@ void uv__threadpool_cleanup(void); #define uv__has_active_reqs(loop) \ ((loop)->active_reqs.count > 0) -#define uv__req_register(loop, req) \ +#define uv__req_register(loop) \ do { \ (loop)->active_reqs.count++; \ } \ while (0) -#define uv__req_unregister(loop, req) \ +#define uv__req_unregister(loop) \ do { \ assert(uv__has_active_reqs(loop)); \ (loop)->active_reqs.count--; \ @@ -349,7 +349,7 @@ void uv__threadpool_cleanup(void); #define uv__req_init(loop, req, typ) \ do { \ UV_REQ_INIT(req, typ); \ - uv__req_register(loop, req); \ + uv__req_register(loop); \ } \ while (0) diff --git a/src/win/fs.c b/src/win/fs.c index b73c17d8c1c..19c2157169e 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -58,7 +58,7 @@ #define POST \ do { \ if (cb != NULL) { \ - uv__req_register(loop, req); \ + uv__req_register(loop); \ uv__work_submit(loop, \ &req->work_req, \ UV__WORK_FAST_IO, \ @@ -2830,7 +2830,7 @@ static void uv__fs_done(struct uv__work* w, int status) { uv_fs_t* req; req = container_of(w, uv_fs_t, work_req); - uv__req_unregister(req->loop, req); + uv__req_unregister(req->loop); if (status == UV_ECANCELED) { assert(req->result == 0); diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index 8b8406ada8e..864de13fce0 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -206,7 +206,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { } complete: - uv__req_unregister(req->loop, req); + uv__req_unregister(req->loop); /* finally do callback with converted result */ if (req->getaddrinfo_cb) @@ -325,7 +325,7 @@ int uv_getaddrinfo(uv_loop_t* loop, req->addrinfow = NULL; } - uv__req_register(loop, req); + uv__req_register(loop); if (getaddrinfo_cb) { uv__work_submit(loop, diff --git a/src/win/getnameinfo.c b/src/win/getnameinfo.c index 32863176ef6..695549580d2 100644 --- a/src/win/getnameinfo.c +++ b/src/win/getnameinfo.c @@ -82,7 +82,7 @@ static void uv__getnameinfo_done(struct uv__work* w, int status) { char* service; req = container_of(w, uv_getnameinfo_t, work_req); - uv__req_unregister(req->loop, req); + uv__req_unregister(req->loop); host = service = NULL; if (status == UV_ECANCELED) { @@ -124,7 +124,7 @@ int uv_getnameinfo(uv_loop_t* loop, } UV_REQ_INIT(req, UV_GETNAMEINFO); - uv__req_register(loop, req); + uv__req_register(loop); req->getnameinfo_cb = getnameinfo_cb; req->flags = flags; diff --git a/src/win/pipe.c b/src/win/pipe.c index 3c8abe1c28c..fc7fb410fc4 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -868,7 +868,7 @@ void uv_pipe_connect(uv_connect_t* req, SET_REQ_ERROR(req, err); uv__insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); } } @@ -959,7 +959,7 @@ int uv_pipe_connect2(uv_connect_t* req, goto error; } - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); handle->reqs_pending++; return 0; @@ -974,7 +974,7 @@ int uv_pipe_connect2(uv_connect_t* req, SET_REQ_SUCCESS(req); uv__insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); return 0; error: @@ -992,7 +992,7 @@ int uv_pipe_connect2(uv_connect_t* req, SET_REQ_ERROR(req, err); uv__insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); return 0; } @@ -1638,7 +1638,7 @@ static int uv__pipe_write_data(uv_loop_t* loop, req->u.io.queued_bytes = 0; } - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); handle->reqs_pending++; handle->stream.conn.write_reqs_pending++; POST_COMPLETION_FOR_REQ(loop, req); @@ -1686,7 +1686,7 @@ static int uv__pipe_write_data(uv_loop_t* loop, CloseHandle(req->event_handle); req->event_handle = NULL; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); handle->reqs_pending++; handle->stream.conn.write_reqs_pending++; return 0; @@ -1719,7 +1719,7 @@ static int uv__pipe_write_data(uv_loop_t* loop, } } - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); handle->reqs_pending++; handle->stream.conn.write_reqs_pending++; @@ -2132,7 +2132,7 @@ void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, assert(handle->write_queue_size >= req->u.io.queued_bytes); handle->write_queue_size -= req->u.io.queued_bytes; - UNREGISTER_HANDLE_REQ(loop, handle, req); + UNREGISTER_HANDLE_REQ(loop, handle); if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (req->wait_handle != INVALID_HANDLE_VALUE) { @@ -2219,7 +2219,7 @@ void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, assert(handle->type == UV_NAMED_PIPE); - UNREGISTER_HANDLE_REQ(loop, handle, req); + UNREGISTER_HANDLE_REQ(loop, handle); err = 0; if (REQ_SUCCESS(req)) { @@ -2251,7 +2251,7 @@ void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, /* Clear the shutdown_req field so we don't go here again. */ handle->stream.conn.shutdown_req = NULL; - UNREGISTER_HANDLE_REQ(loop, handle, req); + UNREGISTER_HANDLE_REQ(loop, handle); if (handle->flags & UV_HANDLE_CLOSING) { /* Already closing. Cancel the shutdown. */ diff --git a/src/win/req-inl.h b/src/win/req-inl.h index 9e2075906f5..ab77b0d9def 100644 --- a/src/win/req-inl.h +++ b/src/win/req-inl.h @@ -53,16 +53,16 @@ (uv__ntstatus_to_winsock_error(GET_REQ_STATUS((req)))) -#define REGISTER_HANDLE_REQ(loop, handle, req) \ +#define REGISTER_HANDLE_REQ(loop, handle) \ do { \ INCREASE_ACTIVE_COUNT((loop), (handle)); \ - uv__req_register((loop), (req)); \ + uv__req_register((loop)); \ } while (0) -#define UNREGISTER_HANDLE_REQ(loop, handle, req) \ +#define UNREGISTER_HANDLE_REQ(loop, handle) \ do { \ DECREASE_ACTIVE_COUNT((loop), (handle)); \ - uv__req_unregister((loop), (req)); \ + uv__req_unregister((loop)); \ } while (0) diff --git a/src/win/stream.c b/src/win/stream.c index 7bf9ca388cb..61a82fe4e6e 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -216,7 +216,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { handle->flags &= ~UV_HANDLE_WRITABLE; handle->stream.conn.shutdown_req = req; handle->reqs_pending++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); if (handle->stream.conn.write_reqs_pending == 0) { if (handle->type == UV_NAMED_PIPE) diff --git a/src/win/tcp.c b/src/win/tcp.c index 4ccfaff2405..c452c12e8f0 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -212,7 +212,7 @@ void uv__process_tcp_shutdown_req(uv_loop_t* loop, uv_tcp_t* stream, uv_shutdown assert(stream->flags & UV_HANDLE_CONNECTION); stream->stream.conn.shutdown_req = NULL; - UNREGISTER_HANDLE_REQ(loop, stream, req); + UNREGISTER_HANDLE_REQ(loop, stream); err = 0; if (stream->flags & UV_HANDLE_CLOSING) @@ -834,7 +834,7 @@ static int uv__tcp_try_connect(uv_connect_t* req, if (handle->delayed_error != 0) { /* Process the req without IOCP. */ handle->reqs_pending++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); uv__insert_pending_req(loop, (uv_req_t*)req); return 0; } @@ -850,12 +850,12 @@ static int uv__tcp_try_connect(uv_connect_t* req, if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { /* Process the req without IOCP. */ handle->reqs_pending++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); uv__insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(success)) { /* The req will be processed with IOCP. */ handle->reqs_pending++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); } else { return WSAGetLastError(); } @@ -925,14 +925,14 @@ int uv__tcp_write(uv_loop_t* loop, req->u.io.queued_bytes = 0; handle->reqs_pending++; handle->stream.conn.write_reqs_pending++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); uv__insert_pending_req(loop, (uv_req_t*) req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs); handle->reqs_pending++; handle->stream.conn.write_reqs_pending++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); handle->write_queue_size += req->u.io.queued_bytes; if (handle->flags & UV_HANDLE_EMULATE_IOCP && !RegisterWaitForSingleObject(&req->wait_handle, @@ -946,7 +946,7 @@ int uv__tcp_write(uv_loop_t* loop, req->u.io.queued_bytes = 0; handle->reqs_pending++; handle->stream.conn.write_reqs_pending++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); SET_REQ_ERROR(req, WSAGetLastError()); uv__insert_pending_req(loop, (uv_req_t*) req); } @@ -1117,7 +1117,7 @@ void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, assert(handle->write_queue_size >= req->u.io.queued_bytes); handle->write_queue_size -= req->u.io.queued_bytes; - UNREGISTER_HANDLE_REQ(loop, handle, req); + UNREGISTER_HANDLE_REQ(loop, handle); if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (req->wait_handle != INVALID_HANDLE_VALUE) { @@ -1209,7 +1209,7 @@ void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, assert(handle->type == UV_TCP); - UNREGISTER_HANDLE_REQ(loop, handle, req); + UNREGISTER_HANDLE_REQ(loop, handle); err = 0; if (handle->delayed_error) { diff --git a/src/win/tty.c b/src/win/tty.c index 9f8dd698d76..f9e3346968b 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -2183,7 +2183,7 @@ int uv__tty_write(uv_loop_t* loop, handle->reqs_pending++; handle->stream.conn.write_reqs_pending++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); req->u.io.queued_bytes = 0; @@ -2219,7 +2219,7 @@ void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, int err; handle->write_queue_size -= req->u.io.queued_bytes; - UNREGISTER_HANDLE_REQ(loop, handle, req); + UNREGISTER_HANDLE_REQ(loop, handle); if (req->cb) { err = GET_REQ_ERROR(req); @@ -2263,7 +2263,7 @@ void uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown assert(req); stream->stream.conn.shutdown_req = NULL; - UNREGISTER_HANDLE_REQ(loop, stream, req); + UNREGISTER_HANDLE_REQ(loop, stream); /* TTY shutdown is really just a no-op */ if (req->cb) { diff --git a/src/win/udp.c b/src/win/udp.c index 165311957d3..5c8f6e1dd0b 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -382,7 +382,7 @@ static int uv__send(uv_udp_send_t* req, handle->reqs_pending++; handle->send_queue_size += req->u.io.queued_bytes; handle->send_queue_count++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); uv__insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ @@ -390,7 +390,7 @@ static int uv__send(uv_udp_send_t* req, handle->reqs_pending++; handle->send_queue_size += req->u.io.queued_bytes; handle->send_queue_count++; - REGISTER_HANDLE_REQ(loop, handle, req); + REGISTER_HANDLE_REQ(loop, handle); } else { /* Send failed due to an error. */ return WSAGetLastError(); @@ -533,7 +533,7 @@ void uv__process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, handle->send_queue_size -= req->u.io.queued_bytes; handle->send_queue_count--; - UNREGISTER_HANDLE_REQ(loop, handle, req); + UNREGISTER_HANDLE_REQ(loop, handle); if (req->cb) { err = 0; From e37539a46c62d8e9c9303a4ef836accb23096662 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 11 Jul 2024 22:22:27 +0200 Subject: [PATCH 552/713] build: fix android ci build (#4451) It's complaining in the post-run step about a missing symbol: /__e/node20/bin/node: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found (required by /__e/node20/bin/node) For now pin actions/checkout to node 16. --- .github/workflows/CI-unix.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 993cfb74209..acc9e8a57db 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -30,6 +30,11 @@ jobs: build-android: runs-on: ubuntu-latest container: reactnativecommunity/react-native-android:2020-5-20 + # Work around an issue where the node from actions/checkout is too new + # to run inside the long-in-the-tooth react-nactive-android container + # image. + env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true steps: - uses: actions/checkout@v2 - name: Envinfo From 2780b87d56c01e3e5e174252acf762f4a60c616d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 12 Jul 2024 10:22:26 +0200 Subject: [PATCH 553/713] unix,win: export wtf8 functions properly (#4437) Mark them UV_EXTERN so they are visible on Windows. Fixes: https://github.com/libuv/libuv/issues/4436 --- include/uv.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/uv.h b/include/uv.h index f1d976ba733..44473fce8fa 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1929,17 +1929,17 @@ struct uv_loop_s { UV_EXTERN void* uv_loop_get_data(const uv_loop_t*); UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data); -/* String utilities needed internally for dealing with Windows. */ -size_t uv_utf16_length_as_wtf8(const uint16_t* utf16, - ssize_t utf16_len); -int uv_utf16_to_wtf8(const uint16_t* utf16, - ssize_t utf16_len, - char** wtf8_ptr, - size_t* wtf8_len_ptr); -ssize_t uv_wtf8_length_as_utf16(const char* wtf8); -void uv_wtf8_to_utf16(const char* wtf8, - uint16_t* utf16, - size_t utf16_len); +/* Unicode utilities needed for dealing with Windows. */ +UV_EXTERN size_t uv_utf16_length_as_wtf8(const uint16_t* utf16, + ssize_t utf16_len); +UV_EXTERN int uv_utf16_to_wtf8(const uint16_t* utf16, + ssize_t utf16_len, + char** wtf8_ptr, + size_t* wtf8_len_ptr); +UV_EXTERN ssize_t uv_wtf8_length_as_utf16(const char* wtf8); +UV_EXTERN void uv_wtf8_to_utf16(const char* wtf8, + uint16_t* utf16, + size_t utf16_len); /* Don't export the private CPP symbols. */ #undef UV_HANDLE_TYPE_PRIVATE From 90648ea3e55125a5a819b32106da6462da310da6 Mon Sep 17 00:00:00 2001 From: Olivier Valentin Date: Tue, 16 Jul 2024 22:34:02 +0200 Subject: [PATCH 554/713] hurd: add includes and macro prerequisites - ptsname() needs _XOPEN_SOURCE >= 500 - setenv needs _POSIX_C_SOURCE >= 200112 - setgroups needs grp.h --- CMakeLists.txt | 1 + src/unix/process.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 40c808b800d..d16cf76f209 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -307,6 +307,7 @@ if(APPLE) endif() if(CMAKE_SYSTEM_NAME STREQUAL "GNU") + list(APPEND uv_defines _GNU_SOURCE _POSIX_C_SOURCE=200112 _XOPEN_SOURCE=500) list(APPEND uv_libraries dl) list(APPEND uv_sources src/unix/bsd-ifaddrs.c diff --git a/src/unix/process.c b/src/unix/process.c index bc73cb694c6..f2038f2c0e8 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -55,7 +55,8 @@ extern char **environ; #endif -#if defined(__linux__) +#if defined(__linux__) || \ + defined(__GNU__) # include #endif From ae6e146775f13361748359f225574b68be6de718 Mon Sep 17 00:00:00 2001 From: Olivier Valentin Date: Thu, 18 Jul 2024 11:33:39 +0200 Subject: [PATCH 555/713] hurd: stub uv_thread_setpriority() --- src/unix/core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/unix/core.c b/src/unix/core.c index 1611cba233e..971ecf93ab2 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1616,6 +1616,7 @@ static int set_nice_for_calling_thread(int priority) { * If the function fails, the return value is non-zero. */ int uv_thread_setpriority(uv_thread_t tid, int priority) { +#if !defined(__GNU__) int r; int min; int max; @@ -1681,6 +1682,10 @@ int uv_thread_setpriority(uv_thread_t tid, int priority) { } return 0; +#else /* !defined(__GNU__) */ + /* Simulate success on systems where thread priority is not implemented. */ + return 0; +#endif /* !defined(__GNU__) */ } int uv_os_uname(uv_utsname_t* buffer) { From f279d9e6c6b23bdfa71235bc1de3e39865f5cb58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 16 Jul 2024 22:37:08 +0200 Subject: [PATCH 556/713] ci: use macOS 12 for macOS and iOS builds macOS 11 is gone: https://github.com/actions/runner-images/pull/10198 --- .github/workflows/CI-unix.yml | 8 ++++---- .github/workflows/sanitizer.yml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index acc9e8a57db..581edaaa08b 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -51,9 +51,9 @@ jobs: ls -lh build build-macos: - runs-on: macos-11 + runs-on: macos-12 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Envinfo run: npx envinfo - name: Setup @@ -86,9 +86,9 @@ jobs: make -C build-auto -j4 build-ios: - runs-on: macos-11 + runs-on: macos-12 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Configure run: | mkdir build-ios diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index fb2f1eb2869..28538174d78 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -67,9 +67,9 @@ jobs: ./build-ubsan/uv_run_tests_a sanitizers-macos: - runs-on: macos-11 + runs-on: macos-12 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Envinfo run: npx envinfo From ecc11611d3c8c4e36b67cb9adc2f4a3f1e18ab78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E8=8B=8F=E6=B3=A2=20=28Super=20Zheng=29?= Date: Mon, 20 May 2024 20:17:06 +0800 Subject: [PATCH 557/713] darwin: fix crash on iOS(arm64) Disable sendfile() on iOS with arm64 architecture to avoid crashes caused by throwing SIGSYS signal. Fixes: #3187 --- src/unix/fs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index a2c8d7638bf..aad55fed072 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1070,7 +1070,10 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { return -1; } -#elif defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) +/* sendfile() on iOS(arm64) will throw SIGSYS signal cause crash. */ +#elif (defined(__APPLE__) && !TARGET_OS_IPHONE) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) { off_t len; ssize_t r; From f56f21d7da6bbf43ae6ec59e8559b49387ab0eda Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 25 Jul 2024 12:22:22 -0400 Subject: [PATCH 558/713] Create dependabot.yml for updating github-actions (#4450) --- .github/dependabot.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..700707ced32 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" # Location of package manifests + schedule: + interval: "weekly" From 5d1ccc12c48099d720bb39f7430c480a52953039 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 26 Jul 2024 00:29:01 +0800 Subject: [PATCH 559/713] doc: correct names of Win32 APIs in fs.rst (#4408) The docs there link to GetFinalPathNameByHandleA() and CreateFileA(), but src/win/fs.c uses GetFinalPathNameByHandleW() and CreateFileW(). --- docs/src/fs.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 891ee74c19d..c039a8e6865 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -454,7 +454,7 @@ API .. c:function:: int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) - Equivalent to :man:`realpath(3)` on Unix. Windows uses `GetFinalPathNameByHandle `_. + Equivalent to :man:`realpath(3)` on Unix. Windows uses `GetFinalPathNameByHandleW `_. The resulting string is stored in `req->ptr`. .. warning:: @@ -653,7 +653,7 @@ File open constants .. note:: `UV_FS_O_RANDOM` is only supported on Windows via - `FILE_FLAG_RANDOM_ACCESS `_. + `FILE_FLAG_RANDOM_ACCESS `_. .. c:macro:: UV_FS_O_RDONLY @@ -670,7 +670,7 @@ File open constants .. note:: `UV_FS_O_SEQUENTIAL` is only supported on Windows via - `FILE_FLAG_SEQUENTIAL_SCAN `_. + `FILE_FLAG_SEQUENTIAL_SCAN `_. .. c:macro:: UV_FS_O_SHORT_LIVED @@ -678,7 +678,7 @@ File open constants .. note:: `UV_FS_O_SHORT_LIVED` is only supported on Windows via - `FILE_ATTRIBUTE_TEMPORARY `_. + `FILE_ATTRIBUTE_TEMPORARY `_. .. c:macro:: UV_FS_O_SYMLINK @@ -699,7 +699,7 @@ File open constants .. note:: `UV_FS_O_TEMPORARY` is only supported on Windows via - `FILE_ATTRIBUTE_TEMPORARY `_. + `FILE_ATTRIBUTE_TEMPORARY `_. .. c:macro:: UV_FS_O_TRUNC From 9678211c240407f97bf8fad356c1bdb80c1fb9d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:13:00 -0400 Subject: [PATCH 560/713] ci: bump upload and download-artifact versions (#4473) --- .github/workflows/CI-win.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index 79a5abf4f00..e9995e1faaf 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -99,7 +99,7 @@ jobs: `${{ matrix.config.arch }}-w64-mingw32-gcc -print-file-name=libatomic-1.dll` \ build/usr/bin - name: Upload build artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: mingw-${{ matrix.config.arch }} path: build/usr/**/* @@ -117,7 +117,7 @@ jobs: - {arch: x86_64, server: 2022} steps: - name: Download build artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: mingw-${{ matrix.config.arch }} - name: Test From 6ab153cf8ef80dbeff1943c80d6c761ff1707d91 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:13:46 -0400 Subject: [PATCH 561/713] ci: bump actions/setup-python from 4 to 5 (#4475) --- .github/workflows/CI-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI-docs.yml b/.github/workflows/CI-docs.yml index d112a98e476..00c64c1b289 100644 --- a/.github/workflows/CI-docs.yml +++ b/.github/workflows/CI-docs.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.9' cache: 'pip' # caching pip dependencies From 372e4c645ee895d76186804088ec4b331afaa1f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:15:23 -0400 Subject: [PATCH 562/713] ci: bump KyleMayes/install-llvm-action from 1 to 2 (#4472) --- .github/workflows/sanitizer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 28538174d78..7cfac3dbdc5 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -111,7 +111,7 @@ jobs: # Note: clang shipped with VS2022 has an issue where the UBSAN runtime doesn't link. - name: Install LLVM and Clang - uses: KyleMayes/install-llvm-action@v1 + uses: KyleMayes/install-llvm-action@v2 with: version: "17" From 47c833675bef34edcfaccd97a9a21b0d82aa1fc4 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 29 Jul 2024 16:16:49 -0400 Subject: [PATCH 563/713] win,error: remap ERROR_NO_DATA to EAGAIN (#4471) This was incorrectly mapped originally, which makes for confusing error messages about an EPIPE if a program happens to (unwisely) set PIPE_WAIT on the handle. It is unclear to me if libuv should try to handle this in some meaningful way, and very unclear what that way would look like, but at least expose this to the caller with the correct errno translation. --- src/win/error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/error.c b/src/win/error.c index 1490576c5da..5cc264fea86 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -78,6 +78,7 @@ int uv_translate_sys_error(int sys_errno) { case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT; case WSAEWOULDBLOCK: return UV_EAGAIN; + case ERROR_NO_DATA: return UV_EAGAIN; case WSAEALREADY: return UV_EALREADY; case ERROR_INVALID_FLAGS: return UV_EBADF; case ERROR_INVALID_HANDLE: return UV_EBADF; @@ -157,7 +158,6 @@ int uv_translate_sys_error(int sys_errno) { case ERROR_ACCESS_DENIED: return UV_EPERM; case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM; case ERROR_BAD_PIPE: return UV_EPIPE; - case ERROR_NO_DATA: return UV_EPIPE; case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE; case WSAESHUTDOWN: return UV_EPIPE; case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT; From 593aa3b2f6a7f7455584594f0b4f6e186635aa0f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 29 Jul 2024 22:30:08 +0200 Subject: [PATCH 564/713] test: handle zero-length udp datagram (#4344) Under rare but benign circumstances (on XNU), incoming datagrams appear to be dropped by the operating system after libuv has been notified of their arrival but before libuv has had a chance to receive them. Fixes: https://github.com/libuv/libuv/issues/4219 --- test/test-udp-recv-in-a-row.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/test/test-udp-recv-in-a-row.c b/test/test-udp-recv-in-a-row.c index 30745def0f6..0d97e5bf529 100644 --- a/test/test-udp-recv-in-a-row.c +++ b/test/test-udp-recv-in-a-row.c @@ -50,11 +50,16 @@ static void sv_recv_cb(uv_udp_t* handle, const uv_buf_t* rcvbuf, const struct sockaddr* addr, unsigned flags) { - if (++ recv_cnt < N) { - ASSERT_EQ(sizeof(send_data), nread); - } else { - ASSERT_OK(nread); - } + /* |nread| can be zero when the kernel drops an incoming datagram after + * marking the file descriptor as readable but before libuv has a chance + * to receive it. Libuv still invokes the uv_udp_recv_cb callback to give + * back the memory from the uv_alloc_cb callback. + * + * See https://github.com/libuv/libuv/issues/4219. + */ + recv_cnt++; + if (nread > 0) + ASSERT_EQ(nread, sizeof(send_data)); } static void check_cb(uv_check_t* handle) { @@ -63,9 +68,11 @@ static void check_cb(uv_check_t* handle) { /** * sv_recv_cb() is called with nread set to zero to indicate * there is no more udp packet in the kernel, so the actual - * recv_cnt is one larger than N. + * recv_cnt is up to one larger than N. UDP being what it is, + * packets can get dropped so don't assume an exact count. */ - ASSERT_EQ(N+1, recv_cnt); + ASSERT_GE(recv_cnt, 1); + ASSERT_LE(recv_cnt, N+1); check_cb_called = 1; /* we are done */ From e4d47c53573ea8389f16eacf4a0c4046da98b985 Mon Sep 17 00:00:00 2001 From: Viacheslav Muravyev Date: Tue, 30 Jul 2024 03:45:12 +0700 Subject: [PATCH 565/713] misc: remove splay trees macros (#4469) --- include/uv/tree.h | 249 +--------------------------------------------- 1 file changed, 1 insertion(+), 248 deletions(-) diff --git a/include/uv/tree.h b/include/uv/tree.h index 2b28835fded..0e41cb0ecee 100644 --- a/include/uv/tree.h +++ b/include/uv/tree.h @@ -35,21 +35,7 @@ #endif /* - * This file defines data structures for different types of trees: - * splay trees and red-black trees. - * - * A splay tree is a self-organizing data structure. Every operation - * on the tree causes a splay to happen. The splay moves the requested - * node to the root of the tree and partly rebalances it. - * - * This has the benefit that request locality causes faster lookups as - * the requested nodes move to the top of the tree. On the other hand, - * every lookup causes memory writes. - * - * The Balance Theorem bounds the total access time for m operations - * and n inserts on an initially empty tree as O((m + n)lg n). The - * amortized cost for a sequence of m accesses to a splay tree is O(lg n); - * + * This file defines data structures for red-black trees. * A red-black tree is a binary search tree with the node color as an * extra attribute. It fulfills a set of conditions: * - every search path from the root to a leaf consists of the @@ -61,239 +47,6 @@ * The maximum height of a red-black tree is 2lg (n+1). */ -#define SPLAY_HEAD(name, type) \ -struct name { \ - struct type *sph_root; /* root of the tree */ \ -} - -#define SPLAY_INITIALIZER(root) \ - { NULL } - -#define SPLAY_INIT(root) do { \ - (root)->sph_root = NULL; \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_ENTRY(type) \ -struct { \ - struct type *spe_left; /* left element */ \ - struct type *spe_right; /* right element */ \ -} - -#define SPLAY_LEFT(elm, field) (elm)->field.spe_left -#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right -#define SPLAY_ROOT(head) (head)->sph_root -#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) - -/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ -#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - (head)->sph_root = tmp; \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_LINKLEFT(head, tmp, field) do { \ - SPLAY_LEFT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_LINKRIGHT(head, tmp, field) do { \ - SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ - tmp = (head)->sph_root; \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ -} while (/*CONSTCOND*/ 0) - -#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ - SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ - SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \ - SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ - SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ -} while (/*CONSTCOND*/ 0) - -/* Generates prototypes and inline functions */ - -#define SPLAY_PROTOTYPE(name, type, field, cmp) \ -void name##_SPLAY(struct name *, struct type *); \ -void name##_SPLAY_MINMAX(struct name *, int); \ -struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ -struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ - \ -/* Finds the node with the same key as elm */ \ -static __inline struct type * \ -name##_SPLAY_FIND(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) \ - return(NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) \ - return (head->sph_root); \ - return (NULL); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_NEXT(struct name *head, struct type *elm) \ -{ \ - name##_SPLAY(head, elm); \ - if (SPLAY_RIGHT(elm, field) != NULL) { \ - elm = SPLAY_RIGHT(elm, field); \ - while (SPLAY_LEFT(elm, field) != NULL) { \ - elm = SPLAY_LEFT(elm, field); \ - } \ - } else \ - elm = NULL; \ - return (elm); \ -} \ - \ -static __inline struct type * \ -name##_SPLAY_MIN_MAX(struct name *head, int val) \ -{ \ - name##_SPLAY_MINMAX(head, val); \ - return (SPLAY_ROOT(head)); \ -} - -/* Main splay operation. - * Moves node close to the key of elm to top - */ -#define SPLAY_GENERATE(name, type, field, cmp) \ -struct type * \ -name##_SPLAY_INSERT(struct name *head, struct type *elm) \ -{ \ - if (SPLAY_EMPTY(head)) { \ - SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ - } else { \ - int __comp; \ - name##_SPLAY(head, elm); \ - __comp = (cmp)(elm, (head)->sph_root); \ - if(__comp < 0) { \ - SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \ - SPLAY_RIGHT(elm, field) = (head)->sph_root; \ - SPLAY_LEFT((head)->sph_root, field) = NULL; \ - } else if (__comp > 0) { \ - SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \ - SPLAY_LEFT(elm, field) = (head)->sph_root; \ - SPLAY_RIGHT((head)->sph_root, field) = NULL; \ - } else \ - return ((head)->sph_root); \ - } \ - (head)->sph_root = (elm); \ - return (NULL); \ -} \ - \ -struct type * \ -name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ -{ \ - struct type *__tmp; \ - if (SPLAY_EMPTY(head)) \ - return (NULL); \ - name##_SPLAY(head, elm); \ - if ((cmp)(elm, (head)->sph_root) == 0) { \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ - (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ - } else { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ - name##_SPLAY(head, elm); \ - SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ - } \ - return (elm); \ - } \ - return (NULL); \ -} \ - \ -void \ -name##_SPLAY(struct name *head, struct type *elm) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ - int __comp; \ - \ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ - __left = __right = &__node; \ - \ - while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if ((cmp)(elm, __tmp) > 0){ \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} \ - \ -/* Splay with either the minimum or the maximum element \ - * Used to find minimum or maximum element in tree. \ - */ \ -void name##_SPLAY_MINMAX(struct name *head, int __comp) \ -{ \ - struct type __node, *__left, *__right, *__tmp; \ - \ - SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \ - __left = __right = &__node; \ - \ - for (;;) { \ - if (__comp < 0) { \ - __tmp = SPLAY_LEFT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp < 0){ \ - SPLAY_ROTATE_RIGHT(head, __tmp, field); \ - if (SPLAY_LEFT((head)->sph_root, field) == NULL) \ - break; \ - } \ - SPLAY_LINKLEFT(head, __right, field); \ - } else if (__comp > 0) { \ - __tmp = SPLAY_RIGHT((head)->sph_root, field); \ - if (__tmp == NULL) \ - break; \ - if (__comp > 0) { \ - SPLAY_ROTATE_LEFT(head, __tmp, field); \ - if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \ - break; \ - } \ - SPLAY_LINKRIGHT(head, __left, field); \ - } \ - } \ - SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ -} - -#define SPLAY_NEGINF -1 -#define SPLAY_INF 1 - -#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) -#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) -#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) -#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) -#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) -#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ - : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) - -#define SPLAY_FOREACH(x, name, head) \ - for ((x) = SPLAY_MIN(name, head); \ - (x) != NULL; \ - (x) = SPLAY_NEXT(name, head, x)) - /* Macros that define a red-black tree */ #define RB_HEAD(name, type) \ struct name { \ From 0c36b16d1b4c14ebc910b2de0112a258c01cf720 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 29 Jul 2024 22:45:31 +0200 Subject: [PATCH 566/713] test,openbsd: remove superfluous ifdef guard (#4461) The test is skipped in its entirety on OpenBSD so there is no point in compiling out code on said platform later on, it's not run anyway. --- test/test-udp-multicast-join.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-udp-multicast-join.c b/test/test-udp-multicast-join.c index 7e8fbe39f08..9e322dc579f 100644 --- a/test/test-udp-multicast-join.c +++ b/test/test-udp-multicast-join.c @@ -126,7 +126,7 @@ static void cl_recv_cb(uv_udp_t* handle, r = uv_udp_set_membership(&server, MULTICAST_ADDR, NULL, UV_LEAVE_GROUP); ASSERT_OK(r); -#if !defined(__OpenBSD__) && !defined(__NetBSD__) +#if !defined(__NetBSD__) r = uv_udp_set_source_membership(&server, MULTICAST_ADDR, NULL, source_addr, UV_JOIN_GROUP); ASSERT_OK(r); #endif From 18266a69696349e9641871f55b88ad6e732a8789 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 29 Jul 2024 17:38:26 -0400 Subject: [PATCH 567/713] win,fs: use posix delete semantics, if supported (#4318) Implements posix delete for files and dirs, with fallback to the old method if not supported (e.g. Fat32 or Win8). Fixes: #3839 --- src/win/fs.c | 128 ++++++++++++++++++++++++++++++++--------------- src/win/winapi.h | 13 +++++ test/test-fs.c | 42 +++++++++++++++- test/test-list.h | 2 + 4 files changed, 143 insertions(+), 42 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 19c2157169e..8414f778462 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -46,6 +46,17 @@ #define UV_FS_FREE_PTR 0x0008 #define UV_FS_CLEANEDUP 0x0010 +#ifndef FILE_DISPOSITION_DELETE +#define FILE_DISPOSITION_DELETE 0x0001 +#endif /* FILE_DISPOSITION_DELETE */ + +#ifndef FILE_DISPOSITION_POSIX_SEMANTICS +#define FILE_DISPOSITION_POSIX_SEMANTICS 0x0002 +#endif /* FILE_DISPOSITION_POSIX_SEMANTICS */ + +#ifndef FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE +#define FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE 0x0010 +#endif /* FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE */ #define INIT(subtype) \ do { \ @@ -1061,22 +1072,15 @@ void fs__write(uv_fs_t* req) { } -void fs__rmdir(uv_fs_t* req) { - int result = _wrmdir(req->file.pathw); - if (result == -1) - SET_REQ_WIN32_ERROR(req, _doserrno); - else - SET_REQ_RESULT(req, 0); -} - - -void fs__unlink(uv_fs_t* req) { +static void fs__unlink_rmdir(uv_fs_t* req, BOOL isrmdir) { const WCHAR* pathw = req->file.pathw; HANDLE handle; BY_HANDLE_FILE_INFORMATION info; FILE_DISPOSITION_INFORMATION disposition; + FILE_DISPOSITION_INFORMATION_EX disposition_ex; IO_STATUS_BLOCK iosb; NTSTATUS status; + DWORD error; handle = CreateFileW(pathw, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE, @@ -1097,10 +1101,17 @@ void fs__unlink(uv_fs_t* req) { return; } - if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - /* Do not allow deletion of directories, unless it is a symlink. When the - * path refers to a non-symlink directory, report EPERM as mandated by - * POSIX.1. */ + if (isrmdir && !(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + /* Error if we're in rmdir mode but it is not a dir */ + SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY); + CloseHandle(handle); + return; + } + + if (!isrmdir && (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + /* If not explicitly allowed, do not allow deletion of directories, unless + * it is a symlink. When the path refers to a non-symlink directory, report + * EPERM as mandated by POSIX.1. */ /* Check if it is a reparse point. If it's not, it's a normal directory. */ if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { @@ -1112,7 +1123,7 @@ void fs__unlink(uv_fs_t* req) { /* Read the reparse point and check if it is a valid symlink. If not, don't * unlink. */ if (fs__readlink_handle(handle, NULL, NULL) < 0) { - DWORD error = GetLastError(); + error = GetLastError(); if (error == ERROR_SYMLINK_NOT_SUPPORTED) error = ERROR_ACCESS_DENIED; SET_REQ_WIN32_ERROR(req, error); @@ -1121,42 +1132,77 @@ void fs__unlink(uv_fs_t* req) { } } - if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { - /* Remove read-only attribute */ - FILE_BASIC_INFORMATION basic = { 0 }; - - basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) | - FILE_ATTRIBUTE_ARCHIVE; - - status = pNtSetInformationFile(handle, - &iosb, - &basic, - sizeof basic, - FileBasicInformation); - if (!NT_SUCCESS(status)) { - SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); - CloseHandle(handle); - return; - } - } + /* Try posix delete first */ + disposition_ex.Flags = FILE_DISPOSITION_DELETE | FILE_DISPOSITION_POSIX_SEMANTICS | + FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE; - /* Try to set the delete flag. */ - disposition.DeleteFile = TRUE; status = pNtSetInformationFile(handle, &iosb, - &disposition, - sizeof disposition, - FileDispositionInformation); + &disposition_ex, + sizeof disposition_ex, + FileDispositionInformationEx); if (NT_SUCCESS(status)) { SET_REQ_SUCCESS(req); } else { - SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + /* If status == STATUS_CANNOT_DELETE here, given we set + * FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE, STATUS_CANNOT_DELETE can only mean + * that there is an existing mapped view to the file, preventing delete. + * STATUS_CANNOT_DELETE maps to UV_EACCES so it's not specifically worth handling */ + error = pRtlNtStatusToDosError(status); + if (error == ERROR_NOT_SUPPORTED /* filesystem does not support posix deletion */ || + error == ERROR_INVALID_PARAMETER /* pre Windows 10 error */ || + error == ERROR_INVALID_FUNCTION /* pre Windows 10 1607 error */) { + /* posix delete not supported so try fallback */ + if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + /* Remove read-only attribute */ + FILE_BASIC_INFORMATION basic = { 0 }; + + basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) | + FILE_ATTRIBUTE_ARCHIVE; + + status = pNtSetInformationFile(handle, + &iosb, + &basic, + sizeof basic, + FileBasicInformation); + if (!NT_SUCCESS(status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + CloseHandle(handle); + return; + } + } + + /* Try to set the delete flag. */ + disposition.DeleteFile = TRUE; + status = pNtSetInformationFile(handle, + &iosb, + &disposition, + sizeof disposition, + FileDispositionInformation); + if (NT_SUCCESS(status)) { + SET_REQ_SUCCESS(req); + } else { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + } + } else { + SET_REQ_WIN32_ERROR(req, error); + } } CloseHandle(handle); } +static void fs__rmdir(uv_fs_t* req) { + fs__unlink_rmdir(req, /*isrmdir*/1); +} + + +static void fs__unlink(uv_fs_t* req) { + fs__unlink_rmdir(req, /*isrmdir*/0); +} + + void fs__mkdir(uv_fs_t* req) { /* TODO: use req->mode. */ if (CreateDirectoryW(req->file.pathw, NULL)) { @@ -1182,7 +1228,7 @@ void fs__mktemp(uv_fs_t* req, uv__fs_mktemp_func func) { size_t len; uint64_t v; char* path; - + path = (char*)req->path; len = wcslen(req->file.pathw); ep = req->file.pathw + len; @@ -1655,7 +1701,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | ((_S_IREAD | _S_IWRITE) >> 6); statbuf->st_nlink = 1; - statbuf->st_blksize = 4096; + statbuf->st_blksize = 4096; statbuf->st_rdev = FILE_DEVICE_NULL << 16; return 0; } diff --git a/src/win/winapi.h b/src/win/winapi.h index d380bda42a3..d3449c18997 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4224,6 +4224,15 @@ typedef enum _FILE_INFORMATION_CLASS { FileNumaNodeInformation, FileStandardLinkInformation, FileRemoteProtocolInformation, + FileRenameInformationBypassAccessCheck, + FileLinkInformationBypassAccessCheck, + FileVolumeNameInformation, + FileIdInformation, + FileIdExtdDirectoryInformation, + FileReplaceCompletionInformation, + FileHardLinkFullIdInformation, + FileIdExtdBothDirectoryInformation, + FileDispositionInformationEx, /* based on https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ne-wdm-_file_information_class */ FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; @@ -4323,6 +4332,10 @@ typedef struct _FILE_DISPOSITION_INFORMATION { BOOLEAN DeleteFile; } FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION; +typedef struct _FILE_DISPOSITION_INFORMATION_EX { + DWORD Flags; +} FILE_DISPOSITION_INFORMATION_EX, *PFILE_DISPOSITION_INFORMATION_EX; + typedef struct _FILE_PIPE_LOCAL_INFORMATION { ULONG NamedPipeType; ULONG NamedPipeConfiguration; diff --git a/test/test-fs.c b/test/test-fs.c index fe78117bbed..ccecb18936a 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -104,6 +104,7 @@ static uv_loop_t* loop; static uv_fs_t open_req1; static uv_fs_t open_req2; +static uv_fs_t open_req_noclose; static uv_fs_t read_req; static uv_fs_t write_req; static uv_fs_t unlink_req; @@ -304,7 +305,7 @@ static void chown_root_cb(uv_fs_t* req) { ASSERT_EQ(req->result, UV_EINVAL); # elif defined(__PASE__) /* On IBMi PASE, there is no root user. uid 0 is user qsecofr. - * User may grant qsecofr's privileges, including changing + * User may grant qsecofr's privileges, including changing * the file's ownership to uid 0. */ ASSERT(req->result == 0 || req->result == UV_EPERM); @@ -1067,6 +1068,45 @@ TEST_IMPL(fs_file_sync) { return 0; } +TEST_IMPL(fs_posix_delete) { + int r; + + /* Setup. */ + unlink("test_dir/file"); + rmdir("test_dir"); + + r = uv_fs_mkdir(NULL, &mkdir_req, "test_dir", 0755, NULL); + ASSERT_OK(r); + + r = uv_fs_open(NULL, &open_req_noclose, "test_dir/file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR, NULL); + ASSERT_GE(r, 0); + uv_fs_req_cleanup(&open_req_noclose); + + /* should not be possible to delete the non-empty dir */ + r = uv_fs_rmdir(NULL, &rmdir_req, "test_dir", NULL); + ASSERT_EQ(r, UV_ENOTEMPTY); + ASSERT_EQ(r, rmdir_req.result); + uv_fs_req_cleanup(&rmdir_req); + + r = uv_fs_unlink(NULL, &unlink_req, "test_dir/file", NULL); + ASSERT_OK(r); + ASSERT_OK(unlink_req.result); + uv_fs_req_cleanup(&unlink_req); + + /* delete the dir while the file is still open, which should succeed on posix */ + r = uv_fs_rmdir(NULL, &rmdir_req, "test_dir", NULL); + ASSERT_OK(r); + ASSERT_OK(rmdir_req.result); + uv_fs_req_cleanup(&rmdir_req); + + /* Cleanup */ + r = uv_fs_close(NULL, &close_req, open_req_noclose.result, NULL); + ASSERT_OK(r); + uv_fs_req_cleanup(&close_req); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} static void fs_file_write_null_buffer(int add_flags) { int r; diff --git a/test/test-list.h b/test/test-list.h index d600aef29a8..68878cf8020 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -354,6 +354,7 @@ TEST_DECLARE (fs_file_nametoolong) TEST_DECLARE (fs_file_loop) TEST_DECLARE (fs_file_async) TEST_DECLARE (fs_file_sync) +TEST_DECLARE (fs_posix_delete) TEST_DECLARE (fs_file_write_null_buffer) TEST_DECLARE (fs_async_dir) TEST_DECLARE (fs_async_sendfile) @@ -1062,6 +1063,7 @@ TASK_LIST_START TEST_ENTRY (fs_file_loop) TEST_ENTRY (fs_file_async) TEST_ENTRY (fs_file_sync) + TEST_ENTRY (fs_posix_delete) TEST_ENTRY (fs_file_write_null_buffer) TEST_ENTRY (fs_async_dir) TEST_ENTRY (fs_async_sendfile) From 83306585ff03dc1325f272922ad9c7737c2ad0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= <110401522+huseyinacacak-janea@users.noreply.github.com> Date: Tue, 30 Jul 2024 00:50:11 +0300 Subject: [PATCH 568/713] win: fix env var in uv_os_homedir and uv_os_tmpdir (#4464) If the corresponding environment variables are empty, the uv_us_homedir() and uv_os_tmpdir() return garbage values. The reason for this situation is the Windows API which doesn't return an error even if the path is empty. This PR fixes this problem by checking the return value of the API call. If it is not an error and the length of the value is less than 3, uv_us_homedir() and uv_os_tmpdir() will return UV_ENOENT. Fixes: https://github.com/libuv/libuv/issues/2328 --- src/win/util.c | 13 ++++++++++++- test/test-homedir.c | 9 +++++++++ test/test-tmpdir.c | 7 +++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/win/util.c b/src/win/util.c index c4dd8bf741f..628136c4e6d 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -942,8 +942,13 @@ int uv_os_homedir(char* buffer, size_t* size) { r = uv_os_getenv("USERPROFILE", buffer, size); /* Don't return an error if USERPROFILE was not found. */ - if (r != UV_ENOENT) + if (r != UV_ENOENT) { + /* USERPROFILE is empty or invalid */ + if (r == 0 && *size < 3) { + return UV_ENOENT; + } return r; + } /* USERPROFILE is not set, so call uv_os_get_passwd() */ r = uv_os_get_passwd(&pwd); @@ -980,6 +985,12 @@ int uv_os_tmpdir(char* buffer, size_t* size) { if (len == 0) { return uv_translate_sys_error(GetLastError()); } + + /* tmp path is empty or invalid */ + if (len < 3) { + return UV_ENOENT; + } + /* Include space for terminating null char. */ len += 1; path = uv__malloc(len * sizeof(wchar_t)); diff --git a/test/test-homedir.c b/test/test-homedir.c index 769d5c8179f..e335540d106 100644 --- a/test/test-homedir.c +++ b/test/test-homedir.c @@ -68,5 +68,14 @@ TEST_IMPL(homedir) { r = uv_os_homedir(homedir, &len); ASSERT_EQ(r, UV_EINVAL); +#ifdef _WIN32 + /* Test empty environment variable */ + r = uv_os_setenv("USERPROFILE", ""); + ASSERT_EQ(r, 0); + len = sizeof homedir; + r = uv_os_homedir(homedir, &len); + ASSERT_EQ(r, UV_ENOENT); +#endif + return 0; } diff --git a/test/test-tmpdir.c b/test/test-tmpdir.c index a4e9ce950aa..c8fc8e06a8b 100644 --- a/test/test-tmpdir.c +++ b/test/test-tmpdir.c @@ -76,6 +76,13 @@ TEST_IMPL(tmpdir) { size_t lenx = sizeof tmpdirx; r = uv_os_tmpdir(tmpdirx, &lenx); ASSERT_OK(r); + + /* Test empty environment variable */ + r = uv_os_setenv("TMP", ""); + ASSERT_EQ(r, 0); + len = sizeof tmpdir; + r = uv_os_tmpdir(tmpdir, &len); + ASSERT_EQ(r, UV_ENOENT); #endif return 0; From badecdca14d30fbfea655b7d4b18bdb4b3518c5d Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 30 Jul 2024 00:59:38 +0200 Subject: [PATCH 569/713] fsevents: detect watched directory removal (#4376) Which was broken both in `windows` and `macos`. --- src/unix/fsevents.c | 4 - src/win/fs-event.c | 20 ++++- test/test-fs-event.c | 186 ++++++++++++++++++++++++++++++------------- test/test-list.h | 2 + 4 files changed, 152 insertions(+), 60 deletions(-) diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c index 5efe495e694..7fb6bb2ec36 100644 --- a/src/unix/fsevents.c +++ b/src/unix/fsevents.c @@ -276,10 +276,6 @@ static void uv__fsevents_event_cb(const FSEventStreamRef streamRef, path += handle->realpath_len; len -= handle->realpath_len; - /* Ignore events with path equal to directory itself */ - if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir)) - continue; - if (len == 0) { /* Since we're using fsevents to watch the file itself, * realpath == path, and we now need to get the basename of the file back diff --git a/src/win/fs-event.c b/src/win/fs-event.c index fce411813e9..7ab407e0534 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -561,7 +561,25 @@ void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } } else { err = GET_REQ_ERROR(req); - handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); + /* + * Check whether the ERROR_ACCESS_DENIED is caused by the watched directory + * being actually deleted (not an actual error) or a legit error. Retrieve + * FileStandardInfo to check whether the directory is pending deletion. + */ + FILE_STANDARD_INFO info; + if (err == ERROR_ACCESS_DENIED && + handle->dirw != NULL && + GetFileInformationByHandleEx(handle->dir_handle, + FileStandardInfo, + &info, + sizeof(info)) && + info.Directory && + info.DeletePending) { + uv__convert_utf16_to_utf8(handle->dirw, -1, &filename); + handle->cb(handle, filename, UV_RENAME, 0); + } else { + handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); + } } if (handle->flags & UV_HANDLE_CLOSING) { diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 67910880a73..ccfa2cbe1a8 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -81,6 +81,22 @@ static void create_file(const char* name) { uv_fs_req_cleanup(&req); } +static int delete_dir(const char* name) { + int r; + uv_fs_t req; + r = uv_fs_rmdir(NULL, &req, name, NULL); + uv_fs_req_cleanup(&req); + return r; +} + +static int delete_file(const char* name) { + int r; + uv_fs_t req; + r = uv_fs_unlink(NULL, &req, name, NULL); + uv_fs_req_cleanup(&req); + return r; +} + static void touch_file(const char* name) { int r; uv_file file; @@ -129,6 +145,19 @@ static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename, uv_close((uv_handle_t*)handle, close_cb); } +static void fs_event_cb_del_dir(uv_fs_event_t* handle, + const char* filename, + int events, + int status) { + ++fs_event_cb_called; + ASSERT_PTR_EQ(handle, &fs_event); + ASSERT_OK(status); + ASSERT_EQ(events, UV_RENAME); + ASSERT_OK(strcmp(filename, "watch_del_dir")); + ASSERT_OK(uv_fs_event_stop(handle)); + uv_close((uv_handle_t*)handle, close_cb); +} + static const char* fs_event_get_filename(int i) { snprintf(fs_event_filename, sizeof(fs_event_filename), @@ -152,6 +181,15 @@ static void fs_event_create_files(uv_timer_t* handle) { } } +static void fs_event_del_dir(uv_timer_t* handle) { + int r; + + r = delete_dir("watch_del_dir"); + ASSERT_OK(r); + + uv_close((uv_handle_t*)handle, close_cb); +} + static void fs_event_unlink_files(uv_timer_t* handle) { int r; int i; @@ -160,7 +198,7 @@ static void fs_event_unlink_files(uv_timer_t* handle) { if (handle == NULL) { /* Unlink all files */ for (i = 0; i < 16; i++) { - r = remove(fs_event_get_filename(i)); + r = delete_file(fs_event_get_filename(i)); if (handle != NULL) ASSERT_OK(r); } @@ -169,7 +207,7 @@ static void fs_event_unlink_files(uv_timer_t* handle) { ASSERT_LT(fs_event_removed, fs_event_file_count); /* Remove the file */ - ASSERT_OK(remove(fs_event_get_filename(fs_event_removed))); + ASSERT_OK(delete_file(fs_event_get_filename(fs_event_removed))); if (++fs_event_removed < fs_event_file_count) { /* Remove another file on a different event loop tick. We do it this way @@ -237,7 +275,7 @@ static void fs_event_unlink_files_in_subdir(uv_timer_t* handle) { if (handle == NULL) { /* Unlink all files */ for (i = 0; i < 16; i++) { - r = remove(fs_event_get_filename_in_subdir(i)); + r = delete_file(fs_event_get_filename_in_subdir(i)); if (handle != NULL) ASSERT_OK(r); } @@ -246,7 +284,7 @@ static void fs_event_unlink_files_in_subdir(uv_timer_t* handle) { ASSERT_LT(fs_event_removed, fs_event_file_count); /* Remove the file */ - ASSERT_OK(remove(fs_event_get_filename_in_subdir(fs_event_removed))); + ASSERT_OK(delete_file(fs_event_get_filename_in_subdir(fs_event_removed))); if (++fs_event_removed < fs_event_file_count) { /* Remove another file on a different event loop tick. We do it this way @@ -407,9 +445,9 @@ TEST_IMPL(fs_event_watch_dir) { /* Setup */ fs_event_unlink_files(NULL); - remove("watch_dir/file2"); - remove("watch_dir/file1"); - remove("watch_dir/"); + delete_file("watch_dir/file2"); + delete_file("watch_dir/file1"); + delete_dir("watch_dir/"); create_dir("watch_dir"); r = uv_fs_event_init(loop, &fs_event); @@ -428,9 +466,47 @@ TEST_IMPL(fs_event_watch_dir) { /* Cleanup */ fs_event_unlink_files(NULL); - remove("watch_dir/file2"); - remove("watch_dir/file1"); - remove("watch_dir/"); + delete_file("watch_dir/file2"); + delete_file("watch_dir/file1"); + delete_dir("watch_dir/"); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + +TEST_IMPL(fs_event_watch_delete_dir) { +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#elif defined(__MVS__) + RETURN_SKIP("Directory watching not supported on this platform."); +#elif defined(__APPLE__) && defined(__TSAN__) + RETURN_SKIP("Times out under TSAN."); +#endif + + uv_loop_t* loop = uv_default_loop(); + int r; + + /* Setup */ + fs_event_unlink_files(NULL); + delete_dir("watch_del_dir/"); + create_dir("watch_del_dir"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT_OK(r); + r = uv_fs_event_start(&fs_event, fs_event_cb_del_dir, "watch_del_dir", 0); + ASSERT_OK(r); + r = uv_timer_init(loop, &timer); + ASSERT_OK(r); + r = uv_timer_start(&timer, fs_event_del_dir, 100, 0); + ASSERT_OK(r); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT_EQ(1, fs_event_cb_called); + ASSERT_EQ(2, close_cb_called); + + /* Cleanup */ + fs_event_unlink_files(NULL); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -448,10 +524,10 @@ TEST_IMPL(fs_event_watch_dir_recursive) { /* Setup */ loop = uv_default_loop(); fs_event_unlink_files(NULL); - remove("watch_dir/file2"); - remove("watch_dir/file1"); - remove("watch_dir/subdir"); - remove("watch_dir/"); + delete_file("watch_dir/file2"); + delete_file("watch_dir/file1"); + delete_dir("watch_dir/subdir"); + delete_dir("watch_dir/"); create_dir("watch_dir"); create_dir("watch_dir/subdir"); @@ -491,10 +567,10 @@ TEST_IMPL(fs_event_watch_dir_recursive) { /* Cleanup */ fs_event_unlink_files_in_subdir(NULL); - remove("watch_dir/file2"); - remove("watch_dir/file1"); - remove("watch_dir/subdir"); - remove("watch_dir/"); + delete_file("watch_dir/file2"); + delete_file("watch_dir/file1"); + delete_dir("watch_dir/subdir"); + delete_dir("watch_dir/"); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -512,8 +588,8 @@ TEST_IMPL(fs_event_watch_dir_short_path) { /* Setup */ loop = uv_default_loop(); - remove("watch_dir/file1"); - remove("watch_dir/"); + delete_file("watch_dir/file1"); + delete_dir("watch_dir/"); create_dir("watch_dir"); create_file("watch_dir/file1"); @@ -540,8 +616,8 @@ TEST_IMPL(fs_event_watch_dir_short_path) { } /* Cleanup */ - remove("watch_dir/file1"); - remove("watch_dir/"); + delete_file("watch_dir/file1"); + delete_dir("watch_dir/"); MAKE_VALGRIND_HAPPY(loop); @@ -562,9 +638,9 @@ TEST_IMPL(fs_event_watch_file) { int r; /* Setup */ - remove("watch_dir/file2"); - remove("watch_dir/file1"); - remove("watch_dir/"); + delete_file("watch_dir/file2"); + delete_file("watch_dir/file1"); + delete_dir("watch_dir/"); create_dir("watch_dir"); create_file("watch_dir/file1"); create_file("watch_dir/file2"); @@ -585,9 +661,9 @@ TEST_IMPL(fs_event_watch_file) { ASSERT_EQ(2, close_cb_called); /* Cleanup */ - remove("watch_dir/file2"); - remove("watch_dir/file1"); - remove("watch_dir/"); + delete_file("watch_dir/file2"); + delete_file("watch_dir/file1"); + delete_dir("watch_dir/"); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -609,9 +685,9 @@ TEST_IMPL(fs_event_watch_file_exact_path) { loop = uv_default_loop(); /* Setup */ - remove("watch_dir/file.js"); - remove("watch_dir/file.jsx"); - remove("watch_dir/"); + delete_file("watch_dir/file.js"); + delete_file("watch_dir/file.jsx"); + delete_dir("watch_dir/"); create_dir("watch_dir"); create_file("watch_dir/file.js"); create_file("watch_dir/file.jsx"); @@ -638,9 +714,9 @@ TEST_IMPL(fs_event_watch_file_exact_path) { ASSERT_EQ(2, timer_cb_exact_called); /* Cleanup */ - remove("watch_dir/file.js"); - remove("watch_dir/file.jsx"); - remove("watch_dir/"); + delete_file("watch_dir/file.js"); + delete_file("watch_dir/file.jsx"); + delete_dir("watch_dir/"); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -681,7 +757,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) { loop = uv_default_loop(); /* Setup */ - remove("watch_file"); + delete_file("watch_file"); create_file("watch_file"); #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_12) /* Empirically, kevent seems to (sometimes) report the preceding @@ -719,7 +795,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) { ASSERT_EQ(1, close_cb_called); /* Cleanup */ - remove("watch_file"); + delete_file("watch_file"); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -761,8 +837,8 @@ TEST_IMPL(fs_event_no_callback_after_close) { int r; /* Setup */ - remove("watch_dir/file1"); - remove("watch_dir/"); + delete_file("watch_dir/file1"); + delete_dir("watch_dir/"); create_dir("watch_dir"); create_file("watch_dir/file1"); @@ -783,8 +859,8 @@ TEST_IMPL(fs_event_no_callback_after_close) { ASSERT_EQ(1, close_cb_called); /* Cleanup */ - remove("watch_dir/file1"); - remove("watch_dir/"); + delete_file("watch_dir/file1"); + delete_dir("watch_dir/"); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -799,8 +875,8 @@ TEST_IMPL(fs_event_no_callback_on_close) { int r; /* Setup */ - remove("watch_dir/file1"); - remove("watch_dir/"); + delete_file("watch_dir/file1"); + delete_dir("watch_dir/"); create_dir("watch_dir"); create_file("watch_dir/file1"); @@ -820,8 +896,8 @@ TEST_IMPL(fs_event_no_callback_on_close) { ASSERT_EQ(1, close_cb_called); /* Cleanup */ - remove("watch_dir/file1"); - remove("watch_dir/"); + delete_file("watch_dir/file1"); + delete_dir("watch_dir/"); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -893,8 +969,8 @@ TEST_IMPL(fs_event_close_with_pending_event) { ASSERT_EQ(1, close_cb_called); /* Clean up */ - remove("watch_dir/file"); - remove("watch_dir/"); + delete_file("watch_dir/file"); + delete_dir("watch_dir/"); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -918,7 +994,7 @@ TEST_IMPL(fs_event_close_with_pending_delete_event) { ASSERT_OK(r); /* Generate an fs event. */ - remove("watch_dir/file"); + delete_file("watch_dir/file"); /* Allow time for the remove event to propagate to the pending list. */ /* XXX - perhaps just for __sun? */ @@ -932,7 +1008,7 @@ TEST_IMPL(fs_event_close_with_pending_delete_event) { ASSERT_EQ(1, close_cb_called); /* Clean up */ - remove("watch_dir/"); + delete_dir("watch_dir/"); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -975,7 +1051,7 @@ TEST_IMPL(fs_event_close_in_callback) { /* Clean up */ fs_event_unlink_files(NULL); - remove("watch_dir/"); + delete_dir("watch_dir/"); MAKE_VALGRIND_HAPPY(loop); return 0; @@ -1011,7 +1087,7 @@ TEST_IMPL(fs_event_start_and_close) { ASSERT_EQ(2, close_cb_called); - remove("watch_dir/"); + delete_dir("watch_dir/"); MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1064,7 +1140,7 @@ TEST_IMPL(fs_event_getpath) { close_cb_called = 0; } - remove("watch_dir/"); + delete_dir("watch_dir/"); MAKE_VALGRIND_HAPPY(loop); return 0; } @@ -1103,7 +1179,7 @@ TEST_IMPL(fs_event_error_reporting) { TEST_FILE_LIMIT(ARRAY_SIZE(loops) * 3); - remove("watch_dir/"); + delete_dir("watch_dir/"); create_dir("watch_dir"); /* Create a lot of loops, and start FSEventStream in each of them. @@ -1153,7 +1229,7 @@ TEST_IMPL(fs_event_error_reporting) { uv_loop_close(loop); } while (i-- != 0); - remove("watch_dir/"); + delete_dir("watch_dir/"); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } @@ -1207,7 +1283,7 @@ TEST_IMPL(fs_event_stop_in_cb) { RETURN_SKIP(NO_FS_EVENTS); #endif - remove(path); + delete_file(path); create_file(path); ASSERT_OK(uv_fs_event_init(uv_default_loop(), &fs)); @@ -1230,7 +1306,7 @@ TEST_IMPL(fs_event_stop_in_cb) { ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT_EQ(1, fs_event_cb_stop_calls); - remove(path); + delete_file(path); MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; diff --git a/test/test-list.h b/test/test-list.h index 68878cf8020..1bc8c9a9b1e 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -396,6 +396,7 @@ TEST_DECLARE (fs_stat_missing_path) TEST_DECLARE (fs_read_bufs) TEST_DECLARE (fs_read_file_eof) TEST_DECLARE (fs_event_watch_dir) +TEST_DECLARE (fs_event_watch_delete_dir) TEST_DECLARE (fs_event_watch_dir_recursive) #ifdef _WIN32 TEST_DECLARE (fs_event_watch_dir_short_path) @@ -1105,6 +1106,7 @@ TASK_LIST_START TEST_ENTRY (fs_read_file_eof) TEST_ENTRY (fs_file_open_append) TEST_ENTRY (fs_event_watch_dir) + TEST_ENTRY (fs_event_watch_delete_dir) TEST_ENTRY (fs_event_watch_dir_recursive) #ifdef _WIN32 TEST_ENTRY (fs_event_watch_dir_short_path) From 63b22be08375372c429ec83e7a933a643adfd73c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 19:54:23 -0400 Subject: [PATCH 570/713] ci: bump actions/checkout to 4 (#4474) Held back one due to https://github.com/libuv/libuv/pull/4451 --- .github/workflows/CI-docs.yml | 2 +- .github/workflows/CI-sample.yml | 2 +- .github/workflows/CI-unix.yml | 6 +++--- .github/workflows/CI-win.yml | 4 ++-- .github/workflows/sanitizer.yml | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/CI-docs.yml b/.github/workflows/CI-docs.yml index 00c64c1b289..f414448814c 100644 --- a/.github/workflows/CI-docs.yml +++ b/.github/workflows/CI-docs.yml @@ -11,7 +11,7 @@ jobs: docs-src: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: '3.9' diff --git a/.github/workflows/CI-sample.yml b/.github/workflows/CI-sample.yml index 4bd82f9f2eb..14ffd4cb6b4 100644 --- a/.github/workflows/CI-sample.yml +++ b/.github/workflows/CI-sample.yml @@ -21,7 +21,7 @@ jobs: os: [macos-latest, ubuntu-latest, windows-latest] runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: setup run: cmake -E make_directory ${{runner.workspace}}/libuv/docs/code/build - name: configure diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 581edaaa08b..7d66517667a 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -17,7 +17,7 @@ jobs: build-linux: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: configure run: | ./autogen.sh @@ -36,7 +36,7 @@ jobs: env: ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Envinfo run: npx envinfo - name: Configure android arm64 @@ -125,7 +125,7 @@ jobs: - {target: ppc64 (u64 slots), toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64-static} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install QEMU # this ensure install latest qemu on ubuntu, apt get version is old env: diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index e9995e1faaf..dda1d9630ce 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -29,7 +29,7 @@ jobs: - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: UBSAN} - {toolchain: Visual Studio 17 2022, arch: arm64, server: 2022} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Build run: cmake -S . -B build -DBUILD_TESTING=ON @@ -81,7 +81,7 @@ jobs: - {arch: i686, server: 2022, libgcc: dw2 } - {arch: x86_64, server: 2022, libgcc: seh } steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install mingw32 environment run: | sudo apt update diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 7cfac3dbdc5..9607b488ff5 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -16,7 +16,7 @@ jobs: sanitizers-linux: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup run: | sudo apt-get install ninja-build @@ -104,7 +104,7 @@ jobs: sanitizers-windows: runs-on: windows-2022 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup run: | choco install ninja From e5cb1d3d3d4ab3178ac567fb6a7f0f4b5eef3083 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Tue, 30 Jul 2024 07:59:41 +0800 Subject: [PATCH 571/713] linux: eliminate a read on eventfd per wakeup (#4400) Register the eventfd with EPOLLET to enable edge-triggered notification where we're able to eliminate the overhead of reading the eventfd via system call on each wakeup event. When the eventfd counter reaches the maximum value of the unsigned 64-bit, which may not happen for the entire lifetime of the process, we rewind the counter and retry. This optimization saves one system call on each event-loop wakeup, eliminating the overhead of read(2) as well as the extra latency for each epoll wakeup. --- src/unix/async.c | 49 +++++++++++++++++++++++++++++++----------------- src/unix/linux.c | 22 ++++++++++++++-------- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/unix/async.c b/src/unix/async.c index 0ff2669e30a..29e2f788c75 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -130,8 +130,10 @@ void uv__async_close(uv_async_t* handle) { static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { +#ifndef __linux__ char buf[1024]; ssize_t r; +#endif struct uv__queue queue; struct uv__queue* q; uv_async_t* h; @@ -139,6 +141,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(w == &loop->async_io_watcher); +#ifndef __linux__ for (;;) { r = read(w->fd, buf, sizeof(buf)); @@ -156,6 +159,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { abort(); } +#endif /* !__linux__ */ uv__queue_move(&loop->async_handles, &queue); while (!uv__queue_empty(&queue)) { @@ -179,34 +183,45 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { static void uv__async_send(uv_loop_t* loop) { - const void* buf; - ssize_t len; int fd; - int r; - - buf = ""; - len = 1; - fd = loop->async_wfd; - -#if defined(__linux__) - if (fd == -1) { - static const uint64_t val = 1; - buf = &val; - len = sizeof(val); - fd = loop->async_io_watcher.fd; /* eventfd */ + ssize_t r; +#ifdef __linux__ + uint64_t val; + + fd = loop->async_io_watcher.fd; /* eventfd */ + for (val = 1; /* empty */; val = 1) { + r = write(fd, &val, sizeof(uint64_t)); + if (r < 0) { + /* When EAGAIN occurs, the eventfd counter hits the maximum value of the unsigned 64-bit. + * We need to first drain the eventfd and then write again. + * + * Check out https://man7.org/linux/man-pages/man2/eventfd.2.html for details. + */ + if (errno == EAGAIN) { + /* It's ready to retry. */ + if (read(fd, &val, sizeof(uint64_t)) > 0 || errno == EAGAIN) { + continue; + } + } + /* Unknown error occurs. */ + break; + } + return; } -#endif +#else + fd = loop->async_wfd; /* write end of the pipe */ do - r = write(fd, buf, len); + r = write(fd, "x", 1); while (r == -1 && errno == EINTR); - if (r == len) + if (r == 1) return; if (r == -1) if (errno == EAGAIN || errno == EWOULDBLOCK) return; +#endif abort(); } diff --git a/src/unix/linux.c b/src/unix/linux.c index ad881867b5c..ad07430e3fe 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1385,6 +1385,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w->events = w->pevents; e.events = w->pevents; + if (w == &loop->async_io_watcher) + /* Enable edge-triggered mode on async_io_watcher(eventfd), + * so that we're able to eliminate the overhead of reading + * the eventfd via system call on each event loop wakeup. + */ + e.events |= EPOLLET; e.data.fd = w->fd; fd = w->fd; @@ -1632,12 +1638,12 @@ int uv_resident_set_memory(size_t* rss) { long val; int rc; int i; - + /* rss: 24th element */ rc = uv__slurp("/proc/self/stat", buf, sizeof(buf)); if (rc < 0) return rc; - + /* find the last ')' */ s = strrchr(buf, ')'); if (s == NULL) @@ -2256,7 +2262,7 @@ uint64_t uv_get_available_memory(void) { } -static int uv__get_cgroupv2_constrained_cpu(const char* cgroup, +static int uv__get_cgroupv2_constrained_cpu(const char* cgroup, uv__cpu_constraint* constraint) { char path[256]; char buf[1024]; @@ -2267,7 +2273,7 @@ static int uv__get_cgroupv2_constrained_cpu(const char* cgroup, if (strncmp(cgroup, "0::/", 4) != 0) return UV_EINVAL; - + /* Trim ending \n by replacing it with a 0 */ cgroup_trimmed = cgroup + sizeof("0::/") - 1; /* Skip the prefix "0::/" */ cgroup_size = (int)strcspn(cgroup_trimmed, "\n"); /* Find the first slash */ @@ -2319,7 +2325,7 @@ static char* uv__cgroup1_find_cpu_controller(const char* cgroup, return cgroup_cpu; } -static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, +static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, uv__cpu_constraint* constraint) { char path[256]; char buf[1024]; @@ -2337,8 +2343,8 @@ static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, cgroup_size, cgroup_cpu); if (uv__slurp(path, buf, sizeof(buf)) < 0) - return UV_EIO; - + return UV_EIO; + if (sscanf(buf, "%lld", &constraint->quota_per_period) != 1) return UV_EINVAL; @@ -2360,7 +2366,7 @@ static int uv__get_cgroupv1_constrained_cpu(const char* cgroup, /* Read cpu.shares */ if (uv__slurp(path, buf, sizeof(buf)) < 0) return UV_EIO; - + if (sscanf(buf, "%u", &shares) != 1) return UV_EINVAL; From f23037fe21ef8e7d36ebeaf5c8a589bd8e56d3dd Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Tue, 30 Jul 2024 06:07:52 +0000 Subject: [PATCH 572/713] test: pipe_overlong_path handle ENAMETOOLONG --- test/test-pipe-bind-error.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/test/test-pipe-bind-error.c b/test/test-pipe-bind-error.c index 412f23aedb0..d79c2e59a25 100644 --- a/test/test-pipe-bind-error.c +++ b/test/test-pipe-bind-error.c @@ -172,18 +172,36 @@ TEST_IMPL(pipe_overlong_path) { #ifndef _WIN32 char path[512]; memset(path, '@', sizeof(path)); + + /* On most platforms sun_path is smaller than the NAME_MAX + * Though there is nothing in the POSIX spec that says it needs to be. + * POSIX allows PATH_MAX length paths in saddr.sun_path BUT individual + * components of the path can only be NAME_MAX long. + * So in this case we end up with UV_ENAMETOOLONG error rather than + * UV_EINVAL. + * ref: https://github.com/libuv/libuv/issues/4231#issuecomment-2194612711 + * On AIX the sun_path is larger than the NAME_MAX + */ +#if defined(_AIX) && !defined(__PASE__) + ASSERT_EQ(UV_ENAMETOOLONG, + uv_pipe_bind2(&pipe, path, sizeof(path), UV_PIPE_NO_TRUNCATE)); + /* UV_ENAMETOOLONG is delayed in uv_pipe_connect2 and won't propagate until + * uv_run is called and causes timeouts, therefore in this case we skip calling + * uv_pipe_connect2 + */ +#else ASSERT_EQ(UV_EINVAL, - uv_pipe_bind2(&pipe, path, sizeof(path), UV_PIPE_NO_TRUNCATE)); + uv_pipe_bind2(&pipe, path, sizeof(path), UV_PIPE_NO_TRUNCATE)); ASSERT_EQ(UV_EINVAL, - uv_pipe_connect2(&req, - &pipe, - path, - sizeof(path), - UV_PIPE_NO_TRUNCATE, - (uv_connect_cb) abort)); + uv_pipe_connect2(&req, + &pipe, + path, + sizeof(path), + UV_PIPE_NO_TRUNCATE, + (uv_connect_cb) abort)); ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); -#endif - +#endif /*if defined(_AIX) && !defined(__PASE__)*/ +#endif /* ifndef _WIN32 */ ASSERT_EQ(UV_EINVAL, uv_pipe_bind(&pipe, "")); uv_pipe_connect(&req, &pipe, From 4e310d0f90af29e699e2dedad5fa0dcee181a7cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= <110401522+huseyinacacak-janea@users.noreply.github.com> Date: Tue, 30 Jul 2024 15:58:41 +0300 Subject: [PATCH 573/713] win,fs: use the new Windows fast stat API (#4327) Windows added a new API for file information, which doesn't have to open the file thus greatly improving performance: https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyname The stat functions are already covered by tests, so no test was added here. I considered comparing the result of old and new code, but that would require exposing internal fs functions, and we would be testing Windows functionality, not libuv. --- src/win/fs.c | 155 ++++++++++++++++++++++++++++++++++++++--------- src/win/winapi.c | 10 +++ src/win/winapi.h | 36 +++++++++++ 3 files changed, 171 insertions(+), 30 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 8414f778462..4b29e597b3f 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -147,6 +147,16 @@ static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGE static DWORD uv__allocation_granularity; +typedef enum { + FS__STAT_PATH_SUCCESS, + FS__STAT_PATH_ERROR, + FS__STAT_PATH_TRY_SLOW +} fs__stat_path_return_t; + +INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf); +INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf, + FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat); + void uv__fs_init(void) { SYSTEM_INFO system_info; @@ -1673,6 +1683,43 @@ void fs__closedir(uv_fs_t* req) { SET_REQ_RESULT(req, 0); } +INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path, + uv_stat_t* statbuf, int do_lstat) { + FILE_STAT_BASIC_INFORMATION stat_info; + + // Check if the new fast API is available. + if (!pGetFileInformationByName) { + return FS__STAT_PATH_TRY_SLOW; + } + + // Check if the API call fails. + if (!pGetFileInformationByName(path, FileStatBasicByNameInfo, &stat_info, + sizeof(stat_info))) { + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_NOT_READY: + case ERROR_BAD_NET_NAME: + /* These errors aren't worth retrying with the slow path. */ + return FS__STAT_PATH_ERROR; + } + return FS__STAT_PATH_TRY_SLOW; + } + + // 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; + } + + if (stat_info.DeviceType == FILE_DEVICE_NULL) { + fs__stat_assign_statbuf_null(statbuf); + return FS__STAT_PATH_SUCCESS; + } + + fs__stat_assign_statbuf(statbuf, stat_info, do_lstat); + return FS__STAT_PATH_SUCCESS; +} + INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, int do_lstat) { size_t target_length = 0; @@ -1681,6 +1728,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, FILE_FS_VOLUME_INFORMATION volume_info; NTSTATUS nt_status; IO_STATUS_BLOCK io_status; + FILE_STAT_BASIC_INFORMATION stat_info; nt_status = pNtQueryVolumeInformationFile(handle, &io_status, @@ -1696,13 +1744,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, /* If it's NUL device set fields as reasonable as possible and return. */ if (device_info.DeviceType == FILE_DEVICE_NULL) { - memset(statbuf, 0, sizeof(uv_stat_t)); - statbuf->st_mode = _S_IFCHR; - statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | - ((_S_IREAD | _S_IWRITE) >> 6); - statbuf->st_nlink = 1; - statbuf->st_blksize = 4096; - statbuf->st_rdev = FILE_DEVICE_NULL << 16; + fs__stat_assign_statbuf_null(statbuf); return 0; } @@ -1726,14 +1768,65 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, /* Buffer overflow (a warning status code) is expected here. */ if (io_status.Status == STATUS_NOT_IMPLEMENTED) { - statbuf->st_dev = 0; + stat_info.VolumeSerialNumber.QuadPart = 0; } else if (NT_ERROR(nt_status)) { SetLastError(pRtlNtStatusToDosError(nt_status)); return -1; } else { - statbuf->st_dev = volume_info.VolumeSerialNumber; + stat_info.VolumeSerialNumber.QuadPart = volume_info.VolumeSerialNumber; + } + + stat_info.DeviceType = device_info.DeviceType; + stat_info.FileAttributes = file_info.BasicInformation.FileAttributes; + stat_info.NumberOfLinks = file_info.StandardInformation.NumberOfLinks; + stat_info.FileId.QuadPart = + file_info.InternalInformation.IndexNumber.QuadPart; + stat_info.ChangeTime.QuadPart = + file_info.BasicInformation.ChangeTime.QuadPart; + stat_info.CreationTime.QuadPart = + file_info.BasicInformation.CreationTime.QuadPart; + stat_info.LastAccessTime.QuadPart = + file_info.BasicInformation.LastAccessTime.QuadPart; + stat_info.LastWriteTime.QuadPart = + file_info.BasicInformation.LastWriteTime.QuadPart; + stat_info.AllocationSize.QuadPart = + file_info.StandardInformation.AllocationSize.QuadPart; + + if (do_lstat && + (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + /* + * If reading the link fails, the reparse point is not a symlink and needs + * to be treated as a regular file. The higher level lstat function will + * 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; + } else { + stat_info.EndOfFile.QuadPart = + file_info.StandardInformation.EndOfFile.QuadPart; } + fs__stat_assign_statbuf(statbuf, stat_info, do_lstat); + return 0; +} + +INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf) { + memset(statbuf, 0, sizeof(uv_stat_t)); + statbuf->st_mode = _S_IFCHR; + statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | + ((_S_IREAD | _S_IWRITE) >> 6); + statbuf->st_nlink = 1; + statbuf->st_blksize = 4096; + statbuf->st_rdev = FILE_DEVICE_NULL << 16; +} + +INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf, + FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat) { + statbuf->st_dev = stat_info.VolumeSerialNumber.QuadPart; + /* Todo: st_mode should probably always be 0666 for everyone. We might also * want to report 0777 if the file is a .exe or a directory. * @@ -1765,50 +1858,43 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, * target. Otherwise, reparse points must be treated as regular files. */ if (do_lstat && - (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { - /* - * If reading the link fails, the reparse point is not a symlink and needs - * to be treated as a regular file. The higher level lstat function will - * detect this failure and retry without do_lstat if appropriate. - */ - if (fs__readlink_handle(handle, NULL, &target_length) != 0) - return -1; + (stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { statbuf->st_mode |= S_IFLNK; - statbuf->st_size = target_length; + statbuf->st_size = stat_info.EndOfFile.QuadPart; } if (statbuf->st_mode == 0) { - if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (stat_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { statbuf->st_mode |= _S_IFDIR; statbuf->st_size = 0; } else { statbuf->st_mode |= _S_IFREG; - statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart; + statbuf->st_size = stat_info.EndOfFile.QuadPart; } } - if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY) + if (stat_info.FileAttributes & FILE_ATTRIBUTE_READONLY) statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6); else statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | ((_S_IREAD | _S_IWRITE) >> 6); uv__filetime_to_timespec(&statbuf->st_atim, - file_info.BasicInformation.LastAccessTime.QuadPart); + stat_info.LastAccessTime.QuadPart); uv__filetime_to_timespec(&statbuf->st_ctim, - file_info.BasicInformation.ChangeTime.QuadPart); + stat_info.ChangeTime.QuadPart); uv__filetime_to_timespec(&statbuf->st_mtim, - file_info.BasicInformation.LastWriteTime.QuadPart); + stat_info.LastWriteTime.QuadPart); uv__filetime_to_timespec(&statbuf->st_birthtim, - file_info.BasicInformation.CreationTime.QuadPart); + stat_info.CreationTime.QuadPart); - statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart; + statbuf->st_ino = stat_info.FileId.QuadPart; /* st_blocks contains the on-disk allocation size in 512-byte units. */ statbuf->st_blocks = - (uint64_t) file_info.StandardInformation.AllocationSize.QuadPart >> 9; + (uint64_t) stat_info.AllocationSize.QuadPart >> 9; - statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks; + statbuf->st_nlink = stat_info.NumberOfLinks; /* The st_blksize is supposed to be the 'optimal' number of bytes for reading * and writing to the disk. That is, for any definition of 'optimal' - it's @@ -1840,8 +1926,6 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, statbuf->st_uid = 0; statbuf->st_rdev = 0; statbuf->st_gen = 0; - - return 0; } @@ -1863,6 +1947,17 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, DWORD flags; DWORD ret; + // If new API exists, try to use it. + switch (fs__stat_path(path, statbuf, do_lstat)) { + case FS__STAT_PATH_SUCCESS: + return 0; + case FS__STAT_PATH_ERROR: + return GetLastError(); + case FS__STAT_PATH_TRY_SLOW: + break; + } + + // 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; diff --git a/src/win/winapi.c b/src/win/winapi.c index 53147b8262e..4add0e27372 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -48,12 +48,16 @@ sSetWinEventHook pSetWinEventHook; /* ws2_32.dll function pointer */ uv_sGetHostNameW pGetHostNameW; +/* api-ms-win-core-file-l2-1-4.dll function pointer */ +sGetFileInformationByName pGetFileInformationByName; + 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; ntdll_module = GetModuleHandleA("ntdll.dll"); if (ntdll_module == NULL) { @@ -144,4 +148,10 @@ void uv__winapi_init(void) { ws2_32_module, "GetHostNameW"); } + + api_win_core_file_module = GetModuleHandleA("api-ms-win-core-file-l2-1-4.dll"); + if (api_win_core_file_module != NULL) { + pGetFileInformationByName = (sGetFileInformationByName)GetProcAddress( + api_win_core_file_module, "GetFileInformationByName"); + } } diff --git a/src/win/winapi.h b/src/win/winapi.h index d3449c18997..6d9482360ad 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4125,6 +4125,24 @@ typedef const UNICODE_STRING *PCUNICODE_STRING; # define DEVICE_TYPE DWORD #endif +typedef struct _FILE_STAT_BASIC_INFORMATION { + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ULONG DeviceType; + ULONG DeviceCharacteristics; + ULONG Reserved; + FILE_ID_128 FileId128; + LARGE_INTEGER VolumeSerialNumber; +} FILE_STAT_BASIC_INFORMATION; + /* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does * not. */ @@ -4752,6 +4770,21 @@ typedef struct _TCP_INITIAL_RTO_PARAMETERS { # define SIO_TCP_INITIAL_RTO _WSAIOW(IOC_VENDOR,17) #endif +/* from winnt.h */ +typedef enum _FILE_INFO_BY_NAME_CLASS { + FileStatByNameInfo, + FileStatLxByNameInfo, + FileCaseSensitiveByNameInfo, + FileStatBasicByNameInfo, + MaximumFileInfoByNameClass +} FILE_INFO_BY_NAME_CLASS; + +typedef BOOL(WINAPI* sGetFileInformationByName)( + PCWSTR FileName, + FILE_INFO_BY_NAME_CLASS FileInformationClass, + PVOID FileInfoBuffer, + ULONG FileInfoBufferSize); + /* Ntdll function pointers */ extern sRtlGetVersion pRtlGetVersion; extern sRtlNtStatusToDosError pRtlNtStatusToDosError; @@ -4772,6 +4805,9 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi /* User32.dll function pointer */ extern sSetWinEventHook pSetWinEventHook; +/* api-ms-win-core-file-l2-1-4.dll function pointers */ +extern sGetFileInformationByName pGetFileInformationByName; + /* ws2_32.dll function pointer */ /* mingw doesn't have this definition, so let's declare it here locally */ typedef int (WINAPI *uv_sGetHostNameW) From 727ee7237ede117c539a64258bf82a1b36b9991e Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 2 Aug 2024 10:50:32 -0400 Subject: [PATCH 574/713] win,pipe: fix race with concurrent readers (#4470) This fixes a race condition if multiple threads are reading from the same NamedPipe, which could previously lead to a deadlock situation. We also substantially improve performance now also, since the PeekFile call is unnecessary overhead with this change. This API was added in Windows Vista. Related to #4467, though doesn't address any of the problems there. I believe that someone could now implement uv__pipe_try_write using this same code pattern however. --- src/win/pipe.c | 205 +++++++++++++++++++++++++++---------------------- 1 file changed, 113 insertions(+), 92 deletions(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index fc7fb410fc4..8d5d09025b9 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -667,15 +667,10 @@ void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { } handle->pipe.conn.ipc_xfer_queue_length = 0; - if (handle->flags & UV_HANDLE_EMULATE_IOCP) { - if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { - UnregisterWait(handle->read_req.wait_handle); - handle->read_req.wait_handle = INVALID_HANDLE_VALUE; - } - if (handle->read_req.event_handle != NULL) { - CloseHandle(handle->read_req.event_handle); - handle->read_req.event_handle = NULL; - } + assert(handle->read_req.wait_handle == INVALID_HANDLE_VALUE); + if (handle->read_req.event_handle != NULL) { + CloseHandle(handle->read_req.event_handle); + handle->read_req.event_handle = NULL; } if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) @@ -1417,13 +1412,12 @@ static void uv__pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { } if (handle->flags & UV_HANDLE_EMULATE_IOCP) { - if (req->wait_handle == INVALID_HANDLE_VALUE) { - if (!RegisterWaitForSingleObject(&req->wait_handle, - req->event_handle, post_completion_read_wait, (void*) req, - INFINITE, WT_EXECUTEINWAITTHREAD)) { - SET_REQ_ERROR(req, GetLastError()); - goto error; - } + assert(req->wait_handle == INVALID_HANDLE_VALUE); + if (!RegisterWaitForSingleObject(&req->wait_handle, + req->event_handle, post_completion_read_wait, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) { + SET_REQ_ERROR(req, GetLastError()); + goto error; } } } @@ -1451,16 +1445,16 @@ int uv__pipe_read_start(uv_pipe_t* handle, handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; + if (handle->read_req.event_handle == NULL) { + handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL); + if (handle->read_req.event_handle == NULL) { + uv_fatal_error(GetLastError(), "CreateEvent"); + } + } + /* If reading was stopped and then started again, there could still be a read * request pending. */ if (!(handle->flags & UV_HANDLE_READ_PENDING)) { - if (handle->flags & UV_HANDLE_EMULATE_IOCP && - handle->read_req.event_handle == NULL) { - handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL); - if (handle->read_req.event_handle == NULL) { - uv_fatal_error(GetLastError(), "CreateEvent"); - } - } uv__pipe_queue_read(loop, handle); } @@ -1713,7 +1707,7 @@ static int uv__pipe_write_data(uv_loop_t* loop, if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (!RegisterWaitForSingleObject(&req->wait_handle, req->event_handle, post_completion_write_wait, (void*) req, - INFINITE, WT_EXECUTEINWAITTHREAD)) { + INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) { return GetLastError(); } } @@ -1889,7 +1883,7 @@ static void uv__pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error, static void uv__pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle, - int error, uv_buf_t buf) { + DWORD error, uv_buf_t buf) { if (error == ERROR_BROKEN_PIPE) { uv__pipe_read_eof(loop, handle, buf); } else { @@ -1919,17 +1913,25 @@ static void uv__pipe_queue_ipc_xfer_info( /* Read an exact number of bytes from a pipe. If an error or end-of-file is * encountered before the requested number of bytes are read, an error is * returned. */ -static int uv__pipe_read_exactly(HANDLE h, void* buffer, DWORD count) { - DWORD bytes_read, bytes_read_now; +static DWORD uv__pipe_read_exactly(uv_pipe_t* handle, void* buffer, DWORD count) { + uv_read_t* req; + DWORD bytes_read; + DWORD bytes_read_now; bytes_read = 0; while (bytes_read < count) { - if (!ReadFile(h, + req = &handle->read_req; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1); + if (!ReadFile(handle->handle, (char*) buffer + bytes_read, count - bytes_read, &bytes_read_now, - NULL)) { - return GetLastError(); + &req->u.io.overlapped)) { + if (GetLastError() != ERROR_IO_PENDING) + return GetLastError(); + if (!GetOverlappedResult(handle->handle, &req->u.io.overlapped, &bytes_read_now, TRUE)) + return GetLastError(); } bytes_read += bytes_read_now; @@ -1940,16 +1942,17 @@ static int uv__pipe_read_exactly(HANDLE h, void* buffer, DWORD count) { } -static DWORD uv__pipe_read_data(uv_loop_t* loop, - uv_pipe_t* handle, - DWORD suggested_bytes, - DWORD max_bytes) { - DWORD bytes_read; +static int uv__pipe_read_data(uv_loop_t* loop, + uv_pipe_t* handle, + DWORD* bytes_read, + DWORD max_bytes) { uv_buf_t buf; + uv_read_t* req; + DWORD r; /* Ask the user for a buffer to read data into. */ buf = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, suggested_bytes, &buf); + handle->alloc_cb((uv_handle_t*) handle, *bytes_read, &buf); if (buf.base == NULL || buf.len == 0) { handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); return 0; /* Break out of read loop. */ @@ -1962,29 +1965,50 @@ static DWORD uv__pipe_read_data(uv_loop_t* loop, if (max_bytes > buf.len) max_bytes = buf.len; - /* Read into the user buffer. */ - if (!ReadFile(handle->handle, buf.base, max_bytes, &bytes_read, NULL)) { - uv__pipe_read_error_or_eof(loop, handle, GetLastError(), buf); - return 0; /* Break out of read loop. */ + /* Read into the user buffer. + * Prepare an Event so that we can cancel if it doesn't complete immediately. + */ + req = &handle->read_req; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1); + if (ReadFile(handle->handle, buf.base, max_bytes, bytes_read, &req->u.io.overlapped)) { + r = ERROR_SUCCESS; + } else { + r = GetLastError(); + *bytes_read = 0; + if (r == ERROR_IO_PENDING) { + r = CancelIoEx(handle->handle, &req->u.io.overlapped); + assert(r || GetLastError() == ERROR_NOT_FOUND); + if (!GetOverlappedResult(handle->handle, &req->u.io.overlapped, bytes_read, TRUE)) { + r = GetLastError(); + *bytes_read = 0; + } + } } /* Call the read callback. */ - handle->read_cb((uv_stream_t*) handle, bytes_read, &buf); + if (r == ERROR_SUCCESS || r == ERROR_OPERATION_ABORTED) + handle->read_cb((uv_stream_t*) handle, *bytes_read, &buf); + else + uv__pipe_read_error_or_eof(loop, handle, r, buf); - return bytes_read; + return *bytes_read == max_bytes; } -static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) { - uint32_t* data_remaining = &handle->pipe.conn.ipc_data_frame.payload_remaining; - int err; +static int uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) { + uint32_t* data_remaining; + DWORD err; + DWORD more; + DWORD bytes_read; + + data_remaining = &handle->pipe.conn.ipc_data_frame.payload_remaining; if (*data_remaining > 0) { /* Read frame data payload. */ - DWORD bytes_read = - uv__pipe_read_data(loop, handle, *data_remaining, *data_remaining); + bytes_read = *data_remaining; + more = uv__pipe_read_data(loop, handle, &bytes_read, bytes_read); *data_remaining -= bytes_read; - return bytes_read; } else { /* Start of a new IPC frame. */ @@ -1995,7 +2019,7 @@ static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) { /* Read the IPC frame header. */ err = uv__pipe_read_exactly( - handle->handle, &frame_header, sizeof frame_header); + handle, &frame_header, sizeof frame_header); if (err) goto error; @@ -2031,21 +2055,28 @@ static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) { /* If no socket xfer info follows, return here. Data will be read in a * subsequent invocation of uv__pipe_read_ipc(). */ - if (xfer_type == UV__IPC_SOCKET_XFER_NONE) - return sizeof frame_header; /* Number of bytes read. */ + if (xfer_type != UV__IPC_SOCKET_XFER_NONE) { + /* Read transferred socket information. */ + err = uv__pipe_read_exactly(handle, &xfer_info, sizeof xfer_info); + if (err) + goto error; - /* Read transferred socket information. */ - err = uv__pipe_read_exactly(handle->handle, &xfer_info, sizeof xfer_info); - if (err) - goto error; + /* Store the pending socket info. */ + uv__pipe_queue_ipc_xfer_info(handle, xfer_type, &xfer_info); + } - /* Store the pending socket info. */ - uv__pipe_queue_ipc_xfer_info(handle, xfer_type, &xfer_info); + more = 1; + } - /* Return number of bytes read. */ - return sizeof frame_header + sizeof xfer_info; + /* Return whether the caller should immediately try another read call to get + * more data. */ + if (more && *data_remaining == 0) { + /* TODO: use PeekNamedPipe to see if it is really worth trying to do + * another ReadFile call. */ } + return more; + invalid: /* Invalid frame. */ err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */ @@ -2059,12 +2090,20 @@ static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) { void uv__process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, uv_req_t* req) { + DWORD err; + DWORD more; + DWORD bytes_requested; assert(handle->type == UV_NAMED_PIPE); handle->flags &= ~(UV_HANDLE_READ_PENDING | UV_HANDLE_CANCELLATION_PENDING); DECREASE_PENDING_REQ_COUNT(handle); eof_timer_stop(handle); + if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(handle->read_req.wait_handle); + handle->read_req.wait_handle = INVALID_HANDLE_VALUE; + } + /* At this point, we're done with bookkeeping. If the user has stopped * reading the pipe in the meantime, there is nothing left to do, since there * is no callback that we can call. */ @@ -2073,7 +2112,7 @@ void uv__process_pipe_read_req(uv_loop_t* loop, if (!REQ_SUCCESS(req)) { /* An error occurred doing the zero-read. */ - DWORD err = GET_REQ_ERROR(req); + err = GET_REQ_ERROR(req); /* If the read was cancelled by uv__pipe_interrupt_read(), the request may * indicate an ERROR_OPERATION_ABORTED error. This error isn't relevant to @@ -2084,34 +2123,18 @@ void uv__process_pipe_read_req(uv_loop_t* loop, } else { /* The zero-read completed without error, indicating there is data * available in the kernel buffer. */ - DWORD avail; - - /* Get the number of bytes available. */ - avail = 0; - if (!PeekNamedPipe(handle->handle, NULL, 0, NULL, &avail, NULL)) - uv__pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_); - - /* Read until we've either read all the bytes available, or the 'reading' - * flag is cleared. */ - while (avail > 0 && handle->flags & UV_HANDLE_READING) { + while (handle->flags & UV_HANDLE_READING) { + bytes_requested = 65536; /* Depending on the type of pipe, read either IPC frames or raw data. */ - DWORD bytes_read = - handle->ipc ? uv__pipe_read_ipc(loop, handle) - : uv__pipe_read_data(loop, handle, avail, (DWORD) -1); + if (handle->ipc) + more = uv__pipe_read_ipc(loop, handle); + else + more = uv__pipe_read_data(loop, handle, &bytes_requested, INT32_MAX); /* If no bytes were read, treat this as an indication that an error * occurred, and break out of the read loop. */ - if (bytes_read == 0) + if (more == 0) break; - - /* It is possible that more bytes were read than we thought were - * available. To prevent `avail` from underflowing, break out of the loop - * if this is the case. */ - if (bytes_read > avail) - break; - - /* Recompute the number of bytes available. */ - avail -= bytes_read; } } @@ -2134,15 +2157,13 @@ void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, UNREGISTER_HANDLE_REQ(loop, handle); - if (handle->flags & UV_HANDLE_EMULATE_IOCP) { - if (req->wait_handle != INVALID_HANDLE_VALUE) { - UnregisterWait(req->wait_handle); - req->wait_handle = INVALID_HANDLE_VALUE; - } - if (req->event_handle) { - CloseHandle(req->event_handle); - req->event_handle = NULL; - } + if (req->wait_handle != INVALID_HANDLE_VALUE) { + UnregisterWait(req->wait_handle); + req->wait_handle = INVALID_HANDLE_VALUE; + } + if (req->event_handle) { + CloseHandle(req->event_handle); + req->event_handle = NULL; } err = GET_REQ_ERROR(req); From a6a987c0de8d7eccf7048a6d768ea88fd7fac449 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 5 Aug 2024 16:32:31 -0400 Subject: [PATCH 575/713] win,signal: fix data race dispatching SIGWINCH (#4488) The Event should be reset before reading the value, or libuv might miss an update that occurred too rapidly after the previously one. Refs: https://github.com/libuv/libuv/pull/2381 Refs: https://github.com/libuv/libuv/discussions/4485 --- src/win/tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/tty.c b/src/win/tty.c index f9e3346968b..c0339ded2e4 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -2380,8 +2380,8 @@ static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param) { /* Make sure to not overwhelm the system with resize events */ Sleep(33); WaitForSingleObject(uv__tty_console_resized, INFINITE); - uv__tty_console_signal_resize(); ResetEvent(uv__tty_console_resized); + uv__tty_console_signal_resize(); } return 0; } From 9b3b61f606cbc4df1680a1aa08959c91023d99eb Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Mon, 5 Aug 2024 18:15:53 -0300 Subject: [PATCH 576/713] build: ubsan fixes (#4254) MSVC does not actually support ubsan. There is a long-standing ticket requesting this: https://developercommunity.visualstudio.com/t/add-support-for-ubsan/840750 There are no known compilers that currently accept the `/fsanitize=undefined` spelling. clang-cl accepts `-fsanitize...`, same as regular clang. Also passes no-sanitizer-recover so that tests actually fail. Fix various ubsan-detected errors, including: * win: fix req-inl.h ubsan failure Don't use CONTAINING_RECORD macro from WinSDK, as it doesn't use the right trick which avoids member access on null pointer. Fixes: ``` src/win/req-inl.h:86:10: runtime error: member access within null pointer of type 'uv_req_t' (aka 'struct uv_req_s') SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior D:/a/libuv/libuv/src/win/req-inl.h:86:10 ``` * test: fix ubsan failure on udp_ref3 Don't call functions through different function type. Fixes: ``` src/win/udp.c:537:5: runtime error: call to function req_cb through pointer to incorrect function type 'void (*)(struct uv_udp_send_s *, int)' test\test-ref.c:66: note: req_cb defined here SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/win/udp.c:537:5 in ``` * win: fix process-stdio.c ubsan failure When accessing HANDLEs within the stdio buffer, use memcpy / memset in order to respect alignment. Fixes: ``` src/win/process-stdio.c:197:5: runtime error: store to misaligned address 0x0230ee72d107 for type 'HANDLE' (aka 'void *'), which requires 8 byte alignment 0x0230ee72d107: note: pointer points here 00 00 cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd fd fd fd fd ^ SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/win/process-stdio.c:197:5 in ``` * win: fix getaddrinfo.c ubsan failure Reworks buffer alignment handling to respect requirements. Fixes: ``` src/win/getaddrinfo.c:157:23: runtime error: member access within misaligned address 0x0290e4c6a17c for type 'struct addrinfo', which requires 8 byte alignment 0x0290e4c6a17c: note: pointer points here 00 00 00 00 cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd ^ SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/win/getaddrinfo.c:157:23 in ``` * win: fix pipe.c ubsan failure Changes "random" representation from pointer to number. Fixes: ``` src/win/pipe.c:234:11: runtime error: applying non-zero offset to non-null pointer 0xffffffffffffffff produced null pointer SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/win/pipe.c:234:11 in ``` * unix: fix stream.c ubsan failure Avoids performing pointer arithmetic on null pointer. Fixes: ``` src/unix/stream.c:701:15: runtime error: applying zero offset to null pointer SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /Users/runner/work/libuv/libuv/src/unix/stream.c:701:15 in ``` --- .github/workflows/CI-win.yml | 3 +- CMakeLists.txt | 17 +++-- src/unix/stream.c | 3 +- src/win/getaddrinfo.c | 122 ++++++++++++++++++----------------- src/win/pipe.c | 17 +++-- src/win/process-stdio.c | 35 +++++----- src/win/req-inl.h | 2 +- test/test-ref.c | 4 +- 8 files changed, 110 insertions(+), 93 deletions(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index dda1d9630ce..b845139de64 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -34,8 +34,7 @@ jobs: run: cmake -S . -B build -DBUILD_TESTING=ON -G "${{ matrix.config.toolchain }}" -A ${{ matrix.config.arch }} - ${{ matrix.config.config == 'ASAN' && '-DASAN=on -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded' || - matrix.config.config == 'UBSAN' && '-DUBSAN=on' || '' }} + ${{ matrix.config.config == 'ASAN' && '-DASAN=on -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded' || '' }} cmake --build build --config RelWithDebInfo diff --git a/CMakeLists.txt b/CMakeLists.txt index d16cf76f209..28c6df25666 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,15 +81,20 @@ if(TSAN) endif() if(UBSAN) + cmake_minimum_required(VERSION 3.13) list(APPEND uv_defines __UBSAN__=1) if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|GNU|Clang") - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer -fsanitize=undefined") - set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=undefined") - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=undefined") - elseif(MSVC) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=undefined") + add_compile_options("-fsanitize=undefined" "-fno-sanitize-recover=undefined") + if (NOT WIN32) + add_link_options("-fsanitize=undefined") + endif() + if(MSVC) + add_compile_options("/Oy-") + else() + add_compile_options("-fno-omit-frame-pointer") + endif() else() - message(SEND_ERROR "UndefinedBehaviorSanitizer support requires clang, gcc, or msvc. Try again with -DCMAKE_C_COMPILER.") + message(SEND_ERROR "UndefinedBehaviorSanitizer support requires clang or gcc. Try again with -DCMAKE_C_COMPILER.") endif() endif() diff --git a/src/unix/stream.c b/src/unix/stream.c index 0eff79ffb15..18763b4744c 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -698,7 +698,8 @@ static int uv__write_req_update(uv_stream_t* stream, do { len = n < buf->len ? n : buf->len; - buf->base += len; + if (buf->len != 0) + buf->base += len; buf->len -= len; buf += (buf->len == 0); /* Advance to next buffer if this one is empty. */ n -= len; diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index 864de13fce0..f20e10d49d9 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -71,10 +71,9 @@ int uv__getaddrinfo_translate_error(int sys_err) { DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo); #endif - -/* Adjust size value to be multiple of 4. Use to keep pointer aligned. - * Do we need different versions of this for different architectures? */ -#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2) +static size_t align_offset(size_t off, size_t alignment) { + return ((off + alignment - 1) / alignment) * alignment; +} #ifndef NDIS_IF_MAX_STRING_SIZE #define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE @@ -103,17 +102,7 @@ static void uv__getaddrinfo_work(struct uv__work* w) { * Each size calculation is adjusted to avoid unaligned pointers. */ static void uv__getaddrinfo_done(struct uv__work* w, int status) { - uv_getaddrinfo_t* req; - size_t addrinfo_len = 0; - ssize_t name_len = 0; - size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); - struct addrinfoW* addrinfow_ptr; - struct addrinfo* addrinfo_ptr; - char* alloc_ptr = NULL; - char* cur_ptr = NULL; - int r; - - req = container_of(w, uv_getaddrinfo_t, work_req); + uv_getaddrinfo_t* req = container_of(w, uv_getaddrinfo_t, work_req); /* release input parameter memory */ uv__free(req->alloc); @@ -126,34 +115,44 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { } if (req->retcode == 0) { + char* alloc_ptr = NULL; + size_t cur_off = 0; + size_t addrinfo_len; /* Convert addrinfoW to addrinfo. First calculate required length. */ - addrinfow_ptr = req->addrinfow; + struct addrinfoW* addrinfow_ptr = req->addrinfow; while (addrinfow_ptr != NULL) { - addrinfo_len += addrinfo_struct_len + - ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); + cur_off = align_offset(cur_off, sizeof(void*)); + cur_off += sizeof(struct addrinfo); + /* TODO: This alignment could be smaller, if we could + portably get the alignment for sockaddr. */ + cur_off = align_offset(cur_off, sizeof(void*)); + cur_off += addrinfow_ptr->ai_addrlen; if (addrinfow_ptr->ai_canonname != NULL) { - name_len = uv_utf16_length_as_wtf8(addrinfow_ptr->ai_canonname, -1); + ssize_t name_len = + uv_utf16_length_as_wtf8(addrinfow_ptr->ai_canonname, -1); if (name_len < 0) { req->retcode = name_len; goto complete; } - addrinfo_len += ALIGNED_SIZE(name_len + 1); + cur_off += name_len + 1; } addrinfow_ptr = addrinfow_ptr->ai_next; } /* allocate memory for addrinfo results */ - alloc_ptr = (char*)uv__malloc(addrinfo_len); + addrinfo_len = cur_off; + alloc_ptr = uv__malloc(addrinfo_len); /* do conversions */ if (alloc_ptr != NULL) { - cur_ptr = alloc_ptr; + struct addrinfo *addrinfo_ptr = (struct addrinfo *)alloc_ptr; + cur_off = 0; addrinfow_ptr = req->addrinfow; - while (addrinfow_ptr != NULL) { + for (;;) { + cur_off += sizeof(struct addrinfo); + assert(cur_off <= addrinfo_len); /* copy addrinfo struct data */ - assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len); - addrinfo_ptr = (struct addrinfo*)cur_ptr; addrinfo_ptr->ai_family = addrinfow_ptr->ai_family; addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype; addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol; @@ -163,35 +162,37 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { addrinfo_ptr->ai_addr = NULL; addrinfo_ptr->ai_next = NULL; - cur_ptr += addrinfo_struct_len; - /* copy sockaddr */ if (addrinfo_ptr->ai_addrlen > 0) { - assert(cur_ptr + addrinfo_ptr->ai_addrlen <= - alloc_ptr + addrinfo_len); - memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen); - addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr; - cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen); + cur_off = align_offset(cur_off, sizeof(void *)); + addrinfo_ptr->ai_addr = (struct sockaddr *)(alloc_ptr + cur_off); + cur_off += addrinfo_ptr->ai_addrlen; + assert(cur_off <= addrinfo_len); + memcpy(addrinfo_ptr->ai_addr, + addrinfow_ptr->ai_addr, + addrinfo_ptr->ai_addrlen); } /* convert canonical name to UTF-8 */ if (addrinfow_ptr->ai_canonname != NULL) { - name_len = alloc_ptr + addrinfo_len - cur_ptr; - r = uv__copy_utf16_to_utf8(addrinfow_ptr->ai_canonname, - -1, - cur_ptr, - (size_t*)&name_len); + ssize_t name_len = addrinfo_len - cur_off; + addrinfo_ptr->ai_canonname = alloc_ptr + cur_off; + int r = uv__copy_utf16_to_utf8(addrinfow_ptr->ai_canonname, + -1, + addrinfo_ptr->ai_canonname, + (size_t*)&name_len); assert(r == 0); - addrinfo_ptr->ai_canonname = cur_ptr; - cur_ptr += ALIGNED_SIZE(name_len + 1); + cur_off += name_len + 1; + assert(cur_off <= addrinfo_len); } - assert(cur_ptr <= alloc_ptr + addrinfo_len); /* set next ptr */ addrinfow_ptr = addrinfow_ptr->ai_next; - if (addrinfow_ptr != NULL) { - addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr; - } + if (addrinfow_ptr == NULL) + break; + cur_off = align_offset(cur_off, sizeof(void *)); + addrinfo_ptr = (struct addrinfo *)(alloc_ptr + cur_off); + addrinfo_ptr->ai_next = addrinfo_ptr; } req->addrinfo = (struct addrinfo*)alloc_ptr; } else { @@ -242,10 +243,12 @@ int uv_getaddrinfo(uv_loop_t* loop, const char* service, const struct addrinfo* hints) { char hostname_ascii[256]; + size_t off = 0; size_t nodesize = 0; size_t servicesize = 0; + size_t serviceoff = 0; size_t hintssize = 0; - char* alloc_ptr = NULL; + size_t hintoff = 0; ssize_t rc; if (req == NULL || (node == NULL && service == NULL)) { @@ -268,6 +271,7 @@ int uv_getaddrinfo(uv_loop_t* loop, return rc; nodesize = strlen(hostname_ascii) + 1; node = hostname_ascii; + off += nodesize * sizeof(WCHAR); } if (service != NULL) { @@ -275,27 +279,28 @@ int uv_getaddrinfo(uv_loop_t* loop, if (rc < 0) return rc; servicesize = rc; + off = align_offset(off, sizeof(WCHAR)); + serviceoff = off; + off += servicesize * sizeof(WCHAR); } + if (hints != NULL) { - hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW)); + off = align_offset(off, sizeof(void *)); + hintoff = off; + hintssize = sizeof(struct addrinfoW); + off += hintssize; } /* allocate memory for inputs, and partition it as needed */ - alloc_ptr = uv__malloc(ALIGNED_SIZE(nodesize * sizeof(WCHAR)) + - ALIGNED_SIZE(servicesize * sizeof(WCHAR)) + - hintssize); - if (!alloc_ptr) + req->alloc = uv__malloc(off); + if (!req->alloc) return UV_ENOMEM; - /* save alloc_ptr now so we can free if error */ - req->alloc = (void*) alloc_ptr; - /* Convert node string to UTF16 into allocated memory and save pointer in the * request. The node here has been converted to ascii. */ if (node != NULL) { - req->node = (WCHAR*) alloc_ptr; - uv_wtf8_to_utf16(node, (WCHAR*) alloc_ptr, nodesize); - alloc_ptr += ALIGNED_SIZE(nodesize * sizeof(WCHAR)); + req->node = (WCHAR*) req->alloc; + uv_wtf8_to_utf16(node, req->node, nodesize); } else { req->node = NULL; } @@ -303,16 +308,15 @@ int uv_getaddrinfo(uv_loop_t* loop, /* Convert service string to UTF16 into allocated memory and save pointer in * the req. */ if (service != NULL) { - req->service = (WCHAR*) alloc_ptr; - uv_wtf8_to_utf16(service, (WCHAR*) alloc_ptr, servicesize); - alloc_ptr += ALIGNED_SIZE(servicesize * sizeof(WCHAR)); + req->service = (WCHAR*) ((char*) req->alloc + serviceoff); + uv_wtf8_to_utf16(service, req->service, servicesize); } else { req->service = NULL; } /* copy hints to allocated memory and save pointer in req */ if (hints != NULL) { - req->addrinfow = (struct addrinfoW*) alloc_ptr; + req->addrinfow = (struct addrinfoW*) ((char*) req->alloc + hintoff); req->addrinfow->ai_family = hints->ai_family; req->addrinfow->ai_socktype = hints->ai_socktype; req->addrinfow->ai_protocol = hints->ai_protocol; diff --git a/src/win/pipe.c b/src/win/pipe.c index 8d5d09025b9..4d72d04fab4 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -106,8 +106,8 @@ static int includes_nul(const char *s, size_t n) { } -static void uv__unique_pipe_name(char* ptr, char* name, size_t size) { - snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId()); +static void uv__unique_pipe_name(unsigned long long ptr, char* name, size_t size) { + snprintf(name, size, "\\\\?\\pipe\\uv\\%llu-%lu", ptr, GetCurrentProcessId()); } @@ -208,7 +208,7 @@ static void close_pipe(uv_pipe_t* pipe) { static int uv__pipe_server( HANDLE* pipeHandle_ptr, DWORD access, - char* name, size_t nameSize, char* random) { + char* name, size_t nameSize, unsigned long long random) { HANDLE pipeHandle; int err; @@ -249,7 +249,7 @@ static int uv__pipe_server( static int uv__create_pipe_pair( HANDLE* server_pipe_ptr, HANDLE* client_pipe_ptr, unsigned int server_flags, unsigned int client_flags, - int inherit_client, char* random) { + int inherit_client, unsigned long long random) { /* allowed flags are: UV_READABLE_PIPE | UV_WRITABLE_PIPE | UV_NONBLOCK_PIPE */ char pipe_name[64]; SECURITY_ATTRIBUTES sa; @@ -357,7 +357,12 @@ int uv_pipe(uv_file fds[2], int read_flags, int write_flags) { /* TODO: better source of local randomness than &fds? */ read_flags |= UV_READABLE_PIPE; write_flags |= UV_WRITABLE_PIPE; - err = uv__create_pipe_pair(&readh, &writeh, read_flags, write_flags, 0, (char*) &fds[0]); + err = uv__create_pipe_pair(&readh, + &writeh, + read_flags, + write_flags, + 0, + (uintptr_t) &fds[0]); if (err != 0) return err; temp[0] = _open_osfhandle((intptr_t) readh, 0); @@ -421,7 +426,7 @@ int uv__create_stdio_pipe_pair(uv_loop_t* loop, } err = uv__create_pipe_pair(&server_pipe, &client_pipe, - server_flags, client_flags, 1, (char*) server_pipe); + server_flags, client_flags, 1, (uintptr_t) server_pipe); if (err) goto error; diff --git a/src/win/process-stdio.c b/src/win/process-stdio.c index 0db35723731..181db92ea30 100644 --- a/src/win/process-stdio.c +++ b/src/win/process-stdio.c @@ -46,12 +46,12 @@ #define CHILD_STDIO_CRT_FLAGS(buffer, fd) \ *((unsigned char*) (buffer) + sizeof(int) + fd) -#define CHILD_STDIO_HANDLE(buffer, fd) \ - *((HANDLE*) ((unsigned char*) (buffer) + \ - sizeof(int) + \ - sizeof(unsigned char) * \ - CHILD_STDIO_COUNT((buffer)) + \ - sizeof(HANDLE) * (fd))) +#define CHILD_STDIO_HANDLE(buffer, fd) \ + ((void*) ((unsigned char*) (buffer) + \ + sizeof(int) + \ + sizeof(unsigned char) * \ + CHILD_STDIO_COUNT((buffer)) + \ + sizeof(HANDLE) * (fd))) /* CRT file descriptor mode flags */ @@ -194,7 +194,7 @@ int uv__stdio_create(uv_loop_t* loop, CHILD_STDIO_COUNT(buffer) = count; for (i = 0; i < count; i++) { CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; - CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE; + memset(CHILD_STDIO_HANDLE(buffer, i), 0xFF, sizeof(HANDLE)); } for (i = 0; i < count; i++) { @@ -215,14 +215,15 @@ int uv__stdio_create(uv_loop_t* loop, * handles in the stdio buffer are initialized with. * INVALID_HANDLE_VALUE, which should be okay. */ if (i <= 2) { + HANDLE nul; DWORD access = (i == 0) ? FILE_GENERIC_READ : FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES; - err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i), - access); + err = uv__create_nul_handle(&nul, access); if (err) goto error; + memcpy(CHILD_STDIO_HANDLE(buffer, i), &nul, sizeof(HANDLE)); CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; } break; @@ -247,7 +248,7 @@ int uv__stdio_create(uv_loop_t* loop, if (err) goto error; - CHILD_STDIO_HANDLE(buffer, i) = child_pipe; + memcpy(CHILD_STDIO_HANDLE(buffer, i), &child_pipe, sizeof(HANDLE)); CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; break; } @@ -263,7 +264,7 @@ int uv__stdio_create(uv_loop_t* loop, * error. */ if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) { CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; - CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE; + memset(CHILD_STDIO_HANDLE(buffer, i), 0xFF, sizeof(HANDLE)); break; } goto error; @@ -298,7 +299,7 @@ int uv__stdio_create(uv_loop_t* loop, return -1; } - CHILD_STDIO_HANDLE(buffer, i) = child_handle; + memcpy(CHILD_STDIO_HANDLE(buffer, i), &child_handle, sizeof(HANDLE)); break; } @@ -334,7 +335,7 @@ int uv__stdio_create(uv_loop_t* loop, if (err) goto error; - CHILD_STDIO_HANDLE(buffer, i) = child_handle; + memcpy(CHILD_STDIO_HANDLE(buffer, i), &child_handle, sizeof(HANDLE)); CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags; break; } @@ -359,7 +360,7 @@ void uv__stdio_destroy(BYTE* buffer) { count = CHILD_STDIO_COUNT(buffer); for (i = 0; i < count; i++) { - HANDLE handle = CHILD_STDIO_HANDLE(buffer, i); + HANDLE handle = uv__stdio_handle(buffer, i); if (handle != INVALID_HANDLE_VALUE) { CloseHandle(handle); } @@ -374,7 +375,7 @@ void uv__stdio_noinherit(BYTE* buffer) { count = CHILD_STDIO_COUNT(buffer); for (i = 0; i < count; i++) { - HANDLE handle = CHILD_STDIO_HANDLE(buffer, i); + HANDLE handle = uv__stdio_handle(buffer, i); if (handle != INVALID_HANDLE_VALUE) { SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); } @@ -412,5 +413,7 @@ WORD uv__stdio_size(BYTE* buffer) { HANDLE uv__stdio_handle(BYTE* buffer, int fd) { - return CHILD_STDIO_HANDLE(buffer, fd); + HANDLE handle; + memcpy(&handle, CHILD_STDIO_HANDLE(buffer, fd), sizeof(HANDLE)); + return handle; } diff --git a/src/win/req-inl.h b/src/win/req-inl.h index ab77b0d9def..cf16e8ba41f 100644 --- a/src/win/req-inl.h +++ b/src/win/req-inl.h @@ -83,7 +83,7 @@ INLINE static uv_req_t* uv__overlapped_to_req(OVERLAPPED* overlapped) { - return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped); + return container_of(overlapped, uv_req_t, u.io.overlapped); } diff --git a/test/test-ref.c b/test/test-ref.c index dbe94f7168b..7a2c33790ab 100644 --- a/test/test-ref.c +++ b/test/test-ref.c @@ -63,7 +63,7 @@ static void fail_cb2(void) { } -static void req_cb(uv_handle_t* req, int status) { +static void req_cb(uv_udp_send_t* req, int status) { req_cb_called++; } @@ -334,7 +334,7 @@ TEST_IMPL(udp_ref3) { &buf, 1, (const struct sockaddr*) &addr, - (uv_udp_send_cb) req_cb); + req_cb); uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT_EQ(1, req_cb_called); From e78e29c231481683c7e72450eeeb1b75b1109b2c Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 6 Aug 2024 22:10:13 +0200 Subject: [PATCH 577/713] linux: disable SQPOLL io_uring by default (#4492) The SQPOLL io_uring instance wasn't providing consistent behaviour to users depending on kernel versions, load shape, ... creating issues difficult to track and fix. Don't use this ring by default but allow enabling it by calling `uv_loop_configure()` with `UV_LOOP_ENABLE_IO_URING_SQPOLL`. --- docs/src/fs.rst | 5 ++++- docs/src/loop.rst | 5 +++++ include/uv.h | 4 +++- src/unix/internal.h | 3 ++- src/unix/linux.c | 8 ++++++++ src/unix/loop.c | 8 ++++++++ 6 files changed, 30 insertions(+), 3 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index c039a8e6865..32cf126c71f 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -16,7 +16,10 @@ Starting with libuv v1.45.0, some file operations on Linux are handed off to `io_uring ` when possible. Apart from a (sometimes significant) increase in throughput there should be no change in observable behavior. Libuv reverts to using its threadpool when the necessary -kernel features are unavailable or unsuitable. +kernel features are unavailable or unsuitable. Starting with libuv v1.49.0 this +behavior was reverted and Libuv on Linux by default will be using the threadpool +again. In order to enable io_uring the :c:type:`uv_loop_t` instance must be +configured with the :c:type:`UV_LOOP_ENABLE_IO_URING_SQPOLL` option. .. note:: On Windows `uv_fs_*` functions use utf-8 encoding. diff --git a/docs/src/loop.rst b/docs/src/loop.rst index 0f5ddfb3ca2..dc26e654e4b 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -73,8 +73,13 @@ API This option is necessary to use :c:func:`uv_metrics_idle_time`. + - UV_LOOP_ENABLE_IO_URING_SQPOLL: Enable SQPOLL io_uring instance to handle + asynchronous file system operations. + .. versionchanged:: 1.39.0 added the UV_METRICS_IDLE_TIME option. + .. versionchanged:: 1.49.0 added the UV_LOOP_ENABLE_IO_URING_SQPOLL option. + .. c:function:: int uv_loop_close(uv_loop_t* loop) Releases all internal loop resources. Call this function only when the loop diff --git a/include/uv.h b/include/uv.h index 44473fce8fa..9e450c5110f 100644 --- a/include/uv.h +++ b/include/uv.h @@ -260,7 +260,9 @@ typedef struct uv_metrics_s uv_metrics_t; typedef enum { UV_LOOP_BLOCK_SIGNAL = 0, - UV_METRICS_IDLE_TIME + UV_METRICS_IDLE_TIME, + UV_LOOP_USE_IO_URING_SQPOLL +#define UV_LOOP_USE_IO_URING_SQPOLL UV_LOOP_USE_IO_URING_SQPOLL } uv_loop_option; typedef enum { diff --git a/src/unix/internal.h b/src/unix/internal.h index a8ff39094f3..8055730a1d1 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -157,7 +157,8 @@ typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t; /* loop flags */ enum { UV_LOOP_BLOCK_SIGPROF = 0x1, - UV_LOOP_REAP_CHILDREN = 0x2 + UV_LOOP_REAP_CHILDREN = 0x2, + UV_LOOP_ENABLE_IO_URING_SQPOLL = 0x4 }; /* flags of excluding ifaddr */ diff --git a/src/unix/linux.c b/src/unix/linux.c index ad07430e3fe..a5f74e89016 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -761,6 +761,14 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, * initialization failed. Anything else is a valid ring file descriptor. */ 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. + */ + if ((loop->flags & UV_LOOP_ENABLE_IO_URING_SQPOLL) == 0) { + iou->ringfd = -1; + return NULL; + } + uv__iou_init(loop->backend_fd, iou, 64, UV__IORING_SETUP_SQPOLL); if (iou->ringfd == -2) iou->ringfd = -1; /* "failed" */ diff --git a/src/unix/loop.c b/src/unix/loop.c index a9468e8e19c..179ee999d80 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -217,6 +217,14 @@ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) { return 0; } +#if defined(__linux__) + if (option == UV_LOOP_USE_IO_URING_SQPOLL) { + loop->flags |= UV_LOOP_ENABLE_IO_URING_SQPOLL; + return 0; + } +#endif + + if (option != UV_LOOP_BLOCK_SIGNAL) return UV_ENOSYS; From 5537d6a689b30039475cf57a0ce8fbbe4d0d9305 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Wed, 7 Aug 2024 12:01:07 -0300 Subject: [PATCH 578/713] win: fix fs.c ubsan failure (#4491) Refactor / cleanup arithmetic for unix -> win filetime conversion in order to avoid multiplication overflow. Fixes: ``` src/win/fs.c:106:48: runtime error: signed integer overflow: 1702781567 * 10 cannot be represented in type 'long' SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/win/fs.c:106:48 in ``` Co-authored-by: Jameson Nash --- src/win/fs.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 4b29e597b3f..d87246e0ff3 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -108,13 +108,14 @@ return; \ } -#define MILLION ((int64_t) 1000 * 1000) -#define BILLION ((int64_t) 1000 * 1000 * 1000) +#define NSEC_PER_TICK 100 +#define TICKS_PER_SEC ((int64_t) 1e9 / NSEC_PER_TICK) +static const int64_t WIN_TO_UNIX_TICK_OFFSET = 11644473600 * TICKS_PER_SEC; static void uv__filetime_to_timespec(uv_timespec_t *ts, int64_t filetime) { - filetime -= 116444736 * BILLION; - ts->tv_sec = (long) (filetime / (10 * MILLION)); - ts->tv_nsec = (long) ((filetime - ts->tv_sec * 10 * MILLION) * 100U); + filetime -= WIN_TO_UNIX_TICK_OFFSET; + ts->tv_sec = filetime / TICKS_PER_SEC; + ts->tv_nsec = (filetime % TICKS_PER_SEC) * NSEC_PER_TICK; if (ts->tv_nsec < 0) { ts->tv_sec -= 1; ts->tv_nsec += 1e9; @@ -123,7 +124,7 @@ static void uv__filetime_to_timespec(uv_timespec_t *ts, int64_t filetime) { #define TIME_T_TO_FILETIME(time, filetime_ptr) \ do { \ - int64_t bigtime = ((time) * 10 * MILLION + 116444736 * BILLION); \ + int64_t bigtime = ((time) * TICKS_PER_SEC + WIN_TO_UNIX_TICK_OFFSET); \ (filetime_ptr)->dwLowDateTime = (uint64_t) bigtime & 0xFFFFFFFF; \ (filetime_ptr)->dwHighDateTime = (uint64_t) bigtime >> 32; \ } while(0) From 88ab6e78daa0fddf92dfed5768417171dcd702c2 Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Wed, 7 Aug 2024 12:20:37 +0000 Subject: [PATCH 579/713] test: rmdir can return `EEXIST` or `ENOTEMPTY` POSIX allows `rmdir` to return `EEXIST` or `ENOTEMPTY` for a non-empty directory, so the test needs to allow both. --- test/test-fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-fs.c b/test/test-fs.c index ccecb18936a..3720b64d021 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1084,7 +1084,7 @@ TEST_IMPL(fs_posix_delete) { /* should not be possible to delete the non-empty dir */ r = uv_fs_rmdir(NULL, &rmdir_req, "test_dir", NULL); - ASSERT_EQ(r, UV_ENOTEMPTY); + ASSERT((r == UV_ENOTEMPTY) || (r == UV_EEXIST)); ASSERT_EQ(r, rmdir_req.result); uv_fs_req_cleanup(&rmdir_req); From c84a2dbe03da6e115aa18fb866df1c88782bb1fe Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Wed, 7 Aug 2024 12:30:42 +0000 Subject: [PATCH 580/713] test: check for `UV_CHANGE` or `UV_RENAME` event All other checks for `UV_RENAME` in `test-fs-event` also allow `UV_CHANGE`. --- test/test-fs-event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index ccfa2cbe1a8..17048a65f2a 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -152,7 +152,7 @@ static void fs_event_cb_del_dir(uv_fs_event_t* handle, ++fs_event_cb_called; ASSERT_PTR_EQ(handle, &fs_event); ASSERT_OK(status); - ASSERT_EQ(events, UV_RENAME); + ASSERT(events == UV_CHANGE || events == UV_RENAME); ASSERT_OK(strcmp(filename, "watch_del_dir")); ASSERT_OK(uv_fs_event_stop(handle)); uv_close((uv_handle_t*)handle, close_cb); From a53e7877e46f55bd79e60f82353361f9c10d8866 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sat, 10 Aug 2024 11:08:39 +0200 Subject: [PATCH 581/713] unix,fs: silence -Wunused-result warning (#4496) --- src/unix/fs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index aad55fed072..4a4e2e3ad85 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1338,9 +1338,10 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { /* * Change the ownership and permissions of the destination file to match the * source file. - * `cp -p` does not care about errors here, so we don't either. + * `cp -p` does not care about errors here, so we don't either. Reuse the + * `result` variable to silence a -Wunused-result warning. */ - fchown(dstfd, src_statsbuf.st_uid, src_statsbuf.st_gid); + result = fchown(dstfd, src_statsbuf.st_uid, src_statsbuf.st_gid); if (fchmod(dstfd, src_statsbuf.st_mode) == -1) { err = UV__ERR(errno); From 1eac3310ad3cfb20dda42c1e5c62cf642f310c21 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 10 Aug 2024 21:04:09 +0200 Subject: [PATCH 582/713] linux: support abstract unix socket autobinding (#4499) Autobinding is a feature that lets the kernel pick a name for the abstract socket, instead of userspace having to provide one. Two bugs that this change exposed are also fixed: 1. strlen(sa.sun_path) can read past the end if the file path is exactly sizeof(sa.sun_path) long (use memchr instead), and 2. don't return UV_ENOBUFS for abstract sockets when the buffer is exactly large enough to hold the result; per commit e5f4b79809, abstract socket names are not zero-terminated --- src/unix/pipe.c | 33 +++++++++++---- test/test-list.h | 2 + test/test-pipe-bind-error.c | 2 - test/test-pipe-getsockname.c | 79 ++++++++++++++++++++++++++++++++++-- 4 files changed, 101 insertions(+), 15 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 7238cd05d7f..1f9acfac41e 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -76,8 +76,13 @@ int uv_pipe_bind2(uv_pipe_t* handle, if (name == NULL) return UV_EINVAL; + /* namelen==0 on Linux means autobind the listen socket in the abstract + * socket namespace, see `man 7 unix` for details. + */ +#if !defined(__linux__) if (namelen == 0) return UV_EINVAL; +#endif if (includes_nul(name, namelen)) return UV_EINVAL; @@ -344,8 +349,15 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, uv__peersockfunc func, char* buffer, size_t* size) { +#if defined(__linux__) + static const int is_linux = 1; +#else + static const int is_linux = 0; +#endif struct sockaddr_un sa; socklen_t addrlen; + size_t slop; + char* p; int err; addrlen = sizeof(sa); @@ -359,17 +371,20 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, return err; } -#if defined(__linux__) - if (sa.sun_path[0] == 0) - /* Linux abstract namespace */ + slop = 1; + if (is_linux && sa.sun_path[0] == '\0') { + /* Linux abstract namespace. Not zero-terminated. */ + slop = 0; addrlen -= offsetof(struct sockaddr_un, sun_path); - else -#endif - addrlen = strlen(sa.sun_path); - + } else { + p = memchr(sa.sun_path, '\0', sizeof(sa.sun_path)); + if (p == NULL) + p = ARRAY_END(sa.sun_path); + addrlen = p - sa.sun_path; + } - if ((size_t)addrlen >= *size) { - *size = addrlen + 1; + if ((size_t)addrlen + slop > *size) { + *size = addrlen + slop; return UV_ENOBUFS; } diff --git a/test/test-list.h b/test/test-list.h index 1bc8c9a9b1e..8d5cc49a5de 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -209,6 +209,7 @@ TEST_DECLARE (pipe_connect_to_file) TEST_DECLARE (pipe_connect_on_prepare) TEST_DECLARE (pipe_getsockname) TEST_DECLARE (pipe_getsockname_abstract) +TEST_DECLARE (pipe_getsockname_autobind) TEST_DECLARE (pipe_getsockname_blocking) TEST_DECLARE (pipe_pending_instances) TEST_DECLARE (pipe_sendmsg) @@ -827,6 +828,7 @@ TASK_LIST_START TEST_ENTRY (pipe_overlong_path) TEST_ENTRY (pipe_getsockname) TEST_ENTRY (pipe_getsockname_abstract) + TEST_ENTRY (pipe_getsockname_autobind) TEST_ENTRY (pipe_getsockname_blocking) TEST_ENTRY (pipe_pending_instances) TEST_ENTRY (pipe_sendmsg) diff --git a/test/test-pipe-bind-error.c b/test/test-pipe-bind-error.c index d79c2e59a25..16164a7ee90 100644 --- a/test/test-pipe-bind-error.c +++ b/test/test-pipe-bind-error.c @@ -202,7 +202,6 @@ TEST_IMPL(pipe_overlong_path) { ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); #endif /*if defined(_AIX) && !defined(__PASE__)*/ #endif /* ifndef _WIN32 */ - ASSERT_EQ(UV_EINVAL, uv_pipe_bind(&pipe, "")); uv_pipe_connect(&req, &pipe, "", @@ -213,5 +212,4 @@ TEST_IMPL(pipe_overlong_path) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; - } diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index d76b6ad4917..34b572343c6 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -78,6 +78,36 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) { } +#if defined(__linux__) +/* Socket name looks like \0[0-9a-f]{5}, e.g. "\0bad42" */ +static void check_is_autobind_abstract_socket_name(const char *p, size_t len) { + ASSERT_EQ(len, 6); + ASSERT_EQ(*p, '\0'); + + while (*p != '\0') { + ASSERT((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f')); + p++; + } +} + + +static void pipe_client_autobind_connect_cb(uv_connect_t* req, int status) { + char buf[16]; + size_t len; + + ASSERT_OK(status); + len = 5; + ASSERT_EQ(UV_ENOBUFS, uv_pipe_getpeername(&pipe_client, buf, &len)); + len = 6; + ASSERT_OK(uv_pipe_getpeername(&pipe_client, buf, &len)); + check_is_autobind_abstract_socket_name(buf, len); + pipe_client_connect_cb_called++; + uv_close((uv_handle_t*) &pipe_client, pipe_close_cb); + uv_close((uv_handle_t*) &pipe_server, pipe_close_cb); +} +#endif /* defined(__linux__) */ + + static void pipe_server_connection_cb(uv_stream_t* handle, int status) { /* This function *may* be called, depending on whether accept or the * connection callback is called first. @@ -124,9 +154,11 @@ TEST_IMPL(pipe_getsockname) { ASSERT_STR_EQ(pipe_server.pipe_fname, TEST_PIPENAME); #endif - len = sizeof buf; - r = uv_pipe_getsockname(&pipe_server, buf, &len); - ASSERT_OK(r); + len = sizeof(TEST_PIPENAME) - 1; + ASSERT_EQ(UV_ENOBUFS, uv_pipe_getsockname(&pipe_server, buf, &len)); + + len = sizeof(TEST_PIPENAME); + ASSERT_OK(uv_pipe_getsockname(&pipe_server, buf, &len)); ASSERT_NE(0, buf[len - 1]); ASSERT_EQ(buf[len], '\0'); @@ -160,7 +192,8 @@ TEST_IMPL(pipe_getsockname) { len = sizeof buf; r = uv_pipe_getsockname(&pipe_client, buf, &len); - ASSERT(r == 0 && len == 0); + ASSERT_EQ(r, 0); + ASSERT_EQ(len, 0); len = sizeof buf; r = uv_pipe_getpeername(&pipe_client, buf, &len); @@ -228,6 +261,44 @@ TEST_IMPL(pipe_getsockname_abstract) { #endif } + +TEST_IMPL(pipe_getsockname_autobind) { +#if defined(__linux__) + char buf[256]; + size_t buflen; + + buflen = sizeof(buf); + memset(buf, 0, sizeof(buf)); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0)); + ASSERT_OK(uv_pipe_bind2(&pipe_server, "", 0, 0)); + ASSERT_OK(uv_pipe_getsockname(&pipe_server, buf, &buflen)); + check_is_autobind_abstract_socket_name(buf, buflen); + ASSERT_OK(uv_listen((uv_stream_t*) &pipe_server, 0, + pipe_server_connection_cb)); + ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_client, 0)); + ASSERT_OK(uv_pipe_connect2(&connect_req, &pipe_client, + buf, + 1 + strlen(&buf[1]), + 0, + pipe_client_autobind_connect_cb)); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, pipe_client_connect_cb_called); + ASSERT_EQ(2, pipe_close_cb_called); + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +#else + /* On other platforms it should simply fail with UV_EINVAL. */ + ASSERT_OK(uv_pipe_init(uv_default_loop(), &pipe_server, 0)); + ASSERT_EQ(UV_EINVAL, uv_pipe_bind2(&pipe_server, "", 0, 0)); + uv_close((uv_handle_t*) &pipe_server, pipe_close_cb); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT_EQ(1, pipe_close_cb_called); + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +#endif +} + + TEST_IMPL(pipe_getsockname_blocking) { #ifdef _WIN32 HANDLE readh, writeh; From 27134547ff7754107e2c490e0c2f0ed18c05dae2 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Sun, 18 Feb 2024 21:08:25 +0800 Subject: [PATCH 583/713] kqueue: use EVFILT_USER for async if available Establishes a user event for kqueue to eliminate the overhead of the pipe and the system call read(2) per wakeup event. --------- Signed-off-by: Andy Pan Co-authored-by: Jameson Nash --- src/unix/async.c | 85 +++++++++++++++++++++++++++++++++++++++++++++ src/unix/core.c | 2 +- src/unix/internal.h | 22 ++++++++++++ src/unix/kqueue.c | 11 ++++++ 4 files changed, 119 insertions(+), 1 deletion(-) diff --git a/src/unix/async.c b/src/unix/async.c index 29e2f788c75..bc97ec54c4f 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -38,6 +38,34 @@ #include #endif +#if UV__KQUEUE_EVFILT_USER +static uv_once_t kqueue_runtime_detection_guard = UV_ONCE_INIT; +static int kqueue_evfilt_user_support = 1; + + +static void uv__kqueue_runtime_detection(void) { + int kq; + struct kevent ev[2]; + struct timespec timeout = {0, 0}; + + /* Perform the runtime detection to ensure that kqueue with + * EVFILT_USER actually works. */ + kq = kqueue(); + EV_SET(ev, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER, + EV_ADD | EV_CLEAR, 0, 0, 0); + EV_SET(ev + 1, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER, + 0, NOTE_TRIGGER, 0, 0); + if (kevent(kq, ev, 2, ev, 1, &timeout) < 1 || + ev[0].filter != EVFILT_USER || + ev[0].ident != UV__KQUEUE_EVFILT_USER_IDENT || + ev[0].flags & EV_ERROR) + /* If we wind up here, we can assume that EVFILT_USER is defined but + * broken on the current system. */ + kqueue_evfilt_user_support = 0; + uv__close(kq); +} +#endif + static void uv__async_send(uv_loop_t* loop); static int uv__async_start(uv_loop_t* loop); static void uv__cpu_relax(void); @@ -142,7 +170,11 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(w == &loop->async_io_watcher); #ifndef __linux__ +#if UV__KQUEUE_EVFILT_USER + for (;!kqueue_evfilt_user_support;) { +#else for (;;) { +#endif r = read(w->fd, buf, sizeof(buf)); if (r == sizeof(buf)) @@ -209,6 +241,19 @@ static void uv__async_send(uv_loop_t* loop) { return; } #else +#if 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; + else + abort(); + } +#endif fd = loop->async_wfd; /* write end of the pipe */ do @@ -230,6 +275,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; @@ -241,6 +289,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) @@ -251,6 +329,13 @@ static int uv__async_start(uv_loop_t* loop) { uv__io_start(loop, &loop->async_io_watcher, POLLIN); loop->async_wfd = pipefd[1]; +#if UV__KQUEUE_EVFILT_USER + /* Prevent the EVFILT_USER event from being added to kqueue redundantly + * and mistakenly later in uv__io_poll(). */ + if (kqueue_evfilt_user_support) + loop->async_io_watcher.events = loop->async_io_watcher.pevents; +#endif + return 0; } diff --git a/src/unix/core.c b/src/unix/core.c index 971ecf93ab2..cfa65023f99 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1678,7 +1678,7 @@ int uv_thread_setpriority(uv_thread_t tid, int priority) { param.sched_priority = prio; r = pthread_setschedparam(tid, policy, ¶m); if (r != 0) - return UV__ERR(errno); + return UV__ERR(errno); } return 0; diff --git a/src/unix/internal.h b/src/unix/internal.h index 8055730a1d1..a987be60321 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -35,6 +35,10 @@ #include #include #include +#if defined(__APPLE__) || defined(__DragonFly__) || \ + defined(__FreeBSD__) || defined(__NetBSD__) +#include +#endif #define uv__msan_unpoison(p, n) \ do { \ @@ -496,4 +500,22 @@ int uv__get_constrained_cpu(uv__cpu_constraint* constraint); #endif #endif +#if defined(EVFILT_USER) && defined(NOTE_TRIGGER) +/* EVFILT_USER is available since OS X 10.6, DragonFlyBSD 4.0, + * FreeBSD 8.1, and NetBSD 10.0. + * + * Note that even though EVFILT_USER is defined on the current system, + * it may still fail to work at runtime somehow. In that case, we fall + * back to pipe-based signaling. + */ +#define UV__KQUEUE_EVFILT_USER 1 +/* Magic number of identifier used for EVFILT_USER during runtime detection. + * There are no Google hits for this number when I create it. That way, + * people will be directed here if this number gets printed due to some + * kqueue error and they google for help. */ +#define UV__KQUEUE_EVFILT_USER_IDENT 0x1e7e7711 +#else +#define UV__KQUEUE_EVFILT_USER 0 +#endif + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 4d09edc06a0..1762165ee09 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -334,6 +334,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); From 31d91659998a2f34395ab44c89940262e71dca22 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 15 Aug 2024 00:47:57 +0200 Subject: [PATCH 584/713] win: remove deprecated GetVersionExW call (#4486) --- src/win/util.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/win/util.c b/src/win/util.c index 628136c4e6d..deed2e35173 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1535,20 +1535,7 @@ int uv_os_uname(uv_utsname_t* buffer) { os_info.dwOSVersionInfoSize = sizeof(os_info); os_info.szCSDVersion[0] = L'\0'; - /* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx() - if RtlGetVersion() is not available. */ - if (pRtlGetVersion) { - pRtlGetVersion(&os_info); - } else { - /* Silence GetVersionEx() deprecation warning. */ - #ifdef _MSC_VER - #pragma warning(suppress : 4996) - #endif - if (GetVersionExW(&os_info) == 0) { - r = uv_translate_sys_error(GetLastError()); - goto error; - } - } + pRtlGetVersion(&os_info); /* Populate the version field. */ version_size = 0; From 1790abb3b233d87a947074a79e8ea68bd3885862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8F=A1=E7=8C=AB=E7=8C=AB?= <164346864@qq.com> Date: Thu, 15 Aug 2024 17:01:20 +0800 Subject: [PATCH 585/713] doc: document uv_loop_option --- docs/src/loop.rst | 13 +++++++++++++ docs/src/misc.rst | 6 +++--- docs/src/request.rst | 24 ++++++++++++++---------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/docs/src/loop.rst b/docs/src/loop.rst index dc26e654e4b..c5ec1d7a444 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -16,6 +16,19 @@ Data types Loop data type. +.. c:enum:: uv_loop_option + + Additional loop options. + See :c:func:`uv_loop_configure`. + + :: + + typedef enum { + UV_LOOP_BLOCK_SIGNAL = 0, + UV_METRICS_IDLE_TIME, + UV_LOOP_USE_IO_URING_SQPOLL + } uv_loop_option; + .. c:enum:: uv_run_mode Mode used to run the loop with :c:func:`uv_run`. diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 239fc176e62..61883b7e21e 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -199,7 +199,7 @@ Data types char* homedir; } uv_passwd_t; -.. c:type:: uv_group_s +.. c:type:: uv_group_t Data type for group file information. @@ -209,7 +209,7 @@ Data types char* groupname; unsigned long gid; char** members; - }; + } uv_group_t; .. c:type:: uv_utsname_t @@ -590,7 +590,7 @@ API .. versionadded:: 1.45.0 -.. c:function:: int uv_os_get_group(uv_group_s* group, uv_uid_t gid) +.. c:function:: int uv_os_get_group(uv_group_t* group, uv_uid_t gid) Gets a subset of the group file entry for the provided uid. The populated data includes the group name, gid, and members. On non-Windows diff --git a/docs/src/request.rst b/docs/src/request.rst index a0414431b0e..a5b9c7f4f04 100644 --- a/docs/src/request.rst +++ b/docs/src/request.rst @@ -21,17 +21,9 @@ Data types Union of all request types. +.. c:enum:: uv_req_type -Public members -^^^^^^^^^^^^^^ - -.. c:member:: void* uv_req_t.data - - Space for user-defined arbitrary data. libuv does not use this field. - -.. c:member:: uv_req_type uv_req_t.type - - Indicated the type of request. Readonly. + The kind of the libuv request. :: @@ -50,6 +42,18 @@ Public members } uv_req_type; +Public members +^^^^^^^^^^^^^^ + +.. c:member:: void* uv_req_t.data + + Space for user-defined arbitrary data. libuv does not use this field. + +.. c:member:: uv_req_type uv_req_t.type + + The :c:type:`uv_req_type`, indicating the type of the request. Readonly. + + API --- From 8809d1df8dbe994dfb63dff0e2509f89966ed289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8F=A1=E7=8C=AB=E7=8C=AB?= <164346864@qq.com> Date: Fri, 16 Aug 2024 15:13:42 +0800 Subject: [PATCH 586/713] doc: fix the `uv_*_set_data` series of functions They have no return value. --- docs/src/handle.rst | 2 +- docs/src/loop.rst | 2 +- docs/src/request.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/handle.rst b/docs/src/handle.rst index e91d6e8fb2d..0d251fc3499 100644 --- a/docs/src/handle.rst +++ b/docs/src/handle.rst @@ -248,7 +248,7 @@ just for some handle types. .. versionadded:: 1.19.0 -.. c:function:: void* uv_handle_set_data(uv_handle_t* handle, void* data) +.. c:function:: void uv_handle_set_data(uv_handle_t* handle, void* data) Sets `handle->data` to `data`. diff --git a/docs/src/loop.rst b/docs/src/loop.rst index c5ec1d7a444..d1f41e1c9f4 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -256,7 +256,7 @@ API .. versionadded:: 1.19.0 -.. c:function:: void* uv_loop_set_data(uv_loop_t* loop, void* data) +.. c:function:: void uv_loop_set_data(uv_loop_t* loop, void* data) Sets `loop->data` to `data`. diff --git a/docs/src/request.rst b/docs/src/request.rst index a5b9c7f4f04..7ac2aaa0d1d 100644 --- a/docs/src/request.rst +++ b/docs/src/request.rst @@ -99,7 +99,7 @@ API .. versionadded:: 1.19.0 -.. c:function:: void* uv_req_set_data(uv_req_t* req, void* data) +.. c:function:: void uv_req_set_data(uv_req_t* req, void* data) Sets `req->data` to `data`. From 3e1733a053799b0e0e1bcabcccab4a32a503cfb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=8F=A1=E7=8C=AB=E7=8C=AB?= <164346864@qq.com> Date: Sat, 17 Aug 2024 01:30:06 +0800 Subject: [PATCH 587/713] doc: properly label enumerations and types (#4506) --- docs/src/fs.rst | 13 ++++++++++--- docs/src/fs_event.rst | 8 ++++---- docs/src/handle.rst | 2 +- docs/src/poll.rst | 2 +- docs/src/process.rst | 6 +++--- docs/src/request.rst | 2 +- docs/src/tcp.rst | 2 +- docs/src/tty.rst | 2 +- docs/src/udp.rst | 2 +- 9 files changed, 23 insertions(+), 16 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 32cf126c71f..7bc8d0cbfd1 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -132,10 +132,9 @@ Data types uint64_t f_spare[4]; } uv_statfs_t; -.. c:enum:: uv_dirent_t +.. c:enum:: uv_dirent_type_t - Cross platform (reduced) equivalent of ``struct dirent``. - Used in :c:func:`uv_fs_scandir_next`. + Type of dirent. :: @@ -150,6 +149,14 @@ Data types UV_DIRENT_BLOCK } uv_dirent_type_t; + +.. c:type:: uv_dirent_t + + Cross platform (reduced) equivalent of ``struct dirent``. + Used in :c:func:`uv_fs_scandir_next`. + + :: + typedef struct uv_dirent_s { const char* name; uv_dirent_type_t type; diff --git a/docs/src/fs_event.rst b/docs/src/fs_event.rst index 54a776ae6f1..3c105c7b73b 100644 --- a/docs/src/fs_event.rst +++ b/docs/src/fs_event.rst @@ -45,9 +45,9 @@ Data types be a relative path to a file contained in the directory, or `NULL` if the file name cannot be determined. - The `events` parameter is an ORed mask of :c:type:`uv_fs_event` elements. + The `events` parameter is an ORed mask of :c:enum:`uv_fs_event` elements. -.. c:type:: uv_fs_event +.. c:enum:: uv_fs_event Event types that :c:type:`uv_fs_event_t` handles monitor. @@ -58,7 +58,7 @@ Data types UV_CHANGE = 2 }; -.. c:type:: uv_fs_event_flags +.. c:enum:: uv_fs_event_flags Flags that can be passed to :c:func:`uv_fs_event_start` to control its behavior. @@ -109,7 +109,7 @@ API .. c:function:: int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags) Start the handle with the given callback, which will watch the specified - `path` for changes. `flags` can be an ORed mask of :c:type:`uv_fs_event_flags`. + `path` for changes. `flags` can be an ORed mask of :c:enum:`uv_fs_event_flags`. .. note:: Currently the only supported flag is ``UV_FS_EVENT_RECURSIVE`` and only on OSX and Windows. diff --git a/docs/src/handle.rst b/docs/src/handle.rst index 0d251fc3499..2b1b8eec968 100644 --- a/docs/src/handle.rst +++ b/docs/src/handle.rst @@ -94,7 +94,7 @@ Public members .. c:member:: uv_handle_type uv_handle_t.type - The :c:type:`uv_handle_type`, indicating the type of the underlying handle. Readonly. + The :c:enum:`uv_handle_type`, indicating the type of the underlying handle. Readonly. .. c:member:: void* uv_handle_t.data diff --git a/docs/src/poll.rst b/docs/src/poll.rst index f501089279d..b598f0737be 100644 --- a/docs/src/poll.rst +++ b/docs/src/poll.rst @@ -45,7 +45,7 @@ Data types Type definition for callback passed to :c:func:`uv_poll_start`. -.. c:type:: uv_poll_event +.. c:enum:: uv_poll_event Poll event types diff --git a/docs/src/process.rst b/docs/src/process.rst index 8d2fdb3e479..f15dcf610f5 100644 --- a/docs/src/process.rst +++ b/docs/src/process.rst @@ -40,7 +40,7 @@ Data types will indicate the exit status and the signal that caused the process to terminate, if any. -.. c:type:: uv_process_flags +.. c:enum:: uv_process_flags Flags to be set on the flags field of :c:type:`uv_process_options_t`. @@ -190,7 +190,7 @@ Public members Command line arguments. args[0] should be the path to the program. On Windows this uses `CreateProcess` which concatenates the arguments into a string this can cause some strange errors. See the - ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` flag on :c:type:`uv_process_flags`. + ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` flag on :c:enum:`uv_process_flags`. .. c:member:: char** uv_process_options_t.env @@ -203,7 +203,7 @@ Public members .. c:member:: unsigned int uv_process_options_t.flags Various flags that control how :c:func:`uv_spawn` behaves. See - :c:type:`uv_process_flags`. + :c:enum:`uv_process_flags`. .. c:member:: int uv_process_options_t.stdio_count .. c:member:: uv_stdio_container_t* uv_process_options_t.stdio diff --git a/docs/src/request.rst b/docs/src/request.rst index 7ac2aaa0d1d..aacabe026a7 100644 --- a/docs/src/request.rst +++ b/docs/src/request.rst @@ -51,7 +51,7 @@ Public members .. c:member:: uv_req_type uv_req_t.type - The :c:type:`uv_req_type`, indicating the type of the request. Readonly. + The :c:enum:`uv_req_type`, indicating the type of the request. Readonly. API diff --git a/docs/src/tcp.rst b/docs/src/tcp.rst index 571b293002e..f9b203c4199 100644 --- a/docs/src/tcp.rst +++ b/docs/src/tcp.rst @@ -16,7 +16,7 @@ Data types TCP handle type. -.. c:type:: uv_tcp_flags +.. c:enum:: uv_tcp_flags Flags used in :c:func:`uv_tcp_bind`. diff --git a/docs/src/tty.rst b/docs/src/tty.rst index f1acfdc1372..7a2235210bf 100644 --- a/docs/src/tty.rst +++ b/docs/src/tty.rst @@ -98,7 +98,7 @@ API .. c:function:: int uv_tty_set_mode(uv_tty_t* handle, uv_tty_mode_t mode) .. versionchanged:: 1.2.0: the mode is specified as a - :c:type:`uv_tty_mode_t` value. + :c:enum:`uv_tty_mode_t` value. Set the TTY using the specified terminal mode. diff --git a/docs/src/udp.rst b/docs/src/udp.rst index 57d4c77e5e1..31f7f7fd71f 100644 --- a/docs/src/udp.rst +++ b/docs/src/udp.rst @@ -18,7 +18,7 @@ Data types UDP send request type. -.. c:type:: uv_udp_flags +.. c:enum:: uv_udp_flags Flags used in :c:func:`uv_udp_bind` and :c:type:`uv_udp_recv_cb`.. From 5cc7175514571e41cc31219df1ae9dbd8e6b69f9 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sat, 17 Aug 2024 13:44:37 +0200 Subject: [PATCH 588/713] doc: document specific macOS fs_event behavior (#4503) --- docs/src/fs_event.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/fs_event.rst b/docs/src/fs_event.rst index 3c105c7b73b..983db1a9d56 100644 --- a/docs/src/fs_event.rst +++ b/docs/src/fs_event.rst @@ -113,6 +113,9 @@ API .. note:: Currently the only supported flag is ``UV_FS_EVENT_RECURSIVE`` and only on OSX and Windows. + .. note:: On macOS, events collected by the OS immediately before calling + ``uv_fs_event_start`` might be reported to the `uv_fs_event_cb` + callback. .. c:function:: int uv_fs_event_stop(uv_fs_event_t* handle) From c869cd1d8a46d25dabb998485cb8b09cbe62f6c7 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 22 Aug 2024 11:08:08 -0400 Subject: [PATCH 589/713] win,pipe: restore fallback handling for blocking pipes (#4511) In #4470, I accidentally copied the bug from unix, where calling uv_stream_set_blocking can cause the whole process to hang on a read. However, unlike unix, where libuv attempts to set the O_NONBLOCK flag in uv_pipe_open (as long as the handle never gets passed to uv_spawn), the NT kernel is not capable of enabling OVERLAPPED operation later (but fortunately, it also cannot disable it later too). This implementation might be good to copy to unix (using FIONREAD) to address the same bug that happens there if the user has called uv_spawn or uv_stream_set_non_blocking on this handle in the past. --- src/win/pipe.c | 58 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index 4d72d04fab4..15e0fe6b6a8 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1949,11 +1949,13 @@ static DWORD uv__pipe_read_exactly(uv_pipe_t* handle, void* buffer, DWORD count) static int uv__pipe_read_data(uv_loop_t* loop, uv_pipe_t* handle, - DWORD* bytes_read, + DWORD* bytes_read, /* inout argument */ DWORD max_bytes) { uv_buf_t buf; uv_read_t* req; DWORD r; + DWORD bytes_available; + int more; /* Ask the user for a buffer to read data into. */ buf = uv_buf_init(NULL, 0); @@ -1966,29 +1968,49 @@ static int uv__pipe_read_data(uv_loop_t* loop, /* Ensure we read at most the smaller of: * (a) the length of the user-allocated buffer. * (b) the maximum data length as specified by the `max_bytes` argument. + * (c) the amount of data that can be read non-blocking */ if (max_bytes > buf.len) max_bytes = buf.len; - /* Read into the user buffer. - * Prepare an Event so that we can cancel if it doesn't complete immediately. - */ - req = &handle->read_req; - memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); - req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1); - if (ReadFile(handle->handle, buf.base, max_bytes, bytes_read, &req->u.io.overlapped)) { - r = ERROR_SUCCESS; - } else { - r = GetLastError(); - *bytes_read = 0; - if (r == ERROR_IO_PENDING) { - r = CancelIoEx(handle->handle, &req->u.io.overlapped); - assert(r || GetLastError() == ERROR_NOT_FOUND); - if (!GetOverlappedResult(handle->handle, &req->u.io.overlapped, bytes_read, TRUE)) { + if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + /* The user failed to supply a pipe that can be used non-blocking or with + * threads. Try to estimate the amount of data that is safe to read without + * blocking, in a race-y way however. */ + bytes_available = 0; + if (!PeekNamedPipe(handle->handle, NULL, 0, NULL, &bytes_available, NULL)) { + r = GetLastError(); + } else { + if (max_bytes > bytes_available) + max_bytes = bytes_available; + if (max_bytes == 0 || ReadFile(handle->handle, buf.base, max_bytes, bytes_read, NULL)) + r = ERROR_SUCCESS; + else r = GetLastError(); - *bytes_read = 0; + } + more = max_bytes < bytes_available; + } else { + /* Read into the user buffer. + * Prepare an Event so that we can cancel if it doesn't complete immediately. + */ + req = &handle->read_req; + memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1); + if (ReadFile(handle->handle, buf.base, max_bytes, bytes_read, &req->u.io.overlapped)) { + r = ERROR_SUCCESS; + } else { + r = GetLastError(); + *bytes_read = 0; + if (r == ERROR_IO_PENDING) { + r = CancelIoEx(handle->handle, &req->u.io.overlapped); + assert(r || GetLastError() == ERROR_NOT_FOUND); + if (!GetOverlappedResult(handle->handle, &req->u.io.overlapped, bytes_read, TRUE)) { + r = GetLastError(); + *bytes_read = 0; + } } } + more = *bytes_read == max_bytes; } /* Call the read callback. */ @@ -1997,7 +2019,7 @@ static int uv__pipe_read_data(uv_loop_t* loop, else uv__pipe_read_error_or_eof(loop, handle, r, buf); - return *bytes_read == max_bytes; + return more; } From b5eb41d882f72e4f74fad599b20c0c8ec69c0c57 Mon Sep 17 00:00:00 2001 From: Viacheslav Muravyev Date: Mon, 26 Aug 2024 03:54:09 +0700 Subject: [PATCH 590/713] unix,win: remove unused rb-tree macro parameters (#4518) --- include/uv/tree.h | 4 ++-- src/unix/signal.c | 2 +- src/win/signal.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/uv/tree.h b/include/uv/tree.h index 0e41cb0ecee..06bba084f38 100644 --- a/include/uv/tree.h +++ b/include/uv/tree.h @@ -483,8 +483,8 @@ name##_RB_MINMAX(struct name *head, int val) \ #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) #define RB_FIND(name, x, y) name##_RB_FIND(x, y) #define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) -#define RB_NEXT(name, x, y) name##_RB_NEXT(y) -#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_NEXT(name, x) name##_RB_NEXT(x) +#define RB_PREV(name, x) name##_RB_PREV(x) #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) diff --git a/src/unix/signal.c b/src/unix/signal.c index bc4206e6d86..f23c887d0d6 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -195,7 +195,7 @@ static void uv__signal_handler(int signum) { for (handle = uv__signal_first_handle(signum); handle != NULL && handle->signum == signum; - handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) { + handle = RB_NEXT(uv__signal_tree_s, handle)) { int r; msg.signum = signum; diff --git a/src/win/signal.c b/src/win/signal.c index 8c79871b9bb..85730b27b2b 100644 --- a/src/win/signal.c +++ b/src/win/signal.c @@ -91,7 +91,7 @@ int uv__signal_dispatch(int signum) { for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup); handle != NULL && handle->signum == signum; - handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) { + handle = RB_NEXT(uv_signal_tree_s, handle)) { unsigned long previous = InterlockedExchange( (volatile LONG*) &handle->pending_signum, signum); From 58dfb6c89ba3deb23301ddbdd4a8769f4c767dff Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 26 Aug 2024 10:22:42 +0200 Subject: [PATCH 591/713] win: compute parallelism from process cpu affinity (#4521) Use GetProcessAffinityMask() to estimate the available parallelism. Before this commit, it simply used the number of available CPUs. Fixes: https://github.com/libuv/libuv/issues/4520 --- src/win/util.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/win/util.c b/src/win/util.c index deed2e35173..72cb74929e8 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -512,19 +512,23 @@ int uv_uptime(double* uptime) { unsigned int uv_available_parallelism(void) { - SYSTEM_INFO info; - unsigned rc; + DWORD_PTR procmask; + DWORD_PTR sysmask; + int count; + int i; /* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems * with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458 */ - GetSystemInfo(&info); + count = 0; + if (GetProcessAffinityMask(GetCurrentProcess(), &procmask, &sysmask)) + for (i = 0; i < 64; i++) /* a.k.a. count = popcount(procmask); */ + count += 1 & (procmask >> i); - rc = info.dwNumberOfProcessors; - if (rc < 1) - rc = 1; + if (count > 0) + return count; - return rc; + return 1; } From 5cbc82e369817adf963e7ad37f70884a6434fb0a Mon Sep 17 00:00:00 2001 From: Zuohui Yang <274048862@qq.com> Date: Tue, 27 Aug 2024 02:17:53 +0800 Subject: [PATCH 592/713] win: use NtQueryInformationProcess in uv_os_getppid (#4514) Get parent process ID using NtQueryInformationProcess, it's faster than using CreateToolhelp32Snapshot. --- src/win/util.c | 30 ++++++++++++------------------ src/win/winapi.h | 12 ++++++++++++ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/win/util.c b/src/win/util.c index 72cb74929e8..1cc42fd45b1 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -316,25 +316,19 @@ uv_pid_t uv_os_getpid(void) { uv_pid_t uv_os_getppid(void) { - int parent_pid = -1; - HANDLE handle; - PROCESSENTRY32 pe; - DWORD current_pid = GetCurrentProcessId(); - - pe.dwSize = sizeof(PROCESSENTRY32); - handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - - if (Process32First(handle, &pe)) { - do { - if (pe.th32ProcessID == current_pid) { - parent_pid = pe.th32ParentProcessID; - break; - } - } while( Process32Next(handle, &pe)); + NTSTATUS nt_status; + PROCESS_BASIC_INFORMATION basic_info; + + nt_status = pNtQueryInformationProcess(GetCurrentProcess(), + ProcessBasicInformation, + &basic_info, + sizeof(basic_info), + NULL); + if (NT_SUCCESS(nt_status)) { + return basic_info.InheritedFromUniqueProcessId; + } else { + return -1; } - - CloseHandle(handle); - return parent_pid; } diff --git a/src/win/winapi.h b/src/win/winapi.h index 6d9482360ad..548081f23a9 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4458,6 +4458,14 @@ typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION { ULONG ByteOffsetForPartitionAlignment; } FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION; +typedef struct _PROCESS_BASIC_INFORMATION { + PVOID Reserved1; + PVOID PebBaseAddress; + PVOID Reserved2[2]; + ULONG_PTR UniqueProcessId; + ULONG_PTR InheritedFromUniqueProcessId; +} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION; + typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { LARGE_INTEGER IdleTime; LARGE_INTEGER KernelTime; @@ -4471,6 +4479,10 @@ typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { # define SystemProcessorPerformanceInformation 8 #endif +#ifndef ProcessBasicInformation +# define ProcessBasicInformation 0 +#endif + #ifndef ProcessConsoleHostProcess # define ProcessConsoleHostProcess 49 #endif From f00d4b677556a007a28fcb0bb3548ecdb54a29ae Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 28 Aug 2024 19:59:46 -0400 Subject: [PATCH 593/713] win,pipe: fix missing assignment to success (#4515) --- src/win/pipe.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index 15e0fe6b6a8..5a324bb0410 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -2004,7 +2004,9 @@ static int uv__pipe_read_data(uv_loop_t* loop, if (r == ERROR_IO_PENDING) { r = CancelIoEx(handle->handle, &req->u.io.overlapped); assert(r || GetLastError() == ERROR_NOT_FOUND); - if (!GetOverlappedResult(handle->handle, &req->u.io.overlapped, bytes_read, TRUE)) { + if (GetOverlappedResult(handle->handle, &req->u.io.overlapped, bytes_read, TRUE)) { + r = ERROR_SUCCESS; + } else { r = GetLastError(); *bytes_read = 0; } From 5ff1fc724f7f53d921599dbe18e6f96b298233f1 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 2 Sep 2024 11:24:11 +0200 Subject: [PATCH 594/713] win: fix uv_available_parallelism on win32 (#4525) Fixes commit 58dfb6c89b from a few days ago. DWORD_PTR is 32 bits on x86 Windows. Use the right bit count when checking the population count. Interestingly enough, it manifested itself as double counting online processors, presumably because the compiler emits a ROR instead of SHR. Fixes: https://github.com/libuv/libuv/issues/4524 --- src/win/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/util.c b/src/win/util.c index 1cc42fd45b1..e0dba1aaa94 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -516,7 +516,7 @@ unsigned int uv_available_parallelism(void) { */ count = 0; if (GetProcessAffinityMask(GetCurrentProcess(), &procmask, &sysmask)) - for (i = 0; i < 64; i++) /* a.k.a. count = popcount(procmask); */ + for (i = 0; i < 8 * sizeof(procmask); i++) count += 1 & (procmask >> i); if (count > 0) From 0a00e80c3686b93eccb9a801954e86bd7d7fe6ab Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 5 Sep 2024 09:46:37 -0400 Subject: [PATCH 595/713] win,pipe: fix another missing assignment to success (#4523) Yet another followup to #4511. The functional/legacy/increment_spec.lua test failed most of the time without this, and passes consistently with it. It seemed unexpected this code path gets reached (perhaps imply that the user wrote zero bytes?), but good to fix of course. --- src/win/pipe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win/pipe.c b/src/win/pipe.c index 5a324bb0410..76ea169e19f 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1983,6 +1983,7 @@ static int uv__pipe_read_data(uv_loop_t* loop, } else { if (max_bytes > bytes_available) max_bytes = bytes_available; + *bytes_read = 0; if (max_bytes == 0 || ReadFile(handle->handle, buf.base, max_bytes, bytes_read, NULL)) r = ERROR_SUCCESS; else From 44e61dab7effb739f543b8b4eee43f577bf2db49 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Tue, 10 Sep 2024 02:22:15 +0800 Subject: [PATCH 596/713] kqueue: disallow ill-suited file descriptor kinds (#4513) Follows up on https://github.com/libuv/libuv/pull/659. Signed-off-by: Andy Pan --- src/unix/kqueue.c | 33 +++++++++++++++++++++++++++ test/test-poll.c | 57 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 78 insertions(+), 12 deletions(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 1762165ee09..876b717086c 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -99,6 +99,39 @@ 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 stat sb; +#ifdef __APPLE__ + char path[MAXPATHLEN]; +#endif + + if (uv__fstat(fd, &sb)) + return UV__ERR(errno); + + /* On FreeBSD, kqueue only supports EVFILT_READ notification for regular files + * and always reports ready events for writing, resulting in busy-looping. + * + * On Darwin, DragonFlyBSD, NetBSD and OpenBSD, kqueue reports ready events for + * regular files as readable and writable only once, acting like an EV_ONESHOT. + * + * Neither of the above cases should be added to the kqueue. + */ + if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode)) + return UV_EINVAL; + +#ifdef __APPLE__ + /* On Darwin (both macOS and iOS), in addition to regular files, FIFOs also don't + * work properly with kqueue: the disconnection from the last writer won't trigger + * an event for kqueue in spite of what the man pages say. Thus, we also disallow + * the case of S_IFIFO. */ + if (S_ISFIFO(sb.st_mode)) { + /* File descriptors of FIFO, pipe and kqueue share the same type of file, + * therefore there is no way to tell them apart via stat.st_mode&S_IFMT. + * Fortunately, FIFO is the only one that has a persisted file on filesystem, + * from which we're able to make the distinction for it. */ + if (!fcntl(fd, F_GETPATH, path)) + return UV_EINVAL; + } +#endif rc = 0; EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); diff --git a/test/test-poll.c b/test/test-poll.c index fcd644f2c25..5161de25376 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -626,26 +626,59 @@ TEST_IMPL(poll_unidirectional) { /* Windows won't let you open a directory so we open a file instead. - * OS X lets you poll a file so open the $PWD instead. Both fail - * on Linux so it doesn't matter which one we pick. Both succeed - * on FreeBSD, Solaris and AIX so skip the test on those platforms. + * OS X lets you poll a file so open the $PWD instead. Both fail + * on Linux so it doesn't matter which one we pick. Both succeed + * on Solaris and AIX so skip the test on those platforms. + * On *BSD/Darwin, we disallow polling of regular files, directories. + * In addition to regular files, we also disallow FIFOs on Darwin. */ +#ifdef __APPLE__ +#define TEST_POLL_FIFO_PATH "/tmp/uv-test-poll-fifo" +#endif TEST_IMPL(poll_bad_fdtype) { -#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \ +#if !defined(__sun) && \ !defined(_AIX) && !defined(__MVS__) && \ - !defined(__OpenBSD__) && !defined(__CYGWIN__) && !defined(__MSYS__) && \ - !defined(__NetBSD__) + !defined(__CYGWIN__) && !defined(__MSYS__) uv_poll_t poll_handle; - int fd; + int fd[2]; #if defined(_WIN32) - fd = _open("test/fixtures/empty_file", UV_FS_O_RDONLY); + fd[0] = _open("test/fixtures/empty_file", UV_FS_O_RDONLY); #else - fd = open(".", UV_FS_O_RDONLY); + fd[0] = open(".", UV_FS_O_RDONLY); +#endif + ASSERT_NE(fd[0], -1); + ASSERT_NE(0, uv_poll_init(uv_default_loop(), &poll_handle, fd[0])); + ASSERT_OK(close(fd[0])); +#if defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) + fd[0] = open("test/fixtures/empty_file", UV_FS_O_RDONLY); + ASSERT_NE(fd[0], -1); + /* Regular files should be banned from kqueue. */ + ASSERT_NE(0, uv_poll_init(uv_default_loop(), &poll_handle, fd[0])); + ASSERT_OK(close(fd[0])); +#ifdef __APPLE__ + ASSERT_OK(pipe(fd)); + /* Pipes should be permitted in kqueue. */ + ASSERT_EQ(0, uv_poll_init(uv_default_loop(), &poll_handle, fd[0])); + ASSERT_OK(close(fd[0])); + ASSERT_OK(close(fd[1])); + + ASSERT_OK(mkfifo(TEST_POLL_FIFO_PATH, 0600)); + fd[0] = open(TEST_POLL_FIFO_PATH, O_RDONLY | O_NONBLOCK); + ASSERT_NE(fd[0], -1); + fd[1] = open(TEST_POLL_FIFO_PATH, O_WRONLY | O_NONBLOCK); + ASSERT_NE(fd[1], -1); + /* FIFOs should be banned from kqueue. */ + ASSERT_NE(0, uv_poll_init(uv_default_loop(), &poll_handle, fd[0])); + ASSERT_OK(close(fd[0])); + ASSERT_OK(close(fd[1])); + unlink(TEST_POLL_FIFO_PATH); +#endif #endif - ASSERT_NE(fd, -1); - ASSERT_NE(0, uv_poll_init(uv_default_loop(), &poll_handle, fd)); - ASSERT_OK(close(fd)); #endif MAKE_VALGRIND_HAPPY(uv_default_loop()); From a49f264dff6bc853d67e2d16f635ba8d80bc62a6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 11 Sep 2024 10:33:54 +0200 Subject: [PATCH 597/713] unix: restore tty attributes on handle close (#4399) Libuv stores the `struct termios` for use inside uv_tty_reset_mode(). Node.js uses said function to restore the tty to its original mode on SIGINT or SIGTERM, when there is no opportunity to shut down the process normally. Track uv_tty_t handle closing, otherwise we might be trying to use a stale termios. The current solution is not ideal because there can be multiple handles that refer to the same tty/pty and, for various reasons, we can't really determine when we close the last handle. The last handle may not even be inside the current process. Still, all things considered, it's probably (hopefully!) an improvement over the status quo. Refs: https://github.com/libuv/libuv/issues/4398 --- src/unix/core.c | 2 +- src/unix/internal.h | 3 +++ src/unix/tty.c | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index cfa65023f99..b74552efcf4 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -156,7 +156,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { break; case UV_TTY: - uv__stream_close((uv_stream_t*)handle); + uv__tty_close((uv_tty_t*)handle); break; case UV_TCP: diff --git a/src/unix/internal.h b/src/unix/internal.h index a987be60321..86c0d18aacd 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -293,6 +293,9 @@ int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb); int uv__tcp_nodelay(int fd, int on); int uv__tcp_keepalive(int fd, int on, unsigned int delay); +/* tty */ +void uv__tty_close(uv_tty_t* handle); + /* pipe */ int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); diff --git a/src/unix/tty.c b/src/unix/tty.c index d099bdb3b67..793054ba5a9 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -335,6 +335,37 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { } +void uv__tty_close(uv_tty_t* handle) { + int expected; + int fd; + + fd = handle->io_watcher.fd; + if (fd == -1) + goto done; + + /* This is used for uv_tty_reset_mode() */ + do + expected = 0; + while (!atomic_compare_exchange_strong(&termios_spinlock, &expected, 1)); + + if (fd == orig_termios_fd) { + /* XXX(bnoordhuis) the tcsetattr is probably wrong when there are still + * other uv_tty_t handles active that refer to the same tty/pty but it's + * hard to recognize that particular situation without maintaining some + * kind of process-global data structure, and that still won't work in a + * multi-process setup. + */ + uv__tcsetattr(fd, TCSANOW, &orig_termios); + orig_termios_fd = -1; + } + + atomic_store(&termios_spinlock, 0); + +done: + uv__stream_close((uv_stream_t*) handle); +} + + int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { struct winsize ws; int err; @@ -452,7 +483,7 @@ int uv_tty_reset_mode(void) { saved_errno = errno; if (atomic_exchange(&termios_spinlock, 1)) - return UV_EBUSY; /* In uv_tty_set_mode(). */ + return UV_EBUSY; /* In uv_tty_set_mode() or uv__tty_close(). */ err = 0; if (orig_termios_fd != -1) From 9dddebab0d93997da87c8452ce13dcf72387bf8e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 12 Sep 2024 22:19:10 +0200 Subject: [PATCH 598/713] test: delete test with invalid assumption (#4530) Delete the fs_event_error_reporting test. It fails in different ways, most frequently on the TSan sanitizer buildbot, due to running out of file descriptors when that is not expected, or vice versa, *not* running out of file descriptors when that *is* expected. The test creates a large number of event loops and expects to, eventually, hit EMFILE but it sometimes hits it too early, and sometimes not at all. I don't think TSan is really responsible here, it just makes the invalid assumption in the test itself more visible. Fixes: https://github.com/libuv/libuv/issues/4368 --- test/test-fs-event.c | 100 ------------------------------------------- test/test-list.h | 2 - 2 files changed, 102 deletions(-) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 17048a65f2a..bb223a5f654 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -1145,106 +1145,6 @@ TEST_IMPL(fs_event_getpath) { return 0; } -#if defined(__APPLE__) - -static int fs_event_error_reported; - -static void fs_event_error_report_cb(uv_fs_event_t* handle, - const char* filename, - int events, - int status) { - if (status != 0) - fs_event_error_reported = status; -} - -static void timer_cb_nop(uv_timer_t* handle) { - ++timer_cb_called; - uv_close((uv_handle_t*) handle, close_cb); -} - -static void fs_event_error_report_close_cb(uv_handle_t* handle) { - ASSERT_NOT_NULL(handle); - close_cb_called++; - - /* handle is allocated on-stack, no need to free it */ -} - - -TEST_IMPL(fs_event_error_reporting) { - unsigned int i; - uv_loop_t loops[1024]; - uv_fs_event_t events[ARRAY_SIZE(loops)]; - uv_loop_t* loop; - uv_fs_event_t* event; - - TEST_FILE_LIMIT(ARRAY_SIZE(loops) * 3); - - delete_dir("watch_dir/"); - create_dir("watch_dir"); - - /* Create a lot of loops, and start FSEventStream in each of them. - * Eventually, this should create enough streams to make FSEventStreamStart() - * fail. - */ - for (i = 0; i < ARRAY_SIZE(loops); i++) { - loop = &loops[i]; - ASSERT_OK(uv_loop_init(loop)); - event = &events[i]; - - timer_cb_called = 0; - close_cb_called = 0; - ASSERT_OK(uv_fs_event_init(loop, event)); - ASSERT_OK(uv_fs_event_start(event, - fs_event_error_report_cb, - "watch_dir", - 0)); - uv_unref((uv_handle_t*) event); - - /* Let loop run for some time */ - ASSERT_OK(uv_timer_init(loop, &timer)); - ASSERT_OK(uv_timer_start(&timer, timer_cb_nop, 2, 0)); - uv_run(loop, UV_RUN_DEFAULT); - ASSERT_EQ(1, timer_cb_called); - ASSERT_EQ(1, close_cb_called); - if (fs_event_error_reported != 0) - break; - } - - /* At least one loop should fail */ - ASSERT_EQ(fs_event_error_reported, UV_EMFILE); - - /* Stop and close all events, and destroy loops */ - do { - loop = &loops[i]; - event = &events[i]; - - ASSERT_OK(uv_fs_event_stop(event)); - uv_ref((uv_handle_t*) event); - uv_close((uv_handle_t*) event, fs_event_error_report_close_cb); - - close_cb_called = 0; - uv_run(loop, UV_RUN_DEFAULT); - ASSERT_EQ(1, close_cb_called); - - uv_loop_close(loop); - } while (i-- != 0); - - delete_dir("watch_dir/"); - MAKE_VALGRIND_HAPPY(uv_default_loop()); - return 0; -} - -#else /* !defined(__APPLE__) */ - -TEST_IMPL(fs_event_error_reporting) { - /* No-op, needed only for FSEvents backend */ - - MAKE_VALGRIND_HAPPY(uv_default_loop()); - return 0; -} - -#endif /* defined(__APPLE__) */ - TEST_IMPL(fs_event_watch_invalid_path) { #if defined(NO_FS_EVENTS) RETURN_SKIP(NO_FS_EVENTS); diff --git a/test/test-list.h b/test/test-list.h index 8d5cc49a5de..22a9a51d95f 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -417,7 +417,6 @@ TEST_DECLARE (fs_event_close_with_pending_event) TEST_DECLARE (fs_event_close_with_pending_delete_event) TEST_DECLARE (fs_event_close_in_callback) TEST_DECLARE (fs_event_start_and_close) -TEST_DECLARE (fs_event_error_reporting) TEST_DECLARE (fs_event_getpath) TEST_DECLARE (fs_event_stop_in_cb) TEST_DECLARE (fs_scandir_empty_dir) @@ -1128,7 +1127,6 @@ TASK_LIST_START TEST_ENTRY (fs_event_close_with_pending_delete_event) TEST_ENTRY (fs_event_close_in_callback) TEST_ENTRY (fs_event_start_and_close) - TEST_ENTRY_CUSTOM (fs_event_error_reporting, 0, 0, 60000) TEST_ENTRY (fs_event_getpath) TEST_ENTRY (fs_event_stop_in_cb) TEST_ENTRY (fs_scandir_empty_dir) From 88af4a87d255834a4edbed1675dee748a90c3c7c Mon Sep 17 00:00:00 2001 From: "Jeffrey H. Johnson" Date: Tue, 17 Sep 2024 15:27:18 -0400 Subject: [PATCH 599/713] dragonflybsd: fix compilation failure (#4534) Fixes: https://github.com/libuv/libuv/issues/4533 Signed-off-by: Jeffrey H. Johnson --- src/unix/freebsd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index 191bc8bc213..a6de29c558c 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -26,7 +26,12 @@ #include #include -#include +#if defined(__DragonFly__) +# include +# include +#else +# include +#endif #include #include #include From 5bb19f35ea1ad974d7f13ce12ebbf2183133226a Mon Sep 17 00:00:00 2001 From: "Edigleysson Silva (Edy)" Date: Tue, 17 Sep 2024 16:30:24 -0300 Subject: [PATCH 600/713] test: run android tests on ci (#4517) --- .github/workflows/CI-unix.yml | 26 ++++++++++++++++++++++++++ test/task.h | 4 ++++ test/test-emfile.c | 8 ++++++++ test/test-udp-multicast-join6.c | 5 +++++ 4 files changed, 43 insertions(+) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 7d66517667a..591c35cf97a 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -35,6 +35,7 @@ jobs: # image. env: ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + ANDROID_AVD_HOME: /root/.android/avd steps: - uses: actions/checkout@v3 - name: Envinfo @@ -49,6 +50,31 @@ jobs: run: | $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake --build build ls -lh build + - name: Install Android ABI arm64-v8a + run: | + # TODO: This can be in a pre-built docker image + sdkmanager "build-tools;24.0.3" "platforms;android-24" "system-images;android-24;google_apis;arm64-v8a" + + - name: Start emulator + run: | + echo no | avdmanager create avd -n test -k "system-images;android-24;google_apis;arm64-v8a" + + adb start-server + + emulator @test -memory 2048 -no-audio -no-window -gpu off -no-snapshot -no-boot-anim -netdelay none -netspeed full -no-snapshot-save -no-snapshot-load -writable-system & + + adb wait-for-device + + adb shell "su 0 setenforce 0" # to allow some syscalls like link, chmod, etc. + + # Push the build and test fixtures to the device + adb push build /data/local/tmp + adb shell mkdir /data/local/tmp/build/test + adb push test/fixtures /data/local/tmp/build/test + + - name: Test + run: | + adb shell "cd /data/local/tmp/build ; env UV_TEST_TIMEOUT_MULTIPLIER=5 ./uv_run_tests_a" build-macos: runs-on: macos-12 diff --git a/test/task.h b/test/task.h index 8b8353263da..e25a9c9a138 100644 --- a/test/task.h +++ b/test/task.h @@ -53,6 +53,10 @@ # define TEST_PIPENAME "\\\\.\\pipe\\uv-test" # define TEST_PIPENAME_2 "\\\\.\\pipe\\uv-test2" # define TEST_PIPENAME_3 "\\\\.\\pipe\\uv-test3" +#elif __ANDROID__ +# define TEST_PIPENAME "/data/local/tmp/uv-test-sock" +# define TEST_PIPENAME_2 "/data/local/tmp/uv-test-sock2" +# define TEST_PIPENAME_3 "/data/local/tmp/uv-test-sock3" #else # define TEST_PIPENAME "/tmp/uv-test-sock" # define TEST_PIPENAME_2 "/tmp/uv-test-sock2" diff --git a/test/test-emfile.c b/test/test-emfile.c index ef2338cdfbb..3ad8378ca1e 100644 --- a/test/test-emfile.c +++ b/test/test-emfile.c @@ -75,6 +75,14 @@ TEST_IMPL(emfile) { ASSERT_EQ(errno, EMFILE); close(maxfd); +#if defined(__ANDROID__) + /* Android connect syscall requires an extra file descriptor + * + * It fails in uv__tcp_connect + * */ + close(maxfd - 1); +#endif + /* Now connect and use up the last available file descriptor. The EMFILE * handling logic in src/unix/stream.c should ensure that connect_cb() runs * whereas connection_cb() should *not* run. diff --git a/test/test-udp-multicast-join6.c b/test/test-udp-multicast-join6.c index 11efb0a6f67..c6872e42832 100644 --- a/test/test-udp-multicast-join6.c +++ b/test/test-udp-multicast-join6.c @@ -192,6 +192,11 @@ TEST_IMPL(udp_multicast_join6) { ASSERT_OK(r); +#if defined(__ANDROID__) + /* It returns an ENOSYS error */ + RETURN_SKIP("Test does not currently work in ANDROID"); +#endif + /* TODO(gengjiawen): Fix test on QEMU. */ #if defined(__QEMU__) RETURN_SKIP("Test does not currently work in QEMU"); From 1c778bd001543371c915a79b7ac3c5864fe59e74 Mon Sep 17 00:00:00 2001 From: Raihaan Shouhell Date: Wed, 18 Sep 2024 05:15:37 +0800 Subject: [PATCH 601/713] darwin: add udp mmsg support (#4527) --- src/unix/darwin-syscalls.h | 17 +++++++++++++++++ src/unix/internal.h | 7 +++++-- src/unix/udp.c | 27 ++++++++++++++++++++------- 3 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 src/unix/darwin-syscalls.h diff --git a/src/unix/darwin-syscalls.h b/src/unix/darwin-syscalls.h new file mode 100644 index 00000000000..dc2d1bd234b --- /dev/null +++ b/src/unix/darwin-syscalls.h @@ -0,0 +1,17 @@ +#ifndef UV_DARWIN_SYSCALLS_H_ +#define UV_DARWIN_SYSCALLS_H_ + +#include +#include + +/* https://github.com/apple/darwin-xnu/blob/master/bsd/sys/socket.h */ + +struct mmsghdr { + struct msghdr msg_hdr; + size_t msg_len; +}; + +ssize_t recvmsg_x(int s, const struct mmsghdr* msgp, u_int cnt, int flags); +ssize_t sendmsg_x(int s, const struct mmsghdr* msgp, u_int cnt, int flags); + +#endif /* UV_DARWIN_SYSCALLS_H_ */ diff --git a/src/unix/internal.h b/src/unix/internal.h index 86c0d18aacd..529c783e6e9 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -75,8 +75,11 @@ # include #endif /* _AIX */ -#if defined(__APPLE__) && !TARGET_OS_IPHONE -# include +#if defined(__APPLE__) +# include "darwin-syscalls.h" +# if !TARGET_OS_IPHONE +# include +# endif #endif /* diff --git a/src/unix/udp.c b/src/unix/udp.c index aa214db03e9..f6640fc7231 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -148,7 +148,7 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { } static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) struct sockaddr_in6 peers[20]; struct iovec iov[ARRAY_SIZE(peers)]; struct mmsghdr msgs[ARRAY_SIZE(peers)]; @@ -173,11 +173,18 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { msgs[k].msg_hdr.msg_control = NULL; msgs[k].msg_hdr.msg_controllen = 0; msgs[k].msg_hdr.msg_flags = 0; + msgs[k].msg_len = 0; } +#if defined(__APPLE__) + do + nread = recvmsg_x(handle->io_watcher.fd, msgs, chunks, MSG_DONTWAIT); + while (nread == -1 && errno == EINTR); +#else do nread = recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL); while (nread == -1 && errno == EINTR); +#endif if (nread < 1) { if (nread == 0 || errno == EAGAIN || errno == EWOULDBLOCK) @@ -204,9 +211,9 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE); } return nread; -#else /* __linux__ || ____FreeBSD__ */ +#else /* __linux__ || ____FreeBSD__ || __APPLE__ */ return UV_ENOSYS; -#endif /* __linux__ || ____FreeBSD__ */ +#endif /* __linux__ || ____FreeBSD__ || __APPLE__ */ } static void uv__udp_recvmsg(uv_udp_t* handle) { @@ -328,7 +335,7 @@ static void uv__udp_sendmsg_one(uv_udp_t* handle, uv_udp_send_t* req) { } } -#if defined(__linux__) || defined(__FreeBSD__) +#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]; @@ -366,9 +373,15 @@ static void uv__udp_sendmsg_many(uv_udp_t* handle) { 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) @@ -409,7 +422,7 @@ static void uv__udp_sendmsg_many(uv_udp_t* handle) { uv__io_feed(handle->loop, &handle->io_watcher); } -#endif /* __linux__ || ____FreeBSD__ */ +#endif /* __linux__ || ____FreeBSD__ || __APPLE__ */ static void uv__udp_sendmsg(uv_udp_t* handle) { struct uv__queue* q; @@ -421,7 +434,7 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { q = uv__queue_head(&handle->write_queue); req = uv__queue_data(q, uv_udp_send_t, queue); -#if defined(__linux__) || defined(__FreeBSD__) +#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.) @@ -1037,7 +1050,7 @@ int uv__udp_init_ex(uv_loop_t* loop, int uv_udp_using_recvmmsg(const uv_udp_t* handle) { -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) if (handle->flags & UV_HANDLE_UDP_RECVMMSG) return 1; #endif From 32603fd5ff56ea4634c66ce2941a053f5d381edd Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 19 Sep 2024 19:53:19 +0200 Subject: [PATCH 602/713] unix: work around arm-linux-gnueabihf-gcc bug (#4537) Both gcc 11 and 12 emit wrong code for a function call pointer in one very specific context. Fixes: https://github.com/libuv/libuv/issues/4532 --- src/unix/fs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 4a4e2e3ad85..6d810debf5d 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -482,7 +482,10 @@ static ssize_t uv__preadv_or_pwritev(int fd, atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed); } - f = p; + /* Use memcpy instead of `f = p` to work around a compiler bug, + * see https://github.com/libuv/libuv/issues/4532 + */ + memcpy(&f, &p, sizeof(p)); return f(fd, bufs, nbufs, off); } From e1a54652555baa5d49b7c8b3503f68ac97c2fb77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Thu, 19 Sep 2024 08:48:58 +0200 Subject: [PATCH 603/713] unix: expand uv_available_parallelism() to support more platforms --- src/unix/core.c | 124 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 101 insertions(+), 23 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index b74552efcf4..1935ba87381 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -53,7 +53,8 @@ #if defined(__APPLE__) # include -# endif /* defined(__APPLE__) */ +# include +#endif /* defined(__APPLE__) */ #if defined(__APPLE__) && !TARGET_OS_IPHONE @@ -94,6 +95,15 @@ extern char** environ; # define uv__accept4 accept4 #endif +#if defined(__FreeBSD__) +# include +# include +#endif + +#if defined(__NetBSD__) +# include +#endif + #if defined(__linux__) && defined(__SANITIZE_THREAD__) && defined(__clang__) # include #endif @@ -1869,13 +1879,31 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) { return UV_EINVAL; } +#if defined(__linux__) || defined (__FreeBSD__) +# define uv__cpu_count(cpuset) CPU_COUNT(cpuset) +#elif defined(__NetBSD__) +static int uv__cpu_count(cpuset_t *cpuset) { + int rc; + cpuid_t i; + + rc = 0; + for (i = 0;; i++) { + int r = cpuset_isset(cpu, set); + if (r < 0) + break; + if (r) + rc++; + } + + return rc; +} +#endif /* __NetBSD__ */ unsigned int uv_available_parallelism(void) { + long rc = -1; + #ifdef __linux__ cpu_set_t set; - long rc; - double rc_with_cgroup; - uv__cpu_constraint c = {0, 0, 0.0}; memset(&set, 0, sizeof(set)); @@ -1884,36 +1912,86 @@ unsigned int uv_available_parallelism(void) { * before falling back to sysconf(_SC_NPROCESSORS_ONLN). */ if (0 == sched_getaffinity(0, sizeof(set), &set)) - rc = CPU_COUNT(&set); - else - rc = sysconf(_SC_NPROCESSORS_ONLN); - - if (uv__get_constrained_cpu(&c) == 0 && c.period_length > 0) { - rc_with_cgroup = (double)c.quota_per_period / c.period_length * c.proportions; - if (rc_with_cgroup < rc) - rc = (long)rc_with_cgroup; /* Casting is safe since rc_with_cgroup < rc < LONG_MAX */ - } - if (rc < 1) - rc = 1; - - return (unsigned) rc; + rc = uv__cpu_count(&set); #elif defined(__MVS__) - int rc; - rc = __get_num_online_cpus(); if (rc < 1) rc = 1; return (unsigned) rc; -#else /* __linux__ */ - long rc; +#elif defined(__FreeBSD__) + cpuset_t set; + + memset(&set, 0, sizeof(set)); + + if (0 == cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(set), &set)) + rc = uv__cpu_count(&set); +#elif defined(__NetBSD__) + cpuset_t* set = cpuset_create(); + if (set != NULL) { + if (0 == sched_getaffinity_np(getpid(), sizeof(set), &set)) + rc = uv__cpu_count(&set); + cpuset_destroy(set); + } +#elif defined(__APPLE__) + int nprocs; + size_t i; + size_t len = sizeof(nprocs); + static const char *mib[] = { + "hw.activecpu", + "hw.logicalcpu", + "hw.ncpu" + }; + + for (i = 0; i < ARRAY_SIZE(mib); i++) { + if (0 == sysctlbyname(mib[i], &nprocs, &len, NULL, 0) && + len == sizeof(nprocs) && + nprocs > 0) { + rc = nprocs; + break; + } + } +#elif defined(__OpenBSD__) + int nprocs; + size_t i; + size_t len = sizeof(nprocs); + static int mib[][2] = { +# ifdef HW_NCPUONLINE + { CTL_HW, HW_NCPUONLINE }, +# endif + { CTL_HW, HW_NCPU } + }; + + for (i = 0; i < ARRAY_SIZE(mib); i++) { + if (0 == sysctl(mib[i], ARRAY_SIZE(mib[i]), &nprocs, &len, NULL, 0) && + len == sizeof(nprocs) && + nprocs > 0) { + rc = nprocs; + break; + } + } +#endif /* __linux__ */ + + if (rc < 0) + rc = sysconf(_SC_NPROCESSORS_ONLN); + +#ifdef __linux__ + { + double rc_with_cgroup; + uv__cpu_constraint c = {0, 0, 0.0}; + + if (uv__get_constrained_cpu(&c) == 0 && c.period_length > 0) { + rc_with_cgroup = (double)c.quota_per_period / c.period_length * c.proportions; + if (rc_with_cgroup < rc) + rc = (long)rc_with_cgroup; /* Casting is safe since rc_with_cgroup < rc < LONG_MAX */ + } + } +#endif /* __linux__ */ - rc = sysconf(_SC_NPROCESSORS_ONLN); if (rc < 1) rc = 1; return (unsigned) rc; -#endif /* __linux__ */ } int uv__sock_reuseport(int fd) { From cc2e0aa3cf5c181fab1c0f1b678a0e85b5841a94 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 24 Sep 2024 21:31:51 +0200 Subject: [PATCH 604/713] doc: add known issue in armv7 (#4541) Refs: https://github.com/libuv/libuv/issues/4532 --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 12c3061a894..8afda75cb89 100644 --- a/README.md +++ b/README.md @@ -343,6 +343,10 @@ after the process terminates unless the event loop is closed. Use the `ipcrm` command to manually clear up System V resources. +## Known Issues + +- A possible arm-linux-gnueabihf-gcc bug causing, sometimes, incorrect generated code on `armv7` when calling `preadv()`: https://github.com/libuv/libuv/issues/4532. + ## Patches See the [guidelines for contributing][]. From d2e56a5e8d3e39947b78405ca6e4727c70f5568a Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 25 Sep 2024 10:17:20 +0200 Subject: [PATCH 605/713] 2024.09.25, Version 1.49.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.48.0: * test: fix -Wpointer-to-int-cast on 32 bits systems (Ben Noordhuis) * build: add alias for libuv to CMakeLists.txt (Anthony Alayo) * linux: create io_uring sqpoll ring lazily (Ben Noordhuis) * misc: run sample CI when code changes (Jameson Nash) * linux: fix uv_available_parallelism using cgroup (Thomas Walter) * doc: fix tty example segfault (hiiizxf) * udp,unix: fix sendmsg use-after-free (Geddy) * cygwin: implement uv_resident_set_memory (Farzin Monsef) * win: almost fix race detecting ESRCH in uv_kill (Santiago Gimeno) * test: disable env var test under win32+asan (Ben Noordhuis) * unix,fs: fix realpath calls that use the system allocator (Saúl Ibarra Corretgé) * sunos: sync tcp keep-alive with other unices (Andy Pan) * linux: fix /proc/self/stat executable name parsing (Farzin Monsef) * test,ci: fix [AM]San, disable ASLR (Ben Noordhuis) * win: remove _alloca usage (Ben Noordhuis) * unix: reinstate preadv/pwritev fallback code (Ben Noordhuis) * linux: don't delay EPOLL_CTL_DEL operations (Ben Noordhuis) * doc: fix typos in ChangeLog (tgolang) * unix,win: error on zero delay tcp keepalive (Saúl Ibarra Corretgé) * win: simplify uv_once implementation (Saúl Ibarra Corretgé) * doc: correct udp socket options documentation (Ben Noordhuis) * linux: don't use sendmmsg() for single datagrams (Ben Noordhuis) * unix: fix fd leaks in SCM_RIGHTS error path (Ben Noordhuis) * win: robustify uv_os_getenv() error checking (Ben Noordhuis) * test: use newer ASSERT_MEM_EQ macro (Ben Noordhuis) * unix: de-duplicate conditions for using kqueue (Brad King) * darwin: simplify uv_hrtime (Saúl Ibarra Corretgé) * mailmap: update saghul's main email address (Saúl Ibarra Corretgé) * win: remove no longer needed define (Saúl Ibarra Corretgé) * doc: fix some typos (josedelinux) * linux,darwin: make `uv_fs_copyfile` behaves like `cp -r` (Juan José Arboleda) * dragonfly: disable SO_REUSEPORT for UDP socket bindings (Andy Pan) * test: remove the obsolete HAVE_KQUEUE macro (Andy Pan) * unix: use the presence of SOCK_* instead of OS macros for socketpair (Andy Pan) * bsd: support pipe2() on *BSD (Andy Pan) * unix: support SO_REUSEPORT with load balancing for TCP (Andy Pan) * doc: add entries for extended getpw (Juan José Arboleda) * test: fix the flaky test-tcp-reuseport (Andy Pan) * aix,ibmi: fix compilation errors in fs_copyfile (Jeffrey H. Johnson) * unix: support SO_REUSEPORT with load balancing for UDP (Andy Pan) * tcpkeepalive: distinguish OS versions and use proper time units (Andy Pan) * win: map ERROR_BAD_EXE_FORMAT to UV_EFTYPE (Hüseyin Açacak) * doc: add instruction how to install with Conan (Uilian Ries) * unix,win: remove unused req parameter from macros (Viacheslav Muravyev) * build: fix android ci build (Ben Noordhuis) * unix,win: export wtf8 functions properly (Ben Noordhuis) * hurd: add includes and macro prerequisites (Olivier Valentin) * hurd: stub uv_thread_setpriority() (Olivier Valentin) * ci: use macOS 12 for macOS and iOS builds (Saúl Ibarra Corretgé) * darwin: fix crash on iOS(arm64) (郑苏波 (Super Zheng)) * Create dependabot.yml for updating github-actions (Jameson Nash) * doc: correct names of Win32 APIs in fs.rst (zeertzjq) * ci: bump upload and download-artifact versions (dependabot[bot]) * ci: bump actions/setup-python from 4 to 5 (dependabot[bot]) * ci: bump KyleMayes/install-llvm-action from 1 to 2 (dependabot[bot]) * win,error: remap ERROR_NO_DATA to EAGAIN (Jameson Nash) * test: handle zero-length udp datagram (Ben Noordhuis) * misc: remove splay trees macros (Viacheslav Muravyev) * test,openbsd: remove superfluous ifdef guard (Ben Noordhuis) * win,fs: use posix delete semantics, if supported (Ian Butterworth) * win: fix env var in uv_os_homedir and uv_os_tmpdir (Hüseyin Açacak) * fsevents: detect watched directory removal (Santiago Gimeno) * ci: bump actions/checkout to 4 (dependabot[bot]) * linux: eliminate a read on eventfd per wakeup (Andy Pan) * test: pipe_overlong_path handle ENAMETOOLONG (Abdirahim Musse) * win,fs: use the new Windows fast stat API (Hüseyin Açacak) * win,pipe: fix race with concurrent readers (Jameson Nash) * win,signal: fix data race dispatching SIGWINCH (Jameson Nash) * build: ubsan fixes (Matheus Izvekov) * linux: disable SQPOLL io_uring by default (Santiago Gimeno) * win: fix fs.c ubsan failure (Matheus Izvekov) * test: rmdir can return `EEXIST` or `ENOTEMPTY` (Richard Lau) * test: check for `UV_CHANGE` or `UV_RENAME` event (Richard Lau) * unix,fs: silence -Wunused-result warning (Santiago Gimeno) * linux: support abstract unix socket autobinding (Ben Noordhuis) * kqueue: use EVFILT_USER for async if available (Andy Pan) * win: remove deprecated GetVersionExW call (Shelley Vohr) * doc: document uv_loop_option (握猫猫) * doc: fix the `uv_*_set_data` series of functions (握猫猫) * doc: properly label enumerations and types (握猫猫) * doc: document specific macOS fs_event behavior (Santiago Gimeno) * win,pipe: restore fallback handling for blocking pipes (Jameson Nash) * unix,win: remove unused rb-tree macro parameters (Viacheslav Muravyev) * win: compute parallelism from process cpu affinity (Ben Noordhuis) * win: use NtQueryInformationProcess in uv_os_getppid (Zuohui Yang) * win,pipe: fix missing assignment to success (Jameson Nash) * win: fix uv_available_parallelism on win32 (Ben Noordhuis) * win,pipe: fix another missing assignment to success (Jameson Nash) * kqueue: disallow ill-suited file descriptor kinds (Andy Pan) * unix: restore tty attributes on handle close (Ben Noordhuis) * test: delete test with invalid assumption (Ben Noordhuis) * dragonflybsd: fix compilation failure (Jeffrey H. Johnson) * test: run android tests on ci (Edigleysson Silva (Edy)) * darwin: add udp mmsg support (Raihaan Shouhell) * unix: work around arm-linux-gnueabihf-gcc bug (Ben Noordhuis) * unix: expand uv_available_parallelism() to support more platforms (Ondřej Surý) * doc: add known issue in armv7 (Santiago Gimeno) --- .mailmap | 2 + AUTHORS | 18 ++++ ChangeLog | 202 +++++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 8 +- 5 files changed, 227 insertions(+), 5 deletions(-) diff --git a/.mailmap b/.mailmap index 1386b6f5db8..4870e449b92 100644 --- a/.mailmap +++ b/.mailmap @@ -4,6 +4,7 @@ Aaron Bieber Alan Gutierrez Andrius Bentkus Andy Fiddaman +Andy Pan Bert Belder Bert Belder Bert Belder @@ -37,6 +38,7 @@ Michael Neumann Michael Penick Nicholas Vavilov Nick Logan +Olivier Valentin Rasmus Christian Pedersen Rasmus Christian Pedersen Richard Lau diff --git a/AUTHORS b/AUTHORS index f3942ced3c5..df8ca842c80 100644 --- a/AUTHORS +++ b/AUTHORS @@ -567,3 +567,21 @@ Ardi Nugraha <33378542+ardi-nugraha@users.noreply.github.com> Anton Bachin Trevor Flynn Andy Pan +Viacheslav Muravyev +Anthony Alayo +Thomas Walter <31201229+waltoss@users.noreply.github.com> +hiiizxf <385122613@qq.com> +Geddy +Farzin Monsef +tgolang <154592711+tgolang@users.noreply.github.com> +josedelinux +Hüseyin Açacak <110401522+huseyinacacak-janea@users.noreply.github.com> +Uilian Ries +Olivier Valentin +郑苏波 (Super Zheng) +zeertzjq +Ian Butterworth +握猫猫 <164346864@qq.com> +Zuohui Yang <274048862@qq.com> +Edigleysson Silva (Edy) +Raihaan Shouhell diff --git a/ChangeLog b/ChangeLog index f23fa226d31..c09814978e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,205 @@ +2024.09.25, Version 1.49.0 (Stable) + +Changes since version 1.48.0: + +* test: fix -Wpointer-to-int-cast on 32 bits systems (Ben Noordhuis) + +* build: add alias for libuv to CMakeLists.txt (Anthony Alayo) + +* linux: create io_uring sqpoll ring lazily (Ben Noordhuis) + +* misc: run sample CI when code changes (Jameson Nash) + +* linux: fix uv_available_parallelism using cgroup (Thomas Walter) + +* doc: fix tty example segfault (hiiizxf) + +* udp,unix: fix sendmsg use-after-free (Geddy) + +* cygwin: implement uv_resident_set_memory (Farzin Monsef) + +* win: almost fix race detecting ESRCH in uv_kill (Santiago Gimeno) + +* test: disable env var test under win32+asan (Ben Noordhuis) + +* unix,fs: fix realpath calls that use the system allocator (Saúl Ibarra + Corretgé) + +* sunos: sync tcp keep-alive with other unices (Andy Pan) + +* linux: fix /proc/self/stat executable name parsing (Farzin Monsef) + +* test,ci: fix [AM]San, disable ASLR (Ben Noordhuis) + +* win: remove _alloca usage (Ben Noordhuis) + +* unix: reinstate preadv/pwritev fallback code (Ben Noordhuis) + +* linux: don't delay EPOLL_CTL_DEL operations (Ben Noordhuis) + +* doc: fix typos in ChangeLog (tgolang) + +* unix,win: error on zero delay tcp keepalive (Saúl Ibarra Corretgé) + +* win: simplify uv_once implementation (Saúl Ibarra Corretgé) + +* doc: correct udp socket options documentation (Ben Noordhuis) + +* linux: don't use sendmmsg() for single datagrams (Ben Noordhuis) + +* unix: fix fd leaks in SCM_RIGHTS error path (Ben Noordhuis) + +* win: robustify uv_os_getenv() error checking (Ben Noordhuis) + +* test: use newer ASSERT_MEM_EQ macro (Ben Noordhuis) + +* unix: de-duplicate conditions for using kqueue (Brad King) + +* darwin: simplify uv_hrtime (Saúl Ibarra Corretgé) + +* mailmap: update saghul's main email address (Saúl Ibarra Corretgé) + +* win: remove no longer needed define (Saúl Ibarra Corretgé) + +* doc: fix some typos (josedelinux) + +* linux,darwin: make `uv_fs_copyfile` behaves like `cp -r` (Juan José Arboleda) + +* dragonfly: disable SO_REUSEPORT for UDP socket bindings (Andy Pan) + +* test: remove the obsolete HAVE_KQUEUE macro (Andy Pan) + +* unix: use the presence of SOCK_* instead of OS macros for socketpair (Andy + Pan) + +* bsd: support pipe2() on *BSD (Andy Pan) + +* unix: support SO_REUSEPORT with load balancing for TCP (Andy Pan) + +* doc: add entries for extended getpw (Juan José Arboleda) + +* test: fix the flaky test-tcp-reuseport (Andy Pan) + +* aix,ibmi: fix compilation errors in fs_copyfile (Jeffrey H. Johnson) + +* unix: support SO_REUSEPORT with load balancing for UDP (Andy Pan) + +* tcpkeepalive: distinguish OS versions and use proper time units (Andy Pan) + +* win: map ERROR_BAD_EXE_FORMAT to UV_EFTYPE (Hüseyin Açacak) + +* doc: add instruction how to install with Conan (Uilian Ries) + +* unix,win: remove unused req parameter from macros (Viacheslav Muravyev) + +* build: fix android ci build (Ben Noordhuis) + +* unix,win: export wtf8 functions properly (Ben Noordhuis) + +* hurd: add includes and macro prerequisites (Olivier Valentin) + +* hurd: stub uv_thread_setpriority() (Olivier Valentin) + +* ci: use macOS 12 for macOS and iOS builds (Saúl Ibarra Corretgé) + +* darwin: fix crash on iOS(arm64) (郑苏波 (Super Zheng)) + +* Create dependabot.yml for updating github-actions (Jameson Nash) + +* doc: correct names of Win32 APIs in fs.rst (zeertzjq) + +* ci: bump upload and download-artifact versions (dependabot[bot]) + +* ci: bump actions/setup-python from 4 to 5 (dependabot[bot]) + +* ci: bump KyleMayes/install-llvm-action from 1 to 2 (dependabot[bot]) + +* win,error: remap ERROR_NO_DATA to EAGAIN (Jameson Nash) + +* test: handle zero-length udp datagram (Ben Noordhuis) + +* misc: remove splay trees macros (Viacheslav Muravyev) + +* test,openbsd: remove superfluous ifdef guard (Ben Noordhuis) + +* win,fs: use posix delete semantics, if supported (Ian Butterworth) + +* win: fix env var in uv_os_homedir and uv_os_tmpdir (Hüseyin Açacak) + +* fsevents: detect watched directory removal (Santiago Gimeno) + +* ci: bump actions/checkout to 4 (dependabot[bot]) + +* linux: eliminate a read on eventfd per wakeup (Andy Pan) + +* test: pipe_overlong_path handle ENAMETOOLONG (Abdirahim Musse) + +* win,fs: use the new Windows fast stat API (Hüseyin Açacak) + +* win,pipe: fix race with concurrent readers (Jameson Nash) + +* win,signal: fix data race dispatching SIGWINCH (Jameson Nash) + +* build: ubsan fixes (Matheus Izvekov) + +* linux: disable SQPOLL io_uring by default (Santiago Gimeno) + +* win: fix fs.c ubsan failure (Matheus Izvekov) + +* test: rmdir can return `EEXIST` or `ENOTEMPTY` (Richard Lau) + +* test: check for `UV_CHANGE` or `UV_RENAME` event (Richard Lau) + +* unix,fs: silence -Wunused-result warning (Santiago Gimeno) + +* linux: support abstract unix socket autobinding (Ben Noordhuis) + +* kqueue: use EVFILT_USER for async if available (Andy Pan) + +* win: remove deprecated GetVersionExW call (Shelley Vohr) + +* doc: document uv_loop_option (握猫猫) + +* doc: fix the `uv_*_set_data` series of functions (握猫猫) + +* doc: properly label enumerations and types (握猫猫) + +* doc: document specific macOS fs_event behavior (Santiago Gimeno) + +* win,pipe: restore fallback handling for blocking pipes (Jameson Nash) + +* unix,win: remove unused rb-tree macro parameters (Viacheslav Muravyev) + +* win: compute parallelism from process cpu affinity (Ben Noordhuis) + +* win: use NtQueryInformationProcess in uv_os_getppid (Zuohui Yang) + +* win,pipe: fix missing assignment to success (Jameson Nash) + +* win: fix uv_available_parallelism on win32 (Ben Noordhuis) + +* win,pipe: fix another missing assignment to success (Jameson Nash) + +* kqueue: disallow ill-suited file descriptor kinds (Andy Pan) + +* unix: restore tty attributes on handle close (Ben Noordhuis) + +* test: delete test with invalid assumption (Ben Noordhuis) + +* dragonflybsd: fix compilation failure (Jeffrey H. Johnson) + +* test: run android tests on ci (Edigleysson Silva (Edy)) + +* darwin: add udp mmsg support (Raihaan Shouhell) + +* unix: work around arm-linux-gnueabihf-gcc bug (Ben Noordhuis) + +* unix: expand uv_available_parallelism() to support more platforms (Ondřej + Surý) + +* doc: add known issue in armv7 (Santiago Gimeno) + + 2024.02.07, Version 1.48.0 (Stable), e9f29cb984231524e3931aa0ae2c5dae1a32884e Changes since version 1.47.0: diff --git a/configure.ac b/configure.ac index 7b67b480597..b7981d61949 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.48.1-dev], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.49.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 8fec6b39b3a..43db019867e 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 48 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 49 +#define UV_VERSION_PATCH 0 +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 511e202e13ad26fd5aa3e0e1ba6bb60148ae646f Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 25 Sep 2024 10:17:21 +0200 Subject: [PATCH 606/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index c09814978e8..16276838955 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2024.09.25, Version 1.49.0 (Stable) +2024.09.25, Version 1.49.0 (Stable), d2e56a5e8d3e39947b78405ca6e4727c70f5568a Changes since version 1.48.0: From 5467ec969aea6bb9a56da7c903dcb152e7b85ee6 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 25 Sep 2024 10:37:04 +0200 Subject: [PATCH 607/713] Now working on version 1.49.1 --- configure.ac | 2 +- include/uv/version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index b7981d61949..d4ce099e215 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.49.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.49.1-dev], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 43db019867e..7d7b9ecff10 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 49 -#define UV_VERSION_PATCH 0 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 1 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 675a5a53960a3535b7061acd2fd9aa96aadd1b1b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 26 Sep 2024 09:45:36 +0200 Subject: [PATCH 608/713] build: add darwin-syscalls.h to release tarball (#4546) Overlooked in commit 1c778bd0 ("darwin: add udp mmsg support") from earlier this month. Fixes: https://github.com/libuv/libuv/issues/4544 --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 9379b671739..f85a41316c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -430,6 +430,7 @@ libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1 libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/darwin-proctitle.c \ src/unix/darwin-stub.h \ + src/unix/darwin-syscalls.h \ src/unix/darwin.c \ src/unix/fsevents.c \ src/unix/kqueue.c \ From bcc6d1c1fce27de9d6d34cc21d37f7c3e5b9d40d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 30 Sep 2024 19:44:27 +0200 Subject: [PATCH 609/713] linux: use IORING_SETUP_NO_SQARRAY when available (#4553) Introduced in Linux 6.6, it tells the kernel to omit the sqarray from the ring buffer. Libuv initalizes the array once to an identity mapping and then forgets about it, so not only does it save a little memory (ca. 1 KiB per ring) but it also makes things more efficient kernel-side because it removes a level of indirection. --- src/unix/linux.c | 19 +++++++++++++++---- src/uv-common.h | 1 - 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index a5f74e89016..2f726294b97 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -126,6 +126,7 @@ enum { UV__IORING_SETUP_SQPOLL = 2u, + UV__IORING_SETUP_NO_SQARRAY = 0x10000u, }; enum { @@ -509,10 +510,13 @@ static void uv__iou_init(int epollfd, size_t sqlen; size_t maxlen; size_t sqelen; + unsigned kernel_version; + uint32_t* sqarray; uint32_t i; char* sq; char* sqe; int ringfd; + int no_sqarray; sq = MAP_FAILED; sqe = MAP_FAILED; @@ -520,11 +524,15 @@ static void uv__iou_init(int epollfd, if (!uv__use_io_uring()) return; + kernel_version = uv__kernel_version(); + no_sqarray = + UV__IORING_SETUP_NO_SQARRAY * (kernel_version >= /* 6.6 */0x060600); + /* SQPOLL required CAP_SYS_NICE until linux v5.12 relaxed that requirement. * Mostly academic because we check for a v5.13 kernel afterwards anyway. */ memset(¶ms, 0, sizeof(params)); - params.flags = flags; + params.flags = flags | no_sqarray; if (flags & UV__IORING_SETUP_SQPOLL) params.sq_thread_idle = 10; /* milliseconds */ @@ -586,7 +594,6 @@ static void uv__iou_init(int epollfd, iou->sqhead = (uint32_t*) (sq + params.sq_off.head); iou->sqtail = (uint32_t*) (sq + params.sq_off.tail); iou->sqmask = *(uint32_t*) (sq + params.sq_off.ring_mask); - iou->sqarray = (uint32_t*) (sq + params.sq_off.array); iou->sqflags = (uint32_t*) (sq + params.sq_off.flags); iou->cqhead = (uint32_t*) (sq + params.cq_off.head); iou->cqtail = (uint32_t*) (sq + params.cq_off.tail); @@ -602,11 +609,15 @@ static void uv__iou_init(int epollfd, iou->in_flight = 0; iou->flags = 0; - if (uv__kernel_version() >= /* 5.15.0 */ 0x050F00) + if (kernel_version >= /* 5.15.0 */ 0x050F00) iou->flags |= UV__MKDIRAT_SYMLINKAT_LINKAT; + if (no_sqarray) + return; + + sqarray = (uint32_t*) (sq + params.sq_off.array); for (i = 0; i <= iou->sqmask; i++) - iou->sqarray[i] = i; /* Slot -> sqe identity mapping. */ + sqarray[i] = i; /* Slot -> sqe identity mapping. */ return; diff --git a/src/uv-common.h b/src/uv-common.h index 339e5f37323..60bd00875b8 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -400,7 +400,6 @@ void uv__metrics_set_provider_entry_time(uv_loop_t* loop); struct uv__iou { uint32_t* sqhead; uint32_t* sqtail; - uint32_t* sqarray; uint32_t sqmask; uint32_t* sqflags; uint32_t* cqhead; From f806be87d3276fc9f672dbf43753a3c44dc26228 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 30 Sep 2024 21:55:34 +0200 Subject: [PATCH 610/713] linux: use IORING_OP_FTRUNCATE when available (#4554) Route ftruncate() system calls through io_uring instead of the thread pool when the kernel is new enough to support it (linux >= 6.9). This commit harmonizes how libuv checks if the kernel is new enough. Some ops were checking against `uv__kernel_version()` directly while others stored the result of the version check as a feature flag. Because the kernel version is cached, and because it is more direct than a feature flag, I opted for the former approach. --- src/unix/fs.c | 3 +++ src/unix/internal.h | 2 ++ src/unix/linux.c | 44 +++++++++++++++++++++++++++----------------- src/uv-common.h | 1 - 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 6d810debf5d..d555491af86 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1910,6 +1910,9 @@ int uv_fs_ftruncate(uv_loop_t* loop, INIT(FTRUNCATE); req->file = file; req->off = off; + if (cb != NULL) + if (uv__iou_fs_ftruncate(loop, req)) + return 0; POST; } diff --git a/src/unix/internal.h b/src/unix/internal.h index 529c783e6e9..138685c99b0 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -344,6 +344,7 @@ int uv__random_sysctl(void* buf, size_t buflen); /* io_uring */ #ifdef __linux__ int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req); +int uv__iou_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req); int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop, uv_fs_t* req, uint32_t fsync_flags); @@ -362,6 +363,7 @@ int uv__iou_fs_symlink(uv_loop_t* loop, uv_fs_t* req); int uv__iou_fs_unlink(uv_loop_t* loop, uv_fs_t* req); #else #define uv__iou_fs_close(loop, req) 0 +#define uv__iou_fs_ftruncate(loop, req) 0 #define uv__iou_fs_fsync_or_fdatasync(loop, req, fsync_flags) 0 #define uv__iou_fs_link(loop, req) 0 #define uv__iou_fs_mkdir(loop, req) 0 diff --git a/src/unix/linux.c b/src/unix/linux.c index 2f726294b97..803a9a9d3f0 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -148,6 +148,7 @@ enum { UV__IORING_OP_MKDIRAT = 37, UV__IORING_OP_SYMLINKAT = 38, UV__IORING_OP_LINKAT = 39, + UV__IORING_OP_FTRUNCATE = 55, }; enum { @@ -160,10 +161,6 @@ enum { UV__IORING_SQ_CQ_OVERFLOW = 2u, }; -enum { - UV__MKDIRAT_SYMLINKAT_LINKAT = 1u, -}; - struct uv__io_cqring_offsets { uint32_t head; uint32_t tail; @@ -607,10 +604,6 @@ static void uv__iou_init(int epollfd, iou->sqelen = sqelen; iou->ringfd = ringfd; iou->in_flight = 0; - iou->flags = 0; - - if (kernel_version >= /* 5.15.0 */ 0x050F00) - iou->flags |= UV__MKDIRAT_SYMLINKAT_LINKAT; if (no_sqarray) return; @@ -871,6 +864,26 @@ int uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req) { } +int uv__iou_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req) { + struct uv__io_uring_sqe* sqe; + struct uv__iou* iou; + + if (uv__kernel_version() < /* 6.9 */0x060900) + return 0; + + iou = &uv__get_internal_fields(loop)->iou; + sqe = uv__iou_get_sqe(iou, loop, req); + if (sqe == NULL) + return 0; + + sqe->fd = req->file; + sqe->len = req->off; + sqe->opcode = UV__IORING_OP_FTRUNCATE; + uv__iou_submit(iou); + + return 1; +} + int uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop, uv_fs_t* req, uint32_t fsync_flags) { @@ -900,11 +913,10 @@ int uv__iou_fs_link(uv_loop_t* loop, uv_fs_t* req) { struct uv__io_uring_sqe* sqe; struct uv__iou* iou; - iou = &uv__get_internal_fields(loop)->iou; - - if (!(iou->flags & UV__MKDIRAT_SYMLINKAT_LINKAT)) + if (uv__kernel_version() < /* 5.15.0 */0x050F00) return 0; + iou = &uv__get_internal_fields(loop)->iou; sqe = uv__iou_get_sqe(iou, loop, req); if (sqe == NULL) return 0; @@ -925,11 +937,10 @@ int uv__iou_fs_mkdir(uv_loop_t* loop, uv_fs_t* req) { struct uv__io_uring_sqe* sqe; struct uv__iou* iou; - iou = &uv__get_internal_fields(loop)->iou; - - if (!(iou->flags & UV__MKDIRAT_SYMLINKAT_LINKAT)) + if (uv__kernel_version() < /* 5.15.0 */0x050F00) return 0; + iou = &uv__get_internal_fields(loop)->iou; sqe = uv__iou_get_sqe(iou, loop, req); if (sqe == NULL) return 0; @@ -993,11 +1004,10 @@ int uv__iou_fs_symlink(uv_loop_t* loop, uv_fs_t* req) { struct uv__io_uring_sqe* sqe; struct uv__iou* iou; - iou = &uv__get_internal_fields(loop)->iou; - - if (!(iou->flags & UV__MKDIRAT_SYMLINKAT_LINKAT)) + if (uv__kernel_version() < /* 5.15.0 */0x050F00) return 0; + iou = &uv__get_internal_fields(loop)->iou; sqe = uv__iou_get_sqe(iou, loop, req); if (sqe == NULL) return 0; diff --git a/src/uv-common.h b/src/uv-common.h index 60bd00875b8..4baede2e506 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -414,7 +414,6 @@ struct uv__iou { size_t sqelen; int ringfd; uint32_t in_flight; - uint32_t flags; }; #endif /* __linux__ */ From 65e3735320495663f022b03bffbdb2776fceb342 Mon Sep 17 00:00:00 2001 From: Rialbat Date: Wed, 2 Oct 2024 11:12:11 +0300 Subject: [PATCH 611/713] win: fix pNtQueryDirectoryFile check Fixed incorrect verification of the pNtQueryDirectoryFile pointer. --- src/win/winapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/winapi.c b/src/win/winapi.c index 4add0e27372..a74108db03e 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -103,7 +103,7 @@ void uv__winapi_init(void) { pNtQueryDirectoryFile = (sNtQueryDirectoryFile) GetProcAddress(ntdll_module, "NtQueryDirectoryFile"); - if (pNtQueryVolumeInformationFile == NULL) { + if (pNtQueryDirectoryFile == NULL) { uv_fatal_error(GetLastError(), "GetProcAddress"); } From 473dafc59354a5284f49efd63d2cdb22f9e989da Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Thu, 3 Oct 2024 18:53:39 +0200 Subject: [PATCH 612/713] win: fix WriteFile() error translation (#4562) Translate `ERROR_BROKEN_PIPE` and `ERROR_NO_DATA` to `UV_EPIPE` instead of their default translation, which will be used for the rest of cases. Refs: https://github.com/libuv/libuv/issues/4548#issuecomment-2383998849 --- src/win/error.c | 9 +++++++++ src/win/fs.c | 2 +- src/win/internal.h | 2 ++ src/win/stream.c | 4 ++-- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/win/error.c b/src/win/error.c index 5cc264fea86..58587c5fb78 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -172,3 +172,12 @@ int uv_translate_sys_error(int sys_errno) { default: return UV_UNKNOWN; } } + +int uv_translate_write_sys_error(int sys_errno) { + switch (sys_errno) { + case ERROR_BROKEN_PIPE: return UV_EPIPE; + case ERROR_NO_DATA: return UV_EPIPE; + default: + return uv_translate_sys_error(sys_errno); + } +} diff --git a/src/win/fs.c b/src/win/fs.c index d87246e0ff3..fadefb51101 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1078,7 +1078,7 @@ void fs__write(uv_fs_t* req) { error = ERROR_INVALID_FLAGS; } - SET_REQ_WIN32_ERROR(req, error); + SET_REQ_UV_ERROR(req, uv_translate_write_sys_error(error), error); } } diff --git a/src/win/internal.h b/src/win/internal.h index 867dea5e0ed..be408af6661 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -330,4 +330,6 @@ void uv__wake_all_loops(void); */ void uv__init_detect_system_wakeup(void); +int uv_translate_write_sys_error(int sys_errno); + #endif /* UV_WIN_INTERNAL_H_ */ diff --git a/src/win/stream.c b/src/win/stream.c index 61a82fe4e6e..a53a10b0382 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -131,7 +131,7 @@ int uv_write(uv_write_t* req, case UV_NAMED_PIPE: err = uv__pipe_write( loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb); - break; + return uv_translate_write_sys_error(err); case UV_TTY: err = uv__tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb); break; @@ -164,7 +164,7 @@ int uv_write2(uv_write_t* req, err = uv__pipe_write( loop, req, (uv_pipe_t*) handle, bufs, nbufs, send_handle, cb); - return uv_translate_sys_error(err); + return uv_translate_write_sys_error(err); } From 88b874e63cc19a37155e9d34396828520a30dacd Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Thu, 3 Oct 2024 21:29:10 +0200 Subject: [PATCH 613/713] win,fs: uv_fs_rmdir() to return ENOENT on file (#4563) After commit 18266a6969, it changed to return `ENOTDIR`, which makes it consistent with other platforms but it also can be considered a breaking change. --- src/win/fs.c | 5 +++-- test/test-fs.c | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index fadefb51101..42f006a370c 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1113,8 +1113,9 @@ static void fs__unlink_rmdir(uv_fs_t* req, BOOL isrmdir) { } if (isrmdir && !(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - /* Error if we're in rmdir mode but it is not a dir */ - SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY); + /* Error if we're in rmdir mode but it is not a dir. + * TODO: change it to UV_NOTDIR in v2. */ + SET_REQ_UV_ERROR(req, UV_ENOENT, ERROR_DIRECTORY); CloseHandle(handle); return; } diff --git a/test/test-fs.c b/test/test-fs.c index 3720b64d021..ff0f9fc89a2 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1088,6 +1088,11 @@ TEST_IMPL(fs_posix_delete) { ASSERT_EQ(r, rmdir_req.result); uv_fs_req_cleanup(&rmdir_req); + r = uv_fs_rmdir(NULL, &rmdir_req, "test_dir/file", NULL); + ASSERT((r == UV_ENOTDIR) || (r == UV_ENOENT)); + ASSERT_EQ(r, rmdir_req.result); + uv_fs_req_cleanup(&rmdir_req); + r = uv_fs_unlink(NULL, &unlink_req, "test_dir/file", NULL); ASSERT_OK(r); ASSERT_OK(unlink_req.result); From f55efb2f386b06ae60379ac17cc9641561fea55a Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 3 Oct 2024 16:12:22 -0400 Subject: [PATCH 614/713] win,pipe: ipc code does not support async read (#4555) The implementation of IPC pipe in libuv on Windows does not properly support async reading. This means we cannot set the more parameter without likely causing hangs. Sorry this is yet another followup to #4511. Fixes #4548 --- src/win/pipe.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index 76ea169e19f..d46ecb9fc70 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -2094,17 +2094,13 @@ static int uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) { /* Store the pending socket info. */ uv__pipe_queue_ipc_xfer_info(handle, xfer_type, &xfer_info); } - - more = 1; } /* Return whether the caller should immediately try another read call to get - * more data. */ - if (more && *data_remaining == 0) { - /* TODO: use PeekNamedPipe to see if it is really worth trying to do - * another ReadFile call. */ - } - + * more data. Calling uv__pipe_read_exactly will hang if there isn't data + * available, so we cannot do this unless we are guaranteed not to reach that. + */ + more = *data_remaining > 0; return more; invalid: From 670e75ee7eecd7ce424aef8561b02f685decbd44 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 4 Oct 2024 09:26:07 +0200 Subject: [PATCH 615/713] netbsd: fix build --- src/unix/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 1935ba87381..071716c33a1 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1882,13 +1882,13 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) { #if defined(__linux__) || defined (__FreeBSD__) # define uv__cpu_count(cpuset) CPU_COUNT(cpuset) #elif defined(__NetBSD__) -static int uv__cpu_count(cpuset_t *cpuset) { +static int uv__cpu_count(cpuset_t* set) { int rc; cpuid_t i; rc = 0; for (i = 0;; i++) { - int r = cpuset_isset(cpu, set); + int r = cpuset_isset(i, set); if (r < 0) break; if (r) From 1cbffcbd5d097c31cdfa715f2a78fde93651d80c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= Date: Thu, 3 Oct 2024 11:28:39 +0300 Subject: [PATCH 616/713] win,fs: fix bug in fs__readdir --- src/win/fs.c | 8 ++-- test/test-fs-readdir.c | 86 ++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 6 +++ 3 files changed, 96 insertions(+), 4 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 42f006a370c..08b42eb14c9 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1651,12 +1651,12 @@ void fs__readdir(uv_fs_t* req) { goto error; /* Copy file type. */ - if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) - dent.d_type = UV__DT_DIR; + if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) != 0) + dent.d_type = UV__DT_CHAR; else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) dent.d_type = UV__DT_LINK; - else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) != 0) - dent.d_type = UV__DT_CHAR; + else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) + dent.d_type = UV__DT_DIR; else dent.d_type = UV__DT_FILE; diff --git a/test/test-fs-readdir.c b/test/test-fs-readdir.c index 0f2b4afa58c..bacea653587 100644 --- a/test/test-fs-readdir.c +++ b/test/test-fs-readdir.c @@ -29,6 +29,7 @@ static uv_fs_t readdir_req; static uv_fs_t closedir_req; static uv_dirent_t dirents[1]; +static uv_dirent_t symlink_dirents[2]; static int empty_opendir_cb_count; static int empty_closedir_cb_count; @@ -460,3 +461,88 @@ TEST_IMPL(fs_readdir_non_empty_dir) { MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } + +static void readdir_symlink_readdir_cb(uv_fs_t* req) { + uv_dir_t* dir; + + ASSERT_PTR_EQ(req, &readdir_req); + ASSERT_EQ(req->fs_type, UV_FS_READDIR); + dir = req->ptr; + + if (req->result == 0) { + uv_fs_req_cleanup(req); + ASSERT_EQ(3, non_empty_readdir_cb_count); + uv_fs_closedir(uv_default_loop(), + &closedir_req, + dir, + non_empty_closedir_cb); + } else { + if (strcmp(symlink_dirents[0].name, "test_symlink") == 0) { + ASSERT_EQ(symlink_dirents[0].type, UV_DIRENT_LINK); + } else { + ASSERT_EQ(symlink_dirents[1].type, UV_DIRENT_LINK); + } + uv_fs_req_cleanup(req); + } +} + +static void readdir_symlink_opendir_cb(uv_fs_t* req) { + uv_dir_t* dir; + int r; + + ASSERT_PTR_EQ(req, &opendir_req); + ASSERT_EQ(req->fs_type, UV_FS_OPENDIR); + ASSERT_OK(req->result); + ASSERT_NOT_NULL(req->ptr); + + dir = req->ptr; + dir->dirents = symlink_dirents; + dir->nentries = ARRAY_SIZE(symlink_dirents); + + r = uv_fs_readdir(uv_default_loop(), + &readdir_req, + dir, + readdir_symlink_readdir_cb); + ASSERT_OK(r); + uv_fs_req_cleanup(req); +} + +static void cleanup_symlink_test_files(void) { + uv_fs_t req; + + uv_fs_rmdir(NULL, &req, "test_symlink_dir/test_subdir", NULL); + uv_fs_req_cleanup(&req); + uv_fs_unlink(NULL, &req, "test_symlink_dir/test_symlink", NULL); + uv_fs_req_cleanup(&req); + uv_fs_rmdir(NULL, &req, "test_symlink_dir", NULL); + uv_fs_req_cleanup(&req); +} + +TEST_IMPL(fs_readdir_symlink) { + + uv_fs_t mkdir_req; + uv_fs_t symlink_req; + int r; + + cleanup_symlink_test_files(); + + r = uv_fs_mkdir(uv_default_loop(), &mkdir_req, "test_symlink_dir", 0755, NULL); + ASSERT_OK(r); + + r = uv_fs_mkdir(uv_default_loop(), &mkdir_req, "test_symlink_dir/test_subdir", 0755, NULL); + ASSERT_OK(r); + + r = uv_fs_symlink(uv_default_loop(), &symlink_req, "test_symlink_dir/test_subdir", "test_symlink_dir/test_symlink", UV_FS_SYMLINK_DIR, NULL); + ASSERT_OK(r); + + r = uv_fs_opendir(uv_default_loop(), &opendir_req, "test_symlink_dir", readdir_symlink_opendir_cb); + ASSERT_OK(r); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT_OK(r); + + cleanup_symlink_test_files(); + + MAKE_VALGRIND_HAPPY(uv_default_loop()); + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 22a9a51d95f..e07bd61ecf7 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -428,6 +428,9 @@ TEST_DECLARE (fs_readdir_empty_dir) TEST_DECLARE (fs_readdir_file) TEST_DECLARE (fs_readdir_non_empty_dir) TEST_DECLARE (fs_readdir_non_existing_dir) +#ifdef _WIN32 +TEST_DECLARE (fs_readdir_symlink) +#endif TEST_DECLARE (fs_rename_to_existing_file) TEST_DECLARE (fs_write_multiple_bufs) TEST_DECLARE (fs_read_write_null_arguments) @@ -1138,6 +1141,9 @@ TASK_LIST_START TEST_ENTRY (fs_readdir_file) TEST_ENTRY (fs_readdir_non_empty_dir) TEST_ENTRY (fs_readdir_non_existing_dir) +#ifdef _WIN32 + TEST_ENTRY (fs_readdir_symlink) +#endif TEST_ENTRY (fs_rename_to_existing_file) TEST_ENTRY (fs_write_multiple_bufs) TEST_ENTRY (fs_write_alotof_bufs) From 0be52c825176152ebe60ccd9f099b7722322c700 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 7 Oct 2024 08:47:16 +0200 Subject: [PATCH 617/713] unix: workaround gcc bug on armv7 (#4564) Disable optimization on `uv__preadv_or_pwritev`. Fixes: https://github.com/libuv/libuv/issues/4532 Fixes: https://github.com/libuv/libuv/issues/4550 --- README.md | 4 ---- src/unix/fs.c | 10 ++++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8afda75cb89..12c3061a894 100644 --- a/README.md +++ b/README.md @@ -343,10 +343,6 @@ after the process terminates unless the event loop is closed. Use the `ipcrm` command to manually clear up System V resources. -## Known Issues - -- A possible arm-linux-gnueabihf-gcc bug causing, sometimes, incorrect generated code on `armv7` when calling `preadv()`: https://github.com/libuv/libuv/issues/4532. - ## Patches See the [guidelines for contributing][]. diff --git a/src/unix/fs.c b/src/unix/fs.c index d555491af86..263d4bbc39d 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -461,7 +461,12 @@ static ssize_t uv__pwritev_emul(int fd, /* The function pointer cache is an uintptr_t because _Atomic void* * doesn't work on macos/ios/etc... + * Disable optimization on armv7 to work around the bug described in + * https://github.com/libuv/libuv/issues/4532 */ +#if defined(__arm__) && (__ARM_ARCH == 7) +__attribute__((optimize("O0"))) +#endif static ssize_t uv__preadv_or_pwritev(int fd, const struct iovec* bufs, size_t nbufs, @@ -482,10 +487,7 @@ static ssize_t uv__preadv_or_pwritev(int fd, atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed); } - /* Use memcpy instead of `f = p` to work around a compiler bug, - * see https://github.com/libuv/libuv/issues/4532 - */ - memcpy(&f, &p, sizeof(p)); + f = p; return f(fd, bufs, nbufs, off); } From 8d957c56b33241b8e93c27d7a698d8079b402285 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 19 Sep 2024 19:53:19 +0200 Subject: [PATCH 618/713] unix: work around arm-linux-gnueabihf-gcc bug (#4565) Both gcc 11 and 12 emit wrong code for a function call pointer in one very specific context. Fixes: https://github.com/libuv/libuv/issues/4532 --- src/unix/fs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 263d4bbc39d..239ecda16a7 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -487,7 +487,10 @@ static ssize_t uv__preadv_or_pwritev(int fd, atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed); } - f = p; + /* Use memcpy instead of `f = p` to work around a compiler bug, + * see https://github.com/libuv/libuv/issues/4532 + */ + memcpy(&f, &p, sizeof(p)); return f(fd, bufs, nbufs, off); } From 1f36b01ed04354f5eb923f504411c5da364da968 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 9 Oct 2024 09:52:00 +0200 Subject: [PATCH 619/713] unix: fix uv_tcp_keepalive in smartOS (#4570) Make sure `UV__SOLARIS_11_4` is not set for `smartOS`/`illumOS`. In our codebase is used only twice: - Detect correct implementation of `SO_REUSEPORT`, which is not even implemented on `illumOS`. - Detect the time unit used for the TCP keepalive options. If set to `0`, which was the case for `illumOS`, it chose milliseconds, which is not correct for `illumOS` either as it uses seconds. --- src/unix/internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/internal.h b/src/unix/internal.h index 138685c99b0..568a55b55ac 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -496,7 +496,7 @@ typedef struct { int uv__get_constrained_cpu(uv__cpu_constraint* constraint); #endif -#ifdef __sun +#if defined(__sun) && !defined(__illumos__) #ifdef SO_FLOW_NAME /* Since it's impossible to detect the Solaris 11.4 version via OS macros, * so we check the presence of the socket option SO_FLOW_NAME that was first From 7c3abfbf1e2a4bf3ee7f2e386e3e92e76d533659 Mon Sep 17 00:00:00 2001 From: Poul T Lomholt Date: Thu, 10 Oct 2024 08:04:11 -0700 Subject: [PATCH 620/713] unix: fix uv_getrusage ru_maxrss on solaris (#4572) --- src/unix/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/core.c b/src/unix/core.c index 071716c33a1..0c52ccf2ad7 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1034,7 +1034,7 @@ int uv_getrusage(uv_rusage_t* rusage) { #if defined(__APPLE__) rusage->ru_maxrss /= 1024; /* macOS and iOS report bytes. */ #elif defined(__sun) - rusage->ru_maxrss /= getpagesize() / 1024; /* Solaris reports pages. */ + rusage->ru_maxrss *= getpagesize() / 1024; /* Solaris reports pages. */ #endif return 0; From 8be336f4ee296d20e1c071a44d6adf279e202236 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 11 Oct 2024 09:13:10 +0200 Subject: [PATCH 621/713] 2024.10.11, Version 1.49.1 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.49.0: * build: add darwin-syscalls.h to release tarball (Ben Noordhuis) * linux: use IORING_SETUP_NO_SQARRAY when available (Ben Noordhuis) * linux: use IORING_OP_FTRUNCATE when available (Ben Noordhuis) * win: fix pNtQueryDirectoryFile check (Rialbat) * win: fix WriteFile() error translation (Santiago Gimeno) * win,fs: uv_fs_rmdir() to return ENOENT on file (Santiago Gimeno) * win,pipe: ipc code does not support async read (Jameson Nash) * netbsd: fix build (Adam) * win,fs: fix bug in fs__readdir (Hüseyin Açacak) * unix: workaround gcc bug on armv7 (Santiago Gimeno) * unix: work around arm-linux-gnueabihf-gcc bug (Ben Noordhuis) * unix: fix uv_tcp_keepalive in smartOS (Santiago Gimeno) * unix: fix uv_getrusage ru_maxrss on solaris (Poul T Lomholt) --- .mailmap | 1 + AUTHORS | 3 +++ ChangeLog | 31 +++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 4 ++-- 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/.mailmap b/.mailmap index 4870e449b92..97f5d1f2c00 100644 --- a/.mailmap +++ b/.mailmap @@ -19,6 +19,7 @@ David Carlier Devchandra Meetei Leishangthem Fedor Indutny Frank Denis +Hüseyin Açacak <110401522+huseyinacacak-janea@users.noreply.github.com> Imran Iqbal Isaac Z. Schlueter Jason Williams diff --git a/AUTHORS b/AUTHORS index df8ca842c80..807440b30e8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -585,3 +585,6 @@ Ian Butterworth Zuohui Yang <274048862@qq.com> Edigleysson Silva (Edy) Raihaan Shouhell +Rialbat +Adam +Poul T Lomholt diff --git a/ChangeLog b/ChangeLog index 16276838955..e1d1aa32989 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +2024.10.11, Version 1.49.1 (Stable) + +Changes since version 1.49.0: + +* build: add darwin-syscalls.h to release tarball (Ben Noordhuis) + +* linux: use IORING_SETUP_NO_SQARRAY when available (Ben Noordhuis) + +* linux: use IORING_OP_FTRUNCATE when available (Ben Noordhuis) + +* win: fix pNtQueryDirectoryFile check (Rialbat) + +* win: fix WriteFile() error translation (Santiago Gimeno) + +* win,fs: uv_fs_rmdir() to return ENOENT on file (Santiago Gimeno) + +* win,pipe: ipc code does not support async read (Jameson Nash) + +* netbsd: fix build (Adam) + +* win,fs: fix bug in fs__readdir (Hüseyin Açacak) + +* unix: workaround gcc bug on armv7 (Santiago Gimeno) + +* unix: work around arm-linux-gnueabihf-gcc bug (Ben Noordhuis) + +* unix: fix uv_tcp_keepalive in smartOS (Santiago Gimeno) + +* unix: fix uv_getrusage ru_maxrss on solaris (Poul T Lomholt) + + 2024.09.25, Version 1.49.0 (Stable), d2e56a5e8d3e39947b78405ca6e4727c70f5568a Changes since version 1.48.0: diff --git a/configure.ac b/configure.ac index d4ce099e215..e3ee8a840c6 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.49.1-dev], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.49.1], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 7d7b9ecff10..77a8b254174 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -33,8 +33,8 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 49 #define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From bfbd6db0d6f3662b7203a51239c89c45c8104e08 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 11 Oct 2024 09:13:11 +0200 Subject: [PATCH 622/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index e1d1aa32989..81447147ab4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2024.10.11, Version 1.49.1 (Stable) +2024.10.11, Version 1.49.1 (Stable), 8be336f4ee296d20e1c071a44d6adf279e202236 Changes since version 1.49.0: From be0b00a80db6cb19da80850127c133e40597f5b0 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 11 Oct 2024 09:21:05 +0200 Subject: [PATCH 623/713] Now working on version 1.49.2 --- configure.ac | 2 +- include/uv/version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index e3ee8a840c6..74cd7c926bb 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.49.1], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.49.2-dev], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 77a8b254174..f16c3d73064 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 49 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 2 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From fbe2d85bd5a5c370a8cacea92b3bdfbd9f98a530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= Date: Thu, 10 Oct 2024 09:09:53 +0300 Subject: [PATCH 624/713] win,fs: remove trailing slash in junctions Fixes: https://github.com/libuv/libuv/issues/3329 --- src/win/fs.c | 1 - test/test-fs.c | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 08b42eb14c9..81a7c99d28d 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -2566,7 +2566,6 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path, path_buf[path_buf_len++] = path[i]; } - path_buf[path_buf_len++] = L'\\'; len = path_buf_len - start; /* Set the info about the substitute name */ diff --git a/test/test-fs.c b/test/test-fs.c index ff0f9fc89a2..33cbd428707 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2379,8 +2379,8 @@ int test_symlink_dir_impl(int type) { strcpy(test_dir_abs_buf, "\\\\?\\"); uv_cwd(test_dir_abs_buf + 4, &test_dir_abs_size); test_dir_abs_size += 4; - strcat(test_dir_abs_buf, "\\test_dir\\"); - test_dir_abs_size += strlen("\\test_dir\\"); + strcat(test_dir_abs_buf, "\\test_dir"); + test_dir_abs_size += strlen("\\test_dir"); test_dir = test_dir_abs_buf; #else uv_cwd(test_dir_abs_buf, &test_dir_abs_size); @@ -2435,8 +2435,8 @@ int test_symlink_dir_impl(int type) { r = uv_fs_realpath(NULL, &req, "test_dir_symlink", NULL); ASSERT_OK(r); #ifdef _WIN32 - ASSERT_EQ(strlen(req.ptr), test_dir_abs_size - 5); - ASSERT_OK(_strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5)); + ASSERT_EQ(strlen(req.ptr), test_dir_abs_size - 4); + ASSERT_OK(_strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 4)); #else ASSERT_OK(strcmp(req.ptr, test_dir_abs_buf)); #endif From 18d48bc13ce4a44efb9c37fd81cfdd9db7bc92b8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 17 Oct 2024 20:41:38 +0200 Subject: [PATCH 625/713] Revert "linux: eliminate a read on eventfd per wakeup (#4400)" (#4585) This reverts commit e5cb1d3d3d4ab3178ac567fb6a7f0f4b5eef3083. Reason: bisecting says it breaks dnstap. Also revert commit 27134547ff ("kqueue: use EVFILT_USER for async if available") because otherwise the first commit doesn't revert cleanly, with enough conflicts in src/unix/async.c that I'm not comfortable fixing those up manually. Fixes: https://github.com/libuv/libuv/issues/4584 --- src/unix/async.c | 132 ++++++-------------------------------------- src/unix/internal.h | 22 -------- src/unix/kqueue.c | 11 ---- src/unix/linux.c | 6 -- 4 files changed, 16 insertions(+), 155 deletions(-) diff --git a/src/unix/async.c b/src/unix/async.c index bc97ec54c4f..0ff2669e30a 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -38,34 +38,6 @@ #include #endif -#if UV__KQUEUE_EVFILT_USER -static uv_once_t kqueue_runtime_detection_guard = UV_ONCE_INIT; -static int kqueue_evfilt_user_support = 1; - - -static void uv__kqueue_runtime_detection(void) { - int kq; - struct kevent ev[2]; - struct timespec timeout = {0, 0}; - - /* Perform the runtime detection to ensure that kqueue with - * EVFILT_USER actually works. */ - kq = kqueue(); - EV_SET(ev, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER, - EV_ADD | EV_CLEAR, 0, 0, 0); - EV_SET(ev + 1, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER, - 0, NOTE_TRIGGER, 0, 0); - if (kevent(kq, ev, 2, ev, 1, &timeout) < 1 || - ev[0].filter != EVFILT_USER || - ev[0].ident != UV__KQUEUE_EVFILT_USER_IDENT || - ev[0].flags & EV_ERROR) - /* If we wind up here, we can assume that EVFILT_USER is defined but - * broken on the current system. */ - kqueue_evfilt_user_support = 0; - uv__close(kq); -} -#endif - static void uv__async_send(uv_loop_t* loop); static int uv__async_start(uv_loop_t* loop); static void uv__cpu_relax(void); @@ -158,10 +130,8 @@ void uv__async_close(uv_async_t* handle) { static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { -#ifndef __linux__ char buf[1024]; ssize_t r; -#endif struct uv__queue queue; struct uv__queue* q; uv_async_t* h; @@ -169,12 +139,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(w == &loop->async_io_watcher); -#ifndef __linux__ -#if UV__KQUEUE_EVFILT_USER - for (;!kqueue_evfilt_user_support;) { -#else for (;;) { -#endif r = read(w->fd, buf, sizeof(buf)); if (r == sizeof(buf)) @@ -191,7 +156,6 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { abort(); } -#endif /* !__linux__ */ uv__queue_move(&loop->async_handles, &queue); while (!uv__queue_empty(&queue)) { @@ -215,58 +179,34 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { static void uv__async_send(uv_loop_t* loop) { + const void* buf; + ssize_t len; int fd; - ssize_t r; -#ifdef __linux__ - uint64_t val; - - fd = loop->async_io_watcher.fd; /* eventfd */ - for (val = 1; /* empty */; val = 1) { - r = write(fd, &val, sizeof(uint64_t)); - if (r < 0) { - /* When EAGAIN occurs, the eventfd counter hits the maximum value of the unsigned 64-bit. - * We need to first drain the eventfd and then write again. - * - * Check out https://man7.org/linux/man-pages/man2/eventfd.2.html for details. - */ - if (errno == EAGAIN) { - /* It's ready to retry. */ - if (read(fd, &val, sizeof(uint64_t)) > 0 || errno == EAGAIN) { - continue; - } - } - /* Unknown error occurs. */ - break; - } - return; - } -#else -#if 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; - else - abort(); + int r; + + buf = ""; + len = 1; + fd = loop->async_wfd; + +#if defined(__linux__) + if (fd == -1) { + static const uint64_t val = 1; + buf = &val; + len = sizeof(val); + fd = loop->async_io_watcher.fd; /* eventfd */ } #endif - fd = loop->async_wfd; /* write end of the pipe */ do - r = write(fd, "x", 1); + r = write(fd, buf, len); while (r == -1 && errno == EINTR); - if (r == 1) + if (r == len) return; if (r == -1) if (errno == EAGAIN || errno == EWOULDBLOCK) return; -#endif abort(); } @@ -275,9 +215,6 @@ 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; @@ -289,36 +226,6 @@ 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) @@ -329,13 +236,6 @@ static int uv__async_start(uv_loop_t* loop) { uv__io_start(loop, &loop->async_io_watcher, POLLIN); loop->async_wfd = pipefd[1]; -#if UV__KQUEUE_EVFILT_USER - /* Prevent the EVFILT_USER event from being added to kqueue redundantly - * and mistakenly later in uv__io_poll(). */ - if (kqueue_evfilt_user_support) - loop->async_io_watcher.events = loop->async_io_watcher.pevents; -#endif - return 0; } diff --git a/src/unix/internal.h b/src/unix/internal.h index 568a55b55ac..8d586b0b64a 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -35,10 +35,6 @@ #include #include #include -#if defined(__APPLE__) || defined(__DragonFly__) || \ - defined(__FreeBSD__) || defined(__NetBSD__) -#include -#endif #define uv__msan_unpoison(p, n) \ do { \ @@ -508,22 +504,4 @@ int uv__get_constrained_cpu(uv__cpu_constraint* constraint); #endif #endif -#if defined(EVFILT_USER) && defined(NOTE_TRIGGER) -/* EVFILT_USER is available since OS X 10.6, DragonFlyBSD 4.0, - * FreeBSD 8.1, and NetBSD 10.0. - * - * Note that even though EVFILT_USER is defined on the current system, - * it may still fail to work at runtime somehow. In that case, we fall - * back to pipe-based signaling. - */ -#define UV__KQUEUE_EVFILT_USER 1 -/* Magic number of identifier used for EVFILT_USER during runtime detection. - * There are no Google hits for this number when I create it. That way, - * people will be directed here if this number gets printed due to some - * kqueue error and they google for help. */ -#define UV__KQUEUE_EVFILT_USER_IDENT 0x1e7e7711 -#else -#define UV__KQUEUE_EVFILT_USER 0 -#endif - #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 876b717086c..66aa166f053 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -367,17 +367,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { continue; } -#if UV__KQUEUE_EVFILT_USER - if (ev->filter == EVFILT_USER) { - w = &loop->async_io_watcher; - assert(fd == w->fd); - uv__metrics_update_idle_time(loop); - w->cb(loop, w, w->events); - nevents++; - continue; - } -#endif - if (ev->filter == EVFILT_VNODE) { assert(w->events == POLLIN); assert(w->pevents == POLLIN); diff --git a/src/unix/linux.c b/src/unix/linux.c index 803a9a9d3f0..857a4ef8a66 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1414,12 +1414,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w->events = w->pevents; e.events = w->pevents; - if (w == &loop->async_io_watcher) - /* Enable edge-triggered mode on async_io_watcher(eventfd), - * so that we're able to eliminate the overhead of reading - * the eventfd via system call on each event loop wakeup. - */ - e.events |= EPOLLET; e.data.fd = w->fd; fd = w->fd; From 52a9243317f90cc15ce709a096dd3da134e40c63 Mon Sep 17 00:00:00 2001 From: Thad House Date: Thu, 17 Oct 2024 12:36:07 -0700 Subject: [PATCH 626/713] win: Fix linked list logic in getaddrinfo (#4578) The logic in #4254 is incorrect, and results in the addrinfo linked list only having a single result. Fix this by correcting the logic. Closes #4577 --- src/win/getaddrinfo.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index f20e10d49d9..4b8ee75a062 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -191,8 +191,9 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { if (addrinfow_ptr == NULL) break; cur_off = align_offset(cur_off, sizeof(void *)); - addrinfo_ptr = (struct addrinfo *)(alloc_ptr + cur_off); - addrinfo_ptr->ai_next = addrinfo_ptr; + struct addrinfo *next_addrinfo_ptr = (struct addrinfo *)(alloc_ptr + cur_off); + addrinfo_ptr->ai_next = next_addrinfo_ptr; + addrinfo_ptr = next_addrinfo_ptr; } req->addrinfo = (struct addrinfo*)alloc_ptr; } else { From 9cf0710d71d16e444b5db733a9ec267e8bfbf091 Mon Sep 17 00:00:00 2001 From: Thad House Date: Thu, 17 Oct 2024 12:36:45 -0700 Subject: [PATCH 627/713] win: fix compilation against Windows 24H2 SDK (#4576) Compilation against the 24H2 SDK is broken by #4327. Fix that issue by only conditionally defining the new values. Closes #4575 --- src/win/winapi.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/win/winapi.h b/src/win/winapi.h index 548081f23a9..5800e70dfd7 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4125,6 +4125,12 @@ typedef const UNICODE_STRING *PCUNICODE_STRING; # define DEVICE_TYPE DWORD #endif +#ifndef NTDDI_WIN11_ZN +# define NTDDI_WIN11_ZN 0x0A00000E +#endif + +/* API is defined in newer SDKS */ +#if (NTDDI_VERSION < NTDDI_WIN11_ZN) typedef struct _FILE_STAT_BASIC_INFORMATION { LARGE_INTEGER FileId; LARGE_INTEGER CreationTime; @@ -4142,6 +4148,7 @@ typedef struct _FILE_STAT_BASIC_INFORMATION { FILE_ID_128 FileId128; LARGE_INTEGER VolumeSerialNumber; } FILE_STAT_BASIC_INFORMATION; +#endif /* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does * not. @@ -4783,6 +4790,8 @@ typedef struct _TCP_INITIAL_RTO_PARAMETERS { #endif /* from winnt.h */ +/* API is defined in newer SDKS */ +#if (NTDDI_VERSION < NTDDI_WIN11_ZN) typedef enum _FILE_INFO_BY_NAME_CLASS { FileStatByNameInfo, FileStatLxByNameInfo, @@ -4790,6 +4799,7 @@ typedef enum _FILE_INFO_BY_NAME_CLASS { FileStatBasicByNameInfo, MaximumFileInfoByNameClass } FILE_INFO_BY_NAME_CLASS; +#endif typedef BOOL(WINAPI* sGetFileInformationByName)( PCWSTR FileName, From 7e6590f31d800b8fdd8740f6a2a0e9a04a0a1e56 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 17 Oct 2024 15:37:00 -0400 Subject: [PATCH 628/713] win: remap ERROR_NOACCESS and ERROR_BUFFER_OVERFLOW (#4567) It seemed incorrect to map a segfault to EACCES, since posix would typically map this to EFAULT. The ERROR_BUFFER_OVERFLOW is literally "the filename is too long", and is not typically an invalid parameter in posix. Test originally added in #1060 to test the API, not the value. --- src/win/error.c | 4 ++-- test/test-error.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/win/error.c b/src/win/error.c index 58587c5fb78..7abf906bb5c 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -69,7 +69,6 @@ int uv_translate_sys_error(int sys_errno) { } switch (sys_errno) { - case ERROR_NOACCESS: return UV_EACCES; case WSAEACCES: return UV_EACCES; case ERROR_ELEVATION_REQUIRED: return UV_EACCES; case ERROR_CANT_ACCESS_FILE: return UV_EACCES; @@ -96,7 +95,7 @@ int uv_translate_sys_error(int sys_errno) { case WSAECONNRESET: return UV_ECONNRESET; case ERROR_ALREADY_EXISTS: return UV_EEXIST; case ERROR_FILE_EXISTS: return UV_EEXIST; - case ERROR_BUFFER_OVERFLOW: return UV_EFAULT; + case ERROR_NOACCESS: return UV_EFAULT; case WSAEFAULT: return UV_EFAULT; case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH; case WSAEHOSTUNREACH: return UV_EHOSTUNREACH; @@ -127,6 +126,7 @@ int uv_translate_sys_error(int sys_errno) { case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE; case WSAEMFILE: return UV_EMFILE; case WSAEMSGSIZE: return UV_EMSGSIZE; + case ERROR_BUFFER_OVERFLOW: return UV_ENAMETOOLONG; case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG; case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH; case WSAENETUNREACH: return UV_ENETUNREACH; diff --git a/test/test-error.c b/test/test-error.c index 2c6d0ca4979..b6e18b0f052 100644 --- a/test/test-error.c +++ b/test/test-error.c @@ -64,7 +64,7 @@ TEST_IMPL(error_message) { TEST_IMPL(sys_error) { #if defined(_WIN32) - ASSERT_EQ(uv_translate_sys_error(ERROR_NOACCESS), UV_EACCES); + ASSERT_EQ(uv_translate_sys_error(ERROR_NOACCESS), UV_EFAULT); ASSERT_EQ(uv_translate_sys_error(ERROR_ELEVATION_REQUIRED), UV_EACCES); ASSERT_EQ(uv_translate_sys_error(WSAEADDRINUSE), UV_EADDRINUSE); ASSERT_EQ(uv_translate_sys_error(ERROR_BAD_PIPE), UV_EPIPE); From 058c49b7ba6314e86e780eb5a9d8e7552ffc27a7 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 18 Oct 2024 15:01:07 -0400 Subject: [PATCH 629/713] win,fs: match trailing slash presence in junctions to user input (#4590) Refs: #4582 --- src/win/fs.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 81a7c99d28d..f2215bb3082 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -2566,15 +2566,17 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path, path_buf[path_buf_len++] = path[i]; } + if (add_slash) + path_buf[path_buf_len++] = L'\\'; len = path_buf_len - start; + /* Insert null terminator */ + path_buf[path_buf_len++] = L'\0'; + /* Set the info about the substitute name */ buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR); buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR); - /* Insert null terminator */ - path_buf[path_buf_len++] = L'\0'; - /* Copy the print name of the target path */ start = path_buf_len; add_slash = 0; @@ -2592,18 +2594,18 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path, path_buf[path_buf_len++] = path[i]; } len = path_buf_len - start; - if (len == 2) { + if (len == 2 || add_slash) { path_buf[path_buf_len++] = L'\\'; len++; } + /* Insert another null terminator */ + path_buf[path_buf_len++] = L'\0'; + /* Set the info about the print name */ buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR); buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR); - /* Insert another null terminator */ - path_buf[path_buf_len++] = L'\0'; - /* Calculate how much buffer space was actually used */ used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + path_buf_len * sizeof(WCHAR); From e1095c7a4373ce00cd8874d8e820de5afb25776e Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 18 Oct 2024 21:02:38 +0200 Subject: [PATCH 630/713] 2024.10.18, Version 1.49.2 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.49.1: * win,fs: remove trailing slash in junctions (Hüseyin Açacak) * Revert "linux: eliminate a read on eventfd per wakeup" (Ben Noordhuis) * win: Fix linked list logic in getaddrinfo (Thad House) * win: fix compilation against Windows 24H2 SDK (Thad House) * win: remap ERROR_NOACCESS and ERROR_BUFFER_OVERFLOW (Jameson Nash) * win,fs: match trailing slash presence in junctions to user input (Jameson Nash) --- AUTHORS | 2 ++ ChangeLog | 18 ++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 4 ++-- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 807440b30e8..041b7aff610 100644 --- a/AUTHORS +++ b/AUTHORS @@ -588,3 +588,5 @@ Raihaan Shouhell Rialbat Adam Poul T Lomholt +dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> +Thad House diff --git a/ChangeLog b/ChangeLog index 81447147ab4..dc2dd2790c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2024.10.18, Version 1.49.2 (Stable) + +Changes since version 1.49.1: + +* win,fs: remove trailing slash in junctions (Hüseyin Açacak) + +* Revert "linux: eliminate a read on eventfd per wakeup" (Ben Noordhuis) + +* win: Fix linked list logic in getaddrinfo (Thad House) + +* win: fix compilation against Windows 24H2 SDK (Thad House) + +* win: remap ERROR_NOACCESS and ERROR_BUFFER_OVERFLOW (Jameson Nash) + +* win,fs: match trailing slash presence in junctions to user input (Jameson + Nash) + + 2024.10.11, Version 1.49.1 (Stable), 8be336f4ee296d20e1c071a44d6adf279e202236 Changes since version 1.49.0: diff --git a/configure.ac b/configure.ac index 74cd7c926bb..98c59363026 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.49.2-dev], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.49.2], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index f16c3d73064..cfa7871322e 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -33,8 +33,8 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 49 #define UV_VERSION_PATCH 2 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 078180e13d28e51a35fc30d6132fed679cbf1a47 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 18 Oct 2024 21:02:38 +0200 Subject: [PATCH 631/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index dc2dd2790c5..68690b6fcca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2024.10.18, Version 1.49.2 (Stable) +2024.10.18, Version 1.49.2 (Stable), e1095c7a4373ce00cd8874d8e820de5afb25776e Changes since version 1.49.1: From 94e467ad93231722df5372eded4ec9d5c84083ae Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 18 Oct 2024 21:08:15 +0200 Subject: [PATCH 632/713] Now working on version 1.49.3 --- configure.ac | 2 +- include/uv/version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 98c59363026..a89f58628ba 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.49.2], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.49.3-dev], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index cfa7871322e..04af319ae35 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 49 -#define UV_VERSION_PATCH 2 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 3 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 0caf5bb8764401f14bbf54fc666cbc9949129218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 16 Jul 2024 22:51:24 +0200 Subject: [PATCH 633/713] ci: run macOS and iOS tests also on macOS 14 The macOS 14 runners are ARM64 (in the non "large" version) whereas macOS 13 runners are still x64, so keep that one around too. --- .github/workflows/CI-unix.yml | 12 ++++++++++-- .github/workflows/sanitizer.yml | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 591c35cf97a..6a805e080cb 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -77,7 +77,11 @@ jobs: adb shell "cd /data/local/tmp/build ; env UV_TEST_TIMEOUT_MULTIPLIER=5 ./uv_run_tests_a" build-macos: - runs-on: macos-12 + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [macos-13, macos-14] steps: - uses: actions/checkout@v4 - name: Envinfo @@ -112,7 +116,11 @@ jobs: make -C build-auto -j4 build-ios: - runs-on: macos-12 + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [macos-13, macos-14] steps: - uses: actions/checkout@v4 - name: Configure diff --git a/.github/workflows/sanitizer.yml b/.github/workflows/sanitizer.yml index 9607b488ff5..58254327d2a 100644 --- a/.github/workflows/sanitizer.yml +++ b/.github/workflows/sanitizer.yml @@ -67,7 +67,7 @@ jobs: ./build-ubsan/uv_run_tests_a sanitizers-macos: - runs-on: macos-12 + runs-on: macos-13 steps: - uses: actions/checkout@v4 From 64f4502b9ba71b4a185ee702dde43f8e6f4841d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 16 Jul 2024 23:59:20 +0200 Subject: [PATCH 634/713] unix,win: map ENOEXEC errno --- include/uv.h | 1 + include/uv/errno.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/uv.h b/include/uv.h index 9e450c5110f..67a25f0c1e2 100644 --- a/include/uv.h +++ b/include/uv.h @@ -157,6 +157,7 @@ struct uv__queue { XX(ESOCKTNOSUPPORT, "socket type not supported") \ XX(ENODATA, "no data available") \ XX(EUNATCH, "protocol driver not attached") \ + XX(ENOEXEC, "exec format error") \ #define UV_HANDLE_TYPE_MAP(XX) \ XX(ASYNC, async) \ diff --git a/include/uv/errno.h b/include/uv/errno.h index 127278ef916..ac00778cfc5 100644 --- a/include/uv/errno.h +++ b/include/uv/errno.h @@ -474,4 +474,10 @@ # define UV__EUNATCH (-4023) #endif +#if defined(ENOEXEC) && !defined(_WIN32) +# define UV__ENOEXEC UV__ERR(ENOEXEC) +#else +# define UV__ENOEXEC (-4022) +#endif + #endif /* UV_ERRNO_H_ */ From a3abfbcb088e639acddfed2771d85426c3392fe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 16 Jul 2024 23:48:26 +0200 Subject: [PATCH 635/713] test: skip multicast join test on ENOEXEC It happens due to the default firewall configuration on macOS >= 13. Note: GH action runners have their firewall disabled, and yet, the test fails all the same. Oh well... Closes: https://github.com/libuv/libuv/issues/4263 --- test/test-udp-multicast-join.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test-udp-multicast-join.c b/test/test-udp-multicast-join.c index 9e322dc579f..2dca600cbb9 100644 --- a/test/test-udp-multicast-join.c +++ b/test/test-udp-multicast-join.c @@ -160,6 +160,8 @@ 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); r = uv_udp_recv_start(&server, alloc_cb, cl_recv_cb); From e129cd7fdae0ffd04bc6939dddb384a7df8fa7c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 22 Oct 2024 09:53:58 +0200 Subject: [PATCH 636/713] ci: make sure the macOS firewall is disabled It seems to be disabled by default, for now, but let's log its status and disable it just in case. --- .github/workflows/CI-unix.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 6a805e080cb..26f1e0e4154 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -86,6 +86,11 @@ jobs: - uses: actions/checkout@v4 - name: Envinfo run: npx envinfo + - name: Disable Firewall + run: | + /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate + sudo defaults write /Library/Preferences/com.apple.alf globalstate -int 0 + /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate - name: Setup run: | brew install ninja automake libtool From d4ab6fbba4669935a6bc23645372dfe4ac29ab39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 22 Oct 2024 10:01:43 +0200 Subject: [PATCH 637/713] darwin,test: squelch EBUSY error on multicast join The firewall was suspected to be the culprit, but the test intermittently fails in the CI, not locally. --- test/test-udp-multicast-join.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/test-udp-multicast-join.c b/test/test-udp-multicast-join.c index 2dca600cbb9..6d3bca5b3d7 100644 --- a/test/test-udp-multicast-join.c +++ b/test/test-udp-multicast-join.c @@ -36,10 +36,9 @@ static uv_udp_t client; static uv_udp_send_t req; static uv_udp_send_t req_ss; +static int darwin_ebusy_errors; static int cl_recv_cb_called; - static int sv_send_cb_called; - static int close_cb_called; static void alloc_cb(uv_handle_t* handle, @@ -128,6 +127,13 @@ static void cl_recv_cb(uv_udp_t* handle, #if !defined(__NetBSD__) r = uv_udp_set_source_membership(&server, MULTICAST_ADDR, NULL, source_addr, UV_JOIN_GROUP); +#if defined(__APPLE__) + if (r == UV_EBUSY) { + uv_close((uv_handle_t*) &server, close_cb); + darwin_ebusy_errors++; + return; + } +#endif ASSERT_OK(r); #endif @@ -177,6 +183,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); From 2d8371a06ef61ed7cb696690c0ce86482c646ba6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 15 Nov 2024 18:48:13 +0100 Subject: [PATCH 638/713] build: update minimum cmake to 3.10 (#4604) Fixes a deprecation warning with new cmake versions. Changing the minimum from 3.9 to 3.10 should be safe because there isn't even a non-EoL'd distro left that ships 3.10, let alone 3.9. Fixes: https://github.com/libuv/libuv/issues/4603 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28c6df25666..805e831f780 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.9) +cmake_minimum_required(VERSION 3.10) if(POLICY CMP0091) cmake_policy(SET CMP0091 NEW) # Enable MSVC_RUNTIME_LIBRARY setting From 7b75935b00567d29ac982903e5f188ab78b4ba9b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 18 Nov 2024 16:13:28 -0500 Subject: [PATCH 639/713] kqueue: use EVFILT_USER for async if available (#4588) Establishes a user event for kqueue to eliminate the overhead of the pipe and the system call read(2) per wakeup event. Relands commit 27134547ff using VSCode merge, since it shows the conflict is just on the order of #ifdef calls. Co-authored-by: Andy Pan --- src/unix/async.c | 83 +++++++++++++++++++++++++++++++++++++++++++++ src/unix/internal.h | 22 ++++++++++++ src/unix/kqueue.c | 11 ++++++ 3 files changed, 116 insertions(+) diff --git a/src/unix/async.c b/src/unix/async.c index 0ff2669e30a..aef25f6bb40 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -38,6 +38,34 @@ #include #endif +#if UV__KQUEUE_EVFILT_USER +static uv_once_t kqueue_runtime_detection_guard = UV_ONCE_INIT; +static int kqueue_evfilt_user_support = 1; + + +static void uv__kqueue_runtime_detection(void) { + int kq; + struct kevent ev[2]; + struct timespec timeout = {0, 0}; + + /* Perform the runtime detection to ensure that kqueue with + * EVFILT_USER actually works. */ + kq = kqueue(); + EV_SET(ev, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER, + EV_ADD | EV_CLEAR, 0, 0, 0); + EV_SET(ev + 1, UV__KQUEUE_EVFILT_USER_IDENT, EVFILT_USER, + 0, NOTE_TRIGGER, 0, 0); + if (kevent(kq, ev, 2, ev, 1, &timeout) < 1 || + ev[0].filter != EVFILT_USER || + ev[0].ident != UV__KQUEUE_EVFILT_USER_IDENT || + ev[0].flags & EV_ERROR) + /* If we wind up here, we can assume that EVFILT_USER is defined but + * broken on the current system. */ + kqueue_evfilt_user_support = 0; + uv__close(kq); +} +#endif + static void uv__async_send(uv_loop_t* loop); static int uv__async_start(uv_loop_t* loop); static void uv__cpu_relax(void); @@ -139,7 +167,11 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(w == &loop->async_io_watcher); +#if UV__KQUEUE_EVFILT_USER + for (;!kqueue_evfilt_user_support;) { +#else for (;;) { +#endif r = read(w->fd, buf, sizeof(buf)); if (r == sizeof(buf)) @@ -195,6 +227,17 @@ static void uv__async_send(uv_loop_t* loop) { len = sizeof(val); fd = loop->async_io_watcher.fd; /* eventfd */ } +#elif defined(UV__KQUEUE_EVFILT_USER) + struct kevent ev; + + if (kqueue_evfilt_user_support) { + fd = loop->async_io_watcher.fd; /* magic number for EVFILT_USER */ + EV_SET(&ev, fd, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0); + r = kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL); + if (r == 0) + return; + abort(); + } #endif do @@ -215,6 +258,9 @@ static void uv__async_send(uv_loop_t* loop) { static int uv__async_start(uv_loop_t* loop) { int pipefd[2]; int err; +#if UV__KQUEUE_EVFILT_USER + struct kevent ev; +#endif if (loop->async_io_watcher.fd != -1) return 0; @@ -226,6 +272,36 @@ static int uv__async_start(uv_loop_t* loop) { pipefd[0] = err; pipefd[1] = -1; +#elif UV__KQUEUE_EVFILT_USER + uv_once(&kqueue_runtime_detection_guard, uv__kqueue_runtime_detection); + if (kqueue_evfilt_user_support) { + /* In order not to break the generic pattern of I/O polling, a valid + * file descriptor is required to take up a room in loop->watchers, + * thus we create one for that, but this fd will not be actually used, + * it's just a placeholder and magic number which is going to be closed + * during the cleanup, as other FDs. */ + err = uv__open_cloexec("/dev/null", O_RDONLY); + if (err < 0) + return err; + + pipefd[0] = err; + pipefd[1] = -1; + + /* When using EVFILT_USER event to wake up the kqueue, this event must be + * registered beforehand. Otherwise, calling kevent() to issue an + * unregistered EVFILT_USER event will get an ENOENT. + * Since uv__async_send() may happen before uv__io_poll() with multi-threads, + * we can't defer this registration of EVFILT_USER event as we did for other + * events, but must perform it right away. */ + EV_SET(&ev, err, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, 0); + err = kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL); + if (err < 0) + return UV__ERR(errno); + } else { + err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE); + if (err < 0) + return err; + } #else err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE); if (err < 0) @@ -236,6 +312,13 @@ static int uv__async_start(uv_loop_t* loop) { uv__io_start(loop, &loop->async_io_watcher, POLLIN); loop->async_wfd = pipefd[1]; +#if UV__KQUEUE_EVFILT_USER + /* Prevent the EVFILT_USER event from being added to kqueue redundantly + * and mistakenly later in uv__io_poll(). */ + if (kqueue_evfilt_user_support) + loop->async_io_watcher.events = loop->async_io_watcher.pevents; +#endif + return 0; } diff --git a/src/unix/internal.h b/src/unix/internal.h index 8d586b0b64a..698caf17cba 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -35,6 +35,10 @@ #include #include #include +#if defined(__APPLE__) || defined(__DragonFly__) || \ + defined(__FreeBSD__) || defined(__NetBSD__) +#include +#endif #define uv__msan_unpoison(p, n) \ do { \ @@ -504,4 +508,22 @@ int uv__get_constrained_cpu(uv__cpu_constraint* constraint); #endif #endif +#if defined(EVFILT_USER) && defined(NOTE_TRIGGER) +/* EVFILT_USER is available since OS X 10.6, DragonFlyBSD 4.0, + * FreeBSD 8.1, and NetBSD 10.0. + * + * Note that even though EVFILT_USER is defined on the current system, + * it may still fail to work at runtime somehow. In that case, we fall + * back to pipe-based signaling. + */ +#define UV__KQUEUE_EVFILT_USER 1 +/* Magic number of identifier used for EVFILT_USER during runtime detection. + * There are no Google hits for this number when I create it. That way, + * people will be directed here if this number gets printed due to some + * kqueue error and they google for help. */ +#define UV__KQUEUE_EVFILT_USER_IDENT 0x1e7e7711 +#else +#define UV__KQUEUE_EVFILT_USER 0 +#endif + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 66aa166f053..876b717086c 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -367,6 +367,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); From c6b67af39011e040267bff20deaeb254feb869ad Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 19 Nov 2024 19:09:03 +0100 Subject: [PATCH 640/713] unix,win: fix off-by-one in uv_wtf8_to_utf16() (#4609) uv_wtf8_length_as_utf16() checks if codepoints are > 0xFFFF (to see if it should be encoded as a surrogate pair), therefore uv_wtf8_to_utf16() should too. Instead it checked > 0x1000. Harmonize the checks. Fixes: https://github.com/nodejs/node/issues/55914 --- src/idna.c | 2 +- test/test-idna.c | 12 ++++++++++++ test/test-list.h | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/idna.c b/src/idna.c index efc5f283ce2..5fcaf64c974 100644 --- a/src/idna.c +++ b/src/idna.c @@ -393,7 +393,7 @@ void uv_wtf8_to_utf16(const char* source_ptr, code_point = uv__wtf8_decode1(&source_ptr); /* uv_wtf8_length_as_utf16 should have been called and checked first. */ assert(code_point >= 0); - if (code_point > 0x10000) { + if (code_point > 0xFFFF) { assert(code_point < 0x10FFFF); *w_target++ = (((code_point - 0x10000) >> 10) + 0xD800); *w_target++ = ((code_point - 0x10000) & 0x3FF) + 0xDC00; diff --git a/test/test-idna.c b/test/test-idna.c index 28f9eaaae9e..4a165573096 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -218,3 +218,15 @@ TEST_IMPL(idna_toascii) { #undef T #endif /* __MVS__ */ + +TEST_IMPL(wtf8) { + static const char input[] = "ᜄȺy𐞲:𞢢𘴇𐀀'¥3̞[ Date: Tue, 19 Nov 2024 18:47:51 +0000 Subject: [PATCH 641/713] doc: add scala-native-loop to LINKS.md (#4613) --- LINKS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/LINKS.md b/LINKS.md index 3e5800747bc..743935cebb8 100644 --- a/LINKS.md +++ b/LINKS.md @@ -37,6 +37,7 @@ * [Pixie-io](https://github.com/pixie-io/pixie): Open-source observability tool for Kubernetes applications. * [potion](https://github.com/perl11/potion)/[p2](https://github.com/perl11/p2): runtime * [racer](https://libraries.io/rubygems/racer): Ruby web server written as an C extension +* [scala-native-loop](https://github.com/scala-native/scala-native-loop): Extensible event loop and async-oriented IO for Scala Native; powered by libuv * [Socket Runtime](https://sockets.sh): A runtime for creating native cross-platform software on mobile and desktop using HTML, CSS, and JavaScript * [spider-gazelle](https://github.com/cotag/spider-gazelle): Ruby web server using libuv bindings * [Suave](http://suave.io/): A simple web development F# library providing a lightweight web server and a set of combinators to manipulate route flow and task composition From 15e3f84678118bda914d1dba8d9e78d9629e36dd Mon Sep 17 00:00:00 2001 From: "Jeffrey H. Johnson" Date: Wed, 20 Nov 2024 13:24:20 +0000 Subject: [PATCH 642/713] unix: fix build breakage on haiku, openbsd, etc (#4618) The compile-time detection check from commit 7b75935 ("kqueue: use EVFILT_USER for async if available") was not being used, breaking numerous operating systems. This commit hopefully unbreaks them. Fixes; https://github.com/libuv/libuv/issues/4608 Signed-off-by: Jeffrey H. Johnson --- src/unix/async.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/async.c b/src/unix/async.c index aef25f6bb40..8265a43ab47 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -227,7 +227,7 @@ static void uv__async_send(uv_loop_t* loop) { len = sizeof(val); fd = loop->async_io_watcher.fd; /* eventfd */ } -#elif defined(UV__KQUEUE_EVFILT_USER) +#elif UV__KQUEUE_EVFILT_USER struct kevent ev; if (kqueue_evfilt_user_support) { From 5dcef22c62a933d2294b9093fa260aaee6c993a4 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Wed, 20 Nov 2024 21:30:14 +0800 Subject: [PATCH 643/713] kqueue: lower overhead in uv__io_check_fd (#4617) Merge kevent calls along with the improvement of code simplicity. Signed-off-by: Andy Pan --- src/unix/kqueue.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 876b717086c..e0166c344b0 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -97,8 +97,7 @@ int uv__io_fork(uv_loop_t* loop) { int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct kevent ev; - int rc; + struct kevent ev[2]; struct stat sb; #ifdef __APPLE__ char path[MAXPATHLEN]; @@ -133,17 +132,12 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { } #endif - rc = 0; - EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); - if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) - rc = UV__ERR(errno); - - EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); - if (rc == 0) - if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) - abort(); + EV_SET(ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); + EV_SET(ev + 1, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, ev, 2, NULL, 0, NULL)) + return UV__ERR(errno); - return rc; + return 0; } From 1b084f7bbe4ae6d90e06600d789126f3b37941d8 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Wed, 20 Nov 2024 11:37:56 -0500 Subject: [PATCH 644/713] doc: move cjihrig back to active maintainers (#4615) --- MAINTAINERS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 41c60cb383c..ff8be88b7b7 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -4,6 +4,9 @@ libuv is currently managed by the following individuals: * **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis)) - GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis) +* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) + - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) + - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) * **Jameson Nash** ([@vtjnash](https://github.com/vtjnash)) - GPG key: AEAD 0A4B 6867 6775 1A0E 4AEF 34A2 5FB1 2824 6514 (pubkey-vtjnash) - GPG key: CFBB 9CA9 A5BE AFD7 0E2B 3C5A 79A6 7C55 A367 9C8B (pubkey2022-vtjnash) @@ -24,9 +27,6 @@ libuv is currently managed by the following individuals: * **Anna Henningsen** ([@addaleax](https://github.com/addaleax)) * **Bartosz Sosnowski** ([@bzoz](https://github.com/bzoz)) * **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus)) -* **Colin Ihrig** ([@cjihrig](https://github.com/cjihrig)) - - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) - - GPG key: 5735 3E0D BDAA A7E8 39B6 6A1A FF47 D5E4 AD8B 4FDC (pubkey-cjihrig-kb) * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) * **Imran Iqbal** ([@imran-iq](https://github.com/imran-iq)) From d05744e3ed362aae366f98d2c63242cd453468df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 08:38:56 -0500 Subject: [PATCH 645/713] build(deps): bump actions/checkout from 3 to 4 (#4490) Requires updating the android builder, since the arm emulator is deprecated and unavailable now. Switch to using a Github Action plugin instead of a container, so that hopefully future updates will be delivered via that channel instead. Changed the idna test since printf returns EILSEQ for some byte sequences in the format on Android in glibc. We don't fully understand the cause, but we can avoid that by not asking it to reencode the bytes in the current locale settings. --- .github/workflows/CI-unix.yml | 71 +++++++++++++++++----------------- test/test-idna.c | 14 +++---- test/test-udp-multicast-join.c | 4 ++ 3 files changed, 46 insertions(+), 43 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 26f1e0e4154..118e5446597 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -29,52 +29,51 @@ jobs: build-android: runs-on: ubuntu-latest - container: reactnativecommunity/react-native-android:2020-5-20 - # Work around an issue where the node from actions/checkout is too new - # to run inside the long-in-the-tooth react-nactive-android container - # image. env: - ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true ANDROID_AVD_HOME: /root/.android/avd steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Envinfo run: npx envinfo - - name: Configure android arm64 - # see build options you can use in https://developer.android.com/ndk/guides/cmake - run: | - mkdir build - cd build - $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/20.0.5594570/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-24 .. - - name: Build android arm64 - run: | - $ANDROID_HOME/cmake/3.10.2.4988404/bin/cmake --build build - ls -lh build - - name: Install Android ABI arm64-v8a - run: | - # TODO: This can be in a pre-built docker image - sdkmanager "build-tools;24.0.3" "platforms;android-24" "system-images;android-24;google_apis;arm64-v8a" - - - name: Start emulator - run: | - echo no | avdmanager create avd -n test -k "system-images;android-24;google_apis;arm64-v8a" + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + - name: Build and Test + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 24 + arch: x86_64 + target: google_apis + ram-size: 2048M + emulator-options: -no-audio -no-window -gpu off -no-boot-anim -netdelay none -netspeed full -writable-system -no-snapshot-save -no-snapshot-load -no-snapshot + disable-animations: true + script: | + echo "::group::Configure" + cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="x86_64" -DANDROID_PLATFORM=android-24 + echo "::endgroup::" - adb start-server + echo "::group::Build" + cmake --build build - emulator @test -memory 2048 -no-audio -no-window -gpu off -no-snapshot -no-boot-anim -netdelay none -netspeed full -no-snapshot-save -no-snapshot-load -writable-system & + ## Correct some ld bugs that cause problems with libuv tests + wget "https://github.com/termux/termux-elf-cleaner/releases/download/v2.2.1/termux-elf-cleaner" -P build + chmod a+x build/termux-elf-cleaner + build/termux-elf-cleaner --api-level 24 ./build/uv_run_tests + build/termux-elf-cleaner --api-level 24 ./build/uv_run_tests_a - adb wait-for-device + adb shell "su 0 setenforce 0" # to allow some syscalls like link, chmod, etc. - adb shell "su 0 setenforce 0" # to allow some syscalls like link, chmod, etc. + ## Push the build and test fixtures to the device + adb push build /data/local/tmp + adb shell mkdir /data/local/tmp/build/test + adb push test/fixtures /data/local/tmp/build/test + echo "::endgroup::" - # Push the build and test fixtures to the device - adb push build /data/local/tmp - adb shell mkdir /data/local/tmp/build/test - adb push test/fixtures /data/local/tmp/build/test - - - name: Test - run: | - adb shell "cd /data/local/tmp/build ; env UV_TEST_TIMEOUT_MULTIPLIER=5 ./uv_run_tests_a" + ## Run the tests + file build/uv_run_tests_a + adb shell "cd /data/local/tmp/build && env UV_TEST_TIMEOUT_MULTIPLIER=5 ./uv_run_tests_a" build-macos: runs-on: ${{ matrix.os }} diff --git a/test/test-idna.c b/test/test-idna.c index 4a165573096..46df9f3c581 100644 --- a/test/test-idna.c +++ b/test/test-idna.c @@ -39,7 +39,7 @@ TEST_IMPL(utf8_decode1) { /* Two-byte sequences. */ p = b; - snprintf(b, sizeof(b), "\xC2\x80\xDF\xBF"); + snprintf(b, sizeof(b), "%s", "\xC2\x80\xDF\xBF"); ASSERT_EQ(128, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 2); ASSERT_EQ(0x7FF, uv__utf8_decode1(&p, b + sizeof(b))); @@ -47,7 +47,7 @@ TEST_IMPL(utf8_decode1) { /* Three-byte sequences. */ p = b; - snprintf(b, sizeof(b), "\xE0\xA0\x80\xEF\xBF\xBF"); + snprintf(b, sizeof(b), "%s", "\xE0\xA0\x80\xEF\xBF\xBF"); ASSERT_EQ(0x800, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 3); ASSERT_EQ(0xFFFF, uv__utf8_decode1(&p, b + sizeof(b))); @@ -55,7 +55,7 @@ TEST_IMPL(utf8_decode1) { /* Four-byte sequences. */ p = b; - snprintf(b, sizeof(b), "\xF0\x90\x80\x80\xF4\x8F\xBF\xBF"); + snprintf(b, sizeof(b), "%s", "\xF0\x90\x80\x80\xF4\x8F\xBF\xBF"); ASSERT_EQ(0x10000, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 4); ASSERT_EQ(0x10FFFF, uv__utf8_decode1(&p, b + sizeof(b))); @@ -63,7 +63,7 @@ TEST_IMPL(utf8_decode1) { /* Four-byte sequences > U+10FFFF; disallowed. */ p = b; - snprintf(b, sizeof(b), "\xF4\x90\xC0\xC0\xF7\xBF\xBF\xBF"); + snprintf(b, sizeof(b), "%s", "\xF4\x90\xC0\xC0\xF7\xBF\xBF\xBF"); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 4); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); @@ -71,7 +71,7 @@ TEST_IMPL(utf8_decode1) { /* Overlong; disallowed. */ p = b; - snprintf(b, sizeof(b), "\xC0\x80\xC1\x80"); + snprintf(b, sizeof(b), "%s", "\xC0\x80\xC1\x80"); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 2); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); @@ -79,7 +79,7 @@ TEST_IMPL(utf8_decode1) { /* Surrogate pairs; disallowed. */ p = b; - snprintf(b, sizeof(b), "\xED\xA0\x80\xED\xA3\xBF"); + snprintf(b, sizeof(b), "%s", "\xED\xA0\x80\xED\xA3\xBF"); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); ASSERT_PTR_EQ(p, b + 3); ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); @@ -87,7 +87,7 @@ TEST_IMPL(utf8_decode1) { /* Simply illegal. */ p = b; - snprintf(b, sizeof(b), "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"); + snprintf(b, sizeof(b), "%s", "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF"); for (i = 1; i <= 8; i++) { ASSERT_EQ((unsigned) -1, uv__utf8_decode1(&p, b + sizeof(b))); diff --git a/test/test-udp-multicast-join.c b/test/test-udp-multicast-join.c index 6d3bca5b3d7..58b055561c6 100644 --- a/test/test-udp-multicast-join.c +++ b/test/test-udp-multicast-join.c @@ -169,6 +169,10 @@ TEST_IMPL(udp_multicast_join) { 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); From 31ea3411ccab6db63a3f573523be61f80f984d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 19 Nov 2024 15:02:57 +0100 Subject: [PATCH 646/713] unix,pipe: fix handling null buffer in uv_pipe_get{sock,peer}name Fixes: https://github.com/libuv/libuv/issues/4610 --- src/unix/pipe.c | 30 +++++++++--------------------- test/test-pipe-getsockname.c | 9 +++++++++ 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 1f9acfac41e..bd57b17fb03 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -360,6 +360,9 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, char* p; int err; + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + addrlen = sizeof(sa); memset(&sa, 0, addrlen); err = uv__getsockpeername((const uv_handle_t*) handle, @@ -444,7 +447,7 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { int uv_pipe_chmod(uv_pipe_t* handle, int mode) { unsigned desired_mode; struct stat pipe_stat; - char* name_buffer; + char name_buffer[1 + UV__PATH_MAX]; size_t name_len; int r; @@ -457,26 +460,14 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { return UV_EINVAL; /* Unfortunately fchmod does not work on all platforms, we will use chmod. */ - name_len = 0; - r = uv_pipe_getsockname(handle, NULL, &name_len); - if (r != UV_ENOBUFS) - return r; - - name_buffer = uv__malloc(name_len); - if (name_buffer == NULL) - return UV_ENOMEM; - + name_len = sizeof(name_buffer); r = uv_pipe_getsockname(handle, name_buffer, &name_len); - if (r != 0) { - uv__free(name_buffer); + if (r != 0) return r; - } /* stat must be used as fstat has a bug on Darwin */ - if (uv__stat(name_buffer, &pipe_stat) == -1) { - uv__free(name_buffer); - return -errno; - } + if (uv__stat(name_buffer, &pipe_stat) == -1) + return UV__ERR(errno); desired_mode = 0; if (mode & UV_READABLE) @@ -485,15 +476,12 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; /* Exit early if pipe already has desired mode. */ - if ((pipe_stat.st_mode & desired_mode) == desired_mode) { - uv__free(name_buffer); + if ((pipe_stat.st_mode & desired_mode) == desired_mode) return 0; - } pipe_stat.st_mode |= desired_mode; r = chmod(name_buffer, pipe_stat.st_mode); - uv__free(name_buffer); return r != -1 ? 0 : UV__ERR(errno); } diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index 34b572343c6..cc345ccd864 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -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)); From c6d43bea09093545e0f199921b2d33548a2a1f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 25 Nov 2024 15:10:47 +0100 Subject: [PATCH 647/713] unix,win: harmonize buffer checking For any API that takes a buffer and size pointer, check both pointers and the pointed-to size and return UV_EINVAL in case of error. Example: ``` int uv_foo(char* buffer, size_t* size) { if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; ... } ``` In order to "peek" the necessary size for dynamic allocation, the following pattern can be used: ``` char *buf; char scratch[1]; size_t len = sizeof(scratch); int r; r = uv_foo(scratch, &len); assert(r == UV_ENOBUFS); buf = malloc(len); r = uv_foo(buf, &len); ... ``` --- src/fs-poll.c | 3 +++ src/unix/core.c | 2 +- src/uv-common.c | 3 +++ src/win/pipe.c | 12 +++++++++--- src/win/util.c | 4 ++-- test/test-fs-event.c | 2 +- 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/fs-poll.c b/src/fs-poll.c index 1bac1c568e3..44f6263a583 100644 --- a/src/fs-poll.c +++ b/src/fs-poll.c @@ -139,6 +139,9 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) { struct poll_ctx* ctx; size_t required_len; + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + if (!uv_is_active((uv_handle_t*)handle)) { *size = 0; return UV_EINVAL; diff --git a/src/unix/core.c b/src/unix/core.c index 0c52ccf2ad7..66053780814 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -751,7 +751,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... */ diff --git a/src/uv-common.c b/src/uv-common.c index 2200fe3f0a4..327e142c5f2 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -644,6 +644,9 @@ int uv_send_buffer_size(uv_handle_t* handle, int *value) { int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) { size_t required_len; + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + if (!uv__is_active(handle)) { *size = 0; return UV_EINVAL; diff --git a/src/win/pipe.c b/src/win/pipe.c index d46ecb9fc70..d05bfd28aec 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1161,9 +1161,9 @@ int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) { err = uv__tcp_xfer_import( (uv_tcp_t*) client, item->xfer_type, &item->xfer_info); - + uv__free(item); - + if (err != 0) return err; @@ -1738,7 +1738,7 @@ static DWORD uv__pipe_get_ipc_remote_pid(uv_pipe_t* handle) { GetNamedPipeServerProcessId(handle->handle, pid); } } - + return *pid; } @@ -2602,6 +2602,9 @@ int uv_pipe_pending_count(uv_pipe_t* handle) { int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) { + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + if (handle->flags & UV_HANDLE_BOUND) return uv__pipe_getname(handle, buffer, size); @@ -2616,6 +2619,9 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) { int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) { + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + /* emulate unix behaviour */ if (handle->flags & UV_HANDLE_BOUND) return UV_ENOTCONN; diff --git a/src/win/util.c b/src/win/util.c index e0dba1aaa94..d7b5f661e6a 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -191,7 +191,7 @@ int uv_cwd(char* buffer, size_t* size) { WCHAR *utf16_buffer; int r; - if (buffer == NULL || size == NULL) { + if (buffer == NULL || size == NULL || *size == 0) { return UV_EINVAL; } @@ -1589,7 +1589,7 @@ int uv_os_uname(uv_utsname_t* buffer) { version_size = sizeof(buffer->version) - version_size; r = uv__copy_utf16_to_utf8(os_info.szCSDVersion, -1, - buffer->version + + buffer->version + sizeof(buffer->version) - version_size, &version_size); if (r) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index bb223a5f654..85649cbcea6 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -1121,7 +1121,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 */ From b1d30f9489771a295c1d9b06402e49a77b3e91e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Mon, 25 Nov 2024 16:42:38 -0500 Subject: [PATCH 648/713] kqueue: change EV_OOBAND to EVFILT_EXCEPT+NOTE_OOB (#4597) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/3947 Signed-off-by: Juan José Arboleda --- src/unix/kqueue.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index e0166c344b0..b0962b97c0f 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -37,17 +37,6 @@ #include #include -/* - * Required on - * - Until at least FreeBSD 11.0 - * - Older versions of Mac OS X - * - * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp - */ -#ifndef EV_OOBAND -#define EV_OOBAND EV_FLAG1 -#endif - static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags); @@ -231,7 +220,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) { - EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0); + EV_SET(events + nevents, w->fd, EVFILT_EXCEPT, EV_ADD, NOTE_OOB, 0, 0); if (++nevents == ARRAY_SIZE(events)) { if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) @@ -393,7 +382,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { revents |= UV__POLLRDHUP; } - if (ev->filter == EV_OOBAND) { + if (ev->filter == EVFILT_EXCEPT) { if (w->pevents & UV__POLLPRI) revents |= UV__POLLPRI; else From 556a0f1f0fd1c89c88738e49ebcc0d75a00a3384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Tue, 26 Nov 2024 08:44:38 -0500 Subject: [PATCH 649/713] unix,win: add support for detached threads (#4621) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces the `uv_thread_detach` for thread detaching, allowing threads to be detached state on both UNIX and Windows platforms. Signed-off-by: Juan José Arboleda --- docs/src/threading.rst | 8 ++++++++ include/uv.h | 1 + src/unix/thread.c | 6 ++++++ src/win/thread.c | 9 +++++++++ test/test-list.h | 2 ++ test/test-thread.c | 10 ++++++++++ 6 files changed, 36 insertions(+) diff --git a/docs/src/threading.rst b/docs/src/threading.rst index 883218fa829..72f8bae0c31 100644 --- a/docs/src/threading.rst +++ b/docs/src/threading.rst @@ -78,6 +78,14 @@ Threads .. versionchanged:: 1.4.1 returns a UV_E* error code on failure +.. c:function:: int uv_thread_detach(uv_thread_t* tid) + + Detaches a thread. Detached threads automatically release their + resources upon termination, eliminating the need for the application to + call `uv_thread_join`. + + .. versionadded:: 1.50.0 + .. c:function:: int uv_thread_create_ex(uv_thread_t* tid, const uv_thread_options_t* params, uv_thread_cb entry, void* arg) Like :c:func:`uv_thread_create`, but additionally specifies options for creating a new thread. diff --git a/include/uv.h b/include/uv.h index 67a25f0c1e2..ae72b0f0989 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1870,6 +1870,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, diff --git a/src/unix/thread.c b/src/unix/thread.c index f05e6fe0f7d..4d6ddc2bb87 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -126,6 +126,12 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { return uv_thread_create_ex(tid, ¶ms, entry, arg); } + +int uv_thread_detach(uv_thread_t *tid) { + return UV__ERR(pthread_detach(*tid)); +} + + int uv_thread_create_ex(uv_thread_t* tid, const uv_thread_options_t* params, void (*entry)(void *arg), diff --git a/src/win/thread.c b/src/win/thread.c index bf39b88633b..28f5e6bf747 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -95,6 +95,15 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { return uv_thread_create_ex(tid, ¶ms, entry, arg); } + +int uv_thread_detach(uv_thread_t *tid) { + if (CloseHandle(*tid) == 0) + return uv_translate_sys_error(GetLastError()); + + return 0; +} + + int uv_thread_create_ex(uv_thread_t* tid, const uv_thread_options_t* params, void (*entry)(void *arg), diff --git a/test/test-list.h b/test/test-list.h index a64c2c3394f..3038d286894 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -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) @@ -1180,6 +1181,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) diff --git a/test/test-thread.c b/test/test-thread.c index d0094e30443..819bbd5c923 100644 --- a/test/test-thread.c +++ b/test/test-thread.c @@ -294,3 +294,13 @@ TEST_IMPL(thread_stack_size_explicit) { return 0; } + +static void thread_detach_cb(void* arg) {} + +TEST_IMPL(thread_detach) { + uv_thread_t thread; + ASSERT_OK(uv_thread_create(&thread, thread_detach_cb, NULL)); + ASSERT_OK(uv_thread_detach(&thread)); + + return 0; +} From b7d07d78e976acc453c9ba8f8409650c2ad8a585 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 26 Nov 2024 18:58:45 +0100 Subject: [PATCH 650/713] Revert "kqueue: change EV_OOBAND to EVFILT_EXCEPT+NOTE_OOB (#4597)" (#4623) Unsupported on FreeBSD, breaking the build. This reverts commit b1d30f9489771a295c1d9b06402e49a77b3e91e6. --- src/unix/kqueue.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index b0962b97c0f..e0166c344b0 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -37,6 +37,17 @@ #include #include +/* + * Required on + * - Until at least FreeBSD 11.0 + * - Older versions of Mac OS X + * + * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp + */ +#ifndef EV_OOBAND +#define EV_OOBAND EV_FLAG1 +#endif + static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags); @@ -220,7 +231,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) { - EV_SET(events + nevents, w->fd, EVFILT_EXCEPT, EV_ADD, NOTE_OOB, 0, 0); + EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0); if (++nevents == ARRAY_SIZE(events)) { if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) @@ -382,7 +393,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { revents |= UV__POLLRDHUP; } - if (ev->filter == EVFILT_EXCEPT) { + if (ev->filter == EV_OOBAND) { if (w->pevents & UV__POLLPRI) revents |= UV__POLLPRI; else From 61c966cf0b4b6b5fc44d5ab3678cf5d0caef249d Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 27 Nov 2024 12:52:18 +0100 Subject: [PATCH 651/713] src: add uv_thread_set/getname() methods (#4599) `uv_thread_setname()` sets the name of the current thread. Different platforms define different limits on the max number of characters a thread name can be: Linux, IBMi (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. `uv_thread_getname()` gets the name of the thread specified by `tid`. The thread name is copied 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. --- CMakeLists.txt | 1 + Makefile.am | 1 + docs/src/threading.rst | 17 +++++ include/uv.h | 3 + src/unix/darwin-proctitle.c | 20 +---- src/unix/internal.h | 2 + src/unix/thread.c | 92 +++++++++++++++++++++++ src/uv-common.h | 14 ++++ src/win/thread.c | 73 ++++++++++++++++++ test/test-list.h | 2 + test/test-thread-name.c | 143 ++++++++++++++++++++++++++++++++++++ 11 files changed, 350 insertions(+), 18 deletions(-) create mode 100644 test/test-thread-name.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 805e831f780..48a78f4cafb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -667,6 +667,7 @@ if(LIBUV_BUILD_TESTS) test/test-thread-affinity.c test/test-thread-equal.c test/test-thread.c + test/test-thread-name.c test/test-thread-priority.c test/test-threadpool-cancel.c test/test-threadpool.c diff --git a/Makefile.am b/Makefile.am index f85a41316c8..09625a69f1b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -294,6 +294,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-thread-equal.c \ test/test-thread.c \ test/test-thread-affinity.c \ + test/test-thread-name.c \ test/test-thread-priority.c \ test/test-threadpool-cancel.c \ test/test-threadpool.c \ diff --git a/docs/src/threading.rst b/docs/src/threading.rst index 72f8bae0c31..f40cf0a33c8 100644 --- a/docs/src/threading.rst +++ b/docs/src/threading.rst @@ -140,6 +140,23 @@ Threads .. c:function:: int uv_thread_join(uv_thread_t *tid) .. c:function:: int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) +.. c:function:: int uv_thread_setname(const char* name) + + Sets the name of the current thread. Different platforms define different limits on the max number of characters + a thread name can be: Linux, IBM i (16), macOS (64), Windows (32767), and NetBSD (32), etc. `uv_thread_setname()` + will truncate it in case `name` is larger than the limit of the platform. + + .. versionadded:: 1.50.0 + +.. c:function:: int uv_thread_getname(uv_thread_t* tid, char* name, size_t* size) + + Gets the name of the thread specified by `tid`. The thread name is copied, with the trailing NUL, into the buffer + pointed to by `name`. The `size` parameter specifies the size of the buffer pointed to by `name`. + The buffer should be large enough to hold the name of the thread plus the trailing NUL, or it will be truncated to fit + with the trailing NUL. + + .. versionadded:: 1.50.0 + .. c:function:: int uv_thread_setpriority(uv_thread_t tid, int priority) If the function succeeds, the return value is 0. If the function fails, the return value is less than zero. diff --git a/include/uv.h b/include/uv.h index ae72b0f0989..b53946fbfa4 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1900,6 +1900,9 @@ UV_EXTERN int uv_thread_getcpu(void); UV_EXTERN uv_thread_t uv_thread_self(void); UV_EXTERN int uv_thread_join(uv_thread_t *tid); UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2); +UV_EXTERN int uv_thread_setname(const char* name); +UV_EXTERN int uv_thread_getname(uv_thread_t* tid, char* name, size_t size); + /* The presence of these unions force similar struct layout. */ #define XX(_, name) uv_ ## name ## _t name; diff --git a/src/unix/darwin-proctitle.c b/src/unix/darwin-proctitle.c index 5288083ef04..5e5642972a4 100644 --- a/src/unix/darwin-proctitle.c +++ b/src/unix/darwin-proctitle.c @@ -33,25 +33,9 @@ #include "darwin-stub.h" #endif - -static int uv__pthread_setname_np(const char* name) { - char namebuf[64]; /* MAXTHREADNAMESIZE */ - int err; - - strncpy(namebuf, name, sizeof(namebuf) - 1); - namebuf[sizeof(namebuf) - 1] = '\0'; - - err = pthread_setname_np(namebuf); - if (err) - return UV__ERR(err); - - return 0; -} - - int uv__set_process_title(const char* title) { #if TARGET_OS_IPHONE - return uv__pthread_setname_np(title); + return uv__thread_setname(title); #else CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, const char*, @@ -177,7 +161,7 @@ int uv__set_process_title(const char* title) { goto out; } - uv__pthread_setname_np(title); /* Don't care if it fails. */ + uv__thread_setname(title); /* Don't care if it fails. */ err = 0; out: diff --git a/src/unix/internal.h b/src/unix/internal.h index 698caf17cba..b1d2b21756d 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -327,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); diff --git a/src/unix/thread.c b/src/unix/thread.c index 4d6ddc2bb87..e51c290466d 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -23,6 +23,9 @@ #include "internal.h" #include +#ifdef __OpenBSD__ +#include +#endif #include #include @@ -297,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) @@ -881,3 +896,80 @@ void uv_key_set(uv_key_t* key, void* value) { if (pthread_setspecific(*key, value)) abort(); } + +#if defined(_AIX) || defined(__MVS__) || defined(__PASE__) +int uv__thread_setname(const char* name) { + return UV_ENOSYS; +} +#elif defined(__APPLE__) +int uv__thread_setname(const char* name) { + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + int err = pthread_setname_np(namebuf); + if (err) + return UV__ERR(errno); + return 0; +} +#elif defined(__NetBSD__) +int uv__thread_setname(const char* name) { + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + return UV__ERR(pthread_setname_np(pthread_self(), "%s", namebuf)); +} +#elif defined(__OpenBSD__) +int uv__thread_setname(const char* name) { + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + pthread_set_name_np(pthread_self(), namebuf); + return 0; +} +#else +int uv__thread_setname(const char* name) { + char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + strncpy(namebuf, name, sizeof(namebuf) - 1); + namebuf[sizeof(namebuf) - 1] = '\0'; + return UV__ERR(pthread_setname_np(pthread_self(), namebuf)); +} +#endif + +#if (defined(__ANDROID_API__) && __ANDROID_API__ < 26) || \ + defined(_AIX) || \ + defined(__MVS__) || \ + defined(__PASE__) +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) { + return UV_ENOSYS; +} +#elif defined(__OpenBSD__) +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) { + char thread_name[UV_PTHREAD_MAX_NAMELEN_NP]; + pthread_get_name_np(*tid, thread_name, sizeof(thread_name)); + strncpy(name, thread_name, size - 1); + name[size - 1] = '\0'; + return 0; +} +#elif defined(__APPLE__) +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) { + char thread_name[UV_PTHREAD_MAX_NAMELEN_NP]; + if (pthread_getname_np(*tid, thread_name, sizeof(thread_name)) != 0) + return UV__ERR(errno); + + strncpy(name, thread_name, size - 1); + name[size - 1] = '\0'; + return 0; +} +#else +int uv__thread_getname(uv_thread_t* tid, char* name, size_t size) { + int r; + char thread_name[UV_PTHREAD_MAX_NAMELEN_NP]; + r = pthread_getname_np(*tid, thread_name, sizeof(thread_name)); + if (r != 0) + return UV__ERR(r); + + strncpy(name, thread_name, size - 1); + name[size - 1] = '\0'; + return 0; +} +#endif diff --git a/src/uv-common.h b/src/uv-common.h index 4baede2e506..10df1706d2b 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -428,4 +428,18 @@ struct uv__loop_internal_fields_s { #endif /* __linux__ */ }; +#if defined(_WIN32) +# define UV_PTHREAD_MAX_NAMELEN_NP 32767 +#elif defined(__APPLE__) +# define UV_PTHREAD_MAX_NAMELEN_NP 64 +#elif defined(__NetBSD__) || defined(__illumos__) +# define UV_PTHREAD_MAX_NAMELEN_NP PTHREAD_MAX_NAMELEN_NP +#elif defined (__linux__) +# define UV_PTHREAD_MAX_NAMELEN_NP 16 +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +# define UV_PTHREAD_MAX_NAMELEN_NP (MAXCOMLEN + 1) +#else +# define UV_PTHREAD_MAX_NAMELEN_NP 16 +#endif + #endif /* UV_COMMON_H_ */ diff --git a/src/win/thread.c b/src/win/thread.c index 28f5e6bf747..0b4e71b98c7 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -278,6 +278,79 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { } +int uv_thread_setname(const char* name) { +#ifdef __MINGW32__ + return UV_ENOSYS; +#else + 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; +#endif /* __MINGW32__ */ +} + + +int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) { +#ifdef __MINGW32__ + return UV_ENOSYS; +#else + 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; +#endif /* __MINGW32__ */ +} + + int uv_mutex_init(uv_mutex_t* mutex) { InitializeCriticalSection(mutex); return 0; diff --git a/test/test-list.h b/test/test-list.h index 3038d286894..3db08aba53d 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -478,6 +478,7 @@ TEST_DECLARE (thread_create) TEST_DECLARE (thread_equal) TEST_DECLARE (thread_affinity) TEST_DECLARE (thread_priority) +TEST_DECLARE (thread_name) TEST_DECLARE (dlerror) #if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ !defined(__sun) @@ -1193,6 +1194,7 @@ TASK_LIST_START TEST_ENTRY (thread_equal) TEST_ENTRY (thread_affinity) TEST_ENTRY (thread_priority) + TEST_ENTRY (thread_name) TEST_ENTRY (dlerror) TEST_ENTRY (ip4_addr) TEST_ENTRY (ip6_addr_link_local) diff --git a/test/test-thread-name.c b/test/test-thread-name.c new file mode 100644 index 00000000000..9f6376f136f --- /dev/null +++ b/test/test-thread-name.c @@ -0,0 +1,143 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include "../src/uv-common.h" + +#include + +struct semaphores { + uv_sem_t main; + uv_sem_t worker; +}; + +static void thread_run(void* arg) { + int r; + char thread_name[16]; + struct semaphores* sem; + uv_thread_t thread; + + sem = arg; + +#ifdef _WIN32 + /* uv_thread_self isn't defined for the main thread on Windows. */ + thread = GetCurrentThread(); +#else + thread = uv_thread_self(); +#endif + + r = uv_thread_setname("worker-thread"); + ASSERT_OK(r); + + uv_sem_post(&sem->worker); + + r = uv_thread_getname(&thread, thread_name, sizeof(thread_name)); + ASSERT_OK(r); + + ASSERT_STR_EQ(thread_name, "worker-thread"); + + uv_sem_wait(&sem->main); +} + +TEST_IMPL(thread_name) { + int r; + uv_thread_t threads[2]; + char tn[UV_PTHREAD_MAX_NAMELEN_NP]; + char thread_name[UV_PTHREAD_MAX_NAMELEN_NP]; + char long_thread_name[UV_PTHREAD_MAX_NAMELEN_NP + 1]; + struct semaphores sem; + +#if defined(__MINGW32__) || \ + 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; +} + From 3d0578e6ebe065836e3407388f6459e8fbefb312 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 28 Nov 2024 21:06:05 +0100 Subject: [PATCH 652/713] build: fix qemu builds (#4630) Upgrade GHA image to Ubuntu 24.04 and use the distro-provided qemu. It should not be necessary anymore to install qemu from .deb because the stock qemu is new enough in 24.04. --- .github/workflows/CI-unix.yml | 47 ++++++++++++++--------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 118e5446597..920cb690da1 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -138,45 +138,36 @@ jobs: ls -lh build-ios build-cross-qemu: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 name: build-cross-qemu-${{ matrix.config.target }} strategy: fail-fast: false matrix: config: - - {target: arm, toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm-static } - - {target: armhf, toolchain: gcc-arm-linux-gnueabihf, cc: arm-linux-gnueabihf-gcc, qemu: qemu-arm-static } - - {target: aarch64, toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64-static } - - {target: riscv64, toolchain: gcc-riscv64-linux-gnu, cc: riscv64-linux-gnu-gcc, qemu: qemu-riscv64-static } - - {target: ppc, toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc-static } - - {target: ppc64, toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64-static } - - {target: ppc64le, toolchain: gcc-powerpc64le-linux-gnu, cc: powerpc64le-linux-gnu-gcc, qemu: qemu-ppc64le-static } - - {target: s390x, toolchain: gcc-s390x-linux-gnu, cc: s390x-linux-gnu-gcc, qemu: qemu-s390x-static } - - {target: mips, toolchain: gcc-mips-linux-gnu, cc: mips-linux-gnu-gcc, qemu: qemu-mips-static } - - {target: mips64, toolchain: gcc-mips64-linux-gnuabi64, cc: mips64-linux-gnuabi64-gcc, qemu: qemu-mips64-static } - - {target: mipsel, toolchain: gcc-mipsel-linux-gnu, cc: mipsel-linux-gnu-gcc, qemu: qemu-mipsel-static } - - {target: mips64el,toolchain: gcc-mips64el-linux-gnuabi64, cc: mips64el-linux-gnuabi64-gcc,qemu: qemu-mips64el-static } - - {target: arm (u64 slots), toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm-static} - - {target: aarch64 (u64 slots), toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64-static} - - {target: ppc (u64 slots), toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc-static} - - {target: ppc64 (u64 slots), toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64-static} + - {target: arm, toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm } + - {target: armhf, toolchain: gcc-arm-linux-gnueabihf, cc: arm-linux-gnueabihf-gcc, qemu: qemu-arm } + - {target: aarch64, toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64 } + - {target: riscv64, toolchain: gcc-riscv64-linux-gnu, cc: riscv64-linux-gnu-gcc, qemu: qemu-riscv64 } + - {target: ppc, toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc } + - {target: ppc64, toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64 } + - {target: ppc64le, toolchain: gcc-powerpc64le-linux-gnu, cc: powerpc64le-linux-gnu-gcc, qemu: qemu-ppc64le } + - {target: s390x, toolchain: gcc-s390x-linux-gnu, cc: s390x-linux-gnu-gcc, qemu: qemu-s390x } + - {target: mips, toolchain: gcc-mips-linux-gnu, cc: mips-linux-gnu-gcc, qemu: qemu-mips } + - {target: mips64, toolchain: gcc-mips64-linux-gnuabi64, cc: mips64-linux-gnuabi64-gcc, qemu: qemu-mips64 } + - {target: mipsel, toolchain: gcc-mipsel-linux-gnu, cc: mipsel-linux-gnu-gcc, qemu: qemu-mipsel } + - {target: mips64el, toolchain: gcc-mips64el-linux-gnuabi64, cc: mips64el-linux-gnuabi64-gcc,qemu: qemu-mips64el } + - {target: arm (u64 slots), toolchain: gcc-arm-linux-gnueabi, cc: arm-linux-gnueabi-gcc, qemu: qemu-arm } + - {target: aarch64 (u64 slots), toolchain: gcc-aarch64-linux-gnu, cc: aarch64-linux-gnu-gcc, qemu: qemu-aarch64 } + - {target: ppc (u64 slots), toolchain: gcc-powerpc-linux-gnu, cc: powerpc-linux-gnu-gcc, qemu: qemu-ppc } + - {target: ppc64 (u64 slots), toolchain: gcc-powerpc64-linux-gnu, cc: powerpc64-linux-gnu-gcc, qemu: qemu-ppc64 } steps: - uses: actions/checkout@v4 - - name: Install QEMU - # this ensure install latest qemu on ubuntu, apt get version is old - env: - QEMU_SRC: "http://archive.ubuntu.com/ubuntu/pool/universe/q/qemu" - QEMU_VER: "qemu-user-static_7\\.2+dfsg-.*_amd64.deb$" - run: | - DEB=`curl -s $QEMU_SRC/ | grep -o -E 'href="([^"#]+)"' | cut -d'"' -f2 | grep $QEMU_VER | tail -1` - wget $QEMU_SRC/$DEB - sudo dpkg -i $DEB - - name: Install ${{ matrix.config.toolchain }} + - name: Install qemu and ${{ matrix.config.toolchain }} run: | sudo apt update - sudo apt install ${{ matrix.config.toolchain }} -y + sudo apt install qemu-user qemu-user-binfmt ${{ matrix.config.toolchain }} -y - name: Configure with ${{ matrix.config.cc }} run: | mkdir build From 14644080c8adf10e460b90c51774531390aebe3c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 28 Nov 2024 22:02:41 +0100 Subject: [PATCH 653/713] win: drop support for windows 8 (#4624) Fixes: https://github.com/libuv/libuv/issues/3889 --- CMakeLists.txt | 2 +- Makefile.am | 2 +- SUPPORTED_PLATFORMS.md | 2 +- include/uv/win.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48a78f4cafb..af89db2dfc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/Makefile.am b/Makefile.am index 09625a69f1b..9b9e6be7178 100644 --- a/Makefile.am +++ b/Makefile.am @@ -59,7 +59,7 @@ if WINNT uvinclude_HEADERS += include/uv/win.h include/uv/tree.h AM_CPPFLAGS += -I$(top_srcdir)/src/win \ -DWIN32_LEAN_AND_MEAN \ - -D_WIN32_WINNT=0x0602 + -D_WIN32_WINNT=0x0A00 libuv_la_SOURCES += src/win/async.c \ src/win/atomicops-inl.h \ src/win/core.c \ diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 8a435d2592e..2c678629862 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -4,7 +4,7 @@ |---|---|---|---| | 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 | diff --git a/include/uv/win.h b/include/uv/win.h index 12ac53b4f21..be17faecc0a 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -20,7 +20,7 @@ */ #ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x0600 +# define _WIN32_WINNT 0x0A00 #endif #if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) From c431bc39c396ce644b47367d415a2c869ee81941 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 3 Dec 2024 00:31:06 +0100 Subject: [PATCH 654/713] linux: fix uv_cpu_info() arm cpu model detection (#4633) Libuv looks for "Processor" in /proc/cpuinfo but it's been reported that on at least some Raspberry Pi models, it's called "model name". Look for both. Fixes: https://github.com/nodejs/node/issues/56105 --- src/unix/linux.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 857a4ef8a66..0fa565b7058 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1713,16 +1713,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 +1827,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. */ From 69bad8201b3c463b2c7d882d9055a2fa8624e180 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 6 Dec 2024 00:11:05 +0100 Subject: [PATCH 655/713] linux: always use io_uring for epoll batching (#4638) io_uring support was default-disabled because of numerous kernel bugs but those are all in the sqpoll (file i/o) parts of io_uring. Batching of epoll_ctl calls through io_uring works fine, is a nice optimization, and is therefore unconditionally enabled again. The UV_USE_IO_URING environment variable now only affects sqpoll, and only when the UV_LOOP_ENABLE_IO_URING_SQPOLL event loop flag is set. Fixes: https://github.com/libuv/libuv/issues/4616 --- src/unix/linux.c | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/unix/linux.c b/src/unix/linux.c index 0fa565b7058..763f5dd5917 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -455,7 +455,7 @@ int uv__io_uring_register(int fd, unsigned opcode, void* arg, unsigned nargs) { } -static int uv__use_io_uring(void) { +static int uv__use_io_uring(uint32_t flags) { #if defined(__ANDROID_API__) return 0; /* Possibly available but blocked by seccomp. */ #elif defined(__arm__) && __SIZEOF_POINTER__ == 4 @@ -470,25 +470,27 @@ static int uv__use_io_uring(void) { char* val; int use; - use = atomic_load_explicit(&use_io_uring, memory_order_relaxed); - - if (use == 0) { - use = uv__kernel_version() >= #if defined(__hppa__) - /* io_uring first supported on parisc in 6.1, functional in .51 */ - /* https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/ */ - /* 6.1.51 */ 0x060133 -#else - /* Older kernels have a bug where the sqpoll thread uses 100% CPU. */ - /* 5.10.186 */ 0x050ABA + /* io_uring first supported on parisc in 6.1, functional in .51 + * https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/ + */ + if (uv__kernel_version() < /*6.1.51*/0x060133) + return 0; #endif - ? 1 : -1; - /* But users can still enable it if they so desire. */ - val = getenv("UV_USE_IO_URING"); - if (val != NULL) - use = atoi(val) ? 1 : -1; + /* SQPOLL is all kinds of buggy but epoll batching should work fine. */ + if (0 == (flags & UV__IORING_SETUP_SQPOLL)) + return 1; + /* Older kernels have a bug where the sqpoll thread uses 100% CPU. */ + if (uv__kernel_version() < /*5.10.186*/0x050ABA) + return 0; + + use = atomic_load_explicit(&use_io_uring, memory_order_relaxed); + + if (use == 0) { + val = getenv("UV_USE_IO_URING"); + use = val != NULL && atoi(val) > 0 ? 1 : -1; atomic_store_explicit(&use_io_uring, use, memory_order_relaxed); } @@ -518,7 +520,7 @@ static void uv__iou_init(int epollfd, sq = MAP_FAILED; sqe = MAP_FAILED; - if (!uv__use_io_uring()) + if (!uv__use_io_uring(flags)) return; kernel_version = uv__kernel_version(); @@ -766,14 +768,13 @@ static struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, */ if (iou->ringfd == -2) { /* By default, the SQPOLL is not created. Enable only if the loop is - * configured with UV_LOOP_USE_IO_URING_SQPOLL. + * configured with UV_LOOP_USE_IO_URING_SQPOLL and the UV_USE_IO_URING + * environment variable is unset or a positive number. */ - if ((loop->flags & UV_LOOP_ENABLE_IO_URING_SQPOLL) == 0) { - iou->ringfd = -1; - return NULL; - } + if (loop->flags & UV_LOOP_ENABLE_IO_URING_SQPOLL) + if (uv__use_io_uring(UV__IORING_SETUP_SQPOLL)) + uv__iou_init(loop->backend_fd, iou, 64, UV__IORING_SETUP_SQPOLL); - uv__iou_init(loop->backend_fd, iou, 64, UV__IORING_SETUP_SQPOLL); if (iou->ringfd == -2) iou->ringfd = -1; /* "failed" */ } From 467859c2ba0beadbb536ebde919e3883c7b4bc11 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 8 Dec 2024 22:32:49 +0100 Subject: [PATCH 656/713] doc: clarify repeating timer behavior more (#4640) It was already documented but only in the uv_timer_set_repeat section. Move it to the toplevel and flesh it out more. Refs: https://github.com/libuv/libuv/issues/181 Refs: https://github.com/libuv/libuv/discussions/4639 --- docs/src/timer.rst | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/src/timer.rst b/docs/src/timer.rst index 070fa79da9d..474c6b8c4cd 100644 --- a/docs/src/timer.rst +++ b/docs/src/timer.rst @@ -6,6 +6,15 @@ Timer handles are used to schedule callbacks to be called in the future. +Timers are either single-shot or repeating. Repeating timers do not adjust +for overhead but are rearmed relative to the event loop's idea of "now". + +Libuv updates its idea of "now" right before executing timer callbacks, and +right after waking up from waiting for I/O. See also :c:func:`uv_update_time`. + +Example: a repeating timer with a 50 ms interval whose callback takes 17 ms +to complete, runs again 33 ms later. If other tasks take longer than 33 ms, +the timer callback runs as soon as possible. Data types ---------- @@ -64,11 +73,6 @@ API duration, and will follow normal timer semantics in the case of a time-slice overrun. - For example, if a 50ms repeating timer first runs for 17ms, it will be - scheduled to run again 33ms later. If other tasks consume more than the - 33ms following the first timer callback, then the callback will run as soon - as possible. - .. note:: If the repeat value is set from a timer callback it does not immediately take effect. If the timer was non-repeating before, it will have been stopped. If it was repeating, From 2494c088f0aacb50305b1c05a81ea64a28b21caf Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 9 Dec 2024 21:14:01 +0100 Subject: [PATCH 657/713] unix,win: handle nbufs=0 in uv_udp_try_send (#4641) --- src/unix/udp.c | 3 ++- src/win/udp.c | 3 ++- test/test-udp-try-send.c | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index f6640fc7231..c3e30314cbc 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -793,7 +793,8 @@ int uv__udp_try_send(uv_udp_t* handle, 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) diff --git a/src/win/udp.c b/src/win/udp.c index 5c8f6e1dd0b..557b4e6084e 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -1101,7 +1101,8 @@ int uv__udp_try_send(uv_udp_t* handle, struct sockaddr_storage converted; int err; - assert(nbufs > 0); + if (nbufs < 1) + return UV_EINVAL; if (addr != NULL) { err = uv__convert_to_localhost_if_unspecified(addr, &converted); diff --git a/test/test-udp-try-send.c b/test/test-udp-try-send.c index 0c76fb1c84d..04246a82d7e 100644 --- a/test/test-udp-try-send.c +++ b/test/test-udp-try-send.c @@ -101,6 +101,10 @@ 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); From 6af08fb527d6aa3ed2a9ac65a7da2c6c16e5d302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 30 Nov 2022 23:59:10 +0100 Subject: [PATCH 658/713] win: use GetQueuedCompletionStatusEx directly It was introduced in Vista, so we can assume it's always there now. --- src/win/core.c | 110 ++++------------------------------------------- src/win/winapi.c | 13 ------ src/win/winapi.h | 11 ----- 3 files changed, 8 insertions(+), 126 deletions(-) diff --git a/src/win/core.c b/src/win/core.c index e9885a0f1ff..bc63b06673a 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -423,97 +423,6 @@ int uv_backend_timeout(const uv_loop_t* loop) { } -static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { - uv__loop_internal_fields_t* lfields; - DWORD bytes; - ULONG_PTR key; - OVERLAPPED* overlapped; - uv_req_t* req; - int repeat; - uint64_t timeout_time; - uint64_t user_timeout; - int reset_timeout; - - lfields = uv__get_internal_fields(loop); - timeout_time = loop->time + timeout; - - if (lfields->flags & UV_METRICS_IDLE_TIME) { - reset_timeout = 1; - user_timeout = timeout; - timeout = 0; - } else { - reset_timeout = 0; - } - - for (repeat = 0; ; repeat++) { - /* Only need to set the provider_entry_time if timeout != 0. The function - * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. - */ - if (timeout != 0) - uv__metrics_set_provider_entry_time(loop); - - /* Store the current timeout in a location that's globally accessible so - * other locations like uv__work_done() can determine whether the queue - * of events in the callback were waiting when poll was called. - */ - lfields->current_timeout = timeout; - - GetQueuedCompletionStatus(loop->iocp, - &bytes, - &key, - &overlapped, - timeout); - - if (reset_timeout != 0) { - if (overlapped && timeout == 0) - uv__metrics_inc_events_waiting(loop, 1); - timeout = user_timeout; - reset_timeout = 0; - } - - /* Placed here because on success the loop will break whether there is an - * empty package or not, or if GetQueuedCompletionStatus returned early then - * the timeout will be updated and the loop will run again. In either case - * the idle time will need to be updated. - */ - uv__metrics_update_idle_time(loop); - - if (overlapped) { - uv__metrics_inc_events(loop, 1); - - /* Package was dequeued */ - req = uv__overlapped_to_req(overlapped); - uv__insert_pending_req(loop, req); - - /* Some time might have passed waiting for I/O, - * so update the loop time here. - */ - uv_update_time(loop); - } else if (GetLastError() != WAIT_TIMEOUT) { - /* Serious error */ - uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); - } else if (timeout > 0) { - /* GetQueuedCompletionStatus can occasionally return a little early. - * Make sure that the desired timeout target time is reached. - */ - uv_update_time(loop); - if (timeout_time > loop->time) { - timeout = (DWORD)(timeout_time - loop->time); - /* The first call to GetQueuedCompletionStatus should return very - * close to the target time and the second should reach it, but - * this is not stated in the documentation. To make sure a busy - * loop cannot happen, the timeout is increased exponentially - * starting on the third round. - */ - timeout += repeat ? (1 << (repeat - 1)) : 0; - continue; - } - } - break; - } -} - - static void uv__poll(uv_loop_t* loop, DWORD timeout) { uv__loop_internal_fields_t* lfields; BOOL success; @@ -553,12 +462,12 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { */ lfields->current_timeout = timeout; - success = pGetQueuedCompletionStatusEx(loop->iocp, - overlappeds, - ARRAY_SIZE(overlappeds), - &count, - timeout, - FALSE); + success = GetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); if (reset_timeout != 0) { timeout = user_timeout; @@ -566,7 +475,7 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { } /* Placed here because on success the loop will break whether there is an - * empty package or not, or if pGetQueuedCompletionStatusEx returned early + * empty package or not, or if GetQueuedCompletionStatusEx returned early * then the timeout will be updated and the loop will run again. In either * case the idle time will need to be updated. */ @@ -647,10 +556,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { uv__metrics_inc_loop_count(loop); - if (pGetQueuedCompletionStatusEx) - uv__poll(loop, timeout); - else - uv__poll_wine(loop, timeout); + uv__poll(loop, timeout); /* Process immediate callbacks (e.g. write_cb) a small fixed number of * times to avoid loop starvation.*/ diff --git a/src/win/winapi.c b/src/win/winapi.c index a74108db03e..315a0d49aff 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -36,9 +36,6 @@ sNtQueryDirectoryFile pNtQueryDirectoryFile; sNtQuerySystemInformation pNtQuerySystemInformation; sNtQueryInformationProcess pNtQueryInformationProcess; -/* Kernel32 function pointers */ -sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; - /* Powrprof.dll function pointer */ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; @@ -55,7 +52,6 @@ void uv__winapi_init(void) { HMODULE ntdll_module; HMODULE powrprof_module; HMODULE user32_module; - HMODULE kernel32_module; HMODULE ws2_32_module; HMODULE api_win_core_file_module; @@ -121,15 +117,6 @@ void uv__winapi_init(void) { uv_fatal_error(GetLastError(), "GetProcAddress"); } - kernel32_module = GetModuleHandleA("kernel32.dll"); - if (kernel32_module == NULL) { - uv_fatal_error(GetLastError(), "GetModuleHandleA"); - } - - pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress( - kernel32_module, - "GetQueuedCompletionStatusEx"); - powrprof_module = LoadLibraryExA("powrprof.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (powrprof_module != NULL) { pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) diff --git a/src/win/winapi.h b/src/win/winapi.h index 5800e70dfd7..f6f5ea7d8de 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4716,14 +4716,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 +4810,6 @@ extern sNtQueryDirectoryFile pNtQueryDirectoryFile; extern sNtQuerySystemInformation pNtQuerySystemInformation; extern sNtQueryInformationProcess pNtQueryInformationProcess; -/* Kernel32 function pointers */ -extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; - /* Powrprof.dll function pointer */ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; From 264bb335af4e56533a93026f9a205329e3df6f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 12 Dec 2024 12:41:08 +0100 Subject: [PATCH 659/713] win: enable uv_thread_{get,set}name on MinGW It supports the API: https://github.com/mirror/mingw-w64/blob/93f3505a758fe70e56678f00e753af3bc4f640bb/mingw-w64-headers/include/processthreadsapi.h#L358 --- src/win/thread.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/win/thread.c b/src/win/thread.c index 0b4e71b98c7..436846a7168 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -279,9 +279,6 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { int uv_thread_setname(const char* name) { -#ifdef __MINGW32__ - return UV_ENOSYS; -#else HRESULT hr; WCHAR* namew; int err; @@ -304,14 +301,10 @@ int uv_thread_setname(const char* name) { return uv_translate_sys_error(HRESULT_CODE(hr)); return 0; -#endif /* __MINGW32__ */ } int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) { -#ifdef __MINGW32__ - return UV_ENOSYS; -#else HRESULT hr; WCHAR* namew; char* thread_name; @@ -347,7 +340,6 @@ int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) { LocalFree(namew); return r; -#endif /* __MINGW32__ */ } From 88baee1a35d73d73576809b23c3e5b9612b1659f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 12 Dec 2024 13:19:47 +0100 Subject: [PATCH 660/713] fixup! --- src/win/winapi.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/win/winapi.h b/src/win/winapi.h index f6f5ea7d8de..d52ad9b3900 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4826,4 +4826,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_ */ From 7752218db2cd3de28a2924d2e9b0f6e062b441c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 12 Dec 2024 14:04:13 +0100 Subject: [PATCH 661/713] fixup! --- test/test-thread-name.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/test-thread-name.c b/test/test-thread-name.c index 9f6376f136f..09432ff98a4 100644 --- a/test/test-thread-name.c +++ b/test/test-thread-name.c @@ -66,8 +66,7 @@ TEST_IMPL(thread_name) { char long_thread_name[UV_PTHREAD_MAX_NAMELEN_NP + 1]; struct semaphores sem; -#if defined(__MINGW32__) || \ - defined(__ANDROID_API__) && __ANDROID_API__ < 26 || \ +#if defined(__ANDROID_API__) && __ANDROID_API__ < 26 || \ defined(_AIX) || \ defined(__MVS__) || \ defined(__PASE__) @@ -140,4 +139,3 @@ TEST_IMPL(thread_name) { return 0; } - From 16e6e84dcc190ca9975802ce742c2ab404f00b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 12 Dec 2024 15:59:30 +0100 Subject: [PATCH 662/713] win: drop support for the legacy MinGW (#4645) The OG MinGW has been dead for years, MinGW-w64 has taken its place. --- SUPPORTED_PLATFORMS.md | 2 +- include/uv/win.h | 8 ----- src/win/winapi.h | 72 +++++++++++++++++------------------------- src/win/winsock.h | 41 ------------------------ test/test-spawn.c | 6 ++-- 5 files changed, 32 insertions(+), 97 deletions(-) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 2c678629862..9597801b919 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -11,7 +11,7 @@ | z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | | Linux with musl | Tier 2 | musl >= 1.0 | | | Android | Tier 3 | NDK >= r15b | Android 7.0, `-DANDROID_PLATFORM=android-24` | -| MinGW | Tier 3 | MinGW32 and MinGW-w64 | | +| MinGW | Tier 3 | MinGW-w64 | | | SunOS | Tier 3 | Solaris 121 and later | | | Other | Tier 3 | N/A | | diff --git a/include/uv/win.h b/include/uv/win.h index be17faecc0a..58d10b8d07f 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -32,14 +32,6 @@ typedef intptr_t ssize_t; #include -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -typedef struct pollfd { - SOCKET fd; - short events; - short revents; -} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD; -#endif - #ifndef LOCALE_INVARIANT # define LOCALE_INVARIANT 0x007f #endif diff --git a/src/win/winapi.h b/src/win/winapi.h index d52ad9b3900..aa68fcd5df7 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4150,40 +4150,35 @@ typedef struct _FILE_STAT_BASIC_INFORMATION { } FILE_STAT_BASIC_INFORMATION; #endif -/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does - * not. - */ -#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) - typedef struct _REPARSE_DATA_BUFFER { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union { - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - struct { - ULONG StringCount; - WCHAR StringList[1]; - } AppExecLinkReparseBuffer; - }; - } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; -#endif +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + struct { + ULONG StringCount; + WCHAR StringList[1]; + } AppExecLinkReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; typedef struct _IO_STATUS_BLOCK { union { @@ -4661,15 +4656,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 diff --git a/src/win/winsock.h b/src/win/winsock.h index 2af958870a7..bb3808a35c2 100644 --- a/src/win/winsock.h +++ b/src/win/winsock.h @@ -154,47 +154,6 @@ typedef struct _AFD_RECV_INFO { #define IOCTL_AFD_POLL \ _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED) -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) -typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP { - /* FIXME: __C89_NAMELESS was removed */ - /* __C89_NAMELESS */ union { - ULONGLONG Alignment; - /* __C89_NAMELESS */ struct { - ULONG Length; - DWORD Flags; - }; - }; - struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next; - SOCKET_ADDRESS Address; - IP_PREFIX_ORIGIN PrefixOrigin; - IP_SUFFIX_ORIGIN SuffixOrigin; - IP_DAD_STATE DadState; - ULONG ValidLifetime; - ULONG PreferredLifetime; - ULONG LeaseLifetime; -} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP; - -typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH { - union { - ULONGLONG Alignment; - struct { - ULONG Length; - DWORD Flags; - }; - }; - struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next; - SOCKET_ADDRESS Address; - IP_PREFIX_ORIGIN PrefixOrigin; - IP_SUFFIX_ORIGIN SuffixOrigin; - IP_DAD_STATE DadState; - ULONG ValidLifetime; - ULONG PreferredLifetime; - ULONG LeaseLifetime; - UINT8 OnLinkPrefixLength; -} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH; - -#endif - int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr, struct sockaddr_storage* storage); diff --git a/test/test-spawn.c b/test/test-spawn.c index efbb2395ff8..964c8a86c76 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1329,9 +1329,7 @@ TEST_IMPL(environment_creation) { } } if (prev) { /* verify sort order */ -#if !defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR) ASSERT_EQ(1, CompareStringOrdinal(prev, -1, str, -1, TRUE)); -#endif } ASSERT(found); /* verify that we expected this variable */ } @@ -1524,7 +1522,7 @@ TEST_IMPL(spawn_setuid_fails) { init_process_options("spawn_helper1", fail_cb); options.flags |= UV_PROCESS_SETUID; - /* On IBMi PASE, there is no root user. User may grant + /* On IBMi PASE, there is no root user. User may grant * root-like privileges, including setting uid to 0. */ #if defined(__PASE__) @@ -1575,7 +1573,7 @@ TEST_IMPL(spawn_setgid_fails) { init_process_options("spawn_helper1", fail_cb); options.flags |= UV_PROCESS_SETGID; - /* On IBMi PASE, there is no root user. User may grant + /* On IBMi PASE, there is no root user. User may grant * root-like privileges, including setting gid to 0. */ #if defined(__MVS__) || defined(__PASE__) From 72d9abccd7d88124f8e9701e64c3469c8f2dea84 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 12 Dec 2024 15:05:53 -0500 Subject: [PATCH 663/713] win,fs: get (most) fstat when no permission (#4566) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces: https://github.com/libuv/libuv/pull/4504 Fixes: https://github.com/libuv/libuv/issues/1980 Fixes: https://github.com/libuv/libuv/issues/3267 Co-authored-by: Hüseyin Açacak --- src/win/fs.c | 205 +++++++++++++++++++++++++++++++++++++++++++++-- src/win/winapi.h | 16 ++++ test/test-fs.c | 54 +++++++++++++ test/test-list.h | 2 + 4 files changed, 269 insertions(+), 8 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index f2215bb3082..a4742aa2ec1 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -58,6 +58,19 @@ #define FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE 0x0010 #endif /* FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE */ +NTSTATUS uv__RtlUnicodeStringInit( + PUNICODE_STRING DestinationString, + PWSTR SourceString, + size_t SourceStringLen +) { + if (SourceStringLen > 0x7FFF) + return STATUS_INVALID_PARAMETER; + DestinationString->MaximumLength = DestinationString->Length = + SourceStringLen * sizeof(SourceString[0]); + DestinationString->Buffer = SourceString; + return STATUS_SUCCESS; +} + #define INIT(subtype) \ do { \ if (req == NULL) \ @@ -1689,12 +1702,12 @@ INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path, uv_stat_t* statbuf, int do_lstat) { FILE_STAT_BASIC_INFORMATION stat_info; - // Check if the new fast API is available. + /* Check if the new fast API is available. */ if (!pGetFileInformationByName) { return FS__STAT_PATH_TRY_SLOW; } - // Check if the API call fails. + /* Check if the API call fails. */ if (!pGetFileInformationByName(path, FileStatBasicByNameInfo, &stat_info, sizeof(stat_info))) { switch(GetLastError()) { @@ -1708,7 +1721,7 @@ INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path, return FS__STAT_PATH_TRY_SLOW; } - // A file handle is needed to get st_size for links. + /* A file handle is needed to get st_size for links. */ if ((stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { return FS__STAT_PATH_TRY_SLOW; } @@ -1802,7 +1815,6 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, * detect this failure and retry without do_lstat if appropriate. */ if (fs__readlink_handle(handle, NULL, &target_length) != 0) { - fs__stat_assign_statbuf(statbuf, stat_info, do_lstat); return -1; } stat_info.EndOfFile.QuadPart = target_length; @@ -1941,6 +1953,179 @@ INLINE static void fs__stat_prepare_path(WCHAR* pathw) { } } +INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, + int do_lstat, DWORD ret_error) { + HANDLE handle = INVALID_HANDLE_VALUE; + FILE_STAT_BASIC_INFORMATION stat_info; + FILE_ID_FULL_DIR_INFORMATION dir_info; + FILE_FS_VOLUME_INFORMATION volume_info; + FILE_FS_DEVICE_INFORMATION device_info; + IO_STATUS_BLOCK io_status; + NTSTATUS nt_status; + WCHAR* path_dirpath = NULL; + WCHAR* path_filename = NULL; + UNICODE_STRING FileMask; + size_t len; + size_t split; + WCHAR splitchar; + int includes_name; + + /* AKA strtok or wcscspn, in reverse. */ + len = wcslen(path); + split = len; + + includes_name = 0; + while (split > 0 && path[split - 1] != L'\\' && path[split - 1] != L'/' && + path[split - 1] != L':') { + /* check if the path contains a character other than /,\,:,. */ + if (path[split-1] != '.') { + includes_name = 1; + } + split--; + } + /* If the path is a relative path with a file name or a folder name */ + if (split == 0 && includes_name) { + path_dirpath = L"."; + /* If there is a slash or a backslash */ + } else if (path[split - 1] == L'\\' || path[split - 1] == L'/') { + path_dirpath = path; + /* If there is no filename, consider it as a relative folder path */ + if (!includes_name) { + split = len; + /* Else, split it */ + } else { + splitchar = path[split - 1]; + path[split - 1] = L'\0'; + } + /* e.g. "..", "c:" */ + } else { + path_dirpath = path; + split = len; + } + path_filename = &path[split]; + + len = 0; + while (1) { + if (path_filename[len] == L'\0') + break; + if (path_filename[len] == L'*' || path_filename[len] == L'?' || + path_filename[len] == L'>' || path_filename[len] == L'<' || + path_filename[len] == L'"') { + ret_error = ERROR_INVALID_NAME; + goto cleanup; + } + len++; + } + + /* Get directory handle */ + handle = CreateFileW(path_dirpath, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + ret_error = GetLastError(); + goto cleanup; + } + + /* Get files in the directory */ + nt_status = uv__RtlUnicodeStringInit(&FileMask, path_filename, len); + if (!NT_SUCCESS(nt_status)) { + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; + } + nt_status = pNtQueryDirectoryFile(handle, + NULL, + NULL, + NULL, + &io_status, + &dir_info, + sizeof(dir_info), + FileIdFullDirectoryInformation, + TRUE, + &FileMask, + TRUE); + + /* Buffer overflow (a warning status code) is expected here since there isn't + * enough space to store the FileName, and actually indicates success. */ + if (!NT_SUCCESS(nt_status) && nt_status != STATUS_BUFFER_OVERFLOW) { + if (nt_status == STATUS_NO_MORE_FILES) + ret_error = ERROR_PATH_NOT_FOUND; + else + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; + } + + /* Assign values to stat_info */ + memset(&stat_info, 0, sizeof(FILE_STAT_BASIC_INFORMATION)); + stat_info.FileAttributes = dir_info.FileAttributes; + stat_info.CreationTime.QuadPart = dir_info.CreationTime.QuadPart; + stat_info.LastAccessTime.QuadPart = dir_info.LastAccessTime.QuadPart; + stat_info.LastWriteTime.QuadPart = dir_info.LastWriteTime.QuadPart; + if (stat_info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + /* A file handle is needed to get st_size for the link (from + * FSCTL_GET_REPARSE_POINT), which is required by posix, but we are here + * because getting the file handle failed. We could get just the + * ReparsePointTag by querying FILE_ID_EXTD_DIR_INFORMATION instead to make + * sure this really is a link before giving up here on the uv_fs_stat call, + * but that doesn't seem essential. */ + if (!do_lstat) + goto cleanup; + stat_info.EndOfFile.QuadPart = 0; + stat_info.AllocationSize.QuadPart = 0; + } else { + stat_info.EndOfFile.QuadPart = dir_info.EndOfFile.QuadPart; + stat_info.AllocationSize.QuadPart = dir_info.AllocationSize.QuadPart; + } + stat_info.ChangeTime.QuadPart = dir_info.ChangeTime.QuadPart; + stat_info.FileId.QuadPart = dir_info.FileId.QuadPart; + + /* Finish up by getting device info from the directory handle, + * since files presumably must live on their device. */ + nt_status = pNtQueryVolumeInformationFile(handle, + &io_status, + &volume_info, + sizeof volume_info, + FileFsVolumeInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (io_status.Status == STATUS_NOT_IMPLEMENTED) { + stat_info.VolumeSerialNumber.QuadPart = 0; + } else if (NT_ERROR(nt_status)) { + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; + } else { + stat_info.VolumeSerialNumber.QuadPart = volume_info.VolumeSerialNumber; + } + + nt_status = pNtQueryVolumeInformationFile(handle, + &io_status, + &device_info, + sizeof device_info, + FileFsDeviceInformation); + + /* Buffer overflow (a warning status code) is expected here. */ + if (NT_ERROR(nt_status)) { + ret_error = pRtlNtStatusToDosError(nt_status); + goto cleanup; + } + + stat_info.DeviceType = device_info.DeviceType; + stat_info.NumberOfLinks = 1; /* No way to recover this info. */ + + fs__stat_assign_statbuf(statbuf, stat_info, do_lstat); + ret_error = 0; + +cleanup: + if (split != 0) + path[split - 1] = splitchar; + if (handle != INVALID_HANDLE_VALUE) + CloseHandle(handle); + return ret_error; +} INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, int do_lstat, @@ -1949,7 +2134,7 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, DWORD flags; DWORD ret; - // If new API exists, try to use it. + /* If new API exists, try to use it. */ switch (fs__stat_path(path, statbuf, do_lstat)) { case FS__STAT_PATH_SUCCESS: return 0; @@ -1959,7 +2144,7 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, break; } - // If the new API does not exist, use the old API. + /* If the new API does not exist, use the old API. */ flags = FILE_FLAG_BACKUP_SEMANTICS; if (do_lstat) flags |= FILE_FLAG_OPEN_REPARSE_POINT; @@ -1972,8 +2157,12 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, flags, NULL); - if (handle == INVALID_HANDLE_VALUE) - return GetLastError(); + if (handle == INVALID_HANDLE_VALUE) { + ret = GetLastError(); + if (ret != ERROR_ACCESS_DENIED && ret != ERROR_SHARING_VIOLATION) + return ret; + return fs__stat_directory(path, statbuf, do_lstat, ret); + } if (fs__stat_handle(handle, statbuf, do_lstat) != 0) ret = GetLastError(); diff --git a/src/win/winapi.h b/src/win/winapi.h index aa68fcd5df7..4e0ccc61baf 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4287,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; diff --git a/test/test-fs.c b/test/test-fs.c index 33cbd428707..423d72dd2f7 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -4507,6 +4507,60 @@ TEST_IMPL(fs_open_readonly_acl) { MAKE_VALGRIND_HAPPY(loop); return 0; } + +TEST_IMPL(fs_stat_no_permission) { + uv_passwd_t pwd; + uv_fs_t req; + int r; + char* filename = "test_file_no_permission.txt"; + + /* Setup - clear the ACL and remove the file */ + loop = uv_default_loop(); + r = uv_os_get_passwd(&pwd); + ASSERT_OK(r); + call_icacls("icacls %s /remove *S-1-1-0:(F)", filename); + unlink(filename); + + /* Create the file */ + r = uv_fs_open(loop, + &open_req1, + filename, + UV_FS_O_RDONLY | UV_FS_O_CREAT, + S_IRUSR, + NULL); + ASSERT_GE(r, 0); + ASSERT_GE(open_req1.result, 0); + uv_fs_req_cleanup(&open_req1); + r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); + ASSERT_OK(r); + ASSERT_OK(close_req.result); + uv_fs_req_cleanup(&close_req); + + /* Set up ACL */ + r = call_icacls("icacls %s /deny *S-1-1-0:(F)", filename); + if (r != 0) { + goto acl_cleanup; + } + + /* Read file stats */ + r = uv_fs_stat(NULL, &req, filename, NULL); + if (r != 0) { + goto acl_cleanup; + } + + uv_fs_req_cleanup(&req); + + acl_cleanup: + /* Cleanup */ + call_icacls("icacls %s /reset", filename); + uv_fs_unlink(NULL, &unlink_req, filename, NULL); + uv_fs_req_cleanup(&unlink_req); + unlink(filename); + uv_os_free_passwd(&pwd); + ASSERT_OK(r); + MAKE_VALGRIND_HAPPY(loop); + return 0; +} #endif #ifdef _WIN32 diff --git a/test/test-list.h b/test/test-list.h index 3db08aba53d..5086bc107b3 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -514,6 +514,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) @@ -1043,6 +1044,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) From 88201044ed7432ecd69fc6de6947d76f207bc3bb Mon Sep 17 00:00:00 2001 From: amcgoogan <105525867+amcgoogan@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:23:36 -0800 Subject: [PATCH 664/713] win: plug uv_fs_event_start memory leak (#4647) Co-authored-by: Andrew McGoogan Fixes: https://github.com/nodejs/node/issues/52769 --- src/win/fs-event.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 7ab407e0534..73e0de8e790 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -253,6 +253,8 @@ int uv_fs_event_start(uv_fs_event_t* handle, } dir_to_watch = dir; + uv__free(short_path); + short_path = NULL; uv__free(pathw); pathw = NULL; } From acebb97490a2ed6cacbdab7049d4c15c78022f6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Fri, 13 Dec 2024 15:30:17 -0500 Subject: [PATCH 665/713] test: address FreeBSD kernel bug causing NULL path in fsevents (#4649) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit documents a FreeBSD kernel issue where uv_fs_event can receive a NULL filename and updates test-fs-event.c to skip filename assertions on FreeBSD. * Bugzilla: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=197695 Refs: https://github.com/libuv/libuv/issues/4606 Signed-off-by: Juan José Arboleda --- docs/src/fs_event.rst | 5 +++++ test/test-fs-event.c | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/docs/src/fs_event.rst b/docs/src/fs_event.rst index 983db1a9d56..bfdecdd7329 100644 --- a/docs/src/fs_event.rst +++ b/docs/src/fs_event.rst @@ -47,6 +47,11 @@ Data types The `events` parameter is an ORed mask of :c:enum:`uv_fs_event` elements. +.. note:: + For FreeBSD path could sometimes be `NULL` due to a kernel bug. + + .. _Reference: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=197695 + .. c:enum:: uv_fs_event Event types that :c:type:`uv_fs_event_t` handles monitor. diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 85649cbcea6..b53057dc25b 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -153,7 +153,14 @@ static void fs_event_cb_del_dir(uv_fs_event_t* handle, ASSERT_PTR_EQ(handle, &fs_event); ASSERT_OK(status); ASSERT(events == UV_CHANGE || events == UV_RENAME); + /* There is a bug in the FreeBSD kernel where the filename is sometimes NULL. + * Refs: https://github.com/libuv/libuv/issues/4606 + */ + #if defined(__FreeBSD__) + ASSERT(filename == NULL || strcmp(filename, "watch_del_dir") == 0); + #else ASSERT_OK(strcmp(filename, "watch_del_dir")); + #endif ASSERT_OK(uv_fs_event_stop(handle)); uv_close((uv_handle_t*)handle, close_cb); } From 7b4cf04a914116d998c5ebcbf2d53b6848b2f65e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 10 Dec 2024 23:36:32 +0100 Subject: [PATCH 666/713] unix: refactor udp sendmsg code Shuffle around and DRY the sendmsg logic in preparation for uv_udp_try_send2(). NFC barring bugs. This work was sponsored by ISC, the Internet Systems Consortium. --- include/uv/unix.h | 5 +- src/unix/udp.c | 369 +++++++++++++++++++++++----------------------- 2 files changed, 188 insertions(+), 186 deletions(-) diff --git a/include/uv/unix.h b/include/uv/unix.h index 538f98b6c5d..7c972026f68 100644 --- a/include/uv/unix.h +++ b/include/uv/unix.h @@ -271,7 +271,10 @@ typedef struct { #define UV_UDP_SEND_PRIVATE_FIELDS \ struct uv__queue queue; \ - struct sockaddr_storage addr; \ + union { \ + struct sockaddr addr; \ + struct sockaddr_storage storage; \ + } u; \ unsigned int nbufs; \ uv_buf_t* bufs; \ ssize_t status; \ diff --git a/src/unix/udp.c b/src/unix/udp.c index c3e30314cbc..045e5fe8d85 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -47,6 +47,10 @@ static void uv__udp_sendmsg(uv_udp_t* handle); static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain, unsigned int flags); +static int uv__udp_sendmsg1(int fd, + const uv_buf_t* bufs, + unsigned int nbufs, + const struct sockaddr* addr); void uv__udp_close(uv_udp_t* handle) { @@ -282,169 +286,6 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { && handle->recv_cb != NULL); } -static void uv__udp_sendmsg_one(uv_udp_t* handle, uv_udp_send_t* req) { - struct uv__queue* q; - struct msghdr h; - ssize_t size; - - for (;;) { - memset(&h, 0, sizeof h); - if (req->addr.ss_family == AF_UNSPEC) { - h.msg_name = NULL; - h.msg_namelen = 0; - } else { - h.msg_name = &req->addr; - if (req->addr.ss_family == AF_INET6) - h.msg_namelen = sizeof(struct sockaddr_in6); - else if (req->addr.ss_family == AF_INET) - h.msg_namelen = sizeof(struct sockaddr_in); - else if (req->addr.ss_family == AF_UNIX) - h.msg_namelen = sizeof(struct sockaddr_un); - else { - assert(0 && "unsupported address family"); - abort(); - } - } - h.msg_iov = (struct iovec*) req->bufs; - h.msg_iovlen = req->nbufs; - - do - size = sendmsg(handle->io_watcher.fd, &h, 0); - while (size == -1 && errno == EINTR); - - if (size == -1) - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) - return; - - req->status = (size == -1 ? UV__ERR(errno) : size); - - /* Sending a datagram is an atomic operation: either all data - * is written or nothing is (and EMSGSIZE is raised). That is - * why we don't handle partial writes. Just pop the request - * off the write queue and onto the completed queue, done. - */ - uv__queue_remove(&req->queue); - uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); - uv__io_feed(handle->loop, &handle->io_watcher); - - if (uv__queue_empty(&handle->write_queue)) - return; - - q = uv__queue_head(&handle->write_queue); - req = uv__queue_data(q, uv_udp_send_t, queue); - } -} - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) -static void uv__udp_sendmsg_many(uv_udp_t* handle) { - uv_udp_send_t* req; - struct mmsghdr h[20]; - struct mmsghdr* p; - struct uv__queue* q; - ssize_t npkts; - size_t pkts; - size_t i; - -write_queue_drain: - for (pkts = 0, q = uv__queue_head(&handle->write_queue); - pkts < ARRAY_SIZE(h) && q != &handle->write_queue; - ++pkts, q = uv__queue_head(q)) { - req = uv__queue_data(q, uv_udp_send_t, queue); - - p = &h[pkts]; - memset(p, 0, sizeof(*p)); - if (req->addr.ss_family == AF_UNSPEC) { - p->msg_hdr.msg_name = NULL; - p->msg_hdr.msg_namelen = 0; - } else { - p->msg_hdr.msg_name = &req->addr; - if (req->addr.ss_family == AF_INET6) - p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in6); - else if (req->addr.ss_family == AF_INET) - p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in); - else if (req->addr.ss_family == AF_UNIX) - p->msg_hdr.msg_namelen = sizeof(struct sockaddr_un); - else { - assert(0 && "unsupported address family"); - abort(); - } - } - h[pkts].msg_hdr.msg_iov = (struct iovec*) req->bufs; - h[pkts].msg_hdr.msg_iovlen = req->nbufs; - } - -#if defined(__APPLE__) - do - npkts = sendmsg_x(handle->io_watcher.fd, h, pkts, MSG_DONTWAIT); - while (npkts == -1 && errno == EINTR); -#else - do - npkts = sendmmsg(handle->io_watcher.fd, h, pkts, 0); - while (npkts == -1 && errno == EINTR); -#endif - - if (npkts < 1) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) - return; - for (i = 0, q = uv__queue_head(&handle->write_queue); - i < pkts && q != &handle->write_queue; - ++i, q = uv__queue_head(&handle->write_queue)) { - req = uv__queue_data(q, uv_udp_send_t, queue); - req->status = UV__ERR(errno); - uv__queue_remove(&req->queue); - uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); - } - uv__io_feed(handle->loop, &handle->io_watcher); - return; - } - - /* Safety: npkts known to be >0 below. Hence cast from ssize_t - * to size_t safe. - */ - for (i = 0, q = uv__queue_head(&handle->write_queue); - i < (size_t)npkts && q != &handle->write_queue; - ++i, q = uv__queue_head(&handle->write_queue)) { - req = uv__queue_data(q, uv_udp_send_t, queue); - req->status = req->bufs[0].len; - - /* Sending a datagram is an atomic operation: either all data - * is written or nothing is (and EMSGSIZE is raised). That is - * why we don't handle partial writes. Just pop the request - * off the write queue and onto the completed queue, done. - */ - uv__queue_remove(&req->queue); - uv__queue_insert_tail(&handle->write_completed_queue, &req->queue); - } - - /* couldn't batch everything, continue sending (jump to avoid stack growth) */ - if (!uv__queue_empty(&handle->write_queue)) - goto write_queue_drain; - - uv__io_feed(handle->loop, &handle->io_watcher); -} -#endif /* __linux__ || ____FreeBSD__ || __APPLE__ */ - -static void uv__udp_sendmsg(uv_udp_t* handle) { - struct uv__queue* q; - uv_udp_send_t* req; - - if (uv__queue_empty(&handle->write_queue)) - return; - - q = uv__queue_head(&handle->write_queue); - req = uv__queue_data(q, uv_udp_send_t, queue); - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) - /* Use sendmmsg() if this send request contains more than one datagram OR - * there is more than one send request (because that automatically implies - * there is more than one datagram.) - */ - if (req->nbufs != 1 || &handle->write_queue != uv__queue_next(&req->queue)) - return uv__udp_sendmsg_many(handle); -#endif - - return uv__udp_sendmsg_one(handle, req); -} /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional * refinements for programs that use multicast. Therefore we preferentially @@ -743,11 +584,11 @@ int uv__udp_send(uv_udp_send_t* req, empty_queue = (handle->send_queue_count == 0); uv__req_init(handle->loop, req, UV_UDP_SEND); - assert(addrlen <= sizeof(req->addr)); + assert(addrlen <= sizeof(req->u.storage)); if (addr == NULL) - req->addr.ss_family = AF_UNSPEC; + req->u.storage.ss_family = AF_UNSPEC; else - memcpy(&req->addr, addr, addrlen); + memcpy(&req->u.storage, addr, addrlen); req->send_cb = send_cb; req->handle = handle; req->nbufs = nbufs; @@ -790,8 +631,6 @@ int uv__udp_try_send(uv_udp_t* handle, const struct sockaddr* addr, unsigned int addrlen) { int err; - struct msghdr h; - ssize_t size; if (nbufs < 1) return UV_EINVAL; @@ -808,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; - - do { - size = sendmsg(handle->io_watcher.fd, &h, 0); - } while (size == -1 && errno == EINTR); - - if (size == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) - return UV_EAGAIN; - else - return UV__ERR(errno); - } + err = uv__udp_sendmsg1(handle->io_watcher.fd, bufs, nbufs, addr); + if (err > 0) + return uv__count_bufs(bufs, nbufs); - return size; + return err; } @@ -1402,3 +1228,176 @@ 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); +} From e8969bff6cfebf950b2a52eabff53e53ff02ab0e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 10 Dec 2024 23:36:32 +0100 Subject: [PATCH 667/713] unix,win: add uv_udp_try_send2 Add a version of uv_udp_try_send that can send multiple datagrams. Uses sendmmsg(2) on platforms that support it (Linux, FreeBSD, macOS), falls back to a regular sendmsg(2) loop elsewhere. This work was sponsored by ISC, the Internet Systems Consortium. --- docs/src/udp.rst | 14 ++++++++++++++ include/uv.h | 6 ++++++ src/unix/udp.c | 15 +++++++++++++++ src/uv-common.c | 19 +++++++++++++++++++ src/uv-common.h | 6 ++++++ src/win/udp.c | 18 ++++++++++++++++++ test/test-udp-try-send.c | 36 ++++++++++++++++++++++++++++++------ 7 files changed, 108 insertions(+), 6 deletions(-) diff --git a/docs/src/udp.rst b/docs/src/udp.rst index 31f7f7fd71f..5f225e5cda4 100644 --- a/docs/src/udp.rst +++ b/docs/src/udp.rst @@ -426,6 +426,20 @@ API .. versionchanged:: 1.27.0 added support for connected sockets +.. c:function:: int uv_udp_try_send2(uv_udp_t* handle, unsigned int count, uv_buf_t* bufs[/*count*/], unsigned int nbufs[/*count*/], struct sockaddr* addrs[/*count*/], unsigned int flags) + + Like :c:func:`uv_udp_try_send`, but can send multiple datagrams. + Lightweight abstraction around :man:`sendmmsg(2)`, with a :man:`sendmsg(2)` + fallback loop for platforms that do not support the former. The handle must + be fully initialized; call c:func:`uv_udp_bind` first. + + :returns: >= 0: number of datagrams sent. Zero only if `count` was zero. + < 0: negative error code. Only if sending the first datagram fails, + otherwise returns a positive send count. ``UV_EAGAIN`` when datagrams + cannot be sent right now; fall back to :c:func:`uv_udp_send`. + + .. versionadded:: 1.50.0 + .. c:function:: int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb) Prepare for receiving data. If the socket has not previously been bound diff --git a/include/uv.h b/include/uv.h index b53946fbfa4..b1689e96d73 100644 --- a/include/uv.h +++ b/include/uv.h @@ -776,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); diff --git a/src/unix/udp.c b/src/unix/udp.c index 045e5fe8d85..67c01f7dce8 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -1401,3 +1401,18 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { feed: uv__io_feed(handle->loop, &handle->io_watcher); } + + +int uv__udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/]) { + int fd; + + fd = handle->io_watcher.fd; + if (fd == -1) + return UV_EINVAL; + + return uv__udp_sendmsgv(fd, count, bufs, nbufs, addrs); +} diff --git a/src/uv-common.c b/src/uv-common.c index 327e142c5f2..60ff56b9dd7 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -514,6 +514,25 @@ int uv_udp_try_send(uv_udp_t* handle, } +int uv_udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/], + unsigned int flags) { + if (count < 1) + return UV_EINVAL; + + if (flags != 0) + return UV_EINVAL; + + if (handle->send_queue_count > 0) + return UV_EAGAIN; + + return uv__udp_try_send2(handle, count, bufs, nbufs, addrs); +} + + int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb) { diff --git a/src/uv-common.h b/src/uv-common.h index 10df1706d2b..372f0c4b3ac 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -191,6 +191,12 @@ int uv__udp_try_send(uv_udp_t* handle, const struct sockaddr* addr, unsigned int addrlen); +int uv__udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/]); + int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb, uv_udp_recv_cb recv_cb); diff --git a/src/win/udp.c b/src/win/udp.c index 557b4e6084e..e0873c2a899 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -1142,3 +1142,21 @@ int uv__udp_try_send(uv_udp_t* handle, return bytes; } + + +int uv__udp_try_send2(uv_udp_t* handle, + unsigned int count, + uv_buf_t* bufs[/*count*/], + unsigned int nbufs[/*count*/], + struct sockaddr* addrs[/*count*/]) { + unsigned int i; + int r; + + for (i = 0; i < count; i++) { + r = uv_udp_try_send(handle, bufs[i], nbufs[i], addrs[i]); + if (r < 0) + return i > 0 ? i : r; /* Error if first packet, else send count. */ + } + + return i; +} diff --git a/test/test-udp-try-send.c b/test/test-udp-try-send.c index 04246a82d7e..6181fbbbffc 100644 --- a/test/test-udp-try-send.c +++ b/test/test-udp-try-send.c @@ -60,8 +60,6 @@ static void sv_recv_cb(uv_udp_t* handle, const uv_buf_t* rcvbuf, const struct sockaddr* addr, unsigned flags) { - ASSERT_GT(nread, 0); - if (nread == 0) { ASSERT_NULL(addr); return; @@ -70,11 +68,17 @@ static void sv_recv_cb(uv_udp_t* handle, ASSERT_EQ(4, nread); ASSERT_NOT_NULL(addr); - ASSERT_OK(memcmp("EXIT", rcvbuf->base, nread)); - uv_close((uv_handle_t*) handle, close_cb); - uv_close((uv_handle_t*) &client, close_cb); + if (!memcmp("EXIT", rcvbuf->base, nread)) { + uv_close((uv_handle_t*) handle, close_cb); + uv_close((uv_handle_t*) &client, close_cb); + } else { + ASSERT_MEM_EQ(rcvbuf->base, "HELO", 4); + } sv_recv_cb_called++; + + if (sv_recv_cb_called == 2) + uv_udp_recv_stop(handle); } @@ -108,6 +112,26 @@ TEST_IMPL(udp_try_send) { 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); @@ -115,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); From 3d78d121f4f41e8156010b6a06e4492cd0398361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Sun, 15 Dec 2024 14:24:20 -0500 Subject: [PATCH 668/713] test: fix flaky flaky udp_mmsg test (#4652) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace comparison of `alloc_cb_called` with the total bytes read (`bytes_read`) to validate the test's correctness. Fixes: https://github.com/libuv/libuv/issues/4650 Signed-off-by: Juan José Arboleda --- test/test-udp-mmsg.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/test-udp-mmsg.c b/test/test-udp-mmsg.c index c0e000b9d92..73213c43d97 100644 --- a/test/test-udp-mmsg.c +++ b/test/test-udp-mmsg.c @@ -32,12 +32,12 @@ #define BUFFER_MULTIPLIER 20 #define MAX_DGRAM_SIZE (64 * 1024) #define NUM_SENDS 40 -#define EXPECTED_MMSG_ALLOCS (NUM_SENDS / BUFFER_MULTIPLIER) static uv_udp_t recver; static uv_udp_t sender; static int recv_cb_called; static int received_datagrams; +static int read_bytes; static int close_cb_called; static int alloc_cb_called; @@ -74,6 +74,7 @@ static void recv_cb(uv_udp_t* handle, const struct sockaddr* addr, unsigned flags) { ASSERT_GE(nread, 0); + read_bytes += nread; /* free and return if this is a mmsg free-only callback invocation */ if (flags & UV_UDP_MMSG_FREE) { @@ -140,7 +141,7 @@ TEST_IMPL(udp_mmsg) { /* On platforms that don't support mmsg, each recv gets its own alloc */ if (uv_udp_using_recvmmsg(&recver)) - ASSERT_EQ(alloc_cb_called, EXPECTED_MMSG_ALLOCS); + ASSERT_EQ(read_bytes, NUM_SENDS * 4); /* we're sending 4 bytes per datagram */ else ASSERT_EQ(alloc_cb_called, recv_cb_called); From a94f2ad2b7b3d9c527d9b589d6200cca3b11d413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Arboleda?= Date: Sat, 23 Nov 2024 17:59:49 -0500 Subject: [PATCH 669/713] build: enable fdsan in Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch will update Android API in CI to 29 and will set up the fdsan in the test runner. Signed-off-by: Juan José Arboleda Fixes: https://github.com/libuv/libuv/issues/4369 --- .github/workflows/CI-unix.yml | 8 ++++---- test/runner.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/.github/workflows/CI-unix.yml b/.github/workflows/CI-unix.yml index 920cb690da1..298dca21400 100644 --- a/.github/workflows/CI-unix.yml +++ b/.github/workflows/CI-unix.yml @@ -43,7 +43,7 @@ jobs: - name: Build and Test uses: reactivecircus/android-emulator-runner@v2 with: - api-level: 24 + api-level: 30 arch: x86_64 target: google_apis ram-size: 2048M @@ -51,7 +51,7 @@ jobs: disable-animations: true script: | echo "::group::Configure" - cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="x86_64" -DANDROID_PLATFORM=android-24 + cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="x86_64" -DANDROID_PLATFORM=android-30 echo "::endgroup::" echo "::group::Build" @@ -60,8 +60,8 @@ jobs: ## Correct some ld bugs that cause problems with libuv tests wget "https://github.com/termux/termux-elf-cleaner/releases/download/v2.2.1/termux-elf-cleaner" -P build chmod a+x build/termux-elf-cleaner - build/termux-elf-cleaner --api-level 24 ./build/uv_run_tests - build/termux-elf-cleaner --api-level 24 ./build/uv_run_tests_a + build/termux-elf-cleaner --api-level 30 ./build/uv_run_tests + build/termux-elf-cleaner --api-level 30 ./build/uv_run_tests_a adb shell "su 0 setenforce 0" # to allow some syscalls like link, chmod, etc. diff --git a/test/runner.c b/test/runner.c index d1dd02f5ce0..54abb39dd22 100644 --- a/test/runner.c +++ b/test/runner.c @@ -27,6 +27,11 @@ #include "task.h" #include "uv.h" +/* Refs: https://github.com/libuv/libuv/issues/4369 */ +#if defined(__ANDROID__) +#include +#endif + char executable_path[sizeof(executable_path)]; @@ -142,6 +147,13 @@ void log_tap_result(int test_count, fflush(stdout); } +void enable_fdsan(void) { +/* Refs: https://github.com/libuv/libuv/issues/4369 */ +#if defined(__ANDROID__) + android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS); +#endif +} + int run_test(const char* test, int benchmark_output, @@ -160,6 +172,8 @@ int run_test(const char* test, main_proc = NULL; process_count = 0; + enable_fdsan(); + #ifndef _WIN32 /* Clean up stale socket from previous run. */ remove(TEST_PIPENAME); From beebf02cf6a69b78673182421445fcbc9b10c341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Mon, 16 Dec 2024 03:05:09 -0500 Subject: [PATCH 670/713] test: fix udp-multicast-join for FreeBSD (#4655) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/4651 Signed-off-by: Juan José Arboleda --- test/test-udp-multicast-join6.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test-udp-multicast-join6.c b/test/test-udp-multicast-join6.c index c6872e42832..430e4e3321e 100644 --- a/test/test-udp-multicast-join6.c +++ b/test/test-udp-multicast-join6.c @@ -33,6 +33,7 @@ #if defined(__APPLE__) || \ defined(_AIX) || \ defined(__MVS__) || \ + defined(__FreeBSD__) || \ defined(__NetBSD__) || \ defined(__OpenBSD__) #define MULTICAST_ADDR "ff02::1%lo0" From ec5a4b54f7da7eeb01679005c615fee9633cdb3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 16 Dec 2024 13:41:36 +0100 Subject: [PATCH 671/713] win: fix leak processing fs event Fixes: https://github.com/libuv/libuv/pull/4376#issuecomment-2544728609 --- src/win/fs-event.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 73e0de8e790..1bbb8c52be2 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -579,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)); } From e59e2a9e49c96feffebdfd44915320e32a91a957 Mon Sep 17 00:00:00 2001 From: Rafael Gonzaga Date: Wed, 8 Jan 2025 09:58:28 -0300 Subject: [PATCH 672/713] src: set a default thread name for workers (#4664) --- docs/src/threadpool.rst | 2 ++ src/threadpool.c | 1 + test/test-list.h | 2 ++ test/test-thread-name.c | 48 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+) diff --git a/docs/src/threadpool.rst b/docs/src/threadpool.rst index 7cfa797314c..05f31d2ccf3 100644 --- a/docs/src/threadpool.rst +++ b/docs/src/threadpool.rst @@ -17,6 +17,8 @@ is 1024). .. versionchanged:: 1.45.0 threads now have an 8 MB stack instead of the (sometimes too low) platform default. +.. versionchanged:: 1.50.0 threads now have a default name of libuv-worker. + The threadpool is global and shared across all event loops. When a particular function makes use of the threadpool (i.e. when using :c:func:`uv_queue_work`) libuv preallocates and initializes the maximum number of threads allowed by diff --git a/src/threadpool.c b/src/threadpool.c index 45af50dcd04..98d81cc7b6a 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -59,6 +59,7 @@ static void worker(void* arg) { struct uv__queue* q; int is_slow_work; + uv_thread_setname("libuv-worker"); uv_sem_post((uv_sem_t*) arg); arg = NULL; diff --git a/test/test-list.h b/test/test-list.h index 5086bc107b3..c6651299c12 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -479,6 +479,7 @@ 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) @@ -1197,6 +1198,7 @@ TASK_LIST_START 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) diff --git a/test/test-thread-name.c b/test/test-thread-name.c index 09432ff98a4..378d82cf81b 100644 --- a/test/test-thread-name.c +++ b/test/test-thread-name.c @@ -139,3 +139,51 @@ TEST_IMPL(thread_name) { 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; +} From be8eec8c5a99bcce5a1b8435237dad588cfd9f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Tue, 14 Jan 2025 08:50:26 -0500 Subject: [PATCH 673/713] misc: implement uv_getrusage_thread (#4666) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs: https://github.com/libuv/libuv/issues/3119 Signed-off-by: Juan José Arboleda Co-authored-by: James M Snell --- docs/src/misc.rst | 11 +++++ include/uv.h | 1 + src/unix/core.c | 48 +++++++++++++++++++- src/win/util.c | 88 +++++++++++++++++++++++++++---------- test/test-platform-output.c | 16 +++++++ 5 files changed, 140 insertions(+), 24 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 61883b7e21e..db95e2dde83 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -360,6 +360,17 @@ API On Windows not all fields are set, the unsupported fields are filled with zeroes. See :c:type:`uv_rusage_t` for more details. +.. c:function:: int uv_getrusage_thread(uv_rusage_t* rusage) + + Gets the resource usage measures for the calling thread. + + .. versionadded:: 1.50.0 + + .. note:: + Not supported on all platforms. May return `UV_ENOTSUP`. + On macOS and Windows not all fields are set, the unsupported fields are filled with zeroes. + See :c:type:`uv_rusage_t` for more details. + .. c:function:: uv_pid_t uv_os_getpid(void) Returns the current process ID. diff --git a/include/uv.h b/include/uv.h index b1689e96d73..f0ec376b607 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1295,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); diff --git a/src/unix/core.c b/src/unix/core.c index 66053780814..61cbc0d027f 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -52,6 +52,8 @@ #endif #if defined(__APPLE__) +# include +# include # include # include #endif /* defined(__APPLE__) */ @@ -999,10 +1001,10 @@ int uv__fd_exists(uv_loop_t* loop, int fd) { } -int uv_getrusage(uv_rusage_t* rusage) { +static int uv__getrusage(int who, uv_rusage_t* rusage) { struct rusage usage; - if (getrusage(RUSAGE_SELF, &usage)) + if (getrusage(who, &usage)) return UV__ERR(errno); rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec; @@ -1041,6 +1043,48 @@ int uv_getrusage(uv_rusage_t* rusage) { } +int uv_getrusage(uv_rusage_t* rusage) { + return uv__getrusage(RUSAGE_SELF, rusage); +} + + +int uv_getrusage_thread(uv_rusage_t* rusage) { +#if defined(__APPLE__) + mach_msg_type_number_t count; + thread_basic_info_data_t info; + kern_return_t kr; + thread_t thread; + + thread = mach_thread_self(); + count = THREAD_BASIC_INFO_COUNT; + kr = thread_info(thread, + THREAD_BASIC_INFO, + (thread_info_t)&info, + &count); + + if (kr != KERN_SUCCESS) { + mach_port_deallocate(mach_task_self(), thread); + return UV_EINVAL; + } + + memset(rusage, 0, sizeof(*rusage)); + + rusage->ru_utime.tv_sec = info.user_time.seconds; + rusage->ru_utime.tv_usec = info.user_time.microseconds; + rusage->ru_stime.tv_sec = info.system_time.seconds; + rusage->ru_stime.tv_usec = info.system_time.microseconds; + + mach_port_deallocate(mach_task_self(), thread); + + return 0; + +#elif defined(RUSAGE_THREAD) + return uv__getrusage(RUSAGE_THREAD, rusage); +#endif /* defined(__APPLE__) */ + return UV_ENOTSUP; +} + + int uv__open_cloexec(const char* path, int flags) { #if defined(O_CLOEXEC) int fd; diff --git a/src/win/util.c b/src/win/util.c index d7b5f661e6a..1d1b2837e1a 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -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; } diff --git a/test/test-platform-output.c b/test/test-platform-output.c index 4e5300da037..d9b39c744ff 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -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; } From 8fb9cb919489a48880680a56efecff6a7dfb4504 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 15 Jan 2025 19:05:29 +0100 Subject: [PATCH 674/713] 2025.01.15, Version 1.50.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- .mailmap | 1 + AUTHORS | 4 ++- ChangeLog | 81 ++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv/version.h | 8 ++--- 5 files changed, 90 insertions(+), 6 deletions(-) diff --git a/.mailmap b/.mailmap index 97f5d1f2c00..f5d5375e044 100644 --- a/.mailmap +++ b/.mailmap @@ -52,6 +52,7 @@ San-Tai Hsu Santiago Gimeno Saúl Ibarra Corretgé Saúl Ibarra Corretgé +Saúl Ibarra Corretgé Shigeki Ohtsu Shuowang (Wayne) Zhang TK-one diff --git a/AUTHORS b/AUTHORS index 041b7aff610..39550bbc535 100644 --- a/AUTHORS +++ b/AUTHORS @@ -588,5 +588,7 @@ Raihaan Shouhell Rialbat Adam Poul T Lomholt -dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Thad House +Julian A Avar C <28635807+julian-a-avar-c@users.noreply.github.com> +amcgoogan <105525867+amcgoogan@users.noreply.github.com> +Rafael Gonzaga diff --git a/ChangeLog b/ChangeLog index 68690b6fcca..006a9e1b415 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,84 @@ +2025.01.15, Version 1.50.0 (Stable) + +Changes since version 1.49.2: + +* ci: run macOS and iOS tests also on macOS 14 (Saúl Ibarra Corretgé) + +* unix,win: map ENOEXEC errno (Saúl Ibarra Corretgé) + +* test: skip multicast join test on ENOEXEC (Saúl Ibarra Corretgé) + +* ci: make sure the macOS firewall is disabled (Saúl Ibarra Corretgé) + +* darwin,test: squelch EBUSY error on multicast join (Saúl Ibarra Corretgé) + +* build: update minimum cmake to 3.10 (Ben Noordhuis) + +* kqueue: use EVFILT_USER for async if available (Jameson Nash) + +* unix,win: fix off-by-one in uv_wtf8_to_utf16() (Ben Noordhuis) + +* doc: add scala-native-loop to LINKS.md (Julian A Avar C) + +* unix: fix build breakage on haiku, openbsd, etc (Jeffrey H. Johnson) + +* kqueue: lower overhead in uv__io_check_fd (Andy Pan) + +* doc: move cjihrig back to active maintainers (cjihrig) + +* build(deps): bump actions/checkout from 3 to 4 (dependabot[bot]) + +* unix,pipe: fix handling null buffer in uv_pipe_get{sock,peer}name (Saúl + Ibarra Corretgé) + +* unix,win: harmonize buffer checking (Saúl Ibarra Corretgé) + +* unix,win: add support for detached threads (Juan José Arboleda) + +* src: add uv_thread_set/getname() methods (Santiago Gimeno) + +* build: fix qemu builds (Ben Noordhuis) + +* win: drop support for windows 8 (Ben Noordhuis) + +* linux: fix uv_cpu_info() arm cpu model detection (Ben Noordhuis) + +* linux: always use io_uring for epoll batching (Ben Noordhuis) + +* doc: clarify repeating timer behavior more (Ben Noordhuis) + +* unix,win: handle nbufs=0 in uv_udp_try_send (Ben Noordhuis) + +* win: use GetQueuedCompletionStatusEx directly (Saúl Ibarra Corretgé) + +* win: enable uv_thread_{get,set}name on MinGW (Saúl Ibarra Corretgé) + +* win: drop support for the legacy MinGW (Saúl Ibarra Corretgé) + +* win,fs: get (most) fstat when no permission (Jameson Nash) + +* win: plug uv_fs_event_start memory leak (amcgoogan) + +* test: address FreeBSD kernel bug causing NULL path in fsevents (Juan José + Arboleda) + +* unix: refactor udp sendmsg code (Ben Noordhuis) + +* unix,win: add uv_udp_try_send2 (Ben Noordhuis) + +* test: fix flaky flaky udp_mmsg test (Juan José Arboleda) + +* build: enable fdsan in Android (Juan José Arboleda) + +* test: fix udp-multicast-join for FreeBSD (Juan José Arboleda) + +* win: fix leak processing fs event (Saúl Ibarra Corretgé) + +* src: set a default thread name for workers (Rafael Gonzaga) + +* misc: implement uv_getrusage_thread (Juan José Arboleda) + + 2024.10.18, Version 1.49.2 (Stable), e1095c7a4373ce00cd8874d8e820de5afb25776e Changes since version 1.49.1: diff --git a/configure.ac b/configure.ac index a89f58628ba..fc8316b8e8f 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.49.3-dev], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.50.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 04af319ae35..76eb7d125fe 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 49 -#define UV_VERSION_PATCH 3 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 50 +#define UV_VERSION_PATCH 0 +#define UV_VERSION_IS_RELEASE 1 +#define UV_VERSION_SUFFIX "" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From a2ba04f83f05fe46ce8758482749f5dd39029c9a Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 15 Jan 2025 19:05:30 +0100 Subject: [PATCH 675/713] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 006a9e1b415..b2770e60004 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2025.01.15, Version 1.50.0 (Stable) +2025.01.15, Version 1.50.0 (Stable), 8fb9cb919489a48880680a56efecff6a7dfb4504 Changes since version 1.49.2: From 0f31978c303b76798ff2b72e9498e5520722ef8a Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 15 Jan 2025 19:11:00 +0100 Subject: [PATCH 676/713] Now working on version 1.50.1 --- configure.ac | 2 +- include/uv/version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index fc8316b8e8f..95a32149ca1 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.50.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.50.1-dev], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/include/uv/version.h b/include/uv/version.h index 76eb7d125fe..6356e1ee44c 100644 --- a/include/uv/version.h +++ b/include/uv/version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 50 -#define UV_VERSION_PATCH 0 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 1 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From f15c602bd048a42be17281bf0f0d0ec9d6015ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 24 Jan 2025 09:59:55 +0100 Subject: [PATCH 677/713] win: fix leak in uv_os_tmpdir Fixes: https://github.com/libuv/libuv/issues/4680 --- src/win/util.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/win/util.c b/src/win/util.c index 1d1b2837e1a..57061bf8d70 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1016,6 +1016,7 @@ int uv_os_homedir(char* buffer, size_t* size) { int uv_os_tmpdir(char* buffer, size_t* size) { + int r; wchar_t *path; size_t len; @@ -1054,7 +1055,9 @@ int uv_os_tmpdir(char* buffer, size_t* size) { path[len] = L'\0'; } - return uv__copy_utf16_to_utf8(path, len, buffer, size); + r = uv__copy_utf16_to_utf8(path, len, buffer, size); + uv__free(path); + return r; } From bc19beadbd9fdc0f0ddbff30daa3ef1851a5ab47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 24 Jan 2025 13:41:36 +0100 Subject: [PATCH 678/713] docs: fix RTD build Setting the configuration key is now mandatory: https://about.readthedocs.com/blog/2024/12/deprecate-config-files-without-sphinx-or-mkdocs-config/ --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index b16bf0d4ab7..5290ec33e89 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -2,7 +2,7 @@ version: 2 sphinx: builder: html - configuration: null + configuration: docs/src/conf.py fail_on_warning: false build: From 82351168b3e11bb02dba2529aa875dd001d03ff2 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 24 Jan 2025 21:53:22 +0100 Subject: [PATCH 679/713] win: lazy-load [GS]etThreadDescription symbols (#4679) Said symbols are not by default available on Windows Server 2016 but libuv can still use them when api-ms-win-core-processthreads-l1-1-3.dll is present. Fixes: https://github.com/libuv/libuv/issues/4677 --- docs/src/threading.rst | 4 ++++ src/win/thread.c | 28 ++++++++++++++++++++++++++-- src/win/winapi.h | 9 --------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/docs/src/threading.rst b/docs/src/threading.rst index f40cf0a33c8..2edf3a89938 100644 --- a/docs/src/threading.rst +++ b/docs/src/threading.rst @@ -146,6 +146,8 @@ Threads a thread name can be: Linux, IBM i (16), macOS (64), Windows (32767), and NetBSD (32), etc. `uv_thread_setname()` will truncate it in case `name` is larger than the limit of the platform. + Not supported on Windows Server 2016, returns `UV_ENOSYS`. + .. versionadded:: 1.50.0 .. c:function:: int uv_thread_getname(uv_thread_t* tid, char* name, size_t* size) @@ -155,6 +157,8 @@ Threads The buffer should be large enough to hold the name of the thread plus the trailing NUL, or it will be truncated to fit with the trailing NUL. + Not supported on Windows Server 2016, returns `UV_ENOSYS`. + .. versionadded:: 1.50.0 .. c:function:: int uv_thread_setpriority(uv_thread_t tid, int priority) diff --git a/src/win/thread.c b/src/win/thread.c index 436846a7168..753cb6a34a5 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -57,6 +57,9 @@ STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*)); static uv_key_t uv__current_thread_key; static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT; +static uv_once_t uv__thread_name_once = UV_ONCE_INIT; +HRESULT (WINAPI *pGetThreadDescription)(HANDLE, PWSTR*); +HRESULT (WINAPI *pSetThreadDescription)(HANDLE, PCWSTR); static void uv__init_current_thread_key(void) { @@ -278,12 +281,28 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { } +static void uv__thread_name_init_once(void) { + HMODULE m; + + m = GetModuleHandleA("api-ms-win-core-processthreads-l1-1-3.dll"); + if (m != NULL) { + pGetThreadDescription = (void*) GetProcAddress(m, "GetThreadDescription"); + pSetThreadDescription = (void*) GetProcAddress(m, "SetThreadDescription"); + } +} + + int uv_thread_setname(const char* name) { HRESULT hr; WCHAR* namew; int err; char namebuf[UV_PTHREAD_MAX_NAMELEN_NP]; + uv_once(&uv__thread_name_once, uv__thread_name_init_once); + + if (pSetThreadDescription == NULL) + return UV_ENOSYS; + if (name == NULL) return UV_EINVAL; @@ -295,7 +314,7 @@ int uv_thread_setname(const char* name) { if (err) return err; - hr = SetThreadDescription(GetCurrentThread(), namew); + hr = pSetThreadDescription(GetCurrentThread(), namew); uv__free(namew); if (FAILED(hr)) return uv_translate_sys_error(HRESULT_CODE(hr)); @@ -312,6 +331,11 @@ int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) { int r; DWORD exit_code; + uv_once(&uv__thread_name_once, uv__thread_name_init_once); + + if (pGetThreadDescription == NULL) + return UV_ENOSYS; + if (name == NULL || size == 0) return UV_EINVAL; @@ -324,7 +348,7 @@ int uv_thread_getname(uv_thread_t* tid, char* name, size_t size) { namew = NULL; thread_name = NULL; - hr = GetThreadDescription(*tid, &namew); + hr = pGetThreadDescription(*tid, &namew); if (FAILED(hr)) return uv_translate_sys_error(HRESULT_CODE(hr)); diff --git a/src/win/winapi.h b/src/win/winapi.h index 4e0ccc61baf..47c34622ff7 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4828,13 +4828,4 @@ 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_ */ From a6ddf41edfe99a88174352ac8a7970bd06ccbe28 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 28 Jan 2025 09:27:58 +0100 Subject: [PATCH 680/713] linux: try preadv64/pwritev64 before preadv/pwritev (#4683) Fixes: https://github.com/libuv/libuv/issues/4678 Refs: https://github.com/libuv/libuv/issues/4532 --- src/unix/fs.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 239ecda16a7..1631d9340bc 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -461,12 +461,7 @@ static ssize_t uv__pwritev_emul(int fd, /* The function pointer cache is an uintptr_t because _Atomic void* * doesn't work on macos/ios/etc... - * Disable optimization on armv7 to work around the bug described in - * https://github.com/libuv/libuv/issues/4532 */ -#if defined(__arm__) && (__ARM_ARCH == 7) -__attribute__((optimize("O0"))) -#endif static ssize_t uv__preadv_or_pwritev(int fd, const struct iovec* bufs, size_t nbufs, @@ -479,7 +474,12 @@ static ssize_t uv__preadv_or_pwritev(int fd, p = (void*) atomic_load_explicit(cache, memory_order_relaxed); if (p == NULL) { #ifdef RTLD_DEFAULT - p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev"); + /* Try _LARGEFILE_SOURCE version of preadv/pwritev first, + * then fall back to the plain version, for libcs like musl. + */ + p = dlsym(RTLD_DEFAULT, is_pread ? "preadv64" : "pwritev64"); + if (p == NULL) + p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev"); dlerror(); /* Clear errors. */ #endif /* RTLD_DEFAULT */ if (p == NULL) @@ -487,10 +487,7 @@ static ssize_t uv__preadv_or_pwritev(int fd, atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed); } - /* Use memcpy instead of `f = p` to work around a compiler bug, - * see https://github.com/libuv/libuv/issues/4532 - */ - memcpy(&f, &p, sizeof(p)); + f = p; return f(fd, bufs, nbufs, off); } From 23632e9104b6506d5bee0d85b807c2351617d226 Mon Sep 17 00:00:00 2001 From: Morten Engelhardt Olsen Date: Wed, 29 Jan 2025 14:51:06 -0700 Subject: [PATCH 681/713] win: check cwd length before spawning a child process The CreateProcess API on Windows is still not longPathAware, even if the process itself is. So, if the cwd used for CreateProcess is too long, then the call fails with a 'INVALID_DIRECTORY' error. To deal with this, check the length of the cwd and shorten it if it is longer than MAX_PATH. --- src/win/process.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index 9d48ddc6f84..27605ca36f4 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -898,7 +898,7 @@ int uv_spawn(uv_loop_t* loop, *env = NULL, *cwd = NULL; STARTUPINFOW startup; PROCESS_INFORMATION info; - DWORD process_flags; + DWORD process_flags, cwd_len; BYTE* child_stdio_buffer; uv__process_init(loop, process); @@ -947,9 +947,10 @@ int uv_spawn(uv_loop_t* loop, if (err) goto done_uv; + cwd_len = wcslen(cwd); } else { /* Inherit cwd */ - DWORD cwd_len, r; + DWORD r; cwd_len = GetCurrentDirectoryW(0, NULL); if (!cwd_len) { @@ -970,6 +971,15 @@ int uv_spawn(uv_loop_t* loop, } } + /* If cwd is too long, shorten it */ + if (cwd_len >= MAX_PATH) { + cwd_len = GetShortPathNameW(cwd, cwd, cwd_len); + if (cwd_len == 0) { + err = GetLastError(); + goto done; + } + } + /* Get PATH environment variable. */ path = find_path(env); if (path == NULL) { From 51477bc71107637173bd974a3b10f682ac71bd9a Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 4 Feb 2025 22:43:18 +0200 Subject: [PATCH 682/713] macos,bsd: handle missing /dev/null in chroot env (#4689) Co-authored-by: Ben Noordhuis --- src/unix/async.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/async.c b/src/unix/async.c index 8265a43ab47..75a181bc1be 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -280,7 +280,7 @@ static int uv__async_start(uv_loop_t* loop) { * 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); + err = uv__open_cloexec("/", O_RDONLY); if (err < 0) return err; From e399e00e7828a47a92f3a2a35ab56740b176bbe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Jord=C3=A1n?= Date: Sat, 8 Feb 2025 15:42:12 +0100 Subject: [PATCH 683/713] doc: fix README link text (#4693) --- docs/src/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/index.rst b/docs/src/index.rst index 5bdb4be84b6..448de4066d6 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -58,5 +58,5 @@ libuv can be downloaded from `here `_. Installation ------------ -Installation instructions can be found in `the README `_. +Installation instructions can be found in the `README `_. From abe59d6319973cbff0686f41869cf8ae50bab1d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= Date: Mon, 10 Feb 2025 13:09:55 +0300 Subject: [PATCH 684/713] win: fix order of FILE_STAT_BASIC_INFORMATION struct fields --- src/win/winapi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/winapi.h b/src/win/winapi.h index 47c34622ff7..b9c9f1abc88 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4145,8 +4145,8 @@ typedef struct _FILE_STAT_BASIC_INFORMATION { ULONG DeviceType; ULONG DeviceCharacteristics; ULONG Reserved; - FILE_ID_128 FileId128; LARGE_INTEGER VolumeSerialNumber; + FILE_ID_128 FileId128; } FILE_STAT_BASIC_INFORMATION; #endif From 7894072528b56b566fd9cbd0124ae7a686d81999 Mon Sep 17 00:00:00 2001 From: Jinho Jang Date: Tue, 11 Feb 2025 00:07:50 +0900 Subject: [PATCH 685/713] macos: increase child process stdio buffer size (#4694) On macOS, when calling `spawn`, the child process's stdio buffer size is 8192 bytes. This is due to the AF_UNIX socket buffer size being 8192 bytes in the XNU kernel. When large amounts of data are transferred through the child process's stdio, this buffer size can cause performance issues. To mitigate this, the buffer size has been increased to 65536 bytes, aligning it with the behavior on Linux. --- src/unix/process.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index f2038f2c0e8..43e6b798458 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -188,8 +188,12 @@ void uv__wait_children(uv_loop_t* loop) { static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { int mask; int fd; + int ret; + int size; + int i; mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM; + size = 64 * 1024; switch (container->flags & mask) { case UV_IGNORE: @@ -199,8 +203,17 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { assert(container->data.stream != NULL); if (container->data.stream->type != UV_NAMED_PIPE) return UV_EINVAL; - else - return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0); + else { + ret = uv_socketpair(SOCK_STREAM, 0, fds, 0, 0); + + if (ret == 0) + for (i = 0; i < 2; i++) { + setsockopt(fds[i], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); + setsockopt(fds[i], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); + } + } + + return ret; case UV_INHERIT_FD: case UV_INHERIT_STREAM: From 378edb28f4bc6fb2414fd07ce2dabd9ccbda81ff Mon Sep 17 00:00:00 2001 From: Velikiy Kirill Date: Sat, 15 Feb 2025 19:11:35 +0300 Subject: [PATCH 686/713] doc: add C3 bindings to LINKS.md (#4699) --- LINKS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/LINKS.md b/LINKS.md index 743935cebb8..9f286ea3e92 100644 --- a/LINKS.md +++ b/LINKS.md @@ -108,3 +108,5 @@ * [node.pas](https://github.com/vovach777/node.pas) NodeJS-like ecosystem * Haskell * [Z.Haskell](https://z.haskell.world) +* C3 + * [libuv.c3l](https://github.com/velikoss/libuv.c3l) From dcace2a393a22650100e8a89debe168e92970ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Arboleda?= Date: Sat, 15 Feb 2025 19:58:50 -0500 Subject: [PATCH 687/713] unix: remove unnecessary errno.h include in poll.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juan José Arboleda --- src/unix/poll.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/unix/poll.c b/src/unix/poll.c index 7a12e2d1488..535ac6baafc 100644 --- a/src/unix/poll.c +++ b/src/unix/poll.c @@ -24,7 +24,6 @@ #include #include -#include static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { From 82cdfb75ff9bbd0dc65820ca418b7c5d412ff4d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20A=C3=A7acak?= Date: Fri, 14 Feb 2025 16:31:22 +0300 Subject: [PATCH 688/713] win: fix the inconsistency in volume serial number --- src/win/fs.c | 4 ++-- test/test-fs.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index a4742aa2ec1..b4ed760e86d 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1788,7 +1788,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, SetLastError(pRtlNtStatusToDosError(nt_status)); return -1; } else { - stat_info.VolumeSerialNumber.QuadPart = volume_info.VolumeSerialNumber; + stat_info.VolumeSerialNumber.LowPart = volume_info.VolumeSerialNumber; } stat_info.DeviceType = device_info.DeviceType; @@ -1839,7 +1839,7 @@ INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf) { INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf, FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat) { - statbuf->st_dev = stat_info.VolumeSerialNumber.QuadPart; + statbuf->st_dev = stat_info.VolumeSerialNumber.LowPart; /* Todo: st_mode should probably always be 0666 for everyone. We might also * want to report 0777 if the file is a .exe or a directory. diff --git a/test/test-fs.c b/test/test-fs.c index 423d72dd2f7..2519e44ccad 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1607,6 +1607,50 @@ TEST_IMPL(fs_fstat) { } +TEST_IMPL(fs_fstat_st_dev) { + uv_fs_t req; + uv_fs_t req_link; + uv_loop_t* loop = uv_default_loop(); + char* test_file = "tmp_st_dev"; + char* symlink_file = "tmp_st_dev_link"; + + unlink(test_file); + unlink(symlink_file); + + // Create file + int r = uv_fs_open(NULL, &req, test_file, UV_FS_O_RDWR | UV_FS_O_CREAT, + S_IWUSR | S_IRUSR, NULL); + ASSERT_GE(r, 0); + ASSERT_GE(req.result, 0); + uv_fs_req_cleanup(&req); + + // Create a symlink + r = uv_fs_symlink(loop, &req, test_file, symlink_file, 0, NULL); + ASSERT_EQ(r, 0); + uv_fs_req_cleanup(&req); + + // Call uv_fs_fstat for file + r = uv_fs_stat(loop, &req, test_file, NULL); + ASSERT_EQ(r, 0); + + // Call uv_fs_fstat for symlink + r = uv_fs_stat(loop, &req_link, symlink_file, NULL); + ASSERT_EQ(r, 0); + + // Compare st_dev + ASSERT_EQ(((uv_stat_t*)req.ptr)->st_dev, ((uv_stat_t*)req_link.ptr)->st_dev); + + // Cleanup + uv_fs_req_cleanup(&req); + uv_fs_req_cleanup(&req_link); + unlink(test_file); + unlink(symlink_file); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + + TEST_IMPL(fs_fstat_stdio) { int fd; int res; diff --git a/test/test-list.h b/test/test-list.h index c6651299c12..5aa71f59d25 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -364,6 +364,7 @@ TEST_DECLARE (fs_mkdtemp) TEST_DECLARE (fs_mkstemp) TEST_DECLARE (fs_fstat) TEST_DECLARE (fs_fstat_stdio) +TEST_DECLARE (fs_fstat_st_dev) TEST_DECLARE (fs_access) TEST_DECLARE (fs_chmod) TEST_DECLARE (fs_copyfile) @@ -1083,6 +1084,7 @@ TASK_LIST_START TEST_ENTRY (fs_mkstemp) TEST_ENTRY (fs_fstat) TEST_ENTRY (fs_fstat_stdio) + TEST_ENTRY (fs_fstat_st_dev) TEST_ENTRY (fs_access) TEST_ENTRY (fs_chmod) TEST_ENTRY (fs_copyfile) From b807450e982a0e486d3bb266c4314d08ab4eabd2 Mon Sep 17 00:00:00 2001 From: rainlow <37818892+rainlow@users.noreply.github.com> Date: Sat, 22 Feb 2025 05:01:16 +0800 Subject: [PATCH 689/713] unix: add thread affinity support on openharmony (#4705) --- src/unix/thread.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/thread.c b/src/unix/thread.c index e51c290466d..34fea364aeb 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -214,7 +214,7 @@ int uv_thread_setaffinity(uv_thread_t* tid, if (cpumask[i]) CPU_SET(i, &cpuset); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__OHOS__) if (sched_setaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset)) r = errno; else @@ -242,7 +242,7 @@ int uv_thread_getaffinity(uv_thread_t* tid, return UV_EINVAL; CPU_ZERO(&cpuset); -#if defined(__ANDROID__) +#if defined(__ANDROID__) || defined(__OHOS__) if (sched_getaffinity(pthread_gettid_np(*tid), sizeof(cpuset), &cpuset)) r = errno; else From 8a94b7b2ec23abc57c5a0bf36c808bc6dcc0ce4f Mon Sep 17 00:00:00 2001 From: Paolo Insogna Date: Fri, 21 Feb 2025 22:02:18 +0100 Subject: [PATCH 690/713] unix: enable getrusage for SunOS (#4707) Fixes: https://github.com/libuv/libuv/issues/4706 --- src/unix/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/unix/core.c b/src/unix/core.c index 61cbc0d027f..e64ea81d6ab 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1078,6 +1078,8 @@ int uv_getrusage_thread(uv_rusage_t* rusage) { return 0; +#elif defined(RUSAGE_LWP) + return uv__getrusage(RUSAGE_LWP, rusage); #elif defined(RUSAGE_THREAD) return uv__getrusage(RUSAGE_THREAD, rusage); #endif /* defined(__APPLE__) */ From 85b526f56ac0ca5e76de5cbc0e1e9452f73a01d5 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 21 Feb 2025 23:08:15 +0100 Subject: [PATCH 691/713] unix,win: accept NAN/INFINITY as file timestamps (#4702) Extend uv_fs_utime, uv_fs_futime and uv_fs_lutime to accept NAN and INFINITY, with NAN meaning "don't touch the timestamp" and INFINITY meaning "set to the current timestamp." Ugly, but it avoids having to add uv_fs_utime2, etc. UV_FS_UTIME_NOW and UV_FS_UTIME_OMIT constants have been added to make it more palatable. Fixes: https://github.com/libuv/libuv/issues/4665 --- docs/src/fs.rst | 6 ++ include/uv.h | 3 + src/unix/fs.c | 99 ++++++++++------------ src/uv-common.h | 19 +++++ src/win/fs.c | 25 ++++-- test/test-fs.c | 221 +++++++++++++++++++++++++++++++++++++++--------- 6 files changed, 270 insertions(+), 103 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 7bc8d0cbfd1..01a48e8edd8 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -430,6 +430,12 @@ API Equivalent to :man:`utime(2)`, :man:`futimes(3)` and :man:`lutimes(3)` respectively. + Passing `UV_FS_UTIME_NOW` as the atime or mtime sets the timestamp to the + current time. + + Passing `UV_FS_UTIME_OMIT` as the atime or mtime leaves the timestamp + untouched. + .. note:: z/OS: `uv_fs_lutime()` is not implemented for z/OS. It can still be called but will return ``UV_ENOSYS``. diff --git a/include/uv.h b/include/uv.h index f0ec376b607..46dedc9ebd7 100644 --- a/include/uv.h +++ b/include/uv.h @@ -58,6 +58,7 @@ extern "C" { #include #include #include +#include /* Internal type, do not use. */ struct uv__queue { @@ -1585,6 +1586,8 @@ UV_EXTERN int uv_fs_chmod(uv_loop_t* loop, const char* path, int mode, uv_fs_cb cb); +#define UV_FS_UTIME_NOW (INFINITY) +#define UV_FS_UTIME_OMIT (NAN) UV_EXTERN int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, diff --git a/src/unix/fs.c b/src/unix/fs.c index 1631d9340bc..717f3fab369 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -203,8 +203,23 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { } -UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) { +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) +static struct timespec uv__fs_to_timespec(double time) { struct timespec ts; + + if (uv__isinf(time)) + return (struct timespec){UTIME_NOW, UTIME_NOW}; + if (uv__isnan(time)) + return (struct timespec){UTIME_OMIT, UTIME_OMIT}; + ts.tv_sec = time; ts.tv_nsec = (time - ts.tv_sec) * 1e9; @@ -221,41 +236,23 @@ UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) { } return ts; } +#endif -UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) { - struct timeval tv; - tv.tv_sec = time; - tv.tv_usec = (time - tv.tv_sec) * 1e6; - if (tv.tv_usec < 0) { - tv.tv_usec += 1e6; - tv.tv_sec -= 1; - } - return tv; -} static ssize_t uv__fs_futime(uv_fs_t* req) { -#if defined(__linux__) \ +#if defined(__APPLE__) \ || defined(_AIX71) \ - || defined(__HAIKU__) \ - || defined(__GNU__) - struct timespec ts[2]; - ts[0] = uv__fs_to_timespec(req->atime); - ts[1] = uv__fs_to_timespec(req->mtime); - return futimens(req->file, ts); -#elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ || defined(__NetBSD__) \ || defined(__OpenBSD__) \ + || defined(__linux__) \ || defined(__sun) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); -# if defined(__sun) - return futimesat(req->file, NULL, tv); -# else - return futimes(req->file, tv); -# endif + struct timespec ts[2]; + ts[0] = uv__fs_to_timespec(req->atime); + ts[1] = uv__fs_to_timespec(req->mtime); + return futimens(req->file, ts); #elif defined(__MVS__) attrib_t atr; memset(&atr, 0, sizeof(atr)); @@ -1142,25 +1139,20 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { static ssize_t uv__fs_utime(uv_fs_t* req) { -#if defined(__linux__) \ - || defined(_AIX71) \ - || defined(__sun) \ - || defined(__HAIKU__) +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); return utimensat(AT_FDCWD, req->path, ts, 0); -#elif defined(__APPLE__) \ - || defined(__DragonFly__) \ - || defined(__FreeBSD__) \ - || defined(__NetBSD__) \ - || defined(__OpenBSD__) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); - return utimes(req->path, tv); -#elif defined(_AIX) \ - && !defined(_AIX71) +#elif defined(_AIX) && !defined(_AIX71) struct utimbuf buf; buf.actime = req->atime; buf.modtime = req->mtime; @@ -1181,24 +1173,19 @@ static ssize_t uv__fs_utime(uv_fs_t* req) { static ssize_t uv__fs_lutime(uv_fs_t* req) { -#if defined(__linux__) || \ - defined(_AIX71) || \ - defined(__sun) || \ - defined(__HAIKU__) || \ - defined(__GNU__) || \ - defined(__OpenBSD__) +#if defined(__APPLE__) \ + || defined(_AIX71) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__HAIKU__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__sun) struct timespec ts[2]; ts[0] = uv__fs_to_timespec(req->atime); ts[1] = uv__fs_to_timespec(req->mtime); return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW); -#elif defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__NetBSD__) - struct timeval tv[2]; - tv[0] = uv__fs_to_timeval(req->atime); - tv[1] = uv__fs_to_timeval(req->mtime); - return lutimes(req->path, tv); #else errno = ENOSYS; return -1; diff --git a/src/uv-common.h b/src/uv-common.h index 372f0c4b3ac..8e779ba5fcf 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "uv.h" #include "uv/tree.h" @@ -448,4 +449,22 @@ struct uv__loop_internal_fields_s { # define UV_PTHREAD_MAX_NAMELEN_NP 16 #endif +/* Open-coded so downstream users don't have to link libm. */ +static inline int uv__isinf(double d) { + uint64_t v; + + STATIC_ASSERT(sizeof(v) == sizeof(d)); + memcpy(&v, &d, sizeof(v)); + return (v << 1 >> 53) == 2047 && !(v << 12); +} + +/* Open-coded so downstream users don't have to link libm. */ +static inline int uv__isnan(double d) { + uint64_t v; + + STATIC_ASSERT(sizeof(v) == sizeof(d)); + memcpy(&v, &d, sizeof(v)); + return (v << 1 >> 53) == 2047 && !!(v << 12); +} + #endif /* UV_COMMON_H_ */ diff --git a/src/win/fs.c b/src/win/fs.c index b4ed760e86d..27248f644f3 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -2580,14 +2580,29 @@ static void fs__fchmod(uv_fs_t* req) { INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { - FILETIME filetime_a, filetime_m; + FILETIME filetime_as, *filetime_a = &filetime_as; + FILETIME filetime_ms, *filetime_m = &filetime_ms; + FILETIME now; - TIME_T_TO_FILETIME(atime, &filetime_a); - TIME_T_TO_FILETIME(mtime, &filetime_m); + if (uv__isinf(atime) || uv__isinf(mtime)) + GetSystemTimeAsFileTime(&now); - if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) { + if (uv__isinf(atime)) + filetime_a = &now; + else if (uv__isnan(atime)) + filetime_a = NULL; + else + TIME_T_TO_FILETIME(atime, filetime_a); + + if (uv__isinf(mtime)) + filetime_m = &now; + else if (uv__isnan(mtime)) + filetime_m = NULL; + else + TIME_T_TO_FILETIME(mtime, filetime_m); + + if (!SetFileTime(handle, NULL, filetime_a, filetime_m)) return -1; - } return 0; } diff --git a/test/test-fs.c b/test/test-fs.c index 2519e44ccad..4761b15bad1 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -59,6 +59,18 @@ #define TOO_LONG_NAME_LENGTH 65536 #define PATHMAX 4096 +#ifdef _WIN32 +static const int is_win32 = 1; +#else +static const int is_win32 = 0; +#endif + +#if defined(__APPLE__) || defined(__SUNPRO_C) +static const int is_apple_or_sunpro_c = 1; +#else +static const int is_apple_or_sunpro_c = 0; +#endif + typedef struct { const char* path; double atime; @@ -827,43 +839,70 @@ static void check_utime(const char* path, ASSERT_OK(req.result); s = &req.statbuf; - if (s->st_atim.tv_nsec == 0 && s->st_mtim.tv_nsec == 0) { - /* - * Test sub-second timestamps only when supported (such as Windows with + if (isfinite(atime)) { + /* Test sub-second timestamps only when supported (such as Windows with * NTFS). Some other platforms support sub-second timestamps, but that * support is filesystem-dependent. Notably OS X (HFS Plus) does NOT * support sub-second timestamps. But kernels may round or truncate in * either direction, so we may accept either possible answer. */ -#ifdef _WIN32 - ASSERT_DOUBLE_EQ(atime, (long) atime); - ASSERT_DOUBLE_EQ(mtime, (long) atime); -#endif - if (atime > 0 || (long) atime == atime) - ASSERT_EQ(s->st_atim.tv_sec, (long) atime); - if (mtime > 0 || (long) mtime == mtime) - ASSERT_EQ(s->st_mtim.tv_sec, (long) mtime); - ASSERT_GE(s->st_atim.tv_sec, (long) atime - 1); - ASSERT_GE(s->st_mtim.tv_sec, (long) mtime - 1); - ASSERT_LE(s->st_atim.tv_sec, (long) atime); - ASSERT_LE(s->st_mtim.tv_sec, (long) mtime); + if (s->st_atim.tv_nsec == 0) { + if (is_win32) + ASSERT_DOUBLE_EQ(atime, (long) atime); + if (atime > 0 || (long) atime == atime) + ASSERT_EQ(s->st_atim.tv_sec, (long) atime); + ASSERT_GE(s->st_atim.tv_sec, (long) atime - 1); + ASSERT_LE(s->st_atim.tv_sec, (long) atime); + } else { + double st_atim; + /* TODO(vtjnash): would it be better to normalize this? */ + if (!is_apple_or_sunpro_c) + ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); + st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; + /* Linux does not allow reading reliably the atime of a symlink + * since readlink() can update it + */ + if (!test_lutime) + ASSERT_DOUBLE_EQ(st_atim, atime); + } + } else if (isinf(atime)) { + /* We test with timestamps that are in the distant past + * (if you're a Gen Z-er) so check it's more recent than that. + */ + ASSERT_GT(s->st_atim.tv_sec, 1739710000); } else { - double st_atim; - double st_mtim; -#if !defined(__APPLE__) && !defined(__SUNPRO_C) - /* TODO(vtjnash): would it be better to normalize this? */ - ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0); - ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); -#endif - st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9; - st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; - /* - * Linux does not allow reading reliably the atime of a symlink - * since readlink() can update it + ASSERT_OK(0); + } + + if (isfinite(mtime)) { + /* Test sub-second timestamps only when supported (such as Windows with + * NTFS). Some other platforms support sub-second timestamps, but that + * support is filesystem-dependent. Notably OS X (HFS Plus) does NOT + * support sub-second timestamps. But kernels may round or truncate in + * either direction, so we may accept either possible answer. */ - if (!test_lutime) - ASSERT_DOUBLE_EQ(st_atim, atime); - ASSERT_DOUBLE_EQ(st_mtim, mtime); + if (s->st_mtim.tv_nsec == 0) { + if (is_win32) + ASSERT_DOUBLE_EQ(mtime, (long) atime); + if (mtime > 0 || (long) mtime == mtime) + ASSERT_EQ(s->st_mtim.tv_sec, (long) mtime); + ASSERT_GE(s->st_mtim.tv_sec, (long) mtime - 1); + ASSERT_LE(s->st_mtim.tv_sec, (long) mtime); + } else { + double st_mtim; + /* TODO(vtjnash): would it be better to normalize this? */ + if (!is_apple_or_sunpro_c) + ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0); + st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9; + ASSERT_DOUBLE_EQ(st_mtim, mtime); + } + } else if (isinf(mtime)) { + /* We test with timestamps that are in the distant past + * (if you're a Gen Z-er) so check it's more recent than that. + */ + ASSERT_GT(s->st_mtim.tv_sec, 1739710000); + } else { + ASSERT_OK(0); } uv_fs_req_cleanup(&req); @@ -2728,13 +2767,46 @@ TEST_IMPL(fs_utime) { atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */ - r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL); - ASSERT_OK(r); + ASSERT_OK(uv_fs_utime(NULL, &req, path, atime, mtime, NULL)); ASSERT_OK(req.result); uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_utime(NULL, + &req, + path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); check_utime(path, atime, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_utime(NULL, + &req, + path, + UV_FS_UTIME_NOW, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_utime(NULL, &req, path, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_utime(NULL, + &req, + path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_NOW, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 0); + atime = mtime = 1291404900.25; /* 2010-12-03 20:35:00.25 - mees <3 */ checkme.path = path; checkme.atime = atime; @@ -2868,9 +2940,43 @@ TEST_IMPL(fs_futime) { ASSERT_OK(req.result); #endif uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_futime(NULL, + &req, + file, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, mtime, /* test_lutime */ 0); + + ASSERT_OK(uv_fs_futime(NULL, + &req, + file, + UV_FS_UTIME_NOW, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_futime(NULL, &req, file, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); check_utime(path, atime, mtime, /* test_lutime */ 0); + ASSERT_OK(uv_fs_futime(NULL, + &req, + file, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_NOW, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 0); + atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */ checkme.atime = atime; @@ -2932,20 +3038,50 @@ TEST_IMPL(fs_lutime) { /* Test the synchronous version. */ atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */ - checkme.atime = atime; - checkme.mtime = mtime; - checkme.path = symlink_path; - req.data = &checkme; - r = uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL); -#if (defined(_AIX) && !defined(_AIX71)) || \ - defined(__MVS__) +#if (defined(_AIX) && !defined(_AIX71)) || defined(__MVS__) ASSERT_EQ(r, UV_ENOSYS); RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1"); #endif ASSERT_OK(r); - lutime_cb(&req); - ASSERT_EQ(1, lutime_cb_count); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, + &req, + symlink_path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, + &req, + symlink_path, + UV_FS_UTIME_NOW, + UV_FS_UTIME_OMIT, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, UV_FS_UTIME_NOW, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, mtime, /* test_lutime */ 1); + + ASSERT_OK(uv_fs_lutime(NULL, + &req, + symlink_path, + UV_FS_UTIME_OMIT, + UV_FS_UTIME_NOW, + NULL)); + ASSERT_OK(req.result); + uv_fs_req_cleanup(&req); + check_utime(symlink_path, atime, UV_FS_UTIME_NOW, /* test_lutime */ 1); /* Test the asynchronous version. */ atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */ @@ -2953,11 +3089,12 @@ TEST_IMPL(fs_lutime) { checkme.atime = atime; checkme.mtime = mtime; checkme.path = symlink_path; + req.data = &checkme; r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb); ASSERT_OK(r); uv_run(loop, UV_RUN_DEFAULT); - ASSERT_EQ(2, lutime_cb_count); + ASSERT_EQ(1, lutime_cb_count); /* Cleanup. */ unlink(path); From 843b64faf5fbbd19c04475bafa38c0c91514efb8 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 21 Feb 2025 23:34:53 +0100 Subject: [PATCH 692/713] win: add ENABLE_VIRTUAL_TERMINAL_INPUT raw tty mode (#4688) Windows provides the `ENABLE_VIRTUAL_TERMINAL_INPUT` flag for TTY input streams as a companion flag to `ENABLE_VIRTUAL_TERMINAL_PROCESSING`, which libuv is already setting for TTY output streams. Setting this flag lets the terminal emulator perform some of the processing that libuv already currently does for input events, but most notably enables receiving control sequences that are otherwise entirely unavailable, e.g. for bracketed paste (which the Node.js readline implementation added basic support for in https://github.com/nodejs/node/commit/87af913b66eab78088acfd). libuv currently already provides translations for key events to control sequences, i.e. what this mode is intended to provide, but libuv does not and cannot translate all such events. Since the control sequences differ from the ones that Windows has chosen to standardize on, and applications may not be expecting this change, this is opt-in for now (but ideally will be the default behavior starting in libuv v2.x, should that ever happen). Another downside of this change is that not all shells reset this mode when an application exits. For example, when running a Node.js program with this flag enabled inside of PowerShell in Windows terminal, if the application exits while in raw TTY input mode, neither the shell nor the terminal emulator reset this flag, rendering the input stream unusable. While there's general awareness of the problem that console state is global state rather than per-process (same as on UNIX platforms), it seems that applications like PowerShell aren't expecting to need to unset this flag on the input stream, only its output counterpart (e.g. https://github.com/PowerShell/PowerShell/blob/4e7942135f998ab40fd3ae298b020e161a76d4ef/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs#L1156). Hence, `uv_tty_reset_mode()` is extended to reset the terminal to its original state if the new mode is being used. Refs: https://github.com/nodejs/node/commit/87af913b66eab78088acfd7f3b57d35e22c5f1ba Refs: https://github.com/microsoft/terminal/issues/4954 --- docs/src/tty.rst | 9 +++- include/uv.h | 9 +++- include/uv/win.h | 7 ++- src/unix/tty.c | 7 +++ src/uv-common.h | 6 ++- src/win/tty.c | 80 ++++++++++++++++++++++++++--------- test/test-list.h | 6 ++- test/test-tty-duplicate-key.c | 62 ++++++++++++++++++++++++++- 8 files changed, 155 insertions(+), 31 deletions(-) diff --git a/docs/src/tty.rst b/docs/src/tty.rst index 7a2235210bf..b461b24437c 100644 --- a/docs/src/tty.rst +++ b/docs/src/tty.rst @@ -27,10 +27,15 @@ Data types typedef enum { /* Initial/normal terminal mode */ UV_TTY_MODE_NORMAL, - /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + /* + * Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled). + * May become equivalent to UV_TTY_MODE_RAW_VT in future libuv versions. + */ UV_TTY_MODE_RAW, /* Binary-safe I/O mode for IPC (Unix-only) */ - UV_TTY_MODE_IO + UV_TTY_MODE_IO, + /* Raw input mode. On Windows ENABLE_VIRTUAL_TERMINAL_INPUT is also set. */ + UV_TTY_MODE_RAW_VT } uv_tty_mode_t; .. c:enum:: uv_tty_vtermstate_t diff --git a/include/uv.h b/include/uv.h index 46dedc9ebd7..938e998fdc5 100644 --- a/include/uv.h +++ b/include/uv.h @@ -806,10 +806,15 @@ struct uv_tty_s { typedef enum { /* Initial/normal terminal mode */ UV_TTY_MODE_NORMAL, - /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */ + /* + * Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled). + * May become equivalent to UV_TTY_MODE_RAW_VT in future libuv versions. + */ UV_TTY_MODE_RAW, /* Binary-safe I/O mode for IPC (Unix-only) */ - UV_TTY_MODE_IO + UV_TTY_MODE_IO, + /* Raw input mode. On Windows ENABLE_VIRTUAL_TERMINAL_INPUT is also set. */ + UV_TTY_MODE_RAW_VT } uv_tty_mode_t; typedef enum { diff --git a/include/uv/win.h b/include/uv/win.h index 58d10b8d07f..a88bf29e9ff 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -499,8 +499,11 @@ typedef struct { union { \ struct { \ /* Used for readable TTY handles */ \ - /* TODO: remove me in v2.x. */ \ - HANDLE unused_; \ + union { \ + /* TODO: remove me in v2.x. */ \ + HANDLE unused_; \ + int mode; \ + } mode; \ uv_buf_t read_line_buffer; \ HANDLE read_raw_wait; \ /* Fields used for translating win keystrokes into vt100 characters */ \ diff --git a/src/unix/tty.c b/src/unix/tty.c index 793054ba5a9..b8610720267 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -284,6 +284,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { int fd; int rc; + if (uv__is_raw_tty_mode(mode)) { + /* There is only a single raw TTY mode on UNIX. */ + mode = UV_TTY_MODE_RAW; + } + if (tty->mode == (int) mode) return 0; @@ -324,6 +329,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { case UV_TTY_MODE_IO: uv__tty_make_raw(&tmp); break; + default: + UNREACHABLE(); } /* Apply changes after draining */ diff --git a/src/uv-common.h b/src/uv-common.h index 8e779ba5fcf..b9a8e976eef 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -126,7 +126,7 @@ enum { /* Only used by uv_tty_t handles. */ UV_HANDLE_TTY_READABLE = 0x01000000, - UV_HANDLE_TTY_RAW = 0x02000000, + UV_HANDLE_UNUSED0 = 0x02000000, UV_HANDLE_TTY_SAVED_POSITION = 0x04000000, UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000, @@ -141,6 +141,10 @@ enum { UV_HANDLE_REAP = 0x10000000 }; +static inline int uv__is_raw_tty_mode(uv_tty_mode_t m) { + return m == UV_TTY_MODE_RAW || m == UV_TTY_MODE_RAW_VT; +} + int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); void uv__loop_close(uv_loop_t* loop); diff --git a/src/win/tty.c b/src/win/tty.c index c0339ded2e4..66ca99cda83 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -58,6 +58,9 @@ #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endif +#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT +#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 +#endif #define CURSOR_SIZE_SMALL 25 #define CURSOR_SIZE_LARGE 100 @@ -119,7 +122,10 @@ static int uv_tty_virtual_width = -1; * handle signalling SIGWINCH */ -static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE; +static HANDLE uv__tty_console_handle_out = INVALID_HANDLE_VALUE; +static HANDLE uv__tty_console_handle_in = INVALID_HANDLE_VALUE; +static DWORD uv__tty_console_in_original_mode = (DWORD)-1; +static volatile LONG uv__tty_console_in_need_mode_reset = 0; static int uv__tty_console_height = -1; static int uv__tty_console_width = -1; static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE; @@ -159,19 +165,21 @@ static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED; static void uv__determine_vterm_state(HANDLE handle); void uv__console_init(void) { + DWORD dwMode; + if (uv_sem_init(&uv_tty_output_lock, 1)) abort(); - uv__tty_console_handle = CreateFileW(L"CONOUT$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - 0, - 0); - if (uv__tty_console_handle != INVALID_HANDLE_VALUE) { + uv__tty_console_handle_out = CreateFileW(L"CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + 0, + 0); + if (uv__tty_console_handle_out != INVALID_HANDLE_VALUE) { CONSOLE_SCREEN_BUFFER_INFO sb_info; uv_mutex_init(&uv__tty_console_resize_mutex); - if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) { + if (GetConsoleScreenBufferInfo(uv__tty_console_handle_out, &sb_info)) { uv__tty_console_width = sb_info.dwSize.X; uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; } @@ -179,6 +187,18 @@ void uv__console_init(void) { NULL, WT_EXECUTELONGFUNCTION); } + uv__tty_console_handle_in = CreateFileW(L"CONIN$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + 0, + OPEN_EXISTING, + 0, + 0); + if (uv__tty_console_handle_in != INVALID_HANDLE_VALUE) { + if (GetConsoleMode(uv__tty_console_handle_in, &dwMode)) { + uv__tty_console_in_original_mode = dwMode; + } + } } @@ -253,7 +273,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { /* Initialize TTY input specific fields. */ tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE; /* TODO: remove me in v2.x. */ - tty->tty.rd.unused_ = NULL; + tty->tty.rd.mode.unused_ = NULL; + /* Partially overwrites unused_ again. */ + tty->tty.rd.mode.mode = 0; tty->tty.rd.read_line_buffer = uv_null_buf_; tty->tty.rd.read_raw_wait = NULL; @@ -344,6 +366,7 @@ static void uv__tty_capture_initial_style( int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { DWORD flags; + DWORD try_set_flags; unsigned char was_reading; uv_alloc_cb alloc_cb; uv_read_cb read_cb; @@ -353,14 +376,19 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { return UV_EINVAL; } - if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) { + if ((int)mode == tty->tty.rd.mode.mode) { return 0; } + try_set_flags = 0; switch (mode) { case UV_TTY_MODE_NORMAL: flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; break; + case UV_TTY_MODE_RAW_VT: + try_set_flags = ENABLE_VIRTUAL_TERMINAL_INPUT; + InterlockedExchange(&uv__tty_console_in_need_mode_reset, 1); + /* fallthrough */ case UV_TTY_MODE_RAW: flags = ENABLE_WINDOW_INPUT; break; @@ -386,16 +414,16 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { } uv_sem_wait(&uv_tty_output_lock); - if (!SetConsoleMode(tty->handle, flags)) { + if (!SetConsoleMode(tty->handle, flags | try_set_flags) && + !SetConsoleMode(tty->handle, flags)) { err = uv_translate_sys_error(GetLastError()); uv_sem_post(&uv_tty_output_lock); return err; } uv_sem_post(&uv_tty_output_lock); - /* Update flag. */ - tty->flags &= ~UV_HANDLE_TTY_RAW; - tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0; + /* Update mode. */ + tty->tty.rd.mode.mode = mode; /* If we just stopped reading, restart. */ if (was_reading) { @@ -614,7 +642,7 @@ static void uv__tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { static void uv__tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) { - if (handle->flags & UV_HANDLE_TTY_RAW) { + if (uv__is_raw_tty_mode(handle->tty.rd.mode.mode)) { uv__tty_queue_read_raw(loop, handle); } else { uv__tty_queue_read_line(loop, handle); @@ -702,7 +730,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, handle->flags &= ~UV_HANDLE_READ_PENDING; if (!(handle->flags & UV_HANDLE_READING) || - !(handle->flags & UV_HANDLE_TTY_RAW)) { + !(uv__is_raw_tty_mode(handle->tty.rd.mode.mode))) { goto out; } @@ -1050,7 +1078,7 @@ int uv__tty_read_stop(uv_tty_t* handle) { if (!(handle->flags & UV_HANDLE_READ_PENDING)) return 0; - if (handle->flags & UV_HANDLE_TTY_RAW) { + if (uv__is_raw_tty_mode(handle->tty.rd.mode.mode)) { /* Cancel raw read. Write some bullshit event to force the console wait to * return. */ memset(&record, 0, sizeof record); @@ -2293,7 +2321,17 @@ void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { int uv_tty_reset_mode(void) { - /* Not necessary to do anything. */ + /** + * Shells on Windows do know to reset output flags after a program exits, + * but not necessarily input flags, so we do that for them. + */ + if ( + uv__tty_console_handle_in != INVALID_HANDLE_VALUE && + uv__tty_console_in_original_mode != (DWORD)-1 && + InterlockedExchange(&uv__tty_console_in_need_mode_reset, 0) != 0 + ) { + SetConsoleMode(uv__tty_console_handle_in, uv__tty_console_in_original_mode); + } return 0; } @@ -2390,7 +2428,7 @@ static void uv__tty_console_signal_resize(void) { CONSOLE_SCREEN_BUFFER_INFO sb_info; int width, height; - if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) + if (!GetConsoleScreenBufferInfo(uv__tty_console_handle_out, &sb_info)) return; width = sb_info.dwSize.X; diff --git a/test/test-list.h b/test/test-list.h index 5aa71f59d25..24dbcdd71c4 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -53,7 +53,8 @@ TEST_DECLARE (tty_raw) TEST_DECLARE (tty_empty_write) TEST_DECLARE (tty_large_write) TEST_DECLARE (tty_raw_cancel) -TEST_DECLARE (tty_duplicate_vt100_fn_key) +TEST_DECLARE (tty_duplicate_vt100_fn_key_libuv) +TEST_DECLARE (tty_duplicate_vt100_fn_key_winvt) TEST_DECLARE (tty_duplicate_alt_modifier_key) TEST_DECLARE (tty_composing_character) TEST_DECLARE (tty_cursor_up) @@ -636,7 +637,8 @@ TASK_LIST_START TEST_ENTRY (tty_empty_write) TEST_ENTRY (tty_large_write) TEST_ENTRY (tty_raw_cancel) - TEST_ENTRY (tty_duplicate_vt100_fn_key) + TEST_ENTRY (tty_duplicate_vt100_fn_key_libuv) + TEST_ENTRY (tty_duplicate_vt100_fn_key_winvt) TEST_ENTRY (tty_duplicate_alt_modifier_key) TEST_ENTRY (tty_composing_character) TEST_ENTRY (tty_cursor_up) diff --git a/test/test-tty-duplicate-key.c b/test/test-tty-duplicate-key.c index 871d580266a..e3e813e69b3 100644 --- a/test/test-tty-duplicate-key.c +++ b/test/test-tty-duplicate-key.c @@ -131,7 +131,7 @@ static void make_key_event_records(WORD virt_key, DWORD ctr_key_state, # undef KEV } -TEST_IMPL(tty_duplicate_vt100_fn_key) { +TEST_IMPL(tty_duplicate_vt100_fn_key_libuv) { int r; int ttyin_fd; uv_tty_t tty_in; @@ -163,6 +163,10 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) { r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read); ASSERT_OK(r); + /* + * libuv has chosen to emit ESC[[A, but other terminals, and even + * Windows itself use a different escape sequence, see the test below. + */ expect_str = ESC"[[A"; expect_nread = strlen(expect_str); @@ -184,6 +188,62 @@ TEST_IMPL(tty_duplicate_vt100_fn_key) { return 0; } +TEST_IMPL(tty_duplicate_vt100_fn_key_winvt) { + int r; + int ttyin_fd; + uv_tty_t tty_in; + uv_loop_t* loop; + HANDLE handle; + INPUT_RECORD records[2]; + DWORD written; + + loop = uv_default_loop(); + + /* Make sure we have an FD that refers to a tty */ + handle = CreateFileA("conin$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE); + ttyin_fd = _open_osfhandle((intptr_t) handle, 0); + ASSERT_GE(ttyin_fd, 0); + ASSERT_EQ(UV_TTY, uv_guess_handle(ttyin_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ + ASSERT_OK(r); + ASSERT(uv_is_readable((uv_stream_t*) &tty_in)); + ASSERT(!uv_is_writable((uv_stream_t*) &tty_in)); + + r = uv_read_start((uv_stream_t*)&tty_in, tty_alloc, tty_read); + ASSERT_OK(r); + + /* + * Some keys, like F1, get are assigned a different value by Windows + * in ENABLE_VIRTUAL_TERMINAL_INPUT mode vs. libuv in the test above. + */ + expect_str = ESC"OP"; + expect_nread = strlen(expect_str); + + /* Turn on raw mode. */ + r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW_VT); + ASSERT_OK(r); + + /* + * Send F1 keystroke. + */ + make_key_event_records(VK_F1, 0, TRUE, records); + WriteConsoleInputW(handle, records, ARRAY_SIZE(records), &written); + ASSERT_EQ(written, ARRAY_SIZE(records)); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + TEST_IMPL(tty_duplicate_alt_modifier_key) { int r; int ttyin_fd; From f61f9c29d8cd4a1213108b456e99e131375b680d Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Tue, 25 Feb 2025 13:22:10 -0500 Subject: [PATCH 693/713] test: handle UV_ENOTSUP in platform_output (#4714) Fixes: https://github.com/libuv/libuv/issues/4713 --- test/test-platform-output.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/test/test-platform-output.c b/test/test-platform-output.c index d9b39c744ff..06a8e484dd7 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -236,21 +236,24 @@ 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); + err = uv_getrusage_thread(&rusage); + if (err != UV_ENOTSUP) { + ASSERT_OK(err); + ASSERT_UINT64_GE(rusage.ru_utime.tv_sec, 0); + ASSERT_UINT64_GE(rusage.ru_utime.tv_usec, 0); + ASSERT_UINT64_GE(rusage.ru_stime.tv_sec, 0); + ASSERT_UINT64_GE(rusage.ru_stime.tv_usec, 0); + printf("uv_getrusage_thread:\n"); + printf(" user: %llu sec %llu microsec\n", + (unsigned long long) rusage.ru_utime.tv_sec, + (unsigned long long) rusage.ru_utime.tv_usec); + printf(" system: %llu sec %llu microsec\n", + (unsigned long long) rusage.ru_stime.tv_sec, + (unsigned long long) rusage.ru_stime.tv_usec); + printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt); + printf(" maximum resident set size: %llu\n", + (unsigned long long) rusage.ru_maxrss); + } return 0; } From feddddb56b8b5a0c5f09b21994dc279341666c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Wed, 26 Feb 2025 01:03:07 +0100 Subject: [PATCH 694/713] doc: fix rendering of threading.html (#4716) --- docs/src/threading.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/threading.rst b/docs/src/threading.rst index 2edf3a89938..27c1d6ee28a 100644 --- a/docs/src/threading.rst +++ b/docs/src/threading.rst @@ -162,6 +162,7 @@ Threads .. versionadded:: 1.50.0 .. c:function:: int uv_thread_setpriority(uv_thread_t tid, int priority) + If the function succeeds, the return value is 0. If the function fails, the return value is less than zero. Sets the scheduling priority of the thread specified by tid. It requires elevated @@ -169,7 +170,9 @@ Threads The priority can be set to the following constants. UV_THREAD_PRIORITY_HIGHEST, UV_THREAD_PRIORITY_ABOVE_NORMAL, UV_THREAD_PRIORITY_NORMAL, UV_THREAD_PRIORITY_BELOW_NORMAL, UV_THREAD_PRIORITY_LOWEST. + .. c:function:: int uv_thread_getpriority(uv_thread_t tid, int* priority) + If the function succeeds, the return value is 0. If the function fails, the return value is less than zero. Retrieves the scheduling priority of the thread specified by tid. The value in the From 436c04048e80ef7d985af6149f9087d7ed4602e4 Mon Sep 17 00:00:00 2001 From: Stacey Marshall Date: Thu, 27 Feb 2025 17:24:40 +0000 Subject: [PATCH 695/713] unix,sunos: enable use of sendmmsg on Solaris and Illumos (#4717) Solaris provides sendmmsg() as of 11.3.32. It was added at the same time as MSG_WAITFORONE. The same is seen in Illumos guarded by __BSD_VISIBLE Fixes: https://github.com/libuv/libuv/issues/4715 --- src/unix/udp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index 67c01f7dce8..12db36652c2 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -1298,7 +1298,8 @@ static int uv__udp_sendmsgv(int fd, r = 0; nsent = 0; -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ + (defined(__sun__) && defined(MSG_WAITFORONE)) if (count > 1) { for (i = 0; i < count; /*empty*/) { struct mmsghdr m[20]; @@ -1325,7 +1326,9 @@ static int uv__udp_sendmsgv(int fd, goto exit; } -#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) */ +#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || + * (defined(__sun__) && defined(MSG_WAITFORONE)) + */ for (i = 0; i < count; i++, nsent++) if ((r = uv__udp_sendmsg1(fd, bufs[i], nbufs[i], addrs[i]))) From 16d6a0b49dcfc15dbcd555fbe6b52517c6206297 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 27 Feb 2025 23:30:29 +0100 Subject: [PATCH 696/713] unix: handle out of memory in iface name copy (#4724) Allocate storage upfront, that way we can never run out of memory halfway through processing the interface list. Fixes: https://github.com/libuv/libuv/issues/4723 --- src/unix/aix.c | 20 ++++++++++---------- src/unix/bsd-ifaddrs.c | 27 ++++++++++++++------------- src/unix/ibmi.c | 19 ++++++++++--------- src/unix/linux.c | 28 ++++++++++++++++------------ src/unix/sunos.c | 21 +++++++++++---------- 5 files changed, 61 insertions(+), 54 deletions(-) diff --git a/src/unix/aix.c b/src/unix/aix.c index 3af3009a216..5aef7d1caee 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -1120,6 +1120,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifreq *ifr, *p, flg; struct in6_ifreq if6; struct sockaddr_dl* sa_addr; + size_t namelen; + char* name; ifc.ifc_req = NULL; sock6fd = -1; @@ -1156,6 +1158,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) /* Count all up and running ipv4/ipv6 addresses */ + namelen = 0; ifr = ifc.ifc_req; while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { p = ifr; @@ -1175,6 +1178,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -1182,8 +1186,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { goto cleanup; /* Alloc the return interface structs */ - *addresses = uv__calloc(*count, sizeof(**addresses)); - if (!(*addresses)) { + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); + if (*addresses == NULL) { r = UV_ENOMEM; goto cleanup; } @@ -1210,7 +1214,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* All conditions above must match count loop */ - address->name = uv__strdup(p->ifr_name); + namelen = strlen(p->ifr_name) + 1; + address->name = memcpy(name, p->ifr_name, namelen); + name += namelen; if (inet6) address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); @@ -1282,13 +1288,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - int i; - - for (i = 0; i < count; ++i) { - uv__free(addresses[i].name); - } - + int count) { uv__free(addresses); } diff --git a/src/unix/bsd-ifaddrs.c b/src/unix/bsd-ifaddrs.c index 11ca95591fc..8d9ebd25d43 100644 --- a/src/unix/bsd-ifaddrs.c +++ b/src/unix/bsd-ifaddrs.c @@ -65,13 +65,13 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return 0; } +/* TODO(bnoordhuis) share with linux.c */ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + uv_interface_address_t* address; struct ifaddrs* addrs; struct ifaddrs* ent; - uv_interface_address_t* address; -#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__) - int i; -#endif + size_t namelen; + char* name; *count = 0; *addresses = NULL; @@ -80,9 +80,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV__ERR(errno); /* Count the number of interfaces */ + namelen = 0; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -92,20 +94,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } /* Make sure the memory is initiallized to zero using calloc() */ - *addresses = uv__calloc(*count, sizeof(**addresses)); - + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); if (*addresses == NULL) { freeifaddrs(addrs); return UV_ENOMEM; } + name = (char*) &(*addresses)[*count]; address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; - address->name = uv__strdup(ent->ifa_name); + namelen = strlen(ent->ifa_name) + 1; + address->name = memcpy(name, ent->ifa_name, namelen); + name += namelen; if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); @@ -129,6 +133,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__) /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + int i; + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) continue; @@ -151,13 +157,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } +/* TODO(bnoordhuis) share with linux.c */ void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(addresses[i].name); - } - uv__free(addresses); } diff --git a/src/unix/ibmi.c b/src/unix/ibmi.c index 837bba6e2fe..fccce8b49b1 100644 --- a/src/unix/ibmi.c +++ b/src/unix/ibmi.c @@ -403,6 +403,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV_ENOSYS; /* The first loop to get the size of the array to be allocated */ + namelen = 0; for (cur = ifap; cur; cur = cur->ifa_next) { if (!(cur->ifa_addr->sa_family == AF_INET6 || cur->ifa_addr->sa_family == AF_INET)) @@ -411,6 +412,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING)) continue; + namelen += strlen(cur->ifa_name) + 1; (*count)++; } @@ -420,11 +422,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } /* Alloc the return interface structs */ - *addresses = uv__calloc(*count, sizeof(**addresses)); + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); if (*addresses == NULL) { Qp2freeifaddrs(ifap); return UV_ENOMEM; } + + name = (char*) &(*addresses)[*count]; address = *addresses; /* The second loop to fill in the array */ @@ -436,7 +440,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING)) continue; - address->name = uv__strdup(cur->ifa_name); + namelen = strlen(cur->ifa_name) + 1; + address->name = memcpy(name, cur->ifa_name, namelen); + name += namelen; inet6 = (cur->ifa_addr->sa_family == AF_INET6); @@ -497,13 +503,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } -void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { - int i; - - for (i = 0; i < count; ++i) { - uv__free(addresses[i].name); - } - +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { uv__free(addresses); } diff --git a/src/unix/linux.c b/src/unix/linux.c index 763f5dd5917..86c12b4f086 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -1954,11 +1954,15 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return !exclude_type; } +/* TODO(bnoordhuis) share with bsd-ifaddrs.c */ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - struct ifaddrs *addrs, *ent; uv_interface_address_t* address; + struct sockaddr_ll* sll; + struct ifaddrs* addrs; + struct ifaddrs* ent; + size_t namelen; + char* name; int i; - struct sockaddr_ll *sll; *count = 0; *addresses = NULL; @@ -1967,10 +1971,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV__ERR(errno); /* Count the number of interfaces */ + namelen = 0; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -1980,19 +1986,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } /* Make sure the memory is initiallized to zero using calloc() */ - *addresses = uv__calloc(*count, sizeof(**addresses)); - if (!(*addresses)) { + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); + if (*addresses == NULL) { freeifaddrs(addrs); return UV_ENOMEM; } + name = (char*) &(*addresses)[*count]; address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; - address->name = uv__strdup(ent->ifa_name); + namelen = strlen(ent->ifa_name) + 1; + address->name = memcpy(name, ent->ifa_name, namelen); + name += namelen; if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); @@ -2036,14 +2045,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } +/* TODO(bnoordhuis) share with bsd-ifaddrs.c */ void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(addresses[i].name); - } - + int count) { uv__free(addresses); } diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 2d6bae79604..84ce52a2da0 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -826,6 +826,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; struct ifaddrs* addrs; struct ifaddrs* ent; + size_t namelen; + char* name; *count = 0; *addresses = NULL; @@ -834,9 +836,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return UV__ERR(errno); /* Count the number of interfaces */ + namelen = 0; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent)) continue; + namelen += strlen(ent->ifa_name) + 1; (*count)++; } @@ -845,19 +849,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { return 0; } - *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) { + *addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen); + if (*addresses == NULL) { freeifaddrs(addrs); return UV_ENOMEM; } + name = (char*) &(*addresses)[*count]; address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent)) continue; - address->name = uv__strdup(ent->ifa_name); + namelen = strlen(ent->ifa_name) + 1; + address->name = memcpy(name, ent->ifa_name, namelen); + name += namelen; if (ent->ifa_addr->sa_family == AF_INET6) { address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); @@ -885,13 +892,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #endif /* SUNOS_NO_IFADDRS */ void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(addresses[i].name); - } - + int count) { uv__free(addresses); } From 545ecf515f4afe4ac0107028aec326727e08e680 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Mon, 3 Mar 2025 09:13:29 +0100 Subject: [PATCH 697/713] openbsd: do not error out if cpuspeed is not available (#4727) On OpenBSD we do not know the cpuspeed in same cases (mostly arm64) and the HW_CPUSPEED sysctl will return EOPNOTSUPP in that case, which can be ignored because we still need the rest of the CPU information. --- src/unix/openbsd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index 9c863b6c90d..cf20fa66582 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -211,8 +211,16 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { which[1] = HW_CPUSPEED; size = sizeof(cpuspeed); - if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0)) + cpuspeed = 0; + /* + * HW_CPUSPEED can return EOPNOTSUPP if cpuspeed is 0, + * so ignore that and continue the flow, because we + * still care about the rest of the CPU info. + */ + if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0) && + (errno != EOPNOTSUPP)) { goto error; + } size = sizeof(info); for (i = 0; i < numcpus; i++) { From 92eacd19a16bc1d0146524946bab3d672de1897f Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Mon, 3 Mar 2025 12:12:48 -0600 Subject: [PATCH 698/713] test: skip thread_name_threadpool on AIX/IBMi (#4731) uv_thread_getname is not available on aix and ibm i Same issue as thread_name test Refs: https://github.com/libuv/libuv/pull/4599#issuecomment-2498376606 --- test/test-thread-name.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test-thread-name.c b/test/test-thread-name.c index 378d82cf81b..39340744290 100644 --- a/test/test-thread-name.c +++ b/test/test-thread-name.c @@ -178,6 +178,10 @@ static void after_work_cb(uv_work_t* req, int status) { } TEST_IMPL(thread_name_threadpool) { + +#if defined(_AIX) || defined(__PASE__) + RETURN_SKIP("API not available on this platform"); +#endif uv_work_t req; loop = uv_default_loop(); // Just to make sure all workers will be executed From 352d992916814d04b847112072693079788e7343 Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Mon, 3 Mar 2025 20:08:09 +0000 Subject: [PATCH 699/713] aix,ibmi: fix undeclared identifiers (#4730) Refs: https://github.com/libuv/libuv/pull/4724 --- src/unix/aix.c | 3 ++- src/unix/ibmi.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/unix/aix.c b/src/unix/aix.c index 5aef7d1caee..48da0c9c40c 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -1178,7 +1178,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) continue; - namelen += strlen(ent->ifa_name) + 1; + namelen += strlen(p->ifr_name) + 1; (*count)++; } @@ -1191,6 +1191,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { r = UV_ENOMEM; goto cleanup; } + name = (char*) &(*addresses)[*count]; address = *addresses; ifr = ifc.ifc_req; diff --git a/src/unix/ibmi.c b/src/unix/ibmi.c index fccce8b49b1..9d94d2af544 100644 --- a/src/unix/ibmi.c +++ b/src/unix/ibmi.c @@ -394,6 +394,8 @@ static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) { int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; struct ifaddrs_pase *ifap = NULL, *cur; + size_t namelen; + char* name; int inet6, r = 0; *count = 0; From 98a4bab92a1d114b22445a413a0dd991841ade61 Mon Sep 17 00:00:00 2001 From: Stacey Marshall Date: Fri, 7 Mar 2025 21:22:48 +0000 Subject: [PATCH 700/713] unix,sunos: prefer SO_REUSEPORT for load balancing (#4733) Solaris 11.4 has Load Balancing for SO_REUSEPORT, but setting SO_REUSEADDR disables load balancing. As per comments in test/test-udp-reuseport.c prefer SO_REUSEPORT when available. With these changes in place udp-reuseport testing passes. BIND (named), which uses routing sockets which cause ENOPROTOOPT to be returned when SO_REUSEPORT is requested, also continues to work with the change. Notes: - The use of getsockopt() to query if SO_REUSEPORT was available was erroneous. - Selectively limiting SO_REUSEPORT setting to specific types of socket was considered but not entertained. - Oracle will investigate if the setting of SO_REUSEADDR was intentionally meant to prevent load balancing. - Adding a test for routing sockets is left for future work. --- src/unix/udp.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index 12db36652c2..c4a3559d61e 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -300,6 +300,9 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { * * zOS does not support getsockname with SO_REUSEPORT option when using * AF_UNIX. + * + * Solaris 11.4: SO_REUSEPORT will not load balance when SO_REUSEADDR + * is also set, but it's not valid for every socket type. */ static int uv__sock_reuseaddr(int fd) { int yes; @@ -317,8 +320,18 @@ static int uv__sock_reuseaddr(int fd) { if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); } -#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) && \ - !defined(__sun__) && !defined(__DragonFly__) && !defined(_AIX73) +#elif defined(SO_REUSEPORT) && defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4 + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) { + if (errno != ENOPROTOOPT) + return UV__ERR(errno); + /* Not all socket types accept SO_REUSEPORT. */ + errno = 0; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) + return UV__ERR(errno); + } +#elif defined(SO_REUSEPORT) && \ + !defined(__linux__) && !defined(__GNU__) && \ + !defined(__illumos__) && !defined(__DragonFly__) && !defined(_AIX73) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) return UV__ERR(errno); #else From c727be4df96d2f01af2fe1905c567c5a16fe1ae8 Mon Sep 17 00:00:00 2001 From: mugitya03 Date: Sun, 9 Mar 2025 16:47:27 -0400 Subject: [PATCH 701/713] doc: free lib pointer before function return (#4720) In function main, the pointer lib allocated at line 7 is passed as an argument to functions uv_dlopen at line 10, uv_dlerror at lines 11 and 17, and uv_dlsym at line 16, but it is never freed before the function returns at line 24. This results in a memory leak bug. --- docs/code/plugin/main.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/code/plugin/main.c b/docs/code/plugin/main.c index 06e581e63db..01335bbcb65 100644 --- a/docs/code/plugin/main.c +++ b/docs/code/plugin/main.c @@ -18,22 +18,21 @@ int main(int argc, char **argv) { return 0; } - uv_lib_t *lib = (uv_lib_t*) malloc(sizeof(uv_lib_t)); + uv_lib_t lib; while (--argc) { fprintf(stderr, "Loading %s\n", argv[argc]); - if (uv_dlopen(argv[argc], lib)) { - fprintf(stderr, "Error: %s\n", uv_dlerror(lib)); + if (uv_dlopen(argv[argc], &lib)) { + fprintf(stderr, "Error: %s\n", uv_dlerror(&lib)); continue; } init_plugin_function init_plugin; - if (uv_dlsym(lib, "initialize", (void **) &init_plugin)) { - fprintf(stderr, "dlsym error: %s\n", uv_dlerror(lib)); + if (uv_dlsym(&lib, "initialize", (void **) &init_plugin)) { + fprintf(stderr, "dlsym error: %s\n", uv_dlerror(&lib)); continue; } init_plugin(); } - return 0; } From 4681d5d5705be932f82e1e79eff72f17b5bf82e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Tue, 11 Mar 2025 04:18:24 -0500 Subject: [PATCH 702/713] test: link with libm (#4735) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/4734 Signed-off-by: Juan José Arboleda --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index af89db2dfc2..63be9480ca8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -434,6 +434,7 @@ endif() if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|Linux|NetBSD|OpenBSD") list(APPEND uv_test_libraries util) + list(APPEND uv_libraries m) endif() if(CYGWIN OR MSYS) From ea1cf034bef1ee39cf453b5b37b98be153541453 Mon Sep 17 00:00:00 2001 From: Mohammed Keyvanzadeh Date: Tue, 11 Mar 2025 01:47:12 +0330 Subject: [PATCH 703/713] style: rename parameter to match definition Rename the `handle` parameter of `timer_close_cb`'s declaration to `timer` to match the definition. --- src/fs-poll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fs-poll.c b/src/fs-poll.c index 44f6263a583..1fadafdea17 100644 --- a/src/fs-poll.c +++ b/src/fs-poll.c @@ -51,7 +51,7 @@ struct poll_ctx { static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b); static void poll_cb(uv_fs_t* req); static void timer_cb(uv_timer_t* timer); -static void timer_close_cb(uv_handle_t* handle); +static void timer_close_cb(uv_handle_t* timer); static uv_stat_t zero_statbuf; From 2b96e47f129419c09ae2188228a7c722ac07f0f1 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Mon, 24 Mar 2025 00:00:22 -0400 Subject: [PATCH 704/713] test: support partial output lines in test runner (#4744) This commit updates the test runner's print_lines() logic to better handle partial lines. --- test/runner-unix.c | 5 +++-- test/runner-win.c | 4 +++- test/runner.c | 16 ++++++++++++---- test/runner.h | 2 +- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/test/runner-unix.c b/test/runner-unix.c index 81560add820..3d14cb69b29 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -367,6 +367,7 @@ long int process_output_size(process_info_t *p) { /* Copy the contents of the stdio output buffer to `fd`. */ int process_copy_output(process_info_t* p, FILE* stream) { char buf[1024]; + int partial; int r; r = fseek(p->stdout_file, 0, SEEK_SET); @@ -375,9 +376,9 @@ int process_copy_output(process_info_t* p, FILE* stream) { return -1; } - /* TODO: what if the line is longer than buf */ + partial = 0; while ((r = fread(buf, 1, sizeof(buf), p->stdout_file)) != 0) - print_lines(buf, r, stream); + partial = print_lines(buf, r, stream, partial); if (ferror(p->stdout_file)) { perror("read"); diff --git a/test/runner-win.c b/test/runner-win.c index 6c6e35f7731..8035ca62f8e 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -219,6 +219,7 @@ long int process_output_size(process_info_t *p) { int process_copy_output(process_info_t* p, FILE* stream) { char buf[1024]; + int partial; int fd, r; fd = _open_osfhandle((intptr_t)p->stdio_out, _O_RDONLY | _O_TEXT); @@ -229,8 +230,9 @@ int process_copy_output(process_info_t* p, FILE* stream) { if (r < 0) return -1; + partial = 0; while ((r = _read(fd, buf, sizeof(buf))) != 0) - print_lines(buf, r, stream); + partial = print_lines(buf, r, stream, partial); _close(fd); return 0; diff --git a/test/runner.c b/test/runner.c index 54abb39dd22..87e7db0b05c 100644 --- a/test/runner.c +++ b/test/runner.c @@ -426,13 +426,17 @@ void print_tests(FILE* stream) { } -void print_lines(const char* buffer, size_t size, FILE* stream) { +int print_lines(const char* buffer, size_t size, FILE* stream, int partial) { const char* start; const char* end; start = buffer; while ((end = memchr(start, '\n', &buffer[size] - start))) { - fputs("# ", stream); + if (partial == 0) + fputs("# ", stream); + else + partial = 0; + fwrite(start, 1, (int)(end - start), stream); fputs("\n", stream); fflush(stream); @@ -441,9 +445,13 @@ void print_lines(const char* buffer, size_t size, FILE* stream) { end = &buffer[size]; if (start < end) { - fputs("# ", stream); + if (partial == 0) + fputs("# ", stream); + fwrite(start, 1, (int)(end - start), stream); - fputs("\n", stream); fflush(stream); + return 1; } + + return 0; } diff --git a/test/runner.h b/test/runner.h index 6801564f961..ff7d4eec9b6 100644 --- a/test/runner.h +++ b/test/runner.h @@ -123,7 +123,7 @@ int run_test_part(const char* test, const char* part); void print_tests(FILE* stream); /* Print lines in |buffer| as TAP diagnostics to |stream|. */ -void print_lines(const char* buffer, size_t size, FILE* stream); +int print_lines(const char* buffer, size_t size, FILE* stream, int partial); /* * Stuff that should be implemented by test-runner-.h From bb706f5fe71827f667f0bce532e95ce0698a498d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 24 Mar 2025 08:01:25 +0100 Subject: [PATCH 705/713] build: switch from c90 to c11 (#4743) After 14 years that should be fairly safe, right? Right!? Not safe enough for Windows Server 2016 apparently; there are build errors coming from system headers. The GHA images are slated for removal in a month anyway so upgrade them to Windows Server 2025. Fixes: https://github.com/libuv/libuv/issues/4742 --- .github/workflows/CI-win.yml | 3 +-- CMakeLists.txt | 2 +- SUPPORTED_PLATFORMS.md | 2 +- configure.ac | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/CI-win.yml b/.github/workflows/CI-win.yml index b845139de64..d1d68547092 100644 --- a/.github/workflows/CI-win.yml +++ b/.github/workflows/CI-win.yml @@ -21,13 +21,12 @@ jobs: fail-fast: false matrix: config: - - {toolchain: Visual Studio 16 2019, arch: Win32, server: 2019} - - {toolchain: Visual Studio 16 2019, arch: x64, server: 2019} - {toolchain: Visual Studio 17 2022, arch: Win32, server: 2022} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: ASAN} - {toolchain: Visual Studio 17 2022, arch: x64, server: 2022, config: UBSAN} - {toolchain: Visual Studio 17 2022, arch: arm64, server: 2022} + - {toolchain: Visual Studio 17 2022, arch: x64, server: 2025} steps: - uses: actions/checkout@v4 - name: Build diff --git a/CMakeLists.txt b/CMakeLists.txt index 63be9480ca8..b391e7c3ca3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ include(CTest) set(CMAKE_C_VISIBILITY_PRESET hidden) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) -set(CMAKE_C_STANDARD 90) +set(CMAKE_C_STANDARD 11) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 9597801b919..c560aa1086b 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -4,7 +4,7 @@ |---|---|---|---| | GNU/Linux | Tier 1 | Linux >= 3.10 with glibc >= 2.17 | | | macOS | Tier 1 | macOS >= 11 | Currently supported macOS releases | -| Windows | Tier 1 | >= Windows 10 | VS 2015 and later are supported | +| Windows | Tier 1 | >= Windows 10 | VS 2017 and later are supported | | FreeBSD | Tier 2 | >= 12 | | | AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | | IBM i | Tier 2 | >= IBM i 7.2 | Maintainers: @libuv/ibmi | diff --git a/configure.ac b/configure.ac index 95a32149ca1..d0e263a3016 100644 --- a/configure.ac +++ b/configure.ac @@ -33,7 +33,7 @@ CC_ATTRIBUTE_VISIBILITY([default], [ # we exclude -fno-strict-aliasing for xlc CC_CHECK_FLAG_SUPPORTED_APPEND([-fno-strict-aliasing]) CC_CHECK_CFLAGS_APPEND([-g]) -CC_CHECK_CFLAGS_APPEND([-std=gnu89]) +CC_CHECK_CFLAGS_APPEND([-std=gnu11]) CC_CHECK_CFLAGS_APPEND([-Wall]) CC_CHECK_CFLAGS_APPEND([-Wextra]) CC_CHECK_CFLAGS_APPEND([-Wno-long-long]) From c1a9f01f226133e3b8539ce678871fe1c0a68270 Mon Sep 17 00:00:00 2001 From: Itay Bookstein Date: Thu, 27 Mar 2025 09:48:56 +0200 Subject: [PATCH 706/713] linux: allow nul bytes in abstract socket address (#4737) Documentation on Linux explains that nul bytes have no special significance in abstract namespace socket names. Avoid precluding such addresses. Signed-off-by: Itay Bookstein --- src/unix/pipe.c | 14 ++++++++------ test/test-pipe-getsockname.c | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index bd57b17fb03..6bfe6cf2fa3 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -31,13 +31,15 @@ /* Does the file path contain embedded nul bytes? */ -static int includes_nul(const char *s, size_t n) { +static int includes_invalid_nul(const char *s, size_t n) { if (n == 0) return 0; #ifdef __linux__ - /* Accept abstract socket namespace path ("\0/virtual/path"). */ - s++; - n--; + /* Accept abstract socket namespace paths, throughout which nul bytes have + * no special significance ("\0foo\0bar"). + */ + if (s[0] == '\0') + return 0; #endif return NULL != memchr(s, '\0', n); } @@ -84,7 +86,7 @@ int uv_pipe_bind2(uv_pipe_t* handle, return UV_EINVAL; #endif - if (includes_nul(name, namelen)) + if (includes_invalid_nul(name, namelen)) return UV_EINVAL; if (flags & UV_PIPE_NO_TRUNCATE) @@ -271,7 +273,7 @@ int uv_pipe_connect2(uv_connect_t* req, if (namelen == 0) return UV_EINVAL; - if (includes_nul(name, namelen)) + if (includes_invalid_nul(name, namelen)) return UV_EINVAL; if (flags & UV_PIPE_NO_TRUNCATE) diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index cc345ccd864..3be30e67418 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -59,7 +59,7 @@ static void pipe_client_connect_cb(uv_connect_t* req, int status) { ASSERT_OK(r); if (*buf == '\0') { /* Linux abstract socket. */ - const char expected[] = "\0" TEST_PIPENAME; + const char expected[] = "\0" TEST_PIPENAME "\0"; ASSERT_EQ(len, sizeof(expected) - 1); ASSERT_MEM_EQ(buf, expected, len); } else { @@ -223,7 +223,7 @@ TEST_IMPL(pipe_getsockname) { TEST_IMPL(pipe_getsockname_abstract) { /* TODO(bnoordhuis) Use unique name, susceptible to concurrent test runs. */ - static const char name[] = "\0" TEST_PIPENAME; + static const char name[] = "\0" TEST_PIPENAME "\0"; #if defined(__linux__) char buf[256]; size_t buflen; From 745c68d4ea5ecbf420056e7dfa7ab9bd43cb2f07 Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Mon, 7 Apr 2025 15:03:26 +0800 Subject: [PATCH 707/713] sunos: use pipe2 on solaris and illumos (#4747) Solaris implemented pipe2 in 11.4 and illumos have had it since 2013. Ref: https://docs.oracle.com/cd/E88353_01/html/E37841/pipe2-2.html https://illumos.org/man/2/pipe2 https://www.illumos.org/issues/3714 --- src/unix/pipe.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 6bfe6cf2fa3..9512c20cac3 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -496,7 +496,9 @@ int uv_pipe(uv_os_fd_t fds[2], int read_flags, int write_flags) { defined(__FreeBSD__) || \ defined(__OpenBSD__) || \ defined(__DragonFly__) || \ - defined(__NetBSD__) + defined(__NetBSD__) || \ + defined(__illumos__) || \ + (defined(UV__SOLARIS_11_4) && UV__SOLARIS_11_4) int flags = O_CLOEXEC; if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE)) From fc29c125d41792e931afe7cf0bc9283499bfd59d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 7 Apr 2025 22:34:23 +0200 Subject: [PATCH 708/713] unix: remove TOCTOU issues from uv_pipe_chmod (#4749) Use fchmod() on platforms that support it on UNIX sockets. Only fall back to chmod() on platforms that don't (macOS and the BSDs.) Remove the stat + chmod dance from the fallback and just call chmod directly, because that's another source of TOCTOU issues. Fixes: https://github.com/libuv/libuv/issues/2040 --- src/unix/pipe.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 9512c20cac3..680e0664b02 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -447,13 +447,17 @@ 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[1 + UV__PATH_MAX]; + int desired_mode; size_t name_len; + int fd; int r; - if (handle == NULL || uv__stream_fd(handle) == -1) + if (handle == NULL) + return UV_EBADF; + + fd = uv__stream_fd(handle); + if (fd == -1) return UV_EBADF; if (mode != UV_READABLE && @@ -461,31 +465,27 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { mode != (UV_WRITABLE | UV_READABLE)) return UV_EINVAL; - /* Unfortunately fchmod does not work on all platforms, we will use chmod. */ - name_len = sizeof(name_buffer); - r = uv_pipe_getsockname(handle, name_buffer, &name_len); - if (r != 0) - return r; - - /* stat must be used as fstat has a bug on Darwin */ - if (uv__stat(name_buffer, &pipe_stat) == -1) - return UV__ERR(errno); - desired_mode = 0; if (mode & UV_READABLE) desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; if (mode & UV_WRITABLE) desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; - /* Exit early if pipe already has desired mode. */ - if ((pipe_stat.st_mode & desired_mode) == desired_mode) - return 0; + /* fchmod on macOS and (Free|Net|Open)BSD does not support UNIX sockets. */ + if (fchmod(fd, desired_mode)) + if (errno != EINVAL && errno != EOPNOTSUPP) + return UV__ERR(errno); - pipe_stat.st_mode |= desired_mode; + /* Fall back to chmod. */ + name_len = sizeof(name_buffer); + r = uv_pipe_getsockname(handle, name_buffer, &name_len); + if (r != 0) + return r; - r = chmod(name_buffer, pipe_stat.st_mode); + if (chmod(name_buffer, desired_mode)) + return UV__ERR(errno); - return r != -1 ? 0 : UV__ERR(errno); + return 0; } From bcc799a16ebb171b9be60a9ac69312ef020e7358 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 8 Apr 2025 16:49:34 +0800 Subject: [PATCH 709/713] unix: use pipe_fname if getsockname returns nothing (#4748) On some platforms (like GNU/Hurd), `getsockname` returns an empty string for sockets in the UNIX domain. However, we do have stored the path info in `pipe_fname` of `uv_pipe_t`, so we can try with it if `getsockname` returns an empty string. --- src/unix/pipe.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 680e0664b02..68e225e2e17 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -450,6 +450,7 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { char name_buffer[1 + UV__PATH_MAX]; int desired_mode; size_t name_len; + const char* name; int fd; int r; @@ -481,8 +482,13 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { r = uv_pipe_getsockname(handle, name_buffer, &name_len); if (r != 0) return r; + name = name_buffer; - if (chmod(name_buffer, desired_mode)) + /* On some platforms, getsockname returns an empty string, and we try with pipe_fname. */ + if (name_len == 0 && handle->pipe_fname != NULL) + name = handle->pipe_fname; + + if (chmod(name, desired_mode)) return UV__ERR(errno); return 0; From bf6c8870dce4fb039f75561265edc9f604a8d834 Mon Sep 17 00:00:00 2001 From: AE1020 <68134252+AE1020@users.noreply.github.com> Date: Wed, 16 Apr 2025 08:47:07 -0400 Subject: [PATCH 710/713] haiku: use uint32 instead of uint32_t (#4754) Haiku has parallel types to stdint.h, and their APIs use these types. In the Haiku-specific haiku.h file, it is passing an address of a uint32_t to get_cpu_topology_info(), that expects the other uint32: https://github.com/haiku/haiku/blob/648fa5897c28d5a4c8a5b4992dbf9b9d410434c8/src/system/libroot/os/system_info.cpp#L187 You get an "incompatible-pointer-types" warning in gcc if the warnings are turned up. But if you pass the pointer to Haiku's notion of uint32, then the warning goes away. --- src/unix/haiku.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/haiku.c b/src/unix/haiku.c index 31284b66dc3..0d3645f014b 100644 --- a/src/unix/haiku.c +++ b/src/unix/haiku.c @@ -120,7 +120,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { int i; status_t status; system_info system; - uint32_t topology_count; + uint32 topology_count; /* Haiku expects address of uint32, not uint32_t */ uint64_t cpuspeed; uv_cpu_info_t* cpu_info; From 11ecfbad8175dc4d754600109c7a9a5b3f30fc80 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 17 Apr 2025 19:56:19 +0200 Subject: [PATCH 711/713] doc: update thread pool stack size comment (#4756) I changed the default stack size in commit 73b0c1f94 from October 2022 and although I added a versionchanged note, I didn't update the blurb a few lines below. It wasn't accurate before that change either though, because even with musl libc's ~80kb thread stacks, 128 threads works out to 10 MB. Refs: https://github.com/nodejs/node/issues/57911 --- docs/src/threadpool.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/threadpool.rst b/docs/src/threadpool.rst index 05f31d2ccf3..d4dc5b8ec56 100644 --- a/docs/src/threadpool.rst +++ b/docs/src/threadpool.rst @@ -20,10 +20,10 @@ is 1024). .. versionchanged:: 1.50.0 threads now have a default name of libuv-worker. The threadpool is global and shared across all event loops. When a particular -function makes use of the threadpool (i.e. when using :c:func:`uv_queue_work`) +function makes use of the threadpool (e.g. when using :c:func:`uv_queue_work`) libuv preallocates and initializes the maximum number of threads allowed by -``UV_THREADPOOL_SIZE``. This causes a relatively minor memory overhead -(~1MB for 128 threads) but increases the performance of threading at runtime. +``UV_THREADPOOL_SIZE``. More threads usually means more throughput but a higher +memory footprint. Thread stacks grow lazily on most platforms though. .. note:: Note that even though a global thread pool which is shared across all events From 942e1418ea235e419a520491b00fe8a96426a5fa Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 18 Apr 2025 16:23:51 +0200 Subject: [PATCH 712/713] unix: improve uv_loop_init OOM handling (#4757) Handle out-of-memory conditions in uv_loop_init better, albeit still not perfect: bubble up the error instead of aborting. Also fixes a file descriptor leak on Linux (and likely other platforms) that the new test caught; the backend epoll fd was being leaked in the error path. Fixes: https://github.com/libuv/libuv/issues/4755 --- CMakeLists.txt | 1 + Makefile.am | 5 ++-- src/unix/async.c | 10 +++++-- src/unix/core.c | 37 +++++++++++++++++++++----- src/unix/internal.h | 7 ++++- src/unix/linux.c | 11 +++++--- src/unix/loop.c | 8 ++++-- src/unix/signal.c | 20 +++++++++----- src/win/core.c | 2 +- test/test-list.h | 2 ++ test/test-loop-oom.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 140 insertions(+), 25 deletions(-) create mode 100644 test/test-loop-oom.c diff --git a/CMakeLists.txt b/CMakeLists.txt index b391e7c3ca3..73d5aff8926 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -584,6 +584,7 @@ if(LIBUV_BUILD_TESTS) test/test-loop-close.c test/test-loop-configure.c test/test-loop-handles.c + test/test-loop-oom.c test/test-loop-stop.c test/test-loop-time.c test/test-metrics.c diff --git a/Makefile.am b/Makefile.am index 9b9e6be7178..f3808b696ce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -206,12 +206,13 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-ipc-send-recv.c \ test/test-ipc.c \ test/test-list.h \ - test/test-loop-handles.c \ test/test-loop-alive.c \ test/test-loop-close.c \ + test/test-loop-configure.c \ + test/test-loop-handles.c \ + test/test-loop-oom.c \ test/test-loop-stop.c \ test/test-loop-time.c \ - test/test-loop-configure.c \ test/test-metrics.c \ test/test-multiple-listen.c \ test/test-mutexes.c \ diff --git a/src/unix/async.c b/src/unix/async.c index 75a181bc1be..538ae7876f2 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -308,8 +308,14 @@ static int uv__async_start(uv_loop_t* loop) { return err; #endif - uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]); - uv__io_start(loop, &loop->async_io_watcher, POLLIN); + err = uv__io_init_start(loop, &loop->async_io_watcher, uv__async_io, + pipefd[0], POLLIN); + if (err < 0) { + uv__close(pipefd[0]); + if (pipefd[1] != -1) + uv__close(pipefd[1]); + return err; + } loop->async_wfd = pipefd[1]; #if UV__KQUEUE_EVFILT_USER diff --git a/src/unix/core.c b/src/unix/core.c index e64ea81d6ab..115cbe69974 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -867,7 +867,7 @@ static unsigned int next_power_of_two(unsigned int val) { return val; } -static void maybe_resize(uv_loop_t* loop, unsigned int len) { +static int maybe_resize(uv_loop_t* loop, unsigned int len) { uv__io_t** watchers; void* fake_watcher_list; void* fake_watcher_count; @@ -875,7 +875,7 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { unsigned int i; if (len <= loop->nwatchers) - return; + return 0; /* Preserve fake watcher list and count at the end of the watchers */ if (loop->watchers != NULL) { @@ -891,7 +891,7 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { (nwatchers + 2) * sizeof(loop->watchers[0])); if (watchers == NULL) - abort(); + return UV_ENOMEM; for (i = loop->nwatchers; i < nwatchers; i++) watchers[i] = NULL; watchers[nwatchers] = fake_watcher_list; @@ -899,11 +899,11 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) { loop->watchers = watchers; loop->nwatchers = nwatchers; + return 0; } void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { - assert(cb != NULL); assert(fd >= -1); uv__queue_init(&w->pending_queue); uv__queue_init(&w->watcher_queue); @@ -914,14 +914,18 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { } -void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { +int uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { + int err; + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); w->pevents |= events; - maybe_resize(loop, w->fd + 1); + err = maybe_resize(loop, w->fd + 1); + if (err) + return err; #if !defined(__sun) /* The event ports backend needs to rearm all file descriptors on each and @@ -929,7 +933,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { * short-circuit here if the event mask is unchanged. */ if (w->events == w->pevents) - return; + return 0; #endif if (uv__queue_empty(&w->watcher_queue)) @@ -939,6 +943,25 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { loop->watchers[w->fd] = w; loop->nfds++; } + + return 0; +} + + +int uv__io_init_start(uv_loop_t* loop, + uv__io_t* w, + uv__io_cb cb, + int fd, + unsigned int events) { + int err; + + assert(cb != NULL); + assert(fd > -1); + uv__io_init(w, cb, fd); + err = uv__io_start(loop, w, events); + if (err) + uv__io_init(w, NULL, -1); + return err; } diff --git a/src/unix/internal.h b/src/unix/internal.h index b1d2b21756d..5002c5fde38 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -257,7 +257,12 @@ void uv__make_close_pending(uv_handle_t* handle); int uv__getiovmax(void); void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd); -void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events); +int uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events); +int uv__io_init_start(uv_loop_t* loop, + uv__io_t* w, + uv__io_cb cb, + int fd, + unsigned int events); void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events); void uv__io_close(uv_loop_t* loop, uv__io_t* w); void uv__io_feed(uv_loop_t* loop, uv__io_t* w); diff --git a/src/unix/linux.c b/src/unix/linux.c index 86c12b4f086..5fa4627da4b 100644 --- a/src/unix/linux.c +++ b/src/unix/linux.c @@ -2460,6 +2460,7 @@ static int compare_watchers(const struct watcher_list* a, static int init_inotify(uv_loop_t* loop) { + int err; int fd; if (loop->inotify_fd != -1) @@ -2469,10 +2470,14 @@ static int init_inotify(uv_loop_t* loop) { if (fd < 0) return UV__ERR(errno); - loop->inotify_fd = fd; - uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); - uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); + err = uv__io_init_start(loop, &loop->inotify_read_watcher, uv__inotify_read, + fd, POLLIN); + if (err) { + uv__close(fd); + return err; + } + loop->inotify_fd = fd; return 0; } diff --git a/src/unix/loop.c b/src/unix/loop.c index 179ee999d80..5d3f0c7a348 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -32,12 +32,11 @@ int uv_loop_init(uv_loop_t* loop) { void* saved_data; int err; - saved_data = loop->data; memset(loop, 0, sizeof(*loop)); loop->data = saved_data; - lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields)); + lfields = uv__calloc(1, sizeof(*lfields)); if (lfields == NULL) return UV_ENOMEM; loop->internal_fields = lfields; @@ -116,6 +115,11 @@ int uv_loop_init(uv_loop_t* loop) { fail_signal_init: uv__platform_loop_delete(loop); + if (loop->backend_fd != -1) { + uv__close(loop->backend_fd); + loop->backend_fd = -1; + } + fail_platform_init: uv_mutex_destroy(&lfields->loop_metrics.lock); diff --git a/src/unix/signal.c b/src/unix/signal.c index f23c887d0d6..ccaa72db457 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -259,22 +259,28 @@ static void uv__signal_unregister_handler(int signum) { static int uv__signal_loop_once_init(uv_loop_t* loop) { + int* pipefd; int err; /* Return if already initialized. */ - if (loop->signal_pipefd[0] != -1) + pipefd = loop->signal_pipefd; + if (pipefd[0] != -1) return 0; - err = uv__make_pipe(loop->signal_pipefd, UV_NONBLOCK_PIPE); + err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE); if (err) return err; - uv__io_init(&loop->signal_io_watcher, - uv__signal_event, - loop->signal_pipefd[0]); - uv__io_start(loop, &loop->signal_io_watcher, POLLIN); + err = uv__io_init_start(loop, &loop->signal_io_watcher, uv__signal_event, + pipefd[0], POLLIN); + if (err) { + uv__close(pipefd[0]); + uv__close(pipefd[1]); + pipefd[0] = -1; + pipefd[1] = -1; + } - return 0; + return err; } diff --git a/src/win/core.c b/src/win/core.c index bc63b06673a..5f41c87ad5e 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -114,7 +114,7 @@ static int uv__loops_add(uv_loop_t* loop) { failed_loops_realloc: uv_mutex_unlock(&uv__loops_lock); - return ERROR_OUTOFMEMORY; + return UV_ENOMEM; } diff --git a/test/test-list.h b/test/test-list.h index 24dbcdd71c4..0dea544699d 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -33,6 +33,7 @@ TEST_DECLARE (loop_stop_before_run) TEST_DECLARE (loop_update_time) TEST_DECLARE (loop_backend_timeout) TEST_DECLARE (loop_configure) +TEST_DECLARE (loop_init_oom) TEST_DECLARE (default_loop_close) TEST_DECLARE (barrier_1) TEST_DECLARE (barrier_2) @@ -605,6 +606,7 @@ TASK_LIST_START TEST_ENTRY (loop_update_time) TEST_ENTRY (loop_backend_timeout) TEST_ENTRY (loop_configure) + TEST_ENTRY (loop_init_oom) TEST_ENTRY (default_loop_close) TEST_ENTRY (barrier_1) TEST_ENTRY (barrier_2) diff --git a/test/test-loop-oom.c b/test/test-loop-oom.c new file mode 100644 index 00000000000..5f5b58c9e56 --- /dev/null +++ b/test/test-loop-oom.c @@ -0,0 +1,62 @@ +/* Copyright libuv contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include +#include + +static int limit; +static int alloc; + +static void* t_realloc(void* p, size_t n) { + alloc += n; + if (alloc > limit) + return NULL; + p = realloc(p, n); + ASSERT_NOT_NULL(p); + return p; +} + +static void* t_calloc(size_t m, size_t n) { + return t_realloc(NULL, m * n); +} + +static void* t_malloc(size_t n) { + return t_realloc(NULL, n); +} + +TEST_IMPL(loop_init_oom) { + uv_loop_t loop; + int err; + + ASSERT_OK(uv_replace_allocator(t_malloc, t_realloc, t_calloc, free)); + for (;;) { + err = uv_loop_init(&loop); + if (err == 0) + break; + ASSERT_EQ(err, UV_ENOMEM); + limit += 8; + alloc = 0; + } + ASSERT_OK(uv_loop_close(&loop)); + return 0; +} From 086da2c458d3f58e1a60a4b314b4bbaa0fee4d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9?= Date: Sun, 20 Apr 2025 14:17:49 -0500 Subject: [PATCH 713/713] test: merge uv_tcp_connect callbacks (#4761) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Distinguish a callback for v4 and v6 connections is not relevant for this test. Signed-off-by: Juan José Arboleda --- test/test-connect-unspecified.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/test-connect-unspecified.c b/test/test-connect-unspecified.c index 73e59a9972b..ebed8c3c20b 100644 --- a/test/test-connect-unspecified.c +++ b/test/test-connect-unspecified.c @@ -22,11 +22,7 @@ #include "uv.h" #include "task.h" -static void connect_4(uv_connect_t* req, int status) { - ASSERT_NE(status, UV_EADDRNOTAVAIL); -} - -static void connect_6(uv_connect_t* req, int status) { +static void connect_cb(uv_connect_t* req, int status) { ASSERT_NE(status, UV_EADDRNOTAVAIL); } @@ -46,7 +42,7 @@ TEST_IMPL(connect_unspecified) { ASSERT_OK(uv_tcp_connect(&connect4, &socket4, (const struct sockaddr*) &addr4, - connect_4)); + connect_cb)); if (can_ipv6()) { ASSERT_OK(uv_tcp_init(loop, &socket6)); @@ -54,7 +50,7 @@ TEST_IMPL(connect_unspecified) { ASSERT_OK(uv_tcp_connect(&connect6, &socket6, (const struct sockaddr*) &addr6, - connect_6)); + connect_cb)); } ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));