From d9d541c41542464a5425b606193c0e2eadc1d2e2 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 16 Aug 2018 22:14:55 -0400 Subject: [PATCH] deps: upgrade to libuv 1.23.0 Notable changes: - Restores compatibility with the old IPC protocol. - Adds uv_open_osfhandle(). - Adds uv_os_{get,set}priority(). Backport-PR-URL: https://github.com/nodejs/node/pull/24103 PR-URL: https://github.com/nodejs/node/pull/22365 Fixes: https://github.com/nodejs/node/issues/21671 Fixes: https://github.com/nodejs/node/issues/15433 Refs: https://github.com/nodejs/node/pull/21675 Refs: https://github.com/nodejs/node-addon-api/issues/304 Refs: https://github.com/nodejs/abi-stable-node/issues/318 Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Anna Henningsen --- deps/uv/AUTHORS | 1 + deps/uv/CMakeLists.txt | 1 + deps/uv/ChangeLog | 22 ++++ deps/uv/Makefile.am | 1 + deps/uv/README.md | 2 +- deps/uv/configure.ac | 2 +- deps/uv/docs/src/fs.rst | 9 ++ deps/uv/docs/src/misc.rst | 28 +++++ deps/uv/include/uv.h | 11 ++ deps/uv/include/uv/version.h | 2 +- deps/uv/src/unix/core.c | 31 +++++ deps/uv/src/unix/stream.c | 12 +- deps/uv/src/win/core.c | 4 +- deps/uv/src/win/getnameinfo.c | 49 ++++---- deps/uv/src/win/handle.c | 4 + deps/uv/src/win/internal.h | 12 +- deps/uv/src/win/pipe.c | 172 ++++++++++++++++++--------- deps/uv/src/win/tcp.c | 34 ++++-- deps/uv/src/win/util.c | 94 +++++++++++++++ deps/uv/test/test-fs.c | 46 +++++++ deps/uv/test/test-list.h | 7 ++ deps/uv/test/test-process-priority.c | 81 +++++++++++++ deps/uv/test/test-tcp-open.c | 111 ++++++++++++++++- deps/uv/test/test.gyp | 1 + 24 files changed, 633 insertions(+), 104 deletions(-) create mode 100644 deps/uv/test/test-process-priority.c diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index ef3d5e181a800f..0ba7c067681477 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -345,3 +345,4 @@ Peter Johnson Paolo Greppi Shelley Vohr Ujjwal Sharma +Michał Kozakiewicz diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt index a133edb8500fa2..4f13efc8e6ef2b 100644 --- a/deps/uv/CMakeLists.txt +++ b/deps/uv/CMakeLists.txt @@ -98,6 +98,7 @@ set(uv_test_sources test/test-poll-closesocket.c test/test-poll-oob.c test/test-poll.c + test/test-process-priority.c test/test-process-title-threadsafe.c test/test-process-title.c test/test-queue-foreach-delete.c diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index acf42e0123a6c1..b57cea4baf150a 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,25 @@ +2018.08.18, Version 1.23.0 (Stable), 7ebb26225f2eaae6db22f4ef34ce76fa16ff89ec + +Changes since version 1.22.0: + +* win,pipe: restore compatibility with the old IPC framing protocol (Bert + Belder) + +* fs: add uv_open_osfhandle (Bartosz Sosnowski) + +* doc: update Visual C++ Build Tools URL (Michał Kozakiewicz) + +* unix: loop starvation on successful write complete (jBarz) + +* win: add uv__getnameinfo_work() error handling (A. Hauptmann) + +* win: return UV_ENOMEM from uv_loop_init() (cjihrig) + +* unix,win: add uv_os_{get,set}priority() (cjihrig) + +* test: fix warning in test-tcp-open (Santiago Gimeno) + + 2018.07.11, Version 1.22.0 (Stable), 8568f78a777d79d35eb7d6994617267b9fb33967 Changes since version 1.21.0: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 04aecab5555886..a217faab3cea25 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -224,6 +224,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-poll-close-doesnt-corrupt-stack.c \ test/test-poll-closesocket.c \ test/test-poll-oob.c \ + test/test-process-priority.c \ test/test-process-title.c \ test/test-process-title-threadsafe.c \ test/test-queue-foreach-delete.c \ diff --git a/deps/uv/README.md b/deps/uv/README.md index f6e7288dedd80d..cb9e26c1e03a7a 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -349,7 +349,7 @@ See the [guidelines for contributing][]. [libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png [x32]: https://en.wikipedia.org/wiki/X32_ABI [Python 2.6 or 2.7]: https://www.python.org/downloads/ -[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools +[Visual C++ Build Tools]: https://visualstudio.microsoft.com/visual-cpp-build-tools/ [Visual Studio 2015 Update 3]: https://www.visualstudio.com/vs/older-downloads/ [Visual Studio 2017]: https://www.visualstudio.com/downloads/ [Git for Windows]: http://git-scm.com/download/win diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index aa6e6d16a8c804..6e084fd04d9a7d 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.22.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.23.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index f383e5b10cd9d5..fcf70a35a1f66d 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -403,6 +403,15 @@ Helper functions .. versionadded:: 1.12.0 +.. c:function:: int uv_open_osfhandle(uv_os_fd_t os_fd) + + For a OS-dependent handle, get the file descriptor in the C runtime. + On UNIX, returns the ``os_fd`` intact. On Windows, this calls `_open_osfhandle `_. + Note that the return value is still owned by the CRT, + any attempts to close it or to use it after closing the handle may lead to malfunction. + + .. versionadded:: 1.23.0 + File open constants ------------------- diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index 07908c98ff8e9c..529d588c5d4bd1 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -517,3 +517,31 @@ API storage required to hold the value. .. versionadded:: 1.12.0 + +.. c:function:: int uv_os_getpriority(uv_pid_t pid, int* priority) + + Retrieves the scheduling priority of the process specified by `pid`. The + returned value of `priority` is between -20 (high priority) and 19 (low + priority). + + .. note:: + On Windows, the returned priority will equal one of the `UV_PRIORITY` + constants. + + .. versionadded:: 1.23.0 + +.. c:function:: int uv_os_setpriority(uv_pid_t pid, int priority) + + Sets the scheduling priority of the process specified by `pid`. The + `priority` value range is between -20 (high priority) and 19 (low priority). + The constants `UV_PRIORITY_LOW`, `UV_PRIORITY_BELOW_NORMAL`, + `UV_PRIORITY_NORMAL`, `UV_PRIORITY_ABOVE_NORMAL`, `UV_PRIORITY_HIGH`, and + `UV_PRIORITY_HIGHEST` are also provided for convenience. + + .. note:: + On Windows, this function utilizes `SetPriorityClass()`. The `priority` + argument is mapped to a Windows priority class. When retrieving the + process priority, the result will equal one of the `UV_PRIORITY` + constants, and not necessarily the exact value of `priority`. + + .. versionadded:: 1.23.0 diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index a8b305793d4b14..717c2e570b9eb9 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -1065,6 +1065,7 @@ UV_EXTERN int uv_set_process_title(const char* title); UV_EXTERN int uv_resident_set_memory(size_t* rss); 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; @@ -1099,6 +1100,16 @@ UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); UV_EXTERN uv_pid_t uv_os_getpid(void); UV_EXTERN uv_pid_t uv_os_getppid(void); +#define UV_PRIORITY_LOW 19 +#define UV_PRIORITY_BELOW_NORMAL 10 +#define UV_PRIORITY_NORMAL 0 +#define UV_PRIORITY_ABOVE_NORMAL -7 +#define UV_PRIORITY_HIGH -14 +#define UV_PRIORITY_HIGHEST -20 + +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 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/deps/uv/include/uv/version.h b/deps/uv/include/uv/version.h index a990137f85209c..30e1d5a6f92bf8 100644 --- a/deps/uv/include/uv/version.h +++ b/deps/uv/include/uv/version.h @@ -31,7 +31,7 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 22 +#define UV_VERSION_MINOR 23 #define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 066c9bee32e2b2..f92446ff42b86b 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -1338,6 +1338,9 @@ uv_os_fd_t uv_get_osfhandle(int fd) { return fd; } +int uv_open_osfhandle(uv_os_fd_t os_fd) { + return os_fd; +} uv_pid_t uv_os_getpid(void) { return getpid(); @@ -1347,3 +1350,31 @@ uv_pid_t uv_os_getpid(void) { uv_pid_t uv_os_getppid(void) { return getppid(); } + + +int uv_os_getpriority(uv_pid_t pid, int* priority) { + int r; + + if (priority == NULL) + return UV_EINVAL; + + errno = 0; + r = getpriority(PRIO_PROCESS, (int) pid); + + if (r == -1 && errno != 0) + return UV__ERR(errno); + + *priority = r; + return 0; +} + + +int uv_os_setpriority(uv_pid_t pid, int priority) { + if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW) + return UV_EINVAL; + + if (setpriority(PRIO_PROCESS, (int) pid, priority) != 0) + return UV__ERR(errno); + + return 0; +} diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 4d62a23f1b9b7a..5a96b66b17bfd5 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -950,10 +950,16 @@ 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; - while (!QUEUE_EMPTY(&stream->write_completed_queue)) { + if (QUEUE_EMPTY(&stream->write_completed_queue)) + return; + + QUEUE_MOVE(&stream->write_completed_queue, &pq); + + while (!QUEUE_EMPTY(&pq)) { /* Pop a req off write_completed_queue. */ - q = QUEUE_HEAD(&stream->write_completed_queue); + q = QUEUE_HEAD(&pq); req = QUEUE_DATA(q, uv_write_t, queue); QUEUE_REMOVE(q); uv__req_unregister(stream->loop, req); @@ -969,8 +975,6 @@ static void uv__write_callbacks(uv_stream_t* stream) { if (req->cb) req->cb(req, req->error); } - - assert(QUEUE_EMPTY(&stream->write_completed_queue)); } diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index 5a76c900337c3d..afdf01e7878913 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -249,8 +249,10 @@ int uv_loop_init(uv_loop_t* loop) { loop->endgame_handles = NULL; loop->timer_heap = timer_heap = uv__malloc(sizeof(*timer_heap)); - if (timer_heap == NULL) + if (timer_heap == NULL) { + err = UV_ENOMEM; goto fail_timers_alloc; + } heap_init(timer_heap); diff --git a/deps/uv/src/win/getnameinfo.c b/deps/uv/src/win/getnameinfo.c index 9f10cd2a5a1432..71785a9fa65718 100644 --- a/deps/uv/src/win/getnameinfo.c +++ b/deps/uv/src/win/getnameinfo.c @@ -42,7 +42,7 @@ static void uv__getnameinfo_work(struct uv__work* w) { uv_getnameinfo_t* req; WCHAR host[NI_MAXHOST]; WCHAR service[NI_MAXSERV]; - int ret = 0; + int ret; req = container_of(w, uv_getnameinfo_t, work_req); if (GetNameInfoW((struct sockaddr*)&req->storage, @@ -53,27 +53,34 @@ static void uv__getnameinfo_work(struct uv__work* w) { ARRAY_SIZE(service), req->flags)) { ret = WSAGetLastError(); + req->retcode = uv__getaddrinfo_translate_error(ret); + 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()); + 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()); } - req->retcode = uv__getaddrinfo_translate_error(ret); - - /* convert results to UTF-8 */ - WideCharToMultiByte(CP_UTF8, - 0, - host, - -1, - req->host, - sizeof(req->host), - NULL, - NULL); - - WideCharToMultiByte(CP_UTF8, - 0, - service, - -1, - req->service, - sizeof(req->service), - NULL, - NULL); } diff --git a/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c index 738d7ff3248ab4..9d76c3f5420997 100644 --- a/deps/uv/src/win/handle.c +++ b/deps/uv/src/win/handle.c @@ -157,3 +157,7 @@ int uv_is_closing(const uv_handle_t* handle) { uv_os_fd_t uv_get_osfhandle(int fd) { return uv__get_osfhandle(fd); } + +int uv_open_osfhandle(uv_os_fd_t os_fd) { + return _open_osfhandle((intptr_t) os_fd, 0); +} diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index b37b4c0c9be59f..634b9f776ccc67 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -61,10 +61,15 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled; * TCP */ +typedef enum { + UV__IPC_SOCKET_XFER_NONE = 0, + UV__IPC_SOCKET_XFER_TCP_CONNECTION, + UV__IPC_SOCKET_XFER_TCP_SERVER +} uv__ipc_socket_xfer_type_t; + typedef struct { WSAPROTOCOL_INFOW socket_info; uint32_t delayed_error; - uint32_t flags; /* Either zero or UV_HANDLE_CONNECTION. */ } uv__ipc_socket_xfer_info_t; int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb); @@ -89,8 +94,11 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); int uv__tcp_xfer_export(uv_tcp_t* handle, int pid, + uv__ipc_socket_xfer_type_t* xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info); +int uv__tcp_xfer_import(uv_tcp_t* tcp, + uv__ipc_socket_xfer_type_t xfer_type, uv__ipc_socket_xfer_info_t* xfer_info); -int uv__tcp_xfer_import(uv_tcp_t* tcp, uv__ipc_socket_xfer_info_t* xfer_info); /* diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 42380f6599a45b..382290e69f4afa 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -25,11 +25,12 @@ #include #include -#include "uv.h" -#include "internal.h" #include "handle-inl.h" -#include "stream-inl.h" +#include "internal.h" #include "req-inl.h" +#include "stream-inl.h" +#include "uv-common.h" +#include "uv.h" #include #include @@ -52,19 +53,36 @@ static const int pipe_prefix_len = sizeof(pipe_prefix) - 1; /* IPC incoming xfer queue item. */ typedef struct { + uv__ipc_socket_xfer_type_t xfer_type; uv__ipc_socket_xfer_info_t xfer_info; QUEUE member; } uv__ipc_xfer_queue_item_t; -/* IPC frame types. */ -enum { UV__IPC_DATA_FRAME = 0, UV__IPC_XFER_FRAME = 1 }; +/* IPC frame header flags. */ +/* clang-format off */ +enum { + UV__IPC_FRAME_HAS_DATA = 0x01, + UV__IPC_FRAME_HAS_SOCKET_XFER = 0x02, + UV__IPC_FRAME_XFER_IS_TCP_CONNECTION = 0x04, + /* These are combinations of the flags above. */ + UV__IPC_FRAME_XFER_FLAGS = 0x06, + UV__IPC_FRAME_VALID_FLAGS = 0x07 +}; +/* clang-format on */ /* IPC frame header. */ typedef struct { - uint32_t type; - uint32_t payload_length; + uint32_t flags; + uint32_t reserved1; /* Ignored. */ + uint32_t data_length; /* Must be zero if there is no data. */ + uint32_t reserved2; /* Must be zero. */ } uv__ipc_frame_header_t; +/* To implement the IPC protocol correctly, these structures must have exactly + * the right size. */ +STATIC_ASSERT(sizeof(uv__ipc_frame_header_t) == 16); +STATIC_ASSERT(sizeof(uv__ipc_socket_xfer_info_t) == 632); + /* Coalesced write request. */ typedef struct { uv_write_t req; /* Internal heap-allocated write request. */ @@ -878,7 +896,8 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { server->pipe.conn.ipc_xfer_queue_length--; item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member); - err = uv__tcp_xfer_import((uv_tcp_t*) client, &item->xfer_info); + err = uv__tcp_xfer_import( + (uv_tcp_t*) client, item->xfer_type, &item->xfer_info); if (err != 0) return err; @@ -1458,10 +1477,10 @@ int uv__pipe_write_ipc(uv_loop_t* loop, uv_buf_t stack_bufs[6]; uv_buf_t* bufs; size_t buf_count, buf_index; - uv__ipc_frame_header_t xfer_frame_header; + uv__ipc_frame_header_t frame_header; + uv__ipc_socket_xfer_type_t xfer_type = UV__IPC_SOCKET_XFER_NONE; uv__ipc_socket_xfer_info_t xfer_info; - uv__ipc_frame_header_t data_frame_header; - size_t data_length; + uint64_t data_length; size_t i; int err; @@ -1472,8 +1491,8 @@ int uv__pipe_write_ipc(uv_loop_t* loop, if (data_length > UINT32_MAX) return WSAENOBUFS; /* Maps to UV_ENOBUFS. */ - /* Prepare xfer frame payload. */ - if (send_handle) { + /* Prepare the frame's socket xfer payload. */ + if (send_handle != NULL) { uv_tcp_t* send_tcp_handle = (uv_tcp_t*) send_handle; /* Verify that `send_handle` it is indeed a tcp handle. */ @@ -1481,20 +1500,18 @@ int uv__pipe_write_ipc(uv_loop_t* loop, return ERROR_NOT_SUPPORTED; /* Export the tcp handle. */ - err = uv__tcp_xfer_export( - send_tcp_handle, uv__pipe_get_ipc_remote_pid(handle), &xfer_info); + err = uv__tcp_xfer_export(send_tcp_handle, + uv__pipe_get_ipc_remote_pid(handle), + &xfer_type, + &xfer_info); if (err != 0) return err; } /* Compute the number of uv_buf_t's required. */ - buf_count = 0; - if (send_handle != NULL) { - buf_count += 2; /* One for the frame header, one for the payload. */ - } - if (data_buf_count > 0) { - buf_count += 1 + data_buf_count; /* One extra for the frame header. */ - } + buf_count = 1 + data_buf_count; /* Frame header and data buffers. */ + if (send_handle != NULL) + buf_count += 1; /* One extra for the socket xfer information. */ /* Use the on-stack buffer array if it is big enough; otherwise allocate * space for it on the heap. */ @@ -1509,25 +1526,32 @@ int uv__pipe_write_ipc(uv_loop_t* loop, } buf_index = 0; - if (send_handle != NULL) { - /* Add xfer frame header. */ - xfer_frame_header.type = UV__IPC_XFER_FRAME; - xfer_frame_header.payload_length = sizeof xfer_info; - bufs[buf_index++] = - uv_buf_init((char*) &xfer_frame_header, sizeof xfer_frame_header); + /* Initialize frame header and add it to the buffers list. */ + memset(&frame_header, 0, sizeof frame_header); + bufs[buf_index++] = uv_buf_init((char*) &frame_header, sizeof frame_header); - /* Add xfer frame payload. */ + if (send_handle != NULL) { + /* Add frame header flags. */ + switch (xfer_type) { + case UV__IPC_SOCKET_XFER_TCP_CONNECTION: + frame_header.flags |= UV__IPC_FRAME_HAS_SOCKET_XFER | + UV__IPC_FRAME_XFER_IS_TCP_CONNECTION; + break; + case UV__IPC_SOCKET_XFER_TCP_SERVER: + frame_header.flags |= UV__IPC_FRAME_HAS_SOCKET_XFER; + break; + default: + assert(0); // Unreachable. + } + /* Add xfer info buffer. */ bufs[buf_index++] = uv_buf_init((char*) &xfer_info, sizeof xfer_info); } if (data_length > 0) { - /* Add data frame header. */ - data_frame_header.type = UV__IPC_DATA_FRAME; - data_frame_header.payload_length = (uint32_t) data_length; - bufs[buf_index++] = - uv_buf_init((char*) &data_frame_header, sizeof data_frame_header); - - /* Add data buffers. */ + /* Update frame header. */ + frame_header.flags |= UV__IPC_FRAME_HAS_DATA; + frame_header.data_length = (uint32_t) data_length; + /* Add data buffers to buffers list. */ for (i = 0; i < data_buf_count; i++) bufs[buf_index++] = data_bufs[i]; } @@ -1601,14 +1625,18 @@ static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle, static void uv__pipe_queue_ipc_xfer_info( - uv_pipe_t* handle, uv__ipc_socket_xfer_info_t* xfer_info) { + uv_pipe_t* handle, + uv__ipc_socket_xfer_type_t xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info) { uv__ipc_xfer_queue_item_t* item; item = (uv__ipc_xfer_queue_item_t*) uv__malloc(sizeof(*item)); if (item == NULL) uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - memcpy(&item->xfer_info, xfer_info, sizeof(item->xfer_info)); + item->xfer_type = xfer_type; + item->xfer_info = *xfer_info; + QUEUE_INSERT_TAIL(&handle->pipe.conn.ipc_xfer_queue, &item->member); handle->pipe.conn.ipc_xfer_queue_length++; } @@ -1678,7 +1706,7 @@ static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) { int err; if (*data_remaining > 0) { - /* Read data frame payload. */ + /* Read frame data payload. */ DWORD bytes_read = uv__pipe_read_data(loop, handle, *data_remaining, *data_remaining); *data_remaining -= bytes_read; @@ -1687,6 +1715,8 @@ static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) { } else { /* Start of a new IPC frame. */ uv__ipc_frame_header_t frame_header; + uint32_t xfer_flags; + uv__ipc_socket_xfer_type_t xfer_type; uv__ipc_socket_xfer_info_t xfer_info; /* Read the IPC frame header. */ @@ -1695,33 +1725,57 @@ static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) { if (err) goto error; - if (frame_header.type == UV__IPC_DATA_FRAME) { - /* Data frame: capture payload length. Actual data will be read in - * subsequent call to uv__pipe_read_ipc(). */ - *data_remaining = frame_header.payload_length; + /* Validate that flags are valid. */ + if ((frame_header.flags & ~UV__IPC_FRAME_VALID_FLAGS) != 0) + goto invalid; + /* Validate that reserved2 is zero. */ + if (frame_header.reserved2 != 0) + goto invalid; + + /* Parse xfer flags. */ + xfer_flags = frame_header.flags & UV__IPC_FRAME_XFER_FLAGS; + if (xfer_flags & UV__IPC_FRAME_HAS_SOCKET_XFER) { + /* Socket coming -- determine the type. */ + xfer_type = xfer_flags & UV__IPC_FRAME_XFER_IS_TCP_CONNECTION + ? UV__IPC_SOCKET_XFER_TCP_CONNECTION + : UV__IPC_SOCKET_XFER_TCP_SERVER; + } else if (xfer_flags == 0) { + /* No socket. */ + xfer_type = UV__IPC_SOCKET_XFER_NONE; + } else { + /* Invalid flags. */ + goto invalid; + } - /* Return number of bytes read. */ - return sizeof frame_header; + /* Parse data frame information. */ + if (frame_header.flags & UV__IPC_FRAME_HAS_DATA) { + *data_remaining = frame_header.data_length; + } else if (frame_header.data_length != 0) { + /* Data length greater than zero but data flag not set -- invalid. */ + goto invalid; + } - } else if (frame_header.type == UV__IPC_XFER_FRAME) { - /* Xfer frame: read the payload. */ - assert(frame_header.payload_length == sizeof xfer_info); - err = - uv__pipe_read_exactly(handle->handle, &xfer_info, sizeof xfer_info); - if (err) - goto error; + /* 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. */ - /* Store the pending socket info. */ - uv__pipe_queue_ipc_xfer_info(handle, &xfer_info); + /* Read transferred socket information. */ + err = uv__pipe_read_exactly(handle->handle, &xfer_info, sizeof xfer_info); + if (err) + goto error; - /* Return number of bytes read. */ - return sizeof frame_header + sizeof xfer_info; - } + /* Store the pending socket info. */ + uv__pipe_queue_ipc_xfer_info(handle, xfer_type, &xfer_info); - /* Invalid frame. */ - err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */ + /* Return number of bytes read. */ + return sizeof frame_header + sizeof xfer_info; } +invalid: + /* Invalid frame. */ + err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */ + error: uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_); return 0; /* Break out of read loop. */ diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index a97ab2a5188714..8b6f0a5c99bd70 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -1191,8 +1191,12 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, int uv__tcp_xfer_export(uv_tcp_t* handle, int target_pid, + uv__ipc_socket_xfer_type_t* xfer_type, uv__ipc_socket_xfer_info_t* xfer_info) { - if (!(handle->flags & UV_HANDLE_CONNECTION)) { + if (handle->flags & UV_HANDLE_CONNECTION) { + *xfer_type = UV__IPC_SOCKET_XFER_TCP_CONNECTION; + } else { + *xfer_type = UV__IPC_SOCKET_XFER_TCP_SERVER; /* We're about to share the socket with another process. Because this is a * listening socket, we assume that the other process will be accepting * connections on it. Thus, before sharing the socket with another process, @@ -1208,12 +1212,9 @@ int uv__tcp_xfer_export(uv_tcp_t* handle, } } - if (WSADuplicateSocketW( - handle->socket, target_pid, &xfer_info->socket_info)) { + if (WSADuplicateSocketW(handle->socket, target_pid, &xfer_info->socket_info)) return WSAGetLastError(); - } xfer_info->delayed_error = handle->delayed_error; - xfer_info->flags = handle->flags & UV_HANDLE_CONNECTION; /* Mark the local copy of the handle as 'shared' so we behave in a way that's * friendly to the process(es) that we share the socket with. */ @@ -1223,14 +1224,21 @@ int uv__tcp_xfer_export(uv_tcp_t* handle, } -int uv__tcp_xfer_import(uv_tcp_t* tcp, uv__ipc_socket_xfer_info_t* xfer_info) { +int uv__tcp_xfer_import(uv_tcp_t* tcp, + uv__ipc_socket_xfer_type_t xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info) { int err; - SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO, - FROM_PROTOCOL_INFO, - FROM_PROTOCOL_INFO, - &xfer_info->socket_info, - 0, - WSA_FLAG_OVERLAPPED); + SOCKET socket; + + assert(xfer_type == UV__IPC_SOCKET_XFER_TCP_SERVER || + xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION); + + socket = WSASocketW(FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + &xfer_info->socket_info, + 0, + WSA_FLAG_OVERLAPPED); if (socket == INVALID_SOCKET) { return WSAGetLastError(); @@ -1246,7 +1254,7 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp, uv__ipc_socket_xfer_info_t* xfer_info) { tcp->delayed_error = xfer_info->delayed_error; tcp->flags |= UV_HANDLE_BOUND | UV_HANDLE_SHARED_TCP_SOCKET; - if (xfer_info->flags & UV_HANDLE_CONNECTION) { + if (xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION) { uv_connection_init((uv_stream_t*)tcp); tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; } diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 3e86ff15048063..c994984fe65a25 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -1530,3 +1530,97 @@ int uv_os_gethostname(char* buffer, size_t* size) { *size = len; return 0; } + + +static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) { + int r; + + if (pid == 0) + *handle = GetCurrentProcess(); + else + *handle = OpenProcess(access, FALSE, pid); + + if (*handle == NULL) { + r = GetLastError(); + + if (r == ERROR_INVALID_PARAMETER) + return UV_ESRCH; + else + return uv_translate_sys_error(r); + } + + return 0; +} + + +int uv_os_getpriority(uv_pid_t pid, int* priority) { + HANDLE handle; + int r; + + if (priority == NULL) + return UV_EINVAL; + + r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle); + + if (r != 0) + return r; + + r = GetPriorityClass(handle); + + if (r == 0) { + r = uv_translate_sys_error(GetLastError()); + } else { + /* Map Windows priority classes to Unix nice values. */ + if (r == REALTIME_PRIORITY_CLASS) + *priority = UV_PRIORITY_HIGHEST; + else if (r == HIGH_PRIORITY_CLASS) + *priority = UV_PRIORITY_HIGH; + else if (r == ABOVE_NORMAL_PRIORITY_CLASS) + *priority = UV_PRIORITY_ABOVE_NORMAL; + else if (r == NORMAL_PRIORITY_CLASS) + *priority = UV_PRIORITY_NORMAL; + else if (r == BELOW_NORMAL_PRIORITY_CLASS) + *priority = UV_PRIORITY_BELOW_NORMAL; + else /* IDLE_PRIORITY_CLASS */ + *priority = UV_PRIORITY_LOW; + + r = 0; + } + + CloseHandle(handle); + return r; +} + + +int uv_os_setpriority(uv_pid_t pid, int priority) { + HANDLE handle; + int priority_class; + int r; + + /* Map Unix nice values to Windows priority classes. */ + if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW) + return UV_EINVAL; + else if (priority < UV_PRIORITY_HIGH) + priority_class = REALTIME_PRIORITY_CLASS; + else if (priority < UV_PRIORITY_ABOVE_NORMAL) + priority_class = HIGH_PRIORITY_CLASS; + else if (priority < UV_PRIORITY_NORMAL) + priority_class = ABOVE_NORMAL_PRIORITY_CLASS; + else if (priority < UV_PRIORITY_BELOW_NORMAL) + priority_class = NORMAL_PRIORITY_CLASS; + else if (priority < UV_PRIORITY_LOW) + priority_class = BELOW_NORMAL_PRIORITY_CLASS; + else + priority_class = IDLE_PRIORITY_CLASS; + + r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle); + + if (r != 0) + return r; + + if (SetPriorityClass(handle, priority_class) == 0) + r = uv_translate_sys_error(GetLastError()); + + CloseHandle(handle); + return r; +} diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 57da39891a5c5b..9c1e8bec205f5d 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -3069,6 +3069,52 @@ TEST_IMPL(get_osfhandle_valid_handle) { return 0; } +TEST_IMPL(open_osfhandle_valid_handle) { + int r; + uv_os_fd_t handle; + int fd; + + /* Setup. */ + unlink("test_file"); + + loop = uv_default_loop(); + + r = uv_fs_open(NULL, + &open_req1, + "test_file", + O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + handle = uv_get_osfhandle(open_req1.result); +#ifdef _WIN32 + ASSERT(handle != INVALID_HANDLE_VALUE); +#else + ASSERT(handle >= 0); +#endif + + fd = uv_open_osfhandle(handle); +#ifdef _WIN32 + ASSERT(fd > 0); +#else + ASSERT(fd == open_req1.result); +#endif + + r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + ASSERT(close_req.result == 0); + uv_fs_req_cleanup(&close_req); + + /* Cleanup. */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + TEST_IMPL(fs_file_pos_after_op_with_offset) { int r; diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 24ba37461eb4de..b501722d4dc83b 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -121,6 +121,7 @@ TEST_DECLARE (tcp_bind6_error_addrnotavail) TEST_DECLARE (tcp_bind6_error_fault) TEST_DECLARE (tcp_bind6_error_inval) TEST_DECLARE (tcp_bind6_localhost_ok) +TEST_DECLARE (tcp_write_ready) TEST_DECLARE (udp_alloc_cb_fail) TEST_DECLARE (udp_bind) TEST_DECLARE (udp_bind_reuseaddr) @@ -213,6 +214,7 @@ TEST_DECLARE (pipe_close_stdout_read_stdin) TEST_DECLARE (pipe_set_non_blocking) TEST_DECLARE (pipe_set_chmod) TEST_DECLARE (process_ref) +TEST_DECLARE (process_priority) TEST_DECLARE (has_ref) TEST_DECLARE (active) TEST_DECLARE (embed) @@ -334,6 +336,7 @@ TEST_DECLARE (fs_rename_to_existing_file) TEST_DECLARE (fs_write_multiple_bufs) TEST_DECLARE (fs_read_write_null_arguments) TEST_DECLARE (get_osfhandle_valid_handle) +TEST_DECLARE (open_osfhandle_valid_handle) TEST_DECLARE (fs_write_alotof_bufs) TEST_DECLARE (fs_write_alotof_bufs_with_offset) TEST_DECLARE (fs_file_pos_after_op_with_offset) @@ -544,6 +547,8 @@ TASK_LIST_START TEST_ENTRY (tcp_open_bound) TEST_ENTRY (tcp_open_connected) TEST_HELPER (tcp_open_connected, tcp4_echo_server) + TEST_ENTRY (tcp_write_ready) + TEST_HELPER (tcp_write_ready, tcp4_echo_server) TEST_ENTRY (tcp_shutdown_after_write) TEST_HELPER (tcp_shutdown_after_write, tcp4_echo_server) @@ -685,6 +690,7 @@ TASK_LIST_START TEST_ENTRY (pipe_ref4) TEST_HELPER (pipe_ref4, pipe_echo_server) TEST_ENTRY (process_ref) + TEST_ENTRY (process_priority) TEST_ENTRY (has_ref) TEST_ENTRY (loop_handles) @@ -887,6 +893,7 @@ TASK_LIST_START TEST_ENTRY (fs_fchmod_archive_readonly) #endif TEST_ENTRY (get_osfhandle_valid_handle) + TEST_ENTRY (open_osfhandle_valid_handle) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) TEST_ENTRY (threadpool_multiple_event_loops) diff --git a/deps/uv/test/test-process-priority.c b/deps/uv/test/test-process-priority.c new file mode 100644 index 00000000000000..ebee6b90afd555 --- /dev/null +++ b/deps/uv/test/test-process-priority.c @@ -0,0 +1,81 @@ +/* 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" + + +TEST_IMPL(process_priority) { + int priority; + int r; + int i; + +#if defined(__MVS__) + if (uv_os_setpriority(0, 0) == UV_ENOSYS) + RETURN_SKIP("functionality not supported on zOS"); +#endif + + /* Verify that passing a NULL pointer returns UV_EINVAL. */ + r = uv_os_getpriority(0, NULL); + ASSERT(r == UV_EINVAL); + + /* Verify that all valid values work. */ + for (i = UV_PRIORITY_HIGHEST; i <= UV_PRIORITY_LOW; i++) { + r = uv_os_setpriority(0, i); + + /* If UV_EACCES is returned, the current user doesn't have permission to + set this specific priority. */ + if (r == UV_EACCES) + continue; + + ASSERT(r == 0); + ASSERT(uv_os_getpriority(0, &priority) == 0); + + /* Verify that the priority values match on Unix, and are range mapped + on Windows. */ +#ifndef _WIN32 + ASSERT(priority == i); +#else + if (i < UV_PRIORITY_HIGH) + ASSERT(priority == UV_PRIORITY_HIGHEST); + else if (i < UV_PRIORITY_ABOVE_NORMAL) + ASSERT(priority == UV_PRIORITY_HIGH); + else if (i < UV_PRIORITY_NORMAL) + ASSERT(priority == UV_PRIORITY_ABOVE_NORMAL); + else if (i < UV_PRIORITY_BELOW_NORMAL) + ASSERT(priority == UV_PRIORITY_NORMAL); + else if (i < UV_PRIORITY_LOW) + ASSERT(priority == UV_PRIORITY_BELOW_NORMAL); + else + ASSERT(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); + } + + /* 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); + + return 0; +} diff --git a/deps/uv/test/test-tcp-open.c b/deps/uv/test/test-tcp-open.c index f5d8f136b1f600..0d92886d61f225 100644 --- a/deps/uv/test/test-tcp-open.c +++ b/deps/uv/test/test-tcp-open.c @@ -30,6 +30,7 @@ #endif static int shutdown_cb_called = 0; +static int shutdown_requested = 0; static int connect_cb_called = 0; static int write_cb_called = 0; static int close_cb_called = 0; @@ -37,6 +38,8 @@ static int close_cb_called = 0; static uv_connect_t connect_req; static uv_shutdown_t shutdown_req; static uv_write_t write_req; +static uv_timer_t tm; +static uv_tcp_t client; static void startup(void) { @@ -115,6 +118,20 @@ static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { ASSERT(memcmp("PING", buf->base, nread) == 0); } else { + ASSERT(nread == UV_EOF); + uv_close((uv_handle_t*)tcp, close_cb); + } +} + + +static void read1_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { + int i; + ASSERT(tcp != NULL); + + if (nread >= 0) { + for (i = 0; i < nread; ++i) + ASSERT(buf->base[i] == 'P'); + } else { ASSERT(nread == UV_EOF); printf("GOT EOF\n"); uv_close((uv_handle_t*)tcp, close_cb); @@ -134,6 +151,37 @@ static void write_cb(uv_write_t* req, int status) { } +static void write1_cb(uv_write_t* req, int status) { + uv_buf_t buf; + int r; + + ASSERT(req != NULL); + if (status) { + ASSERT(shutdown_cb_called); + return; + } + + if (shutdown_requested) + return; + + buf = uv_buf_init("P", 1); + r = uv_write(&write_req, req->handle, &buf, 1, write1_cb); + ASSERT(r == 0); + + write_cb_called++; +} + + +static void timer_cb(uv_timer_t* handle) { + int r; + + /* Shutdown on drain. */ + r = uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb); + ASSERT(r == 0); + shutdown_requested++; +} + + static void connect_cb(uv_connect_t* req, int status) { uv_buf_t buf = uv_buf_init("PING", 4); uv_stream_t* stream; @@ -158,9 +206,35 @@ static void connect_cb(uv_connect_t* req, int status) { } +static void connect1_cb(uv_connect_t* req, int status) { + uv_buf_t buf; + uv_stream_t* stream; + int r; + + ASSERT(req == &connect_req); + ASSERT(status == 0); + + stream = req->handle; + connect_cb_called++; + + r = uv_timer_init(uv_default_loop(), &tm); + ASSERT(r == 0); + + r = uv_timer_start(&tm, timer_cb, 2000, 0); + ASSERT(r == 0); + + buf = uv_buf_init("P", 1); + r = uv_write(&write_req, stream, &buf, 1, write1_cb); + ASSERT(r == 0); + + /* Start reading */ + r = uv_read_start(stream, alloc_cb, read1_cb); + ASSERT(r == 0); +} + + TEST_IMPL(tcp_open) { struct sockaddr_in addr; - uv_tcp_t client; uv_os_sock_t sock; int r; @@ -289,3 +363,38 @@ TEST_IMPL(tcp_open_connected) { MAKE_VALGRIND_HAPPY(); return 0; } + + +TEST_IMPL(tcp_write_ready) { + struct sockaddr_in addr; + uv_os_sock_t sock; + int r; + + ASSERT(0 == 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); + + r = uv_tcp_open(&client, sock); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, + &client, + (const struct sockaddr*) &addr, + connect1_cb); + ASSERT(r == 0); + + 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); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test.gyp b/deps/uv/test/test.gyp index 917533618bf12c..855eda1c50003a 100644 --- a/deps/uv/test/test.gyp +++ b/deps/uv/test/test.gyp @@ -80,6 +80,7 @@ 'test-poll-close-doesnt-corrupt-stack.c', 'test-poll-closesocket.c', 'test-poll-oob.c', + 'test-process-priority.c', 'test-process-title.c', 'test-process-title-threadsafe.c', 'test-queue-foreach-delete.c',