From 7a1996ae9042ce1af3b887b904c9dbad2ff11d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 22 Sep 2015 22:12:18 +0200 Subject: [PATCH 001/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index aae7ad6f8..42f10352b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2015.09.23, Version 1.7.5 (Stable) +2015.09.23, Version 1.7.5 (Stable), a8c1136de2cabf25b143021488cbaab05834daa8 Changes since version 1.7.4: From 455c4035d40cc60390cddff0b920da43c4b55cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 22 Sep 2015 22:27:51 +0200 Subject: [PATCH 002/632] Now working on version 1.7.6 --- configure.ac | 2 +- include/uv-version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index c55a11847..f911789c7 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.7.5], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.7.6], [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 e1f26601a..7a637e07b 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 7 -#define UV_VERSION_PATCH 5 -#define UV_VERSION_IS_RELEASE 1 -#define UV_VERSION_SUFFIX "" +#define UV_VERSION_PATCH 6 +#define UV_VERSION_IS_RELEASE 0 +#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ (UV_VERSION_MINOR << 8) | \ From 25c369d4cfe7b4be546b4504a71105aeeda989f3 Mon Sep 17 00:00:00 2001 From: Jianghua Yang Date: Tue, 22 Sep 2015 14:51:38 +0800 Subject: [PATCH 003/632] unix: fix memory leak in uv_interface_addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/537 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/darwin.c | 4 +++- src/unix/freebsd.c | 4 +++- src/unix/linux-core.c | 4 +++- src/unix/netbsd.c | 4 +++- src/unix/openbsd.c | 4 +++- src/unix/sunos.c | 4 +++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/unix/darwin.c b/src/unix/darwin.c index dab6ca999..cf95da216 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -258,8 +258,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) + if (!(*addresses)) { + freeifaddrs(addrs); return -ENOMEM; + } address = *addresses; diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index c69608b13..ddfd0f28a 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -373,8 +373,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) + if (!(*addresses)) { + freeifaddrs(addrs); return -ENOMEM; + } address = *addresses; diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index e6e68283d..3ff6fb15e 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -814,8 +814,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, return 0; *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) + if (!(*addresses)) { + freeifaddrs(addrs); return -ENOMEM; + } address = *addresses; diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index 29f2a4dec..ca48550f9 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -298,8 +298,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) + if (!(*addresses)) { + freeifaddrs(addrs); return -ENOMEM; + } address = *addresses; diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index c8d545993..e6ca7a8b0 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -313,8 +313,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) + if (!(*addresses)) { + freeifaddrs(addrs); return -ENOMEM; + } address = *addresses; diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 05b7a1140..0c46817b4 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -693,8 +693,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) + if (!(*addresses)) { + freeifaddrs(addrs); return -ENOMEM; + } address = *addresses; From 25506bb33156f15e27a837979773264dfe8d06be Mon Sep 17 00:00:00 2001 From: Gireesh Punathil Date: Tue, 22 Sep 2015 07:37:48 -0400 Subject: [PATCH 004/632] unix: make uv_guess_handle work properly for AIX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On AIX, the getsockname API does not operate on the UNIX domain sockets Please see: https://www-01.ibm.com/support/knowledgecenter/ssw_aix_61/ com.ibm.aix.commtrf2/getsockname.htm This means that the internal helper routine uv_guess_handle in tty.c fails in AIX, for common use cases. There is no direct API support which helps identifying a UNIX domain socket in AIX. getpeername() retrieves the information pertinent to connected UNIX domain socket pairs, and using getpeername where getsockname fails was a good workaround. However, there are edge cases where one end of a socketpair comes for introspection while the other end has been closed, which causes getpeername to fail. A better solution is derived based on these facts: 1.getsockname() on a broken / un-broken socketpair does not actually fail with -1, instead it returns 0. However, the API does not modify the socketaddr structure passed to it, with the socket information. 2.This behavior of getsockname is observed only for UNIX domain socket, among all possible types of sockets which I tested - ~30 of them. So a practical and stable workaround for AIX is to return UV_UNKNOWN_HANDLE if getsockname fails. If it passes and the length of the structure returned is 0 then we know that the type is AF_UNIX and return UV_NAMED_PIPE , otherwise we inspect in the same way as for other platforms to derive the type. PR-URL: https://github.com/libuv/libuv/pull/539 Reviewed-By: Ben Noordhuis Reviewed-By: Michael Dawson Reviewed-By: Saúl Ibarra Corretgé --- src/unix/tty.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/unix/tty.c b/src/unix/tty.c index 54c9055a0..7cc5b714e 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -236,6 +236,15 @@ uv_handle_type uv_guess_handle(uv_file file) { return UV_UDP; if (type == SOCK_STREAM) { +#if defined(_AIX) + /* on AIX 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 (len == 0) + return UV_NAMED_PIPE; +#endif /* defined(_AIX) */ + if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) return UV_TCP; if (sa.sa_family == AF_UNIX) From 01999559cfb7b8794da4c4796f5e44f4339d335e Mon Sep 17 00:00:00 2001 From: Jianghua Yang Date: Wed, 23 Sep 2015 16:37:40 +0800 Subject: [PATCH 005/632] fs: undo uv__req_init when uv__malloc failed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/543 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fs.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index d739c2825..ff27e84ad 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -80,8 +80,10 @@ req->path = path; \ } else { \ req->path = uv__strdup(path); \ - if (req->path == NULL) \ + if (req->path == NULL) { \ + uv__req_unregister(loop, req); \ return -ENOMEM; \ + } \ } \ } \ while (0) @@ -97,8 +99,10 @@ path_len = strlen(path) + 1; \ new_path_len = strlen(new_path) + 1; \ req->path = uv__malloc(path_len + new_path_len); \ - if (req->path == NULL) \ + if (req->path == NULL) { \ + uv__req_unregister(loop, req); \ return -ENOMEM; \ + } \ req->new_path = req->path + path_len; \ memcpy((void*) req->path, path, path_len); \ memcpy((void*) req->new_path, new_path, new_path_len); \ @@ -1062,8 +1066,10 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_cb cb) { INIT(MKDTEMP); req->path = uv__strdup(tpl); - if (req->path == NULL) + if (req->path == NULL) { + uv__req_unregister(loop, req); return -ENOMEM; + } POST; } @@ -1099,8 +1105,10 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, if (nbufs > ARRAY_SIZE(req->bufsml)) req->bufs = uv__malloc(nbufs * sizeof(*bufs)); - if (req->bufs == NULL) + if (req->bufs == NULL) { + uv__req_unregister(loop, req); return -ENOMEM; + } memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); @@ -1224,8 +1232,10 @@ int uv_fs_write(uv_loop_t* loop, if (nbufs > ARRAY_SIZE(req->bufsml)) req->bufs = uv__malloc(nbufs * sizeof(*bufs)); - if (req->bufs == NULL) + if (req->bufs == NULL) { + uv__req_unregister(loop, req); return -ENOMEM; + } memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); From 2a98e76b4560db3954510ea34b286e14705a590c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 24 Sep 2015 10:23:22 +0200 Subject: [PATCH 006/632] build: remove unused 'component' GYP option PR-URL: https://github.com/libuv/libuv/pull/548 Reviewed-By: Ben Noordhuis --- common.gypi | 1 - gyp_uv.py | 3 --- 2 files changed, 4 deletions(-) diff --git a/common.gypi b/common.gypi index 392c85951..7cebcde5f 100644 --- a/common.gypi +++ b/common.gypi @@ -4,7 +4,6 @@ 'target_arch%': 'ia32', # set v8's target architecture 'host_arch%': 'ia32', # set v8's host architecture 'uv_library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds - 'component%': 'static_library', # NB. these names match with what V8 expects 'msvs_multi_core_compile': '0', # we do enable multicore compiles, but not using the V8 way }, diff --git a/gyp_uv.py b/gyp_uv.py index 0491ff873..39933f624 100755 --- a/gyp_uv.py +++ b/gyp_uv.py @@ -83,9 +83,6 @@ def run_gyp(args): if not any(a.startswith('-Duv_library=') for a in args): args.append('-Duv_library=static_library') - if not any(a.startswith('-Dcomponent=') for a in args): - args.append('-Dcomponent=static_library') - # Some platforms (OpenBSD for example) don't have multiprocessing.synchronize # so gyp must be run with --no-parallel if not gyp_parallel_support: From e5c03aed6bee3c73817d69dcaafef3ee5e7a8296 Mon Sep 17 00:00:00 2001 From: Jianghua Yang Date: Thu, 24 Sep 2015 14:16:34 +0800 Subject: [PATCH 007/632] include: remove duplicate extern declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/547 Reviewed-By: Saúl Ibarra Corretgé --- include/uv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uv.h b/include/uv.h index f96026b60..9d81514a8 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1363,7 +1363,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 extern uint64_t uv_hrtime(void); +UV_EXTERN uint64_t uv_hrtime(void); UV_EXTERN void uv_disable_stdio_inheritance(void); From a59085e140d52076960fd2ee84875577378abc62 Mon Sep 17 00:00:00 2001 From: Peter Jas Date: Sat, 19 Sep 2015 15:05:13 +0000 Subject: [PATCH 008/632] win: use the MSVC provided snprintf where possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/532 Reviewed-By: Saúl Ibarra Corretgé --- src/inet.c | 4 ---- src/uv-common.c | 4 ---- src/uv-common.h | 4 ++++ src/win/pipe.c | 2 +- src/win/snprintf.c | 41 +++++++++++++++++++++++++++++++++++++++++ test/runner-win.h | 10 +++------- test/task.h | 36 ++---------------------------------- test/test-spawn.c | 10 +++++----- uv.gyp | 7 +++++++ 9 files changed, 63 insertions(+), 55 deletions(-) create mode 100644 src/win/snprintf.c diff --git a/src/inet.c b/src/inet.c index c948b2e7c..da63a688c 100644 --- a/src/inet.c +++ b/src/inet.c @@ -55,11 +55,7 @@ static int inet_ntop4(const unsigned char *src, char *dst, size_t size) { char tmp[UV__INET_ADDRSTRLEN]; int l; -#ifndef _WIN32 l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); -#else - l = _snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); -#endif if (l <= 0 || (size_t) l >= size) { return UV_ENOSPC; } diff --git a/src/uv-common.c b/src/uv-common.c index 675a776bf..8ce3d1f4b 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -141,11 +141,7 @@ static const char* uv__unknown_err_code(int err) { char buf[32]; char* copy; -#ifndef _WIN32 snprintf(buf, sizeof(buf), "Unknown system error %d", err); -#else - _snprintf(buf, sizeof(buf), "Unknown system error %d", err); -#endif copy = uv__strdup(buf); return copy != NULL ? copy : "Unknown system error"; diff --git a/src/uv-common.h b/src/uv-common.h index b348ec76b..27902fdf8 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -41,6 +41,10 @@ #include "tree.h" #include "queue.h" +#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900 +extern int snprintf(char*, size_t, const char*, ...); +#endif + #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #define container_of(ptr, type, member) \ diff --git a/src/win/pipe.c b/src/win/pipe.c index 8312b1ceb..796d06dcd 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -85,7 +85,7 @@ static void eof_timer_close_cb(uv_handle_t* handle); static void uv_unique_pipe_name(char* ptr, char* name, size_t size) { - _snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId()); + snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId()); } diff --git a/src/win/snprintf.c b/src/win/snprintf.c new file mode 100644 index 000000000..b589417a3 --- /dev/null +++ b/src/win/snprintf.c @@ -0,0 +1,41 @@ +/* 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. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1900 + +#include +#include + +/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer + * on overflow... + */ +int snprintf(char* buf, size_t len, const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + + int n = _vscprintf(fmt, ap); + vsnprintf_s(buf, len, _TRUNCATE, fmt, ap); + + va_end(ap); + return n; +} + +#endif diff --git a/test/runner-win.h b/test/runner-win.h index c94b89bd5..8cc4c16eb 100644 --- a/test/runner-win.h +++ b/test/runner-win.h @@ -19,9 +19,6 @@ * IN THE SOFTWARE. */ -/* Don't complain about _snprintf being insecure. */ -#define _CRT_SECURE_NO_WARNINGS - /* Don't complain about write(), fileno() etc. being deprecated. */ #pragma warning(disable : 4996) @@ -30,10 +27,9 @@ #include #include - -/* Windows has no snprintf, only _snprintf. */ -#define snprintf _snprintf - +#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900 +extern int snprintf(char*, size_t, const char*, ...); +#endif typedef struct { HANDLE process; diff --git a/test/task.h b/test/task.h index e73676380..8999c20a4 100644 --- a/test/task.h +++ b/test/task.h @@ -174,40 +174,8 @@ enum test_status { #endif - -#if defined _WIN32 && ! defined __GNUC__ - -#include - -/* Define inline for MSVC<2015 */ -# if defined(_MSC_VER) && _MSC_VER < 1900 -# define inline __inline -# endif - -# if defined(_MSC_VER) && _MSC_VER < 1900 -/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer - * on overflow... - */ -inline int snprintf(char* buf, size_t len, const char* fmt, ...) { - va_list ap; - int n; - - va_start(ap, fmt); - n = _vsprintf_p(buf, len, fmt, ap); - va_end(ap); - - /* It's a sad fact of life that no one ever checks the return value of - * snprintf(). Zero-terminating the buffer hopefully reduces the risk - * of gaping security holes. - */ - if (n < 0) - if (len > 0) - buf[0] = '\0'; - - return n; -} -# endif - +#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900 +extern int snprintf(char*, size_t, const char*, ...); #endif #if defined(__clang__) || \ diff --git a/test/test-spawn.c b/test/test-spawn.c index e71f0f7d5..eba54ae70 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -960,11 +960,11 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) { options.stdio_count = 2; /* Create a pipe that'll cause a collision. */ - _snprintf(name, - sizeof(name), - "\\\\.\\pipe\\uv\\%p-%d", - &out, - GetCurrentProcessId()); + snprintf(name, + sizeof(name), + "\\\\.\\pipe\\uv\\%p-%d", + &out, + GetCurrentProcessId()); pipe_handle = CreateNamedPipeA(name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, diff --git a/uv.gyp b/uv.gyp index 8049faa7a..36cc8abe3 100644 --- a/uv.gyp +++ b/uv.gyp @@ -104,6 +104,13 @@ 'src/win/winsock.c', 'src/win/winsock.h', ], + 'conditions': [ + ['MSVS_VERSION < "2015"', { + 'sources': [ + 'src/win/snprintf.c' + ] + }] + ], 'link_settings': { 'libraries': [ '-ladvapi32', From 037a8ab29fdb1f1e9793f3a3269ed8538cf84a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 21 Sep 2015 22:25:43 +0200 Subject: [PATCH 009/632] win, test: fix compilation warning uv_os_fd_t is HANDLE on Windows, but closesocket needs a SOCKET. PR-URL: https://github.com/libuv/libuv/pull/534 Reviewed-By: Ben Noordhuis --- test/test-tcp-write-fail.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-tcp-write-fail.c b/test/test-tcp-write-fail.c index 2840d8161..5256a9f4a 100644 --- a/test/test-tcp-write-fail.c +++ b/test/test-tcp-write-fail.c @@ -43,7 +43,7 @@ static void close_socket(uv_tcp_t* sock) { r = uv_fileno((uv_handle_t*)sock, &fd); ASSERT(r == 0); #ifdef _WIN32 - r = closesocket(fd); + r = closesocket((uv_os_sock_t)fd); #else r = close(fd); #endif From 764877fd9e4ea67c0cbe27bf81b2b294ed33b0f5 Mon Sep 17 00:00:00 2001 From: Ryan Johnston Date: Wed, 30 Sep 2015 13:10:02 +1300 Subject: [PATCH 010/632] win: fix compilation with VS < 2012 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/554 Reviewed-By: Saúl Ibarra Corretgé --- src/win/snprintf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/win/snprintf.c b/src/win/snprintf.c index b589417a3..776c0e392 100644 --- a/src/win/snprintf.c +++ b/src/win/snprintf.c @@ -28,10 +28,11 @@ * on overflow... */ int snprintf(char* buf, size_t len, const char* fmt, ...) { + int n; va_list ap; va_start(ap, fmt); - int n = _vscprintf(fmt, ap); + n = _vscprintf(fmt, ap); vsnprintf_s(buf, len, _TRUNCATE, fmt, ap); va_end(ap); From 5e761a5f812296aad8b44236f3363a9685c9c77e Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sat, 3 Oct 2015 16:19:11 -0400 Subject: [PATCH 011/632] stream: support empty uv_try_write on unix PR-URL: https://github.com/libuv/libuv/pull/558 Reviewed-By: Ben Noordhuis --- src/unix/stream.c | 2 +- test/test-tcp-try-write.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 183b68cf7..7ebd9fde4 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1471,7 +1471,7 @@ int uv_try_write(uv_stream_t* stream, uv__stream_osx_interrupt_select(stream); } - if (written == 0) + if (written == 0 && req_size != 0) return -EAGAIN; else return written; diff --git a/test/test-tcp-try-write.c b/test/test-tcp-try-write.c index 8a60136b6..97a1d6e3d 100644 --- a/test/test-tcp-try-write.c +++ b/test/test-tcp-try-write.c @@ -58,6 +58,11 @@ static void connect_cb(uv_connect_t* req, int status) { break; } } while (1); + + do { + buf = uv_buf_init("", 0); + r = uv_try_write((uv_stream_t*) &client, &buf, 1); + } while (r != 0); uv_close((uv_handle_t*) &client, close_cb); } From 26917ddf7a5279c5d913c12121fe955ba4de91c0 Mon Sep 17 00:00:00 2001 From: Jianghua Yang Date: Wed, 7 Oct 2015 21:39:28 +0800 Subject: [PATCH 012/632] unix: fix request handle leak in uv__udp_send PR-URL: https://github.com/libuv/libuv/pull/561 Reviewed-By: Ben Noordhuis --- src/unix/udp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index 66ecc4e34..39ade8de3 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -410,8 +410,10 @@ int uv__udp_send(uv_udp_send_t* req, if (nbufs > ARRAY_SIZE(req->bufsml)) req->bufs = uv__malloc(nbufs * sizeof(bufs[0])); - if (req->bufs == NULL) + if (req->bufs == NULL) { + uv__req_unregister(handle->loop, req); return -ENOMEM; + } memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs); From 1867a6c1ce015462db5038739e3d15b6b47e6a74 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 8 Oct 2015 16:24:10 +0200 Subject: [PATCH 013/632] src: replace QUEUE_SPLIT with QUEUE_MOVE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All uses of QUEUE_SPLIT in libuv split the list at the head so introduce a QUEUE_MOVE macro that automates that. PR-URL: https://github.com/libuv/libuv/pull/565 Reviewed-By: Fedor Indutny Reviewed-By: Saúl Ibarra Corretgé --- src/queue.h | 11 +++++++++++ src/threadpool.c | 7 +------ src/unix/core.c | 4 +--- src/unix/fsevents.c | 14 +++----------- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/queue.h b/src/queue.h index 60c800003..f942e13fd 100644 --- a/src/queue.h +++ b/src/queue.h @@ -66,6 +66,17 @@ typedef void *QUEUE[2]; } \ 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); \ diff --git a/src/threadpool.c b/src/threadpool.c index 15d719944..2c5152b42 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -223,13 +223,8 @@ void uv__work_done(uv_async_t* handle) { int err; loop = container_of(handle, uv_loop_t, wq_async); - QUEUE_INIT(&wq); - uv_mutex_lock(&loop->wq_mutex); - if (!QUEUE_EMPTY(&loop->wq)) { - q = QUEUE_HEAD(&loop->wq); - QUEUE_SPLIT(&loop->wq, q, &wq); - } + QUEUE_MOVE(&loop->wq, &wq); uv_mutex_unlock(&loop->wq_mutex); while (!QUEUE_EMPTY(&wq)) { diff --git a/src/unix/core.c b/src/unix/core.c index e149357e0..48dbfd0a8 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -721,9 +721,7 @@ static int uv__run_pending(uv_loop_t* loop) { if (QUEUE_EMPTY(&loop->pending_queue)) return 0; - QUEUE_INIT(&pq); - q = QUEUE_HEAD(&loop->pending_queue); - QUEUE_SPLIT(&loop->pending_queue, q, &pq); + QUEUE_MOVE(&loop->pending_queue, &pq); while (!QUEUE_EMPTY(&pq)) { q = QUEUE_HEAD(&pq); diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c index 8143f7c1f..8f582c41c 100644 --- a/src/unix/fsevents.c +++ b/src/unix/fsevents.c @@ -149,11 +149,7 @@ static void (*pFSEventStreamStop)(FSEventStreamRef); int err; \ uv_mutex_lock(&(handle)->cf_mutex); \ /* Split-off all events and empty original queue */ \ - QUEUE_INIT(&events); \ - if (!QUEUE_EMPTY(&(handle)->cf_events)) { \ - q = QUEUE_HEAD(&(handle)->cf_events); \ - QUEUE_SPLIT(&(handle)->cf_events, q, &events); \ - } \ + QUEUE_MOVE(&(handle)->cf_events, &events); \ /* Get error (if any) and zero original one */ \ err = (handle)->cf_error; \ (handle)->cf_error = 0; \ @@ -735,17 +731,14 @@ static void uv__cf_loop_cb(void* arg) { loop = arg; state = loop->cf_state; - QUEUE_INIT(&split_head); uv_mutex_lock(&loop->cf_mutex); - if (!QUEUE_EMPTY(&loop->cf_signals)) { - QUEUE* split_pos = QUEUE_HEAD(&loop->cf_signals); - QUEUE_SPLIT(&loop->cf_signals, split_pos, &split_head); - } + 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); s = QUEUE_DATA(item, uv__cf_loop_signal_t, member); @@ -755,7 +748,6 @@ static void uv__cf_loop_cb(void* arg) { else uv__fsevents_reschedule(s->handle); - QUEUE_REMOVE(item); uv__free(s); } } From 442b8a5a848e1589520a4d4fd175d7e9aa084c44 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 8 Oct 2015 17:03:04 +0200 Subject: [PATCH 014/632] unix: use QUEUE_MOVE when iterating over lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace uses of QUEUE_FOREACH when the list can get modified while iterating over it, in particular when a callback is made into the user's code. This should fix a number of spurious failures that people have been reporting. PR-URL: https://github.com/libuv/libuv/pull/565 Reviewed-By: Fedor Indutny Reviewed-By: Saúl Ibarra Corretgé --- src/queue.h | 3 +++ src/unix/async.c | 8 +++++++- src/unix/linux-inotify.c | 9 ++++++++- src/unix/loop-watcher.c | 7 ++++++- src/unix/signal.c | 2 ++ src/uv-common.c | 9 ++++++++- 6 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/queue.h b/src/queue.h index f942e13fd..ff3540a0a 100644 --- a/src/queue.h +++ b/src/queue.h @@ -30,6 +30,9 @@ typedef void *QUEUE[2]; #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)) diff --git a/src/unix/async.c b/src/unix/async.c index 9ff24aeb3..184b59812 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -78,12 +78,18 @@ void uv__async_close(uv_async_t* handle) { static void uv__async_event(uv_loop_t* loop, struct uv__async* w, unsigned int nevents) { + QUEUE queue; QUEUE* q; uv_async_t* h; - QUEUE_FOREACH(q, &loop->async_handles) { + 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); + if (cmpxchgi(&h->pending, 1, 0) == 0) continue; diff --git a/src/unix/linux-inotify.c b/src/unix/linux-inotify.c index d9ed9f4b2..e3ff6d529 100644 --- a/src/unix/linux-inotify.c +++ b/src/unix/linux-inotify.c @@ -120,6 +120,7 @@ static void uv__inotify_read(uv_loop_t* loop, const struct uv__inotify_event* e; struct watcher_list* w; uv_fs_event_t* h; + QUEUE queue; QUEUE* q; const char* path; ssize_t size; @@ -159,8 +160,14 @@ static void uv__inotify_read(uv_loop_t* loop, */ path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path); - QUEUE_FOREACH(q, &w->watchers) { + 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); } } diff --git a/src/unix/loop-watcher.c b/src/unix/loop-watcher.c index dc25760bd..340bb0dfa 100644 --- a/src/unix/loop-watcher.c +++ b/src/unix/loop-watcher.c @@ -47,9 +47,14 @@ \ void uv__run_##name(uv_loop_t* loop) { \ uv_##name##_t* h; \ + QUEUE queue; \ QUEUE* q; \ - QUEUE_FOREACH(q, &loop->name##_handles) { \ + 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); \ h->name##_cb(h); \ } \ } \ diff --git a/src/unix/signal.c b/src/unix/signal.c index 0b7a405c1..edd9085d3 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -234,6 +234,8 @@ void uv__signal_loop_cleanup(uv_loop_t* loop) { /* 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 + * 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); diff --git a/src/uv-common.c b/src/uv-common.c index 8ce3d1f4b..539756c8b 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -337,11 +337,18 @@ 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; uv_handle_t* h; - QUEUE_FOREACH(q, &loop->handle_queue) { + QUEUE_MOVE(&loop->handle_queue, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); h = QUEUE_DATA(q, uv_handle_t, handle_queue); + + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&loop->handle_queue, q); + if (h->flags & UV__HANDLE_INTERNAL) continue; walk_cb(h, arg); } From 1457496452f5e6dcae10abc125dfbd9b75e4eea1 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 8 Oct 2015 17:18:50 +0200 Subject: [PATCH 015/632] unix: squelch harmless valgrind warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Valgrind complains that the msg_control pointer points to uninitialized memory. While the memory is only used for writing data to, not for reading data from, and the warning is therefore bogus, it's still annoying enough that I decided to squelch it by zeroing the memory. The performance implications should be minimal because this code path is only used when sending over a handle to another process. The warning: ==14859== Syscall param sendmsg(msg.msg_control) points to uninitialised byte(s) ==14859== at 0x5AF1A80: __sendmsg_nocancel (in /usr/lib64/libpthread-2.21.so) ==14859== by 0x46350E: uv__write (stream.c:810) ==14859== by 0x464B24: uv_write2 (stream.c:1398) ==14859== by 0x421ACE: run_test (test-ipc-send-recv.c:104) ==14859== by 0x421DD1: run_test_ipc_send_recv_tcp (test-ipc-send-recv.c:156) ==14859== by 0x406D2F: run_test_part (runner.c:404) ==14859== by 0x4058CD: main (run-tests.c:58) ==14859== Address 0xffefff934 is on thread 1's stack ==14859== in frame #1, created by uv__write (stream.c:742) PR-URL: https://github.com/libuv/libuv/pull/565 Reviewed-By: Fedor Indutny Reviewed-By: Saúl Ibarra Corretgé --- src/unix/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 7ebd9fde4..7d7ab2633 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -779,9 +779,9 @@ static void uv__write(uv_stream_t* stream) { if (req->send_handle) { struct msghdr msg; - char scratch[64]; struct cmsghdr *cmsg; int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); + char scratch[64] = {0}; assert(fd_to_send >= 0); From 822969ad2f530278348ac33c716f0c2a51ee5c3d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 8 Oct 2015 17:37:53 +0200 Subject: [PATCH 016/632] test: don't abort on setrlimit() failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Valgrind blocks the setrlimit() system call. Print a warning and skip the test, don't consider it a fatal error. PR-URL: https://github.com/libuv/libuv/pull/565 Reviewed-By: Fedor Indutny Reviewed-By: Saúl Ibarra Corretgé --- test/test-emfile.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/test/test-emfile.c b/test/test-emfile.c index 453bfe4cf..dd35f785b 100644 --- a/test/test-emfile.c +++ b/test/test-emfile.c @@ -25,7 +25,6 @@ #include "task.h" #include -#include #include #include @@ -45,6 +44,13 @@ TEST_IMPL(emfile) { uv_loop_t* loop; int first_fd; + /* 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. */ + 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)); @@ -52,13 +58,6 @@ TEST_IMPL(emfile) { ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 8, connection_cb)); - /* 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)) { - perror("setrlimit(RLIMIT_NOFILE)"); - ASSERT(0); - } - /* Remember the first one so we can clean up afterwards. */ do first_fd = dup(0); From bf52579f92c30cb6ebb65a007b4f0dab9f135695 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 9 Oct 2015 13:14:24 +0200 Subject: [PATCH 017/632] unix: only undo fs req registration in async mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 0199955 ("fs: undo uv__req_init when uv__malloc failed") mistakingly unregisters the requests unconditionally in a few places, resulting in memory corruption when it hasn't been registered first. Fixes: https://github.com/libuv/libuv/pull/543 PR-URL: https://github.com/libuv/libuv/pull/567 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index ff27e84ad..d593d2ec6 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1067,7 +1067,8 @@ int uv_fs_mkdtemp(uv_loop_t* loop, INIT(MKDTEMP); req->path = uv__strdup(tpl); if (req->path == NULL) { - uv__req_unregister(loop, req); + if (cb != NULL) + uv__req_unregister(loop, req); return -ENOMEM; } POST; @@ -1106,7 +1107,8 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, req->bufs = uv__malloc(nbufs * sizeof(*bufs)); if (req->bufs == NULL) { - uv__req_unregister(loop, req); + if (cb != NULL) + uv__req_unregister(loop, req); return -ENOMEM; } @@ -1233,7 +1235,8 @@ int uv_fs_write(uv_loop_t* loop, req->bufs = uv__malloc(nbufs * sizeof(*bufs)); if (req->bufs == NULL) { - uv__req_unregister(loop, req); + if (cb != NULL) + uv__req_unregister(loop, req); return -ENOMEM; } From 9fbcca048181b927cfcdb5c6c49e5bdff173aad5 Mon Sep 17 00:00:00 2001 From: HungMingWu Date: Tue, 13 Oct 2015 06:13:51 +0000 Subject: [PATCH 018/632] unix: fix uv__getiovmax return value On some embedded devices (arm-linux-uclibc based ip camera), sysconf(_SC_IOV_MAX) can not get the correct value. The return value is -1 and the errno is EINPROGRESS. Degrade the value to 1. PR-URL: https://github.com/libuv/libuv/pull/573 Reviewed-By: Ben Noordhuis --- src/unix/core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/unix/core.c b/src/unix/core.c index 48dbfd0a8..0db5f828c 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -204,8 +204,14 @@ int uv__getiovmax(void) { return IOV_MAX; #elif defined(_SC_IOV_MAX) static int iovmax = -1; - if (iovmax == -1) + if (iovmax == -1) { iovmax = sysconf(_SC_IOV_MAX); + /* On some embedded devices (arm-linux-uclibc based ip camera), + * sysconf(_SC_IOV_MAX) can not get the correct value. The return + * value is -1 and the errno is EINPROGRESS. Degrade the value to 1. + */ + if (iovmax == -1) iovmax = 1; + } return iovmax; #else return 1024; From ef47e8b2127c45ee58cae6b6f8ace5d6fde695b2 Mon Sep 17 00:00:00 2001 From: Adam Stylinski Date: Sun, 11 Oct 2015 12:51:43 -0400 Subject: [PATCH 019/632] unix: make work with Solaris Studio. The atomics that are in place of a lack of x86 cmpxchg are a GCC specific intrinsic. When compiling for Solaris on a SPARC platform with a non-gcc compiler, this prevents a successful build. This commit will rely on a Solaris Studio specific preprocessor macro to redefine the GCC intrinsic name to be the Solaris Studio one instead. PR-URL: https://github.com/libuv/libuv/pull/569 Reviewed-By: Ben Noordhuis --- src/unix/atomic-ops.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h index 8fb157dcc..84e471838 100644 --- a/src/unix/atomic-ops.h +++ b/src/unix/atomic-ops.h @@ -18,6 +18,11 @@ #include "internal.h" /* UV_UNUSED */ +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#include +#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n) +#endif + UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)); UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)); UV_UNUSED(static void cpu_relax(void)); From a0e30b551cd6d0d77f005db14d443b808997ea57 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 20 Oct 2015 09:04:45 +0200 Subject: [PATCH 020/632] test: fix fs_event_watch_file_currentdir flakiness In FreeBSD 10.2 the test sometimes times out because the "touch file" timer fires before the "watch file" event has been registered in the kqueue. Increasing the timeout value seems to fix the issue. PR-URL: https://github.com/libuv/libuv/pull/581 Reviewed-By: Ben Noordhuis --- 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 a0908ce57..725103b74 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -487,7 +487,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) { r = uv_timer_init(loop, &timer); ASSERT(r == 0); - r = uv_timer_start(&timer, timer_cb_touch, 1, 0); + r = uv_timer_start(&timer, timer_cb_touch, 10, 0); ASSERT(r == 0); ASSERT(timer_cb_touch_called == 0); From bda29cf8083ceb33a9abda421da267e81030ff77 Mon Sep 17 00:00:00 2001 From: Nathan Corvino Date: Mon, 19 Oct 2015 02:48:05 -0700 Subject: [PATCH 021/632] unix: skip prohibited syscalls on tvOS and watchOS fork and the exec functions are marked prohibited on tvOS and watchOS, so referencing them causes compile errors. This adds preprocessor conditionals to avoid calling them for those targets. PR-URL: https://github.com/libuv/libuv/pull/580 Reviewed-By: Ben Noordhuis --- src/unix/process.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/unix/process.c b/src/unix/process.c index 9fa061e6b..571f8cd77 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -270,6 +270,11 @@ static void uv__write_int(int fd, int val) { } +#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], @@ -375,11 +380,16 @@ static void uv__process_child_init(const uv_process_options_t* options, uv__write_int(error_fd, -errno); _exit(127); } +#endif int uv_spawn(uv_loop_t* loop, uv_process_t* process, const uv_process_options_t* options) { +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ + return -ENOSYS; +#else int signal_pipe[2] = { -1, -1 }; int (*pipes)[2]; int stdio_count; @@ -528,6 +538,7 @@ int uv_spawn(uv_loop_t* loop, } return err; +#endif } From 7d7400c87f04aa780257785672735a2708cc9339 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 22 Oct 2015 12:17:55 -0700 Subject: [PATCH 022/632] test: use FQDN in getaddrinfo_fail test For the getaddrinfo_fail test cases you want to use a fully qualified domain name so that in network configurations that have a search domain the test will still fail. To create a fully qualified domain add a period at the end, see http://www.dns-sd.org/trailingdotsindomainnames.html for an explanation. Fixes: https://github.com/libuv/libuv/issues/583 PR-URL: https://github.com/libuv/libuv/pull/586 Reviewed-By: Ben Noordhuis --- test/test-getaddrinfo.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/test-getaddrinfo.c b/test/test-getaddrinfo.c index 45813c313..6b644a8d4 100644 --- a/test/test-getaddrinfo.c +++ b/test/test-getaddrinfo.c @@ -83,10 +83,11 @@ static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle, TEST_IMPL(getaddrinfo_fail) { uv_getaddrinfo_t req; + /* Use a FQDN by ending in a period */ ASSERT(0 == uv_getaddrinfo(uv_default_loop(), &req, getaddrinfo_fail_cb, - "xyzzy.xyzzy.xyzzy", + "xyzzy.xyzzy.xyzzy.", NULL, NULL)); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); @@ -100,10 +101,11 @@ TEST_IMPL(getaddrinfo_fail) { 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, - "xyzzy.xyzzy.xyzzy", + "xyzzy.xyzzy.xyzzy.", NULL, NULL)); uv_freeaddrinfo(req.addrinfo); From e9b5a86aa68dde78972559a6fcfe91721b97b97d Mon Sep 17 00:00:00 2001 From: Andrius Bentkus Date: Thu, 29 Oct 2015 02:44:26 +0200 Subject: [PATCH 023/632] docs: clarify documentation of uv_tcp_init_ex I think this makes it clear that the flags can't contain any other information. PR-URL: https://github.com/libuv/libuv/pull/592 Reviewed-By: Ben Noordhuis --- docs/src/tcp.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tcp.rst b/docs/src/tcp.rst index dd18522d9..ca0c9b4ac 100644 --- a/docs/src/tcp.rst +++ b/docs/src/tcp.rst @@ -34,7 +34,7 @@ API .. c:function:: int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) - Initialize the handle with the specified flags. At the moment the lower 8 bits + Initialize the handle with the specified flags. At the moment only the lower 8 bits of the `flags` parameter are used as the socket domain. A socket will be created for the given domain. If the specified domain is ``AF_UNSPEC`` no socket is created, just like :c:func:`uv_tcp_init`. From 010f0b96a37dbdce3b3216ebf8d6148be2bbe179 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 18 Oct 2015 11:00:55 +0200 Subject: [PATCH 024/632] win: fix comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following: ~~~~ src/win/tty.c: In function 'uv_tty_capture_initial_style': src/win/tty.c:211:3: error: "/" within comment [-Werror=comment] / Assumption: Caller has acquired uv_tty_output_lock. */ ~~~~ PR-URL: https://github.com/libuv/libuv/pull/578 Reviewed-By: Saúl Ibarra Corretgé --- 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 b40bb4271..d87cc6990 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -208,7 +208,7 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) { static int style_captured = 0; /* Only do this once. - /* Assumption: Caller has acquired uv_tty_output_lock. */ + Assumption: Caller has acquired uv_tty_output_lock. */ if (style_captured) return; From f3216246a21e7e451e2ada29c934ed375da83cc3 Mon Sep 17 00:00:00 2001 From: Angel Leon Date: Fri, 30 Oct 2015 17:14:54 -0400 Subject: [PATCH 025/632] doc: fix typo in README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/598 Reviewed-By: Saúl Ibarra Corretgé --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ce266997..dfd24ba79 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ Git tags are signed with the developer's key, they can be verified as follows: $ git verify-tag v1.6.1 Starting with libuv 1.7.0, the tarballs stored in the -[downloads site](http://dist.libuv.org/dist/) are signed and an accomanying +[downloads site](http://dist.libuv.org/dist/) are signed and an accompanying signature file sit alongside each. Once both the release tarball and the signature file are downloaded, the file can be verified as follows: From a6da5d7d6557fdfbb6887384b6119ef7e43f2d3f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 2 Nov 2015 01:00:48 +0100 Subject: [PATCH 026/632] darwin: abort() if (un)locking fs mutex fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pthread_mutex_lock() and pthread_mutex_unlock() calls logically cannot fail in uv__fs_write() but let's check the return value anyway: cosmic rays and memory corruption do happen. PR-URL: https://github.com/libuv/libuv/pull/603 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index d593d2ec6..3f5cd6aa5 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -630,7 +630,9 @@ static ssize_t uv__fs_write(uv_fs_t* req) { */ #if defined(__APPLE__) static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_lock(&lock); + + if (pthread_mutex_lock(&lock)) + abort(); #endif if (req->off < 0) { @@ -687,7 +689,8 @@ static ssize_t uv__fs_write(uv_fs_t* req) { done: #if defined(__APPLE__) - pthread_mutex_unlock(&lock); + if (pthread_mutex_unlock(&lock)) + abort(); #endif return r; From dfdecf000622ea4dc9eec24be8f0cae99c0469cd Mon Sep 17 00:00:00 2001 From: Louis DeJardin Date: Wed, 28 Oct 2015 11:40:51 -0700 Subject: [PATCH 027/632] pipe: enable inprocess uv_write2 on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When duplicating the socket handle being sent the target process id is defaulted to the current process id. This enables uv_write2 to be used for thread-clustering in addition to process-clustering on multi-threaded programming languages. The ipc tests are updated to run in two modes. In the _inproc mode the echo work is done on a second thread instead of in a second process. An internal function int uv_current_pid() is added to the windows specific code which caches the value of GetCurrentProcessId(). This means uv_write2 does not call GetCurrentProcessId() every inprocess send. Refs: https://github.com/joyent/libuv/issues/926 PR-URL: https://github.com/libuv/libuv/pull/540 Reviewed-By: Saúl Ibarra Corretgé --- src/win/internal.h | 1 + src/win/pipe.c | 4 + src/win/util.c | 12 +++ test/runner.c | 1 + test/test-ipc-send-recv.c | 176 ++++++++++++++++++++++++++++++-------- test/test-list.h | 4 + 6 files changed, 164 insertions(+), 34 deletions(-) diff --git a/src/win/internal.h b/src/win/internal.h index 8d4081bdb..783f21af0 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -327,6 +327,7 @@ void uv__util_init(); uint64_t uv__hrtime(double scale); int uv_parent_pid(); +int uv_current_pid(); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); diff --git a/src/win/pipe.c b/src/win/pipe.c index 796d06dcd..d57d77a41 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1246,6 +1246,10 @@ static int uv_pipe_write_impl(uv_loop_t* loop, if (send_handle) { tcp_send_handle = (uv_tcp_t*)send_handle; + if (handle->pipe.conn.ipc_pid == 0) { + handle->pipe.conn.ipc_pid = uv_current_pid(); + } + err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid, &ipc_frame.socket_info_ex.socket_info); if (err) { diff --git a/src/win/util.c b/src/win/util.c index a0d1307f8..cb2475130 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -59,6 +59,10 @@ static char *process_title; static CRITICAL_SECTION process_title_lock; +/* Cached copy of the process id, written once. */ +static DWORD current_pid = 0; + + /* Interval (in seconds) of the high-resolution clock. */ static double hrtime_interval_ = 0; @@ -359,6 +363,14 @@ int uv_parent_pid() { } +int uv_current_pid() { + if (current_pid == 0) { + current_pid = GetCurrentProcessId(); + } + return current_pid; +} + + char** uv_setup_args(int argc, char** argv) { return argv; } diff --git a/test/runner.c b/test/runner.c index e094defc7..914a067f3 100644 --- a/test/runner.c +++ b/test/runner.c @@ -210,6 +210,7 @@ int run_test(const char* test, #ifndef _WIN32 /* Clean up stale socket from previous run. */ remove(TEST_PIPENAME); + remove(TEST_PIPENAME_2); #endif /* If it's a helper the user asks for, start it directly. */ diff --git a/test/test-ipc-send-recv.c b/test/test-ipc-send-recv.c index d9b913339..d0558a940 100644 --- a/test/test-ipc-send-recv.c +++ b/test/test-ipc-send-recv.c @@ -30,6 +30,8 @@ void spawn_helper(uv_pipe_t* channel, uv_process_t* process, const char* helper); +void ipc_send_recv_helper_threadproc(void* arg); + union handles { uv_handle_t handle; uv_stream_t stream; @@ -38,15 +40,26 @@ union handles { uv_tty_t tty; }; -struct echo_ctx { +struct test_ctx { uv_pipe_t channel; + uv_connect_t connect_req; uv_write_t write_req; uv_handle_type expected_type; union handles send; union handles recv; }; -static struct echo_ctx ctx; +struct echo_ctx { + uv_pipe_t listen; + uv_pipe_t channel; + uv_write_t write_req; + uv_handle_type expected_type; + union handles recv; +}; + +static struct test_ctx ctx; +static struct echo_ctx ctx2; + static int num_recv_handles; @@ -92,13 +105,12 @@ static void recv_cb(uv_stream_t* handle, num_recv_handles++; } - -static int run_test(void) { - uv_process_t process; - uv_buf_t buf; +static void connect_cb(uv_connect_t* req, int status) { int r; + uv_buf_t buf; - spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper"); + ASSERT(req == &ctx.connect_req); + ASSERT(status == 0); buf = uv_buf_init(".", 1); r = uv_write2(&ctx.write_req, @@ -110,17 +122,43 @@ static int run_test(void) { r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb); ASSERT(r == 0); +} + +static int run_test(int inprocess) { + uv_process_t process; + uv_thread_t tid; + int r; + + if (inprocess) { + r = uv_thread_create(&tid, ipc_send_recv_helper_threadproc, (void *) 42); + ASSERT(r == 0); + + uv_sleep(1000); + + r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1); + ASSERT(r == 0); + + uv_pipe_connect(&ctx.connect_req, &ctx.channel, TEST_PIPENAME_2, connect_cb); + } else { + spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper"); + + connect_cb(&ctx.connect_req, 0); + } r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); ASSERT(num_recv_handles == 1); + if (inprocess) { + r = uv_thread_join(&tid); + ASSERT(r == 0); + } + return 0; } - -TEST_IMPL(ipc_send_recv_pipe) { +static int run_ipc_send_recv_pipe(int inprocess) { int r; ctx.expected_type = UV_NAMED_PIPE; @@ -131,15 +169,22 @@ TEST_IMPL(ipc_send_recv_pipe) { r = uv_pipe_bind(&ctx.send.pipe, TEST_PIPENAME); ASSERT(r == 0); - r = run_test(); + r = run_test(inprocess); ASSERT(r == 0); MAKE_VALGRIND_HAPPY(); return 0; } +TEST_IMPL(ipc_send_recv_pipe) { + return run_ipc_send_recv_pipe(0); +} -TEST_IMPL(ipc_send_recv_tcp) { +TEST_IMPL(ipc_send_recv_pipe_inprocess) { + return run_ipc_send_recv_pipe(1); +} + +static int run_ipc_send_recv_tcp(int inprocess) { struct sockaddr_in addr; int r; @@ -153,23 +198,31 @@ TEST_IMPL(ipc_send_recv_tcp) { r = uv_tcp_bind(&ctx.send.tcp, (const struct sockaddr*) &addr, 0); ASSERT(r == 0); - r = run_test(); + r = run_test(inprocess); ASSERT(r == 0); MAKE_VALGRIND_HAPPY(); return 0; } +TEST_IMPL(ipc_send_recv_tcp) { + return run_ipc_send_recv_tcp(0); +} + +TEST_IMPL(ipc_send_recv_tcp_inprocess) { + return run_ipc_send_recv_tcp(1); +} + -/* Everything here runs in a child process. */ +/* Everything here runs in a child process or second thread. */ static void write2_cb(uv_write_t* req, int status) { ASSERT(status == 0); - uv_close(&ctx.recv.handle, NULL); - uv_close((uv_handle_t*)&ctx.channel, NULL); + uv_close(&ctx2.recv.handle, NULL); + uv_close((uv_handle_t*)&ctx2.channel, NULL); + uv_close((uv_handle_t*)&ctx2.listen, NULL); } - static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* rdbuf) { @@ -178,8 +231,12 @@ static void read_cb(uv_stream_t* handle, uv_handle_type pending; int r; + if (nread == UV__EOF || nread == UV__ECONNABORTED) { + return; + } + pipe = (uv_pipe_t*) handle; - ASSERT(pipe == &ctx.channel); + ASSERT(pipe == &ctx2.channel); ASSERT(nread >= 0); ASSERT(1 == uv_pipe_pending_count(pipe)); @@ -189,25 +246,75 @@ static void read_cb(uv_stream_t* handle, wrbuf = uv_buf_init(".", 1); if (pending == UV_NAMED_PIPE) - r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0); + r = uv_pipe_init(ctx2.channel.loop, &ctx2.recv.pipe, 0); else if (pending == UV_TCP) - r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp); + r = uv_tcp_init(ctx2.channel.loop, &ctx2.recv.tcp); else abort(); ASSERT(r == 0); - r = uv_accept(handle, &ctx.recv.stream); + r = uv_accept(handle, &ctx2.recv.stream); ASSERT(r == 0); - r = uv_write2(&ctx.write_req, - (uv_stream_t*)&ctx.channel, + r = uv_write2(&ctx2.write_req, + (uv_stream_t*)&ctx2.channel, &wrbuf, 1, - &ctx.recv.stream, + &ctx2.recv.stream, write2_cb); ASSERT(r == 0); } +static void send_recv_start() { + 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)); + + r = uv_read_start((uv_stream_t*)&ctx2.channel, alloc_cb, read_cb); + ASSERT(r == 0); +} + +static void listen_cb(uv_stream_t* handle, int status) { + int r; + ASSERT(handle == (uv_stream_t*)&ctx2.listen); + ASSERT(status == 0); + + r = uv_accept((uv_stream_t*)&ctx2.listen, (uv_stream_t*)&ctx2.channel); + ASSERT(r == 0); + + send_recv_start(); +} + +int run_ipc_send_recv_helper(uv_loop_t* loop, int inprocess) { + int r; + + memset(&ctx2, 0, sizeof(ctx2)); + + r = uv_pipe_init(loop, &ctx2.listen, 0); + ASSERT(r == 0); + + r = uv_pipe_init(loop, &ctx2.channel, 1); + ASSERT(r == 0); + + if (inprocess) { + r = uv_pipe_bind(&ctx2.listen, TEST_PIPENAME_2); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&ctx2.listen, SOMAXCONN, listen_cb); + ASSERT(r == 0); + } else { + r = uv_pipe_open(&ctx2.channel, 0); + ASSERT(r == 0); + + send_recv_start(); + } + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + return 0; +} /* stdin is a duplex channel over which a handle is sent. * We receive it and send it back where it came from. @@ -215,22 +322,23 @@ static void read_cb(uv_stream_t* handle, int ipc_send_recv_helper(void) { int r; - memset(&ctx, 0, sizeof(ctx)); - - r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1); + r = run_ipc_send_recv_helper(uv_default_loop(), 0); ASSERT(r == 0); - uv_pipe_open(&ctx.channel, 0); - ASSERT(1 == uv_is_readable((uv_stream_t*)&ctx.channel)); - ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx.channel)); - ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx.channel)); + MAKE_VALGRIND_HAPPY(); + return 0; +} + +void ipc_send_recv_helper_threadproc(void* arg) { + int r; + uv_loop_t loop; - r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, read_cb); + r = uv_loop_init(&loop); ASSERT(r == 0); - r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + r = run_ipc_send_recv_helper(&loop, 1); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); - return 0; + r = uv_loop_close(&loop); + ASSERT(r == 0); } diff --git a/test/test-list.h b/test/test-list.h index 8ee74391a..040f3c00c 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -50,8 +50,10 @@ TEST_DECLARE (ipc_listen_before_write) TEST_DECLARE (ipc_listen_after_write) #ifndef _WIN32 TEST_DECLARE (ipc_send_recv_pipe) +TEST_DECLARE (ipc_send_recv_pipe_inprocess) #endif TEST_DECLARE (ipc_send_recv_tcp) +TEST_DECLARE (ipc_send_recv_tcp_inprocess) TEST_DECLARE (ipc_tcp_connection) TEST_DECLARE (tcp_ping_pong) TEST_DECLARE (tcp_ping_pong_v6) @@ -380,8 +382,10 @@ TASK_LIST_START TEST_ENTRY (ipc_listen_after_write) #ifndef _WIN32 TEST_ENTRY (ipc_send_recv_pipe) + TEST_ENTRY (ipc_send_recv_pipe_inprocess) #endif TEST_ENTRY (ipc_send_recv_tcp) + TEST_ENTRY (ipc_send_recv_tcp_inprocess) TEST_ENTRY (ipc_tcp_connection) TEST_ENTRY (tcp_ping_pong) From 77eda8d90b51c8a654f97fd8d2c32ccc8280191a Mon Sep 17 00:00:00 2001 From: Nikolai Vavilov Date: Wed, 11 Nov 2015 13:18:31 +0200 Subject: [PATCH 028/632] win: properly return UV_EBADF when _close() fails Previously, libuv didn't return the correct error code when attempting to close an invalid file descriptor with `uv_fs_close()`. PR-URL: https://github.com/libuv/libuv/pull/613 Reviewed-by: Bert Belder --- src/win/fs.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/win/fs.c b/src/win/fs.c index 4a1757311..fe56dba63 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -533,7 +533,15 @@ void fs__close(uv_fs_t* req) { else result = 0; - SET_REQ_RESULT(req, result); + /* _close doesn't set _doserrno on failure, but it does always set errno + * to EBADF on failure. + */ + if (result == -1) { + assert(errno == EBADF); + SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE); + } else { + req->result = 0; + } } From baf700acdb58c1294b1d7a2403a3fde694ce50f0 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Wed, 11 Nov 2015 16:31:15 -0500 Subject: [PATCH 029/632] test: skip process_title for AIX uv_(get|set)_process_title is not implemented for AIX. See unix/aix.c PR-URL: https://github.com/libuv/libuv/pull/616 Reviewed-By: Ben Noordhuis --- test/test-process-title.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-process-title.c b/test/test-process-title.c index 29be20749..42ade4416 100644 --- a/test/test-process-title.c +++ b/test/test-process-title.c @@ -42,7 +42,7 @@ static void set_title(const char* title) { TEST_IMPL(process_title) { -#if defined(__sun) +#if defined(__sun) || defined(_AIX) RETURN_SKIP("uv_(get|set)_process_title is not implemented."); #else /* Check for format string vulnerabilities. */ From 6490c508a9db719f25ca3b37a0987ca4d923bbe4 Mon Sep 17 00:00:00 2001 From: Petka Antonov Date: Mon, 16 Nov 2015 10:22:00 +0200 Subject: [PATCH 030/632] misc: expose handle print APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/291 Reviewed-By: Saúl Ibarra Corretgé --- docs/src/misc.rst | 38 ++++++++++++++++++++++++++++++++++++++ include/uv.h | 4 ++++ src/uv-common.c | 14 ++++++-------- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index e9ddba3db..2ce0887db 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -288,3 +288,41 @@ API .. note:: Not every platform can support nanosecond resolution; however, this value will always be in nanoseconds. + +.. 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`. + + Example: + + :: + + uv_print_all_handles(uv_default_loop(), stderr); + /* + [--I] signal 0x1a25ea8 + [-AI] async 0x1a25cf0 + [R--] idle 0x1a7a8c8 + */ + + The format is `[flags] handle-type handle-address`. For `flags`: + + - `R` is printed for a handle that is referenced + - `A` is printed for a handle that is active + - `I` is printed for a handle that is internal + + .. warning:: + This function is meant for ad hoc debugging, there is no API/ABI + stability guarantees. + + .. versionadded:: 1.8.0 + +.. c:function:: void uv_print_active_handles(uv_loop_t* loop, FILE* stream) + + This is the same as :c:func:`uv_print_all_handles` except only active handles + are printed. + + .. warning:: + This function is meant for ad hoc debugging, there is no API/ABI + stability guarantees. + + .. versionadded:: 1.8.0 diff --git a/include/uv.h b/include/uv.h index 9d81514a8..acd00d102 100644 --- a/include/uv.h +++ b/include/uv.h @@ -424,6 +424,10 @@ UV_EXTERN int uv_is_active(const uv_handle_t* handle); UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg); +/* Helpers for ad hoc debugging, no API/ABI stability guaranteed. */ +UV_EXTERN void uv_print_all_handles(uv_loop_t* loop, FILE* stream); +UV_EXTERN void uv_print_active_handles(uv_loop_t* loop, FILE* stream); + UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb); UV_EXTERN int uv_send_buffer_size(uv_handle_t* handle, int* value); diff --git a/src/uv-common.c b/src/uv-common.c index 539756c8b..40ed28fec 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -355,8 +355,7 @@ void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { } -#ifndef NDEBUG -static void uv__print_handles(uv_loop_t* loop, int only_active) { +static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) { const char* type; QUEUE* q; uv_handle_t* h; @@ -377,7 +376,7 @@ static void uv__print_handles(uv_loop_t* loop, int only_active) { default: type = ""; } - fprintf(stderr, + fprintf(stream, "[%c%c%c] %-8s %p\n", "R-"[!(h->flags & UV__HANDLE_REF)], "A-"[!(h->flags & UV__HANDLE_ACTIVE)], @@ -388,15 +387,14 @@ static void uv__print_handles(uv_loop_t* loop, int only_active) { } -void uv_print_all_handles(uv_loop_t* loop) { - uv__print_handles(loop, 0); +void uv_print_all_handles(uv_loop_t* loop, FILE* stream) { + uv__print_handles(loop, 0, stream); } -void uv_print_active_handles(uv_loop_t* loop) { - uv__print_handles(loop, 1); +void uv_print_active_handles(uv_loop_t* loop, FILE* stream) { + uv__print_handles(loop, 1, stream); } -#endif void uv_ref(uv_handle_t* handle) { From f41b7386de48a50a1cc3d1549a118b7bd596711d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 16 Nov 2015 17:45:38 +0100 Subject: [PATCH 031/632] include: add stdio.h to uv.h Fixes a compilation problem in some platforms (notably OSX) after 6490c50. PR-URL: https://github.com/libuv/libuv/pull/618 Reviewed-By: Ben Noordhuis Reviewed-By: Jeremy Whitlock --- include/uv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uv.h b/include/uv.h index acd00d102..d0c071ce7 100644 --- a/include/uv.h +++ b/include/uv.h @@ -48,6 +48,7 @@ extern "C" { #include "uv-errno.h" #include "uv-version.h" #include +#include #if defined(_MSC_VER) && _MSC_VER < 1600 # include "stdint-msvc2008.h" From 81072b98f5a8f7830161ef65a6bdd50906a88e72 Mon Sep 17 00:00:00 2001 From: Ian Kronquist Date: Mon, 2 Nov 2015 14:49:22 -0800 Subject: [PATCH 032/632] misc: remove unnecessary null pointer checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/595 PR-URL: https://github.com/libuv/libuv/pull/604 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/dl.c | 9 +++------ src/unix/freebsd.c | 2 +- src/unix/openbsd.c | 2 +- src/win/getaddrinfo.c | 13 +++++-------- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/unix/dl.c b/src/unix/dl.c index 7c6d41c96..fc1c052bb 100644 --- a/src/unix/dl.c +++ b/src/unix/dl.c @@ -39,10 +39,8 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) { void uv_dlclose(uv_lib_t* lib) { - if (lib->errmsg) { - uv__free(lib->errmsg); - lib->errmsg = NULL; - } + uv__free(lib->errmsg); + lib->errmsg = NULL; if (lib->handle) { /* Ignore errors. No good way to signal them without leaking memory. */ @@ -67,8 +65,7 @@ const char* uv_dlerror(const uv_lib_t* lib) { static int uv__dlerror(uv_lib_t* lib) { const char* errmsg; - if (lib->errmsg) - uv__free(lib->errmsg); + uv__free(lib->errmsg); errmsg = dlerror(); diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index ddfd0f28a..b747abdf5 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -176,7 +176,7 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { int oid[4]; - if (process_title) uv__free(process_title); + uv__free(process_title); process_title = uv__strdup(title); oid[0] = CTL_KERN; diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index e6ca7a8b0..6a3909a66 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -161,7 +161,7 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { - if (process_title) uv__free(process_title); + uv__free(process_title); process_title = uv__strdup(title); setproctitle(title); return 0; diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index 3d23660e8..ceed3b763 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -109,10 +109,8 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { req = container_of(w, uv_getaddrinfo_t, work_req); /* release input parameter memory */ - if (req->alloc != NULL) { - uv__free(req->alloc); - req->alloc = NULL; - } + uv__free(req->alloc); + req->alloc = NULL; if (status == UV_ECANCELED) { assert(req->retcode == 0); @@ -219,9 +217,7 @@ void uv_freeaddrinfo(struct addrinfo* ai) { char* alloc_ptr = (char*)ai; /* release copied result memory */ - if (alloc_ptr != NULL) { - uv__free(alloc_ptr); - } + uv__free(alloc_ptr); } @@ -354,8 +350,9 @@ int uv_getaddrinfo(uv_loop_t* loop, } error: - if (req != NULL && req->alloc != NULL) { + if (req != NULL) { uv__free(req->alloc); + req->alloc = NULL; } return uv_translate_sys_error(err); } From 4052c747971f0f57cb14dd5cc9a64d7b8788e733 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 11 Nov 2015 10:10:19 +0100 Subject: [PATCH 033/632] test,freebsd: skip udp_dual_stack if not supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By default, FreeBSD has net.inet6.ip6.v6only set to 1 (i.e., no dual stack support). A new function can_ipv6_ipv4_dual is added to check its value and decide whether `udp_dual_stack` test must be skipped or not. PR-URL: https://github.com/libuv/libuv/pull/614 Reviewed-By: Saúl Ibarra Corretgé --- test/test-udp-ipv6.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/test-udp-ipv6.c b/test/test-udp-ipv6.c index 1d5720ce7..1b0db78b8 100644 --- a/test/test-udp-ipv6.c +++ b/test/test-udp-ipv6.c @@ -26,6 +26,10 @@ #include #include +#ifdef __FreeBSD__ +#include +#endif + #define CHECK_HANDLE(handle) \ ASSERT((uv_udp_t*)(handle) == &server \ || (uv_udp_t*)(handle) == &client \ @@ -43,6 +47,18 @@ static int send_cb_called; static int recv_cb_called; static int close_cb_called; +#ifdef __FreeBSD__ +static int can_ipv6_ipv4_dual() { + int v6only; + size_t size = sizeof(int); + + if (sysctlbyname("net.inet6.ip6.v6only", &v6only, &size, NULL, 0)) + return 0; + + return v6only != 1; +} +#endif + static void alloc_cb(uv_handle_t* handle, size_t suggested_size, @@ -150,6 +166,11 @@ TEST_IMPL(udp_dual_stack) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); +#ifdef __FreeBSD__ + if (!can_ipv6_ipv4_dual()) + RETURN_SKIP("IPv6-IPv4 dual stack not supported"); +#endif + do_test(ipv6_recv_ok, 0); ASSERT(recv_cb_called == 1); From af7a3614d0d64233bae84fe089faefbcf720e95b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 5 Nov 2015 16:49:38 +0100 Subject: [PATCH 034/632] linux: don't retry dup2/dup3 on EINTR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retrying seems like a bad idea in a multi-threaded program because the man page leaves it unspecified whether the file descriptor is closed after EINTR. It's probably an academic issue because as far as I have been able to establish by checking the kernel sources, dup2 and dup3 never actually return EINTR. For dup3, this appears to have been the case since its introduction in v2.6.27; for dup2, it goes back to at least v2.6.18. Fixes: https://github.com/libuv/libuv/issues/462 PR-URL: https://github.com/libuv/libuv/pull/608 Reviewed-By: Saúl Ibarra Corretgé --- 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 0db5f828c..efbb85d44 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -980,7 +980,7 @@ int uv__dup2_cloexec(int oldfd, int newfd) { if (!no_dup3) { do r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC); - while (r == -1 && (errno == EINTR || errno == EBUSY)); + while (r == -1 && errno == EBUSY); if (r != -1) return r; if (errno != ENOSYS) @@ -994,7 +994,7 @@ int uv__dup2_cloexec(int oldfd, int newfd) { do r = dup2(oldfd, newfd); #if defined(__linux__) - while (r == -1 && (errno == EINTR || errno == EBUSY)); + while (r == -1 && errno == EBUSY); #else while (r == -1 && errno == EINTR); #endif From 9bbc1137eee705b818f145c3819e1383771fcbb2 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 5 Nov 2015 17:06:53 +0100 Subject: [PATCH 035/632] unix: don't retry dup2/dup3 on EINTR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like the previous commit, but this time for UNIX platforms other than Linux. As far as I have been able to establish, dup2 and dup3 never return EINTR on OS X and FreeBSD. Even if other platforms do return EINTR, it's probably still better not to retry because it's unspecified whether the file descriptor has been closed. Fixes: https://github.com/libuv/libuv/issues/462 PR-URL: https://github.com/libuv/libuv/pull/608 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/core.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index efbb85d44..a06a8c16c 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -960,16 +960,12 @@ int uv__open_cloexec(const char* path, int flags) { int uv__dup2_cloexec(int oldfd, int newfd) { int r; #if defined(__FreeBSD__) && __FreeBSD__ >= 10 - do - r = dup3(oldfd, newfd, O_CLOEXEC); - while (r == -1 && errno == EINTR); + r = dup3(oldfd, newfd, O_CLOEXEC); if (r == -1) return -errno; return r; #elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC) - do - r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); - while (r == -1 && errno == EINTR); + r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); if (r != -1) return r; if (errno != EINVAL) @@ -996,7 +992,7 @@ int uv__dup2_cloexec(int oldfd, int newfd) { #if defined(__linux__) while (r == -1 && errno == EBUSY); #else - while (r == -1 && errno == EINTR); + while (0); /* Never retry. */ #endif if (r == -1) From 5f15f72ccacd5243b354b2cfc7d573389ac60340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 18 Nov 2015 22:13:11 +0100 Subject: [PATCH 036/632] test: fix -Wtautological-pointer-compare warnings ~~~~ test/test-get-loadavg.c:30:14: warning: comparison of array 'avg' not equal to a null pointer is always true [-Wtautological-pointer-compare] test/test-getnameinfo.c:76:18: warning: comparison of array 'req.host' not equal to a null pointer is always true [-Wtautological-pointer-compare] test/test-getnameinfo.c:77:18: warning: comparison of array 'req.service' not equal to a null pointer is always true [-Wtautological-pointer-compare] ~~~~ PR-URL: https://github.com/libuv/libuv/pull/622 Reviewed-By: Ben Noordhuis --- test/test-get-loadavg.c | 3 +-- test/test-getnameinfo.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/test-get-loadavg.c b/test/test-get-loadavg.c index 7465e18b9..4762e4757 100644 --- a/test/test-get-loadavg.c +++ b/test/test-get-loadavg.c @@ -24,10 +24,9 @@ TEST_IMPL(get_loadavg) { - double avg[3]; + double avg[3] = {-1, -1, -1}; uv_loadavg(avg); - ASSERT(avg != NULL); ASSERT(avg[0] >= 0); ASSERT(avg[1] >= 0); ASSERT(avg[2] >= 0); diff --git a/test/test-getnameinfo.c b/test/test-getnameinfo.c index ebe924669..b1391616d 100644 --- a/test/test-getnameinfo.c +++ b/test/test-getnameinfo.c @@ -73,8 +73,8 @@ TEST_IMPL(getnameinfo_basic_ip4_sync) { NULL, (const struct sockaddr*)&addr4, 0)); - ASSERT(req.host != NULL); - ASSERT(req.service != NULL); + ASSERT(req.host[0] != '\0'); + ASSERT(req.service[0] != '\0'); MAKE_VALGRIND_HAPPY(); return 0; From 7b9bc28e85b81bb2c116912038ae976f815824c4 Mon Sep 17 00:00:00 2001 From: Tony Kelman Date: Wed, 18 Nov 2015 16:42:23 -0800 Subject: [PATCH 037/632] win: map ERROR_BAD_PATHNAME to UV_ENOENT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit e.g. when trying to call uv_fs_stat on "Z:\\:\\a" for a network drive Z: Refs: https://github.com/joyent/libuv/issues/390 PR-URL: https://github.com/libuv/libuv/pull/623 Reviewed-By: Saúl Ibarra Corretgé --- src/win/error.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win/error.c b/src/win/error.c index a265a272d..c512f35af 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -129,6 +129,7 @@ int uv_translate_sys_error(int sys_errno) { case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH; case WSAENETUNREACH: return UV_ENETUNREACH; case WSAENOBUFS: return UV_ENOBUFS; + case ERROR_BAD_PATHNAME: return UV_ENOENT; case ERROR_DIRECTORY: return UV_ENOENT; case ERROR_FILE_NOT_FOUND: return UV_ENOENT; case ERROR_INVALID_NAME: return UV_ENOENT; From f5796d2fbac47b026e3cc3f2b988a18c1d5b3f21 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Fri, 20 Nov 2015 15:04:55 -0500 Subject: [PATCH 038/632] test: fix test/test-tty.c for AIX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit '/dev/random' causes 'isatty()' to return 1 on AIX[1]. This causes an issue where 'dev/tty' is opened (hard coded in src/unix/tty.c:uv_tty_init). Tried to replace the hardcoded value with what is returned by 'ttyname()' but on AIX all that is returned is '/dev/'. This seems to be a bug with the AIX kernel. [1]http://goo.gl/wGa7mf PR-URL: https://github.com/libuv/libuv/pull/624 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- test/test-tty.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test-tty.c b/test/test-tty.c index 81e612c1d..b844959d5 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -153,11 +153,14 @@ TEST_IMPL(tty_file) { ASSERT(0 == close(fd)); } +/* 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)); } +#endif /* _AIX */ fd = open("/dev/zero", O_RDONLY); if (fd != -1) { From 43994b4e3c86f594eb25a47b87b3d82228dd5746 Mon Sep 17 00:00:00 2001 From: kkdaemon Date: Mon, 30 Nov 2015 15:14:25 +0300 Subject: [PATCH 039/632] android: support api level less than 21 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove restriction to Android API level >= 21, now libuv can be used with Android API level at least 14. Direct use of getpwuid_r function resulted in linker errors in applications were built against API level below 21. That function was 'officially' introduced in Android API level 21, but it exists in libc beginning from API level at least 14. So try to get a pointer to getpwuid_r at runtime using dlsym when building libuv with API level < 21. PR-URL: https://github.com/libuv/libuv/pull/633 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/unix/core.c b/src/unix/core.c index a06a8c16c..cedd86ed3 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -75,6 +75,10 @@ #include #endif +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 +# include /* for dlsym */ +#endif + static int uv__run_pending(uv_loop_t* loop); /* Verify that uv_buf_t is ABI-compatible with struct iovec. */ @@ -1018,6 +1022,9 @@ int uv_os_homedir(char* buffer, size_t* size) { size_t len; long initsize; int r; +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); +#endif if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; @@ -1039,6 +1046,12 @@ int uv_os_homedir(char* buffer, size_t* size) { return 0; } +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); + if (getpwuid_r == NULL) + return -ENOSYS; +#endif + /* HOME is not set, so call getpwuid() */ initsize = sysconf(_SC_GETPW_R_SIZE_MAX); From 0761bfe6a3d6c08326630879574354141741b0f1 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Wed, 2 Dec 2015 03:59:10 -0500 Subject: [PATCH 040/632] fsevents: fix race on simultaneous init+close When `uv_fsevents_t` handle is closed immediately after initializing, there is a possibility that the `CFRunLoop`'s thread will process both of these events at the same time. `uv__is_active(handle)` will return `0`, and the `uv_close()` semaphore will be unblocked, leading to the use after free in node.js. See: https://github.com/nodejs/node/issues/4091 PR-URL: https://github.com/libuv/libuv/pull/637 Reviewed-By: Ben Noordhuis --- src/unix/fsevents.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c index 8f582c41c..d331a1317 100644 --- a/src/unix/fsevents.c +++ b/src/unix/fsevents.c @@ -73,9 +73,16 @@ typedef struct uv__fsevents_event_s uv__fsevents_event_t; typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t; typedef struct uv__cf_loop_state_s uv__cf_loop_state_t; +enum uv__cf_loop_signal_type_e { + kUVCFLoopSignalRegular, + kUVCFLoopSignalClosing +}; +typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t; + struct uv__cf_loop_signal_s { QUEUE member; uv_fs_event_t* handle; + uv__cf_loop_signal_type_t type; }; struct uv__fsevents_event_s { @@ -98,7 +105,9 @@ struct uv__cf_loop_state_s { /* Forward declarations */ static void uv__cf_loop_cb(void* arg); static void* uv__cf_loop_runner(void* arg); -static int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle); +static int uv__cf_loop_signal(uv_loop_t* loop, + uv_fs_event_t* handle, + uv__cf_loop_signal_type_t type); /* Lazy-loaded by uv__fsevents_global_init(). */ static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef, @@ -383,7 +392,8 @@ 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_fs_event_t* handle, + uv__cf_loop_signal_type_t type) { uv__cf_loop_state_t* state; QUEUE* q; uv_fs_event_t* curr; @@ -482,7 +492,7 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle) { * * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close` */ - if (!uv__is_active(handle)) + if (type == kUVCFLoopSignalClosing) uv_sem_post(&state->fsevent_sem); } @@ -672,7 +682,7 @@ void uv__fsevents_loop_delete(uv_loop_t* loop) { if (loop->cf_state == NULL) return; - if (uv__cf_loop_signal(loop, NULL) != 0) + if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0) abort(); uv_thread_join(&loop->cf_thread); @@ -746,7 +756,7 @@ static void uv__cf_loop_cb(void* arg) { if (s->handle == NULL) pCFRunLoopStop(state->loop); else - uv__fsevents_reschedule(s->handle); + uv__fsevents_reschedule(s->handle, s->type); uv__free(s); } @@ -754,7 +764,9 @@ static void uv__cf_loop_cb(void* arg) { /* Runs in UV loop to notify CF thread */ -int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) { +int uv__cf_loop_signal(uv_loop_t* loop, + uv_fs_event_t* handle, + uv__cf_loop_signal_type_t type) { uv__cf_loop_signal_t* item; uv__cf_loop_state_t* state; @@ -763,6 +775,7 @@ int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) { return -ENOMEM; item->handle = handle; + item->type = type; uv_mutex_lock(&loop->cf_mutex); QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member); @@ -825,7 +838,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) { /* Reschedule FSEventStream */ assert(handle != NULL); - err = uv__cf_loop_signal(handle->loop, handle); + err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular); if (err) goto fail_loop_signal; @@ -865,7 +878,7 @@ int uv__fsevents_close(uv_fs_event_t* handle) { /* Reschedule FSEventStream */ assert(handle != NULL); - err = uv__cf_loop_signal(handle->loop, handle); + err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing); if (err) return -err; From 176fdc735205f009b9c66e498d7b35a0142531c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 3 Dec 2015 01:44:14 +0100 Subject: [PATCH 041/632] linux,fs: fix p{read,write}v with a 64bit offset According to [0] we need to pass it in 2 32bit registers on some platforms such as MIPS. Fix inspired by the musl libc implementation [1]. [0]: http://man7.org/linux/man-pages/man2/syscall.2.html#NOTES [1]: http://git.musl-libc.org/cgit/musl/tree/src/unistd/preadv.c Fixes: https://github.com/libuv/libuv/issues/473 Refs: https://github.com/libuv/libuv/pull/498 Refs: https://github.com/libuv/libuv/pull/627 PR-URL: https://github.com/libuv/libuv/pull/638 Reviewed-By: Ben Noordhuis --- src/unix/linux-syscalls.c | 8 ++++---- src/unix/linux-syscalls.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/unix/linux-syscalls.c b/src/unix/linux-syscalls.c index 566e1f37c..89998ded2 100644 --- a/src/unix/linux-syscalls.c +++ b/src/unix/linux-syscalls.c @@ -444,18 +444,18 @@ int uv__utimesat(int dirfd, } -ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) { +ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { #if defined(__NR_preadv) - return syscall(__NR_preadv, fd, iov, iovcnt, offset); + return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); #else return errno = ENOSYS, -1; #endif } -ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) { +ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { #if defined(__NR_pwritev) - return syscall(__NR_pwritev, fd, iov, iovcnt, offset); + return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); #else return errno = ENOSYS, -1; #endif diff --git a/src/unix/linux-syscalls.h b/src/unix/linux-syscalls.h index 6f249b724..96e79439c 100644 --- a/src/unix/linux-syscalls.h +++ b/src/unix/linux-syscalls.h @@ -151,8 +151,8 @@ int uv__utimesat(int dirfd, const char* path, const struct timespec times[2], int flags); -ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); -ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); +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); #endif /* UV_LINUX_SYSCALL_H_ */ From e76b8838e51f6e8f1944b6c6d50c3948ed764a0b Mon Sep 17 00:00:00 2001 From: Yuval Brik Date: Sat, 19 Sep 2015 00:40:34 +0300 Subject: [PATCH 042/632] fs: add uv_fs_realpath() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Equivalent to realpath(3), returns the full resolved absolute path of a file or directory. PR-URL: https://github.com/libuv/libuv/pull/531 Reviewed-By: Saúl Ibarra Corretgé --- docs/src/fs.rst | 10 ++ include/uv.h | 7 +- src/unix/fs.c | 53 +++++++-- src/win/fs.c | 205 ++++++++++++++++++++++++++-------- src/win/winapi.c | 4 + src/win/winapi.h | 7 ++ test/test-fs.c | 142 +++++++++++++++++++++-- test/test-list.h | 2 + test/test-threadpool-cancel.c | 3 +- 9 files changed, 368 insertions(+), 65 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 33c04406f..69e283f4c 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -279,6 +279,16 @@ API Equivalent to :man:`readlink(2)`. +.. 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()``. + + .. 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) .. c:function:: 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) diff --git a/include/uv.h b/include/uv.h index d0c071ce7..dd3111a96 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1088,7 +1088,8 @@ typedef enum { UV_FS_SYMLINK, UV_FS_READLINK, UV_FS_CHOWN, - UV_FS_FCHOWN + UV_FS_FCHOWN, + UV_FS_REALPATH } uv_fs_type; /* uv_fs_t is a subclass of uv_req_t. */ @@ -1240,6 +1241,10 @@ UV_EXTERN int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb); +UV_EXTERN int uv_fs_realpath(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, diff --git a/src/unix/fs.c b/src/unix/fs.c index 3f5cd6aa5..57b65be25 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -374,20 +374,27 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) { } -static ssize_t uv__fs_readlink(uv_fs_t* req) { - ssize_t len; - char* buf; +static ssize_t uv__fs_pathmax_size(const char* path) { + ssize_t pathmax; - len = pathconf(req->path, _PC_PATH_MAX); + pathmax = pathconf(path, _PC_PATH_MAX); - if (len == -1) { + if (pathmax == -1) { #if defined(PATH_MAX) - len = PATH_MAX; + return PATH_MAX; #else - len = 4096; + return 4096; #endif } + return pathmax; +} + +static ssize_t uv__fs_readlink(uv_fs_t* req) { + ssize_t len; + char* buf; + + len = uv__fs_pathmax_size(req->path); buf = uv__malloc(len + 1); if (buf == NULL) { @@ -408,6 +415,27 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) { return 0; } +static ssize_t uv__fs_realpath(uv_fs_t* req) { + ssize_t len; + char* buf; + + len = uv__fs_pathmax_size(req->path); + buf = uv__malloc(len + 1); + + if (buf == NULL) { + errno = ENOMEM; + return -1; + } + + if (realpath(req->path, buf) == NULL) { + uv__free(buf); + return -1; + } + + req->ptr = buf; + + return 0; +} static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) { struct pollfd pfd; @@ -874,6 +902,7 @@ static void uv__fs_work(struct uv__work* w) { X(READ, uv__fs_buf_iter(req, uv__fs_read)); X(SCANDIR, uv__fs_scandir(req)); X(READLINK, uv__fs_readlink(req)); + X(REALPATH, uv__fs_realpath(req)); X(RENAME, rename(req->path, req->new_path)); X(RMDIR, rmdir(req->path)); X(SENDFILE, uv__fs_sendfile(req)); @@ -1144,6 +1173,16 @@ int uv_fs_readlink(uv_loop_t* loop, } +int uv_fs_realpath(uv_loop_t* loop, + uv_fs_t* req, + const char * path, + uv_fs_cb cb) { + INIT(REALPATH); + PATH; + POST; +} + + int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, diff --git a/src/win/fs.c b/src/win/fs.c index fe56dba63..a32b0127f 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -110,6 +110,9 @@ const WCHAR JUNCTION_PREFIX_LEN = 4; const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\"; const WCHAR LONG_PATH_PREFIX_LEN = 4; +const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\"; +const WCHAR UNC_PATH_PREFIX_LEN = 8; + void uv_fs_init() { _fmode = _O_BINARY; @@ -233,14 +236,61 @@ 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); + + if (target_len == 0) { + return -1; + } + + if (target_len_ptr != NULL) { + *target_len_ptr = target_len; + } + + if (target_ptr == NULL) { + return 0; + } + + target = uv__malloc(target_len + 1); + if (target == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + + 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) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer; - WCHAR *w_target; + WCHAR* w_target; DWORD w_target_len; - char* target; - int target_len; DWORD bytes; if (!DeviceIoControl(handle, @@ -333,50 +383,7 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, return -1; } - /* If needed, compute the length of the target. */ - if (target_ptr != NULL || target_len_ptr != NULL) { - /* Compute the length of the target. */ - target_len = WideCharToMultiByte(CP_UTF8, - 0, - w_target, - w_target_len, - NULL, - 0, - NULL, - NULL); - if (target_len == 0) { - return -1; - } - } - - /* If requested, allocate memory and convert to UTF8. */ - if (target_ptr != NULL) { - int r; - target = (char*) uv__malloc(target_len + 1); - if (target == NULL) { - SetLastError(ERROR_OUTOFMEMORY); - return -1; - } - - r = WideCharToMultiByte(CP_UTF8, - 0, - w_target, - w_target_len, - target, - target_len, - NULL, - NULL); - assert(r == target_len); - target[target_len] = '\0'; - - *target_ptr = target; - } - - if (target_len_ptr != NULL) { - *target_len_ptr = target_len; - } - - return 0; + return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr); } @@ -1707,6 +1714,84 @@ static void fs__readlink(uv_fs_t* req) { } +static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { + int r; + DWORD w_realpath_len; + WCHAR* w_realpath_ptr; + WCHAR* w_finalpath_ptr = NULL; + + w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); + if (w_realpath_len == 0) { + return -1; + } + + w_realpath_ptr = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); + if (w_realpath_ptr == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + + if (pGetFinalPathNameByHandleW(handle, + w_realpath_ptr, + w_realpath_len, + VOLUME_NAME_DOS) == 0) { + uv__free(w_realpath_ptr); + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } + + /* convert UNC path to long path */ + if (wcsncmp(w_realpath_ptr, + UNC_PATH_PREFIX, + UNC_PATH_PREFIX_LEN) == 0) { + w_finalpath_ptr = w_realpath_ptr + 6; + *w_finalpath_ptr = L'\\'; + } else if (wcsncmp(w_realpath_ptr, + LONG_PATH_PREFIX, + LONG_PATH_PREFIX_LEN) == 0) { + w_finalpath_ptr = w_realpath_ptr + 4; + } else { + uv__free(w_realpath_ptr); + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } + + r = fs__wide_to_utf8(w_finalpath_ptr, w_realpath_len, realpath_ptr, NULL); + uv__free(w_realpath_ptr); + return r; +} + +static void fs__realpath(uv_fs_t* req) { + HANDLE handle; + + if (!pGetFinalPathNameByHandleW) { + SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); + return; + } + + handle = CreateFileW(req->file.pathw, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) { + CloseHandle(handle); + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + CloseHandle(handle); + req->flags |= UV_FS_FREE_PTR; + SET_REQ_RESULT(req, 0); +} + static void fs__chown(uv_fs_t* req) { req->result = 0; @@ -1751,6 +1836,7 @@ static void uv__fs_work(struct uv__work* w) { XX(LINK, link) XX(SYMLINK, symlink) XX(READLINK, readlink) + XX(REALPATH, realpath) XX(CHOWN, chown) XX(FCHOWN, fchown); default: @@ -2075,6 +2161,31 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, } +int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + if (!req || !path) { + return UV_EINVAL; + } + + uv_fs_req_init(loop, req, UV_FS_REALPATH, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__realpath(req); + return req->result; + } +} + + 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 err; diff --git a/src/win/winapi.c b/src/win/winapi.c index b0b7fd825..26bd06486 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -46,6 +46,7 @@ sSleepConditionVariableSRW pSleepConditionVariableSRW; sWakeAllConditionVariable pWakeAllConditionVariable; sWakeConditionVariable pWakeConditionVariable; sCancelSynchronousIo pCancelSynchronousIo; +sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; void uv_winapi_init() { @@ -139,4 +140,7 @@ void uv_winapi_init() { pCancelSynchronousIo = (sCancelSynchronousIo) GetProcAddress(kernel32_module, "CancelSynchronousIo"); + + pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW) + GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW"); } diff --git a/src/win/winapi.h b/src/win/winapi.h index 5bc79bcab..122198a6d 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4678,6 +4678,12 @@ typedef VOID (WINAPI* sWakeConditionVariable) typedef BOOL (WINAPI* sCancelSynchronousIo) (HANDLE hThread); +typedef DWORD (WINAPI* sGetFinalPathNameByHandleW) + (HANDLE hFile, + LPWSTR lpszFilePath, + DWORD cchFilePath, + DWORD dwFlags); + /* Ntdll function pointers */ extern sRtlNtStatusToDosError pRtlNtStatusToDosError; extern sNtDeviceIoControlFile pNtDeviceIoControlFile; @@ -4699,5 +4705,6 @@ extern sSleepConditionVariableSRW pSleepConditionVariableSRW; extern sWakeAllConditionVariable pWakeAllConditionVariable; extern sWakeConditionVariable pWakeConditionVariable; extern sCancelSynchronousIo pCancelSynchronousIo; +extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; #endif /* UV_WIN_WINAPI_H_ */ diff --git a/test/test-fs.c b/test/test-fs.c index 90572ca61..cf37ac490 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -83,6 +83,7 @@ static int fchown_cb_count; static int link_cb_count; static int symlink_cb_count; static int readlink_cb_count; +static int realpath_cb_count; static int utime_cb_count; static int futime_cb_count; @@ -168,6 +169,35 @@ 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); +#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); +#ifdef _WIN32 + strcat(test_file_abs_buf, "\\test_file"); + ASSERT(stricmp(req->ptr, test_file_abs_buf) == 0); +#else + strcat(test_file_abs_buf, "/test_file"); + ASSERT(strcmp(req->ptr, test_file_abs_buf) == 0); +#endif + realpath_cb_count++; + uv_fs_req_cleanup(req); +} + + static void access_cb(uv_fs_t* req) { ASSERT(req->fs_type == UV_FS_ACCESS); access_cb_count++; @@ -1565,11 +1595,43 @@ TEST_IMPL(fs_readlink) { } +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(req.ptr == NULL); +#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); + + ASSERT(UV_ENOENT == uv_fs_realpath(NULL, &req, "no_such_file", NULL)); + ASSERT(req.ptr == NULL); + ASSERT(req.result == UV_ENOENT); + uv_fs_req_cleanup(&req); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + TEST_IMPL(fs_symlink) { int r; uv_fs_t req; uv_file file; uv_file link; + char test_file_abs_buf[PATHMAX]; + size_t test_file_abs_size; /* Setup. */ unlink("test_file"); @@ -1577,6 +1639,14 @@ TEST_IMPL(fs_symlink) { unlink("test_file_symlink2"); unlink("test_file_symlink_symlink"); unlink("test_file_symlink2_symlink"); + test_file_abs_size = sizeof(test_file_abs_buf); +#ifdef _WIN32 + uv_cwd(test_file_abs_buf, &test_file_abs_size); + strcat(test_file_abs_buf, "\\test_file"); +#else + uv_cwd(test_file_abs_buf, &test_file_abs_size); + strcat(test_file_abs_buf, "/test_file"); +#endif loop = uv_default_loop(); @@ -1647,6 +1717,24 @@ TEST_IMPL(fs_symlink) { ASSERT(strcmp(req.ptr, "test_file_symlink") == 0); 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); +#else + ASSERT(strcmp(req.ptr, test_file_abs_buf) == 0); +#endif + uv_fs_req_cleanup(&req); + /* async link */ r = uv_fs_symlink(loop, &req, @@ -1687,6 +1775,20 @@ TEST_IMPL(fs_symlink) { uv_run(loop, UV_RUN_DEFAULT); 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); + /* * Run the loop just to check we don't have make any extraneous uv_ref() * calls. This should drop out immediately. @@ -1710,12 +1812,15 @@ TEST_IMPL(fs_symlink_dir) { int r; char* test_dir; uv_dirent_t dent; + static char test_dir_abs_buf[PATHMAX]; + size_t test_dir_abs_size; /* set-up */ unlink("test_dir/file1"); unlink("test_dir/file2"); rmdir("test_dir"); rmdir("test_dir_symlink"); + test_dir_abs_size = sizeof(test_dir_abs_buf); loop = uv_default_loop(); @@ -1723,16 +1828,16 @@ TEST_IMPL(fs_symlink_dir) { uv_fs_req_cleanup(&req); #ifdef _WIN32 - { - static char src_path_buf[PATHMAX]; - size_t size; - size = sizeof(src_path_buf); - strcpy(src_path_buf, "\\\\?\\"); - uv_cwd(src_path_buf + 4, &size); - strcat(src_path_buf, "\\test_dir\\"); - test_dir = src_path_buf; - } + 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\\"); + test_dir = test_dir_abs_buf; #else + uv_cwd(test_dir_abs_buf, &test_dir_abs_size); + strcat(test_dir_abs_buf, "/test_dir"); + test_dir_abs_size += strlen("/test_dir"); test_dir = "test_dir"; #endif @@ -1767,6 +1872,25 @@ TEST_IMPL(fs_symlink_dir) { #endif 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); + ASSERT(strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5) == 0); +#else + ASSERT(strcmp(req.ptr, test_dir_abs_buf) == 0); +#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); diff --git a/test/test-list.h b/test/test-list.h index 040f3c00c..c84041cd0 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -254,6 +254,7 @@ TEST_DECLARE (fs_unlink_readonly) TEST_DECLARE (fs_chown) TEST_DECLARE (fs_link) TEST_DECLARE (fs_readlink) +TEST_DECLARE (fs_realpath) TEST_DECLARE (fs_symlink) TEST_DECLARE (fs_symlink_dir) TEST_DECLARE (fs_utime) @@ -675,6 +676,7 @@ TASK_LIST_START TEST_ENTRY (fs_utime) TEST_ENTRY (fs_futime) TEST_ENTRY (fs_readlink) + TEST_ENTRY (fs_realpath) TEST_ENTRY (fs_symlink) TEST_ENTRY (fs_symlink_dir) TEST_ENTRY (fs_stat_missing_path) diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index cb4562245..784c1739f 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -276,7 +276,7 @@ TEST_IMPL(threadpool_cancel_work) { TEST_IMPL(threadpool_cancel_fs) { struct cancel_info ci; - uv_fs_t reqs[25]; + uv_fs_t reqs[26]; uv_loop_t* loop; unsigned n; uv_buf_t iov; @@ -305,6 +305,7 @@ TEST_IMPL(threadpool_cancel_fs) { ASSERT(0 == uv_fs_read(loop, reqs + n++, 0, &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)); From e0250b7d5c6fcb74602039afc8457d715e11c1b8 Mon Sep 17 00:00:00 2001 From: Joran Dirk Greef Date: Thu, 3 Dec 2015 09:33:36 +0200 Subject: [PATCH 043/632] win: fix path for removed and renamed fs events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous behavior on Windows was to set the path to NULL for removed and renamed fs events. This was because the path provided by ReadDirectoryChangesW might (in rare cases) be an 8.3 short name which could then no longer be converted to a long name after the path had been removed or renamed. This meant that the user had to detect which path was actually deleted or renamed and required the user to rescan the entire watched subtree, taking several seconds or more for large subtrees. However, ReadDirectoryChangesW is publicly documented to emit 8.3 short names if the original handle for the changed path was opened using an 8.3 short name, and libuv may already emit 8.3 short names for other events if the path cannot be explicitly resolved to a long name. This commit fixes the path for removed and renamed fs events, and does not set the path to NULL, even if the path might be an 8.3 short name. This makes it possible for the user to do a partial scan of the subtree, restricting the scan to paths which match the long form or 8.3 short name (even if some of these are false positive matches). This means that deletes and renames can now be detected accurately on Windows within a few milliseconds. Fixes: https://github.com/libuv/libuv/issues/634 Refs: https://github.com/libuv/libuv/pull/199 PR-URL: https://github.com/libuv/libuv/pull/639 Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs-event.c | 23 ++++++++++++++++------- test/test-fs-event.c | 26 +++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index ba68f78c8..76ecfebaa 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -381,9 +381,10 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, if (handle->dirw) { /* - * We attempt to convert the file name to its long form for - * events that still point to valid files on disk. - * For removed and renamed events, we do not provide the file name. + * We attempt to resolve the long form of the file name explicitly. + * We only do this for file names that might still exist on disk. + * If this fails, we use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. */ if (file_info->Action != FILE_ACTION_REMOVED && file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) { @@ -438,16 +439,24 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } /* - * If we couldn't get the long name - just use the name - * provided by ReadDirectoryChangesW. + * We could not resolve the long form explicitly. + * We therefore use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. */ if (!long_filenamew) { filenamew = file_info->FileName; sizew = file_info->FileNameLength / sizeof(WCHAR); } } else { - /* Removed or renamed callbacks don't provide filename. */ - filenamew = NULL; + /* + * Removed or renamed events cannot be resolved to the long form. + * We therefore use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. + */ + if (!long_filenamew) { + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); + } } } else { /* We already have the long name of the file, so just use it. */ diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 725103b74..e02ff2fda 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -115,7 +115,11 @@ static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename, ASSERT(handle == &fs_event); ASSERT(status == 0); ASSERT(events == UV_RENAME); + #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) + ASSERT(strcmp(filename, "file1") == 0); + #else ASSERT(filename == NULL || strcmp(filename, "file1") == 0); + #endif ASSERT(0 == uv_fs_event_stop(handle)); uv_close((uv_handle_t*)handle, close_cb); } @@ -178,8 +182,12 @@ static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle, ASSERT(handle == &fs_event); ASSERT(status == 0); ASSERT(events == UV_CHANGE || UV_RENAME); + #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) + ASSERT(strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0); + #else ASSERT(filename == NULL || strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0); + #endif if (fs_event_created + fs_event_removed == fs_event_file_count) { /* Once we've processed all create events, delete all files */ @@ -250,8 +258,16 @@ static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle, ASSERT(handle == &fs_event); ASSERT(status == 0); ASSERT(events == UV_CHANGE || UV_RENAME); + #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) + ASSERT(strncmp(filename, + file_prefix_in_subdir, + sizeof(file_prefix_in_subdir) - 1) == 0); + #else ASSERT(filename == NULL || - strncmp(filename, file_prefix_in_subdir, sizeof(file_prefix_in_subdir) - 1) == 0); + strncmp(filename, + file_prefix_in_subdir, + sizeof(file_prefix_in_subdir) - 1) == 0); + #endif if (fs_event_created + fs_event_removed == fs_event_file_count) { /* Once we've processed all create events, delete all files */ @@ -270,7 +286,11 @@ static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename, ASSERT(handle == &fs_event); ASSERT(status == 0); ASSERT(events == UV_CHANGE); + #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) + ASSERT(strcmp(filename, "file2") == 0); + #else ASSERT(filename == NULL || strcmp(filename, "file2") == 0); + #endif ASSERT(0 == uv_fs_event_stop(handle)); uv_close((uv_handle_t*)handle, close_cb); } @@ -293,7 +313,11 @@ static void fs_event_cb_file_current_dir(uv_fs_event_t* handle, ASSERT(handle == &fs_event); ASSERT(status == 0); ASSERT(events == UV_CHANGE); + #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) + ASSERT(strcmp(filename, "watch_file") == 0); + #else ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0); + #endif /* Regression test for SunOS: touch should generate just one event. */ { From eb3f48ebafb6e631e93dea7a4aa21f4ef571bfeb Mon Sep 17 00:00:00 2001 From: Jeremy Whitlock Date: Thu, 24 Sep 2015 14:02:17 -0600 Subject: [PATCH 044/632] win: do not read more from stream than available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Windows the pipe implementation could read more from a stream than was available and it would create an assertion failure. This change will make it so we read the minimum of the available data or the length of the data. To test this, I took the existing ipc_send_recv_tcp test and updated it to do two writes and two read on each side of the pipe since that was the reproduction recipe used by the reporter. This approach reproduced the issue on Windows and the committed fix resolved the issue. Fixes: https://github.com/libuv/libuv/issues/505 PR-URL: https://github.com/libuv/libuv/pull/549 Reviewed-By: Saúl Ibarra Corretgé --- src/win/pipe.c | 2 +- test/runner.c | 1 + test/task.h | 2 + test/test-ipc-send-recv.c | 131 ++++++++++++++++++++++++++++---------- 4 files changed, 103 insertions(+), 33 deletions(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index d57d77a41..bcce80c77 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1633,7 +1633,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, if (ReadFile(handle->handle, buf.base, - buf.len, + min(buf.len, avail), &bytes, NULL)) { /* Successful read */ diff --git a/test/runner.c b/test/runner.c index 914a067f3..c616d1764 100644 --- a/test/runner.c +++ b/test/runner.c @@ -211,6 +211,7 @@ int run_test(const char* test, /* Clean up stale socket from previous run. */ remove(TEST_PIPENAME); remove(TEST_PIPENAME_2); + remove(TEST_PIPENAME_3); #endif /* If it's a helper the user asks for, start it directly. */ diff --git a/test/task.h b/test/task.h index 8999c20a4..d18c1daa3 100644 --- a/test/task.h +++ b/test/task.h @@ -50,9 +50,11 @@ #ifdef _WIN32 # 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" +# define TEST_PIPENAME_3 "/tmp/uv-test-sock3" #endif #ifdef _WIN32 diff --git a/test/test-ipc-send-recv.c b/test/test-ipc-send-recv.c index d0558a940..c445483fa 100644 --- a/test/test-ipc-send-recv.c +++ b/test/test-ipc-send-recv.c @@ -44,23 +44,33 @@ struct test_ctx { uv_pipe_t channel; uv_connect_t connect_req; uv_write_t write_req; + uv_write_t write_req2; uv_handle_type expected_type; union handles send; + union handles send2; union handles recv; + union handles recv2; }; struct echo_ctx { uv_pipe_t listen; uv_pipe_t channel; uv_write_t write_req; + uv_write_t write_req2; uv_handle_type expected_type; union handles recv; + union handles recv2; }; static struct test_ctx ctx; static struct echo_ctx ctx2; -static int num_recv_handles; +/* Used in write2_cb to decide if we need to cleanup or not */ +static int is_child_process; +static int is_in_process; +static int read_cb_called; +static int recv_cb_called; +static int write2_cb_called; static void alloc_cb(uv_handle_t* handle, @@ -79,30 +89,47 @@ static void recv_cb(uv_stream_t* handle, uv_handle_type pending; uv_pipe_t* pipe; int r; + union handles* recv; + + if (++recv_cb_called == 1) { + recv = &ctx.recv; + } else { + recv = &ctx.recv2; + } pipe = (uv_pipe_t*) handle; ASSERT(pipe == &ctx.channel); - ASSERT(nread >= 0); - ASSERT(1 == uv_pipe_pending_count(pipe)); - pending = uv_pipe_pending_type(pipe); - ASSERT(pending == ctx.expected_type); - - if (pending == UV_NAMED_PIPE) - r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0); - else if (pending == UV_TCP) - r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp); - else - abort(); - ASSERT(r == 0); + /* Depending on the OS, the final recv_cb can be called after the child + * process has terminated which can result in nread being UV_EOF instead of + * the number of bytes read. Since the other end of the pipe has closed this + * UV_EOF is an acceptable value. */ + if (nread == UV_EOF) { + /* UV_EOF is only acceptable for the final recv_cb call */ + ASSERT(recv_cb_called == 2); + } else { + ASSERT(nread >= 0); + ASSERT(1 == uv_pipe_pending_count(pipe)); + + pending = uv_pipe_pending_type(pipe); + ASSERT(pending == ctx.expected_type); + + if (pending == UV_NAMED_PIPE) + r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0); + else if (pending == UV_TCP) + r = uv_tcp_init(ctx.channel.loop, &recv->tcp); + else + abort(); + ASSERT(r == 0); - r = uv_accept(handle, &ctx.recv.stream); - ASSERT(r == 0); + r = uv_accept(handle, &recv->stream); + ASSERT(r == 0); + } - uv_close((uv_handle_t*)&ctx.channel, NULL); - uv_close(&ctx.send.handle, NULL); - uv_close(&ctx.recv.handle, NULL); - num_recv_handles++; + /* Close after two writes received */ + if (recv_cb_called == 2) { + uv_close((uv_handle_t*)&ctx.channel, NULL); + } } static void connect_cb(uv_connect_t* req, int status) { @@ -120,6 +147,17 @@ static void connect_cb(uv_connect_t* req, int status) { NULL); ASSERT(r == 0); + /* Perform two writes to the same pipe to make sure that on Windows we are + * not running into issue 505: + * https://github.com/libuv/libuv/issues/505 */ + buf = uv_buf_init(".", 1); + r = uv_write2(&ctx.write_req2, + (uv_stream_t*)&ctx.channel, + &buf, 1, + &ctx.send2.stream, + NULL); + ASSERT(r == 0); + r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb); ASSERT(r == 0); } @@ -138,7 +176,7 @@ static int run_test(int inprocess) { r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1); ASSERT(r == 0); - uv_pipe_connect(&ctx.connect_req, &ctx.channel, TEST_PIPENAME_2, connect_cb); + uv_pipe_connect(&ctx.connect_req, &ctx.channel, TEST_PIPENAME_3, connect_cb); } else { spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper"); @@ -148,7 +186,7 @@ static int run_test(int inprocess) { r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); - ASSERT(num_recv_handles == 1); + ASSERT(recv_cb_called == 2); if (inprocess) { r = uv_thread_join(&tid); @@ -169,6 +207,12 @@ static int run_ipc_send_recv_pipe(int inprocess) { r = uv_pipe_bind(&ctx.send.pipe, TEST_PIPENAME); ASSERT(r == 0); + r = uv_pipe_init(uv_default_loop(), &ctx.send2.pipe, 1); + ASSERT(r == 0); + + r = uv_pipe_bind(&ctx.send2.pipe, TEST_PIPENAME_2); + ASSERT(r == 0); + r = run_test(inprocess); ASSERT(r == 0); @@ -195,9 +239,15 @@ static int run_ipc_send_recv_tcp(int inprocess) { r = uv_tcp_init(uv_default_loop(), &ctx.send.tcp); ASSERT(r == 0); + r = uv_tcp_init(uv_default_loop(), &ctx.send2.tcp); + ASSERT(r == 0); + r = uv_tcp_bind(&ctx.send.tcp, (const struct sockaddr*) &addr, 0); ASSERT(r == 0); + r = uv_tcp_bind(&ctx.send2.tcp, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + r = run_test(inprocess); ASSERT(r == 0); @@ -218,9 +268,15 @@ TEST_IMPL(ipc_send_recv_tcp_inprocess) { static void write2_cb(uv_write_t* req, int status) { ASSERT(status == 0); - uv_close(&ctx2.recv.handle, NULL); - uv_close((uv_handle_t*)&ctx2.channel, NULL); - uv_close((uv_handle_t*)&ctx2.listen, NULL); + + /* After two successful writes in the child process, allow the child + * process to be closed. */ + if (++write2_cb_called == 2 && (is_child_process || is_in_process)) { + uv_close(&ctx2.recv.handle, NULL); + uv_close(&ctx2.recv2.handle, NULL); + uv_close((uv_handle_t*)&ctx2.channel, NULL); + uv_close((uv_handle_t*)&ctx2.listen, NULL); + } } static void read_cb(uv_stream_t* handle, @@ -230,11 +286,21 @@ static void read_cb(uv_stream_t* handle, uv_pipe_t* pipe; uv_handle_type pending; int r; + union handles* recv; + uv_write_t* write_req; if (nread == UV__EOF || nread == UV__ECONNABORTED) { return; } + if (++read_cb_called == 2) { + recv = &ctx2.recv; + write_req = &ctx2.write_req; + } else { + recv = &ctx2.recv2; + write_req = &ctx2.write_req2; + } + pipe = (uv_pipe_t*) handle; ASSERT(pipe == &ctx2.channel); ASSERT(nread >= 0); @@ -243,24 +309,23 @@ static void read_cb(uv_stream_t* handle, pending = uv_pipe_pending_type(pipe); ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP); - wrbuf = uv_buf_init(".", 1); - if (pending == UV_NAMED_PIPE) - r = uv_pipe_init(ctx2.channel.loop, &ctx2.recv.pipe, 0); + r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0); else if (pending == UV_TCP) - r = uv_tcp_init(ctx2.channel.loop, &ctx2.recv.tcp); + r = uv_tcp_init(ctx2.channel.loop, &recv->tcp); else abort(); ASSERT(r == 0); - r = uv_accept(handle, &ctx2.recv.stream); + r = uv_accept(handle, &recv->stream); ASSERT(r == 0); - r = uv_write2(&ctx2.write_req, + wrbuf = uv_buf_init(".", 1); + r = uv_write2(write_req, (uv_stream_t*)&ctx2.channel, &wrbuf, 1, - &ctx2.recv.stream, + &recv->stream, write2_cb); ASSERT(r == 0); } @@ -289,6 +354,8 @@ static void listen_cb(uv_stream_t* handle, int status) { int run_ipc_send_recv_helper(uv_loop_t* loop, int inprocess) { int r; + is_in_process = inprocess; + memset(&ctx2, 0, sizeof(ctx2)); r = uv_pipe_init(loop, &ctx2.listen, 0); @@ -298,7 +365,7 @@ int run_ipc_send_recv_helper(uv_loop_t* loop, int inprocess) { ASSERT(r == 0); if (inprocess) { - r = uv_pipe_bind(&ctx2.listen, TEST_PIPENAME_2); + r = uv_pipe_bind(&ctx2.listen, TEST_PIPENAME_3); ASSERT(r == 0); r = uv_listen((uv_stream_t*)&ctx2.listen, SOMAXCONN, listen_cb); From 6060841edca2393345b119c93d11b102b6ce650f Mon Sep 17 00:00:00 2001 From: Andrey Mazo Date: Wed, 30 Sep 2015 12:47:02 -0400 Subject: [PATCH 045/632] test: test that uv_close() doesn't corrupt QUEUE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test adds all types of handles, that were known to be affected by QUEUE_REMOVE()-within-QUEUE_FOREACH() bug, to a loop. It then calls uv_close() to trigger QUEUE_REMOVE()-within-QUEUE_FOREACH() case and checks whether a particular QUEUE is corrupted or not. Restrict the test to Linux only for now as it fails on other platforms for various reasons. PR-URL: https://github.com/libuv/libuv/pull/621 Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 1 + test/test-list.h | 4 + test/test-queue-foreach-delete.c | 143 +++++++++++++++++++++++++++++++ uv.gyp | 1 + 4 files changed, 149 insertions(+) create mode 100644 test/test-queue-foreach-delete.c diff --git a/Makefile.am b/Makefile.am index fbf9527ae..0ef781ff1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -200,6 +200,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-poll-closesocket.c \ test/test-poll.c \ test/test-process-title.c \ + test/test-queue-foreach-delete.c \ test/test-ref.c \ test/test-run-nowait.c \ test/test-run-once.c \ diff --git a/test/test-list.h b/test/test-list.h index c84041cd0..858a20af4 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -337,6 +337,7 @@ HELPER_DECLARE (tcp6_echo_server) HELPER_DECLARE (udp4_echo_server) HELPER_DECLARE (pipe_echo_server) +TEST_DECLARE (queue_foreach_delete) TASK_LIST_START TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000) @@ -720,6 +721,9 @@ TASK_LIST_START TEST_ENTRY (dlerror) TEST_ENTRY (ip4_addr) TEST_ENTRY (ip6_addr_link_local) + + TEST_ENTRY (queue_foreach_delete) + #if 0 /* These are for testing the test runner. */ TEST_ENTRY (fail_always) diff --git a/test/test-queue-foreach-delete.c b/test/test-queue-foreach-delete.c new file mode 100644 index 000000000..cc4ba0138 --- /dev/null +++ b/test/test-queue-foreach-delete.c @@ -0,0 +1,143 @@ +/* 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 + + +/* + * 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()) + * 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): + * 1. Create and start 3 handles (#0, #1, and #2). + * + * The queue after the start() calls: + * ..=> [queue head] <=> [handle] <=> [handle #1] <=> [handle] <=.. + * + * 2. Trigger handles to fire (for uv_idle_t, uv_prepare_t, and uv_check_t there is nothing to do). + * + * 3. In the callback for the first-executed handle (#0 or #2 depending on handle type) + * stop the handle and the next one (#1). + * (for uv_idle_t, uv_prepare_t, and uv_check_t callbacks are executed in the reverse order as they are start()'ed, + * so callback for handle #2 will be called first) + * + * The queue after the stop() calls: + * correct foreach "next" | + * \/ + * ..=> [queue head] <==============================> [handle] <=.. + * [ ] <- [handle] <=> [handle #1] -> [ ] + * /\ + * 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. + */ + +static const unsigned first_handle_number_idle = 2; +static const unsigned first_handle_number_prepare = 2; +static const unsigned first_handle_number_check = 2; + + +#define DEFINE_GLOBALS_AND_CBS(name) \ + static uv_##name##_t (name)[3]; \ + static unsigned name##_cb_calls[3]; \ + \ + static void name##2_cb(uv_##name##_t* handle) { \ + ASSERT(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); \ + } \ + name##_cb_calls[2]++; \ + } \ + \ + static void name##1_cb(uv_##name##_t* handle) { \ + ASSERT(handle == &(name)[1]); \ + ASSERT(0 && "Shouldn't be called" && (&name[0])); \ + } \ + \ + static void name##0_cb(uv_##name##_t* handle) { \ + ASSERT(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); \ + } \ + name##_cb_calls[0]++; \ + } \ + \ + static const uv_##name##_cb name##_cbs[] = { \ + (uv_##name##_cb)name##0_cb, \ + (uv_##name##_cb)name##1_cb, \ + (uv_##name##_cb)name##2_cb, \ + }; + +#define INIT_AND_START(name, loop) \ + do { \ + size_t i; \ + for (i = 0; i < ARRAY_SIZE(name); i++) { \ + int r; \ + r = uv_##name##_init((loop), &(name)[i]); \ + ASSERT(r == 0); \ + \ + r = uv_##name##_start(&(name)[i], name##_cbs[i]); \ + ASSERT(r == 0); \ + } \ + } 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); \ + } while (0) + +DEFINE_GLOBALS_AND_CBS(idle) +DEFINE_GLOBALS_AND_CBS(prepare) +DEFINE_GLOBALS_AND_CBS(check) + + +TEST_IMPL(queue_foreach_delete) { + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + INIT_AND_START(idle, loop); + INIT_AND_START(prepare, loop); + INIT_AND_START(check, loop); + + r = uv_run(loop, UV_RUN_NOWAIT); + ASSERT(r == 1); + + END_ASSERTS(idle); + END_ASSERTS(prepare); + END_ASSERTS(check); + + MAKE_VALGRIND_HAPPY(); + + return 0; +} diff --git a/uv.gyp b/uv.gyp index 36cc8abe3..635a234ea 100644 --- a/uv.gyp +++ b/uv.gyp @@ -347,6 +347,7 @@ 'test/test-poll-close-doesnt-corrupt-stack.c', 'test/test-poll-closesocket.c', 'test/test-process-title.c', + 'test/test-queue-foreach-delete.c', 'test/test-ref.c', 'test/test-run-nowait.c', 'test/test-run-once.c', From 46343764d5aa4af0a2e939b6f0f1fad798af43ef Mon Sep 17 00:00:00 2001 From: Andrey Mazo Date: Wed, 18 Nov 2015 19:05:26 -0500 Subject: [PATCH 046/632] unix: fix uv_fs_event_stop() from fs_event_cb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following changeset 442b8a5a848e1589520a4d4fd175d7e9aa084c44 "unix: use QUEUE_MOVE when iterating over lists" introduced a new assert failure: `queue_foreach_delete` failed: exit code 6 Output from process `queue_foreach_delete`: run-tests: src/unix/linux-inotify.c:244: uv_fs_event_stop: Assertion `w != ((void *)0)' failed. Simplest test case for this: 1. create and start two uv_fs_event_t for the same path; 2. in the callback for the first one, call uv_close() on it; 3. assert/segfault while accessing the second uv_fs_event_t from uv__inotify_read(). PR-URL: https://github.com/libuv/libuv/pull/621 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/linux-inotify.c | 33 ++++++++++++++---- test/test-queue-foreach-delete.c | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 6 deletions(-) diff --git a/src/unix/linux-inotify.c b/src/unix/linux-inotify.c index e3ff6d529..282912115 100644 --- a/src/unix/linux-inotify.c +++ b/src/unix/linux-inotify.c @@ -35,6 +35,7 @@ struct watcher_list { RB_ENTRY(watcher_list) entry; QUEUE watchers; + int iterating; char* path; int wd; }; @@ -113,6 +114,15 @@ static struct watcher_list* find_watcher(uv_loop_t* loop, int 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); + uv__inotify_rm_watch(loop->inotify_fd, w->wd); + uv__free(w); + } +} static void uv__inotify_read(uv_loop_t* loop, uv__io_t* dummy, @@ -160,6 +170,18 @@ static void uv__inotify_read(uv_loop_t* loop, */ 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); @@ -170,6 +192,9 @@ static void uv__inotify_read(uv_loop_t* loop, h->cb(h, path, events, 0); } + /* done iterating, time to (maybe) free empty watcher_list */ + w->iterating = 0; + maybe_free_watcher_list(w, loop); } } } @@ -221,6 +246,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, w->wd = wd; w->path = strcpy((char*)(w + 1), path); QUEUE_INIT(&w->watchers); + w->iterating = 0; RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w); no_insert: @@ -248,12 +274,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { uv__handle_stop(handle); QUEUE_REMOVE(&handle->watchers); - if (QUEUE_EMPTY(&w->watchers)) { - /* No watchers left for this path. Clean up. */ - RB_REMOVE(watcher_root, CAST(&handle->loop->inotify_watchers), w); - uv__inotify_rm_watch(handle->loop->inotify_fd, w->wd); - uv__free(w); - } + maybe_free_watcher_list(w, handle->loop); return 0; } diff --git a/test/test-queue-foreach-delete.c b/test/test-queue-foreach-delete.c index cc4ba0138..45da22538 100644 --- a/test/test-queue-foreach-delete.c +++ b/test/test-queue-foreach-delete.c @@ -60,6 +60,9 @@ static const unsigned first_handle_number_idle = 2; static const unsigned first_handle_number_prepare = 2; static const unsigned first_handle_number_check = 2; +#ifdef __linux__ +static const unsigned first_handle_number_fs_event = 0; +#endif #define DEFINE_GLOBALS_AND_CBS(name) \ @@ -119,6 +122,45 @@ DEFINE_GLOBALS_AND_CBS(idle) DEFINE_GLOBALS_AND_CBS(prepare) DEFINE_GLOBALS_AND_CBS(check) +#ifdef __linux__ +DEFINE_GLOBALS_AND_CBS(fs_event) + +static const char watched_dir[] = "."; +static uv_timer_t timer; +static unsigned helper_timer_cb_calls; + + +static void init_and_start_fs_events(uv_loop_t* loop) { + size_t i; + for (i = 0; i < ARRAY_SIZE(fs_event); i++) { + int r; + r = uv_fs_event_init(loop, &fs_event[i]); + ASSERT(r == 0); + + r = uv_fs_event_start(&fs_event[i], + (uv_fs_event_cb)fs_event_cbs[i], + watched_dir, + 0); + ASSERT(r == 0); + } +} + +static void helper_timer_cb(uv_timer_t* thandle) { + int r; + uv_fs_t fs_req; + + /* 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); + uv_fs_req_cleanup(&fs_req); + + helper_timer_cb_calls++; +} +#endif + TEST_IMPL(queue_foreach_delete) { uv_loop_t* loop; @@ -130,6 +172,17 @@ TEST_IMPL(queue_foreach_delete) { INIT_AND_START(prepare, loop); INIT_AND_START(check, loop); +#ifdef __linux__ + init_and_start_fs_events(loop); + + /* helper timer to trigger async and fs_event callbacks */ + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, helper_timer_cb, 0, 0); + ASSERT(r == 0); +#endif + r = uv_run(loop, UV_RUN_NOWAIT); ASSERT(r == 1); @@ -137,6 +190,10 @@ TEST_IMPL(queue_foreach_delete) { END_ASSERTS(prepare); END_ASSERTS(check); +#ifdef __linux__ + ASSERT(helper_timer_cb_calls == 1); +#endif + MAKE_VALGRIND_HAPPY(); return 0; From e4675f6fe79602184735013dd04edfa57f104069 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 11 Dec 2015 13:30:31 +0100 Subject: [PATCH 047/632] test: fix self-deadlocks in thread_rwlock_trylock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trying to acquire a rwlock that the current thread already owns may fail (not "shall fail") with EDEADLK. Libuv considers that a fatal error and rightly so in my opinion; it normally means the program contains a logic error. The test had indeed logic errors. This commit splits off the UV_EBUSY return code testing into a separate thread, eliminating the potential for self-deadlock. Fixes: https://github.com/libuv/libuv/issues/544 PR-URL: https://github.com/libuv/libuv/pull/649 Reviewed-By: Jeremy Whitlock Reviewed-By: Saúl Ibarra Corretgé --- test/test-mutexes.c | 104 ++++++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 32 deletions(-) diff --git a/test/test-mutexes.c b/test/test-mutexes.c index 4aeac73b4..af5e4e88a 100644 --- a/test/test-mutexes.c +++ b/test/test-mutexes.c @@ -25,6 +25,10 @@ #include #include +static uv_cond_t condvar; +static uv_mutex_t mutex; +static uv_rwlock_t rwlock; +static int step; /* The mutex and rwlock tests are really poor. * They're very basic sanity checks and nothing more. @@ -63,60 +67,96 @@ TEST_IMPL(thread_rwlock) { } -TEST_IMPL(thread_rwlock_trylock) { - uv_rwlock_t rwlock; - int r; - - r = uv_rwlock_init(&rwlock); - ASSERT(r == 0); - - /* No locks held. */ +/* Call when holding |mutex|. */ +static void synchronize_nowait(void) { + step += 1; + uv_cond_signal(&condvar); +} - r = uv_rwlock_trywrlock(&rwlock); - ASSERT(r == 0); - /* Write lock held. */ +/* Call when holding |mutex|. */ +static void synchronize(void) { + int current; - r = uv_rwlock_tryrdlock(&rwlock); - ASSERT(r == UV_EBUSY); - r = uv_rwlock_trywrlock(&rwlock); - ASSERT(r == UV_EBUSY); + 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); +} - uv_rwlock_wrunlock(&rwlock); - /* No locks held. */ +static void thread_rwlock_trylock_peer(void* unused) { + (void) &unused; - r = uv_rwlock_tryrdlock(&rwlock); - ASSERT(r == 0); + uv_mutex_lock(&mutex); - /* One read lock held. */ + /* Write lock held by other thread. */ + ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock)); + ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); + synchronize(); - r = uv_rwlock_tryrdlock(&rwlock); - ASSERT(r == 0); + /* Read lock held by other thread. */ + ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); + uv_rwlock_rdunlock(&rwlock); + ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); + synchronize(); - /* Two read locks held. */ + /* Acquire write lock. */ + ASSERT(0 == uv_rwlock_trywrlock(&rwlock)); + synchronize(); - r = uv_rwlock_trywrlock(&rwlock); - ASSERT(r == UV_EBUSY); + /* Release write lock and acquire read lock. */ + uv_rwlock_wrunlock(&rwlock); + ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); + synchronize(); uv_rwlock_rdunlock(&rwlock); + synchronize_nowait(); /* Signal main thread we're going away. */ + uv_mutex_unlock(&mutex); +} - /* One read lock held. */ - uv_rwlock_rdunlock(&rwlock); +TEST_IMPL(thread_rwlock_trylock) { + uv_thread_t thread; - /* No read locks held. */ + ASSERT(0 == uv_cond_init(&condvar)); + ASSERT(0 == uv_mutex_init(&mutex)); + ASSERT(0 == uv_rwlock_init(&rwlock)); - r = uv_rwlock_trywrlock(&rwlock); - ASSERT(r == 0); + uv_mutex_lock(&mutex); + ASSERT(0 == uv_thread_create(&thread, thread_rwlock_trylock_peer, NULL)); - /* Write lock held. */ + /* Hold write lock. */ + ASSERT(0 == 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)); + synchronize(); + + /* Release read lock. */ + uv_rwlock_rdunlock(&rwlock); + synchronize(); - /* No locks held. */ + /* Write lock held by other thread. */ + ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock)); + ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); + synchronize(); + /* Read lock held by other thread. */ + ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); + uv_rwlock_rdunlock(&rwlock); + ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); + synchronize(); + + ASSERT(0 == uv_thread_join(&thread)); uv_rwlock_destroy(&rwlock); + uv_mutex_unlock(&mutex); + uv_mutex_destroy(&mutex); + uv_cond_destroy(&condvar); return 0; } From b4126dd6dbc09fdd670f0fb2571d0023cbbae029 Mon Sep 17 00:00:00 2001 From: sztomi Date: Sat, 12 Dec 2015 00:27:27 +0100 Subject: [PATCH 048/632] src: remove non ascii character MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/651 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/android-ifaddrs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/android-ifaddrs.c b/src/unix/android-ifaddrs.c index 71f7290b3..30f681b7d 100644 --- a/src/unix/android-ifaddrs.c +++ b/src/unix/android-ifaddrs.c @@ -1,6 +1,6 @@ /* Copyright (c) 2013, Kenneth MacKay -Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement n° 289016) +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, From 99e5fb767082964baa892103393e893b27bb52ec Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Fri, 11 Dec 2015 14:44:04 -0500 Subject: [PATCH 049/632] test: fix test udp_multicast_join6 for AIX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/650 Reviewed-By: Saúl Ibarra Corretgé --- test/test-udp-multicast-join6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-udp-multicast-join6.c b/test/test-udp-multicast-join6.c index 873cb6d81..f635bdb9e 100644 --- a/test/test-udp-multicast-join6.c +++ b/test/test-udp-multicast-join6.c @@ -119,7 +119,7 @@ TEST_IMPL(udp_multicast_join6) { ASSERT(r == 0); /* join the multicast channel */ -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(_AIX) r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP); #else r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP); From 5467299450ecf61635657557b6e01aaaf6c3fdf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 14 Dec 2015 20:54:30 +0100 Subject: [PATCH 050/632] 2015.12.15, Version 1.8.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.7.5: * unix: fix memory leak in uv_interface_addresses (Jianghua Yang) * unix: make uv_guess_handle work properly for AIX (Gireesh Punathil) * fs: undo uv__req_init when uv__malloc failed (Jianghua Yang) * build: remove unused 'component' GYP option (Saúl Ibarra Corretgé) * include: remove duplicate extern declaration (Jianghua Yang) * win: use the MSVC provided snprintf where possible (Jason Williams) * win, test: fix compilation warning (Saúl Ibarra Corretgé) * win: fix compilation with VS < 2012 (Ryan Johnston) * stream: support empty uv_try_write on unix (Fedor Indutny) * unix: fix request handle leak in uv__udp_send (Jianghua Yang) * src: replace QUEUE_SPLIT with QUEUE_MOVE (Ben Noordhuis) * unix: use QUEUE_MOVE when iterating over lists (Ben Noordhuis) * unix: squelch harmless valgrind warning (Ben Noordhuis) * test: don't abort on setrlimit() failure (Ben Noordhuis) * unix: only undo fs req registration in async mode (Ben Noordhuis) * unix: fix uv__getiovmax return value (HungMingWu) * unix: make work with Solaris Studio. (Adam Stylinski) * test: fix fs_event_watch_file_currentdir flakiness (Santiago Gimeno) * unix: skip prohibited syscalls on tvOS and watchOS (Nathan Corvino) * test: use FQDN in getaddrinfo_fail test (Wink Saville) * docs: clarify documentation of uv_tcp_init_ex (Andrius Bentkus) * win: fix comment (Miodrag Milanovic) * doc: fix typo in README (Angel Leon) * darwin: abort() if (un)locking fs mutex fails (Ben Noordhuis) * pipe: enable inprocess uv_write2 on Windows (Louis DeJardin) * win: properly return UV_EBADF when _close() fails (Nicholas Vavilov) * test: skip process_title for AIX (Imran Iqbal) * misc: expose handle print APIs (Petka Antonov) * include: add stdio.h to uv.h (Saúl Ibarra Corretgé) * misc: remove unnecessary null pointer checks (Ian Kronquist) * test,freebsd: skip udp_dual_stack if not supported (Santiago Gimeno) * linux: don't retry dup2/dup3 on EINTR (Ben Noordhuis) * unix: don't retry dup2/dup3 on EINTR (Ben Noordhuis) * test: fix -Wtautological-pointer-compare warnings (Saúl Ibarra Corretgé) * win: map ERROR_BAD_PATHNAME to UV_ENOENT (Tony Kelman) * test: fix test/test-tty.c for AIX (Imran Iqbal) * android: support api level less than 21 (kkdaemon) * fsevents: fix race on simultaneous init+close (Fedor Indutny) * linux,fs: fix p{read,write}v with a 64bit offset (Saúl Ibarra Corretgé) * fs: add uv_fs_realpath() (Yuval Brik) * win: fix path for removed and renamed fs events (Joran Dirk Greef) * win: do not read more from stream than available (Jeremy Whitlock) * test: test that uv_close() doesn't corrupt QUEUE (Andrey Mazo) * unix: fix uv_fs_event_stop() from fs_event_cb (Andrey Mazo) * test: fix self-deadlocks in thread_rwlock_trylock (Ben Noordhuis) * src: remove non ascii character (sztomi) * test: fix test udp_multicast_join6 for AIX (Imran Iqbal) --- .mailmap | 1 + AUTHORS | 15 +++++++ ChangeLog | 99 ++++++++++++++++++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 8 ++-- 6 files changed, 121 insertions(+), 6 deletions(-) diff --git a/.mailmap b/.mailmap index eb9b5e0d9..7a51588c0 100644 --- a/.mailmap +++ b/.mailmap @@ -22,6 +22,7 @@ Maciej Małecki Marc Schlaich Michael Michael Neumann +Nicholas Vavilov Rasmus Christian Pedersen Rasmus Christian Pedersen Robert Mustacchi diff --git a/AUTHORS b/AUTHORS index b2397e2df..8dc3955ca 100644 --- a/AUTHORS +++ b/AUTHORS @@ -225,3 +225,18 @@ Colin Snover Sakthipriyan Vairamani Eli Skeggs nmushell +Gireesh Punathil +Ryan Johnston +Adam Stylinski +Nathan Corvino +Wink Saville +Angel Leon +Louis DeJardin +Imran Iqbal +Petka Antonov +Ian Kronquist +kkdaemon +Yuval Brik +Joran Dirk Greef +Andrey Mazo +sztomi diff --git a/ChangeLog b/ChangeLog index 42f10352b..d5f95404a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,102 @@ +2015.12.15, Version 1.8.0 (Stable) + +Changes since version 1.7.5: + +* unix: fix memory leak in uv_interface_addresses (Jianghua Yang) + +* unix: make uv_guess_handle work properly for AIX (Gireesh Punathil) + +* fs: undo uv__req_init when uv__malloc failed (Jianghua Yang) + +* build: remove unused 'component' GYP option (Saúl Ibarra Corretgé) + +* include: remove duplicate extern declaration (Jianghua Yang) + +* win: use the MSVC provided snprintf where possible (Jason Williams) + +* win, test: fix compilation warning (Saúl Ibarra Corretgé) + +* win: fix compilation with VS < 2012 (Ryan Johnston) + +* stream: support empty uv_try_write on unix (Fedor Indutny) + +* unix: fix request handle leak in uv__udp_send (Jianghua Yang) + +* src: replace QUEUE_SPLIT with QUEUE_MOVE (Ben Noordhuis) + +* unix: use QUEUE_MOVE when iterating over lists (Ben Noordhuis) + +* unix: squelch harmless valgrind warning (Ben Noordhuis) + +* test: don't abort on setrlimit() failure (Ben Noordhuis) + +* unix: only undo fs req registration in async mode (Ben Noordhuis) + +* unix: fix uv__getiovmax return value (HungMingWu) + +* unix: make work with Solaris Studio. (Adam Stylinski) + +* test: fix fs_event_watch_file_currentdir flakiness (Santiago Gimeno) + +* unix: skip prohibited syscalls on tvOS and watchOS (Nathan Corvino) + +* test: use FQDN in getaddrinfo_fail test (Wink Saville) + +* docs: clarify documentation of uv_tcp_init_ex (Andrius Bentkus) + +* win: fix comment (Miodrag Milanovic) + +* doc: fix typo in README (Angel Leon) + +* darwin: abort() if (un)locking fs mutex fails (Ben Noordhuis) + +* pipe: enable inprocess uv_write2 on Windows (Louis DeJardin) + +* win: properly return UV_EBADF when _close() fails (Nicholas Vavilov) + +* test: skip process_title for AIX (Imran Iqbal) + +* misc: expose handle print APIs (Petka Antonov) + +* include: add stdio.h to uv.h (Saúl Ibarra Corretgé) + +* misc: remove unnecessary null pointer checks (Ian Kronquist) + +* test,freebsd: skip udp_dual_stack if not supported (Santiago Gimeno) + +* linux: don't retry dup2/dup3 on EINTR (Ben Noordhuis) + +* unix: don't retry dup2/dup3 on EINTR (Ben Noordhuis) + +* test: fix -Wtautological-pointer-compare warnings (Saúl Ibarra Corretgé) + +* win: map ERROR_BAD_PATHNAME to UV_ENOENT (Tony Kelman) + +* test: fix test/test-tty.c for AIX (Imran Iqbal) + +* android: support api level less than 21 (kkdaemon) + +* fsevents: fix race on simultaneous init+close (Fedor Indutny) + +* linux,fs: fix p{read,write}v with a 64bit offset (Saúl Ibarra Corretgé) + +* fs: add uv_fs_realpath() (Yuval Brik) + +* win: fix path for removed and renamed fs events (Joran Dirk Greef) + +* win: do not read more from stream than available (Jeremy Whitlock) + +* test: test that uv_close() doesn't corrupt QUEUE (Andrey Mazo) + +* unix: fix uv_fs_event_stop() from fs_event_cb (Andrey Mazo) + +* test: fix self-deadlocks in thread_rwlock_trylock (Ben Noordhuis) + +* src: remove non ascii character (sztomi) + +* test: fix test udp_multicast_join6 for AIX (Imran Iqbal) + + 2015.09.23, Version 1.7.5 (Stable), a8c1136de2cabf25b143021488cbaab05834daa8 Changes since version 1.7.4: diff --git a/appveyor.yml b/appveyor.yml index c9f55134e..9aa63c5a5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.7.5.build{build} +version: v1.8.0.build{build} install: - cinst -y nsis diff --git a/configure.ac b/configure.ac index f911789c7..011bee2a8 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.7.6], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.8.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 7a637e07b..6e61f55ed 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 7 -#define UV_VERSION_PATCH 6 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 8 +#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 59dab837d858ad89cee562a7b419fbe55bd322d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 14 Dec 2015 20:54:37 +0100 Subject: [PATCH 051/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index d5f95404a..af0743af7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2015.12.15, Version 1.8.0 (Stable) +2015.12.15, Version 1.8.0 (Stable), 5467299450ecf61635657557b6e01aaaf6c3fdf4 Changes since version 1.7.5: From 61f13a6d5e52817c748ddedea73efcf3eb94c089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 14 Dec 2015 21:07:52 +0100 Subject: [PATCH 052/632] Now working on version 1.8.1 --- 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 6e61f55ed..d53d62ab2 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 8 -#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 427e4c9d4893b041d90fb282aa69fa1f972ae1a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Reis?= Date: Tue, 2 Jun 2015 20:02:55 +0100 Subject: [PATCH 053/632] win: wait for full timeout duration uv_poll should wait for at least the full timeout duration when there is nothing else to do. This was not happening because GetQueuedCompletionStatus can occasionally return up to 15ms early. The added test reproduces https://github.com/joyent/node/blob/d13d7f74d794340ac5e126cfb4ce507fe0f803d5/test/simple/test-timers-first-fire.js on libuv, being flaky before this fix. Fixes: https://github.com/joyent/node/issues/8960 PR-URL: https://github.com/libuv/libuv/pull/385 Reviewed-By: Alexis Campailla Reviewed-by: Bert Belder --- src/win/core.c | 130 +++++++++++++++++++++++++++++---------------- src/win/internal.h | 1 - src/win/timer.c | 9 +--- test/test-list.h | 2 + test/test-timer.c | 27 ++++++++++ 5 files changed, 114 insertions(+), 55 deletions(-) diff --git a/src/win/core.c b/src/win/core.c index de0483e10..ba306ebc0 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -256,30 +256,48 @@ static void uv_poll(uv_loop_t* loop, DWORD timeout) { ULONG_PTR key; OVERLAPPED* overlapped; uv_req_t* req; + int repeat; + uint64_t timeout_time; - GetQueuedCompletionStatus(loop->iocp, - &bytes, - &key, - &overlapped, - timeout); + timeout_time = loop->time + timeout; - if (overlapped) { - /* Package was dequeued */ - req = uv_overlapped_to_req(overlapped); - uv_insert_pending_req(loop, req); + for (repeat = 0; ; repeat++) { + GetQueuedCompletionStatus(loop->iocp, + &bytes, + &key, + &overlapped, + timeout); - /* 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 is reflected in the loop time. - */ - uv__time_forward(loop, timeout); + if (overlapped) { + /* 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; } } @@ -290,33 +308,51 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { OVERLAPPED_ENTRY overlappeds[128]; ULONG count; ULONG i; - - success = pGetQueuedCompletionStatusEx(loop->iocp, - overlappeds, - ARRAY_SIZE(overlappeds), - &count, - timeout, - FALSE); - - if (success) { - for (i = 0; i < count; i++) { - /* Package was dequeued */ - req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); - uv_insert_pending_req(loop, req); + int repeat; + uint64_t timeout_time; + + timeout_time = loop->time + timeout; + + for (repeat = 0; ; repeat++) { + success = pGetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); + + if (success) { + for (i = 0; i < count; i++) { + /* Package was dequeued */ + req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); + 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(), "GetQueuedCompletionStatusEx"); + } 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; + } } - - /* 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(), "GetQueuedCompletionStatusEx"); - } else if (timeout > 0) { - /* GetQueuedCompletionStatus can occasionally return a little early. - * Make sure that the desired timeout is reflected in the loop time. - */ - uv__time_forward(loop, timeout); + break; } } diff --git a/src/win/internal.h b/src/win/internal.h index 783f21af0..b2b929be5 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -246,7 +246,6 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); DWORD uv__next_timeout(const uv_loop_t* loop); -void uv__time_forward(uv_loop_t* loop, uint64_t msecs); void uv_process_timers(uv_loop_t* loop); diff --git a/src/win/timer.c b/src/win/timer.c index 0da541a2c..27ca7716a 100644 --- a/src/win/timer.c +++ b/src/win/timer.c @@ -34,13 +34,8 @@ void uv_update_time(uv_loop_t* loop) { uint64_t new_time = uv__hrtime(UV__MILLISEC); - if (new_time > loop->time) { - loop->time = new_time; - } -} - -void uv__time_forward(uv_loop_t* loop, uint64_t msecs) { - loop->time += msecs; + assert(new_time >= loop->time); + loop->time = new_time; } diff --git a/test/test-list.h b/test/test-list.h index 858a20af4..d1eaf2ac9 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -154,6 +154,7 @@ TEST_DECLARE (timer_huge_repeat) TEST_DECLARE (timer_run_once) TEST_DECLARE (timer_from_check) TEST_DECLARE (timer_null_callback) +TEST_DECLARE (timer_early_check) TEST_DECLARE (idle_starvation) TEST_DECLARE (loop_handles) TEST_DECLARE (get_loadavg) @@ -522,6 +523,7 @@ TASK_LIST_START TEST_ENTRY (timer_run_once) TEST_ENTRY (timer_from_check) TEST_ENTRY (timer_null_callback) + TEST_ENTRY (timer_early_check) TEST_ENTRY (idle_starvation) diff --git a/test/test-timer.c b/test/test-timer.c index aba050fd6..080a73005 100644 --- a/test/test-timer.c +++ b/test/test-timer.c @@ -301,3 +301,30 @@ TEST_IMPL(timer_null_callback) { MAKE_VALGRIND_HAPPY(); return 0; } + + +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); +} + + +TEST_IMPL(timer_early_check) { + uv_timer_t timer_handle; + const uint64_t timeout_ms = 10; + + 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)); + + uv_close((uv_handle_t*) &timer_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From c8619721404c2a9f97adc34a8c3b5336317311bc Mon Sep 17 00:00:00 2001 From: Martin Bark Date: Mon, 14 Dec 2015 21:46:17 +0000 Subject: [PATCH 054/632] unix: fix support for uClibc-ng MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uClibc-ng is currently at v1.0.9. The patch corrects the uClibc version test so that HAVE_IFADDRS_H is defined for uClibc versions after v0.9.32. Signed-off-by: Martin Bark PR-URL: https://github.com/libuv/libuv/pull/653 Reviewed-By: Saúl Ibarra Corretgé --- 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 3ff6fb15e..4735bc4ca 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -39,7 +39,7 @@ #define HAVE_IFADDRS_H 1 #ifdef __UCLIBC__ -# if __UCLIBC_MAJOR__ < 0 || __UCLIBC_MINOR__ < 9 || __UCLIBC_SUBLEVEL__ < 32 +# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32 # undef HAVE_IFADDRS_H # endif #endif From a0057d96bec15dd1ef5886e9e69941132101a4f9 Mon Sep 17 00:00:00 2001 From: Dave Date: Tue, 22 Dec 2015 05:00:13 -0800 Subject: [PATCH 055/632] doc: indicate where new test files need to be added MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/662 Reviewed-By: Saúl Ibarra Corretgé --- CONTRIBUTING.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b46edd492..01b6b223e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -138,7 +138,10 @@ $ git rebase upstream/v1.x # or upstream/master ### TEST Bug fixes and features should come with tests. Add your tests in the -`test/` directory. Tests also need to be registered in `test/test-list.h`. +`test/` directory. Each new test needs to be registered in `test/test-list.h`. If you add a new test file, it needs to be registered in two places: +- `Makefile.am`: add the file's name to the `test_run_tests_SOURCES` list. +- `uv.gyp`: add the file's name to the `sources` list in the `run-tests` target. + Look at other tests to see how they should be structured (license boilerplate, the way entry points are declared, etc.). From bcecc3dda3090d3b9fa787d315c9609f6174a7ef Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 4 Jan 2016 10:56:02 +0100 Subject: [PATCH 056/632] test,unix: fix logic error in test runner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the logic that guards against the system clock jumping back in time. Fixes: https://github.com/libuv/libuv/issues/667 PR-URL: https://github.com/libuv/libuv/pull/670 Reviewed-By: Saúl Ibarra Corretgé --- test/runner-unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runner-unix.c b/test/runner-unix.c index 2264d1e89..2405fa878 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -226,7 +226,7 @@ int process_wait(process_info_t* vec, int n, int timeout) { tv = timebase; for (;;) { /* Check that gettimeofday() doesn't jump back in time. */ - assert(tv.tv_sec == timebase.tv_sec || + assert(tv.tv_sec > timebase.tv_sec || (tv.tv_sec == timebase.tv_sec && tv.tv_usec >= timebase.tv_usec)); elapsed_ms = From a564ef09dc260240b001131b627b8bfc9b895b37 Mon Sep 17 00:00:00 2001 From: Dave Date: Sat, 19 Dec 2015 22:21:07 -0800 Subject: [PATCH 057/632] fs: don't nullify req->bufs on EINTR uv__fs_buf_iter currently sets req->bufs to NULL after it is done, but if the operation fails with EINTR then it will be retried, at which point it expects the bufs to not be NULL, causing a seg fault as in https://github.com/nodejs/node/issues/4291. uv__fs_buf_iter should not set req->bufs to NULL if the operation fails with EINTR. Also, when it sets req->bufs to NULL, it should set req->nbufs to 0 as well, so we don't have the messy situation of a positive nbufs with no actual bufs. PR-URL: https://github.com/libuv/libuv/pull/661 Reviewed-By: Fedor Indutny --- Makefile.am | 1 + src/unix/fs.c | 5 ++ test/test-eintr-handling.c | 93 ++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 + uv.gyp | 1 + 5 files changed, 102 insertions(+) create mode 100644 test/test-eintr-handling.c diff --git a/Makefile.am b/Makefile.am index 0ef781ff1..1fd09a5e2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -151,6 +151,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-default-loop-close.c \ test/test-delayed-accept.c \ test/test-dlerror.c \ + test/test-eintr-handling.c \ test/test-embed.c \ test/test-emfile.c \ test/test-error.c \ diff --git a/src/unix/fs.c b/src/unix/fs.c index 57b65be25..27b6c5dc0 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -858,9 +858,14 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) total += result; } + if (errno == EINTR && total == -1) + return total; + if (bufs != req->bufsml) uv__free(bufs); + req->bufs = NULL; + req->nbufs = 0; return total; } diff --git a/test/test-eintr-handling.c b/test/test-eintr-handling.c new file mode 100644 index 000000000..1fffcd2dc --- /dev/null +++ b/test/test-eintr-handling.c @@ -0,0 +1,93 @@ +/* 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(pipe_set_non_blocking) { + RETURN_SKIP("Test not implemented on Windows."); +} + +#else /* !_WIN32 */ + +#include + +static uv_loop_t* loop; +static uv_fs_t read_req; +static uv_buf_t iov; + +static char buf[32]; +static char test_buf[] = "test-buffer\n"; +int pipe_fds[2]; + +struct thread_ctx { + uv_barrier_t barrier; + int fd; +}; + +static void thread_main(void* arg) { + int nwritten; + ASSERT(0 == kill(getpid(), SIGUSR1)); + + do { + nwritten = write(pipe_fds[1], test_buf, sizeof(test_buf)); + } while (nwritten == -1 && errno == EINTR); + + ASSERT(nwritten == sizeof(test_buf)); +} + +static void sig_func(uv_signal_t* handle, int signum) { + uv_signal_stop(handle); +} + +TEST_IMPL(eintr_handling) { + struct thread_ctx ctx; + uv_thread_t thread; + uv_signal_t signal; + int nread; + + 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(0 == pipe(pipe_fds)); + ASSERT(0 == 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(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(0 == close(pipe_fds[0])); + ASSERT(0 == close(pipe_fds[1])); + uv_close((uv_handle_t*) &signal, NULL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* !_WIN32 */ diff --git a/test/test-list.h b/test/test-list.h index d1eaf2ac9..42315b35d 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -192,6 +192,7 @@ TEST_DECLARE (active) TEST_DECLARE (embed) TEST_DECLARE (async) TEST_DECLARE (async_null_cb) +TEST_DECLARE (eintr_handling) TEST_DECLARE (get_currentexe) TEST_DECLARE (process_title) TEST_DECLARE (cwd_and_chdir) @@ -568,6 +569,7 @@ TASK_LIST_START TEST_ENTRY (async) TEST_ENTRY (async_null_cb) + TEST_ENTRY (eintr_handling) TEST_ENTRY (get_currentexe) diff --git a/uv.gyp b/uv.gyp index 635a234ea..c3734ba3f 100644 --- a/uv.gyp +++ b/uv.gyp @@ -300,6 +300,7 @@ 'test/test-cwd-and-chdir.c', 'test/test-default-loop-close.c', 'test/test-delayed-accept.c', + 'test/test-eintr-handling.c', 'test/test-error.c', 'test/test-embed.c', 'test/test-emfile.c', From 3db07cc379a881d942eef6d2248afaef89a8857a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 4 Jan 2016 12:32:22 +0100 Subject: [PATCH 058/632] osx: set the default thread stack size to RLIMIT_STACK Fixes: https://github.com/libuv/libuv/issues/669 PR-URL: https://github.com/libuv/libuv/pull/671 Reviewed-By: Ben Noordhuis --- src/unix/thread.c | 31 ++++++++++++++++++++++++++++++- test/test-list.h | 2 ++ test/test-thread.c | 21 +++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/unix/thread.c b/src/unix/thread.c index c56a31702..673e47e9e 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -27,6 +27,7 @@ #include #include +#include /* getrlimit() */ #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) @@ -55,6 +56,11 @@ static void* uv__thread_start(void *arg) int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { struct thread_ctx* ctx; int err; + pthread_attr_t* attr; +#if defined(__APPLE__) + pthread_attr_t attr_storage; + struct rlimit lim; +#endif ctx = uv__malloc(sizeof(*ctx)); if (ctx == NULL) @@ -63,7 +69,30 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { ctx->entry = entry; ctx->arg = arg; - err = pthread_create(tid, NULL, uv__thread_start, ctx); + /* On OSX threads other than the main thread are created with a reduced stack + * size by default, adjust it to RLIMIT_STACK. + */ +#if defined(__APPLE__) + if (getrlimit(RLIMIT_STACK, &lim)) + abort(); + + attr = &attr_storage; + if (pthread_attr_init(attr)) + abort(); + + if (lim.rlim_cur != RLIM_INFINITY && + lim.rlim_cur >= PTHREAD_STACK_MIN) { + if (pthread_attr_setstacksize(attr, lim.rlim_cur)) + abort(); + } +#else + attr = NULL; +#endif + + err = pthread_create(tid, attr, uv__thread_start, ctx); + + if (attr != NULL) + pthread_attr_destroy(attr); if (err) uv__free(ctx); diff --git a/test/test-list.h b/test/test-list.h index 42315b35d..dce5de324 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -294,6 +294,7 @@ TEST_DECLARE (threadpool_cancel_work) TEST_DECLARE (threadpool_cancel_fs) TEST_DECLARE (threadpool_cancel_single) TEST_DECLARE (thread_local_storage) +TEST_DECLARE (thread_stack_size) TEST_DECLARE (thread_mutex) TEST_DECLARE (thread_rwlock) TEST_DECLARE (thread_rwlock_trylock) @@ -717,6 +718,7 @@ TASK_LIST_START TEST_ENTRY (threadpool_cancel_fs) TEST_ENTRY (threadpool_cancel_single) TEST_ENTRY (thread_local_storage) + TEST_ENTRY (thread_stack_size) TEST_ENTRY (thread_mutex) TEST_ENTRY (thread_rwlock) TEST_ENTRY (thread_rwlock_trylock) diff --git a/test/test-thread.c b/test/test-thread.c index 7f3321aa0..10bec3fe6 100644 --- a/test/test-thread.c +++ b/test/test-thread.c @@ -209,3 +209,24 @@ TEST_IMPL(thread_local_storage) { uv_key_delete(&tls_key); return 0; } + + +#if defined(__APPLE__) +static void thread_check_stack(void* arg) { + /* 512KB is the default stack size of threads other than the main thread + * on OSX. */ + ASSERT(pthread_get_stacksize_np(pthread_self()) > 512*1024); +} +#endif + + +TEST_IMPL(thread_stack_size) { +#if defined(__APPLE__) + uv_thread_t thread; + ASSERT(0 == uv_thread_create(&thread, thread_check_stack, NULL)); + ASSERT(0 == uv_thread_join(&thread)); + return 0; +#else + RETURN_SKIP("OSX only test"); +#endif +} From 893195750d667e04441f524ab1c301f45199c087 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 5 Jan 2016 13:01:26 +0100 Subject: [PATCH 059/632] build: invoke libtoolize with --copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure that ltmain.sh gets copied, not symlinked, like we do with automake artifacts. PR-URL: https://github.com/libuv/libuv/pull/675 Reviewed-By: Saúl Ibarra Corretgé --- autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index 0574778a4..271c2ee8c 100755 --- a/autogen.sh +++ b/autogen.sh @@ -40,7 +40,7 @@ echo "m4_define([UV_EXTRA_AUTOMAKE_FLAGS], [$UV_EXTRA_AUTOMAKE_FLAGS])" \ > m4/libuv-extra-automake-flags.m4 set -ex -"$LIBTOOLIZE" +"$LIBTOOLIZE" --copy "$ACLOCAL" -I m4 "$AUTOCONF" "$AUTOMAKE" --add-missing --copy From 01ab8d64ad9c0dd8bedb1bcaff3ef74d09372c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 5 Jan 2016 09:10:12 +0100 Subject: [PATCH 060/632] test: fixup eintr_handling - Add missing include - Fix test name on Windows - Fixup style Refs: https://github.com/libuv/libuv/pull/661 PR-URL: https://github.com/libuv/libuv/pull/673 Reviewed-By: Ben Noordhuis Reviewed-By: Fedor Indutny --- test/test-eintr-handling.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/test-eintr-handling.c b/test/test-eintr-handling.c index 1fffcd2dc..1aaf623b7 100644 --- a/test/test-eintr-handling.c +++ b/test/test-eintr-handling.c @@ -24,12 +24,13 @@ #ifdef _WIN32 -TEST_IMPL(pipe_set_non_blocking) { +TEST_IMPL(eintr_handling) { RETURN_SKIP("Test not implemented on Windows."); } #else /* !_WIN32 */ +#include #include static uv_loop_t* loop; @@ -49,9 +50,9 @@ static void thread_main(void* arg) { int nwritten; ASSERT(0 == kill(getpid(), SIGUSR1)); - do { - nwritten = write(pipe_fds[1], test_buf, sizeof(test_buf)); - } while (nwritten == -1 && errno == EINTR); + do + nwritten = write(pipe_fds[1], test_buf, sizeof(test_buf)); + while (nwritten == -1 && errno == EINTR); ASSERT(nwritten == sizeof(test_buf)); } From f1a13e9b4abe8c97768a1d38b12ca3766c8a9b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 6 Jan 2016 10:07:34 +0100 Subject: [PATCH 061/632] osx: avoid compilation warning with Clang ~~~~ src/unix/stream.c:1089:19: warning: variable length array folded to constant array as an extension [-Wgnu-folding-constant] char cmsg_space[CMSG_SPACE(UV__CMSG_FD_SIZE)]; ~~~~ PR-URL: https://github.com/libuv/libuv/pull/677 Reviewed-By: Ben Noordhuis --- src/unix/stream.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/unix/stream.c b/src/unix/stream.c index 7d7ab2633..4da6ce673 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1082,6 +1082,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" +#endif + static void uv__read(uv_stream_t* stream) { uv_buf_t buf; ssize_t nread; @@ -1187,6 +1192,10 @@ 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 From ad2cc8f6a79499732225c239a3c988b95f6767be Mon Sep 17 00:00:00 2001 From: Alexis Murzeau Date: Thu, 7 Jan 2016 00:47:25 +0100 Subject: [PATCH 062/632] test,win: fix compilation with shared lib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests were failing to link because of undefined snprintf symbol with VS < 2015 and using shared library. snprintf is implemented in libuv in src/win/snprintf.c when compiling with VS < 2015, so this commit add src/win/snprintf.c to test sources to make snprintf available in tests. PR-URL: https://github.com/libuv/libuv/pull/678 Reviewed-By: Saúl Ibarra Corretgé --- uv.gyp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/uv.gyp b/uv.gyp index c3734ba3f..4a044b28f 100644 --- a/uv.gyp +++ b/uv.gyp @@ -418,7 +418,8 @@ [ 'OS=="win"', { 'sources': [ 'test/runner-win.c', - 'test/runner-win.h' + 'test/runner-win.h', + 'src/win/snprintf.c', ], 'libraries': [ '-lws2_32' ] }, { # POSIX @@ -486,6 +487,7 @@ 'sources': [ 'test/runner-win.c', 'test/runner-win.h', + 'src/win/snprintf.c', ], 'libraries': [ '-lws2_32' ] }, { # POSIX From d41749d546e70c5456c13c8741c7784c2c4b2048 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Tue, 19 Jan 2016 15:21:42 -0500 Subject: [PATCH 063/632] test: fix race condition in pipe-close-stdout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the child process reaches uv_run before the parent has closed the write end of the pipe the test fails with the following output: Assertion failed in test/test-pipe-close-stdout-read-stdin.c on line 86: uv_run(uv_default_loop(), UV_RUN_NOWAIT) == 0 Assertion failed in test/test-pipe-close-stdout-read-stdin.c on line 97: WIFEXITED(status) && WEXITSTATUS(status) == 0 This is mainly seen on AIX, but does not mean that it can not occur on linux. This change causes the child process to be blocked until the write end of the pipe is properly closed. See 'man 7 pipe'[0] for more detail. [0]http://linux.die.net/man/7/pipe PR-URL: https://github.com/libuv/libuv/pull/688 Reviewed-By: Saúl Ibarra Corretgé --- test/test-pipe-close-stdout-read-stdin.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test-pipe-close-stdout-read-stdin.c b/test/test-pipe-close-stdout-read-stdin.c index ee8bb2a9a..4ab14789a 100644 --- a/test/test-pipe-close-stdout-read-stdin.c +++ b/test/test-pipe-close-stdout-read-stdin.c @@ -53,6 +53,7 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { int pid; int fd[2]; int status; + char buf; uv_pipe_t stdin_pipe; r = pipe(fd); @@ -64,6 +65,8 @@ TEST_IMPL(pipe_close_stdout_read_stdin) { * The write side will be closed by the parent process. */ close(fd[1]); + /* block until write end of pipe is closed */ + read(fd[0], &buf, 1); close(0); r = dup(fd[0]); ASSERT(r != -1); From c0fa2e7518a3a0e364c56f8223bdd0f549ddac66 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 4 Jan 2016 16:52:44 -0500 Subject: [PATCH 064/632] unix,win: add uv_os_tmpdir() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/672 Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 1 + checksparse.sh | 1 + docs/src/misc.rst | 16 ++++++++++++++ include/uv.h | 1 + src/unix/core.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ src/win/util.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 3 +++ test/test-tmpdir.c | 50 +++++++++++++++++++++++++++++++++++++++++++ uv.gyp | 1 + 9 files changed, 177 insertions(+) create mode 100644 test/test-tmpdir.c diff --git a/Makefile.am b/Makefile.am index 1fd09a5e2..663b55ee3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -243,6 +243,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-timer-again.c \ test/test-timer-from-check.c \ test/test-timer.c \ + test/test-tmpdir.c \ test/test-tty.c \ test/test-udp-bind.c \ test/test-udp-create-socket-early.c \ diff --git a/checksparse.sh b/checksparse.sh index 619cf6f8b..dbaa45749 100755 --- a/checksparse.sh +++ b/checksparse.sh @@ -155,6 +155,7 @@ test/test-threadpool-cancel.c test/test-threadpool.c test/test-timer-again.c test/test-timer.c +test/test-tmpdir.c test/test-tty.c test/test-udp-dgram-too-big.c test/test-udp-ipv6.c diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 2ce0887db..bf234dae6 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -273,6 +273,22 @@ API .. versionadded:: 1.6.0 +.. c:function:: int uv_os_tmpdir(char* buffer, size_t* size) + + Gets the temp directory. On Windows, `uv_os_tmpdir()` uses `GetTempPathW()`. + On all other operating systems, `uv_os_tmpdir()` uses the first environment + variable found in the ordered list `TMPDIR`, `TMP`, `TEMP`, and `TEMPDIR`. + If none of these are found, the path `"/tmp"` is used, or, on Android, + `"/data/local/tmp"` is used. The temp directory is stored in `buffer`. When + `uv_os_tmpdir()` is called, `size` indicates the maximum size of `buffer`. + On success or `UV_ENOBUFS` failure, `size` is set to the string length of + `buffer` (which does not include the terminating null). + + .. warning:: + `uv_os_tmpdir()` is not thread safe. + + .. versionadded:: 1.9.0 + .. uint64_t uv_get_free_memory(void) .. c:function:: uint64_t uv_get_total_memory(void) diff --git a/include/uv.h b/include/uv.h index dd3111a96..8d56a45e3 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1049,6 +1049,7 @@ typedef struct { UV_EXTERN int uv_getrusage(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); 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 cedd86ed3..8a7898e10 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1102,3 +1102,54 @@ int uv_os_homedir(char* buffer, size_t* size) { return 0; } + + +int uv_os_tmpdir(char* buffer, size_t* size) { + const char* buf; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + +#define CHECK_ENV_VAR(name) \ + do { \ + buf = getenv(name); \ + if (buf != NULL) \ + goto return_buffer; \ + } \ + while (0) + + /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */ + CHECK_ENV_VAR("TMPDIR"); + CHECK_ENV_VAR("TMP"); + CHECK_ENV_VAR("TEMP"); + CHECK_ENV_VAR("TEMPDIR"); + +#undef CHECK_ENV_VAR + + /* No temp environment variables defined */ + #if defined(__ANDROID__) + buf = "/data/local/tmp"; + #else + buf = "/tmp"; + #endif + +return_buffer: + len = strlen(buf); + + if (len >= *size) { + *size = len; + return -ENOBUFS; + } + + /* The returned directory should not have a trailing slash. */ + if (len > 1 && buf[len - 1] == '/') { + len--; + } + + memcpy(buffer, buf, len + 1); + buffer[len] = '\0'; + *size = len; + + return 0; +} diff --git a/src/win/util.c b/src/win/util.c index cb2475130..dbad249b2 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1230,3 +1230,56 @@ int uv_os_homedir(char* buffer, size_t* size) { *size = bufsize - 1; return 0; } + + +int uv_os_tmpdir(char* buffer, size_t* size) { + wchar_t path[MAX_PATH + 1]; + DWORD bufsize; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + len = GetTempPathW(MAX_PATH + 1, path); + + if (len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (len > MAX_PATH + 1) { + /* This should not be possible */ + return UV_EIO; + } + + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed.*/ + if (path[len - 1] == L'\\' && + !(len == 3 && path[1] == L':')) { + len--; + path[len] = L'\0'; + } + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize - 1; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index dce5de324..3584df8a4 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -199,6 +199,7 @@ TEST_DECLARE (cwd_and_chdir) TEST_DECLARE (get_memory) TEST_DECLARE (handle_fileno) TEST_DECLARE (homedir) +TEST_DECLARE (tmpdir) TEST_DECLARE (hrtime) TEST_DECLARE (getaddrinfo_fail) TEST_DECLARE (getaddrinfo_fail_sync) @@ -586,6 +587,8 @@ TASK_LIST_START TEST_ENTRY (homedir) + TEST_ENTRY (tmpdir) + TEST_ENTRY (hrtime) TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000) diff --git a/test/test-tmpdir.c b/test/test-tmpdir.c new file mode 100644 index 000000000..bbc8ba73c --- /dev/null +++ b/test/test-tmpdir.c @@ -0,0 +1,50 @@ +#include "uv.h" +#include "task.h" +#include + +#define PATHMAX 1024 +#define SMALLPATH 1 + +TEST_IMPL(tmpdir) { + char tmpdir[PATHMAX]; + size_t len; + char last; + int r; + + /* Test the normal case */ + len = sizeof tmpdir; + tmpdir[0] = '\0'; + + ASSERT(strlen(tmpdir) == 0); + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == 0); + ASSERT(strlen(tmpdir) == len); + ASSERT(len > 0); + ASSERT(tmpdir[len] == '\0'); + + if (len > 1) { + last = tmpdir[len - 1]; +#ifdef _WIN32 + ASSERT(last != '\\'); +#else + ASSERT(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); + + /* Test invalid inputs */ + r = uv_os_tmpdir(NULL, &len); + ASSERT(r == UV_EINVAL); + r = uv_os_tmpdir(tmpdir, NULL); + ASSERT(r == UV_EINVAL); + len = 0; + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/uv.gyp b/uv.gyp index 4a044b28f..0e88f3fc0 100644 --- a/uv.gyp +++ b/uv.gyp @@ -387,6 +387,7 @@ 'test/test-threadpool.c', 'test/test-threadpool-cancel.c', 'test/test-thread-equal.c', + 'test/test-tmpdir.c', 'test/test-mutexes.c', 'test/test-thread.c', 'test/test-barrier.c', From db680a1dff55fa549c6b05ad7423183f72c05369 Mon Sep 17 00:00:00 2001 From: Didiet Date: Thu, 21 Jan 2016 14:47:39 +0700 Subject: [PATCH 065/632] ios: fix undefined PTHREAD_STACK_MIN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/692 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/thread.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/unix/thread.c b/src/unix/thread.c index 673e47e9e..c35bc926b 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -29,6 +29,8 @@ #include #include /* getrlimit() */ +#include + #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) From c21a75a16cf96b42e659f01ad2209d4968377c71 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Tue, 19 Jan 2016 17:33:50 -0500 Subject: [PATCH 066/632] test: fix threadpool_multiple_event_loops for AIX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disabled the filesystem portion of the test as there are known issues with AIX and its fs. This particular test was failing with a timeout. PR-URL: https://github.com/libuv/libuv/pull/689 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- test/test-thread.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test-thread.c b/test/test-thread.c index 10bec3fe6..94524ae9b 100644 --- a/test/test-thread.c +++ b/test/test-thread.c @@ -123,12 +123,17 @@ static void do_work(void* arg) { getaddrinfo_do(req); } +/* Disable fs work on AIX as there are known issues. + * See: Readme.md AIX Notes + */ +#ifndef _AIX for (i = 0; i < ARRAY_SIZE(fs_reqs); i++) { struct fs_req* req = fs_reqs + i; req->counter = 16; req->loop = loop; fs_do(req); } +#endif r = uv_run(loop, UV_RUN_DEFAULT); ASSERT(r == 0); From a0b56059cfce1a923be17115fd5c666750f0497a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 20 Dec 2015 02:29:11 +0100 Subject: [PATCH 067/632] unix: report errors for unpollable fds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Libuv would abort() when trying to watch a file descriptor that is not compatible with epoll-style polling; file descriptors referring to on-disk files fall into this category. File descriptors that libuv creates itself are not an issue but external ones that come in through the uv_poll_init() API are. Make uv_poll_init() check whether the file descriptor is accepted by the underlying system call and return an error when it's not. Fixes: https://github.com/libuv/libuv/issues/658 PR-URL: https://github.com/libuv/libuv/pull/659 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/aix.c | 18 ++++++++++++++++++ src/unix/internal.h | 1 + src/unix/kqueue.c | 18 ++++++++++++++++++ src/unix/linux-core.c | 20 ++++++++++++++++++++ src/unix/poll.c | 4 ++++ src/unix/sunos.c | 11 +++++++++++ test/test-list.h | 2 ++ test/test-poll.c | 29 ++++++++++++++++++++++++++++- 8 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/unix/aix.c b/src/unix/aix.c index c90b7e5cb..0bd9c0eb5 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -91,6 +91,24 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct poll_ctl pc; + + pc.events = POLLIN; + pc.cmd = PS_MOD; /* Equivalent to PS_ADD if the fd is not in the pollset. */ + pc.fd = fd; + + if (pollset_ctl(loop->backend_fd, &pc, 1)) + return -errno; + + pc.cmd = PS_DELETE; + if (pollset_ctl(loop->backend_fd, &pc, 1)) + abort(); + + return 0; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { struct pollfd events[1024]; struct pollfd pqry; diff --git a/src/unix/internal.h b/src/unix/internal.h index 741fa57d6..bc5ea4ddb 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -180,6 +180,7 @@ 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); int uv__io_active(const uv__io_t* w, unsigned int events); +int uv__io_check_fd(uv_loop_t* loop, int fd); void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ /* async */ diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 495f20d28..b054b4a8c 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -48,6 +48,24 @@ int uv__kqueue_init(uv_loop_t* loop) { } +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct kevent ev; + int rc; + + rc = 0; + EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + rc = -errno; + + EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + if (rc == 0) + if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) + abort(); + + return rc; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { struct kevent events[1024]; struct kevent* ev; diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 4735bc4ca..d7ff89f26 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -140,6 +140,26 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { } +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct uv__epoll_event e; + int rc; + + e.events = UV__EPOLLIN; + e.data = -1; + + rc = 0; + if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e)) + if (errno != EEXIST) + rc = -errno; + + if (rc == 0) + if (uv__epoll_ctl(loop->backend_fd, UV__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 diff --git a/src/unix/poll.c b/src/unix/poll.c index 37da3b958..e8091dcc0 100644 --- a/src/unix/poll.c +++ b/src/unix/poll.c @@ -53,6 +53,10 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { int err; + err = uv__io_check_fd(loop, fd); + if (err) + return err; + err = uv__nonblock(fd, 1); if (err) return err; diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 0c46817b4..9a6cc42b5 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -116,6 +116,17 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { } +int uv__io_check_fd(uv_loop_t* loop, int fd) { + if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) + return -errno; + + if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) + abort(); + + return 0; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { struct port_event events[1024]; struct port_event* pe; diff --git a/test/test-list.h b/test/test-list.h index 3584df8a4..d368c4fd7 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -305,6 +305,7 @@ TEST_DECLARE (dlerror) TEST_DECLARE (poll_duplex) TEST_DECLARE (poll_unidirectional) TEST_DECLARE (poll_close) +TEST_DECLARE (poll_bad_fdtype) TEST_DECLARE (ip4_addr) TEST_DECLARE (ip6_addr_link_local) @@ -608,6 +609,7 @@ TASK_LIST_START TEST_ENTRY (poll_duplex) TEST_ENTRY (poll_unidirectional) TEST_ENTRY (poll_close) + TEST_ENTRY (poll_bad_fdtype) TEST_ENTRY (socket_buffer_size) diff --git a/test/test-poll.c b/test/test-poll.c index be8b00c32..524dfab49 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -21,7 +21,9 @@ #include -#ifndef _WIN32 +#ifdef _WIN32 +# include +#else # include # include #endif @@ -558,3 +560,28 @@ TEST_IMPL(poll_unidirectional) { start_poll_test(); return 0; } + + +/* 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 and Solaris so skip the test on those platforms. + */ +TEST_IMPL(poll_bad_fdtype) { +#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) + uv_poll_t poll_handle; + int fd; + +#if defined(_WIN32) + fd = open("test/fixtures/empty_file", O_RDONLY); +#else + fd = open(".", O_RDONLY); +#endif + ASSERT(fd != -1); + ASSERT(0 != uv_poll_init(uv_default_loop(), &poll_handle, fd)); + ASSERT(0 == close(fd)); +#endif + + MAKE_VALGRIND_HAPPY(); + return 0; +} From 3c59ad6d9520bd3edadc84d15402582caf75dec2 Mon Sep 17 00:00:00 2001 From: Nikolai Vavilov Date: Thu, 14 Jan 2016 19:21:47 +0200 Subject: [PATCH 068/632] win: fix watching root files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When passing "\\?\C:" to CreateFile, it opens the drive rather than the root directory. So include the trailing backslash in the directory name. Fixes: https://github.com/nodejs/node/issues/4643 PR-URL: https://github.com/libuv/libuv/pull/689 Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs-event.c | 6 +++--- test/test-fs-event.c | 27 +++++++++++++++++++++++++++ test/test-list.h | 6 ++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 76ecfebaa..d9733a879 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -101,12 +101,12 @@ static int uv_split_path(const WCHAR* filename, WCHAR** dir, *file = wcsdup(filename); } else { if (dir) { - *dir = (WCHAR*)uv__malloc((i + 1) * sizeof(WCHAR)); + *dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR)); if (!*dir) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - wcsncpy(*dir, filename, i); - (*dir)[i] = L'\0'; + wcsncpy(*dir, filename, i + 1); + (*dir)[i + 1] = L'\0'; } *file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR)); diff --git a/test/test-fs-event.c b/test/test-fs-event.c index e02ff2fda..e45b9de58 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -531,6 +531,33 @@ TEST_IMPL(fs_event_watch_file_current_dir) { return 0; } +#ifdef _WIN32 +TEST_IMPL(fs_event_watch_file_root_dir) { + uv_loop_t* loop; + int r; + + const char* sys_drive = getenv("SystemDrive"); + char path[] = "\\\\?\\X:\\bootsect.bak"; + + ASSERT(sys_drive != NULL); + strncpy(path + sizeof("\\\\?\\") - 1, sys_drive, 1); + + loop = uv_default_loop(); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + 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); + + uv_close(&fs_event, NULL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + TEST_IMPL(fs_event_no_callback_after_close) { uv_loop_t* loop = uv_default_loop(); int r; diff --git a/test/test-list.h b/test/test-list.h index d368c4fd7..37746b8e2 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -270,6 +270,9 @@ TEST_DECLARE (fs_event_watch_dir_recursive) TEST_DECLARE (fs_event_watch_file) TEST_DECLARE (fs_event_watch_file_twice) TEST_DECLARE (fs_event_watch_file_current_dir) +#ifdef _WIN32 +TEST_DECLARE (fs_event_watch_file_root_dir) +#endif TEST_DECLARE (fs_event_no_callback_after_close) TEST_DECLARE (fs_event_no_callback_on_close) TEST_DECLARE (fs_event_immediate_close) @@ -698,6 +701,9 @@ TASK_LIST_START TEST_ENTRY (fs_event_watch_file) TEST_ENTRY (fs_event_watch_file_twice) TEST_ENTRY (fs_event_watch_file_current_dir) +#ifdef _WIN32 + TEST_ENTRY (fs_event_watch_file_root_dir) +#endif TEST_ENTRY (fs_event_no_callback_after_close) TEST_ENTRY (fs_event_no_callback_on_close) TEST_ENTRY (fs_event_immediate_close) From af4c489e0a8592d2fa14337020891e651f9405ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 26 Jan 2016 09:52:02 +0100 Subject: [PATCH 069/632] build,win: print the Visual Studio version in use PR-URL: https://github.com/libuv/libuv/pull/698 Reviewed-By: Ben Noordhuis --- vcbuild.bat | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vcbuild.bat b/vcbuild.bat index 696f0db30..9a7ed4b8c 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -49,6 +49,7 @@ if not defined VS140COMNTOOLS goto vc-set-2013 if not exist "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2013 call "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2015 +echo Using Visual Studio 2015 goto select-target :vc-set-2013 @@ -57,6 +58,7 @@ if not defined VS120COMNTOOLS goto vc-set-2012 if not exist "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2012 call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2013 +echo Using Visual Studio 2013 goto select-target :vc-set-2012 @@ -65,6 +67,7 @@ if not defined VS110COMNTOOLS goto vc-set-2010 if not exist "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2010 call "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2012 +echo Using Visual Studio 2012 goto select-target :vc-set-2010 @@ -73,6 +76,7 @@ if not defined VS100COMNTOOLS goto vc-set-2008 if not exist "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2008 call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2010 +echo Using Visual Studio 2010 goto select-target :vc-set-2008 @@ -81,6 +85,7 @@ if not defined VS90COMNTOOLS goto vc-set-notfound if not exist "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-notfound call "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% set GYP_MSVS_VERSION=2008 +echo Using Visual Studio 2008 goto select-target :vc-set-notfound From 76da68ea04b9ceebfa428b30f62c2fdd592c43dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 26 Jan 2016 09:47:28 +0100 Subject: [PATCH 070/632] build,win: remove unneeded condition from GYP file The file itself contains include guards, so don't compile it conditionally. PR-URL: https://github.com/libuv/libuv/pull/697 Reviewed-By: Ben Noordhuis --- uv.gyp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/uv.gyp b/uv.gyp index 0e88f3fc0..cd945b184 100644 --- a/uv.gyp +++ b/uv.gyp @@ -92,6 +92,7 @@ 'src/win/req.c', 'src/win/req-inl.h', 'src/win/signal.c', + 'src/win/snprintf.c', 'src/win/stream.c', 'src/win/stream-inl.h', 'src/win/tcp.c', @@ -104,13 +105,6 @@ 'src/win/winsock.c', 'src/win/winsock.h', ], - 'conditions': [ - ['MSVS_VERSION < "2015"', { - 'sources': [ - 'src/win/snprintf.c' - ] - }] - ], 'link_settings': { 'libraries': [ '-ladvapi32', From 51c1a28d7e5ac189570a5e57664f4031038c5f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 28 Jan 2016 14:51:37 +0100 Subject: [PATCH 071/632] test,win: fix compilation warning PR-URL: https://github.com/libuv/libuv/pull/700 Reviewed-By: Ben Noordhuis --- 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 e45b9de58..267533dd9 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -551,7 +551,7 @@ TEST_IMPL(fs_event_watch_file_root_dir) { RETURN_SKIP("bootsect.bak doesn't exist in system root.\n"); ASSERT(r == 0); - uv_close(&fs_event, NULL); + uv_close((uv_handle_t*) &fs_event, NULL); MAKE_VALGRIND_HAPPY(); return 0; From b6650dff56ac78830331cffeb1eec93869c1de0e Mon Sep 17 00:00:00 2001 From: Nan Xiang <514580344@qq.com> Date: Tue, 26 Jan 2016 12:15:15 +0800 Subject: [PATCH 072/632] test: use uv_loop_close and assert its result MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uv_loop_delete is considered deprecated. PR-URL: https://github.com/libuv/libuv/pull/696 Reviewed-By: Saúl Ibarra Corretgé --- test/task.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/task.h b/test/task.h index d18c1daa3..d10add74d 100644 --- a/test/task.h +++ b/test/task.h @@ -108,10 +108,10 @@ typedef enum { /* This macro cleans up the main loop. This is used to avoid valgrind * warnings about memory being "leaked" by the main event loop. */ -#define MAKE_VALGRIND_HAPPY() \ - do { \ - close_loop(uv_default_loop()); \ - uv_loop_delete(uv_default_loop()); \ +#define MAKE_VALGRIND_HAPPY() \ + do { \ + close_loop(uv_default_loop()); \ + ASSERT(0 == uv_loop_close(uv_default_loop())); \ } while (0) /* Just sugar for wrapping the main() for a task or helper. */ From ca6cd35d57db84d63be40f6ae7b5170944d76782 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 2 Feb 2016 00:00:20 +0100 Subject: [PATCH 073/632] build: map 'AMD64' host arch to 'x64' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/705 PR-URL: https://github.com/libuv/libuv/pull/706 Reviewed-By: Saúl Ibarra Corretgé --- gyp_uv.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gyp_uv.py b/gyp_uv.py index 39933f624..458e89e95 100755 --- a/gyp_uv.py +++ b/gyp_uv.py @@ -27,6 +27,7 @@ def host_arch(): machine = platform.machine() if machine == 'i386': return 'ia32' + if machine == 'AMD64': return 'x64' if machine == 'x86_64': return 'x64' if machine.startswith('arm'): return 'arm' if machine.startswith('mips'): return 'mips' From 7dc1bd9230c2d7140a5643662413ed999a7c36e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Lor=C3=A9tan?= Date: Thu, 4 Feb 2016 22:30:04 -0800 Subject: [PATCH 074/632] osx: protected use of potentially undefined macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `__FreeBSD__` macro is not defined by default on OSX, and building with `-Wundef` will cause a warning to be emitted. This change makes sure that the macro is only used if defined, removing the warning. PR-URL: https://github.com/libuv/libuv/pull/710 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- 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 8a7898e10..bcfa1b036 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -435,7 +435,7 @@ int uv__accept(int sockfd) { assert(sockfd >= 0); while (1) { -#if defined(__linux__) || __FreeBSD__ >= 10 +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) static int no_accept4; if (no_accept4) From befe1550b9799321f0080456acfed3299f7944e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 9 Feb 2016 17:40:04 +0100 Subject: [PATCH 075/632] linux: fix compilation with musl PR-URL: https://github.com/libuv/libuv/pull/720 Reviewed-By: Ben Noordhuis --- 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 d7ff89f26..a303b21bc 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -52,7 +52,7 @@ # endif # include # include -# include +# include #endif /* HAVE_IFADDRS_H */ /* Available from 2.6.32 onwards. */ From 67e22296d7b6bb82dc05d8716b29ed493726883c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 12 Feb 2016 09:27:26 +0100 Subject: [PATCH 076/632] doc: describe how to make release builds on Unix Refs: https://github.com/libuv/libuv/issues/550 PR-URL: https://github.com/libuv/libuv/pull/722 Reviewed-By: Ben Noordhuis --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dfd24ba79..152db52c4 100644 --- a/README.md +++ b/README.md @@ -156,11 +156,16 @@ project tree manually: ### Unix -Run: +For Debug builds (recommended) run: $ ./gyp_uv.py -f make $ make -C out +For Release builds run: + + $ ./gyp_uv.py -f make + $ BUILDTYPE=Release make -C out + Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries. ### OS X From 2543f56406823aed38a0f8a6a33c1f95dc709b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 12 Feb 2016 09:30:07 +0100 Subject: [PATCH 077/632] doc: add missing link in README PR-URL: https://github.com/libuv/libuv/pull/722 Reviewed-By: Ben Noordhuis --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 152db52c4..17304a7ab 100644 --- a/README.md +++ b/README.md @@ -248,3 +248,4 @@ See the [guidelines for contributing][]. [Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express [guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md [libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png +[x32]: https://en.wikipedia.org/wiki/X32_ABI From 96da21d3f44c571f30052d9b49ba9bceaf9ffba4 Mon Sep 17 00:00:00 2001 From: Rasmus Christian Pedersen Date: Fri, 12 Feb 2016 14:09:35 +0100 Subject: [PATCH 078/632] build: python 2.x/3.x consistent print usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/723 Reviewed-By: Saúl Ibarra Corretgé --- gyp_uv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gyp_uv.py b/gyp_uv.py index 458e89e95..bd37d95c4 100755 --- a/gyp_uv.py +++ b/gyp_uv.py @@ -37,7 +37,7 @@ def host_arch(): def run_gyp(args): rc = gyp.main(args) if rc != 0: - print 'Error running GYP' + print('Error running GYP') sys.exit(rc) @@ -90,5 +90,5 @@ def run_gyp(args): args.append('--no-parallel') gyp_args = list(args) - print gyp_args + print(gyp_args) run_gyp(gyp_args) From 12548de1b568abae81f823779f4ba721f025c000 Mon Sep 17 00:00:00 2001 From: Nan Xiang <514580344@qq.com> Date: Sat, 13 Feb 2016 21:03:35 +0800 Subject: [PATCH 079/632] test: assume no IPv6 if interfaces cannot be listed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/724 Reviewed-By: Saúl Ibarra Corretgé --- test/task.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/task.h b/test/task.h index d10add74d..96cc6377c 100644 --- a/test/task.h +++ b/test/task.h @@ -207,7 +207,7 @@ UNUSED static int can_ipv6(void) { int i; if (uv_interface_addresses(&addr, &count)) - return 1; /* Assume IPv6 support on failure. */ + return 0; /* Assume no IPv6 support on failure. */ supported = 0; for (i = 0; supported == 0 && i < count; i += 1) From a4213b769999070f8fcce25dd32c1c111d31b652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 24 Feb 2016 12:35:13 +0100 Subject: [PATCH 080/632] darwin: replace F_FULLFSYNC with fdatasync syscall Refs: https://github.com/nodejs/node/pull/5402 PR-URL: https://github.com/libuv/libuv/pull/732 Reviewed-By: Ben Noordhuis --- src/unix/fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 27b6c5dc0..54253303a 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -127,8 +127,8 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { #if defined(__linux__) || defined(__sun) || defined(__NetBSD__) return fdatasync(req->file); -#elif defined(__APPLE__) && defined(F_FULLFSYNC) - return fcntl(req->file, F_FULLFSYNC); +#elif defined(__APPLE__) && defined(SYS_fdatasync) + return syscall(SYS_fdatasync, req->file); #else return fsync(req->file); #endif From 729d68596cc6289d60979f29f500cd46c99c6f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A1ndor=20Istv=C3=A1n=20Kr=C3=A1cser?= Date: Wed, 24 Feb 2016 20:37:22 +0100 Subject: [PATCH 081/632] doc: add missing write callback to example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/734 Reviewed-By: Saúl Ibarra Corretgé --- docs/src/stream.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/src/stream.rst b/docs/src/stream.rst index 9f0aacd16..ed0c79d00 100644 --- a/docs/src/stream.rst +++ b/docs/src/stream.rst @@ -148,6 +148,10 @@ API :: + void cb(uv_write_t* req, int status) { + /* Logic which handles the write result */ + } + uv_buf_t a[] = { { .base = "1", .len = 1 }, { .base = "2", .len = 1 } @@ -162,8 +166,8 @@ API uv_write_t req2; /* writes "1234" */ - uv_write(&req1, stream, a, 2); - uv_write(&req2, stream, b, 2); + uv_write(&req1, stream, a, 2, cb); + uv_write(&req2, stream, b, 2, cb); .. c:function:: int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb) From 4a24df9167c14717089e1076ff59a3753c537b26 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Fri, 26 Feb 2016 15:57:18 -0500 Subject: [PATCH 082/632] build: compile with -D_THREAD_SAFE on AIX This enables thread safe errno on AIX and causes the following tests to pass: ipc_send_recv_pipe_inprocess ipc_send_recv_tcp_inprocess fs_poll fs_file_noent fs_file_nametoolong fs_file_loop fs_chown fs_readlink fs_realpath fs_scandir_file PR-URL: https://github.com/libuv/libuv/pull/739 Reviewed-By: Ben Noordhuis --- Makefile.am | 2 +- uv.gyp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 663b55ee3..a0de6f560 100644 --- a/Makefile.am +++ b/Makefile.am @@ -282,7 +282,7 @@ endif if AIX -libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT +libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT -D_THREAD_SAFE include_HEADERS += include/uv-aix.h libuv_la_SOURCES += src/unix/aix.c endif diff --git a/uv.gyp b/uv.gyp index cd945b184..a12753a98 100644 --- a/uv.gyp +++ b/uv.gyp @@ -241,6 +241,7 @@ '_ALL_SOURCE', '_XOPEN_SOURCE=500', '_LINUX_SOURCE_COMPAT', + '_THREAD_SAFE', ], 'link_settings': { 'libraries': [ From b015b4d0ee03b825d61b0b54e36aa405a8e1cf03 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Thu, 25 Feb 2016 11:51:31 -0500 Subject: [PATCH 083/632] test: fix threadpool_multiple_event_loops on PPC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On PPC (linux and AIX) uv_thread_join (which is just a call to pthread_join) takes quite a while. Increased the timeout of this specific test on PPC so that there is ample time for all threads to join back. The fs_do and getaddrinfo_do calls do not take up much time. Also removing the ifdef for AIX around fs_do since it did nothing. Fixes: https://github.com/libuv/libuv/issues/687 PR-URL: https://github.com/libuv/libuv/pull/737 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- test/test-list.h | 7 +++++++ test/test-thread.c | 5 ----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/test/test-list.h b/test/test-list.h index 37746b8e2..3ad8d32be 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -722,7 +722,14 @@ TASK_LIST_START TEST_ENTRY (fs_read_write_null_arguments) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) +#if defined(__PPC__) || defined(__PPC64__) /* For linux PPC and AIX */ + /* pthread_join takes a while, especially on AIX. + * Therefore being gratuitous with timeout. + */ + TEST_ENTRY_CUSTOM (threadpool_multiple_event_loops, 0, 0, 120000) +#else TEST_ENTRY (threadpool_multiple_event_loops) +#endif TEST_ENTRY (threadpool_cancel_getaddrinfo) TEST_ENTRY (threadpool_cancel_getnameinfo) TEST_ENTRY (threadpool_cancel_work) diff --git a/test/test-thread.c b/test/test-thread.c index 94524ae9b..10bec3fe6 100644 --- a/test/test-thread.c +++ b/test/test-thread.c @@ -123,17 +123,12 @@ static void do_work(void* arg) { getaddrinfo_do(req); } -/* Disable fs work on AIX as there are known issues. - * See: Readme.md AIX Notes - */ -#ifndef _AIX for (i = 0; i < ARRAY_SIZE(fs_reqs); i++) { struct fs_req* req = fs_reqs + i; req->counter = 16; req->loop = loop; fs_do(req); } -#endif r = uv_run(loop, UV_RUN_DEFAULT); ASSERT(r == 0); From e76e21389bf57cb5731867f5e87056e4406c922f Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Wed, 2 Mar 2016 11:37:52 -0500 Subject: [PATCH 084/632] test: reduce timeout in tcp_close_while_connecting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Somtimes (once every 10 runs or so) the socket would 'connect' before 'uv_close' was called. This caused EHOSTUNREACH to be set for SO_ERROR instead of ECANCELED. PR-URL: https://github.com/libuv/libuv/pull/744 Reviewed-By: Saúl Ibarra Corretgé --- test/test-tcp-close-while-connecting.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-tcp-close-while-connecting.c b/test/test-tcp-close-while-connecting.c index 2c39b652b..60df7a574 100644 --- a/test/test-tcp-close-while-connecting.c +++ b/test/test-tcp-close-while-connecting.c @@ -72,7 +72,7 @@ TEST_IMPL(tcp_close_while_connecting) { RETURN_SKIP("Network unreachable."); ASSERT(r == 0); ASSERT(0 == uv_timer_init(loop, &timer1_handle)); - ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 50, 0)); + 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)); From e5f4b7980953ab6445db07e141032e903623aba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 20 Jan 2016 09:52:54 +0100 Subject: [PATCH 085/632] unix, win: consistently null-terminate buffers libuv has multiple functions which return buffers. Make them consistent with the following rules: the returned size *does not* include the null byte, but the buffer *is* null terminated. There is only one exception to the above: Linux abstract sockets, because null bytes are not used as string terminators in those. Refs: https://github.com/libuv/libuv/pull/674 PR-URL: https://github.com/libuv/libuv/pull/690 Reviewed-By: Colin Ihrig --- src/fs-poll.c | 3 ++- src/unix/pipe.c | 6 +++++- src/uv-common.c | 3 ++- src/win/pipe.c | 3 ++- test/test-fs-event.c | 1 + test/test-fs-poll.c | 1 + test/test-pipe-getsockname.c | 1 + 7 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/fs-poll.c b/src/fs-poll.c index 44d47b88e..570c95474 100644 --- a/src/fs-poll.c +++ b/src/fs-poll.c @@ -138,13 +138,14 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) { assert(ctx != NULL); required_len = strlen(ctx->path); - if (required_len > *size) { + if (required_len >= *size) { *size = required_len; return UV_ENOBUFS; } memcpy(buffer, ctx->path, required_len); *size = required_len; + buffer[required_len] = '\0'; return 0; } diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 7f87a713b..228f1f77d 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -234,7 +234,7 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, addrlen = strlen(sa.sun_path); - if (addrlen > *size) { + if (addrlen >= *size) { *size = addrlen; return UV_ENOBUFS; } @@ -242,6 +242,10 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, memcpy(buffer, sa.sun_path, addrlen); *size = addrlen; + /* only null-terminate if it's not an abstract socket */ + if (buffer[0] != '\0') + buffer[addrlen] = '\0'; + return 0; } diff --git a/src/uv-common.c b/src/uv-common.c index 40ed28fec..099795364 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -451,13 +451,14 @@ int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) { } required_len = strlen(handle->path); - if (required_len > *size) { + if (required_len >= *size) { *size = required_len; return UV_ENOBUFS; } memcpy(buffer, handle->path, required_len); *size = required_len; + buffer[required_len] = '\0'; return 0; } diff --git a/src/win/pipe.c b/src/win/pipe.c index bcce80c77..a0948ded7 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -2038,7 +2038,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) *size = 0; err = uv_translate_sys_error(GetLastError()); goto error; - } else if (pipe_prefix_len + addrlen > *size) { + } else if (pipe_prefix_len + addrlen >= *size) { /* "\\\\.\\pipe" + name */ *size = pipe_prefix_len + addrlen; err = UV_ENOBUFS; @@ -2062,6 +2062,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) addrlen += pipe_prefix_len; *size = addrlen; + buffer[addrlen] = '\0'; err = 0; goto cleanup; diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 267533dd9..35583529e 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -819,6 +819,7 @@ TEST_IMPL(fs_event_getpath) { r = uv_fs_event_getpath(&fs_event, buf, &len); ASSERT(r == 0); ASSERT(buf[len - 1] != 0); + ASSERT(buf[len] == '\0'); ASSERT(memcmp(buf, "watch_dir", len) == 0); r = uv_fs_event_stop(&fs_event); ASSERT(r == 0); diff --git a/test/test-fs-poll.c b/test/test-fs-poll.c index dbc1515b0..737d50dfd 100644 --- a/test/test-fs-poll.c +++ b/test/test-fs-poll.c @@ -173,6 +173,7 @@ TEST_IMPL(fs_poll_getpath) { 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)); uv_close((uv_handle_t*) &poll_handle, close_cb); diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index 5e036f9d5..58041c026 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -114,6 +114,7 @@ TEST_IMPL(pipe_getsockname) { ASSERT(r == 0); ASSERT(buf[len - 1] != 0); + ASSERT(buf[len] == '\0'); ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0); len = sizeof buf; From 2606ba22a7012d0ed0ebb4464eec8fca9042c51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 21 Jan 2016 10:00:27 +0100 Subject: [PATCH 086/632] unix, win: count null byte on UV_ENOBUFS If an API function returns UV_ENOBUFS make sure we count the terminating null, which we need space for. In case of success the null byte is not included in the count, but the buffer *is* null terminated. PR-URL: https://github.com/libuv/libuv/pull/690 Reviewed-By: Colin Ihrig --- docs/src/misc.rst | 10 ++++++---- src/fs-poll.c | 2 +- src/unix/core.c | 6 +++--- src/unix/pipe.c | 2 +- src/uv-common.c | 2 +- src/win/pipe.c | 2 +- src/win/util.c | 6 +++--- 7 files changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index bf234dae6..ebcb75a28 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -265,8 +265,9 @@ API `uv_os_homedir()` first checks the `HOME` environment variable using :man:`getenv(3)`. If `HOME` is not set, :man:`getpwuid_r(3)` is called. The user's home directory is stored in `buffer`. When `uv_os_homedir()` is - called, `size` indicates the maximum size of `buffer`. On success or - `UV_ENOBUFS` failure, `size` is set to the string length of `buffer`. + called, `size` indicates the maximum size of `buffer`. On success `size` is set + to the string length of `buffer`. On `UV_ENOBUFS` failure `size` is set to the + required length for `buffer`, including the null byte. .. warning:: `uv_os_homedir()` is not thread safe. @@ -281,8 +282,9 @@ API If none of these are found, the path `"/tmp"` is used, or, on Android, `"/data/local/tmp"` is used. The temp directory is stored in `buffer`. When `uv_os_tmpdir()` is called, `size` indicates the maximum size of `buffer`. - On success or `UV_ENOBUFS` failure, `size` is set to the string length of - `buffer` (which does not include the terminating null). + On success `size` is set to the string length of `buffer` (which does not + include the terminating null). On `UV_ENOBUFS` failure `size` is set to the + required length for `buffer`, including the null byte. .. warning:: `uv_os_tmpdir()` is not thread safe. diff --git a/src/fs-poll.c b/src/fs-poll.c index 570c95474..ee73d5a2e 100644 --- a/src/fs-poll.c +++ b/src/fs-poll.c @@ -139,7 +139,7 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) { required_len = strlen(ctx->path); if (required_len >= *size) { - *size = required_len; + *size = required_len + 1; return UV_ENOBUFS; } diff --git a/src/unix/core.c b/src/unix/core.c index bcfa1b036..3997d09da 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1036,7 +1036,7 @@ int uv_os_homedir(char* buffer, size_t* size) { len = strlen(buf); if (len >= *size) { - *size = len; + *size = len + 1; return -ENOBUFS; } @@ -1091,7 +1091,7 @@ int uv_os_homedir(char* buffer, size_t* size) { len = strlen(pw.pw_dir); if (len >= *size) { - *size = len; + *size = len + 1; uv__free(buf); return -ENOBUFS; } @@ -1138,7 +1138,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) { len = strlen(buf); if (len >= *size) { - *size = len; + *size = len + 1; return -ENOBUFS; } diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 228f1f77d..05d37f462 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -235,7 +235,7 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, if (addrlen >= *size) { - *size = addrlen; + *size = addrlen + 1; return UV_ENOBUFS; } diff --git a/src/uv-common.c b/src/uv-common.c index 099795364..6b8c584fb 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -452,7 +452,7 @@ int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) { required_len = strlen(handle->path); if (required_len >= *size) { - *size = required_len; + *size = required_len + 1; return UV_ENOBUFS; } diff --git a/src/win/pipe.c b/src/win/pipe.c index a0948ded7..d42bbfec3 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -2040,7 +2040,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) goto error; } else if (pipe_prefix_len + addrlen >= *size) { /* "\\\\.\\pipe" + name */ - *size = pipe_prefix_len + addrlen; + *size = pipe_prefix_len + addrlen + 1; err = UV_ENOBUFS; goto error; } diff --git a/src/win/util.c b/src/win/util.c index dbad249b2..8cfbd86f3 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -210,7 +210,7 @@ int uv_cwd(char* buffer, size_t* size) { if (r == 0) { return uv_translate_sys_error(GetLastError()); } else if (r > (int) *size) { - *size = r -1; + *size = r; return UV_ENOBUFS; } @@ -1218,7 +1218,7 @@ int uv_os_homedir(char* buffer, size_t* size) { if (bufsize == 0) { return uv_translate_sys_error(GetLastError()); } else if (bufsize > *size) { - *size = bufsize - 1; + *size = bufsize; return UV_ENOBUFS; } @@ -1263,7 +1263,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) { if (bufsize == 0) { return uv_translate_sys_error(GetLastError()); } else if (bufsize > *size) { - *size = bufsize - 1; + *size = bufsize; return UV_ENOBUFS; } From ca0b6578913f861ebeba19189cd6a1b46e320aae Mon Sep 17 00:00:00 2001 From: Katsutoshi Horie Date: Thu, 18 Feb 2016 14:18:00 +0900 Subject: [PATCH 087/632] test: fix deadlocks in uv_cond_wait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling uv_cond_wait without uv_cond_signal/uv_cond_broadcast may cause deadlock. This commit avoids this situation as well as tests these functions. PR-URL: https://github.com/libuv/libuv/pull/728 Reviewed-By: Saúl Ibarra Corretgé --- test/test-condvar.c | 100 +++++++++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 33 deletions(-) diff --git a/test/test-condvar.c b/test/test-condvar.c index dbacdba38..83b28494a 100644 --- a/test/test-condvar.c +++ b/test/test-condvar.c @@ -25,24 +25,33 @@ #include #include -typedef struct { +typedef struct worker_config { uv_mutex_t mutex; uv_cond_t cond; - int delay; + int signal_delay; + int wait_delay; int use_broadcast; - volatile int posted; + volatile int posted_1; + volatile int posted_2; + void (*signal_cond)(struct worker_config* c, volatile int* flag); + void (*wait_cond)(struct worker_config* c, const volatile int* flag); } worker_config; static void worker(void* arg) { worker_config* c = arg; + c->signal_cond(c, &c->posted_1); + c->wait_cond(c, &c->posted_2); +} + - if (c->delay) - uv_sleep(c->delay); +static void condvar_signal(worker_config* c, volatile int* flag) { + if (c->signal_delay) + uv_sleep(c->signal_delay); uv_mutex_lock(&c->mutex); - ASSERT(c->posted == 0); - c->posted = 1; + ASSERT(*flag == 0); + *flag = 1; if (c->use_broadcast) uv_cond_broadcast(&c->cond); else @@ -51,21 +60,33 @@ static void worker(void* arg) { } +static void condvar_wait(worker_config* c, const volatile int* flag) { + uv_mutex_lock(&c->mutex); + if (c->wait_delay) + uv_sleep(c->wait_delay); + while (*flag == 0) { + uv_cond_wait(&c->cond, &c->mutex); + } + ASSERT(*flag == 1); + uv_mutex_unlock(&c->mutex); +} + + TEST_IMPL(condvar_1) { uv_thread_t thread; worker_config wc; memset(&wc, 0, sizeof(wc)); + wc.wait_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - uv_sleep(100); - uv_cond_wait(&wc.cond, &wc.mutex); - ASSERT(wc.posted == 1); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); @@ -80,15 +101,16 @@ TEST_IMPL(condvar_2) { worker_config wc; memset(&wc, 0, sizeof(wc)); - wc.delay = 100; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - uv_cond_wait(&wc.cond, &wc.mutex); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); @@ -98,22 +120,35 @@ TEST_IMPL(condvar_2) { } +static void condvar_timedwait(worker_config* c, const volatile int* flag) { + int r; + + uv_mutex_lock(&c->mutex); + if (c->wait_delay) + uv_sleep(c->wait_delay); + while (*flag == 0) { + r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(150 * 1e6)); + ASSERT(r == 0); + } + uv_mutex_unlock(&c->mutex); +} + + TEST_IMPL(condvar_3) { uv_thread_t thread; worker_config wc; - int r; memset(&wc, 0, sizeof(wc)); - wc.delay = 100; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(50 * 1e6)); - ASSERT(r == UV_ETIMEDOUT); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); @@ -126,19 +161,18 @@ TEST_IMPL(condvar_3) { TEST_IMPL(condvar_4) { uv_thread_t thread; worker_config wc; - int r; memset(&wc, 0, sizeof(wc)); - wc.delay = 100; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(150 * 1e6)); - ASSERT(r == 0); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); @@ -154,16 +188,16 @@ TEST_IMPL(condvar_5) { memset(&wc, 0, sizeof(wc)); wc.use_broadcast = 1; + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_wait; ASSERT(0 == uv_cond_init(&wc.cond)); ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - uv_mutex_lock(&wc.mutex); - uv_sleep(100); - uv_cond_wait(&wc.cond, &wc.mutex); - ASSERT(wc.posted == 1); - uv_mutex_unlock(&wc.mutex); + wc.wait_cond(&wc, &wc.posted_1); + wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); uv_mutex_destroy(&wc.mutex); From 6798876a6b2c2046d926bd2317284de920e6d124 Mon Sep 17 00:00:00 2001 From: Lukasz Jagiello Date: Thu, 25 Feb 2016 07:29:18 +0000 Subject: [PATCH 088/632] linux: fix cpu count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When libuv is running inside container - eg. lxc container, cpu number is not obvious. Linux control groups (cgroups) may limit numer of cpus. As a result of different number cpu cores inside container and outside container, libuv is crashing. sysconf(_SC_NPROCESSORS_ONLN) - returns num of host cpus (eg. 32) `/proc/stat` - sees only cpus limited by cgroups (eg. 4) When libuv is trying to operate at both numbers and they're different it's crashing with current test: run-tests: ../src/unix/linux-core.c:766: read_times: Assertion `num == numcpus' failed. Count the number of cpus based on `/proc/stat` instead. PR-URL: https://github.com/libuv/libuv/pull/735 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/linux-core.c | 54 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index a303b21bc..1fdd71d0f 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -69,7 +69,7 @@ #endif static int read_models(unsigned int numcpus, uv_cpu_info_t* ci); -static int read_times(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 unsigned long read_cpufreq(unsigned int cpunum); @@ -552,15 +552,48 @@ int uv_uptime(double* uptime) { } +static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { + unsigned int num; + char buf[1024]; + + if (!fgets(buf, sizeof(buf), statfile_fp)) + abort(); + + num = 0; + while (fgets(buf, sizeof(buf), statfile_fp)) { + if (strncmp(buf, "cpu", 3)) + break; + num++; + } + + *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; + int statfile_fd; + FILE* statfile_fp; *cpu_infos = NULL; *count = 0; - numcpus = sysconf(_SC_NPROCESSORS_ONLN); + err = uv__open_cloexec("/proc/stat", O_RDONLY); + if (err < 0) + return err; + statfile_fd = err; + + statfile_fp = fdopen(statfile_fd, "r"); + if (statfile_fp == NULL) + return -errno; + + err = uv__cpu_num(statfile_fp, &numcpus); + if (err < 0) + return err; + assert(numcpus != (unsigned int) -1); assert(numcpus != 0); @@ -570,7 +603,10 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { err = read_models(numcpus, ci); if (err == 0) - err = read_times(numcpus, ci); + rewind(statfile_fp); + err = read_times(statfile_fp, numcpus, ci); + + uv__close(statfile_fd); if (err) { uv_free_cpu_info(ci, numcpus); @@ -696,7 +732,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { } -static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { +static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci) { unsigned long clock_ticks; struct uv_cpu_times_s ts; unsigned long user; @@ -708,22 +744,19 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { unsigned int num; unsigned int len; char buf[1024]; - FILE* fp; clock_ticks = sysconf(_SC_CLK_TCK); assert(clock_ticks != (unsigned long) -1); assert(clock_ticks != 0); - fp = fopen("/proc/stat", "r"); - if (fp == NULL) - return -errno; + rewind(statfile_fp); - if (!fgets(buf, sizeof(buf), fp)) + if (!fgets(buf, sizeof(buf), statfile_fp)) abort(); num = 0; - while (fgets(buf, sizeof(buf), fp)) { + while (fgets(buf, sizeof(buf), statfile_fp)) { if (num >= numcpus) break; @@ -762,7 +795,6 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { ts.irq = clock_ticks * irq; ci[num++].cpu_times = ts; } - fclose(fp); assert(num == numcpus); return 0; From a7009a03539b1d56d77c29c68da73b26c71a4ce1 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Thu, 3 Mar 2016 14:56:04 -0500 Subject: [PATCH 089/632] unix: fix uv__handle_type for AIX 'getsockname' does not handle UNIX domain sockets on AIX[1], it does not fail but simply returns an empty structure with length 0. If 'getsockname' does not fail (i.e. does not return -1) and the length is 0 we know, on AIX, that the type is AF_UNIX. This fixes test pipe_sendmsg. [1] https://goo.gl/ozqcmS PR-URL: https://github.com/libuv/libuv/pull/748 Reviewed-By: Ben Noordhuis --- src/unix/stream.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 4da6ce673..9043664df 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -946,13 +946,14 @@ 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)); - len = sizeof(ss); + sslen = sizeof(ss); - if (getsockname(fd, (struct sockaddr*)&ss, &len)) + if (getsockname(fd, (struct sockaddr*)&ss, &sslen)) return UV_UNKNOWN_HANDLE; len = sizeof type; @@ -961,6 +962,14 @@ uv_handle_type uv__handle_type(int fd) { return UV_UNKNOWN_HANDLE; if (type == SOCK_STREAM) { +#if defined(_AIX) + /* on AIX 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; From bb77113042d844a9047ed6fde46922db72ac0bb0 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 3 Mar 2016 02:03:52 +0100 Subject: [PATCH 090/632] linux: call fclose(), fix fdopen() memory leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 6798876 ("linux: fix cpu count") switched the /proc/stat parser to fdopen(). Use fclose() to close the file descriptor to avoid leaking resources associated with the FILE struct. PR-URL: https://github.com/libuv/libuv/pull/747 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/linux-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 1fdd71d0f..5cb3bef62 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -606,7 +606,9 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { rewind(statfile_fp); err = read_times(statfile_fp, numcpus, ci); - uv__close(statfile_fd); + if (fclose(statfile_fp)) + if (errno != EINTR && errno != EINPROGRESS) + abort(); if (err) { uv_free_cpu_info(ci, numcpus); From cfef25dba2f9875dcc1ceec951581eb75255a165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 3 Mar 2016 11:19:42 +0100 Subject: [PATCH 091/632] win: remove unneeded condition PR-URL: https://github.com/libuv/libuv/pull/745 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/win/tty.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/win/tty.c b/src/win/tty.c index d87cc6990..1b27f60a6 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -292,12 +292,9 @@ 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; - - if (was_reading) { - err = uv_tty_read_stop(tty); - if (err) { - return uv_translate_sys_error(err); - } + err = uv_tty_read_stop(tty); + if (err) { + return uv_translate_sys_error(err); } } else { was_reading = 0; From 4c765d72a6ea37f0d90315149fd53dadc54c2966 Mon Sep 17 00:00:00 2001 From: Robert Chiras Date: Thu, 3 Mar 2016 15:20:11 +0200 Subject: [PATCH 092/632] unix: fix compile error in Android using bionic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling with bionic, st_atime_nsec (and the other nsec members) canot be found. In order to compile uv with both NDK and bionic, tv_nsec should be accessed from st_atimensec (and the others nsec members). See "Compatibility with glibc" in stat.h from bionic. Signed-off-by: Robert Chiras PR-URL: https://github.com/libuv/libuv/pull/746 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 54253303a..8936ad9d8 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -749,13 +749,13 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_gen = src->st_gen; #elif defined(__ANDROID__) dst->st_atim.tv_sec = src->st_atime; - dst->st_atim.tv_nsec = src->st_atime_nsec; + dst->st_atim.tv_nsec = src->st_atimensec; dst->st_mtim.tv_sec = src->st_mtime; - dst->st_mtim.tv_nsec = src->st_mtime_nsec; + dst->st_mtim.tv_nsec = src->st_mtimensec; dst->st_ctim.tv_sec = src->st_ctime; - dst->st_ctim.tv_nsec = src->st_ctime_nsec; + dst->st_ctim.tv_nsec = src->st_ctimensec; dst->st_birthtim.tv_sec = src->st_ctime; - dst->st_birthtim.tv_nsec = src->st_ctime_nsec; + dst->st_birthtim.tv_nsec = src->st_ctimensec; dst->st_flags = 0; dst->st_gen = 0; #elif !defined(_AIX) && ( \ From 80d9d86e0fe2e8be1e3d45f1702b31f352d07a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A1ri=20Tristan=20Helgason?= Date: Sat, 5 Mar 2016 08:54:43 +0100 Subject: [PATCH 093/632] linux: add braces to multi-statement if MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/750 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/linux-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 5cb3bef62..7468015c5 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -602,9 +602,10 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { return -ENOMEM; err = read_models(numcpus, ci); - if (err == 0) + if (err == 0) { rewind(statfile_fp); err = read_times(statfile_fp, numcpus, ci); + } if (fclose(statfile_fp)) if (errno != EINTR && errno != EINPROGRESS) From 4972f7411c7683cb91af981e973fc6497a5adc68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 7 Mar 2016 19:51:20 +0100 Subject: [PATCH 094/632] doc: add @cjihrig as a maintainer PR-URL: https://github.com/libuv/libuv/pull/752 Reviewed-By: Ben Noordhuis Reviewed-by: Bert Belder Reviewed-By: Fedor Indutny --- CONTRIBUTING.md | 4 ++-- MAINTAINERS.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 01b6b223e..ef5c2b2fe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,8 +23,7 @@ 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 -(@bnoordhuis, @piscisaureus, @indutny or @saghul) on [IRC][]. +to the [libuv mailing list], or contact one of [project maintainers][] on [IRC][]. 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 @@ -167,3 +166,4 @@ not send out notifications when you add commits. [libuv mailing list]: http://groups.google.com/group/libuv [IRC]: http://webchat.freelibuv.net/?channels=libuv [Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml +[project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 4db2f5130..2f0e618ca 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -6,6 +6,7 @@ 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)) * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) * **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul)) From d7910e42d0d5d2f43952f1723abd7db022b65a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A1ri=20Tristan=20Helgason?= Date: Tue, 1 Mar 2016 22:42:37 +0000 Subject: [PATCH 095/632] unix: add fork-safe open file function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/743 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/core.c | 16 ++++++++++++++++ src/unix/internal.h | 3 +++ 2 files changed, 19 insertions(+) diff --git a/src/unix/core.c b/src/unix/core.c index 3997d09da..5a8987e78 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -427,6 +427,22 @@ int uv__socket(int domain, int type, int protocol) { return sockfd; } +/* get a file pointer to a file in read-only and close-on-exec mode */ +FILE* uv__open_file(const char* path) { + int fd; + FILE* fp; + + fd = uv__open_cloexec(path, O_RDONLY); + if (fd == -1) + return NULL; + + fp = fdopen(fd, "r"); + if (fp == NULL) + uv__close(fd); + + return fp; +} + int uv__accept(int sockfd) { int peerfd; diff --git a/src/unix/internal.h b/src/unix/internal.h index bc5ea4ddb..79dab40ea 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -28,6 +28,7 @@ #include /* abort */ #include /* strrchr */ #include /* O_CLOEXEC, may be */ +#include #if defined(__STRICT_ANSI__) # define inline __inline @@ -246,6 +247,8 @@ void uv__timer_close(uv_timer_t* handle); 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); + #if defined(__APPLE__) int uv___stream_fd(const uv_stream_t* handle); From 2f02ae5f51eb5796aff7184797e5a0047ca239f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A1ri=20Tristan=20Helgason?= Date: Tue, 1 Mar 2016 22:43:12 +0000 Subject: [PATCH 096/632] linux: replace calls to fopen with uv__open_file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/743 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/linux-core.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 7468015c5..f581cfef0 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -575,18 +575,12 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { unsigned int numcpus; uv_cpu_info_t* ci; int err; - int statfile_fd; FILE* statfile_fp; *cpu_infos = NULL; *count = 0; - err = uv__open_cloexec("/proc/stat", O_RDONLY); - if (err < 0) - return err; - statfile_fd = err; - - statfile_fp = fdopen(statfile_fd, "r"); + statfile_fp = uv__open_file("/proc/stat"); if (statfile_fp == NULL) return -errno; @@ -667,7 +661,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { defined(__i386__) || \ defined(__mips__) || \ defined(__x86_64__) - fp = fopen("/proc/cpuinfo", "r"); + fp = uv__open_file("/proc/cpuinfo"); if (fp == NULL) return -errno; @@ -814,7 +808,7 @@ static unsigned long read_cpufreq(unsigned int cpunum) { "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", cpunum); - fp = fopen(buf, "r"); + fp = uv__open_file(buf); if (fp == NULL) return 0; From 365bdec434a7da85526ce3864110962f70cc6a5e Mon Sep 17 00:00:00 2001 From: Krishnaraj Bhat Date: Sat, 5 Mar 2016 23:06:44 +0530 Subject: [PATCH 097/632] linux: remove redundant call to rewind() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's already called in callee read_times() PR-URL: https://github.com/libuv/libuv/pull/751 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/linux-core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index f581cfef0..fb8ac3f23 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -596,10 +596,8 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { return -ENOMEM; err = read_models(numcpus, ci); - if (err == 0) { - rewind(statfile_fp); + if (err == 0) err = read_times(statfile_fp, numcpus, ci); - } if (fclose(statfile_fp)) if (errno != EINTR && errno != EINPROGRESS) From 86051a49d8d0bb48d4372ce5c4caef83c5890c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 8 Mar 2016 09:32:39 +0100 Subject: [PATCH 098/632] win: remove duplicated code when processing fsevents PR-URL: https://github.com/libuv/libuv/pull/756 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/win/fs-event.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index d9733a879..e774ab958 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -437,26 +437,15 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, long_filenamew = NULL; } } - - /* - * We could not resolve the long form explicitly. - * We therefore use the name given by ReadDirectoryChangesW. - * This may be the long form or the 8.3 short name in some cases. - */ - if (!long_filenamew) { - filenamew = file_info->FileName; - sizew = file_info->FileNameLength / sizeof(WCHAR); - } - } else { - /* - * Removed or renamed events cannot be resolved to the long form. - * We therefore use the name given by ReadDirectoryChangesW. - * This may be the long form or the 8.3 short name in some cases. - */ - if (!long_filenamew) { - filenamew = file_info->FileName; - sizew = file_info->FileNameLength / sizeof(WCHAR); - } + } + /* + * Removed or renamed events cannot be resolved to the long form. + * We therefore use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. + */ + if (!long_filenamew) { + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); } } else { /* We already have the long name of the file, so just use it. */ From 213e681acf82c427e221e1435a52f8f1682f44fc Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Wed, 9 Mar 2016 16:27:47 -0500 Subject: [PATCH 099/632] test: fix poll_bad_fdtype for AIX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/757 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- test/test-poll.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/test-poll.c b/test/test-poll.c index 524dfab49..f558ab1eb 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -565,10 +565,11 @@ 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 and Solaris so skip the test on those platforms. + * on FreeBSD, Solaris and AIX so skip the test on those platforms. */ TEST_IMPL(poll_bad_fdtype) { -#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) +#if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \ + !defined(_AIX) uv_poll_t poll_handle; int fd; From 42ebae18d6635251aeecff135ba506ca96881e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 10 Mar 2016 11:59:48 +0100 Subject: [PATCH 100/632] linux: fix error checking in uv__open_file uv__open_cloexec returns either the fd or a libuv error, which is -errno on Unix, not -1. PR-URL: https://github.com/libuv/libuv/pull/760 Reviewed-By: Colin Ihrig Reviewed-By: Fedor Indutny --- 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 5a8987e78..51318be8a 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -433,7 +433,7 @@ FILE* uv__open_file(const char* path) { FILE* fp; fd = uv__open_cloexec(path, O_RDONLY); - if (fd == -1) + if (fd < 0) return NULL; fp = fdopen(fd, "r"); From c7c8e916b86d2b168e97b04d7b4c8913322c8329 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 11 Jan 2016 23:00:57 +0100 Subject: [PATCH 101/632] poll: add UV_DISCONNECT event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It allows detecting the remote socket closing the connection. It's emitted when `EPOLLRDHUP`(Linux), `EV_EOF`(BSD), `POLLRDHUP`(Solaris, AIX) and `AFD_POLL_DISCONNECT`(Windows) events are received. PR-URL: https://github.com/libuv/libuv/pull/691 Reviewed-By: Ben Noordhuis Reviewed-By: Fedor Indutny Reviewed-By: Saúl Ibarra Corretgé --- docs/src/poll.rst | 17 ++++++++++++----- include/uv.h | 3 ++- src/unix/core.c | 8 ++++---- src/unix/internal.h | 22 ++++++++++++++-------- src/unix/kqueue.c | 3 +++ src/unix/linux-syscalls.h | 1 + src/unix/poll.c | 12 +++++++++--- src/win/poll.c | 15 +++++++++++++-- test/test-poll.c | 22 ++++++++++++++++------ 9 files changed, 74 insertions(+), 29 deletions(-) diff --git a/docs/src/poll.rst b/docs/src/poll.rst index 6dc41839a..69d45be6d 100644 --- a/docs/src/poll.rst +++ b/docs/src/poll.rst @@ -4,8 +4,8 @@ :c:type:`uv_poll_t` --- Poll handle =================================== -Poll handles are used to watch file descriptors for readability and -writability, similar to the purpose of :man:`poll(2)`. +Poll handles are used to watch file descriptors for readability, +writability and disconnection similar to the purpose of :man:`poll(2)`. The purpose of poll handles is to enable integrating external libraries that rely on the event loop to signal it about the socket status changes, like @@ -51,7 +51,8 @@ Data types enum uv_poll_event { UV_READABLE = 1, - UV_WRITABLE = 2 + UV_WRITABLE = 2, + UV_DISCONNECT = 4 }; @@ -82,10 +83,14 @@ API .. c:function:: int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) Starts polling the file descriptor. `events` is a bitmask consisting made up - of UV_READABLE and UV_WRITABLE. As soon as an event is detected the callback - will be called with `status` set to 0, and the detected events set on the + of UV_READABLE, UV_WRITABLE and UV_DISCONNECT. As soon as an event is detected + the callback will be called with `status` set to 0, and the detected events set on the `events` field. + The UV_DISCONNECT event is optional in the sense that it may not be + reported and the user is free to ignore it, but it can help optimize the shutdown + path because an extra read or write call might be avoided. + If an error happens while polling, `status` will be < 0 and corresponds 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 @@ -96,6 +101,8 @@ API Calling :c:func:`uv_poll_start` on a handle that is already active is fine. Doing so will update the events mask that is being watched for. + .. versionchanged:: 1.9.0 Added the UV_DISCONNECT event. + .. c:function:: int uv_poll_stop(uv_poll_t* poll) Stop polling the file descriptor, the callback will no longer be called. diff --git a/include/uv.h b/include/uv.h index 8d56a45e3..c8f42a27e 100644 --- a/include/uv.h +++ b/include/uv.h @@ -714,7 +714,8 @@ struct uv_poll_s { enum uv_poll_event { UV_READABLE = 1, - UV_WRITABLE = 2 + UV_WRITABLE = 2, + UV_DISCONNECT = 4 }; UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd); diff --git a/src/unix/core.c b/src/unix/core.c index 51318be8a..5820cc1c8 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -825,7 +825,7 @@ 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) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT))); + assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); @@ -858,7 +858,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT))); + assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); assert(0 != events); if (w->fd == -1) @@ -890,7 +890,7 @@ 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) { - uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT); + uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); QUEUE_REMOVE(&w->pending_queue); /* Remove stale events for this file descriptor */ @@ -905,7 +905,7 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { int uv__io_active(const uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT))); + assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); assert(0 != events); return 0 != (w->pevents & events); } diff --git a/src/unix/internal.h b/src/unix/internal.h index 79dab40ea..e4b98943f 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -90,17 +90,19 @@ #endif #if defined(__linux__) -# define UV__POLLIN UV__EPOLLIN -# define UV__POLLOUT UV__EPOLLOUT -# define UV__POLLERR UV__EPOLLERR -# define UV__POLLHUP UV__EPOLLHUP +# define UV__POLLIN UV__EPOLLIN +# define UV__POLLOUT UV__EPOLLOUT +# define UV__POLLERR UV__EPOLLERR +# define UV__POLLHUP UV__EPOLLHUP +# define UV__POLLRDHUP UV__EPOLLRDHUP #endif #if defined(__sun) || defined(_AIX) -# define UV__POLLIN POLLIN -# define UV__POLLOUT POLLOUT -# define UV__POLLERR POLLERR -# define UV__POLLHUP POLLHUP +# define UV__POLLIN POLLIN +# define UV__POLLOUT POLLOUT +# define UV__POLLERR POLLERR +# define UV__POLLHUP POLLHUP +# define UV__POLLRDHUP POLLRDHUP #endif #ifndef UV__POLLIN @@ -119,6 +121,10 @@ # define UV__POLLHUP 8 #endif +#ifndef UV__POLLRDHUP +# define UV__POLLRDHUP 0x200 +#endif + #if !defined(O_CLOEXEC) && defined(__FreeBSD__) /* * It may be that we are just missing `__POSIX_VISIBLE >= 200809`. diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index b054b4a8c..400b4a4b7 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -259,6 +259,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (ev->flags & EV_ERROR) revents |= UV__POLLERR; + if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) + revents |= UV__POLLRDHUP; + if (revents == 0) continue; diff --git a/src/unix/linux-syscalls.h b/src/unix/linux-syscalls.h index 96e79439c..4260df111 100644 --- a/src/unix/linux-syscalls.h +++ b/src/unix/linux-syscalls.h @@ -76,6 +76,7 @@ #define UV__EPOLLOUT 4 #define UV__EPOLLERR 8 #define UV__EPOLLHUP 16 +#define UV__EPOLLRDHUP 0x2000 #define UV__EPOLLONESHOT 0x40000000 #define UV__EPOLLET 0x80000000 diff --git a/src/unix/poll.c b/src/unix/poll.c index e8091dcc0..e5efb1716 100644 --- a/src/unix/poll.c +++ b/src/unix/poll.c @@ -34,7 +34,7 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { handle = container_of(w, uv_poll_t, io_watcher); if (events & UV__POLLERR) { - uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT); + uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); uv__handle_stop(handle); handle->poll_cb(handle, -EBADF, 0); return; @@ -45,6 +45,8 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { pevents |= UV_READABLE; if (events & UV__POLLOUT) pevents |= UV_WRITABLE; + if (events & UV__POLLRDHUP) + pevents |= UV_DISCONNECT; handle->poll_cb(handle, 0, pevents); } @@ -75,7 +77,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, static void uv__poll_stop(uv_poll_t* handle) { - uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT); + uv__io_stop(handle->loop, + &handle->io_watcher, + UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); uv__handle_stop(handle); } @@ -90,7 +94,7 @@ int uv_poll_stop(uv_poll_t* handle) { int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { int events; - assert((pevents & ~(UV_READABLE | UV_WRITABLE)) == 0); + assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); uv__poll_stop(handle); @@ -103,6 +107,8 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { events |= UV__POLLIN; if (pevents & UV_WRITABLE) events |= UV__POLLOUT; + if (pevents & UV_DISCONNECT) + events |= UV__POLLRDHUP; uv__io_start(handle->loop, &handle->io_watcher, events); uv__handle_start(handle); diff --git a/src/win/poll.c b/src/win/poll.c index ce861d6ff..d479e521e 100644 --- a/src/win/poll.c +++ b/src/win/poll.c @@ -91,7 +91,11 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { handle->mask_events_1 = handle->events; handle->mask_events_2 = 0; } else { - assert(0); + /* Just wait until there's an unsubmitted req. */ + /* This will happen almost immediately as one of the 2 outstanding */ + /* requests is about to return. When this happens, */ + /* uv__fast_poll_process_poll_req will be called, and the pending */ + /* events, if needed, will be processed in a subsequent request. */ return; } @@ -107,6 +111,10 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { if (handle->events & UV_READABLE) { afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE | AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT; + } else { + if (handle->events & UV_DISCONNECT) { + afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT; + } } if (handle->events & UV_WRITABLE) { afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL; @@ -184,6 +192,9 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE | AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) { events |= UV_READABLE; + if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) { + events |= UV_DISCONNECT; + } } if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL)) != 0) { @@ -218,7 +229,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { assert(handle->type == UV_POLL); assert(!(handle->flags & UV__HANDLE_CLOSING)); - assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); + assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); handle->events = events; diff --git a/test/test-poll.c b/test/test-poll.c index f558ab1eb..bfb75af13 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -51,7 +51,7 @@ typedef struct connection_context_s { size_t read, sent; int is_server_connection; int open_handles; - int got_fin, sent_fin; + int got_fin, sent_fin, got_disconnect; unsigned int events, delayed_events; } connection_context_t; @@ -72,6 +72,8 @@ static int closed_connections = 0; static int valid_writable_wakeups = 0; static int spurious_writable_wakeups = 0; +static int disconnects = 0; + static int got_eagain(void) { #ifdef _WIN32 @@ -142,6 +144,7 @@ static connection_context_t* create_connection_context( context->delayed_events = 0; context->got_fin = 0; context->sent_fin = 0; + context->got_disconnect = 0; r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock); context->open_handles++; @@ -375,7 +378,13 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { } } - if (context->got_fin && context->sent_fin) { + if (events & UV_DISCONNECT) { + context->got_disconnect = 1; + ++disconnects; + new_events &= ~UV_DISCONNECT; + } + + if (context->got_fin && context->sent_fin && context->got_disconnect) { /* Sent and received FIN. Close and destroy context. */ close_socket(context->sock); destroy_connection_context(context); @@ -463,9 +472,9 @@ static void server_poll_cb(uv_poll_t* handle, int status, int events) { #endif connection_context = create_connection_context(sock, 1); - connection_context->events = UV_READABLE | UV_WRITABLE; + connection_context->events = UV_READABLE | UV_WRITABLE | UV_DISCONNECT; r = uv_poll_start(&connection_context->poll_handle, - UV_READABLE | UV_WRITABLE, + UV_READABLE | UV_WRITABLE | UV_DISCONNECT, connection_poll_cb); ASSERT(r == 0); @@ -507,9 +516,9 @@ static void start_client(void) { sock = create_bound_socket(addr); context = create_connection_context(sock, 0); - context->events = UV_READABLE | UV_WRITABLE; + context->events = UV_READABLE | UV_WRITABLE | UV_DISCONNECT; r = uv_poll_start(&context->poll_handle, - UV_READABLE | UV_WRITABLE, + UV_READABLE | UV_WRITABLE | UV_DISCONNECT, connection_poll_cb); ASSERT(r == 0); @@ -543,6 +552,7 @@ static void start_poll_test(void) { spurious_writable_wakeups > 20); ASSERT(closed_connections == NUM_CLIENTS * 2); + ASSERT(disconnects == NUM_CLIENTS * 2); MAKE_VALGRIND_HAPPY(); } From 5dc15cc26956b981b2c4fa6b6b0799e5922cf1d1 Mon Sep 17 00:00:00 2001 From: Yuval Brik Date: Sat, 20 Feb 2016 17:42:39 +0200 Subject: [PATCH 102/632] fs: realpath: fix string size before converting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fs__realpath_handle() removes the UNC prefixes \\?\ and \\?\UNC\ from paths returned by GetFinalPathNameByHandle, but doesn't update the string length before sending it to fs__wide_to_utf8. Fix that by decrement the correct size from the string length. PR-URL: https://github.com/libuv/libuv/pull/733 Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index a32b0127f..16e3ae7cf 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1717,25 +1717,26 @@ static void fs__readlink(uv_fs_t* req) { static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { int r; DWORD w_realpath_len; - WCHAR* w_realpath_ptr; - WCHAR* w_finalpath_ptr = NULL; + WCHAR* w_realpath_ptr = NULL; + WCHAR* w_realpath_buf; w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); if (w_realpath_len == 0) { return -1; } - w_realpath_ptr = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); - if (w_realpath_ptr == NULL) { + w_realpath_buf = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); + if (w_realpath_buf == NULL) { SetLastError(ERROR_OUTOFMEMORY); return -1; } + w_realpath_ptr = w_realpath_buf; if (pGetFinalPathNameByHandleW(handle, w_realpath_ptr, w_realpath_len, VOLUME_NAME_DOS) == 0) { - uv__free(w_realpath_ptr); + uv__free(w_realpath_buf); SetLastError(ERROR_INVALID_HANDLE); return -1; } @@ -1744,20 +1745,22 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { if (wcsncmp(w_realpath_ptr, UNC_PATH_PREFIX, UNC_PATH_PREFIX_LEN) == 0) { - w_finalpath_ptr = w_realpath_ptr + 6; - *w_finalpath_ptr = L'\\'; + w_realpath_ptr += 6; + *w_realpath_ptr = L'\\'; + w_realpath_len -= 6; } else if (wcsncmp(w_realpath_ptr, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0) { - w_finalpath_ptr = w_realpath_ptr + 4; + w_realpath_ptr += 4; + w_realpath_len -= 4; } else { - uv__free(w_realpath_ptr); + uv__free(w_realpath_buf); SetLastError(ERROR_INVALID_HANDLE); return -1; } - r = fs__wide_to_utf8(w_finalpath_ptr, w_realpath_len, realpath_ptr, NULL); - uv__free(w_realpath_ptr); + r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL); + uv__free(w_realpath_buf); return r; } From f04d5fc3b98cfa6699b9d0b2dedda84a14689761 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 14 Mar 2016 11:35:46 -0400 Subject: [PATCH 103/632] win: use native APIs for UTF conversions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit replaces uv_utf16_to_utf8() and uv_utf8_to_utf16() with calls to the native Windows API equivalents. Refs: https://github.com/libuv/libuv/pull/672#discussion_r49049746 PR-URL: https://github.com/libuv/libuv/pull/762 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- include/uv-win.h | 5 ---- src/win/dl.c | 7 ++++- src/win/fs-event.c | 36 +++++++++++++++++-------- src/win/getaddrinfo.c | 61 +++++++++++++++++++++++++++++++------------ src/win/pipe.c | 18 ++++++++++--- src/win/util.c | 50 ++++++++++++++--------------------- 6 files changed, 109 insertions(+), 68 deletions(-) diff --git a/include/uv-win.h b/include/uv-win.h index 300be4762..6b537fed0 100644 --- a/include/uv-win.h +++ b/include/uv-win.h @@ -634,11 +634,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); struct uv_req_s signal_req; \ unsigned long pending_signum; -int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size, - char* utf8Buffer, size_t utf8Size); -int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer, - size_t utf16Size); - #ifndef F_OK #define F_OK 0 #endif diff --git a/src/win/dl.c b/src/win/dl.c index e5f3407f8..39e400ab2 100644 --- a/src/win/dl.c +++ b/src/win/dl.c @@ -31,7 +31,12 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) { lib->handle = NULL; lib->errmsg = NULL; - if (!uv_utf8_to_utf16(filename, filename_w, ARRAY_SIZE(filename_w))) { + if (!MultiByteToWideChar(CP_UTF8, + 0, + filename, + -1, + filename_w, + ARRAY_SIZE(filename_w))) { return uv__dlerror(lib, GetLastError()); } diff --git a/src/win/fs-event.c b/src/win/fs-event.c index e774ab958..52c24a40c 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -159,14 +159,20 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv__handle_start(handle); /* Convert name to UTF16. */ - name_size = uv_utf8_to_utf16(path, NULL, 0) * sizeof(WCHAR); + + 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 (!uv_utf8_to_utf16(path, pathw, - name_size / sizeof(WCHAR))) { + if (!MultiByteToWideChar(CP_UTF8, + 0, + path, + -1, + pathw, + name_size / sizeof(WCHAR))) { return uv_translate_sys_error(GetLastError()); } @@ -455,20 +461,28 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, if (filenamew) { /* Convert the filename to utf8. */ - size = uv_utf16_to_utf8(filenamew, - sizew, - NULL, - 0); + size = WideCharToMultiByte(CP_UTF8, + 0, + filenamew, + sizew, + NULL, + 0, + NULL, + NULL); if (size) { filename = (char*)uv__malloc(size + 1); if (!filename) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - size = uv_utf16_to_utf8(filenamew, - sizew, - filename, - size); + size = WideCharToMultiByte(CP_UTF8, + 0, + filenamew, + sizew, + filename, + size, + NULL, + NULL); if (size) { filename[size] = '\0'; } else { diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index ceed3b763..744f8e026 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -126,7 +126,14 @@ 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 = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0); + 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()); goto complete; @@ -170,16 +177,24 @@ 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 = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, - -1, - NULL, - 0); + 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 = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, - -1, - cur_ptr, - name_len); + name_len = WideCharToMultiByte(CP_UTF8, + 0, + addrinfow_ptr->ai_canonname, + -1, + cur_ptr, + name_len, + NULL, + NULL); assert(name_len > 0); addrinfo_ptr->ai_canonname = cur_ptr; cur_ptr += ALIGNED_SIZE(name_len); @@ -261,7 +276,8 @@ int uv_getaddrinfo(uv_loop_t* loop, /* calculate required memory size for all input values */ if (node != NULL) { - nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(WCHAR)); + nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) * + sizeof(WCHAR)); if (nodesize == 0) { err = GetLastError(); goto error; @@ -269,7 +285,12 @@ int uv_getaddrinfo(uv_loop_t* loop, } if (service != NULL) { - servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) * + servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + NULL, + 0) * sizeof(WCHAR)); if (servicesize == 0) { err = GetLastError(); @@ -294,9 +315,12 @@ int uv_getaddrinfo(uv_loop_t* loop, /* the request. */ if (node != NULL) { req->node = (WCHAR*)alloc_ptr; - if (uv_utf8_to_utf16(node, - (WCHAR*) alloc_ptr, - nodesize / sizeof(WCHAR)) == 0) { + if (MultiByteToWideChar(CP_UTF8, + 0, + node, + -1, + (WCHAR*) alloc_ptr, + nodesize / sizeof(WCHAR)) == 0) { err = GetLastError(); goto error; } @@ -309,9 +333,12 @@ int uv_getaddrinfo(uv_loop_t* loop, /* in the req. */ if (service != NULL) { req->service = (WCHAR*)alloc_ptr; - if (uv_utf8_to_utf16(service, - (WCHAR*) alloc_ptr, - servicesize / sizeof(WCHAR)) == 0) { + if (MultiByteToWideChar(CP_UTF8, + 0, + service, + -1, + (WCHAR*) alloc_ptr, + servicesize / sizeof(WCHAR)) == 0) { err = GetLastError(); goto error; } diff --git a/src/win/pipe.c b/src/win/pipe.c index d42bbfec3..a784325c5 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -513,13 +513,18 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { } /* Convert name to UTF16. */ - nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); handle->name = (WCHAR*)uv__malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + handle->name, + nameSize / sizeof(WCHAR))) { err = GetLastError(); goto error; } @@ -627,13 +632,18 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, req->cb = cb; /* Convert name to UTF16. */ - nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); + nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); handle->name = (WCHAR*)uv__malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { + if (!MultiByteToWideChar(CP_UTF8, + 0, + name, + -1, + handle->name, + nameSize / sizeof(WCHAR))) { err = GetLastError(); goto error; } diff --git a/src/win/util.c b/src/win/util.c index 8cfbd86f3..6949a56bd 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -87,30 +87,6 @@ void uv__util_init() { } -int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size, - char* utf8Buffer, size_t utf8Size) { - return WideCharToMultiByte(CP_UTF8, - 0, - utf16Buffer, - utf16Size, - utf8Buffer, - utf8Size, - NULL, - NULL); -} - - -int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer, - size_t utf16Size) { - return MultiByteToWideChar(CP_UTF8, - 0, - utf8Buffer, - -1, - utf16Buffer, - utf16Size); -} - - int uv_exepath(char* buffer, size_t* size_ptr) { int utf8_len, utf16_buffer_len, utf16_len; WCHAR* utf16_buffer; @@ -384,7 +360,7 @@ 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 = uv_utf8_to_utf16(title, NULL, 0); + length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0); if (!length) { err = GetLastError(); goto done; @@ -396,7 +372,7 @@ int uv_set_process_title(const char* title) { uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); } - length = uv_utf8_to_utf16(title, title_w, length); + length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length); if (!length) { err = GetLastError(); goto done; @@ -434,7 +410,7 @@ static int uv__get_process_title() { } /* Find out what the size of the buffer is that we need */ - length = uv_utf16_to_utf8(title_w, -1, NULL, 0); + length = WideCharToMultiByte(CP_UTF8, 0, title_w, -1, NULL, 0, NULL, NULL); if (!length) { return -1; } @@ -446,7 +422,14 @@ static int uv__get_process_title() { } /* Do utf16 -> utf8 conversion here */ - if (!uv_utf16_to_utf8(title_w, -1, process_title, length)) { + if (!WideCharToMultiByte(CP_UTF8, + 0, + title_w, + -1, + process_title, + length, + NULL, + NULL)) { uv__free(process_title); return -1; } @@ -1214,7 +1197,7 @@ int uv_os_homedir(char* buffer, size_t* size) { convert_buffer: /* Check how much space we need */ - bufsize = uv_utf16_to_utf8(path, -1, NULL, 0); + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); if (bufsize == 0) { return uv_translate_sys_error(GetLastError()); } else if (bufsize > *size) { @@ -1223,7 +1206,14 @@ int uv_os_homedir(char* buffer, size_t* size) { } /* Convert to UTF-8 */ - bufsize = uv_utf16_to_utf8(path, -1, buffer, *size); + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); if (bufsize == 0) return uv_translate_sys_error(GetLastError()); From df961637027df4093aaad5faab16a617ab13b335 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 16 Mar 2016 10:15:27 +0100 Subject: [PATCH 104/632] doc: clarify uv_loop_close() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make explicit that handles and requests should be closed before calling uv_loop_close(). Fixes: https://github.com/libuv/libuv/issues/765 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- docs/src/loop.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/src/loop.rst b/docs/src/loop.rst index 2a01d7963..1f504cb39 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -71,9 +71,10 @@ API .. c:function:: int uv_loop_close(uv_loop_t* loop) - Closes all internal loop resources. This function must only be called once - the loop has finished its execution or it will return UV_EBUSY. After this - function returns the user shall free the memory allocated for the loop. + Releases all internal loop resources. Call this function only when the loop + has finished executing and all open handles and requests have been closed, + or it will return UV_EBUSY. After this function returns, the user can free + the memory allocated for the loop. .. c:function:: uv_loop_t* uv_default_loop(void) From b12624c13693c4d29ca84b3556eadc9e9c0936a4 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 20 Mar 2016 11:49:46 +0100 Subject: [PATCH 105/632] unix: retry ioctl(TIOCGWINSZ) on EINTR Some platforms (notably Solaris) can fail in this ioctl() if interrupted by a signal. Retry the system call when that happens. Fixes: https://github.com/nodejs/node/issues/5737 PR-URL: https://github.com/libuv/libuv/pull/772 Reviewed-By: Colin Ihrig --- src/unix/tty.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/unix/tty.c b/src/unix/tty.c index 7cc5b714e..02164f9dc 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -185,8 +185,13 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { struct winsize ws; + int err; + + do + err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws); + while (err == -1 && errno == EINTR); - if (ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws)) + if (err == -1) return -errno; *width = ws.ws_col; From 60db5b5a1bb446e4b8a6d15ce277d5f7987bf07a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 23 Mar 2016 12:43:18 +0100 Subject: [PATCH 106/632] win,build: remove unused build defines PR-URL: https://github.com/libuv/libuv/pull/777 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- Makefile.am | 1 - Makefile.mingw | 1 - 2 files changed, 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index a0de6f560..4811fb36a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,7 +43,6 @@ if WINNT include_HEADERS += include/uv-win.h include/tree.h AM_CPPFLAGS += -I$(top_srcdir)/src/win \ - -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv libuv_la_SOURCES += src/win/async.c \ diff --git a/Makefile.mingw b/Makefile.mingw index 156f15dab..3130bac47 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -20,7 +20,6 @@ CFLAGS += -Wall \ -Iinclude \ -Isrc \ -Isrc/win \ - -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 INCLUDES = include/stdint-msvc2008.h \ From b44abe20ef359aff1d0054fbf69c240642bf0bf1 Mon Sep 17 00:00:00 2001 From: Joran Dirk Greef Date: Tue, 26 Jan 2016 12:21:52 +0200 Subject: [PATCH 107/632] win: fix buffer overflow in fs events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When converting an absolute path to a relative path on Windows, uv_relative_path assumed that the relative path could be no longer than MAX_PATH characters, and would allocate a buffer of MAX_PATH characters for the relative path. However, where a recursive watch is started for a directory using a UNC path, and where events within that directory occur for pathnames longer than MAX_PATH, it is possible for the relative path to exceed MAX_PATH characters and overflow the buffer. This commit fixes uv_relative_path to allocate a buffer for the exact number of characters counted in the relative path. Fixes: https://github.com/libuv/libuv/issues/693 PR-URL: https://github.com/libuv/libuv/pull/699 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs-event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 52c24a40c..bb1a2bc15 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -70,7 +70,7 @@ static int uv_relative_path(const WCHAR* filename, int filelen = wcslen(filename); if (dir[dirlen - 1] == '\\') dirlen--; - *relpath = uv__malloc((MAX_PATH + 1) * sizeof(WCHAR)); + *relpath = uv__malloc((filelen - dirlen - 1 + 1) * sizeof(WCHAR)); if (!*relpath) uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); wcsncpy(*relpath, filename + dirlen + 1, filelen - dirlen - 1); From 757e3c60716aa16850da57569a800e31907d2ec2 Mon Sep 17 00:00:00 2001 From: Joran Dirk Greef Date: Tue, 26 Jan 2016 14:04:26 +0200 Subject: [PATCH 108/632] win: fix uv_relative_path and remove dead branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wcslen() returns a size_t, not an int. Add bounds checking to dirlen to avoid undefined if dirlen is 0. Cache relpath size calculation to replace redundant (- 1 + 1) expression while still showing workings. Change uv_relative_path return type to void and remove dead code which branched on the return value. PR-URL: https://github.com/libuv/libuv/pull/699 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs-event.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index bb1a2bc15..77c935a2d 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -63,19 +63,19 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, handle->req_pending = 1; } -static int uv_relative_path(const WCHAR* filename, - const WCHAR* dir, - WCHAR** relpath) { - int dirlen = wcslen(dir); - int filelen = wcslen(filename); - if (dir[dirlen - 1] == '\\') +static void uv_relative_path(const WCHAR* filename, + const WCHAR* dir, + WCHAR** relpath) { + size_t dirlen = wcslen(dir); + if (dirlen > 0 && dir[dirlen - 1] == '\\') dirlen--; - *relpath = uv__malloc((filelen - dirlen - 1 + 1) * sizeof(WCHAR)); + size_t filenamelen = wcslen(filename); + size_t relpathlen = filenamelen - dirlen - 1; + *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR)); if (!*relpath) uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - wcsncpy(*relpath, filename + dirlen + 1, filelen - dirlen - 1); - (*relpath)[filelen - dirlen - 1] = L'\0'; - return 0; + wcsncpy(*relpath, filename + dirlen + 1, relpathlen); + (*relpath)[relpathlen] = L'\0'; } static int uv_split_path(const WCHAR* filename, WCHAR** dir, @@ -346,7 +346,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { 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, result; + int err, sizew, size; char* filename = NULL; WCHAR* filenamew, *long_filenamew = NULL; DWORD offset = 0; @@ -431,17 +431,12 @@ 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. */ - result = uv_relative_path(long_filenamew, - handle->dirw, - &filenamew); + uv_relative_path(long_filenamew, + handle->dirw, + &filenamew); uv__free(long_filenamew); - - if (result == 0) { - long_filenamew = filenamew; - sizew = -1; - } else { - long_filenamew = NULL; - } + long_filenamew = filenamew; + sizew = -1; } } /* From 02709a947f6db046e8d1808b768260c1afbb0079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A1ri=20Tristan=20Helgason?= Date: Mon, 7 Mar 2016 22:38:43 +0000 Subject: [PATCH 109/632] unix: use open(2) with O_CLOEXEC on OS X MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/753 Reviewed-By: Saúl Ibarra Corretgé --- 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 5820cc1c8..bfd2bb07d 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -53,6 +53,9 @@ # include /* _NSGetExecutablePath */ # include # include +# if defined(O_CLOEXEC) +# define UV__O_CLOEXEC O_CLOEXEC +# endif #endif #if defined(__FreeBSD__) || defined(__DragonFly__) @@ -946,8 +949,7 @@ int uv__open_cloexec(const char* path, int flags) { int err; int fd; -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9) || \ - defined(__DragonFly__) +#if defined(UV__O_CLOEXEC) static int no_cloexec; if (!no_cloexec) { From 13f4dc82887fa0e235e26265b53b949b50066dc3 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 24 Mar 2016 11:06:11 -0400 Subject: [PATCH 110/632] test: add missing copyright header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds the copyright header to the two tests that were missing it. PR-URL: https://github.com/libuv/libuv/pull/782 Reviewed-By: Saúl Ibarra Corretgé --- test/test-homedir.c | 21 +++++++++++++++++++++ test/test-tmpdir.c | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/test/test-homedir.c b/test/test-homedir.c index cbc47566c..5027d44c1 100644 --- a/test/test-homedir.c +++ b/test/test-homedir.c @@ -1,3 +1,24 @@ +/* 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 diff --git a/test/test-tmpdir.c b/test/test-tmpdir.c index bbc8ba73c..29e8055f1 100644 --- a/test/test-tmpdir.c +++ b/test/test-tmpdir.c @@ -1,3 +1,24 @@ +/* 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 From 27aa81fe5a19940d2f39f902c1bede814d49bbb6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 25 Mar 2016 12:14:31 +0100 Subject: [PATCH 111/632] aix: fix 'POLLRDHUP undeclared' build error AIX doesn't have POLLRDHUP. Fixes the following compile-time error: src/unix/core.c: In function 'uv__io_start': src/unix/core.c:831:40: error: 'POLLRDHUP' undeclared assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); Fixes: https://github.com/libuv/libuv/issues/783 PR-URL: https://github.com/libuv/libuv/pull/785 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/unix/internal.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/unix/internal.h b/src/unix/internal.h index e4b98943f..2f9f7e983 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -102,7 +102,6 @@ # define UV__POLLOUT POLLOUT # define UV__POLLERR POLLERR # define UV__POLLHUP POLLHUP -# define UV__POLLRDHUP POLLRDHUP #endif #ifndef UV__POLLIN @@ -122,7 +121,11 @@ #endif #ifndef UV__POLLRDHUP -# define UV__POLLRDHUP 0x200 +# ifdef POLLRDHUP +# define UV__POLLRDHUP POLLRDHUP +# else +# define UV__POLLRDHUP 0x200 +# endif #endif #if !defined(O_CLOEXEC) && defined(__FreeBSD__) From 217f81b6a18f52322ddfdaf704e9057005e3d10d Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 1 Mar 2016 15:41:01 -0500 Subject: [PATCH 112/632] unix,win: add uv_get_passwd() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds the uv_get_passwd() function, which returns a subset of the current effective user's password file entry. Refs: https://github.com/libuv/libuv/issues/11 Fixes: https://github.com/libuv/libuv/issues/731 PR-URL: https://github.com/libuv/libuv/pull/742 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 1 + checksparse.sh | 1 + docs/src/misc.rst | 32 ++++++ include/uv.h | 11 +++ src/unix/core.c | 168 ++++++++++++++++++++++---------- src/unix/internal.h | 1 + src/win/internal.h | 2 + src/win/util.c | 187 +++++++++++++++++++++++++++++------- test/test-get-passwd.c | 80 +++++++++++++++ test/test-list.h | 3 + test/test-platform-output.c | 11 +++ uv.gyp | 1 + 12 files changed, 413 insertions(+), 85 deletions(-) create mode 100644 test/test-get-passwd.c diff --git a/Makefile.am b/Makefile.am index 4811fb36a..625f02515 100644 --- a/Makefile.am +++ b/Makefile.am @@ -161,6 +161,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-get-currentexe.c \ test/test-get-loadavg.c \ test/test-get-memory.c \ + test/test-get-passwd.c \ test/test-getaddrinfo.c \ test/test-getnameinfo.c \ test/test-getsockname.c \ diff --git a/checksparse.sh b/checksparse.sh index dbaa45749..68e3bde39 100755 --- a/checksparse.sh +++ b/checksparse.sh @@ -101,6 +101,7 @@ test/test-fs.c test/test-get-currentexe.c test/test-get-loadavg.c test/test-get-memory.c +test/test-get-passwd.c test/test-getaddrinfo.c test/test-getsockname.c test/test-homedir.c diff --git a/docs/src/misc.rst b/docs/src/misc.rst index ebcb75a28..f32af48ff 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -122,6 +122,20 @@ Data types } netmask; } uv_interface_address_t; +.. c:type:: uv_passwd_t + + Data type for password file information. + + :: + + typedef struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; + } uv_passwd_t; + API --- @@ -291,6 +305,24 @@ API .. versionadded:: 1.9.0 +.. c:function:: int uv_os_get_passwd(uv_passwd_t* pwd) + + Gets a subset of the password file entry for the current effective uid (not + the real 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.9.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`. + + .. versionadded:: 1.9.0 + .. uint64_t uv_get_free_memory(void) .. c:function:: uint64_t uv_get_total_memory(void) diff --git a/include/uv.h b/include/uv.h index c8f42a27e..baa0b2812 100644 --- a/include/uv.h +++ b/include/uv.h @@ -230,6 +230,7 @@ typedef struct uv_work_s uv_work_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 enum { UV_LOOP_BLOCK_SIGNAL @@ -1001,6 +1002,14 @@ struct uv_interface_address_s { } netmask; }; +struct uv_passwd_s { + char* username; + long uid; + long gid; + char* shell; + char* homedir; +}; + typedef enum { UV_DIRENT_UNKNOWN, UV_DIRENT_FILE, @@ -1051,6 +1060,8 @@ UV_EXTERN int uv_getrusage(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); +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_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 bfd2bb07d..b7f7c25f4 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1032,17 +1032,10 @@ int uv__dup2_cloexec(int oldfd, int newfd) { int uv_os_homedir(char* buffer, size_t* size) { - struct passwd pw; - struct passwd* result; + uv_passwd_t pwd; char* buf; - uid_t uid; - size_t bufsize; size_t len; - long initsize; int r; -#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 - int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); -#endif if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; @@ -1064,59 +1057,24 @@ int uv_os_homedir(char* buffer, size_t* size) { return 0; } -#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 - getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); - if (getpwuid_r == NULL) - return -ENOSYS; -#endif - - /* HOME is not set, so call getpwuid() */ - initsize = sysconf(_SC_GETPW_R_SIZE_MAX); - - if (initsize <= 0) - bufsize = 4096; - else - bufsize = (size_t) initsize; - - uid = getuid(); - buf = NULL; - - for (;;) { - uv__free(buf); - buf = uv__malloc(bufsize); - - if (buf == NULL) - return -ENOMEM; - - r = getpwuid_r(uid, &pw, buf, bufsize, &result); - - if (r != ERANGE) - break; - - bufsize *= 2; - } + /* HOME is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); if (r != 0) { - uv__free(buf); - return -r; - } - - if (result == NULL) { - uv__free(buf); - return -ENOENT; + return r; } - len = strlen(pw.pw_dir); + len = strlen(pwd.homedir); if (len >= *size) { *size = len + 1; - uv__free(buf); + uv_os_free_passwd(&pwd); return -ENOBUFS; } - memcpy(buffer, pw.pw_dir, len + 1); + memcpy(buffer, pwd.homedir, len + 1); *size = len; - uv__free(buf); + uv_os_free_passwd(&pwd); return 0; } @@ -1171,3 +1129,113 @@ int uv_os_tmpdir(char* buffer, size_t* size) { return 0; } + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + struct passwd pw; + struct passwd* result; + char* buf; + uid_t uid; + size_t bufsize; + size_t name_size; + size_t homedir_size; + size_t shell_size; + long initsize; + int r; +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); + + getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); + if (getpwuid_r == NULL) + return -ENOSYS; +#endif + + if (pwd == NULL) + return -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); + buf = uv__malloc(bufsize); + + if (buf == NULL) + return -ENOMEM; + + r = getpwuid_r(uid, &pw, buf, bufsize, &result); + + if (r != ERANGE) + break; + + bufsize *= 2; + } + + if (r != 0) { + uv__free(buf); + return -r; + } + + if (result == NULL) { + uv__free(buf); + return -ENOENT; + } + + /* Allocate memory for the username, shell, and home directory */ + name_size = strlen(pw.pw_name) + 1; + homedir_size = strlen(pw.pw_dir) + 1; + shell_size = strlen(pw.pw_shell) + 1; + pwd->username = uv__malloc(name_size + homedir_size + shell_size); + + if (pwd->username == NULL) { + uv__free(buf); + return -ENOMEM; + } + + /* Copy the username */ + memcpy(pwd->username, pw.pw_name, name_size); + + /* Copy the home directory */ + pwd->homedir = pwd->username + name_size; + memcpy(pwd->homedir, pw.pw_dir, homedir_size); + + /* Copy the shell */ + pwd->shell = pwd->homedir + homedir_size; + memcpy(pwd->shell, pw.pw_shell, shell_size); + + /* Copy the uid and gid */ + pwd->uid = pw.pw_uid; + pwd->gid = pw.pw_gid; + + uv__free(buf); + + return 0; +} + + +void uv_os_free_passwd(uv_passwd_t* pwd) { + if (pwd == NULL) + return; + + /* + 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; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} diff --git a/src/unix/internal.h b/src/unix/internal.h index 2f9f7e983..328c66328 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -257,6 +257,7 @@ 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); #if defined(__APPLE__) diff --git a/src/win/internal.h b/src/win/internal.h index b2b929be5..c724793bf 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -328,6 +328,8 @@ uint64_t uv__hrtime(double scale); int uv_parent_pid(); int uv_current_pid(); __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, char** utf8); /* diff --git a/src/win/util.c b/src/win/util.c index 6949a56bd..1788b1780 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1152,7 +1152,7 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { int uv_os_homedir(char* buffer, size_t* size) { - HANDLE token; + uv_passwd_t pwd; wchar_t path[MAX_PATH]; DWORD bufsize; size_t len; @@ -1166,6 +1166,7 @@ int uv_os_homedir(char* buffer, size_t* size) { if (len == 0) { r = GetLastError(); + /* Don't return an error if USERPROFILE was not found */ if (r != ERROR_ENVVAR_NOT_FOUND) return uv_translate_sys_error(r); @@ -1173,51 +1174,52 @@ int uv_os_homedir(char* buffer, size_t* size) { /* This should not be possible */ return UV_EIO; } else { - goto convert_buffer; - } - - /* USERPROFILE is not set, so call GetUserProfileDirectoryW() */ - if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) - return uv_translate_sys_error(GetLastError()); + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); - bufsize = MAX_PATH; - if (!GetUserProfileDirectoryW(token, path, &bufsize)) { - r = GetLastError(); - CloseHandle(token); + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize; + return UV_ENOBUFS; + } - /* This should not be possible */ - if (r == ERROR_INSUFFICIENT_BUFFER) - return UV_EIO; + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); - return uv_translate_sys_error(r); + *size = bufsize - 1; + return 0; } - CloseHandle(token); + /* USERPROFILE is not set, so call uv__getpwuid_r() */ + r = uv__getpwuid_r(&pwd); -convert_buffer: + if (r != 0) { + return r; + } - /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); - if (bufsize == 0) { - return uv_translate_sys_error(GetLastError()); - } else if (bufsize > *size) { - *size = bufsize; + len = strlen(pwd.homedir); + + if (len >= *size) { + *size = len + 1; + uv_os_free_passwd(&pwd); return UV_ENOBUFS; } - /* Convert to UTF-8 */ - bufsize = WideCharToMultiByte(CP_UTF8, - 0, - path, - -1, - buffer, - *size, - NULL, - NULL); - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); + memcpy(buffer, pwd.homedir, len + 1); + *size = len; + uv_os_free_passwd(&pwd); - *size = bufsize - 1; return 0; } @@ -1273,3 +1275,118 @@ int uv_os_tmpdir(char* buffer, size_t* size) { *size = bufsize - 1; return 0; } + + +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; +} + + +int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) { + DWORD bufsize; + + if (utf16 == NULL) + return UV_EINVAL; + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + /* Allocate the destination buffer */ + *utf8 = uv__malloc(bufsize); + + if (*utf8 == NULL) + return UV_ENOMEM; + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + -1, + *utf8, + bufsize, + NULL, + NULL); + + if (bufsize == 0) { + uv__free(*utf8); + return uv_translate_sys_error(GetLastError()); + } + + return 0; +} + + +int uv__getpwuid_r(uv_passwd_t* pwd) { + HANDLE token; + wchar_t username[UNLEN + 1]; + wchar_t path[MAX_PATH]; + DWORD bufsize; + int r; + + if (pwd == NULL) + return UV_EINVAL; + + /* Get the home directory using GetUserProfileDirectoryW() */ + if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) + return uv_translate_sys_error(GetLastError()); + + bufsize = sizeof(path); + if (!GetUserProfileDirectoryW(token, path, &bufsize)) { + r = GetLastError(); + CloseHandle(token); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + CloseHandle(token); + + /* Get the username using GetUserNameW() */ + bufsize = sizeof(username); + if (!GetUserNameW(username, &bufsize)) { + r = GetLastError(); + + /* This should not be possible */ + if (r == ERROR_INSUFFICIENT_BUFFER) + return UV_ENOMEM; + + return uv_translate_sys_error(r); + } + + pwd->homedir = NULL; + r = uv__convert_utf16_to_utf8(path, &pwd->homedir); + + if (r != 0) + return r; + + pwd->username = NULL; + r = uv__convert_utf16_to_utf8(username, &pwd->username); + + if (r != 0) { + uv__free(pwd->homedir); + return r; + } + + pwd->shell = NULL; + pwd->uid = -1; + pwd->gid = -1; + + return 0; +} + + +int uv_os_get_passwd(uv_passwd_t* pwd) { + return uv__getpwuid_r(pwd); +} diff --git a/test/test-get-passwd.c b/test/test-get-passwd.c new file mode 100644 index 000000000..58d9c73c6 --- /dev/null +++ b/test/test-get-passwd.c @@ -0,0 +1,80 @@ +/* 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 + +TEST_IMPL(get_passwd) { + uv_passwd_t pwd; + size_t len; + int r; + + /* Test the normal case */ + r = uv_os_get_passwd(&pwd); + ASSERT(r == 0); + len = strlen(pwd.username); + ASSERT(len > 0); + +#ifdef _WIN32 + ASSERT(pwd.shell == NULL); +#else + len = strlen(pwd.shell); + ASSERT(len > 0); +#endif + + len = strlen(pwd.homedir); + ASSERT(len > 0); + +#ifdef _WIN32 + ASSERT(pwd.homedir[len - 1] != '\\'); +#else + ASSERT(pwd.homedir[len - 1] != '/'); +#endif + +#ifdef _WIN32 + ASSERT(pwd.uid == -1); + ASSERT(pwd.gid == -1); +#else + ASSERT(pwd.uid >= 0); + ASSERT(pwd.gid >= 0); +#endif + + /* Test uv_os_free_passwd() */ + uv_os_free_passwd(&pwd); + + ASSERT(pwd.username == NULL); + ASSERT(pwd.shell == NULL); + ASSERT(pwd.homedir == NULL); + + /* Test a double free */ + uv_os_free_passwd(&pwd); + + ASSERT(pwd.username == NULL); + ASSERT(pwd.shell == NULL); + ASSERT(pwd.homedir == NULL); + + /* Test invalid input */ + r = uv_os_get_passwd(NULL); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 3ad8d32be..8c0f68108 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -197,6 +197,7 @@ TEST_DECLARE (get_currentexe) TEST_DECLARE (process_title) TEST_DECLARE (cwd_and_chdir) TEST_DECLARE (get_memory) +TEST_DECLARE (get_passwd) TEST_DECLARE (handle_fileno) TEST_DECLARE (homedir) TEST_DECLARE (tmpdir) @@ -585,6 +586,8 @@ TASK_LIST_START TEST_ENTRY (get_memory) + TEST_ENTRY (get_passwd) + TEST_ENTRY (get_loadavg) TEST_ENTRY (handle_fileno) diff --git a/test/test-platform-output.c b/test/test-platform-output.c index 76495e14f..b7ce070a3 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -32,6 +32,7 @@ TEST_IMPL(platform_output) { uv_rusage_t rusage; uv_cpu_info_t* cpus; uv_interface_address_t* interfaces; + uv_passwd_t pwd; int count; int i; int err; @@ -122,5 +123,15 @@ TEST_IMPL(platform_output) { } uv_free_interface_addresses(interfaces, count); + err = uv_os_get_passwd(&pwd); + ASSERT(err == 0); + + printf("uv_os_get_passwd:\n"); + printf(" euid: %d\n", pwd.uid); + printf(" gid: %d\n", pwd.gid); + printf(" username: %s\n", pwd.username); + printf(" shell: %s\n", pwd.shell); + printf(" home directory: %s\n", pwd.homedir); + return 0; } diff --git a/uv.gyp b/uv.gyp index a12753a98..cbef71f7c 100644 --- a/uv.gyp +++ b/uv.gyp @@ -304,6 +304,7 @@ 'test/test-fs-event.c', 'test/test-get-currentexe.c', 'test/test-get-memory.c', + 'test/test-get-passwd.c', 'test/test-getaddrinfo.c', 'test/test-getnameinfo.c', 'test/test-getsockname.c', From 1c0281e3e210aa97f7faaa5725cb95538f1c97fd Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 29 Mar 2016 18:55:14 +0200 Subject: [PATCH 113/632] process: fix uv_spawn edge-case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It can happen that the `parent` end of the `signal_pipe` is given a STDIO file descriptor, so closing it using `uv__close` fails. This problem is happening when running the `spawn_closed_process_io` test in `SmartOS`. The reason being that when creating a socketpair in `uv__process_init_stdio`, the `Illumos` implementation uses 3 sockets: one is used as a listener, and the other 2 represent both ends of the pipe. The listener socket is closed once the pipe is created. In the test, the listener socket is assigned to the `0` fd, as it is the first free fd in the system. So the fd `0` remained free after the call to `socketpair`. Afterwards, when creating the `signal_pipe`, the fd `0` is being assigned again, so closing it with `uv__close` made the test fail. This issue is not happening in the other unixes because `socketpair` doesn't use 3 fd's, but only 2. To solve the issue, a new `uv__close__nocheckstdio()` function has been added and used. PR-URL: https://github.com/libuv/libuv/pull/796 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/core.c | 9 +++++++-- src/unix/internal.h | 1 + src/unix/process.c | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index b7f7c25f4..9aaca8418 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -498,12 +498,11 @@ int uv__accept(int sockfd) { } -int uv__close(int fd) { +int uv__close_nocheckstdio(int fd) { int saved_errno; int rc; assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */ - assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ saved_errno = errno; rc = close(fd); @@ -518,6 +517,12 @@ int uv__close(int fd) { } +int uv__close(int fd) { + assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ + return uv__close_nocheckstdio(fd); +} + + #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ defined(_AIX) || defined(__DragonFly__) diff --git a/src/unix/internal.h b/src/unix/internal.h index 328c66328..938e76f1d 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -177,6 +177,7 @@ struct uv__stream_queued_fds_s { /* core */ int uv__nonblock(int fd, int set); int uv__close(int fd); +int uv__close_nocheckstdio(int fd); int uv__cloexec(int fd, int set); int uv__socket(int domain, int type, int protocol); int uv__dup(int fd); diff --git a/src/unix/process.c b/src/unix/process.c index 571f8cd77..02468e6e5 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -498,7 +498,7 @@ int uv_spawn(uv_loop_t* loop, } else abort(); - uv__close(signal_pipe[0]); + uv__close_nocheckstdio(signal_pipe[0]); for (i = 0; i < options->stdio_count; i++) { err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0); From 2d6437888ef36037c65ffd3ffe33eb180c6fe0a0 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 31 Mar 2016 11:56:57 +0200 Subject: [PATCH 114/632] test: use %ld for printing uid/gid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The uid and gid fields in uv_passwd_t are of type long so use %ld for printing them. Fixes two -Wformat compiler warnings. PR-URL: https://github.com/libuv/libuv/pull/797 Reviewed-By: Saúl Ibarra Corretgé --- test/test-platform-output.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-platform-output.c b/test/test-platform-output.c index b7ce070a3..2c4740550 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -127,8 +127,8 @@ TEST_IMPL(platform_output) { ASSERT(err == 0); printf("uv_os_get_passwd:\n"); - printf(" euid: %d\n", pwd.uid); - printf(" gid: %d\n", pwd.gid); + printf(" euid: %ld\n", pwd.uid); + printf(" gid: %ld\n", pwd.gid); printf(" username: %s\n", pwd.username); printf(" shell: %s\n", pwd.shell); printf(" home directory: %s\n", pwd.homedir); From a117fbd13bd5246b878c9a55bb3d080830755dfc Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Tue, 22 Mar 2016 16:53:36 -0400 Subject: [PATCH 115/632] aix: fix ahafs implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uv__makedir_p was not processing all directories in passed string. Now if a directory already exists (EEXIST) it simply moves onto the next directory in the provided string. Fixed bogus assert in uv__ahafs_event. PR-URL: https://github.com/libuv/libuv/pull/776 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/aix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/aix.c b/src/unix/aix.c index 0bd9c0eb5..8cf3d3430 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -524,7 +524,7 @@ static int uv__makedir_p(const char *dir) { if (*p == '/') { *p = 0; err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - if(err != 0) + if (err != 0 && errno != EEXIST) return err; *p = '/'; } @@ -743,7 +743,7 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int */ bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0); - assert((bytes <= 0) && "uv__ahafs_event - Error reading monitor file"); + assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file"); /* Parse the data */ if(bytes > 0) From 6ae622b0a178420f33f997feb6346159114a9a92 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Tue, 22 Mar 2016 19:06:52 -0400 Subject: [PATCH 116/632] aix: do not store absolute path to ahafs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only need the absolute path to create our .mon file under /aha. So only duplicate the passed string. This keeps behaviour similar to other platforms. Fixes test fs_event_getpath. PR-URL: https://github.com/libuv/libuv/pull/776 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/aix.c | 41 +++++++++++++---------------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/src/unix/aix.c b/src/unix/aix.c index 8cf3d3430..bcaa5ee50 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -725,18 +725,11 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int int bytes, rc = 0; uv_fs_event_t* handle; int events = 0; - int i = 0; char fname[PATH_MAX]; char *p; handle = container_of(event_watch, uv_fs_event_t, event_watcher); - /* Clean all the buffers*/ - for(i = 0; i < PATH_MAX; i++) { - fname[i] = 0; - } - i = 0; - /* At this point, we assume that polling has been done on the * file descriptor, so we can just read the AHAFS event occurrence * data and parse its results without having to block anything @@ -749,35 +742,27 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int if(bytes > 0) rc = uv__parse_data(result_data, &events, handle); + /* Unrecoverable error */ + if (rc == -1) + return; + /* For directory changes, the name of the files that triggered the change * are never absolute pathnames */ if (uv__path_is_a_directory(handle->path) == 0) { p = handle->dir_filename; - while(*p != NULL){ - fname[i]= *p; - i++; - p++; - } } else { - /* For file changes, figure out whether filename is absolute or not */ - if (handle->path[0] == '/') { - p = strrchr(handle->path, '/'); + p = strrchr(handle->path, '/'); + if (p == NULL) + p = handle->path; + else p++; - - while(*p != NULL) { - fname[i]= *p; - i++; - p++; - } - } } + strncpy(fname, p, sizeof(fname) - 1); + /* Just in case */ + fname[sizeof(fname) - 1] = '\0'; - /* Unrecoverable error */ - if (rc == -1) - return; - else /* Call the actual JavaScript callback function */ - handle->cb(handle, (const char*)&fname, events, 0); + handle->cb(handle, fname, events, 0); } #endif @@ -857,7 +842,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, /* Setup/Initialize all the libuv routines */ uv__handle_start(handle); uv__io_init(&handle->event_watcher, uv__ahafs_event, fd); - handle->path = uv__strdup((const char*)&absolute_path); + handle->path = uv__strdup(filename); handle->cb = cb; uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN); From 643c9e9c32895e166e372200779ed7d5b2365d18 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Thu, 31 Mar 2016 12:22:57 +0200 Subject: [PATCH 117/632] process: close process pipes safely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use `uv__close__nocheckstdio` instead of `close`. PR-URL: https://github.com/libuv/libuv/pull/798 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/unix/process.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index 02468e6e5..ef10a3422 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -530,9 +530,9 @@ int uv_spawn(uv_loop_t* loop, if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM)) continue; if (pipes[i][0] != -1) - close(pipes[i][0]); + uv__close_nocheckstdio(pipes[i][0]); if (pipes[i][1] != -1) - close(pipes[i][1]); + uv__close_nocheckstdio(pipes[i][1]); } uv__free(pipes); } From 387102b2475776e5e40a3f6da5041eb674ad4abf Mon Sep 17 00:00:00 2001 From: Enno Boland Date: Wed, 23 Mar 2016 23:18:53 +0100 Subject: [PATCH 118/632] unix: open ttyname instead of /dev/tty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Find the real name of the tty using ttyname_r(3) instead of opening "/dev/tty" which causes trouble if the fd doesn't point to the controlling terminal. PR-URL: https://github.com/libuv/libuv/pull/779 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 7 +++++++ docs/src/tty.rst | 16 ++++++++++++---- src/unix/tty.c | 29 ++++++++++++++++++++++++++++- test/test-list.h | 2 ++ test/test-tty.c | 39 +++++++++++++++++++++++++++++++++++++++ uv.gyp | 5 +++++ 6 files changed, 93 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index 625f02515..dfd4353a3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -129,6 +129,7 @@ EXTRA_DIST = test/fixtures/empty_file \ TESTS = test/run-tests check_PROGRAMS = test/run-tests test_run_tests_CFLAGS = +test_run_tests_LDFLAGS = test_run_tests_SOURCES = test/blackhole-server.c \ test/dns-server.c \ test/echo-server.c \ @@ -303,15 +304,18 @@ libuv_la_SOURCES += src/unix/darwin.c \ src/unix/fsevents.c \ src/unix/kqueue.c \ src/unix/proctitle.c +test_run_tests_LDFLAGS += -lutil endif if DRAGONFLY include_HEADERS += include/uv-bsd.h +test_run_tests_LDFLAGS += -lutil endif if FREEBSD include_HEADERS += include/uv-bsd.h libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c +test_run_tests_LDFLAGS += -lutil endif if LINUX @@ -322,16 +326,19 @@ libuv_la_SOURCES += src/unix/linux-core.c \ src/unix/linux-syscalls.c \ src/unix/linux-syscalls.h \ src/unix/proctitle.c +test_run_tests_LDFLAGS += -lutil endif if NETBSD include_HEADERS += include/uv-bsd.h libuv_la_SOURCES += src/unix/kqueue.c src/unix/netbsd.c +test_run_tests_LDFLAGS += -lutil endif if OPENBSD include_HEADERS += include/uv-bsd.h libuv_la_SOURCES += src/unix/kqueue.c src/unix/openbsd.c +test_run_tests_LDFLAGS += -lutil endif if SUNOS diff --git a/docs/src/tty.rst b/docs/src/tty.rst index 655dca9ca..01a058528 100644 --- a/docs/src/tty.rst +++ b/docs/src/tty.rst @@ -58,14 +58,22 @@ API `readable`, specifies if you plan on calling :c:func:`uv_read_start` with this stream. stdin is readable, stdout is not. - On Unix this function will try to open ``/dev/tty`` and use it if the passed - file descriptor refers to a TTY. This lets libuv put the tty in non-blocking - mode without affecting other processes that share the tty. + On Unix this function will determine the path of the fd of the terminal + using :man:`ttyname_r(3)`, open it, and use it if the passed file descriptor + refers to a TTY. This lets libuv put the tty in non-blocking mode without + affecting other processes that share the tty. + + This function is not thread safe on systems that don't support + ioctl TIOCGPTN or TIOCPTYGNAME, for instance OpenBSD and Solaris. .. note:: - If opening ``/dev/tty`` fails, libuv falls back to blocking writes for + If reopening the TTY fails, libuv falls back to blocking writes for non-readable TTY streams. + .. versionchanged:: 1.9.0: the path of the TTY is determined by + :man:`ttyname_r(3)`. In earlier versions libuv opened + `/dev/tty` instead. + .. versionchanged:: 1.5.0: trying to initialize a TTY stream with a file descriptor that refers to a file returns `UV_EINVAL` on UNIX. diff --git a/src/unix/tty.c b/src/unix/tty.c index 02164f9dc..32fa37eac 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -23,6 +23,7 @@ #include "internal.h" #include "spinlock.h" +#include #include #include #include @@ -33,12 +34,30 @@ static int orig_termios_fd = -1; static struct termios orig_termios; static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; +static int uv__tty_is_slave(const int fd) { + int result; +#if defined(__linux__) || defined(__FreeBSD__) + int dummy; + + result = ioctl(fd, TIOCGPTN, &dummy) != 0; +#elif defined(__APPLE__) + char dummy[256]; + + result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0; +#else + /* Fallback to ptsname + */ + result = ptsname(fd) == NULL; +#endif + return result; +} int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { uv_handle_type type; int flags; int newfd; int r; + char path[256]; /* File descriptors that refer to files cannot be monitored with epoll. * That restriction also applies to character devices like /dev/random @@ -62,7 +81,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { * other processes. */ if (type == UV_TTY) { - r = uv__open_cloexec("/dev/tty", O_RDWR); + /* Reopening a pty in master mode won't work either because the reopened + * pty will be in slave mode (*BSD) or reopening will allocate a new + * master/slave pair (Linux). Therefore check if the fd points to a + * slave device. + */ + if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) + r = uv__open_cloexec(path, O_RDWR); + else + r = -1; if (r < 0) { /* fallback to using blocking writes */ diff --git a/test/test-list.h b/test/test-list.h index 8c0f68108..8b10f1a5f 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -44,6 +44,7 @@ TEST_DECLARE (semaphore_2) TEST_DECLARE (semaphore_3) TEST_DECLARE (tty) TEST_DECLARE (tty_file) +TEST_DECLARE (tty_pty) TEST_DECLARE (stdio_over_pipes) TEST_DECLARE (ip6_pton) TEST_DECLARE (ipc_listen_before_write) @@ -387,6 +388,7 @@ TASK_LIST_START TEST_ENTRY (pipe_set_non_blocking) TEST_ENTRY (tty) TEST_ENTRY (tty_file) + TEST_ENTRY (tty_pty) TEST_ENTRY (stdio_over_pipes) TEST_ENTRY (ip6_pton) TEST_ENTRY (ipc_listen_before_write) diff --git a/test/test-tty.c b/test/test-tty.c index b844959d5..461d19413 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -28,6 +28,13 @@ #else /* Unix */ # include # include +# if defined(__linux__) +# include +# elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) +# include +# elif defined(__FreeBSD__) || defined(__DragonFly__) +# include +# endif #endif #include @@ -182,3 +189,35 @@ TEST_IMPL(tty_file) { #endif return 0; } + +TEST_IMPL(tty_pty) { +# if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ + defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) + int master_fd, slave_fd; + struct winsize w; + uv_loop_t loop; + uv_tty_t master_tty, slave_tty; + + ASSERT(0 == uv_loop_init(&loop)); + + ASSERT(0 == openpty(&master_fd, &slave_fd, NULL, NULL, &w)); + ASSERT(0 == uv_tty_init(&loop, &slave_tty, slave_fd, 0)); + ASSERT(0 == uv_tty_init(&loop, &master_tty, master_fd, 0)); + /* Check if the file descriptor was reopened. If it is, + * UV_STREAM_BLOCKING (value 0x80) isn't set on flags. + */ + ASSERT(0 == (slave_tty.flags & 0x80)); + /* The master_fd of a pty should never be reopened. + */ + ASSERT(master_tty.flags & 0x80); + ASSERT(0 == close(slave_fd)); + uv_close((uv_handle_t*) &slave_tty, NULL); + ASSERT(0 == close(master_fd)); + uv_close((uv_handle_t*) &master_tty, NULL); + + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + + MAKE_VALGRIND_HAPPY(); +#endif + return 0; +} diff --git a/uv.gyp b/uv.gyp index cbef71f7c..757540193 100644 --- a/uv.gyp +++ b/uv.gyp @@ -426,6 +426,11 @@ 'test/runner-unix.h', ], }], + [ 'OS in "mac dragonflybsd freebsd linux netbsd openbsd".split()', { + 'link_settings': { + 'libraries': [ '-lutil' ], + }, + }], [ 'OS=="solaris"', { # make test-fs.c compile, needs _POSIX_C_SOURCE 'defines': [ '__EXTENSIONS__', From 7ed5d671332dca3fea1008f22a6cc30892ee2ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A1ri=20Tristan=20Helgason?= Date: Sat, 2 Apr 2016 16:00:47 +0200 Subject: [PATCH 119/632] unix: remove outdated comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The comment removed by this commit is no longer relevant, as the function's return type changed from int to void. PR-URL: https://github.com/libuv/libuv/pull/804 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/unix/pipe.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 05d37f462..d4fdfa9d5 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -200,9 +200,6 @@ void uv_pipe_connect(uv_connect_t* req, if (err) uv__io_feed(handle->loop, &handle->io_watcher); - /* Mimic the Windows pipe implementation, always - * return 0 and let the callback handle errors. - */ } From 229b3a4cc150aebd6561e6bd43076eafa7a03756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 7 Apr 2016 12:14:56 +0200 Subject: [PATCH 120/632] 2016.04.08, Version 1.9.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.8.0: * win: wait for full timeout duration (João Reis) * unix: fix support for uClibc-ng (Martin Bark) * doc: indicate where new test files need to be added (Dave) * test,unix: fix logic error in test runner (Ben Noordhuis) * fs: don't nullify req->bufs on EINTR (Dave) * osx: set the default thread stack size to RLIMIT_STACK (Saúl Ibarra Corretgé) * build: invoke libtoolize with --copy (Ben Noordhuis) * test: fixup eintr_handling (Saúl Ibarra Corretgé) * osx: avoid compilation warning with Clang (Saúl Ibarra Corretgé) * test,win: fix compilation with shared lib (Alexis Murzeau) * test: fix race condition in pipe-close-stdout (Imran Iqbal) * unix,win: add uv_os_tmpdir() (cjihrig) * ios: fix undefined PTHREAD_STACK_MIN (Didiet) * test: fix threadpool_multiple_event_loops for AIX (Imran Iqbal) * unix: report errors for unpollable fds (Ben Noordhuis) * win: fix watching root files (Nicholas Vavilov) * build,win: print the Visual Studio version in use (Saúl Ibarra Corretgé) * build,win: remove unneeded condition from GYP file (Saúl Ibarra Corretgé) * test,win: fix compilation warning (Saúl Ibarra Corretgé) * test: use uv_loop_close and assert its result (Nan Xiang) * build: map 'AMD64' host arch to 'x64' (Ben Noordhuis) * osx: protected use of potentially undefined macro (Samuel Lorétan) * linux: fix compilation with musl (Saúl Ibarra Corretgé) * doc: describe how to make release builds on Unix (Saúl Ibarra Corretgé) * doc: add missing link in README (Saúl Ibarra Corretgé) * build: python 2.x/3.x consistent print usage (Rasmus Christian Pedersen) * test: assume no IPv6 if interfaces cannot be listed (Nan Xiang) * darwin: replace F_FULLFSYNC with fdatasync syscall (Saúl Ibarra Corretgé) * doc: add missing write callback to example (Nándor István Krácser) * build: compile with -D_THREAD_SAFE on AIX (Imran Iqbal) * test: fix threadpool_multiple_event_loops on PPC (Imran Iqbal) * test: reduce timeout in tcp_close_while_connecting (Imran Iqbal) * unix, win: consistently null-terminate buffers (Saúl Ibarra Corretgé) * unix, win: count null byte on UV_ENOBUFS (Saúl Ibarra Corretgé) * test: fix deadlocks in uv_cond_wait (Katsutoshi Horie) * linux: fix cpu count (Lukasz Jagiello) * unix: fix uv__handle_type for AIX (Imran Iqbal) * linux: call fclose(), fix fdopen() memory leak (Ben Noordhuis) * win: remove unneeded condition (Saúl Ibarra Corretgé) * unix: fix compile error in Android using bionic (Robert Chiras) * linux: add braces to multi-statement if (Kári Tristan Helgason) * doc: add @cjihrig as a maintainer (Saúl Ibarra Corretgé) * unix: add fork-safe open file function (Kári Tristan Helgason) * linux: replace calls to fopen with uv__open_file (Kári Tristan Helgason) * linux: remove redundant call to rewind() (Krishnaraj Bhat) * win: remove duplicated code when processing fsevents (Saúl Ibarra Corretgé) * test: fix poll_bad_fdtype for AIX (Imran Iqbal) * linux: fix error checking in uv__open_file (Saúl Ibarra Corretgé) * poll: add UV_DISCONNECT event (Santiago Gimeno) * fs: realpath: fix string size before converting (Yuval Brik) * win: use native APIs for UTF conversions (cjihrig) * doc: clarify uv_loop_close() (Ben Noordhuis) * unix: retry ioctl(TIOCGWINSZ) on EINTR (Ben Noordhuis) * win,build: remove unused build defines (Saúl Ibarra Corretgé) * win: fix buffer overflow in fs events (Joran Dirk Greef) * win: fix uv_relative_path and remove dead branch (Joran Dirk Greef) * unix: use open(2) with O_CLOEXEC on OS X (Kári Tristan Helgason) * test: add missing copyright header (cjihrig) * aix: fix 'POLLRDHUP undeclared' build error (Ben Noordhuis) * unix,win: add uv_get_passwd() (cjihrig) * process: fix uv_spawn edge-case (Santiago Gimeno) * test: use %ld for printing uid/gid (Ben Noordhuis) * aix: fix ahafs implementation (Imran Iqbal) * aix: do not store absolute path to ahafs (Imran Iqbal) * process: close process pipes safely (Santiago Gimeno) * unix: open ttyname instead of /dev/tty (Enno Boland) * unix: remove outdated comment (Kári Tristan Helgason) --- AUTHORS | 13 ++++ ChangeLog | 139 +++++++++++++++++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 8 +-- 5 files changed, 158 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index 8dc3955ca..9a9e9c2a2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -240,3 +240,16 @@ Yuval Brik Joran Dirk Greef Andrey Mazo sztomi +Martin Bark +Dave +Alexis Murzeau +Didiet +Nan Xiang <514580344@qq.com> +Samuel Lorétan +Nándor István Krácser +Katsutoshi Horie +Lukasz Jagiello +Robert Chiras +Kári Tristan Helgason +Krishnaraj Bhat +Enno Boland diff --git a/ChangeLog b/ChangeLog index af0743af7..01114d083 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,142 @@ +2016.04.08, Version 1.9.0 (Stable) + +Changes since version 1.8.0: + +* win: wait for full timeout duration (João Reis) + +* unix: fix support for uClibc-ng (Martin Bark) + +* doc: indicate where new test files need to be added (Dave) + +* test,unix: fix logic error in test runner (Ben Noordhuis) + +* fs: don't nullify req->bufs on EINTR (Dave) + +* osx: set the default thread stack size to RLIMIT_STACK (Saúl Ibarra Corretgé) + +* build: invoke libtoolize with --copy (Ben Noordhuis) + +* test: fixup eintr_handling (Saúl Ibarra Corretgé) + +* osx: avoid compilation warning with Clang (Saúl Ibarra Corretgé) + +* test,win: fix compilation with shared lib (Alexis Murzeau) + +* test: fix race condition in pipe-close-stdout (Imran Iqbal) + +* unix,win: add uv_os_tmpdir() (cjihrig) + +* ios: fix undefined PTHREAD_STACK_MIN (Didiet) + +* test: fix threadpool_multiple_event_loops for AIX (Imran Iqbal) + +* unix: report errors for unpollable fds (Ben Noordhuis) + +* win: fix watching root files (Nicholas Vavilov) + +* build,win: print the Visual Studio version in use (Saúl Ibarra Corretgé) + +* build,win: remove unneeded condition from GYP file (Saúl Ibarra Corretgé) + +* test,win: fix compilation warning (Saúl Ibarra Corretgé) + +* test: use uv_loop_close and assert its result (Nan Xiang) + +* build: map 'AMD64' host arch to 'x64' (Ben Noordhuis) + +* osx: protected use of potentially undefined macro (Samuel Lorétan) + +* linux: fix compilation with musl (Saúl Ibarra Corretgé) + +* doc: describe how to make release builds on Unix (Saúl Ibarra Corretgé) + +* doc: add missing link in README (Saúl Ibarra Corretgé) + +* build: python 2.x/3.x consistent print usage (Rasmus Christian Pedersen) + +* test: assume no IPv6 if interfaces cannot be listed (Nan Xiang) + +* darwin: replace F_FULLFSYNC with fdatasync syscall (Saúl Ibarra Corretgé) + +* doc: add missing write callback to example (Nándor István Krácser) + +* build: compile with -D_THREAD_SAFE on AIX (Imran Iqbal) + +* test: fix threadpool_multiple_event_loops on PPC (Imran Iqbal) + +* test: reduce timeout in tcp_close_while_connecting (Imran Iqbal) + +* unix, win: consistently null-terminate buffers (Saúl Ibarra Corretgé) + +* unix, win: count null byte on UV_ENOBUFS (Saúl Ibarra Corretgé) + +* test: fix deadlocks in uv_cond_wait (Katsutoshi Horie) + +* linux: fix cpu count (Lukasz Jagiello) + +* unix: fix uv__handle_type for AIX (Imran Iqbal) + +* linux: call fclose(), fix fdopen() memory leak (Ben Noordhuis) + +* win: remove unneeded condition (Saúl Ibarra Corretgé) + +* unix: fix compile error in Android using bionic (Robert Chiras) + +* linux: add braces to multi-statement if (Kári Tristan Helgason) + +* doc: add @cjihrig as a maintainer (Saúl Ibarra Corretgé) + +* unix: add fork-safe open file function (Kári Tristan Helgason) + +* linux: replace calls to fopen with uv__open_file (Kári Tristan Helgason) + +* linux: remove redundant call to rewind() (Krishnaraj Bhat) + +* win: remove duplicated code when processing fsevents (Saúl Ibarra Corretgé) + +* test: fix poll_bad_fdtype for AIX (Imran Iqbal) + +* linux: fix error checking in uv__open_file (Saúl Ibarra Corretgé) + +* poll: add UV_DISCONNECT event (Santiago Gimeno) + +* fs: realpath: fix string size before converting (Yuval Brik) + +* win: use native APIs for UTF conversions (cjihrig) + +* doc: clarify uv_loop_close() (Ben Noordhuis) + +* unix: retry ioctl(TIOCGWINSZ) on EINTR (Ben Noordhuis) + +* win,build: remove unused build defines (Saúl Ibarra Corretgé) + +* win: fix buffer overflow in fs events (Joran Dirk Greef) + +* win: fix uv_relative_path and remove dead branch (Joran Dirk Greef) + +* unix: use open(2) with O_CLOEXEC on OS X (Kári Tristan Helgason) + +* test: add missing copyright header (cjihrig) + +* aix: fix 'POLLRDHUP undeclared' build error (Ben Noordhuis) + +* unix,win: add uv_get_passwd() (cjihrig) + +* process: fix uv_spawn edge-case (Santiago Gimeno) + +* test: use %ld for printing uid/gid (Ben Noordhuis) + +* aix: fix ahafs implementation (Imran Iqbal) + +* aix: do not store absolute path to ahafs (Imran Iqbal) + +* process: close process pipes safely (Santiago Gimeno) + +* unix: open ttyname instead of /dev/tty (Enno Boland) + +* unix: remove outdated comment (Kári Tristan Helgason) + + 2015.12.15, Version 1.8.0 (Stable), 5467299450ecf61635657557b6e01aaaf6c3fdf4 Changes since version 1.7.5: diff --git a/appveyor.yml b/appveyor.yml index 9aa63c5a5..835730b92 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.8.0.build{build} +version: v1.9.0.build{build} install: - cinst -y nsis diff --git a/configure.ac b/configure.ac index 011bee2a8..2d5a3b9de 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.8.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.9.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 d53d62ab2..cb6661828 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 8 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 9 +#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 4b444d3fbc4d588834b6089d401587dd0a8e85ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 7 Apr 2016 12:15:02 +0200 Subject: [PATCH 121/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 01114d083..85d40113e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2016.04.08, Version 1.9.0 (Stable) +2016.04.08, Version 1.9.0 (Stable), 229b3a4cc150aebd6561e6bd43076eafa7a03756 Changes since version 1.8.0: From d476185bb373601b884b9a75746b8e9f666a43ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 7 Apr 2016 07:52:59 -0300 Subject: [PATCH 122/632] Now working on version 1.9.1 --- 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 cb6661828..33856120f 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 9 -#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 a84caf6fd7867eaf6073d074d448998a8699ea6e Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 7 Apr 2016 10:44:04 -0400 Subject: [PATCH 123/632] test: handle root home directories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the tests assert that the home directory doesn't end in a slash. However, if the home directory is / or something like C:\, then this assertion is incorrect. This commit adds special handling for these cases. Fixes: https://github.com/libuv/libuv/issues/812 PR-URL: https://github.com/libuv/libuv/pull/813 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- test/test-get-passwd.c | 10 ++++++++-- test/test-homedir.c | 14 ++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/test/test-get-passwd.c b/test/test-get-passwd.c index 58d9c73c6..8e16fb83c 100644 --- a/test/test-get-passwd.c +++ b/test/test-get-passwd.c @@ -45,9 +45,15 @@ TEST_IMPL(get_passwd) { ASSERT(len > 0); #ifdef _WIN32 - ASSERT(pwd.homedir[len - 1] != '\\'); + if (len == 3 && pwd.homedir[1] == ':') + ASSERT(pwd.homedir[2] == '\\'); + else + ASSERT(pwd.homedir[len - 1] != '\\'); #else - ASSERT(pwd.homedir[len - 1] != '/'); + if (len == 1) + ASSERT(pwd.homedir[0] == '/'); + else + ASSERT(pwd.homedir[len - 1] != '/'); #endif #ifdef _WIN32 diff --git a/test/test-homedir.c b/test/test-homedir.c index 5027d44c1..856534a40 100644 --- a/test/test-homedir.c +++ b/test/test-homedir.c @@ -29,7 +29,6 @@ TEST_IMPL(homedir) { char homedir[PATHMAX]; size_t len; - char last; int r; /* Test the normal case */ @@ -42,14 +41,17 @@ TEST_IMPL(homedir) { ASSERT(len > 0); ASSERT(homedir[len] == '\0'); - if (len > 1) { - last = homedir[len - 1]; #ifdef _WIN32 - ASSERT(last != '\\'); + if (len == 3 && homedir[1] == ':') + ASSERT(homedir[2] == '\\'); + else + ASSERT(homedir[len - 1] != '\\'); #else - ASSERT(last != '/'); + if (len == 1) + ASSERT(homedir[0] == '/'); + else + ASSERT(homedir[len - 1] != '/'); #endif - } /* Test the case where the buffer is too small */ len = SMALLPATH; From 4aeed1ac13b81806acc230a9599098f8796629ab Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Mon, 14 Mar 2016 15:20:40 -0400 Subject: [PATCH 124/632] unix: implement uv__fs_futime for AIX 7.1 'futimens' is only implemented on AIX 7.1. Other functions like 'utimes' and 'utimes' are merely stub functions that return ENOSYS on AIX 6.1 and below. Skip test fs_futime for AIX versions below 7.1. PR-URL: https://github.com/libuv/libuv/pull/811 Reviewed-By: Ben Noordhuis --- src/unix/fs.c | 7 +++++++ test/test-fs.c | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index 8936ad9d8..419961c05 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -205,6 +205,13 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { # else return futimes(req->file, tv); # endif +#elif defined(_AIX71) + struct timespec ts[2]; + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000; + return futimens(req->file, ts); #else errno = ENOSYS; return -1; diff --git a/test/test-fs.c b/test/test-fs.c index cf37ac490..1cc1a7c06 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2033,6 +2033,9 @@ TEST_IMPL(fs_stat_root) { TEST_IMPL(fs_futime) { +#if defined(_AIX) && !defined(_AIX71) + RETURN_SKIP("futime is not implemented for AIX versions below 7.1"); +#else utime_check_t checkme; const char* path = "test_file"; double atime; @@ -2087,6 +2090,7 @@ TEST_IMPL(fs_futime) { MAKE_VALGRIND_HAPPY(); return 0; +#endif } From 7acb6bd8434909e4c85c32f0748da57085eb30eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 7 Apr 2016 17:04:33 -0300 Subject: [PATCH 125/632] test: skip early bind tests if no IPv6 is supported PR-URL: https://github.com/libuv/libuv/pull/814 Reviewed-By: Colin Ihrig --- test/test-tcp-create-socket-early.c | 3 +++ test/test-udp-create-socket-early.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/test/test-tcp-create-socket-early.c b/test/test-tcp-create-socket-early.c index 65650adcc..1a508e474 100644 --- a/test/test-tcp-create-socket-early.c +++ b/test/test-tcp-create-socket-early.c @@ -139,6 +139,9 @@ TEST_IMPL(tcp_create_early_bad_bind) { uv_os_fd_t fd; int r; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET6); diff --git a/test/test-udp-create-socket-early.c b/test/test-udp-create-socket-early.c index 3d0152428..3f3027404 100644 --- a/test/test-udp-create-socket-early.c +++ b/test/test-udp-create-socket-early.c @@ -79,6 +79,9 @@ TEST_IMPL(udp_create_early_bad_bind) { uv_os_fd_t fd; int r; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET6); From 3819e48277a7bdb5c2b1d96aac4139fd25430b6e Mon Sep 17 00:00:00 2001 From: Michael Fero Date: Fri, 8 Apr 2016 15:12:17 -0400 Subject: [PATCH 126/632] win: fix var declaration to be C89 compliant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Visual Studio 2013+ relaxed variable declaration C89 compliance; older compilers are strict (e.g. VS 2008 - 2012). PR-URL: https://github.com/libuv/libuv/pull/815 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs-event.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 77c935a2d..c30b55312 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -66,11 +66,12 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, 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); if (dirlen > 0 && dir[dirlen - 1] == '\\') dirlen--; - size_t filenamelen = wcslen(filename); - size_t relpathlen = filenamelen - dirlen - 1; + relpathlen = filenamelen - dirlen - 1; *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR)); if (!*relpath) uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); From 375ba2d76dbe25fb35f04f4cbb0d36614f8d4944 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 9 Apr 2016 10:36:41 +0200 Subject: [PATCH 127/632] unix: use POLL{IN,OUT,etc} constants directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the UV__POLL defines and use POLL{IN,OUT,etc} directly. On Linux, we lean on the fact that the POLL constants correspond one-to-one to their EPOLL counterparts. Fixes: https://github.com/libuv/libuv/issues/816 PR-URL: https://github.com/libuv/libuv/pull/817 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/aix.c | 2 +- src/unix/async.c | 4 +-- src/unix/core.c | 10 +++--- src/unix/internal.h | 50 ++++++---------------------- src/unix/kqueue.c | 20 +++++------ src/unix/linux-core.c | 15 ++++++--- src/unix/linux-inotify.c | 2 +- src/unix/linux-syscalls.h | 8 ----- src/unix/pipe.c | 4 +-- src/unix/poll.c | 14 ++++---- src/unix/signal.c | 2 +- src/unix/stream.c | 70 +++++++++++++++++++-------------------- src/unix/sunos.c | 2 +- src/unix/tcp.c | 4 +-- src/unix/udp.c | 20 +++++------ 15 files changed, 97 insertions(+), 130 deletions(-) diff --git a/src/unix/aix.c b/src/unix/aix.c index bcaa5ee50..baa660f90 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -845,7 +845,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, handle->path = uv__strdup(filename); handle->cb = cb; - uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->event_watcher, POLLIN); return 0; #else diff --git a/src/unix/async.c b/src/unix/async.c index 184b59812..393cdebd4 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -223,7 +223,7 @@ int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) { return err; uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]); - uv__io_start(loop, &wa->io_watcher, UV__POLLIN); + uv__io_start(loop, &wa->io_watcher, POLLIN); wa->wfd = pipefd[1]; wa->cb = cb; @@ -241,7 +241,7 @@ void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) { wa->wfd = -1; } - uv__io_stop(loop, &wa->io_watcher, UV__POLLIN); + uv__io_stop(loop, &wa->io_watcher, POLLIN); uv__close(wa->io_watcher.fd); wa->io_watcher.fd = -1; } diff --git a/src/unix/core.c b/src/unix/core.c index 9aaca8418..cdcd0b504 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -762,7 +762,7 @@ static int uv__run_pending(uv_loop_t* loop) { QUEUE_REMOVE(q); QUEUE_INIT(q); w = QUEUE_DATA(q, uv__io_t, pending_queue); - w->cb(loop, w, UV__POLLOUT); + w->cb(loop, w, POLLOUT); } return 1; @@ -833,7 +833,7 @@ 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) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); @@ -866,7 +866,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); assert(0 != events); if (w->fd == -1) @@ -898,7 +898,7 @@ 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) { - uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); QUEUE_REMOVE(&w->pending_queue); /* Remove stale events for this file descriptor */ @@ -913,7 +913,7 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { int uv__io_active(const uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); assert(0 != events); return 0 != (w->pevents & events); } diff --git a/src/unix/internal.h b/src/unix/internal.h index 938e76f1d..2c3421f91 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -44,9 +44,11 @@ #endif /* __sun */ #if defined(_AIX) -#define reqevents events -#define rtnevents revents -#include +# define reqevents events +# define rtnevents revents +# include +#else +# include #endif /* _AIX */ #if defined(__APPLE__) && !TARGET_OS_IPHONE @@ -89,43 +91,11 @@ # define UV_UNUSED(declaration) declaration #endif -#if defined(__linux__) -# define UV__POLLIN UV__EPOLLIN -# define UV__POLLOUT UV__EPOLLOUT -# define UV__POLLERR UV__EPOLLERR -# define UV__POLLHUP UV__EPOLLHUP -# define UV__POLLRDHUP UV__EPOLLRDHUP -#endif - -#if defined(__sun) || defined(_AIX) -# define UV__POLLIN POLLIN -# define UV__POLLOUT POLLOUT -# define UV__POLLERR POLLERR -# define UV__POLLHUP POLLHUP -#endif - -#ifndef UV__POLLIN -# define UV__POLLIN 1 -#endif - -#ifndef UV__POLLOUT -# define UV__POLLOUT 2 -#endif - -#ifndef UV__POLLERR -# define UV__POLLERR 4 -#endif - -#ifndef UV__POLLHUP -# define UV__POLLHUP 8 -#endif - -#ifndef UV__POLLRDHUP -# ifdef POLLRDHUP -# define UV__POLLRDHUP POLLRDHUP -# else -# define UV__POLLRDHUP 0x200 -# endif +/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */ +#ifdef POLLRDHUP +# define UV__POLLRDHUP POLLRDHUP +#else +# define UV__POLLRDHUP 0x2000 #endif #if !defined(O_CLOEXEC) && defined(__FreeBSD__) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 400b4a4b7..588666d35 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -103,7 +103,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); - if ((w->events & UV__POLLIN) == 0 && (w->pevents & UV__POLLIN) != 0) { + if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) { filter = EVFILT_READ; fflags = 0; op = EV_ADD; @@ -124,7 +124,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } } - if ((w->events & UV__POLLOUT) == 0 && (w->pevents & UV__POLLOUT) != 0) { + if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) { EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (++nevents == ARRAY_SIZE(events)) { @@ -219,8 +219,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (ev->filter == EVFILT_VNODE) { - assert(w->events == UV__POLLIN); - assert(w->pevents == UV__POLLIN); + assert(w->events == POLLIN); + assert(w->pevents == POLLIN); w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ nevents++; continue; @@ -229,8 +229,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { revents = 0; if (ev->filter == EVFILT_READ) { - if (w->pevents & UV__POLLIN) { - revents |= UV__POLLIN; + if (w->pevents & POLLIN) { + revents |= POLLIN; w->rcount = ev->data; } else { /* TODO batch up */ @@ -243,8 +243,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (ev->filter == EVFILT_WRITE) { - if (w->pevents & UV__POLLOUT) { - revents |= UV__POLLOUT; + if (w->pevents & POLLOUT) { + revents |= POLLOUT; w->wcount = ev->data; } else { /* TODO batch up */ @@ -257,7 +257,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (ev->flags & EV_ERROR) - revents |= UV__POLLERR; + revents |= POLLERR; if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) revents |= UV__POLLRDHUP; @@ -409,7 +409,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, fallback: #endif /* defined(__APPLE__) */ - uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->event_watcher, POLLIN); return 0; } diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index fb8ac3f23..66cb7fa6d 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -18,6 +18,11 @@ * IN THE SOFTWARE. */ +/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their + * EPOLL* counterparts. We use the POLL* variants in this file because that + * is what libuv uses elsewhere and it avoids a dependency on . + */ + #include "uv.h" #include "internal.h" @@ -102,7 +107,7 @@ int uv__platform_loop_init(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, UV__POLLIN); + uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN); uv__close(loop->inotify_fd); loop->inotify_fd = -1; } @@ -144,7 +149,7 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { struct uv__epoll_event e; int rc; - e.events = UV__EPOLLIN; + e.events = POLLIN; e.data = -1; rc = 0; @@ -341,7 +346,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * the current watcher. Also, filters out events that users has not * requested us to watch. */ - pe->events &= w->pevents | UV__POLLERR | UV__POLLHUP; + 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 @@ -358,8 +363,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * 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 == UV__EPOLLERR || pe->events == UV__EPOLLHUP) - pe->events |= w->pevents & (UV__EPOLLIN | UV__EPOLLOUT); + if (pe->events == POLLERR || pe->events == POLLHUP) + pe->events |= w->pevents & (POLLIN | POLLOUT); if (pe->events != 0) { w->cb(loop, w, pe->events); diff --git a/src/unix/linux-inotify.c b/src/unix/linux-inotify.c index 282912115..4708c051d 100644 --- a/src/unix/linux-inotify.c +++ b/src/unix/linux-inotify.c @@ -102,7 +102,7 @@ static int init_inotify(uv_loop_t* loop) { loop->inotify_fd = err; uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); - uv__io_start(loop, &loop->inotify_read_watcher, UV__POLLIN); + uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); return 0; } diff --git a/src/unix/linux-syscalls.h b/src/unix/linux-syscalls.h index 4260df111..4c095e9b5 100644 --- a/src/unix/linux-syscalls.h +++ b/src/unix/linux-syscalls.h @@ -72,14 +72,6 @@ #define UV__EPOLL_CTL_DEL 2 #define UV__EPOLL_CTL_MOD 3 -#define UV__EPOLLIN 1 -#define UV__EPOLLOUT 4 -#define UV__EPOLLERR 8 -#define UV__EPOLLHUP 16 -#define UV__EPOLLRDHUP 0x2000 -#define UV__EPOLLONESHOT 0x40000000 -#define UV__EPOLLET 0x80000000 - /* inotify flags */ #define UV__IN_ACCESS 0x001 #define UV__IN_MODIFY 0x002 diff --git a/src/unix/pipe.c b/src/unix/pipe.c index d4fdfa9d5..c8d163dcc 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -102,7 +102,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { handle->connection_cb = cb; handle->io_watcher.cb = uv__server_io; - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->io_watcher, POLLIN); return 0; } @@ -185,7 +185,7 @@ void uv_pipe_connect(uv_connect_t* req, } if (err == 0) - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT); + uv__io_start(handle->loop, &handle->io_watcher, POLLIN | POLLOUT); out: handle->delayed_error = err; diff --git a/src/unix/poll.c b/src/unix/poll.c index e5efb1716..0d5944b0a 100644 --- a/src/unix/poll.c +++ b/src/unix/poll.c @@ -33,17 +33,17 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { handle = container_of(w, uv_poll_t, io_watcher); - if (events & UV__POLLERR) { - uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); + if (events & POLLERR) { + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); uv__handle_stop(handle); handle->poll_cb(handle, -EBADF, 0); return; } pevents = 0; - if (events & UV__POLLIN) + if (events & POLLIN) pevents |= UV_READABLE; - if (events & UV__POLLOUT) + if (events & POLLOUT) pevents |= UV_WRITABLE; if (events & UV__POLLRDHUP) pevents |= UV_DISCONNECT; @@ -79,7 +79,7 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, static void uv__poll_stop(uv_poll_t* handle) { uv__io_stop(handle->loop, &handle->io_watcher, - UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); + POLLIN | POLLOUT | UV__POLLRDHUP); uv__handle_stop(handle); } @@ -104,9 +104,9 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { events = 0; if (pevents & UV_READABLE) - events |= UV__POLLIN; + events |= POLLIN; if (pevents & UV_WRITABLE) - events |= UV__POLLOUT; + events |= POLLOUT; if (pevents & UV_DISCONNECT) events |= UV__POLLRDHUP; diff --git a/src/unix/signal.c b/src/unix/signal.c index edd9085d3..d82b9b7cf 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -222,7 +222,7 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) { uv__io_init(&loop->signal_io_watcher, uv__signal_event, loop->signal_pipefd[0]); - uv__io_start(loop, &loop->signal_io_watcher, UV__POLLIN); + uv__io_start(loop, &loop->signal_io_watcher, POLLIN); return 0; } diff --git a/src/unix/stream.c b/src/unix/stream.c index 9043664df..7dbc556f7 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -159,9 +159,9 @@ static void uv__stream_osx_select(void* arg) { memset(s->sread, 0, s->sread_sz); memset(s->swrite, 0, s->swrite_sz); - if (uv__io_active(&stream->io_watcher, UV__POLLIN)) + if (uv__io_active(&stream->io_watcher, POLLIN)) FD_SET(fd, s->sread); - if (uv__io_active(&stream->io_watcher, UV__POLLOUT)) + if (uv__io_active(&stream->io_watcher, POLLOUT)) FD_SET(fd, s->swrite); FD_SET(s->int_fd, s->sread); @@ -202,9 +202,9 @@ static void uv__stream_osx_select(void* arg) { /* Handle events */ events = 0; if (FD_ISSET(fd, s->sread)) - events |= UV__POLLIN; + events |= POLLIN; if (FD_ISSET(fd, s->swrite)) - events |= UV__POLLOUT; + events |= POLLOUT; assert(events != 0 || FD_ISSET(s->int_fd, s->sread)); if (events != 0) { @@ -233,14 +233,14 @@ static void uv__stream_osx_select_cb(uv_async_t* handle) { ACCESS_ONCE(int, s->events) = 0; assert(events != 0); - assert(events == (events & (UV__POLLIN | UV__POLLOUT))); + assert(events == (events & (POLLIN | POLLOUT))); /* Invoke callback on event-loop */ - if ((events & UV__POLLIN) && uv__io_active(&stream->io_watcher, UV__POLLIN)) - uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLIN); + if ((events & POLLIN) && uv__io_active(&stream->io_watcher, POLLIN)) + uv__stream_io(stream->loop, &stream->io_watcher, POLLIN); - if ((events & UV__POLLOUT) && uv__io_active(&stream->io_watcher, UV__POLLOUT)) - uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLOUT); + if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT)) + uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT); if (stream->flags & UV_CLOSING) return; @@ -437,7 +437,7 @@ void uv__stream_flush_write_queue(uv_stream_t* stream, int error) { void uv__stream_destroy(uv_stream_t* stream) { - assert(!uv__io_active(&stream->io_watcher, UV__POLLIN | UV__POLLOUT)); + assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT)); assert(stream->flags & UV_CLOSED); if (stream->connect_req) { @@ -511,11 +511,11 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int err; stream = container_of(w, uv_stream_t, io_watcher); - assert(events == UV__POLLIN); + assert(events == POLLIN); assert(stream->accepted_fd == -1); assert(!(stream->flags & UV_CLOSING)); - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); + 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. @@ -552,7 +552,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { if (stream->accepted_fd != -1) { /* The user hasn't yet accepted called uv_accept() */ - uv__io_stop(loop, &stream->io_watcher, UV__POLLIN); + uv__io_stop(loop, &stream->io_watcher, POLLIN); return; } @@ -626,7 +626,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { } else { server->accepted_fd = -1; if (err == 0) - uv__io_start(server->loop, &server->io_watcher, UV__POLLIN); + uv__io_start(server->loop, &server->io_watcher, POLLIN); } return err; } @@ -660,7 +660,7 @@ static void uv__drain(uv_stream_t* stream) { int err; assert(QUEUE_EMPTY(&stream->write_queue)); - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); /* Shutdown? */ @@ -846,8 +846,8 @@ static void uv__write(uv_stream_t* stream) { /* Error */ req->error = -errno; uv__write_req_finish(req); - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); - if (!uv__io_active(&stream->io_watcher, UV__POLLIN)) + 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); return; @@ -910,7 +910,7 @@ static void uv__write(uv_stream_t* stream) { assert(!(stream->flags & UV_STREAM_BLOCKING)); /* We're not done. */ - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); /* Notify select() thread about state change */ uv__stream_osx_interrupt_select(stream); @@ -989,8 +989,8 @@ 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_STREAM_READ_EOF; - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); - if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); stream->read_cb(stream, UV_EOF, buf); @@ -1159,7 +1159,7 @@ static void uv__read(uv_stream_t* stream) { if (errno == EAGAIN || errno == EWOULDBLOCK) { /* Wait for the next one. */ if (stream->flags & UV_STREAM_READING) { - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); uv__stream_osx_interrupt_select(stream); } stream->read_cb(stream, 0, &buf); @@ -1168,8 +1168,8 @@ static void uv__read(uv_stream_t* stream) { stream->read_cb(stream, -errno, &buf); if (stream->flags & UV_STREAM_READING) { stream->flags &= ~UV_STREAM_READING; - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); - if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); } @@ -1230,7 +1230,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { stream->shutdown_req = req; stream->flags |= UV_STREAM_SHUTTING; - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); return 0; @@ -1255,7 +1255,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(uv__stream_fd(stream) >= 0); /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */ - if (events & (UV__POLLIN | UV__POLLERR | UV__POLLHUP)) + if (events & (POLLIN | POLLERR | POLLHUP)) uv__read(stream); if (uv__stream_fd(stream) == -1) @@ -1267,7 +1267,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { * have to do anything. If the partial read flag is not set, we can't * report the EOF yet because there is still data to read. */ - if ((events & UV__POLLHUP) && + if ((events & POLLHUP) && (stream->flags & UV_STREAM_READING) && (stream->flags & UV_STREAM_READ_PARTIAL) && !(stream->flags & UV_STREAM_READ_EOF)) { @@ -1278,7 +1278,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { if (uv__stream_fd(stream) == -1) return; /* read_cb closed stream. */ - if (events & (UV__POLLOUT | UV__POLLERR | UV__POLLHUP)) { + if (events & (POLLOUT | POLLERR | POLLHUP)) { uv__write(stream); uv__write_callbacks(stream); @@ -1327,7 +1327,7 @@ static void uv__stream_connect(uv_stream_t* stream) { uv__req_unregister(stream->loop, req); if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) { - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); } if (req->cb) @@ -1422,7 +1422,7 @@ int uv_write2(uv_write_t* req, * sufficiently flushed in uv__write. */ assert(!(stream->flags & UV_STREAM_BLOCKING)); - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); } @@ -1461,7 +1461,7 @@ int uv_try_write(uv_stream_t* stream, if (stream->connect_req != NULL || stream->write_queue_size != 0) return -EAGAIN; - has_pollout = uv__io_active(&stream->io_watcher, UV__POLLOUT); + has_pollout = uv__io_active(&stream->io_watcher, POLLOUT); r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb); if (r != 0) @@ -1485,7 +1485,7 @@ int uv_try_write(uv_stream_t* stream, /* Do not poll for writable, if we wasn't before calling this */ if (!has_pollout) { - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); } @@ -1520,7 +1520,7 @@ int uv_read_start(uv_stream_t* stream, stream->read_cb = read_cb; stream->alloc_cb = alloc_cb; - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); uv__handle_start(stream); uv__stream_osx_interrupt_select(stream); @@ -1533,8 +1533,8 @@ int uv_read_stop(uv_stream_t* stream) { return 0; stream->flags &= ~UV_STREAM_READING; - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); - if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); @@ -1621,7 +1621,7 @@ void uv__stream_close(uv_stream_t* handle) { handle->queued_fds = NULL; } - assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT)); + assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT)); } diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 9a6cc42b5..7426a102c 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -456,7 +456,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (first_run) { uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd); - uv__io_start(handle->loop, &handle->loop->fs_event_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN); } return 0; diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 6d213a497..793e4c7d6 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -181,7 +181,7 @@ int uv__tcp_connect(uv_connect_t* req, QUEUE_INIT(&req->queue); handle->connect_req = req; - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT); + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); if (handle->delayed_error) uv__io_feed(handle->loop, &handle->io_watcher); @@ -273,7 +273,7 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { /* Start listening for connections. */ tcp->io_watcher.cb = uv__server_io; - uv__io_start(tcp->loop, &tcp->io_watcher, UV__POLLIN); + uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN); return 0; } diff --git a/src/unix/udp.c b/src/unix/udp.c index 39ade8de3..4527bba1f 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -61,7 +61,7 @@ void uv__udp_finish_close(uv_udp_t* handle) { uv_udp_send_t* req; QUEUE* q; - assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT)); + assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT)); assert(handle->io_watcher.fd == -1); while (!QUEUE_EMPTY(&handle->write_queue)) { @@ -120,8 +120,8 @@ static void uv__udp_run_completed(uv_udp_t* handle) { if (QUEUE_EMPTY(&handle->write_queue)) { /* Pending queue and completion queue empty, stop watcher. */ - uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLOUT); - if (!uv__io_active(&handle->io_watcher, UV__POLLIN)) + uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT); + if (!uv__io_active(&handle->io_watcher, POLLIN)) uv__handle_stop(handle); } @@ -135,10 +135,10 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { handle = container_of(w, uv_udp_t, io_watcher); assert(handle->type == UV_UDP); - if (revents & UV__POLLIN) + if (revents & POLLIN) uv__udp_recvmsg(handle); - if (revents & UV__POLLOUT) { + if (revents & POLLOUT) { uv__udp_sendmsg(handle); uv__udp_run_completed(handle); } @@ -424,7 +424,7 @@ int uv__udp_send(uv_udp_send_t* req, if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) { uv__udp_sendmsg(handle); } else { - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT); + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); } return 0; @@ -843,7 +843,7 @@ int uv__udp_recv_start(uv_udp_t* handle, if (alloc_cb == NULL || recv_cb == NULL) return -EINVAL; - if (uv__io_active(&handle->io_watcher, UV__POLLIN)) + if (uv__io_active(&handle->io_watcher, POLLIN)) return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */ err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0); @@ -853,7 +853,7 @@ int uv__udp_recv_start(uv_udp_t* handle, handle->alloc_cb = alloc_cb; handle->recv_cb = recv_cb; - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->io_watcher, POLLIN); uv__handle_start(handle); return 0; @@ -861,9 +861,9 @@ int uv__udp_recv_start(uv_udp_t* handle, int uv__udp_recv_stop(uv_udp_t* handle) { - uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN); + uv__io_stop(handle->loop, &handle->io_watcher, POLLIN); - if (!uv__io_active(&handle->io_watcher, UV__POLLOUT)) + if (!uv__io_active(&handle->io_watcher, POLLOUT)) uv__handle_stop(handle); handle->alloc_cb = NULL; From 341097403d0301abae8a856fd36a4461c91fd08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 10 Apr 2016 12:11:51 -0300 Subject: [PATCH 128/632] doc: add ability to live reload and regenerate HTML PR-URL: https://github.com/libuv/libuv/pull/819 Reviewed-By: Ben Noordhuis --- README.md | 5 +++++ docs/Makefile | 17 +++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 17304a7ab..e94fcc902 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,11 @@ Build documentation as HTML: $ make html +Build documentation as HTML and live reload it when it changes (this requires +sphinx-autobuild to be installed and is only supported on Unix): + + $ make livehtml + Build documentation as man pages: $ make man diff --git a/docs/Makefile b/docs/Makefile index 1e0fc8f02..9d461ff8a 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -2,11 +2,12 @@ # # You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build -SRCDIR = src +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXAUTOBUILD = sphinx-autobuild +PAPER = +BUILDDIR = build +SRCDIR = src # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) @@ -20,11 +21,12 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(S # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SRCDIR) -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext +.PHONY: help clean html livehtml dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" + @echo " livehtml to make standalone HTML files and live reload them" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @@ -55,6 +57,9 @@ html: @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." +livehtml: + $(SPHINXAUTOBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo From be8e237a8e462f8517392eccf0f94a30d16d7ef3 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 11 Apr 2016 11:11:47 -0400 Subject: [PATCH 129/632] Revert "win,build: remove unused build defines" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 60db5b5a1bb446e4b8a6d15ce277d5f7987bf07a. Removing the WIN32_LEAN_AND_MEAN definition caused build errors on mingw64. Fixes: https://github.com/libuv/libuv/issues/820 PR-URL: https://github.com/libuv/libuv/pull/821 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Ben Noordhuis --- Makefile.am | 1 + Makefile.mingw | 1 + 2 files changed, 2 insertions(+) diff --git a/Makefile.am b/Makefile.am index dfd4353a3..b6925288a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,6 +43,7 @@ if WINNT include_HEADERS += include/uv-win.h include/tree.h AM_CPPFLAGS += -I$(top_srcdir)/src/win \ + -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv libuv_la_SOURCES += src/win/async.c \ diff --git a/Makefile.mingw b/Makefile.mingw index 3130bac47..156f15dab 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -20,6 +20,7 @@ CFLAGS += -Wall \ -Iinclude \ -Isrc \ -Isrc/win \ + -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 INCLUDES = include/stdint-msvc2008.h \ From 2bf7b3855c2a9c0931bf5a8bb5029a5c84d106c1 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 11 Apr 2016 17:57:19 +0200 Subject: [PATCH 130/632] linux: fix fd leaks in uv_cpu_info() error paths Introduced in commit 6798876a, "linux: fix cpu count". PR-URL: https://github.com/libuv/libuv/pull/822 Reviewed-By: Colin Ihrig --- src/unix/linux-core.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 66cb7fa6d..333dbe80e 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -591,26 +591,23 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { err = uv__cpu_num(statfile_fp, &numcpus); if (err < 0) - return err; + goto out; assert(numcpus != (unsigned int) -1); assert(numcpus != 0); + err = -ENOMEM; ci = uv__calloc(numcpus, sizeof(*ci)); if (ci == NULL) - return -ENOMEM; + goto out; err = read_models(numcpus, ci); if (err == 0) err = read_times(statfile_fp, numcpus, ci); - if (fclose(statfile_fp)) - if (errno != EINTR && errno != EINPROGRESS) - abort(); - if (err) { uv_free_cpu_info(ci, numcpus); - return err; + goto out; } /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo. @@ -621,8 +618,15 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { *cpu_infos = ci; *count = numcpus; + err = 0; - return 0; +out: + + if (fclose(statfile_fp)) + if (errno != EINTR && errno != EINPROGRESS) + abort(); + + return err; } From 732fb03ac6df5bb1c3cdd9cd67cd9319557403e3 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 11 Apr 2016 18:03:00 +0200 Subject: [PATCH 131/632] linux: don't abort on malformed /proc/stat Return an error instead of aborting when /proc/stat doesn't have the expected format. PR-URL: https://github.com/libuv/libuv/pull/822 Reviewed-By: Colin Ihrig --- src/unix/linux-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 333dbe80e..2d7124831 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -562,7 +562,7 @@ static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { char buf[1024]; if (!fgets(buf, sizeof(buf), statfile_fp)) - abort(); + return -EIO; num = 0; while (fgets(buf, sizeof(buf), statfile_fp)) { @@ -571,6 +571,9 @@ static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { num++; } + if (num == 0) + return -EIO; + *numcpus = num; return 0; } @@ -593,9 +596,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { if (err < 0) goto out; - assert(numcpus != (unsigned int) -1); - assert(numcpus != 0); - err = -ENOMEM; ci = uv__calloc(numcpus, sizeof(*ci)); if (ci == NULL) From 60ef1e7f1363e24b662088f9d7e8bb386cce8d84 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 11 Apr 2016 18:09:27 +0200 Subject: [PATCH 132/632] linux: fix long lines in linux-core.c Introduced in commit 6798876a, "linux: fix cpu count". PR-URL: https://github.com/libuv/libuv/pull/822 Reviewed-By: Colin Ihrig --- src/unix/linux-core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 2d7124831..cdb107e6d 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -74,7 +74,9 @@ #endif 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 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 unsigned long read_cpufreq(unsigned int cpunum); @@ -736,7 +738,9 @@ 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 int read_times(FILE* statfile_fp, + unsigned int numcpus, + uv_cpu_info_t* ci) { unsigned long clock_ticks; struct uv_cpu_times_s ts; unsigned long user; From f28a11229fcf3df9674c735ab542be6be6f02866 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Tue, 12 Apr 2016 19:01:25 -0400 Subject: [PATCH 133/632] test: fix fs_event_watch_file_current_dir for AIX PR-URL: https://github.com/libuv/libuv/pull/828 Reviewed-By: Ben Noordhuis --- 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 35583529e..20f489c26 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -511,7 +511,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) { r = uv_timer_init(loop, &timer); ASSERT(r == 0); - r = uv_timer_start(&timer, timer_cb_touch, 10, 0); + r = uv_timer_start(&timer, timer_cb_touch, 100, 0); ASSERT(r == 0); ASSERT(timer_cb_touch_called == 0); From 572d31599f66858b9fd25a98a799b443c61e57dc Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Tue, 12 Apr 2016 15:04:52 -0400 Subject: [PATCH 134/632] unix,fs: code cleanup of uv_fs_event_start for AIX Remove unused variables and code. Also remove some code duplication. End result is code is cleaner, readable and easier to step through when debugging. PR-URL: https://github.com/libuv/libuv/pull/825 Reviewed-By: Ben Noordhuis --- src/unix/aix.c | 57 +++++++++++++++----------------------------------- 1 file changed, 17 insertions(+), 40 deletions(-) diff --git a/src/unix/aix.c b/src/unix/aix.c index baa660f90..47c80b616 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -782,53 +782,30 @@ int uv_fs_event_start(uv_fs_event_t* handle, const char* filename, unsigned int flags) { #ifdef HAVE_SYS_AHAFS_EVPRODS_H - int fd, rc, i = 0, res = 0; + int fd, rc, str_offset = 0; char cwd[PATH_MAX]; char absolute_path[PATH_MAX]; - char fname[PATH_MAX]; - char *p; + char readlink_cwd[PATH_MAX]; - /* Clean all the buffers*/ - for(i = 0; i < PATH_MAX; i++) { - cwd[i] = 0; - absolute_path[i] = 0; - fname[i] = 0; - } - i = 0; /* Figure out whether filename is absolute or not */ if (filename[0] == '/') { - /* We have absolute pathname, create the relative pathname*/ - sprintf(absolute_path, filename); - p = strrchr(filename, '/'); - p++; + /* We have absolute pathname */ + snprintf(absolute_path, sizeof(absolute_path), "%s", filename); } else { - if (filename[0] == '.' && filename[1] == '/') { - /* We have a relative pathname, compose the absolute pathname */ - sprintf(fname, filename); - snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); - res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1); - if (res < 0) - return res; - p = strrchr(absolute_path, '/'); - p++; - p++; - } else { - /* We have a relative pathname, compose the absolute pathname */ - sprintf(fname, filename); - snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); - res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1); - if (res < 0) - return res; - p = strrchr(absolute_path, '/'); - p++; - } - /* Copy to filename buffer */ - while(filename[i] != NULL) { - *p = filename[i]; - i++; - p++; - } + /* We have a relative pathname, compose the absolute pathname */ + snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid()); + rc = readlink(cwd, readlink_cwd, sizeof(readlink_cwd) - 1); + if (rc < 0) + return rc; + /* readlink does not null terminate our string */ + readlink_cwd[rc] = '\0'; + + if (filename[0] == '.' && filename[1] == '/') + str_offset = 2; + + snprintf(absolute_path, sizeof(absolute_path), "%s%s", readlink_cwd, + filename + str_offset); } if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */ From 4a5b3f982efbdee8f458ceec3a6fb18c6573a4b6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 7 Nov 2015 00:26:44 +0100 Subject: [PATCH 135/632] unix: delay signal handling until after normal i/o MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was reported that some node.js tests fail on AIX because the exit event sometimes comes before the final stdio output of a child process. Work around that by deferring the signal watcher that is used for process management until after the dispatch of regular i/o watchers. Fixes: https://github.com/libuv/libuv/issues/610 PR-URL: https://github.com/libuv/libuv/pull/611 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/aix.c | 17 ++++++++++++++++- src/unix/kqueue.c | 18 +++++++++++++++++- src/unix/linux-core.c | 18 +++++++++++++++++- src/unix/sunos.c | 18 +++++++++++++++++- 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/unix/aix.c b/src/unix/aix.c index 47c80b616..27736590b 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -118,6 +118,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { uv__io_t* w; uint64_t base; uint64_t diff; + int have_signals; int nevents; int count; int nfds; @@ -225,6 +226,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { goto update_timeout; } + have_signals = 0; nevents = 0; assert(loop->watchers != NULL); @@ -255,13 +257,26 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { continue; } - w->cb(loop, w, pe->revents); + /* 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 + w->cb(loop, w, pe->revents); + nevents++; } + if (have_signals != 0) + 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. */ diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 588666d35..fffd4626f 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -78,6 +78,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { sigset_t set; uint64_t base; uint64_t diff; + int have_signals; int filter; int fflags; int count; @@ -192,6 +193,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { goto update_timeout; } + have_signals = 0; nevents = 0; assert(loop->watchers != NULL); @@ -265,12 +267,26 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (revents == 0) continue; - w->cb(loop, w, revents); + /* 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 + w->cb(loop, w, revents); + nevents++; } + + if (have_signals != 0) + 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. */ diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index cdb107e6d..b48a11117 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -188,6 +188,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { sigset_t sigset; uint64_t sigmask; uint64_t base; + int have_signals; int nevents; int count; int nfds; @@ -315,6 +316,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { goto update_timeout; } + have_signals = 0; nevents = 0; assert(loop->watchers != NULL); @@ -369,13 +371,27 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { pe->events |= w->pevents & (POLLIN | POLLOUT); if (pe->events != 0) { - 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 + w->cb(loop, w, pe->events); + nevents++; } } + + if (have_signals != 0) + 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. */ diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 7426a102c..e67be8fcf 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -140,6 +140,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { unsigned int nfds; unsigned int i; int saved_errno; + int have_signals; int nevents; int count; int err; @@ -230,6 +231,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { return; } + have_signals = 0; nevents = 0; assert(loop->watchers != NULL); @@ -252,7 +254,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (w == NULL) continue; - w->cb(loop, w, pe->portev_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 + w->cb(loop, w, pe->portev_events); + nevents++; if (w != loop->watchers[fd]) @@ -262,9 +271,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); } + + if (have_signals != 0) + 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 70d5014266ec6659e9a9a7c8f9ba320385c9caec Mon Sep 17 00:00:00 2001 From: Oguz Bastemur Date: Thu, 14 Apr 2016 14:35:23 +0200 Subject: [PATCH 136/632] android: pthread_sigmask() does not set errno Originally intended workaround is especially needed for Android <4.4. However it fails to compare errno collected from pthread_sigmask. This has been fixed separately in JXcore. See issue: https://github.com/jxcore/jxcore-cordova/issues/55 PR-URL: https://github.com/libuv/libuv/pull/833 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/unix/pthread-fixes.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/unix/pthread-fixes.c b/src/unix/pthread-fixes.c index 3a71eb5aa..0c4a47516 100644 --- a/src/unix/pthread-fixes.c +++ b/src/unix/pthread-fixes.c @@ -39,19 +39,23 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { static int workaround; + int err; if (workaround) { return sigprocmask(how, set, oset); - } else if (pthread_sigmask(how, set, oset)) { - if (errno == EINVAL && sigprocmask(how, set, oset) == 0) { - workaround = 1; - return 0; - } else { - return -1; - } } else { - return 0; + err = pthread_sigmask(how, set, oset); + if (err) { + if (err == EINVAL && sigprocmask(how, set, oset) == 0) { + workaround = 1; + return 0; + } else { + return -1; + } + } } + + return 0; } /*Android doesn't provide pthread_barrier_t for now.*/ From d03abfd4007f5b073c406a0d3afe37e6d8407f49 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 1 Dec 2015 17:41:38 +0100 Subject: [PATCH 137/632] win: work around sharepoint scandir bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It has been reported that for SharePoint connections mapped as a drive, uv_fs_scandir() returns "." and ".." entries when the expectation is that they should be filtered out. After some investigation it looks like the driver returns ".\0" and "..\0" for those entries, that is, it includes the zero byte in the filename length. Rewrite the filter to catch those entries as well. Fixes: https://github.com/nodejs/node/issues/4002 PR-URL: https://github.com/libuv/libuv/pull/636 Reviewed-By: Alexis Campailla Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/win/fs.c b/src/win/fs.c index 16e3ae7cf..fd2547e94 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -901,7 +901,15 @@ void fs__scandir(uv_fs_t* req) { /* Compute the length of the filename in WCHARs. */ wchar_len = info->FileNameLength / sizeof info->FileName[0]; - /* Skip over '.' and '..' entries. */ + /* Skip over '.' and '..' entries. It has been reported that + * the SharePoint driver includes the terminating zero byte in + * the filename length. Strip those first. + */ + while (wchar_len > 0 && info->FileName[wchar_len - 1] == L'\0') + wchar_len -= 1; + + if (wchar_len == 0) + continue; if (wchar_len == 1 && info->FileName[0] == L'.') continue; if (wchar_len == 2 && info->FileName[0] == L'.' && From 322de63a9b6618ec615c2db31cc93bfc87760f96 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 18 Apr 2016 12:20:17 +0200 Subject: [PATCH 138/632] unix: guard against clobbering errno in uv__free() Libuv expects that free() does not clobber errno. The system allocator honors that assumption but custom allocators may not be so careful. PR-URL: https://github.com/libuv/libuv/pull/837 Reviewed-By: Colin Ihrig --- src/unix/freebsd.c | 8 ++++---- src/unix/openbsd.c | 4 ++-- src/uv-common.c | 10 +++++++++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index b747abdf5..adc95235c 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -292,7 +292,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(cpuspeed); if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(*cpu_infos); return -errno; } @@ -301,7 +301,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { */ size = sizeof(maxcpus); if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(*cpu_infos); return -errno; } @@ -314,8 +314,8 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { } if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(cp_times)); - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(cp_times); + uv__free(*cpu_infos); return -errno; } diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index 6a3909a66..8c40bde40 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -247,7 +247,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { which[1] = HW_CPUSPEED; size = sizeof(cpuspeed); if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(*cpu_infos); return -errno; } @@ -258,7 +258,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { which[2] = i; size = sizeof(info); if (sysctl(which, 3, &info, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(*cpu_infos); return -errno; } diff --git a/src/uv-common.c b/src/uv-common.c index 6b8c584fb..074383d28 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -22,10 +22,11 @@ #include "uv.h" #include "uv-common.h" -#include #include +#include #include #include /* NULL */ +#include #include /* malloc */ #include /* memset */ @@ -75,7 +76,14 @@ void* uv__malloc(size_t size) { } void uv__free(void* ptr) { + int saved_errno; + + /* Libuv expects that free() does not clobber errno. The system allocator + * honors that assumption but custom allocators may not be so careful. + */ + saved_errno = errno; uv__allocator.local_free(ptr); + errno = saved_errno; } void* uv__calloc(size_t count, size_t size) { From b9324acb75153cfd386d4dd6433b19b69ff6d99e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 18 Apr 2016 12:23:09 +0200 Subject: [PATCH 139/632] unix: remove unneeded SAVE_ERRNO wrappers uv__close() won't clobber errno so there is no need to guard calls with a SAVE_ERRNO(...) wrapper. PR-URL: https://github.com/libuv/libuv/pull/837 Reviewed-By: Colin Ihrig --- src/unix/aix.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/unix/aix.c b/src/unix/aix.c index 27736590b..2276985fc 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -1028,14 +1028,14 @@ int uv_interface_addresses(uv_interface_address_t** addresses, } if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { - SAVE_ERRNO(uv__close(sockfd)); + uv__close(sockfd); return -errno; } ifc.ifc_req = (struct ifreq*)uv__malloc(size); ifc.ifc_len = size; if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { - SAVE_ERRNO(uv__close(sockfd)); + uv__close(sockfd); return -errno; } @@ -1054,7 +1054,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { - SAVE_ERRNO(uv__close(sockfd)); + uv__close(sockfd); return -errno; } From faea76d81d3cb827de2d16cc0ace53fc240db060 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Tue, 19 Apr 2016 18:25:54 -0400 Subject: [PATCH 140/632] test: skip fs_event_close_in_callback on AIX The file descriptor that you receive from ahafs has to be part of the pollset_poll set of interest in order to receive events. This does not happen until we are in the event loop causing the test to hang and therefore timeout. PR-URL: https://github.com/libuv/libuv/pull/838 Reviewed-By: Ben Noordhuis --- test/test-fs-event.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 20f489c26..353c43b0d 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -698,18 +698,19 @@ TEST_IMPL(fs_event_close_with_pending_event) { return 0; } -#if defined(HAVE_KQUEUE) +#if defined(HAVE_KQUEUE) || defined(_AIX) /* kqueue doesn't register fs events if you don't have an active watcher. * The file descriptor needs to be part of the kqueue set of interest and * that's not the case until we actually enter the event loop. + * This is also observed on AIX with ahafs. */ TEST_IMPL(fs_event_close_in_callback) { - fprintf(stderr, "Skipping test, doesn't work with kqueue.\n"); + fprintf(stderr, "Skipping test, doesn't work with kqueue and AIX.\n"); return 0; } -#else /* !HAVE_KQUEUE */ +#else /* !HAVE_KQUEUE || !_AIX */ static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, int events, int status) { @@ -766,7 +767,7 @@ TEST_IMPL(fs_event_close_in_callback) { return 0; } -#endif /* HAVE_KQUEUE */ +#endif /* HAVE_KQUEUE || _AIX */ TEST_IMPL(fs_event_start_and_close) { uv_loop_t* loop; From 6f17a617da4065552e899578c73f516255d83dfb Mon Sep 17 00:00:00 2001 From: Robert Jefe Lindstaedt Date: Mon, 4 Apr 2016 22:32:29 +0200 Subject: [PATCH 141/632] win: add maxrss, pagefaults to uv_getrusage() This commit populates the ru_majflt and ru_maxrss fields of uv_getrusage() on Windows. PR-URL: https://github.com/libuv/libuv/pull/805 Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis --- src/win/util.c | 11 +++++++++++ test/test-platform-output.c | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/src/win/util.c b/src/win/util.c index 1788b1780..b4690f63a 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1118,6 +1118,7 @@ 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; int ret; ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime); @@ -1135,6 +1136,13 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { return uv_translate_sys_error(GetLastError()); } + ret = GetProcessMemoryInfo(GetCurrentProcess(), + &memCounters, + sizeof(memCounters)); + 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 + @@ -1147,6 +1155,9 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { kernelSystemTime.wSecond; uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000; + uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; + uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; + return 0; } diff --git a/test/test-platform-output.c b/test/test-platform-output.c index 2c4740550..4d43b4381 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -61,6 +61,8 @@ TEST_IMPL(platform_output) { ASSERT(rusage.ru_utime.tv_usec >= 0); ASSERT(rusage.ru_stime.tv_sec >= 0); ASSERT(rusage.ru_stime.tv_usec >= 0); + ASSERT(rusage.ru_majflt >= 0); + ASSERT(rusage.ru_maxrss >= 0); printf("uv_getrusage:\n"); printf(" user: %llu sec %llu microsec\n", (unsigned long long) rusage.ru_utime.tv_sec, @@ -68,6 +70,8 @@ TEST_IMPL(platform_output) { 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", rusage.ru_majflt); + printf(" maximum resident set size: %llu\n", rusage.ru_maxrss); err = uv_cpu_info(&cpus, &count); ASSERT(err == 0); From 5c6c2681824ef825040fafa54157544696b8ef4c Mon Sep 17 00:00:00 2001 From: Andrius Bentkus Date: Thu, 17 Mar 2016 08:32:27 +0200 Subject: [PATCH 142/632] test: set a big send buffer size for tcp_write_queue_order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We set the maximum buffer size of the client socket to a specific value so unreasonable OS settings won't trigger assert failures. Fixes: https://github.com/libuv/libuv/issues/764 Refs: https://github.com/libuv/libuv/pull/767 PR-URL: https://github.com/libuv/libuv/pull/768 Reviewed-By: Saúl Ibarra Corretgé --- test/test-tcp-write-queue-order.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test-tcp-write-queue-order.c b/test/test-tcp-write-queue-order.c index aa4d2acc2..8a98ab836 100644 --- a/test/test-tcp-write-queue-order.c +++ b/test/test-tcp-write-queue-order.c @@ -107,6 +107,7 @@ static void start_server(void) { TEST_IMPL(tcp_write_queue_order) { uv_connect_t connect_req; struct sockaddr_in addr; + int buffer_size = 16 * 1024; start_server(); @@ -117,6 +118,7 @@ TEST_IMPL(tcp_write_queue_order) { &client, (struct sockaddr*) &addr, connect_cb)); + ASSERT(0 == uv_send_buffer_size((uv_handle_t*) &client, &buffer_size)); ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); ASSERT(0 == uv_timer_start(&timer, timer_cb, 100, 0)); From f617ccc64408e36250216b02e61373cfdbccf98b Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Mon, 25 Apr 2016 09:07:37 -0700 Subject: [PATCH 143/632] unix: error on realpath if PATH_MAX is undefined MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently when PATH_MAX is undefined realpath will default to using 4096. There is a potential stack overflow attack that can be mitigated by having PATH_MAX defined. This change conservatively errors if a system does not have PATH_MAX defined. This change also explicitly includes `limits.h` to ensure that all platforms have PATH_MAX defined if it is available. Ref: http://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html Refs: https://github.com/nodejs/node/issues/2680#issuecomment-213521708 PR-URL: https://github.com/libuv/libuv/pull/843 Reviewed-By: Colin Ihrig Reviewed-By: Fedor Indutny Reviewed-By: Saúl Ibarra Corretgé --- 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 419961c05..5235d8652 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -33,6 +33,7 @@ #include #include #include +#include /* PATH_MAX */ #include #include @@ -390,7 +391,7 @@ static ssize_t uv__fs_pathmax_size(const char* path) { #if defined(PATH_MAX) return PATH_MAX; #else - return 4096; +#error "PATH_MAX undefined in the current platform" #endif } From f57bfd4dca7f2b736027a3a41384cea5ab34b39c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A1ri=20Tristan=20Helgason?= Date: Sat, 19 Mar 2016 11:21:37 +0000 Subject: [PATCH 144/632] unix: fix bug in barrier fallback implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was a memory corruption issue with the pthread barrier implementation on android, where a barrier could still be in use by one thread when being freed by another. This fixes that issue and adds lots of missing error handling. This implementation is now also used for the OSX fallback. Fixes: https://github.com/libuv/libuv/issues/615 PR-URL: https://github.com/libuv/libuv/pull/790 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Ben Noordhuis --- Makefile.am | 11 ++-- include/pthread-barrier.h | 64 ++++++++++++++++++++ include/pthread-fixes.h | 72 ---------------------- include/uv-unix.h | 21 ++----- src/unix/internal.h | 8 +++ src/unix/pthread-barrier.c | 120 +++++++++++++++++++++++++++++++++++++ src/unix/pthread-fixes.c | 54 +---------------- src/unix/thread.c | 68 --------------------- uv.gyp | 4 +- 9 files changed, 207 insertions(+), 215 deletions(-) create mode 100644 include/pthread-barrier.h delete mode 100644 include/pthread-fixes.h create mode 100644 src/unix/pthread-barrier.c diff --git a/Makefile.am b/Makefile.am index b6925288a..88b536248 100644 --- a/Makefile.am +++ b/Makefile.am @@ -291,20 +291,23 @@ endif if ANDROID include_HEADERS += include/android-ifaddrs.h \ - include/pthread-fixes.h + include/pthread-barrier.h libuv_la_SOURCES += src/unix/android-ifaddrs.c \ - src/unix/pthread-fixes.c + src/unix/pthread-fixes.c \ + src/unix/pthread-barrier.c endif if DARWIN -include_HEADERS += include/uv-darwin.h +include_HEADERS += include/uv-darwin.h \ + include/pthread-barrier.h libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1 libuv_la_SOURCES += src/unix/darwin.c \ src/unix/darwin-proctitle.c \ src/unix/fsevents.c \ src/unix/kqueue.c \ - src/unix/proctitle.c + src/unix/proctitle.c \ + src/unix/pthread-barrier.c test_run_tests_LDFLAGS += -lutil endif diff --git a/include/pthread-barrier.h b/include/pthread-barrier.h new file mode 100644 index 000000000..084e1c2d5 --- /dev/null +++ b/include/pthread-barrier.h @@ -0,0 +1,64 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason + +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_PTHREAD_BARRIER_ +#define _UV_PTHREAD_BARRIER_ +#include +#include +#include /* sem_t */ + +#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 + +/* + * To maintain ABI compatibility with + * libuv v1.x struct is padded according + * to target platform + */ +#if defined(__ANDROID__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + sizeof(pthread_cond_t) + \ + sizeof(unsigned int) - \ + sizeof(void *) +#elif defined(__APPLE__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + 2 * sizeof(sem_t) + \ + 2 * sizeof(unsigned int) - \ + sizeof(void *) +#endif + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + unsigned threshold; + unsigned in; + unsigned out; +} _uv_barrier; + +typedef struct { + _uv_barrier* b; + char _pad[UV_BARRIER_STRUCT_PADDING]; +} pthread_barrier_t; + +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count); + +int pthread_barrier_wait(pthread_barrier_t* barrier); +int pthread_barrier_destroy(pthread_barrier_t *barrier); + +#endif /* _UV_PTHREAD_BARRIER_ */ diff --git a/include/pthread-fixes.h b/include/pthread-fixes.h deleted file mode 100644 index 88c6b6698..000000000 --- a/include/pthread-fixes.h +++ /dev/null @@ -1,72 +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. -*/ - -#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H -#define GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H - -#include - - -/*Android doesn't provide pthread_barrier_t for now.*/ -#ifndef PTHREAD_BARRIER_SERIAL_THREAD - -/* Anything except 0 will do here.*/ -#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 - -typedef struct { - pthread_mutex_t mutex; - pthread_cond_t cond; - unsigned count; -} pthread_barrier_t; - -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* barrier_attr, - unsigned count); - -int pthread_barrier_wait(pthread_barrier_t* barrier); -int pthread_barrier_destroy(pthread_barrier_t *barrier); -#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */ - -int pthread_yield(void); - -/* Workaround pthread_sigmask() returning EINVAL on versions < 4.1 by - * replacing all calls to pthread_sigmask with sigprocmask. See: - * https://android.googlesource.com/platform/bionic/+/9bf330b5 - * https://code.google.com/p/android/issues/detail?id=15337 - */ -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 /* GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H */ diff --git a/include/uv-unix.h b/include/uv-unix.h index 82d193bdc..a852c40e4 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -38,9 +38,6 @@ #include #include -#ifdef __ANDROID__ -#include "pthread-fixes.h" -#endif #include #include "uv-threadpool.h" @@ -60,6 +57,10 @@ # include "uv-bsd.h" #endif +#ifndef PTHREAD_BARRIER_SERIAL_THREAD +# include "pthread-barrier.h" +#endif + #ifndef NI_MAXHOST # define NI_MAXHOST 1025 #endif @@ -136,22 +137,8 @@ typedef pthread_rwlock_t uv_rwlock_t; typedef UV_PLATFORM_SEM_T uv_sem_t; typedef pthread_cond_t uv_cond_t; typedef pthread_key_t uv_key_t; - -#if defined(__APPLE__) && defined(__MACH__) - -typedef struct { - unsigned int n; - unsigned int count; - uv_mutex_t mutex; - uv_sem_t turnstile1; - uv_sem_t turnstile2; -} uv_barrier_t; - -#else /* defined(__APPLE__) && defined(__MACH__) */ - typedef pthread_barrier_t uv_barrier_t; -#endif /* defined(__APPLE__) && defined(__MACH__) */ /* Platform-specific definitions for uv_spawn support. */ typedef gid_t uv_gid_t; diff --git a/src/unix/internal.h b/src/unix/internal.h index 2c3421f91..670b14bc2 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -55,6 +55,14 @@ # include #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-barrier.c b/src/unix/pthread-barrier.c new file mode 100644 index 000000000..f57bf2508 --- /dev/null +++ b/src/unix/pthread-barrier.c @@ -0,0 +1,120 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason + +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. +*/ +#include "uv-common.h" +#include "pthread-barrier.h" + +#include +#include + +/* TODO: support barrier_attr */ +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || count == 0) + return EINVAL; + + if (barrier_attr != NULL) + return ENOTSUP; + + b = uv__malloc(sizeof(*b)); + if (b == NULL) + return ENOMEM; + + b->in = 0; + b->out = 0; + b->threshold = count; + + if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) + goto error2; + if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) + goto error; + + barrier->b = b; + return 0; + +error: + pthread_mutex_destroy(&b->mutex); +error2: + uv__free(b); + return rc; +} + +int pthread_barrier_wait(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + /* Lock the mutex*/ + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + /* Increment the count. If this is the first thread to reach the threshold, + wake up waiters, unlock the mutex, then return + PTHREAD_BARRIER_SERIAL_THREAD. */ + if (++b->in == b->threshold) { + b->in = 0; + b->out = b->threshold - 1; + assert(pthread_cond_signal(&b->cond) == 0); + + pthread_mutex_unlock(&b->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + /* Otherwise, wait for other threads until in is set to 0, + then return 0 to indicate this is not the first thread. */ + do { + if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) + break; + } while (b->in != 0); + + /* mark thread exit */ + b->out--; + pthread_cond_signal(&b->cond); + pthread_mutex_unlock(&b->mutex); + return rc; +} + +int pthread_barrier_destroy(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + if (b->in > 0 || b->out > 0) + rc = EBUSY; + + pthread_mutex_unlock(&b->mutex); + + if (rc) + return rc; + + pthread_cond_destroy(&b->cond); + pthread_mutex_destroy(&b->mutex); + uv__free(barrier->b); + barrier->b = NULL; + return 0; +} diff --git a/src/unix/pthread-fixes.c b/src/unix/pthread-fixes.c index 0c4a47516..fb1799584 100644 --- a/src/unix/pthread-fixes.c +++ b/src/unix/pthread-fixes.c @@ -29,10 +29,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* Android versions < 4.1 have a broken pthread_sigmask. - * Note that this block of code must come before any inclusion of - * pthread-fixes.h so that the real pthread_sigmask can be referenced. - * */ +/* Android versions < 4.1 have a broken pthread_sigmask. */ #include #include #include @@ -57,52 +54,3 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { return 0; } - -/*Android doesn't provide pthread_barrier_t for now.*/ -#ifndef PTHREAD_BARRIER_SERIAL_THREAD - -#include "pthread-fixes.h" - -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* barrier_attr, - unsigned count) { - barrier->count = count; - pthread_mutex_init(&barrier->mutex, NULL); - pthread_cond_init(&barrier->cond, NULL); - return 0; -} - -int pthread_barrier_wait(pthread_barrier_t* barrier) { - /* Lock the mutex*/ - pthread_mutex_lock(&barrier->mutex); - /* Decrement the count. If this is the first thread to reach 0, wake up - waiters, unlock the mutex, then return PTHREAD_BARRIER_SERIAL_THREAD.*/ - if (--barrier->count == 0) { - /* First thread to reach the barrier */ - pthread_cond_broadcast(&barrier->cond); - pthread_mutex_unlock(&barrier->mutex); - return PTHREAD_BARRIER_SERIAL_THREAD; - } - /* Otherwise, wait for other threads until the count reaches 0, then - return 0 to indicate this is not the first thread.*/ - do { - pthread_cond_wait(&barrier->cond, &barrier->mutex); - } while (barrier->count > 0); - - pthread_mutex_unlock(&barrier->mutex); - return 0; -} - -int pthread_barrier_destroy(pthread_barrier_t *barrier) { - barrier->count = 0; - pthread_cond_destroy(&barrier->cond); - pthread_mutex_destroy(&barrier->mutex); - return 0; -} - -#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */ - -int pthread_yield(void) { - sched_yield(); - return 0; -} diff --git a/src/unix/thread.c b/src/unix/thread.c index c35bc926b..b1fb02bd2 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -34,7 +34,6 @@ #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) - struct thread_ctx { void (*entry)(void* arg); void* arg; @@ -448,72 +447,6 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { } -#if defined(__APPLE__) && defined(__MACH__) - -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; -} - -#else /* !(defined(__APPLE__) && defined(__MACH__)) */ - int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { return -pthread_barrier_init(barrier, NULL, count); } @@ -532,7 +465,6 @@ int uv_barrier_wait(uv_barrier_t* barrier) { return r == PTHREAD_BARRIER_SERIAL_THREAD; } -#endif /* defined(__APPLE__) && defined(__MACH__) */ int uv_key_create(uv_key_t* key) { return -pthread_key_create(key, NULL); diff --git a/uv.gyp b/uv.gyp index 757540193..2c815331a 100644 --- a/uv.gyp +++ b/uv.gyp @@ -184,6 +184,7 @@ 'src/unix/darwin.c', 'src/unix/fsevents.c', 'src/unix/darwin-proctitle.c', + 'src/unix/pthread-barrier.c' ], 'defines': [ '_DARWIN_USE_64_BIT_INODE=1', @@ -214,7 +215,8 @@ 'src/unix/linux-syscalls.c', 'src/unix/linux-syscalls.h', 'src/unix/pthread-fixes.c', - 'src/unix/android-ifaddrs.c' + 'src/unix/android-ifaddrs.c', + 'src/unix/pthread-barrier.c' ], 'link_settings': { 'libraries': [ '-ldl' ], From 4b342554b57013efb2db6fd81d6cb3f6c678fc52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A1ri=20Tristan=20Helgason?= Date: Sat, 19 Mar 2016 11:21:37 +0000 Subject: [PATCH 145/632] build: bump android ndk version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/790 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Ben Noordhuis --- android-configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android-configure b/android-configure index e0b250fb6..7ffc035c1 100755 --- a/android-configure +++ b/android-configure @@ -3,7 +3,7 @@ export TOOLCHAIN=$PWD/android-toolchain mkdir -p $TOOLCHAIN $1/build/tools/make-standalone-toolchain.sh \ - --toolchain=arm-linux-androideabi-4.8 \ + --toolchain=arm-linux-androideabi-4.9 \ --arch=arm \ --install-dir=$TOOLCHAIN \ --platform=android-21 @@ -14,7 +14,7 @@ export CXX=arm-linux-androideabi-g++ export LINK=arm-linux-androideabi-g++ export PLATFORM=android -if [ $2 -a $2 == 'gyp' ] +if [[ $2 == 'gyp' ]] then ./gyp_uv.py -Dtarget_arch=arm -DOS=android -f make-android fi From 4844c75de8d6fefd6efb1ac7e6050a07160e8eec Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 29 Apr 2016 12:43:52 +0200 Subject: [PATCH 146/632] build: always compile with -fvisibility=hidden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'visibility%' gyp variable was designed as an override mechanism for old (<=3.4) versions of gcc that don't know about -fvisibility=hidden. It turns out it's fairly easy for embedders to muck up the define, as witnessed by the fact that node.js is currently leaking internal libuv symbols due to not properly setting 'visibility%'. While that could be fixed by tweaking node.js, because we don't support gcc 3.4 anymore and haven't for a long time, making -fvisibility=hidden the default here seems all around easier. PR-URL: https://github.com/libuv/libuv/pull/847 Reviewed-By: Saúl Ibarra Corretgé --- common.gypi | 7 ------- uv.gyp | 2 ++ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/common.gypi b/common.gypi index 7cebcde5f..56bca2948 100644 --- a/common.gypi +++ b/common.gypi @@ -1,6 +1,5 @@ { 'variables': { - 'visibility%': 'hidden', # V8's visibility setting 'target_arch%': 'ia32', # set v8's target architecture 'host_arch%': 'ia32', # set v8's host architecture 'uv_library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds @@ -156,9 +155,6 @@ 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], - [ 'visibility=="hidden"', { - 'cflags': [ '-fvisibility=hidden' ], - }], ], }], ['OS=="mac"', { @@ -170,9 +166,6 @@ 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions 'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings - # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden - 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', - 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics 'PREBINDING': 'NO', # No -Wl,-prebind 'USE_HEADERMAP': 'NO', diff --git a/uv.gyp b/uv.gyp index 2c815331a..42a1a7f1e 100644 --- a/uv.gyp +++ b/uv.gyp @@ -17,6 +17,7 @@ }], ], 'xcode_settings': { + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden 'WARNING_CFLAGS': [ '-Wall', '-Wextra', '-Wno-unused-parameter' ], 'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ], } @@ -117,6 +118,7 @@ }, }, { # Not Windows i.e. POSIX 'cflags': [ + '-fvisibility=hidden', '-g', '--std=gnu89', '-pedantic', From 2753bc1fc88843a7c1cad37e8bf12572ac03c3e8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 29 Apr 2016 17:22:14 +0200 Subject: [PATCH 147/632] test: fix -Wformat warnings in platform test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cast the `ru_majflt` and `ru_maxrss` field to `unsigned long long` when printing them with `"%llu"`. Warnings introduced in commit 6f17a61 ("win: add maxrss, pagefaults to uv_getrusage()".) PR-URL: https://github.com/libuv/libuv/pull/855 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- test/test-platform-output.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/test-platform-output.c b/test/test-platform-output.c index 4d43b4381..bd61454fa 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -70,8 +70,9 @@ TEST_IMPL(platform_output) { 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", rusage.ru_majflt); - printf(" maximum resident set size: %llu\n", rusage.ru_maxrss); + 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_cpu_info(&cpus, &count); ASSERT(err == 0); From d43ee0eafa3605d8e4edc1c405a7a08baf00993d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 5 May 2016 17:49:59 +0100 Subject: [PATCH 148/632] win: clarify fsevents handling code The code for handling fs events is quite complex, this commits tries to make it easier to follow. First, there are 2 cases in which we use the name of the file straight from the event (when watching a directory): - if we cannot create the long path - if the file got renamed or removed So separate this logically, even if the code we need is the same. Second, one way or anothwer we will always have some filename to report, so remove an unnecessary if. Third, nullify filenamew, to avoid having a dangling pointer, should the code change. PR-URL: https://github.com/libuv/libuv/pull/858 Reviewed-By: Colin Ihrig --- src/win/fs-event.c | 66 ++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index c30b55312..6b7d1d933 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -349,7 +349,8 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, FILE_NOTIFY_INFORMATION* file_info; int err, sizew, size; char* filename = NULL; - WCHAR* filenamew, *long_filenamew = NULL; + WCHAR* filenamew = NULL; + WCHAR* long_filenamew = NULL; DWORD offset = 0; assert(req->type == UV_FS_EVENT_REQ); @@ -374,6 +375,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, do { file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset); assert(!filename); + assert(!filenamew); assert(!long_filenamew); /* @@ -438,14 +440,17 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv__free(long_filenamew); long_filenamew = filenamew; sizew = -1; + } else { + /* We couldn't get the long filename, use the one reported. */ + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); } - } - /* - * Removed or renamed events cannot be resolved to the long form. - * We therefore use the name given by ReadDirectoryChangesW. - * This may be the long form or the 8.3 short name in some cases. - */ - if (!long_filenamew) { + } else { + /* + * Removed or renamed events cannot be resolved to the long form. + * We therefore use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. + */ filenamew = file_info->FileName; sizew = file_info->FileNameLength / sizeof(WCHAR); } @@ -455,36 +460,34 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, sizew = -1; } - if (filenamew) { - /* Convert the filename to utf8. */ + /* Convert the filename to utf8. */ + size = WideCharToMultiByte(CP_UTF8, + 0, + filenamew, + sizew, + NULL, + 0, + NULL, + NULL); + if (size) { + filename = (char*)uv__malloc(size + 1); + if (!filename) { + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + } + size = WideCharToMultiByte(CP_UTF8, 0, filenamew, sizew, - NULL, - 0, + filename, + size, NULL, NULL); if (size) { - filename = (char*)uv__malloc(size + 1); - if (!filename) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - size = WideCharToMultiByte(CP_UTF8, - 0, - filenamew, - sizew, - filename, - size, - NULL, - NULL); - if (size) { - filename[size] = '\0'; - } else { - uv__free(filename); - filename = NULL; - } + filename[size] = '\0'; + } else { + uv__free(filename); + filename = NULL; } } @@ -505,6 +508,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, filename = NULL; uv__free(long_filenamew); long_filenamew = NULL; + filenamew = NULL; } offset = file_info->NextEntryOffset; From 337e9fd0f5ea7b17bad39a94cf2452aac59b410a Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Wed, 4 May 2016 17:26:33 -0400 Subject: [PATCH 149/632] test: fix POLLHDRUP related failures for AIX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `POLLHDRUP` is not implemented on AIX. Therefore `UV_DISCONNECT` will never be set on `events`. This causes the socket to never be closed and the tests to be stuck inside `pollset_poll` indefinitely, resulting in a timeout. This fixes the following tests: - poll_duplex - poll_unidirectional Updated docs to let end users know that `UV_DISCONNECT` can be set, but is unsupported on AIX. Fixes: https://github.com/libuv/libuv/issues/844 PR-URL: https://github.com/libuv/libuv/pull/857 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- docs/src/poll.rst | 6 ++++++ test/test-poll.c | 11 ++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/src/poll.rst b/docs/src/poll.rst index 69d45be6d..004ff4b92 100644 --- a/docs/src/poll.rst +++ b/docs/src/poll.rst @@ -31,6 +31,8 @@ closed immediately after a call to :c:func:`uv_poll_stop` or :c:func:`uv_close`. On windows only sockets can be polled with poll handles. On Unix any file descriptor that would be accepted by :man:`poll(2)` can be used. +.. note:: + On AIX, watching for disconnection is not supported. Data types ---------- @@ -101,6 +103,10 @@ API Calling :c:func:`uv_poll_start` on a handle that is already active is fine. Doing so will update the events mask that is being watched for. + .. note:: + Though UV_DISCONNECT can be set, it is unsupported on AIX and as such will not be set + on the `events` field in the callback. + .. versionchanged:: 1.9.0 Added the UV_DISCONNECT event. .. c:function:: int uv_poll_stop(uv_poll_t* poll) diff --git a/test/test-poll.c b/test/test-poll.c index bfb75af13..f3cfe7977 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -72,8 +72,9 @@ static int closed_connections = 0; static int valid_writable_wakeups = 0; static int spurious_writable_wakeups = 0; +#ifndef _AIX static int disconnects = 0; - +#endif /* !_AIX */ static int got_eagain(void) { #ifdef _WIN32 @@ -377,7 +378,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { new_events &= ~UV_WRITABLE; } } - +#ifndef _AIX if (events & UV_DISCONNECT) { context->got_disconnect = 1; ++disconnects; @@ -385,6 +386,9 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { } if (context->got_fin && context->sent_fin && context->got_disconnect) { +#else /* _AIX */ + if (context->got_fin && context->sent_fin) { +#endif /* !_AIx */ /* Sent and received FIN. Close and destroy context. */ close_socket(context->sock); destroy_connection_context(context); @@ -552,8 +556,9 @@ static void start_poll_test(void) { spurious_writable_wakeups > 20); ASSERT(closed_connections == NUM_CLIENTS * 2); +#ifndef _AIX ASSERT(disconnects == NUM_CLIENTS * 2); - +#endif MAKE_VALGRIND_HAPPY(); } From 9386f2ca94b1218c159661a83070f560a2022443 Mon Sep 17 00:00:00 2001 From: Tony Theodore Date: Tue, 12 Apr 2016 11:06:36 +1000 Subject: [PATCH 150/632] build, mingw: set LIBS in configure.ac MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of doing it instead Makefile.am, this fixes libuv.pc on MinGW. Previous version generates libuv.pc with LIBS = "-lpthread" instead of "-lpthread -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv" on MinGW. Previous version generates the following Makefile.am: am__append_4 = -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv ... LIBS = -lpthread $(am__append_4) and the following configure.ac: AS_IF([test "x$PKG_CONFIG" != "x"], [ AC_CONFIG_FILES([libuv.pc]) ]) AC_CONFIG_FILES([Makefile]) Therefore, Makefile is generated after libuv.pc. Variables from Makefile don't affect config.status and libuv.pc. PR-URL: https://github.com/libuv/libuv/pull/841 Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 1 - configure.ac | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 88b536248..05ccd58ac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,7 +45,6 @@ include_HEADERS += include/uv-win.h include/tree.h AM_CPPFLAGS += -I$(top_srcdir)/src/win \ -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 -LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv libuv_la_SOURCES += src/win/async.c \ src/win/atomicops-inl.h \ src/win/core.c \ diff --git a/configure.ac b/configure.ac index 2d5a3b9de..4f8619685 100644 --- a/configure.ac +++ b/configure.ac @@ -58,6 +58,9 @@ AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false]) AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [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" +]) AC_CHECK_HEADERS([sys/ahafs_evProds.h]) AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes) AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" != "x"]) From 4c945f49365ab4d6e1b07bf0ef2893455dc04622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 5 May 2016 19:52:20 +0100 Subject: [PATCH 151/632] win: improve uv__convert_utf16_to_utf8 - take a size parameter - always null terminate the buffer - nullify the output parameter in case of error PR-URL: https://github.com/libuv/libuv/pull/859 Reviewed-By: Colin Ihrig --- src/win/internal.h | 2 +- src/win/util.c | 32 +++++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/win/internal.h b/src/win/internal.h index c724793bf..7da41074a 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -329,7 +329,7 @@ int uv_parent_pid(); int uv_current_pid(); __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, char** utf8); +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); /* diff --git a/src/win/util.c b/src/win/util.c index b4690f63a..7b1e37e99 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1299,20 +1299,36 @@ void uv_os_free_passwd(uv_passwd_t* pwd) { } -int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) { +/* + * Converts a UTF-16 string into a UTF-8 one. The resulting string is + * null-terminated. + * + * 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; if (utf16 == NULL) return UV_EINVAL; /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL); + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + utf16len, + NULL, + 0, + NULL, + NULL); if (bufsize == 0) return uv_translate_sys_error(GetLastError()); - /* Allocate the destination buffer */ - *utf8 = uv__malloc(bufsize); + /* 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; @@ -1321,7 +1337,7 @@ int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) { bufsize = WideCharToMultiByte(CP_UTF8, 0, utf16, - -1, + utf16len, *utf8, bufsize, NULL, @@ -1329,9 +1345,11 @@ int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) { if (bufsize == 0) { uv__free(*utf8); + *utf8 = NULL; return uv_translate_sys_error(GetLastError()); } + (*utf8)[bufsize] = '\0'; return 0; } @@ -1377,13 +1395,13 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { } pwd->homedir = NULL; - r = uv__convert_utf16_to_utf8(path, &pwd->homedir); + r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir); if (r != 0) return r; pwd->username = NULL; - r = uv__convert_utf16_to_utf8(username, &pwd->username); + r = uv__convert_utf16_to_utf8(username, -1, &pwd->username); if (r != 0) { uv__free(pwd->homedir); From 46d84eae28bbf82eb8e1ace35cead0bd73163a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 5 May 2016 19:58:44 +0100 Subject: [PATCH 152/632] win: simplified UTF16 -> UTF8 conversions PR-URL: https://github.com/libuv/libuv/pull/859 Reviewed-By: Colin Ihrig --- src/win/fs-event.c | 30 +--------------------- src/win/util.c | 63 +++------------------------------------------- 2 files changed, 4 insertions(+), 89 deletions(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 6b7d1d933..e79a48d0e 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -461,35 +461,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } /* Convert the filename to utf8. */ - size = WideCharToMultiByte(CP_UTF8, - 0, - filenamew, - sizew, - NULL, - 0, - NULL, - NULL); - if (size) { - filename = (char*)uv__malloc(size + 1); - if (!filename) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - size = WideCharToMultiByte(CP_UTF8, - 0, - filenamew, - sizew, - filename, - size, - NULL, - NULL); - if (size) { - filename[size] = '\0'; - } else { - uv__free(filename); - filename = NULL; - } - } + uv__convert_utf16_to_utf8(filenamew, sizew, &filename); switch (file_info->Action) { case FILE_ACTION_ADDED: diff --git a/src/win/util.c b/src/win/util.c index 7b1e37e99..2944ddb76 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -403,36 +403,13 @@ int uv_set_process_title(const char* title) { static int uv__get_process_title() { WCHAR title_w[MAX_TITLE_LENGTH]; - int length; if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { return -1; } - /* Find out what the size of the buffer is that we need */ - length = WideCharToMultiByte(CP_UTF8, 0, title_w, -1, NULL, 0, NULL, NULL); - if (!length) { - return -1; - } - - assert(!process_title); - process_title = (char*)uv__malloc(length); - if (!process_title) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - /* Do utf16 -> utf8 conversion here */ - if (!WideCharToMultiByte(CP_UTF8, - 0, - title_w, - -1, - process_title, - length, - NULL, - NULL)) { - uv__free(process_title); + if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0) return -1; - } return 0; } @@ -704,43 +681,9 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; cpu_info->cpu_times.nice = 0; - - len = WideCharToMultiByte(CP_UTF8, - 0, - cpu_brand, + uv__convert_utf16_to_utf8(cpu_brand, cpu_brand_size / sizeof(WCHAR), - NULL, - 0, - NULL, - NULL); - if (len == 0) { - err = GetLastError(); - goto error; - } - - assert(len > 0); - - /* Allocate 1 extra byte for the null terminator. */ - cpu_info->model = uv__malloc(len + 1); - if (cpu_info->model == NULL) { - err = ERROR_OUTOFMEMORY; - goto error; - } - - if (WideCharToMultiByte(CP_UTF8, - 0, - cpu_brand, - cpu_brand_size / sizeof(WCHAR), - cpu_info->model, - len, - NULL, - NULL) == 0) { - err = GetLastError(); - goto error; - } - - /* Ensure that cpu_info->model is null terminated. */ - cpu_info->model[len] = '\0'; + &(cpu_info->model)); } uv__free(sppi); From e397caa3a6a139fff2fed06e0223ee92582fa2d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 5 May 2016 20:27:10 +0100 Subject: [PATCH 153/632] win: remove unneeded condition The size is checked beforehand, no need to check it again. PR-URL: https://github.com/libuv/libuv/pull/859 Reviewed-By: Colin Ihrig --- 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 2944ddb76..4cebad390 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -124,7 +124,7 @@ int uv_exepath(char* buffer, size_t* size_ptr) { utf16_buffer, -1, buffer, - *size_ptr > INT_MAX ? INT_MAX : (int) *size_ptr, + (int) *size_ptr, NULL, NULL); if (utf8_len == 0) { From a8840fb34741ca0475e6eefe19b42937d4ba94c3 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 6 May 2016 22:04:46 +0200 Subject: [PATCH 154/632] darwin: work around condition variable kernel bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It has been reported that destroying condition variables that have been signalled but not waited on can sometimes result in application crashes. See https://codereview.chromium.org/1323293005. PR-URL: https://github.com/libuv/libuv/pull/860 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/thread.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/unix/thread.c b/src/unix/thread.c index b1fb02bd2..43dcdd1a5 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -392,6 +392,35 @@ int uv_cond_init(uv_cond_t* cond) { #endif /* defined(__APPLE__) && defined(__MACH__) */ void uv_cond_destroy(uv_cond_t* cond) { +#if defined(__APPLE__) && defined(__MACH__) + /* It has been reported that destroying condition variables that have been + * signalled but not waited on can sometimes result in application crashes. + * See https://codereview.chromium.org/1323293005. + */ + pthread_mutex_t mutex; + struct timespec ts; + int err; + + if (pthread_mutex_init(&mutex, NULL)) + abort(); + + if (pthread_mutex_lock(&mutex)) + abort(); + + ts.tv_sec = 0; + ts.tv_nsec = 1; + + err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts); + if (err != 0 && err != ETIMEDOUT) + abort(); + + if (pthread_mutex_unlock(&mutex)) + abort(); + + if (pthread_mutex_destroy(&mutex)) + abort(); +#endif /* defined(__APPLE__) && defined(__MACH__) */ + if (pthread_cond_destroy(cond)) abort(); } From 28d160f3dea256b198b7df887162e432a75cac4e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 10 May 2016 15:22:38 +0200 Subject: [PATCH 155/632] darwin: make thread stack multiple of page size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pthread_attr_setstacksize() expects that the stack size is a multiple of the page size so make sure that it is. Fixes a regression introduced in commit 3db07cc ("osx: set the default thread stack size to RLIMIT_STACK") that made the program abort under certain configurations; GNU Emacs on OS X apparently sets RLIMIT_STACK to odd values when executing child processes. Fixes: https://github.com/nodejs/node/issues/6563 PR-URL: https://github.com/libuv/libuv/pull/864 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/thread.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/unix/thread.c b/src/unix/thread.c index 43dcdd1a5..236f59139 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -28,6 +28,7 @@ #include #include /* getrlimit() */ +#include /* getpagesize() */ #include @@ -81,10 +82,13 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { if (pthread_attr_init(attr)) abort(); - if (lim.rlim_cur != RLIM_INFINITY && - lim.rlim_cur >= PTHREAD_STACK_MIN) { - if (pthread_attr_setstacksize(attr, lim.rlim_cur)) - abort(); + if (lim.rlim_cur != RLIM_INFINITY) { + /* pthread_attr_setstacksize() expects page-aligned values. */ + lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); + + if (lim.rlim_cur >= PTHREAD_STACK_MIN) + if (pthread_attr_setstacksize(attr, lim.rlim_cur)) + abort(); } #else attr = NULL; From 11e93aaf53915dc60a8410f593abda9d620ae7cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Reis?= Date: Thu, 12 May 2016 10:36:59 +0100 Subject: [PATCH 156/632] build,win: rename platform to msbuild_platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This variable is used to select 32 or 64 bit builds when invoking MSBuild. The Visual C++ Build Tools also use the `platform` variable name, resulting in a conflict when vcvarsall.bat is called. Thus, it is necessary to rename it. Ref: https://github.com/libuv/libuv/issues/839 PR-URL: https://github.com/libuv/libuv/pull/868 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Ben Noordhuis --- vcbuild.bat | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vcbuild.bat b/vcbuild.bat index 9a7ed4b8c..91f45b721 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -19,7 +19,7 @@ set nobuild= set run= set target_arch=ia32 set vs_toolset=x86 -set platform=WIN32 +set msbuild_platform=WIN32 set library=static_library :next-arg @@ -31,9 +31,9 @@ if /i "%1"=="bench" set run=run-benchmarks.exe&goto arg-ok if /i "%1"=="clean" set target=Clean&goto arg-ok if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok if /i "%1"=="nobuild" set nobuild=1&goto arg-ok -if /i "%1"=="x86" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok -if /i "%1"=="ia32" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok -if /i "%1"=="x64" set target_arch=x64&set platform=x64&set vs_toolset=x64&goto arg-ok +if /i "%1"=="x86" set target_arch=ia32&set msbuild_platform=WIN32&set vs_toolset=x86&goto arg-ok +if /i "%1"=="ia32" set target_arch=ia32&set msbuild_platform=WIN32&set vs_toolset=x86&goto arg-ok +if /i "%1"=="x64" set target_arch=x64&set msbuild_platform=x64&set vs_toolset=x64&goto arg-ok if /i "%1"=="shared" set library=shared_library&goto arg-ok if /i "%1"=="static" set library=static_library&goto arg-ok :arg-ok @@ -132,7 +132,7 @@ goto run @rem Build the sln with msbuild. :msbuild-found -msbuild uv.sln /t:%target% /p:Configuration=%config% /p:Platform="%platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo +msbuild uv.sln /t:%target% /p:Configuration=%config% /p:Platform="%msbuild_platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo if errorlevel 1 exit /b 1 :run From 31a0132a6877a76bc9217313bce41327ec6f4a2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Reis?= Date: Thu, 12 May 2016 11:53:12 +0100 Subject: [PATCH 157/632] gitignore: ignore VS temporary database files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Visual Studio 2015 uses a new database engine, creating temporary files that should be ignored. PR-URL: https://github.com/libuv/libuv/pull/869 Reviewed-By: Saúl Ibarra Corretgé --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 86a8a5b7b..eb54f9248 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ *.pyc *.sdf *.suo +.vs/ +*.VC.db +*.VC.opendb core vgcore.* .buildstamp From a1bd1ee803529086c0390b55ce81713b60b5ac46 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Thu, 12 May 2016 15:51:53 -0400 Subject: [PATCH 158/632] test: skip emfile on AIX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On AIX, if a 'accept' call fails ECONNRESET is set on the socket which causes uv__emfile_trick to not work as intended and this test to fail. Fixes: https://github.com/libuv/libuv/issues/845 PR-URL: https://github.com/libuv/libuv/pull/870 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- test/test-emfile.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/test-emfile.c b/test/test-emfile.c index dd35f785b..5f4dd9efd 100644 --- a/test/test-emfile.c +++ b/test/test-emfile.c @@ -38,6 +38,13 @@ static uv_tcp_t client_handle; TEST_IMPL(emfile) { +#ifdef _AIX + /* On AIX, if a 'accept' call fails ECONNRESET is set on the socket + * which causes uv__emfile_trick to not work as intended and this test + * to fail. + */ + RETURN_SKIP("uv__emfile_trick does not work on AIX"); +#endif struct sockaddr_in addr; struct rlimit limits; uv_connect_t connect_req; From 4fa89fbc616b9ac28d5b4706d666ba7d62c5abd5 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 16 May 2016 11:34:36 -0400 Subject: [PATCH 159/632] unix: use system allocator for scandir() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On unix, scandir() uses the system allocator to allocate memory. This commit releases the memory with free() instead of uv__free(). uv__free() is still used on Windows, which uses uv__malloc() to request the memory. Fixes: https://github.com/libuv/libuv/issues/873 PR-URL: https://github.com/libuv/libuv/pull/874 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fs.c | 5 +++-- src/uv-common.c | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 5235d8652..085970a06 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -370,9 +370,10 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) { if (dents != NULL) { int i; + /* Memory was allocated using the system allocator, so use free() here. */ for (i = 0; i < n; i++) - uv__free(dents[i]); - uv__free(dents); + free(dents[i]); + free(dents); } errno = saved_errno; diff --git a/src/uv-common.c b/src/uv-common.c index 074383d28..e311f32ce 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -483,6 +483,16 @@ static unsigned int* uv__get_nbufs(uv_fs_t* req) { #endif } +/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows + * systems. So, the memory should be released using free(). On Windows, + * uv__malloc() is used, so use uv__free() to free memory. +*/ +#ifdef _WIN32 +# define uv__fs_scandir_free uv__free +#else +# define uv__fs_scandir_free free +#endif + void uv__fs_scandir_cleanup(uv_fs_t* req) { uv__dirent_t** dents; @@ -492,7 +502,7 @@ void uv__fs_scandir_cleanup(uv_fs_t* req) { if (*nbufs > 0 && *nbufs != (unsigned int) req->result) (*nbufs)--; for (; *nbufs < (unsigned int) req->result; (*nbufs)++) - uv__free(dents[*nbufs]); + uv__fs_scandir_free(dents[*nbufs]); } @@ -506,11 +516,11 @@ int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { /* Free previous entity */ if (*nbufs > 0) - uv__free(dents[*nbufs - 1]); + uv__fs_scandir_free(dents[*nbufs - 1]); /* End was already reached */ if (*nbufs == (unsigned int) req->result) { - uv__free(dents); + uv__fs_scandir_free(dents); req->ptr = NULL; return UV_EOF; } From 40e7a9867d21f748b28b4e99df27755af84436b8 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 16 May 2016 12:35:42 -0400 Subject: [PATCH 160/632] common: release uv_fs_scandir() array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uv__fs_scandir_cleanup() releases individual directory entries, but not the container array. This commit frees the array as well. Fixes: https://github.com/libuv/libuv/issues/873 PR-URL: https://github.com/libuv/libuv/pull/874 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/uv-common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/uv-common.c b/src/uv-common.c index e311f32ce..ba2644691 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -503,6 +503,9 @@ void uv__fs_scandir_cleanup(uv_fs_t* req) { (*nbufs)--; for (; *nbufs < (unsigned int) req->result; (*nbufs)++) uv__fs_scandir_free(dents[*nbufs]); + + uv__fs_scandir_free(req->ptr); + req->ptr = NULL; } From 4e4407b17ed375a56d4886d875647fc886a81224 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 16 May 2016 13:15:36 -0400 Subject: [PATCH 161/632] win: call uv__fs_scandir_cleanup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a previously missing call to uv__fs_scandir_cleanup() to uv_fs_req_cleanup(). This better aligns the Windows and Unix implementations. Fixes: https://github.com/libuv/libuv/issues/873 PR-URL: https://github.com/libuv/libuv/pull/874 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index fd2547e94..54dfea724 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1878,8 +1878,12 @@ void uv_fs_req_cleanup(uv_fs_t* req) { if (req->flags & UV_FS_FREE_PATHS) uv__free(req->file.pathw); - if (req->flags & UV_FS_FREE_PTR) - uv__free(req->ptr); + if (req->flags & UV_FS_FREE_PTR) { + if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) + uv__fs_scandir_cleanup(req); + else + uv__free(req->ptr); + } req->path = NULL; req->file.pathw = NULL; From e51442bbc9b37dff32430c047844d9181798a9a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Reis?= Date: Wed, 11 May 2016 13:03:30 +0100 Subject: [PATCH 162/632] win,tty: fix read stop in line mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closing the handle does not make ReadConsoleW exit reliably on Windows 7 and above. Thus, after switching from line to raw mode, keypresses were held until enter was pressed. This makes ReadConsoleW exit by writing a return keypress to its input buffer, similar to what was already done for raw mode. Fixes: https://github.com/libuv/libuv/issues/852 PR-URL: https://github.com/libuv/libuv/pull/866 Reviewed-by: Bert Belder Reviewed-By: Saúl Ibarra Corretgé --- configure.ac | 2 +- src/win/internal.h | 1 + src/win/tty.c | 33 +++++++++++++++++----- test/test-list.h | 6 ++++ test/test-tty.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++ uv.gyp | 1 + 6 files changed, 104 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 4f8619685..1910b2f47 100644 --- a/configure.ac +++ b/configure.ac @@ -59,7 +59,7 @@ AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [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" + LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32" ]) AC_CHECK_HEADERS([sys/ahafs_evProds.h]) AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes) diff --git a/src/win/internal.h b/src/win/internal.h index 7da41074a..0a7c9404f 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -83,6 +83,7 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled; #define UV_HANDLE_ZERO_READ 0x00080000 #define UV_HANDLE_EMULATE_IOCP 0x00100000 #define UV_HANDLE_BLOCKING_WRITES 0x00200000 +#define UV_HANDLE_CANCELLATION_PENDING 0x00400000 /* Used by uv_tcp_t and uv_udp_t handles */ #define UV_HANDLE_IPV6 0x01000000 diff --git a/src/win/tty.c b/src/win/tty.c index 1b27f60a6..db51f069c 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -871,10 +871,15 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, } } else { - /* Read successful */ - /* TODO: read unicode, convert to utf-8 */ - DWORD bytes = req->u.io.overlapped.InternalHigh; - handle->read_cb((uv_stream_t*) handle, bytes, &buf); + if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Read successful */ + /* TODO: read unicode, convert to utf-8 */ + DWORD bytes = req->u.io.overlapped.InternalHigh; + handle->read_cb((uv_stream_t*) handle, bytes, &buf); + } else { + handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING; + handle->read_cb((uv_stream_t*) handle, 0, &buf); + } } /* Wait for more input events. */ @@ -937,6 +942,9 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, int uv_tty_read_stop(uv_tty_t* handle) { + INPUT_RECORD record; + DWORD written; + handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(handle->loop, handle); @@ -944,8 +952,6 @@ int uv_tty_read_stop(uv_tty_t* handle) { if ((handle->flags & UV_HANDLE_READ_PENDING) && (handle->flags & UV_HANDLE_TTY_RAW)) { /* Write some bullshit event to force the console wait to return. */ - INPUT_RECORD record; - DWORD written; memset(&record, 0, sizeof record); if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { return GetLastError(); @@ -954,7 +960,20 @@ int uv_tty_read_stop(uv_tty_t* handle) { /* Cancel line-buffered read */ if (handle->tty.rd.read_line_handle != NULL) { - /* Closing this handle will cancel the ReadConsole operation */ + if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Write enter key event to force the console wait to return. */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + record.Event.KeyEvent.wVirtualScanCode = + MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; + record.Event.KeyEvent.dwControlKeyState = 0; + WriteConsoleInputW(handle->handle, &record, 1, &written); + handle->flags |= UV_HANDLE_CANCELLATION_PENDING; + } + /* Close line-buffered read handle */ CloseHandle(handle->tty.rd.read_line_handle); handle->tty.rd.read_line_handle = NULL; } diff --git a/test/test-list.h b/test/test-list.h index 8b10f1a5f..c93f08199 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -43,6 +43,9 @@ TEST_DECLARE (semaphore_1) TEST_DECLARE (semaphore_2) TEST_DECLARE (semaphore_3) TEST_DECLARE (tty) +#ifdef _WIN32 +TEST_DECLARE (tty_raw) +#endif TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) TEST_DECLARE (stdio_over_pipes) @@ -387,6 +390,9 @@ TASK_LIST_START #endif TEST_ENTRY (pipe_set_non_blocking) TEST_ENTRY (tty) +#ifdef _WIN32 + TEST_ENTRY (tty_raw) +#endif TEST_ENTRY (tty_file) TEST_ENTRY (tty_pty) TEST_ENTRY (stdio_over_pipes) diff --git a/test/test-tty.c b/test/test-tty.c index 461d19413..55cc01675 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -146,6 +146,75 @@ TEST_IMPL(tty) { } +#ifdef _WIN32 +static void tty_raw_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = malloc(size); + buf->len = size; +} + +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] == ' '); + uv_close((uv_handle_t*) tty_in, NULL); + } else { + ASSERT(nread == 0); + } +} + +TEST_IMPL(tty_raw) { + int r; + int ttyin_fd; + uv_tty_t tty_in; + uv_loop_t* loop = uv_default_loop(); + HANDLE handle; + INPUT_RECORD record; + DWORD written; + + /* 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(handle != INVALID_HANDLE_VALUE); + ttyin_fd = _open_osfhandle((intptr_t) handle, 0); + 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. */ + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read); + ASSERT(r == 0); + + /* 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); + + /* Write ' ' that should be read in raw mode */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_SPACE; + record.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(VK_SPACE, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L' '; + record.Event.KeyEvent.dwControlKeyState = 0; + WriteConsoleInputW(handle, &record, 1, &written); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + TEST_IMPL(tty_file) { #ifndef _WIN32 uv_loop_t loop; diff --git a/uv.gyp b/uv.gyp index 42a1a7f1e..2fdd59ac7 100644 --- a/uv.gyp +++ b/uv.gyp @@ -112,6 +112,7 @@ '-liphlpapi', '-lpsapi', '-lshell32', + '-luser32', '-luserenv', '-lws2_32' ], From 349aa6c0dd004960a44a83faf894e9d8592ca95b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Reis?= Date: Wed, 11 May 2016 15:43:16 +0100 Subject: [PATCH 163/632] win,tty: don't duplicate handle for line reads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we cancel ReadConsole by sending a newline, the duplicate handle is no longer necessary. PR-URL: https://github.com/libuv/libuv/pull/866 Reviewed-by: Bert Belder Reviewed-By: Saúl Ibarra Corretgé --- include/uv-win.h | 3 +- src/win/tty.c | 75 ++++++++++++++---------------------------------- 2 files changed, 24 insertions(+), 54 deletions(-) diff --git a/include/uv-win.h b/include/uv-win.h index 6b537fed0..a75dba8d1 100644 --- a/include/uv-win.h +++ b/include/uv-win.h @@ -483,7 +483,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); union { \ struct { \ /* Used for readable TTY handles */ \ - HANDLE read_line_handle; \ + /* TODO: remove me in v2.x. */ \ + HANDLE unused_; \ uv_buf_t read_line_buffer; \ HANDLE read_raw_wait; \ /* Fields used for translating win keystrokes into vt100 characters */ \ diff --git a/src/win/tty.c b/src/win/tty.c index db51f069c..412cba091 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -173,7 +173,8 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { if (readable) { /* Initialize TTY input specific fields. */ tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE; - tty->tty.rd.read_line_handle = NULL; + /* TODO: remove me in v2.x. */ + tty->tty.rd.unused_ = NULL; tty->tty.rd.read_line_buffer = uv_null_buf_; tty->tty.rd.read_raw_wait = NULL; @@ -419,7 +420,7 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */ chars = bytes / 3; - if (ReadConsoleW(handle->tty.rd.read_line_handle, + if (ReadConsoleW(handle->handle, (void*) utf16, chars, &read_chars, @@ -463,25 +464,6 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { } assert(handle->tty.rd.read_line_buffer.base != NULL); - /* Duplicate the console handle, so if we want to cancel the read, we can */ - /* just close this handle duplicate. */ - if (handle->tty.rd.read_line_handle == NULL) { - HANDLE this_process = GetCurrentProcess(); - r = DuplicateHandle(this_process, - handle->handle, - this_process, - &handle->tty.rd.read_line_handle, - 0, - 0, - DUPLICATE_SAME_ACCESS); - if (!r) { - handle->tty.rd.read_line_handle = NULL; - SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)req); - goto out; - } - } - r = QueueUserWorkItem(uv_tty_line_read_thread, (void*) req, WT_EXECUTELONGFUNCTION); @@ -490,7 +472,6 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { uv_insert_pending_req(loop, (uv_req_t*)req); } - out: handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; } @@ -857,8 +838,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, if (!REQ_SUCCESS(req)) { /* Read was not successful */ - if ((handle->flags & UV_HANDLE_READING) && - handle->tty.rd.read_line_handle != NULL) { + if (handle->flags & UV_HANDLE_READING) { /* Real error */ handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(loop, handle); @@ -948,37 +928,31 @@ int uv_tty_read_stop(uv_tty_t* handle) { handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(handle->loop, handle); - /* Cancel raw read */ - if ((handle->flags & UV_HANDLE_READ_PENDING) && - (handle->flags & UV_HANDLE_TTY_RAW)) { + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + return 0; + + if (handle->flags & UV_HANDLE_TTY_RAW) { + /* Cancel raw read */ /* Write some bullshit event to force the console wait to return. */ memset(&record, 0, sizeof record); if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { return GetLastError(); } + } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Cancel line-buffered read if not already pending */ + /* Write enter key event to force the console wait to return. */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + record.Event.KeyEvent.wVirtualScanCode = + MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; + record.Event.KeyEvent.dwControlKeyState = 0; + WriteConsoleInputW(handle->handle, &record, 1, &written); + handle->flags |= UV_HANDLE_CANCELLATION_PENDING; } - /* Cancel line-buffered read */ - if (handle->tty.rd.read_line_handle != NULL) { - if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { - /* Write enter key event to force the console wait to return. */ - record.EventType = KEY_EVENT; - record.Event.KeyEvent.bKeyDown = TRUE; - record.Event.KeyEvent.wRepeatCount = 1; - record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; - record.Event.KeyEvent.wVirtualScanCode = - MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); - record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; - record.Event.KeyEvent.dwControlKeyState = 0; - WriteConsoleInputW(handle->handle, &record, 1, &written); - handle->flags |= UV_HANDLE_CANCELLATION_PENDING; - } - /* Close line-buffered read handle */ - CloseHandle(handle->tty.rd.read_line_handle); - handle->tty.rd.read_line_handle = NULL; - } - - return 0; } @@ -2064,11 +2038,6 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { if (handle->flags & UV__HANDLE_CLOSING && handle->reqs_pending == 0) { - /* The console handle duplicate used for line reading should be destroyed */ - /* by uv_tty_read_stop. */ - assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || - handle->tty.rd.read_line_handle == NULL); - /* The wait handle used for raw reading should be unregistered when the */ /* wait callback runs. */ assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || From 9eb131197171abda215452c5decd4a174ff1456d Mon Sep 17 00:00:00 2001 From: Alexis Campailla Date: Wed, 11 May 2016 12:15:13 +0200 Subject: [PATCH 164/632] win,tty: restore cursor after canceling line read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we send VK_RETURN to make ReadConsole return, a spurious new line is echoed to the screen. This is pretty visible in Node.js, since it calls uv_tty_read_start() and uv_tty_read_stop() in rapid succession during startup. With this change, we save the screen state just before sending VK_RETURN, and restore the cursor position as soon as ReadConsole returns. PR-URL: https://github.com/libuv/libuv/pull/866 Reviewed-by: Bert Belder Reviewed-By: Saúl Ibarra Corretgé --- src/win/tty.c | 120 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 109 insertions(+), 11 deletions(-) diff --git a/src/win/tty.c b/src/win/tty.c index 412cba091..9b9637784 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -57,11 +57,23 @@ static void uv_tty_capture_initial_style(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); /* Null uv_buf_t */ static const uv_buf_t uv_null_buf_ = { 0, NULL }; +enum uv__read_console_status_e { + NOT_STARTED, + IN_PROGRESS, + TRAP_REQUESTED, + COMPLETED +}; + +static volatile LONG uv__read_console_status = NOT_STARTED; +static volatile LONG uv__restore_screen_state; +static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state; + /* * The console virtual window. @@ -399,6 +411,8 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { DWORD bytes, read_bytes; WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3]; DWORD chars, read_chars; + LONG status; + COORD pos; assert(data); @@ -420,6 +434,14 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */ chars = bytes / 3; + status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS); + if (status == TRAP_REQUESTED) { + SET_REQ_SUCCESS(req); + req->u.io.overlapped.InternalHigh = 0; + POST_COMPLETION_FOR_REQ(loop, req); + return 0; + } + if (ReadConsoleW(handle->handle, (void*) utf16, chars, @@ -439,6 +461,33 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { SET_REQ_ERROR(req, GetLastError()); } + InterlockedExchange(&uv__read_console_status, COMPLETED); + + /* If we canceled the read by sending a VK_RETURN event, restore the screen + state to undo the visual effect of the VK_RETURN*/ + if (InterlockedOr(&uv__restore_screen_state, 0)) { + HANDLE active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (active_screen_buffer != INVALID_HANDLE_VALUE) { + pos = uv__saved_screen_state.dwCursorPosition; + + /* If the cursor was at the bottom line of the screen buffer, the + VK_RETURN would have caused the buffer contents to scroll up by + one line. The right position to reset the cursor to is therefore one + line higher */ + if (pos.Y == uv__saved_screen_state.dwSize.Y - 1) + pos.Y--; + + SetConsoleCursorPosition(active_screen_buffer, pos); + CloseHandle(active_screen_buffer); + } + } + POST_COMPLETION_FOR_REQ(loop, req); return 0; } @@ -464,6 +513,11 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { } assert(handle->tty.rd.read_line_buffer.base != NULL); + /* Reset flags No locking is required since there cannot be a line read + in progress. We are also relying on the memory barrier provided by + QueueUserWorkItem*/ + uv__restore_screen_state = FALSE; + uv__read_console_status = NOT_STARTED; r = QueueUserWorkItem(uv_tty_line_read_thread, (void*) req, WT_EXECUTELONGFUNCTION); @@ -923,7 +977,7 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, int uv_tty_read_stop(uv_tty_t* handle) { INPUT_RECORD record; - DWORD written; + DWORD written, err; handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(handle->loop, handle); @@ -940,22 +994,66 @@ int uv_tty_read_stop(uv_tty_t* handle) { } } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { /* Cancel line-buffered read if not already pending */ - /* Write enter key event to force the console wait to return. */ - record.EventType = KEY_EVENT; - record.Event.KeyEvent.bKeyDown = TRUE; - record.Event.KeyEvent.wRepeatCount = 1; - record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; - record.Event.KeyEvent.wVirtualScanCode = - MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); - record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; - record.Event.KeyEvent.dwControlKeyState = 0; - WriteConsoleInputW(handle->handle, &record, 1, &written); + err = uv__cancel_read_console(handle); + if (err) + return err; + handle->flags |= UV_HANDLE_CANCELLATION_PENDING; } return 0; } +static int uv__cancel_read_console(uv_tty_t* handle) { + HANDLE active_screen_buffer = INVALID_HANDLE_VALUE; + INPUT_RECORD record; + DWORD written; + DWORD err = 0; + LONG status; + + assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)); + + status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED); + if (status != IN_PROGRESS) { + /* Either we have managed to set a trap for the other thread before + ReadConsole is called, or ReadConsole has returned because the user + has pressed ENTER. In either case, there is nothing else to do. */ + return 0; + } + + /* Save screen state before sending the VK_RETURN event */ + active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (active_screen_buffer != INVALID_HANDLE_VALUE && + GetConsoleScreenBufferInfo(active_screen_buffer, + &uv__saved_screen_state)) { + InterlockedOr(&uv__restore_screen_state, 1); + } + + /* Write enter key event to force the console wait to return. */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + record.Event.KeyEvent.wVirtualScanCode = + MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; + record.Event.KeyEvent.dwControlKeyState = 0; + if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) + err = GetLastError(); + + if (active_screen_buffer != INVALID_HANDLE_VALUE) + CloseHandle(active_screen_buffer); + + return err; +} + static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { int old_virtual_width = uv_tty_virtual_width; From d989902ac658b4323a4f4020446e6f4dc449e25c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 16 May 2016 23:22:19 +0200 Subject: [PATCH 165/632] 2016.05.17, Version 1.9.1 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.9.0: * test: handle root home directories (cjihrig) * unix: implement uv__fs_futime for AIX 7.1 (Imran Iqbal) * test: skip early bind tests if no IPv6 is supported (Saúl Ibarra Corretgé) * win: fix var declaration to be C89 compliant (Michael Fero) * unix: use POLL{IN,OUT,etc} constants directly (Ben Noordhuis) * doc: add ability to live reload and regenerate HTML (Saúl Ibarra Corretgé) * Revert "win,build: remove unused build defines" (cjihrig) * linux: fix fd leaks in uv_cpu_info() error paths (Ben Noordhuis) * linux: don't abort on malformed /proc/stat (Ben Noordhuis) * linux: fix long lines in linux-core.c (Ben Noordhuis) * test: fix fs_event_watch_file_current_dir for AIX (Imran Iqbal) * unix,fs: code cleanup of uv_fs_event_start for AIX (Imran Iqbal) * unix: delay signal handling until after normal i/o (Ben Noordhuis) * android: pthread_sigmask() does not set errno (Oguz Bastemur) * win: work around sharepoint scandir bug (Ben Noordhuis) * unix: guard against clobbering errno in uv__free() (Ben Noordhuis) * unix: remove unneeded SAVE_ERRNO wrappers (Ben Noordhuis) * test: skip fs_event_close_in_callback on AIX (Imran Iqbal) * win: add maxrss, pagefaults to uv_getrusage() (Robert Jefe Lindstaedt) * test: set a big send buffer size for tcp_write_queue_order (Andrius Bentkus) * unix: error on realpath if PATH_MAX is undefined (Myles Borins) * unix: fix bug in barrier fallback implementation (Kári Tristan Helgason) * build: bump android ndk version (Kári Tristan Helgason) * build: always compile with -fvisibility=hidden (Ben Noordhuis) * test: fix -Wformat warnings in platform test (Ben Noordhuis) * win: clarify fsevents handling code (Saúl Ibarra Corretgé) * test: fix POLLHDRUP related failures for AIX (Imran Iqbal) * build, mingw: set LIBS in configure.ac (Tony Theodore) * win: improve uv__convert_utf16_to_utf8 (Saúl Ibarra Corretgé) * win: simplified UTF16 -> UTF8 conversions (Saúl Ibarra Corretgé) * win: remove unneeded condition (Saúl Ibarra Corretgé) * darwin: work around condition variable kernel bug (Ben Noordhuis) * darwin: make thread stack multiple of page size (Ben Noordhuis) * build,win: rename platform to msbuild_platform (João Reis) * gitignore: ignore VS temporary database files (João Reis) * test: skip emfile on AIX (Imran Iqbal) * unix: use system allocator for scandir() (cjihrig) * common: release uv_fs_scandir() array (cjihrig) * win: call uv__fs_scandir_cleanup() (cjihrig) * win,tty: fix read stop in line mode (João Reis) * win,tty: don't duplicate handle for line reads (João Reis) * win,tty: restore cursor after canceling line read (Alexis Campailla) --- .mailmap | 1 + AUTHORS | 4 ++ ChangeLog | 89 ++++++++++++++++++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 4 +- 6 files changed, 98 insertions(+), 4 deletions(-) diff --git a/.mailmap b/.mailmap index 7a51588c0..4966caf5f 100644 --- a/.mailmap +++ b/.mailmap @@ -11,6 +11,7 @@ Christoph Iserlohn Devchandra Meetei Leishangthem Fedor Indutny Frank Denis +Imran Iqbal Isaac Z. Schlueter Jason Williams Justin Venus diff --git a/AUTHORS b/AUTHORS index 9a9e9c2a2..7acee7c53 100644 --- a/AUTHORS +++ b/AUTHORS @@ -253,3 +253,7 @@ Robert Chiras Kári Tristan Helgason Krishnaraj Bhat Enno Boland +Michael Fero +Robert Jefe Lindstaedt +Myles Borins +Tony Theodore diff --git a/ChangeLog b/ChangeLog index 85d40113e..30cdf7a67 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,92 @@ +2016.05.17, Version 1.9.1 (Stable) + +Changes since version 1.9.0: + +* test: handle root home directories (cjihrig) + +* unix: implement uv__fs_futime for AIX 7.1 (Imran Iqbal) + +* test: skip early bind tests if no IPv6 is supported (Saúl Ibarra Corretgé) + +* win: fix var declaration to be C89 compliant (Michael Fero) + +* unix: use POLL{IN,OUT,etc} constants directly (Ben Noordhuis) + +* doc: add ability to live reload and regenerate HTML (Saúl Ibarra Corretgé) + +* Revert "win,build: remove unused build defines" (cjihrig) + +* linux: fix fd leaks in uv_cpu_info() error paths (Ben Noordhuis) + +* linux: don't abort on malformed /proc/stat (Ben Noordhuis) + +* linux: fix long lines in linux-core.c (Ben Noordhuis) + +* test: fix fs_event_watch_file_current_dir for AIX (Imran Iqbal) + +* unix,fs: code cleanup of uv_fs_event_start for AIX (Imran Iqbal) + +* unix: delay signal handling until after normal i/o (Ben Noordhuis) + +* android: pthread_sigmask() does not set errno (Oguz Bastemur) + +* win: work around sharepoint scandir bug (Ben Noordhuis) + +* unix: guard against clobbering errno in uv__free() (Ben Noordhuis) + +* unix: remove unneeded SAVE_ERRNO wrappers (Ben Noordhuis) + +* test: skip fs_event_close_in_callback on AIX (Imran Iqbal) + +* win: add maxrss, pagefaults to uv_getrusage() (Robert Jefe Lindstaedt) + +* test: set a big send buffer size for tcp_write_queue_order (Andrius Bentkus) + +* unix: error on realpath if PATH_MAX is undefined (Myles Borins) + +* unix: fix bug in barrier fallback implementation (Kári Tristan Helgason) + +* build: bump android ndk version (Kári Tristan Helgason) + +* build: always compile with -fvisibility=hidden (Ben Noordhuis) + +* test: fix -Wformat warnings in platform test (Ben Noordhuis) + +* win: clarify fsevents handling code (Saúl Ibarra Corretgé) + +* test: fix POLLHDRUP related failures for AIX (Imran Iqbal) + +* build, mingw: set LIBS in configure.ac (Tony Theodore) + +* win: improve uv__convert_utf16_to_utf8 (Saúl Ibarra Corretgé) + +* win: simplified UTF16 -> UTF8 conversions (Saúl Ibarra Corretgé) + +* win: remove unneeded condition (Saúl Ibarra Corretgé) + +* darwin: work around condition variable kernel bug (Ben Noordhuis) + +* darwin: make thread stack multiple of page size (Ben Noordhuis) + +* build,win: rename platform to msbuild_platform (João Reis) + +* gitignore: ignore VS temporary database files (João Reis) + +* test: skip emfile on AIX (Imran Iqbal) + +* unix: use system allocator for scandir() (cjihrig) + +* common: release uv_fs_scandir() array (cjihrig) + +* win: call uv__fs_scandir_cleanup() (cjihrig) + +* win,tty: fix read stop in line mode (João Reis) + +* win,tty: don't duplicate handle for line reads (João Reis) + +* win,tty: restore cursor after canceling line read (Alexis Campailla) + + 2016.04.08, Version 1.9.0 (Stable), 229b3a4cc150aebd6561e6bd43076eafa7a03756 Changes since version 1.8.0: diff --git a/appveyor.yml b/appveyor.yml index 835730b92..c7ea73650 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.9.0.build{build} +version: v1.9.1.build{build} install: - cinst -y nsis diff --git a/configure.ac b/configure.ac index 1910b2f47..d9251f319 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.9.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.9.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 33856120f..08ad0edaa 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -33,8 +33,8 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 9 #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 fe2992145413ce43fa4000dfd81c43b0516ca094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 16 May 2016 23:22:29 +0200 Subject: [PATCH 166/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 30cdf7a67..3f376de6b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2016.05.17, Version 1.9.1 (Stable) +2016.05.17, Version 1.9.1 (Stable), d989902ac658b4323a4f4020446e6f4dc449e25c Changes since version 1.9.0: From 67f4d1c5312224da3e4fd5efd8eb34b985722cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 16 May 2016 23:49:30 +0200 Subject: [PATCH 167/632] Now working on version 1.9.2 --- 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 08ad0edaa..3cb9b5fdd 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 9 -#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 c5622a1c4f083c7f43149755d52d1649c5266c29 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 17 May 2016 14:53:19 -0400 Subject: [PATCH 168/632] doc: add cjihrig GPG ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/877 Reviewed-By: Saúl Ibarra Corretgé --- MAINTAINERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 2f0e618ca..80f63fd68 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -7,6 +7,7 @@ libuv is currently managed by the following individuals: - 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) * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) * **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul)) @@ -34,4 +35,3 @@ be garbage collected since nothing references it, so we'll create a tag for it: Commit the changes and push: $ git push origin pubkey-saghul - From 36a024de052d57edb40684f0adbafde4b0ccbf92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 19 May 2016 00:26:12 +0200 Subject: [PATCH 169/632] win,build: fix compilation on old Windows / MSVC Observed on Windows XP with Visual Studio 2008. PR-URL: https://github.com/libuv/libuv/pull/880 Reviewed-By: Alexis Campailla --- src/win/tty.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/win/tty.c b/src/win/tty.c index 9b9637784..59a991c6a 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -40,6 +40,9 @@ #include "stream-inl.h" #include "req-inl.h" +#ifndef InterlockedOr +# define InterlockedOr _InterlockedOr +#endif #define UNICODE_REPLACEMENT_CHARACTER (0xfffd) From c0fdc7102b226b253135c34ecf1098c9ba12a53d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 18 May 2016 14:07:55 +0100 Subject: [PATCH 170/632] darwin: fix setting fd to non-blocking in select(() trick When the select trick is used fd is replaced with the fake fd (one end of the socketpair) so we're not setting the original fd in non-blocking mode. Refs: https://github.com/nodejs/node/issues/6456#issuecomment-220018822 PR-URL: https://github.com/libuv/libuv/pull/879 Reviewed-By: Ben Noordhuis Reviewed-By: Fedor Indutny --- src/unix/tty.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/unix/tty.c b/src/unix/tty.c index 32fa37eac..ca1087123 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -57,6 +57,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { int flags; int newfd; int r; + int saved_flags; char path[256]; /* File descriptors that refer to files cannot be monitored with epoll. @@ -113,6 +114,22 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { fd = newfd; } +#if defined(__APPLE__) + /* Save the fd flags in case we need to restore them due to an error. */ + do + saved_flags = fcntl(fd, F_GETFL); + while (saved_flags == -1 && errno == EINTR); + + if (saved_flags == -1) { + if (newfd != -1) + uv__close(newfd); + return -errno; + } +#endif + + /* Pacify the compiler. */ + (void) &saved_flags; + skip: uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); @@ -120,13 +137,20 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { * the handle queue, since it was added by uv__handle_init in uv_stream_init. */ + if (!(flags & UV_STREAM_BLOCKING)) + uv__nonblock(fd, 1); + #if defined(__APPLE__) r = uv__stream_try_select((uv_stream_t*) tty, &fd); if (r) { + int rc = r; if (newfd != -1) uv__close(newfd); QUEUE_REMOVE(&tty->handle_queue); - return r; + do + r = fcntl(fd, F_SETFL, saved_flags); + while (r == -1 && errno == EINTR); + return rc; } #endif @@ -135,9 +159,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { else flags |= UV_STREAM_WRITABLE; - if (!(flags & UV_STREAM_BLOCKING)) - uv__nonblock(fd, 1); - uv__stream_open((uv_stream_t*) tty, fd, flags); tty->mode = UV_TTY_MODE_NORMAL; From c5c419f7c8bafb67b5cf077dbf53cf90b2a448e6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 23 May 2016 20:03:30 +0200 Subject: [PATCH 171/632] unix: allow nesting of kqueue fds in uv_poll_start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kqueue file descriptors don't support ioctl(FIONBIO) (or any other ioctl for that matter) so retry using fcntl(F_GETFL) + fcntl(F_SETFL) when we receive a ENOTTY error. Fixes: https://github.com/libuv/libuv/issues/883 PR-URL: https://github.com/libuv/libuv/pull/885 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/core.c | 28 +++++------------------ src/unix/internal.h | 18 +++++++++++++-- src/unix/poll.c | 7 ++++++ test/test-list.h | 14 ++++++++++++ test/test-poll.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 24 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index cdcd0b504..eb6b483af 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -40,11 +41,8 @@ #include /* getrusage */ #include -#ifdef __linux__ -# include -#endif - #ifdef __sun +# include # include # include #endif @@ -52,7 +50,6 @@ #ifdef __APPLE__ # include /* _NSGetExecutablePath */ # include -# include # if defined(O_CLOEXEC) # define UV__O_CLOEXEC O_CLOEXEC # endif @@ -61,7 +58,6 @@ #if defined(__FreeBSD__) || defined(__DragonFly__) # include # include -# include # include # define UV__O_CLOEXEC O_CLOEXEC # if defined(__FreeBSD__) && __FreeBSD__ >= 10 @@ -74,10 +70,6 @@ # endif #endif -#ifdef _AIX -#include -#endif - #if defined(__ANDROID_API__) && __ANDROID_API__ < 21 # include /* for dlsym */ #endif @@ -523,10 +515,7 @@ int uv__close(int fd) { } -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ - defined(_AIX) || defined(__DragonFly__) - -int uv__nonblock(int fd, int set) { +int uv__nonblock_ioctl(int fd, int set) { int r; do @@ -540,7 +529,7 @@ int uv__nonblock(int fd, int set) { } -int uv__cloexec(int fd, int set) { +int uv__cloexec_ioctl(int fd, int set) { int r; do @@ -553,10 +542,8 @@ int uv__cloexec(int fd, int set) { return 0; } -#else /* !(defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ - defined(_AIX) || defined(__DragonFly__)) */ -int uv__nonblock(int fd, int set) { +int uv__nonblock_fcntl(int fd, int set) { int flags; int r; @@ -587,7 +574,7 @@ int uv__nonblock(int fd, int set) { } -int uv__cloexec(int fd, int set) { +int uv__cloexec_fcntl(int fd, int set) { int flags; int r; @@ -617,9 +604,6 @@ int uv__cloexec(int fd, int set) { return 0; } -#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ - defined(_AIX) || defined(__DragonFly__) */ - /* This function is not execve-safe, there is a race window * between the call to dup() and fcntl(FD_CLOEXEC). diff --git a/src/unix/internal.h b/src/unix/internal.h index 670b14bc2..4cae73764 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -152,11 +152,25 @@ struct uv__stream_queued_fds_s { }; +#if defined(_AIX) || \ + defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__linux__) +#define uv__cloexec uv__cloexec_ioctl +#define uv__nonblock uv__nonblock_ioctl +#else +#define uv__cloexec uv__cloexec_fcntl +#define uv__nonblock uv__nonblock_fcntl +#endif + /* core */ -int uv__nonblock(int fd, int set); +int uv__cloexec_ioctl(int fd, int set); +int uv__cloexec_fcntl(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); int uv__close_nocheckstdio(int fd); -int uv__cloexec(int fd, int set); int uv__socket(int domain, int type, int protocol); int uv__dup(int fd); ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags); diff --git a/src/unix/poll.c b/src/unix/poll.c index 0d5944b0a..4c0d478ee 100644 --- a/src/unix/poll.c +++ b/src/unix/poll.c @@ -59,7 +59,14 @@ int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { if (err) return err; + /* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL). + * Workaround for e.g. kqueue fds not supporting ioctls. + */ err = uv__nonblock(fd, 1); + if (err == -ENOTTY) + if (uv__nonblock == uv__nonblock_ioctl) + err = uv__nonblock_fcntl(fd, 1); + if (err) return err; diff --git a/test/test-list.h b/test/test-list.h index c93f08199..1227da363 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -19,6 +19,8 @@ * IN THE SOFTWARE. */ +#include "uv.h" + TEST_DECLARE (platform_output) TEST_DECLARE (callback_order) TEST_DECLARE (close_order) @@ -314,6 +316,12 @@ TEST_DECLARE (poll_duplex) TEST_DECLARE (poll_unidirectional) TEST_DECLARE (poll_close) TEST_DECLARE (poll_bad_fdtype) +#ifdef __linux__ +TEST_DECLARE (poll_nested_epoll) +#endif +#ifdef UV_HAVE_KQUEUE +TEST_DECLARE (poll_nested_kqueue) +#endif TEST_DECLARE (ip4_addr) TEST_DECLARE (ip6_addr_link_local) @@ -624,6 +632,12 @@ TASK_LIST_START TEST_ENTRY (poll_unidirectional) TEST_ENTRY (poll_close) TEST_ENTRY (poll_bad_fdtype) +#ifdef __linux__ + TEST_ENTRY (poll_nested_epoll) +#endif +#ifdef UV_HAVE_KQUEUE + TEST_ENTRY (poll_nested_kqueue) +#endif TEST_ENTRY (socket_buffer_size) diff --git a/test/test-poll.c b/test/test-poll.c index f3cfe7977..33d0761a6 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -31,6 +31,16 @@ #include "uv.h" #include "task.h" +#ifdef __linux__ +# include +#endif + +#ifdef UV_HAVE_KQUEUE +# include +# include +# include +#endif + #define NUM_CLIENTS 5 #define TRANSFER_BYTES (1 << 16) @@ -601,3 +611,47 @@ TEST_IMPL(poll_bad_fdtype) { MAKE_VALGRIND_HAPPY(); return 0; } + + +#ifdef __linux__ +TEST_IMPL(poll_nested_epoll) { + uv_poll_t poll_handle; + int fd; + + fd = epoll_create(1); + ASSERT(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)); + + uv_close((uv_handle_t*) &poll_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == close(fd)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif /* __linux__ */ + + +#ifdef UV_HAVE_KQUEUE +TEST_IMPL(poll_nested_kqueue) { + uv_poll_t poll_handle; + int fd; + + fd = kqueue(); + ASSERT(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)); + + uv_close((uv_handle_t*) &poll_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == close(fd)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif /* UV_HAVE_KQUEUE */ From bd0e8e82def364fdd2c2cdf5466a362eb25f1210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 23 May 2016 23:23:08 +0200 Subject: [PATCH 172/632] doc: fix generation the first time livehtml runs PR-URL: https://github.com/libuv/libuv/pull/886 Reviewed-By: Ben Noordhuis --- docs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Makefile b/docs/Makefile index 9d461ff8a..d23c6948e 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -57,7 +57,7 @@ html: @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." -livehtml: +livehtml: html $(SPHINXAUTOBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html dirhtml: From 51d660de00e44f46d8d5222d370e52c99d76d842 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 4 Apr 2016 17:59:34 +0200 Subject: [PATCH 173/632] test: fix test_close_accept flakiness on Centos5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is not guaranteed which stream will read the data first. PR-URL: https://github.com/libuv/libuv/pull/807 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- test/test-tcp-close-accept.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/test/test-tcp-close-accept.c b/test/test-tcp-close-accept.c index 5517aaf99..0729d46dc 100644 --- a/test/test-tcp-close-accept.c +++ b/test/test-tcp-close-accept.c @@ -40,6 +40,7 @@ static unsigned int got_connections; static unsigned int close_cb_called; static unsigned int write_cb_called; static unsigned int read_cb_called; +static unsigned int pending_incoming; static void close_cb(uv_handle_t* handle) { close_cb_called++; @@ -58,8 +59,11 @@ static void connect_cb(uv_connect_t* req, int status) { if (req == &tcp_check_req) { ASSERT(status != 0); - /* Close check and incoming[0], time to finish test */ - uv_close((uv_handle_t*) &tcp_incoming[0], close_cb); + /* + * Time to finish the test: close both the check and pending incoming + * connections + */ + uv_close((uv_handle_t*) &tcp_incoming[pending_incoming], close_cb); uv_close((uv_handle_t*) &tcp_check, close_cb); return; } @@ -84,8 +88,8 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { uv_loop_t* loop; unsigned int i; - /* Only first stream should receive read events */ - ASSERT(stream == (uv_stream_t*) &tcp_incoming[0]); + pending_incoming = (uv_tcp_t*) stream - &tcp_incoming[0]; + ASSERT(pending_incoming < got_connections); ASSERT(0 == uv_read_stop(stream)); ASSERT(1 == nread); @@ -93,8 +97,10 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { read_cb_called++; /* Close all active incomings, except current one */ - for (i = 1; i < got_connections; i++) - uv_close((uv_handle_t*) &tcp_incoming[i], close_cb); + for (i = 0; i < got_connections; i++) { + if (i != pending_incoming) + uv_close((uv_handle_t*) &tcp_incoming[i], close_cb); + } /* Create new fd that should be one of the closed incomings */ ASSERT(0 == uv_tcp_init(loop, &tcp_check)); From f8691366466f020ac94a98fd6c5119938338bcce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 23 May 2016 23:26:12 +0200 Subject: [PATCH 174/632] license: libuv is no longer a Node project PR-URL: https://github.com/libuv/libuv/pull/887 Reviewed-By: Ben Noordhuis Reviewed-By: Fedor Indutny --- LICENSE | 3 --- 1 file changed, 3 deletions(-) diff --git a/LICENSE b/LICENSE index 4d411670e..cedae3466 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,3 @@ -libuv is part of the Node project: http://nodejs.org/ -libuv may be distributed alone under Node's license: - ==== Copyright Joyent, Inc. and other Node contributors. All rights reserved. From acc0175c6c16299ba7c3d37e9bbfe56d0814c0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 23 May 2016 23:34:01 +0200 Subject: [PATCH 175/632] license: add license text we've been using for a while PR-URL: https://github.com/libuv/libuv/pull/887 Reviewed-By: Ben Noordhuis Reviewed-By: Fedor Indutny --- LICENSE | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/LICENSE b/LICENSE index cedae3466..41ba44c28 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,30 @@ +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 +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 parts of libuv originating from the +https://github.com/joyent/libuv repository: + ==== Copyright Joyent, Inc. and other Node contributors. All rights reserved. From 8b3176933d316e2de0eb4606e4afcac8c6a465ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 23 May 2016 23:39:46 +0200 Subject: [PATCH 176/632] doc: add licensing information to README PR-URL: https://github.com/libuv/libuv/pull/887 Reviewed-By: Ben Noordhuis Reviewed-By: Fedor Indutny --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e94fcc902..1b40e76ea 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,10 @@ Starting with version 1.0.0 libuv follows the [semantic versioning](http://semve scheme. The API change and backwards compatibility rules are those indicated by SemVer. libuv will keep a stable ABI across major releases. +## Licensing + +libuv is licensed under the MIT license. Check the [LICENSE file](LICENSE). + ## Community * [Mailing list](http://groups.google.com/group/libuv) From 6cf935b1eac69c9d7ab889469f524a795213e5ac Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sat, 28 May 2016 12:38:07 +0200 Subject: [PATCH 177/632] win,pipe: fixed formatting, DWORD is long unsigned MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/890 Reviewed-By: Saúl Ibarra Corretgé --- src/win/pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index a784325c5..2a949e79b 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -85,7 +85,7 @@ static void eof_timer_close_cb(uv_handle_t* handle); static void uv_unique_pipe_name(char* ptr, char* name, size_t size) { - snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId()); + snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId()); } From 399e2c814019dfeeec45f2de0ecbb0893ebb5126 Mon Sep 17 00:00:00 2001 From: Jason Ginchereau Date: Sat, 30 Apr 2016 16:56:56 -0700 Subject: [PATCH 178/632] win: support sub-second precision in uv_fs_futimes() Fixes: https://github.com/libuv/libuv/issues/800 PR-URL: https://github.com/libuv/libuv/pull/849 Reviewed-by: Bert Belder --- docs/src/fs.rst | 2 ++ src/win/fs.c | 6 +++--- test/test-fs.c | 22 ++++++++++++++++++++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 69e283f4c..918bff946 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -258,6 +258,8 @@ API Equivalent to :man:`utime(2)` and :man:`futime(2)` respectively. + .. versionchanged:: 1.10.0 sub-second precission is supported on Windows + .. c:function:: int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) Equivalent to :man:`link(2)`. diff --git a/src/win/fs.c b/src/win/fs.c index 54dfea724..24c608475 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -94,7 +94,7 @@ #define TIME_T_TO_FILETIME(time, filetime_ptr) \ do { \ - uint64_t bigtime = ((int64_t) (time) * 10000000LL) + \ + uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \ 116444736000000000ULL; \ (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \ (filetime_ptr)->dwHighDateTime = bigtime >> 32; \ @@ -1429,8 +1429,8 @@ 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; - TIME_T_TO_FILETIME((time_t) atime, &filetime_a); - TIME_T_TO_FILETIME((time_t) mtime, &filetime_m); + TIME_T_TO_FILETIME(atime, &filetime_a); + TIME_T_TO_FILETIME(mtime, &filetime_m); if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) { return -1; diff --git a/test/test-fs.c b/test/test-fs.c index 1cc1a7c06..250d13501 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -662,8 +662,8 @@ static void check_utime(const char* path, double atime, double mtime) { ASSERT(req.result == 0); s = &req.statbuf; - ASSERT(s->st_atim.tv_sec == atime); - ASSERT(s->st_mtim.tv_sec == mtime); + ASSERT(s->st_atim.tv_sec + (s->st_atim.tv_nsec / 1000000000.0) == atime); + ASSERT(s->st_mtim.tv_sec + (s->st_mtim.tv_nsec / 1000000000.0) == mtime); uv_fs_req_cleanup(&req); } @@ -1968,6 +1968,15 @@ TEST_IMPL(fs_utime) { atime = mtime = 400497753; /* 1982-09-10 11:22:33 */ + /* + * Test sub-second timestamps only on Windows (assuming 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. + */ +#ifdef _WIN32 + mtime += 0.444; /* 1982-09-10 11:22:33.444 */ +#endif + r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL); ASSERT(r == 0); ASSERT(req.result == 0); @@ -2055,6 +2064,15 @@ TEST_IMPL(fs_futime) { atime = mtime = 400497753; /* 1982-09-10 11:22:33 */ + /* + * Test sub-second timestamps only on Windows (assuming 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. + */ +#ifdef _WIN32 + mtime += 0.444; /* 1982-09-10 11:22:33.444 */ +#endif + r = uv_fs_open(NULL, &req, path, O_RDWR, 0, NULL); ASSERT(r >= 0); ASSERT(req.result >= 0); From 193a6f9b93b8b50f9fa9290b207a3513480c4f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 29 May 2016 11:50:54 +0200 Subject: [PATCH 179/632] unix: ignore EINPROGRESS in uv__close It's just an indicator that the operation will happen later, so return success. PR-URL: https://github.com/libuv/libuv/pull/892 Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis --- src/unix/core.c | 4 ++-- src/unix/fs.c | 2 +- src/unix/process.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index eb6b483af..645223833 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -500,8 +500,8 @@ int uv__close_nocheckstdio(int fd) { rc = close(fd); if (rc == -1) { rc = -errno; - if (rc == -EINTR) - rc = -EINPROGRESS; /* For platform/libc consistency. */ + if (rc == -EINTR || rc == -EINPROGRESS) + rc = 0; /* The close is in progress, not an error. */ errno = saved_errno; } diff --git a/src/unix/fs.c b/src/unix/fs.c index 085970a06..fed15d5eb 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -251,7 +251,7 @@ static ssize_t uv__fs_open(uv_fs_t* req) { */ if (r >= 0 && uv__cloexec(r, 1) != 0) { r = uv__close(r); - if (r != 0 && r != -EINPROGRESS) + if (r != 0) abort(); r = -1; } diff --git a/src/unix/process.c b/src/unix/process.c index ef10a3422..8a010edc7 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -232,7 +232,7 @@ static int uv__process_open_stream(uv_stdio_container_t* container, return 0; err = uv__close(pipefds[1]); - if (err != 0 && err != -EINPROGRESS) + if (err != 0) abort(); pipefds[1] = -1; From 422bc5f16814e4d123077b8ed119f30d1c49d8ca Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Mon, 30 May 2016 11:21:00 -0400 Subject: [PATCH 180/632] doc: add Imran Iqbal (iWuzHere) to maintainers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/894 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- MAINTAINERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 80f63fd68..420e4498b 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -10,6 +10,7 @@ libuv is currently managed by the following individuals: - GPG key: 94AE 3667 5C46 4D64 BAFA 68DD 7434 390B DBE9 B9C5 (pubkey-cjihrig) * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) +* **Imran Iqbal** ([@iWuzHere](https://github.com/iWuzHere)) * **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul)) - GPG key: FDF5 1936 4458 319F A823 3DC9 410E 5553 AE9B C059 (pubkey-saghul) From 71bd07e588942b95009fbe055d4ae8cafe6532fa Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Tue, 31 May 2016 14:16:07 -0400 Subject: [PATCH 181/632] doc: update docs with AIX related information MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/882 PR-URL: https://github.com/libuv/libuv/pull/896 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- docs/src/fs.rst | 4 ++++ docs/src/fs_event.rst | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 918bff946..f810319ca 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -258,6 +258,10 @@ API Equivalent to :man:`utime(2)` and :man:`futime(2)` respectively. + .. note:: + AIX: This function only works for AIX 7.1 and newer. It can still be called on older + versions but will return ``UV_ENOSYS``. + .. versionchanged:: 1.10.0 sub-second precission is supported on Windows .. c:function:: int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) diff --git a/docs/src/fs_event.rst b/docs/src/fs_event.rst index c2d7f5202..c08ade2ef 100644 --- a/docs/src/fs_event.rst +++ b/docs/src/fs_event.rst @@ -8,6 +8,20 @@ FS Event handles allow the user to monitor a given path for changes, for example if the file was renamed or there was a generic change in it. This handle uses the best backend for the job on each platform. +.. note:: + For AIX, the non default IBM bos.ahafs package has to be installed. + The AIX Event Infrastructure file system (ahafs) has some limitations: + + - ahafs tracks monitoring per process and is not thread safe. A separate process + must be spawned for each monitor for the same event. + - Events for file modification (writing to a file) are not received if only the + containing folder is watched. + + See documentation_ for more details. + + .. _documentation: http://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/ + + Data types ---------- From 89f01a41ab71b3f539247bfb54e15f8dc2c395f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A1ri=20Tristan=20Helgason?= Date: Mon, 30 May 2016 08:36:36 +0000 Subject: [PATCH 182/632] test: silence build warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/893 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Johan Bergström Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 2 +- test/test-list.h | 4 ++-- test/test-platform-output.c | 2 -- test/test-poll-close-doesnt-corrupt-stack.c | 10 ++++++---- test/test-poll-closesocket.c | 8 ++++++-- uv.gyp | 1 + 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Makefile.am b/Makefile.am index 05ccd58ac..3670ad464 100644 --- a/Makefile.am +++ b/Makefile.am @@ -128,7 +128,7 @@ EXTRA_DIST = test/fixtures/empty_file \ TESTS = test/run-tests check_PROGRAMS = test/run-tests -test_run_tests_CFLAGS = +test_run_tests_CFLAGS = -Wno-long-long test_run_tests_LDFLAGS = test_run_tests_SOURCES = test/blackhole-server.c \ test/dns-server.c \ diff --git a/test/test-list.h b/test/test-list.h index 1227da363..3d99c266c 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -326,9 +326,9 @@ TEST_DECLARE (poll_nested_kqueue) TEST_DECLARE (ip4_addr) TEST_DECLARE (ip6_addr_link_local) -#ifdef _WIN32 TEST_DECLARE (poll_close_doesnt_corrupt_stack) TEST_DECLARE (poll_closesocket) +#ifdef _WIN32 TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) #if !defined(USING_UV_SHARED) TEST_DECLARE (argument_escaping) @@ -669,9 +669,9 @@ TASK_LIST_START TEST_ENTRY (fs_poll_getpath) TEST_ENTRY (kill) -#ifdef _WIN32 TEST_ENTRY (poll_close_doesnt_corrupt_stack) TEST_ENTRY (poll_closesocket) +#ifdef _WIN32 TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows) #if !defined(USING_UV_SHARED) TEST_ENTRY (argument_escaping) diff --git a/test/test-platform-output.c b/test/test-platform-output.c index bd61454fa..b89550801 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -61,8 +61,6 @@ TEST_IMPL(platform_output) { ASSERT(rusage.ru_utime.tv_usec >= 0); ASSERT(rusage.ru_stime.tv_sec >= 0); ASSERT(rusage.ru_stime.tv_usec >= 0); - ASSERT(rusage.ru_majflt >= 0); - ASSERT(rusage.ru_maxrss >= 0); printf("uv_getrusage:\n"); printf(" user: %llu sec %llu microsec\n", (unsigned long long) rusage.ru_utime.tv_sec, diff --git a/test/test-poll-close-doesnt-corrupt-stack.c b/test/test-poll-close-doesnt-corrupt-stack.c index fc2cc004f..1dfc80e35 100644 --- a/test/test-poll-close-doesnt-corrupt-stack.c +++ b/test/test-poll-close-doesnt-corrupt-stack.c @@ -19,8 +19,6 @@ * IN THE SOFTWARE. */ -#ifdef _WIN32 - #include #include @@ -37,6 +35,7 @@ uv_os_sock_t sock; uv_poll_t handle; +#ifdef _WIN32 static int close_cb_called = 0; @@ -69,9 +68,13 @@ static void NO_INLINE close_socket_and_verify_stack() { for (i = 0; i < ARRAY_SIZE(data); i++) ASSERT(data[i] == MARKER); } +#endif TEST_IMPL(poll_close_doesnt_corrupt_stack) { +#ifndef _WIN32 + RETURN_SKIP("Test only relevant on Windows"); +#else struct WSAData wsa_data; int r; unsigned long on; @@ -109,6 +112,5 @@ TEST_IMPL(poll_close_doesnt_corrupt_stack) { MAKE_VALGRIND_HAPPY(); return 0; +#endif } - -#endif /* _WIN32 */ diff --git a/test/test-poll-closesocket.c b/test/test-poll-closesocket.c index 4db74a01f..ecaa9e54a 100644 --- a/test/test-poll-closesocket.c +++ b/test/test-poll-closesocket.c @@ -19,7 +19,6 @@ * IN THE SOFTWARE. */ -#ifdef _WIN32 #include @@ -29,6 +28,7 @@ uv_os_sock_t sock; uv_poll_t handle; +#ifdef _WIN32 static int close_cb_called = 0; @@ -50,9 +50,13 @@ static void poll_cb(uv_poll_t* h, int status, int events) { uv_close((uv_handle_t*) &handle, close_cb); } +#endif TEST_IMPL(poll_closesocket) { +#ifndef _WIN32 + RETURN_SKIP("Test only relevant on Windows"); +#else struct WSAData wsa_data; int r; unsigned long on; @@ -85,5 +89,5 @@ TEST_IMPL(poll_closesocket) { MAKE_VALGRIND_HAPPY(); return 0; -} #endif +} diff --git a/uv.gyp b/uv.gyp index 2fdd59ac7..aa4a42445 100644 --- a/uv.gyp +++ b/uv.gyp @@ -426,6 +426,7 @@ 'libraries': [ '-lws2_32' ] }, { # POSIX 'defines': [ '_GNU_SOURCE' ], + 'cflags': [ '-Wno-long-long' ], 'sources': [ 'test/runner-unix.c', 'test/runner-unix.h', From 5af420669a40974ce91dd66c51f779fd66c19f63 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Wed, 8 Jun 2016 17:18:37 -0400 Subject: [PATCH 183/632] doc: add iWuzHere GPG ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/902 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- MAINTAINERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 420e4498b..5974d9d3f 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -11,6 +11,7 @@ libuv is currently managed by the following individuals: * **Fedor Indutny** ([@indutny](https://github.com/indutny)) - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) * **Imran Iqbal** ([@iWuzHere](https://github.com/iWuzHere)) + - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) * **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul)) - GPG key: FDF5 1936 4458 319F A823 3DC9 410E 5553 AE9B C059 (pubkey-saghul) From c4e917790ed17c3452e4a97e74fd3b7d60a004e0 Mon Sep 17 00:00:00 2001 From: Nicolas Cavallari Date: Wed, 8 Jun 2016 14:33:58 +0200 Subject: [PATCH 184/632] linux-core: fix uv_get_total/free_memory on uclibc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The _SC_PHYS_PAGES and _SC_AVPHYS_PAGES are not POSIX sysconf values, so the standart C libraries have no obligation to support it, even on Linux. Use the Linux sysinfo() system call instead. PR-URL: https://github.com/libuv/libuv/pull/901 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/unix/linux-core.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index b48a11117..ae927b7eb 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -484,12 +484,20 @@ int uv_exepath(char* buffer, size_t* size) { uint64_t uv_get_free_memory(void) { - return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES); + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.freeram * info.mem_unit; + return 0; } uint64_t uv_get_total_memory(void) { - return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES); + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.totalram * info.mem_unit; + return 0; } From 0c82efa4d5e949318909786ac5e8c00376ccc76d Mon Sep 17 00:00:00 2001 From: Michael Neumann Date: Sun, 22 May 2016 23:51:51 +0200 Subject: [PATCH 185/632] build: fix build on DragonFly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/884 Reviewed-By: Ben Noordhuis Reviewed-By: Imran Iqbal Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 3670ad464..882bbef53 100644 --- a/Makefile.am +++ b/Makefile.am @@ -312,6 +312,7 @@ endif if DRAGONFLY include_HEADERS += include/uv-bsd.h +libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c test_run_tests_LDFLAGS += -lutil endif From 96b37293a9a6a4f100e117b9760aaac3e39f94ee Mon Sep 17 00:00:00 2001 From: Michael Neumann Date: Mon, 23 May 2016 00:02:54 +0200 Subject: [PATCH 186/632] unix: correctly detect named pipes on DragonFly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes test-stdio-over-pipes and test-pipe-sendmsg test cases. ~~~~ Assertion failed in test/test-stdio-over-pipes.c on line 56: term_signal == 0 Assertion failed in test/test-pipe-sendmsg.c on line 86: pending == UV_NAMED_PIPE ~~~~ This fixes a longstanding issue with nodejs on DragonFly, which was triggered whenever spawning a process and pipes were involed. PR-URL: https://github.com/libuv/libuv/pull/884 Reviewed-By: Ben Noordhuis Reviewed-By: Imran Iqbal Reviewed-By: Saúl Ibarra Corretgé --- src/unix/stream.c | 4 ++-- src/unix/tty.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 7dbc556f7..eaec92bb3 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -962,8 +962,8 @@ uv_handle_type uv__handle_type(int fd) { return UV_UNKNOWN_HANDLE; if (type == SOCK_STREAM) { -#if defined(_AIX) - /* on AIX the getsockname call returns an empty sa structure +#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. */ diff --git a/src/unix/tty.c b/src/unix/tty.c index ca1087123..a56afe183 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -289,14 +289,14 @@ uv_handle_type uv_guess_handle(uv_file file) { return UV_UDP; if (type == SOCK_STREAM) { -#if defined(_AIX) - /* on AIX the getsockname call returns an empty sa structure +#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 (len == 0) return UV_NAMED_PIPE; -#endif /* defined(_AIX) */ +#endif /* defined(_AIX) || defined(__DragonFly__) */ if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) return UV_TCP; From cc1d38ea933e457b7a075b5a26822936aae1ce34 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 6 Jun 2016 14:39:05 +0200 Subject: [PATCH 187/632] test: make tap output the default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the non-tap output, it's sometimes difficult to distinguish skipped tests from test failures. PR-URL: https://github.com/libuv/libuv/pull/898 Reviewed-By: Saúl Ibarra Corretgé --- test/runner-unix.c | 9 +------ test/runner-win.c | 33 ++++++++---------------- test/runner.c | 64 +++------------------------------------------- test/runner.h | 3 --- 4 files changed, 16 insertions(+), 93 deletions(-) diff --git a/test/runner-unix.c b/test/runner-unix.c index 2405fa878..69b81b215 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -43,11 +43,6 @@ /* Do platform-specific initialization. */ int platform_init(int argc, char **argv) { - const char* tap; - - tap = getenv("UV_TAP_OUTPUT"); - tap_output = (tap != NULL && atoi(tap) > 0); - /* Disable stdio output buffering. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); @@ -310,9 +305,7 @@ int process_copy_output(process_info_t *p, int fd) { /* TODO: what if write doesn't write the whole buffer... */ nwritten = 0; - if (tap_output) - nwritten += write(fd, "#", 1); - + nwritten += write(fd, "#", 1); nwritten += write(fd, buf, strlen(buf)); if (nwritten < 0) { diff --git a/test/runner-win.c b/test/runner-win.c index 97ef7599e..c2a45828d 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -44,11 +44,6 @@ /* Do platform-specific initialization. */ int platform_init(int argc, char **argv) { - const char* tap; - - tap = getenv("UV_TAP_OUTPUT"); - tap_output = (tap != NULL && atoi(tap) > 0); - /* Disable the "application crashed" popup. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); @@ -225,29 +220,23 @@ int process_copy_output(process_info_t *p, int fd) { return -1; } - if (tap_output) - write(fd, "#", 1); + write(fd, "#", 1); while (ReadFile(p->stdio_out, (void*)&buf, sizeof(buf), &read, NULL) && read > 0) { - if (tap_output) { - start = buf; - - while ((line = strchr(start, '\n')) != NULL) { - write(fd, start, line - start + 1); - write(fd, "#", 1); - start = line + 1; - } - - if (start < buf + read) - write(fd, start, buf + read - start); - } else { - write(fd, buf, read); + start = buf; + + while ((line = strchr(start, '\n')) != NULL) { + write(fd, start, line - start + 1); + write(fd, "#", 1); + start = line + 1; } + + if (start < buf + read) + write(fd, start, buf + read - start); } - if (tap_output) - write(fd, "\n", 1); + write(fd, "\n", 1); if (GetLastError() != ERROR_HANDLE_EOF) return -1; diff --git a/test/runner.c b/test/runner.c index c616d1764..ef3fda57a 100644 --- a/test/runner.c +++ b/test/runner.c @@ -28,31 +28,6 @@ char executable_path[sizeof(executable_path)]; -int tap_output = 0; - - -static void log_progress(int total, - int passed, - int failed, - int todos, - int skipped, - const char* name) { - int progress; - - if (total == 0) - total = 1; - - progress = 100 * (passed + failed + skipped + todos) / total; - fprintf(stderr, "[%% %3d|+ %3d|- %3d|T %3d|S %3d]: %s", - progress, - passed, - failed, - todos, - skipped, - name); - fflush(stderr); -} - const char* fmt(double d) { static char buf[1024]; @@ -109,10 +84,8 @@ int run_tests(int benchmark_output) { } } - if (tap_output) { - fprintf(stderr, "1..%d\n", total); - fflush(stderr); - } + fprintf(stderr, "1..%d\n", total); + fflush(stderr); /* Run all tests. */ passed = 0; @@ -125,13 +98,6 @@ int run_tests(int benchmark_output) { continue; } - if (!tap_output) - rewind_cursor(); - - if (!benchmark_output && !tap_output) { - log_progress(total, passed, failed, todos, skipped, task->task_name); - } - test_result = run_test(task->task_name, benchmark_output, current); switch (test_result) { case TEST_OK: passed++; break; @@ -142,13 +108,6 @@ int run_tests(int benchmark_output) { current++; } - if (!tap_output) - rewind_cursor(); - - if (!benchmark_output && !tap_output) { - log_progress(total, passed, failed, todos, skipped, "Done.\n"); - } - return failed; } @@ -319,22 +278,11 @@ int run_test(const char* test, FATAL("process_wait failed"); } - if (tap_output) - log_tap_result(test_count, test, status, &processes[i]); + log_tap_result(test_count, test, status, &processes[i]); /* Show error and output from processes if the test failed. */ if (status != 0 || task->show_output) { - if (tap_output) { - fprintf(stderr, "#"); - } else if (status == TEST_TODO) { - fprintf(stderr, "\n`%s` todo\n", test); - } else if (status == TEST_SKIP) { - fprintf(stderr, "\n`%s` skipped\n", test); - } else if (status != 0) { - fprintf(stderr, "\n`%s` failed: %s\n", test, errmsg); - } else { - fprintf(stderr, "\n"); - } + fprintf(stderr, "#"); fflush(stderr); for (i = 0; i < process_count; i++) { @@ -359,10 +307,6 @@ int run_test(const char* test, } } - if (!tap_output) { - fprintf(stderr, "=============================================================\n"); - } - /* In benchmark mode show concise output from the main process. */ } else if (benchmark_output) { switch (process_output_size(main_proc)) { diff --git a/test/runner.h b/test/runner.h index 78f3c880a..851744788 100644 --- a/test/runner.h +++ b/test/runner.h @@ -172,7 +172,4 @@ void process_cleanup(process_info_t *p); /* Move the console cursor one line up and back to the first column. */ void rewind_cursor(void); -/* trigger output as tap */ -extern int tap_output; - #endif /* RUNNER_H_ */ From dd9f751eadffdc63f25917f1cb8859707b90d3de Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 6 Jun 2016 14:45:40 +0200 Subject: [PATCH 188/632] test: don't dump output for skipped tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A skipped test already prints a diagnostic. Dumping its output just prints the same message twice. PR-URL: https://github.com/libuv/libuv/pull/898 Reviewed-By: Saúl Ibarra Corretgé --- test/runner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runner.c b/test/runner.c index ef3fda57a..ee87a2986 100644 --- a/test/runner.c +++ b/test/runner.c @@ -281,7 +281,7 @@ int run_test(const char* test, log_tap_result(test_count, test, status, &processes[i]); /* Show error and output from processes if the test failed. */ - if (status != 0 || task->show_output) { + if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) { fprintf(stderr, "#"); fflush(stderr); From b936ace934abcebad19b9bc0089998cc89e151af Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 6 Jun 2016 14:47:51 +0200 Subject: [PATCH 189/632] test: improve formatting of diagnostic messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Put a space after the '#' and handle messages with newlines. PR-URL: https://github.com/libuv/libuv/pull/898 Reviewed-By: Saúl Ibarra Corretgé --- test/runner-unix.c | 17 +++-------------- test/runner-win.c | 22 +++------------------- test/runner.c | 24 +++++++++++++++++++++--- test/runner.h | 6 ++++-- 4 files changed, 31 insertions(+), 38 deletions(-) diff --git a/test/runner-unix.c b/test/runner-unix.c index 69b81b215..0edd671b9 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -289,8 +289,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, int fd) { - ssize_t nwritten; +int process_copy_output(process_info_t* p, FILE* stream) { char buf[1024]; int r; @@ -301,18 +300,8 @@ int process_copy_output(process_info_t *p, int fd) { } /* TODO: what if the line is longer than buf */ - while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) { - /* TODO: what if write doesn't write the whole buffer... */ - nwritten = 0; - - nwritten += write(fd, "#", 1); - nwritten += write(fd, buf, strlen(buf)); - - if (nwritten < 0) { - perror("write"); - return -1; - } - } + while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) + print_lines(buf, strlen(buf), stream); if (ferror(p->stdout_file)) { perror("read"); diff --git a/test/runner-win.c b/test/runner-win.c index c2a45828d..1b4a569ae 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -208,10 +208,9 @@ long int process_output_size(process_info_t *p) { } -int process_copy_output(process_info_t *p, int fd) { +int process_copy_output(process_info_t* p, FILE* stream) { DWORD read; char buf[1024]; - char *line, *start; if (SetFilePointer(p->stdio_out, 0, @@ -220,23 +219,8 @@ int process_copy_output(process_info_t *p, int fd) { return -1; } - write(fd, "#", 1); - - while (ReadFile(p->stdio_out, (void*)&buf, sizeof(buf), &read, NULL) && - read > 0) { - start = buf; - - while ((line = strchr(start, '\n')) != NULL) { - write(fd, start, line - start + 1); - write(fd, "#", 1); - start = line + 1; - } - - if (start < buf + read) - write(fd, start, buf + read - start); - } - - write(fd, "\n", 1); + while (ReadFile(p->stdio_out, &buf, sizeof(buf), &read, NULL) && read > 0) + print_lines(buf, read, stream); if (GetLastError() != ERROR_HANDLE_EOF) return -1; diff --git a/test/runner.c b/test/runner.c index ee87a2986..f611ae28a 100644 --- a/test/runner.c +++ b/test/runner.c @@ -282,7 +282,7 @@ 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) { - fprintf(stderr, "#"); + fprintf(stderr, "# "); fflush(stderr); for (i = 0; i < process_count; i++) { @@ -302,7 +302,7 @@ int run_test(const char* test, default: fprintf(stderr, "Output from process `%s`:\n", process_get_name(&processes[i])); fflush(stderr); - process_copy_output(&processes[i], fileno(stderr)); + process_copy_output(&processes[i], stderr); break; } } @@ -322,7 +322,7 @@ int run_test(const char* test, default: for (i = 0; i < process_count; i++) { - process_copy_output(&processes[i], fileno(stderr)); + process_copy_output(&processes[i], stderr); } break; } @@ -408,3 +408,21 @@ void print_tests(FILE* stream) { } } } + + +void print_lines(const char* buffer, size_t size, FILE* stream) { + const char* start; + const char* end; + + start = buffer; + while ((end = memchr(start, '\n', &buffer[size] - start))) { + fprintf(stream, "# %.*s\n", (int) (end - start), start); + fflush(stream); + start = end + 1; + } + + if (start < &buffer[size]) { + fprintf(stream, "# %s\n", start); + fflush(stream); + } +} diff --git a/test/runner.h b/test/runner.h index 851744788..555f2f8eb 100644 --- a/test/runner.h +++ b/test/runner.h @@ -126,6 +126,8 @@ 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); /* * Stuff that should be implemented by test-runner-.h @@ -148,8 +150,8 @@ int process_wait(process_info_t *vec, int n, int timeout); /* Returns the number of bytes in the stdio output buffer for process `p`. */ 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, int fd); +/* Copy the contents of the stdio output buffer to `stream`. */ +int process_copy_output(process_info_t* p, FILE* stream); /* Copy the last line of the stdio output buffer to `buffer` */ int process_read_last_line(process_info_t *p, From 7e7e22126008813a187aa95041ae95f03afc3c5b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 6 Jun 2016 15:37:42 +0200 Subject: [PATCH 190/632] test: remove unused RETURN_TODO macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/898 Reviewed-By: Saúl Ibarra Corretgé --- test/runner.c | 10 +--------- test/task.h | 8 -------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/test/runner.c b/test/runner.c index f611ae28a..5e22c18f2 100644 --- a/test/runner.c +++ b/test/runner.c @@ -70,7 +70,6 @@ int run_tests(int benchmark_output) { int total; int passed; int failed; - int todos; int skipped; int current; int test_result; @@ -90,7 +89,6 @@ int run_tests(int benchmark_output) { /* Run all tests. */ passed = 0; failed = 0; - todos = 0; skipped = 0; current = 1; for (task = TASKS; task->main; task++) { @@ -101,7 +99,6 @@ 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_TODO: todos++; break; case TEST_SKIP: skipped++; break; default: failed++; } @@ -125,10 +122,6 @@ void log_tap_result(int test_count, result = "ok"; directive = ""; break; - case TEST_TODO: - result = "not ok"; - directive = " # TODO "; - break; case TEST_SKIP: result = "ok"; directive = " # SKIP "; @@ -138,8 +131,7 @@ void log_tap_result(int test_count, directive = ""; } - if ((status == TEST_SKIP || status == TEST_TODO) && - process_output_size(process) > 0) { + if (status == TEST_SKIP && process_output_size(process) > 0) { process_read_last_line(process, reason, sizeof reason); } else { reason[0] = '\0'; diff --git a/test/task.h b/test/task.h index 96cc6377c..65a1132e4 100644 --- a/test/task.h +++ b/test/task.h @@ -136,7 +136,6 @@ const char* fmt(double d); /* Reserved test exit codes. */ enum test_status { TEST_OK = 0, - TEST_TODO, TEST_SKIP }; @@ -145,13 +144,6 @@ enum test_status { return TEST_OK; \ } while (0) -#define RETURN_TODO(explanation) \ - do { \ - fprintf(stderr, "%s\n", explanation); \ - fflush(stderr); \ - return TEST_TODO; \ - } while (0) - #define RETURN_SKIP(explanation) \ do { \ fprintf(stderr, "%s\n", explanation); \ From 23043a7e95c93c35d076211a640427ce69f0cb96 Mon Sep 17 00:00:00 2001 From: Pierre-Marie de Rodat Date: Mon, 13 Jun 2016 08:15:33 +0200 Subject: [PATCH 191/632] doc: fix stream typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/910 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- docs/src/stream.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/stream.rst b/docs/src/stream.rst index ed0c79d00..dfcad0fa2 100644 --- a/docs/src/stream.rst +++ b/docs/src/stream.rst @@ -61,7 +61,7 @@ Data types .. c:type:: void (*uv_shutdown_cb)(uv_shutdown_t* req, int status) - Callback called after s shutdown request has been completed. `status` will + Callback called after a shutdown request has been completed. `status` will be 0 in case of success, < 0 otherwise. .. c:type:: void (*uv_connection_cb)(uv_stream_t* server, int status) @@ -92,7 +92,7 @@ Public members .. c:member:: uv_stream_t* uv_write_t.send_handle - Pointer to the stream being sent using this write request.. + Pointer to the stream being sent using this write request. .. seealso:: The :c:type:`uv_handle_t` members also apply. From e2da05669812ab0385870b9e293ae1cf4425bebb Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Fri, 10 Jun 2016 18:41:49 -0400 Subject: [PATCH 192/632] doc: update coding style link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/909 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ef5c2b2fe..aa97506db 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -165,5 +165,5 @@ 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.freelibuv.net/?channels=libuv -[Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml +[Google C/C++ style guide]: https://google.github.io/styleguide/cppguide.html [project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md From fcfe230130b26a943fd5fd4b390c484a5ab308f4 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Tue, 14 Jun 2016 15:17:43 -0400 Subject: [PATCH 193/632] unix,fs: use uint64_t instead of unsigned long MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `unsigned long` is not guaranteed to be 8 bytes long. This prevents overflow errors from occurring as seen in issue #913 Fixes: https://github.com/libuv/libuv/issues/913 PR-URL: https://github.com/libuv/libuv/pull/914 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis --- 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 fed15d5eb..508b748a3 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -151,9 +151,9 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { goto skip; ts[0].tv_sec = req->atime; - ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000; + ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; ts[1].tv_sec = req->mtime; - ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; r = uv__utimesat(req->file, NULL, ts, 0); if (r == 0) @@ -167,9 +167,9 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { skip: tv[0].tv_sec = req->atime; - tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; tv[1].tv_sec = req->mtime; - tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file); r = utimes(path, tv); @@ -198,9 +198,9 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { || defined(__sun) struct timeval tv[2]; tv[0].tv_sec = req->atime; - tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; tv[1].tv_sec = req->mtime; - tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; # if defined(__sun) return futimesat(req->file, NULL, tv); # else @@ -209,9 +209,9 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { #elif defined(_AIX71) struct timespec ts[2]; ts[0].tv_sec = req->atime; - ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000; + ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; ts[1].tv_sec = req->mtime; - ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; return futimens(req->file, ts); #else errno = ENOSYS; From 9940b84041402f85ec90596a47ea5c4dec6efd14 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Mon, 13 Jun 2016 14:55:41 -0400 Subject: [PATCH 194/632] build: check for warnings for -fvisibility=hidden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/911 PR-URL: https://github.com/libuv/libuv/pull/912 Reviewed-By: Ben Noordhuis Reviewed-By: Fedor Indutny Reviewed-By: Saúl Ibarra Corretgé --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d9251f319..4a106bec9 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,7 @@ AC_ENABLE_SHARED AC_ENABLE_STATIC AC_PROG_CC AM_PROG_CC_C_O -CC_CHECK_CFLAGS_APPEND([-fvisibility=hidden]) +CC_FLAG_VISIBILITY #[-fvisibility=hidden] CC_CHECK_CFLAGS_APPEND([-g]) CC_CHECK_CFLAGS_APPEND([-std=gnu89]) CC_CHECK_CFLAGS_APPEND([-pedantic]) From 2fc54807fca6d3d3022d23fda6d3c060ebbc5be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 15 Jun 2016 09:46:03 +0200 Subject: [PATCH 195/632] unix: remove unneeded TODO note It's already documented in http://docs.libuv.org/en/v1.x/stream.html#c.uv_accept PR-URL: https://github.com/libuv/libuv/pull/916 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Imran Iqbal --- src/unix/stream.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index eaec92bb3..2143cd88d 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -571,7 +571,6 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int uv_accept(uv_stream_t* server, uv_stream_t* client) { int err; - /* TODO document this */ assert(server->loop == client->loop); if (server->accepted_fd == -1) From 7b9e25a9a978e2655b77678670f4b329d95bb9d5 Mon Sep 17 00:00:00 2001 From: Luca Bruno Date: Sun, 19 Jun 2016 18:20:53 +0200 Subject: [PATCH 196/632] test: skip tty_pty test if pty is not available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not let `tty_pty` test fail if no terminals are available to `openpty()`. PR-URL: https://github.com/libuv/libuv/pull/919 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- test/test-tty.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/test-tty.c b/test/test-tty.c index 55cc01675..5787d1dae 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -262,14 +262,17 @@ TEST_IMPL(tty_file) { TEST_IMPL(tty_pty) { # if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) - int master_fd, slave_fd; + int master_fd, slave_fd, r; struct winsize w; uv_loop_t loop; uv_tty_t master_tty, slave_tty; ASSERT(0 == uv_loop_init(&loop)); - ASSERT(0 == openpty(&master_fd, &slave_fd, NULL, NULL, &w)); + 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)); /* Check if the file descriptor was reopened. If it is, From d75e334e34487575bcb46f6311fefbdc4849a564 Mon Sep 17 00:00:00 2001 From: Brian Maher Date: Fri, 10 Jun 2016 09:04:59 -0700 Subject: [PATCH 197/632] sunos: set phys_addr of interface_address using ARP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If getifaddrs() returns an all zero ifa_addr field, then use ARP to set the phys_addr field of the uv_interface_address_t on the sunos platform. PR-URL: https://github.com/libuv/libuv/pull/907 Reviewed-By: Imran Iqbal Reviewed-By: Saúl Ibarra Corretgé --- src/unix/sunos.c | 68 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/src/unix/sunos.c b/src/unix/sunos.c index e67be8fcf..efadcea72 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -33,6 +33,8 @@ #endif #include #include +#include +#include #include #include @@ -692,13 +694,57 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } +/* + * Inspired By: + * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris + * http://www.pauliesworld.org/project/getmac.c + */ +static int uv__set_phys_addr(uv_interface_address_t* address, + struct ifaddrs* ent) { + + struct sockaddr_dl* sa_addr; + int sockfd; + int i; + struct arpreq arpreq; + + /* This appears to only work as root */ + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + for (i = 0; i < sizeof(address->phys_addr); i++) { + if (address->phys_addr[i] != 0) + return 0; + } + memset(&arpreq, 0, sizeof(arpreq)); + if (address->address.address4.sin_family == AF_INET) { + struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa); + sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr; + } else if (address->address.address4.sin_family == AF_INET6) { + struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa); + memcpy(sin->sin6_addr.s6_addr, + address->address.address6.sin6_addr.s6_addr, + sizeof(address->address.address6.sin6_addr.s6_addr)); + } else { + return 0; + } + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + return -errno; + + if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) { + uv__close(sockfd); + return -errno; + } + memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr)); + uv__close(sockfd); + return 0; +} int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #ifdef SUNOS_NO_IFADDRS return -ENOSYS; #else uv_interface_address_t* address; - struct sockaddr_dl* sa_addr; struct ifaddrs* addrs; struct ifaddrs* ent; int i; @@ -751,28 +797,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) || (ent->ifa_flags & IFF_LOOPBACK)); + uv__set_phys_addr(address, ent); address++; } - /* Fill in physical addresses for each interface */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != AF_LINK)) { - continue; - } - - address = *addresses; - - for (i = 0; i < (*count); i++) { - if (strcmp(address->name, ent->ifa_name) == 0) { - sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); - memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); - } - address++; - } - } - freeifaddrs(addrs); return 0; From cdccd4f9900eaf123e1e70bca7e13e115f576bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sat, 18 Jun 2016 18:57:12 +0200 Subject: [PATCH 198/632] doc: clarify callbacks won't be called in error case PR-URL: https://github.com/libuv/libuv/pull/918 Reviewed-By: Colin Ihrig --- docs/src/errors.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/errors.rst b/docs/src/errors.rst index cec25f518..2ebaf1e41 100644 --- a/docs/src/errors.rst +++ b/docs/src/errors.rst @@ -8,6 +8,9 @@ In libuv errors are negative numbered constants. As a rule of thumb, whenever there is a status parameter, or an API functions returns an integer, a negative number will imply an error. +When a function which takes a callback returns an error, the callback will never +be called. + .. note:: Implementation detail: on Unix error codes are the negated `errno` (or `-errno`), while on Windows they are defined by libuv to arbitrary negative numbers. From 34ee25734f752609707de339796c31b49fcfb683 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 22 Jun 2016 16:06:26 +0200 Subject: [PATCH 199/632] unix: don't convert stat buffer when syscall fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't call uv__to_stat() when the stat/fstat/lstat system call fails; the stack-allocated buffer contains only garbage in that case. Not a very serious bug it's technically undefined behavior and it made valgrind squawk. Introduced in commit 499c7976 ("unix, windows: nanosecond resolution for uv_fs_[fl]stat"). PR-URL: https://github.com/libuv/libuv/pull/921 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fs.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 508b748a3..0b2505e4c 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -810,8 +810,11 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { static int uv__fs_stat(const char *path, uv_stat_t *buf) { struct stat pbuf; int ret; + ret = stat(path, &pbuf); - uv__to_stat(&pbuf, buf); + if (ret == 0) + uv__to_stat(&pbuf, buf); + return ret; } @@ -819,8 +822,11 @@ static int uv__fs_stat(const char *path, uv_stat_t *buf) { static int uv__fs_lstat(const char *path, uv_stat_t *buf) { struct stat pbuf; int ret; + ret = lstat(path, &pbuf); - uv__to_stat(&pbuf, buf); + if (ret == 0) + uv__to_stat(&pbuf, buf); + return ret; } @@ -828,8 +834,11 @@ static int uv__fs_lstat(const char *path, uv_stat_t *buf) { static int uv__fs_fstat(int fd, uv_stat_t *buf) { struct stat pbuf; int ret; + ret = fstat(fd, &pbuf); - uv__to_stat(&pbuf, buf); + if (ret == 0) + uv__to_stat(&pbuf, buf); + return ret; } From 77c8abae33351acc3a845aebb61f485c94d61cdf Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 22 Jun 2016 13:14:04 -0400 Subject: [PATCH 200/632] win: compare entire filename in watch events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit causes Window file watching events to compare the entire file path when filtering events. This fixes a bug where incomplete path comparisons would cause invalid events to be raised. Refs: https://github.com/libuv/libuv/pull/682 PR-URL: https://github.com/libuv/libuv/pull/924 Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs-event.c | 26 ++++++++++++++--- test/test-fs-event.c | 68 ++++++++++++++++++++++++++++++++++++++++---- test/test-list.h | 2 ++ 3 files changed, 86 insertions(+), 10 deletions(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index e79a48d0e..f96a7bfd9 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -344,6 +344,22 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { } +static int file_info_cmp(WCHAR* str, WCHAR* file_name, int file_name_len) { + int str_len; + + str_len = wcslen(str); + + /* + Since we only care about equality, return early if the strings + aren't the same length + */ + if (str_len != (file_name_len / sizeof(WCHAR))) + return -1; + + return _wcsnicmp(str, file_name, str_len); +} + + void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv_fs_event_t* handle) { FILE_NOTIFY_INFORMATION* file_info; @@ -383,10 +399,12 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, * or if the filename filter matches. */ if (handle->dirw || - _wcsnicmp(handle->filew, file_info->FileName, - file_info->FileNameLength / sizeof(WCHAR)) == 0 || - _wcsnicmp(handle->short_filew, file_info->FileName, - file_info->FileNameLength / sizeof(WCHAR)) == 0) { + file_info_cmp(handle->filew, + file_info->FileName, + file_info->FileNameLength) == 0 || + file_info_cmp(handle->short_filew, + file_info->FileName, + file_info->FileNameLength) == 0) { if (handle->dirw) { /* diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 353c43b0d..25eef07b1 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -53,6 +53,14 @@ static char fs_event_filename[PATH_MAX]; static char fs_event_filename[1024]; #endif /* defined(PATH_MAX) */ static int timer_cb_touch_called; +static int timer_cb_exact_called; + +static void fs_event_fail(uv_fs_event_t* handle, + const char* filename, + int events, + int status) { + ASSERT(0 && "should never be called"); +} static void create_dir(const char* name) { int r; @@ -345,6 +353,21 @@ static void timer_cb_touch(uv_timer_t* timer) { timer_cb_touch_called++; } +static void timer_cb_exact(uv_timer_t* handle) { + int r; + + if (timer_cb_exact_called == 0) { + touch_file("watch_dir/file.js"); + } else { + uv_close((uv_handle_t*)handle, NULL); + r = uv_fs_event_stop(&fs_event); + ASSERT(r == 0); + uv_close((uv_handle_t*) &fs_event, NULL); + } + + ++timer_cb_exact_called; +} + static void timer_cb_watch_twice(uv_timer_t* handle) { uv_fs_event_t* handles = handle->data; uv_close((uv_handle_t*) (handles + 0), NULL); @@ -467,6 +490,45 @@ TEST_IMPL(fs_event_watch_file) { return 0; } +TEST_IMPL(fs_event_watch_file_exact_path) { + /* + This test watches a file named "file.jsx" and modifies a file named + "file.js". The test verifies that no events occur for file.jsx. + */ + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + /* Setup */ + remove("watch_dir/file.js"); + remove("watch_dir/file.jsx"); + remove("watch_dir/"); + create_dir("watch_dir"); + create_file("watch_dir/file.js"); + create_file("watch_dir/file.jsx"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file.jsx", 0); + ASSERT(r == 0); + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + r = uv_timer_start(&timer, timer_cb_exact, 100, 100); + ASSERT(r == 0); + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + ASSERT(timer_cb_exact_called == 2); + + /* Cleanup */ + remove("watch_dir/file.js"); + remove("watch_dir/file.jsx"); + remove("watch_dir/"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + TEST_IMPL(fs_event_watch_file_twice) { const char path[] = "test/fixtures/empty_file"; uv_fs_event_t watchers[2]; @@ -626,12 +688,6 @@ TEST_IMPL(fs_event_no_callback_on_close) { } -static void fs_event_fail(uv_fs_event_t* handle, const char* filename, - int events, int status) { - ASSERT(0 && "should never be called"); -} - - static void timer_cb(uv_timer_t* handle) { int r; diff --git a/test/test-list.h b/test/test-list.h index 3d99c266c..41ed64c69 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -275,6 +275,7 @@ TEST_DECLARE (fs_read_file_eof) TEST_DECLARE (fs_event_watch_dir) TEST_DECLARE (fs_event_watch_dir_recursive) TEST_DECLARE (fs_event_watch_file) +TEST_DECLARE (fs_event_watch_file_exact_path) TEST_DECLARE (fs_event_watch_file_twice) TEST_DECLARE (fs_event_watch_file_current_dir) #ifdef _WIN32 @@ -724,6 +725,7 @@ TASK_LIST_START TEST_ENTRY (fs_event_watch_dir) TEST_ENTRY (fs_event_watch_dir_recursive) TEST_ENTRY (fs_event_watch_file) + TEST_ENTRY (fs_event_watch_file_exact_path) TEST_ENTRY (fs_event_watch_file_twice) TEST_ENTRY (fs_event_watch_file_current_dir) #ifdef _WIN32 From 1d27bbbb8d65b218f5c6cb7f9c4e2f4f043b30ad Mon Sep 17 00:00:00 2001 From: neevek Date: Mon, 27 Jun 2016 22:41:29 +0800 Subject: [PATCH 201/632] doc: add a note on safe reuse of uv_write_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uv_write_t can be reused safely only after the callback passed to uv_write is fired. PR-URL: https://github.com/libuv/libuv/pull/927 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- docs/src/stream.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/src/stream.rst b/docs/src/stream.rst index dfcad0fa2..7989cd4f8 100644 --- a/docs/src/stream.rst +++ b/docs/src/stream.rst @@ -26,7 +26,11 @@ Data types .. c:type:: uv_write_t - Write request type. + Write request type. Careful attention must be paid when reusing objects of + this type. When a stream is in non-blocking mode, write requests sent + with ``uv_write`` will be queued. Reusing objects at this point is undefined + behaviour. It is safe to reuse the ``uv_write_t`` object only after the + callback passed to ``uv_write`` is fired. .. c:type:: void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) From 70002c80bf1447fad605b61d9d6e83e9d0c1a6bc Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 21 Jun 2016 15:25:43 +0200 Subject: [PATCH 202/632] linux: fix potential event loop stall It was pointed out[0] that libuv could effectively enter an infinite loop (but not a busy loop) under certain conditions when polling for events: 1. When the architecture is 32 bits, and 2. When timeout > 0, i.e., finite, and 3. When timeout > max_safe_timeout (~30 minutes), and 4. When epoll_wait(timeout) returns 0, then 5. timeout was not properly updated on the next call to epoll_wait(). Inspection of the code uncovered a secondary bug where under a similar set of circumstances the timeout could drift when the epoll_wait() system call returned late. [0] https://github.com/libuv/libuv/pull/354#discussion_r67837112 PR-URL: https://github.com/libuv/libuv/pull/922 Reviewed-By: Colin Ihrig --- src/unix/linux-core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index ae927b7eb..58dd813dd 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -289,11 +289,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (nfds == 0) { assert(timeout != -1); - timeout = real_timeout - timeout; - if (timeout > 0) - continue; + if (timeout == 0) + return; - 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) { From 840a8c599ec1f138992a538f5b8109f91f31805e Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 27 Jun 2016 16:09:46 -0400 Subject: [PATCH 203/632] unix,win: make uv_get_process_title() stricter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit causes uv_get_process_title() to: - return EINVAL if the buffer is null or size is 0 - return ENOBUFS if the title is too big for the buffer - null terminate the buffer on success Fixes: https://github.com/libuv/libuv/issues/315 PR-URL: https://github.com/libuv/libuv/pull/928 Reviewed-By: Saúl Ibarra Corretgé --- docs/src/misc.rst | 4 +++- src/unix/aix.c | 27 ++++++++++++++------------- src/unix/freebsd.c | 18 ++++++++++++++---- src/unix/netbsd.c | 18 ++++++++++++++---- src/unix/openbsd.c | 18 ++++++++++++++---- src/unix/proctitle.c | 11 +++++++---- src/unix/sunos.c | 7 ++++--- src/win/util.c | 14 +++++++++++++- test/test-process-title.c | 22 ++++++++++++++++++++++ 9 files changed, 105 insertions(+), 34 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index f32af48ff..3b7f31aac 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -183,7 +183,9 @@ API .. c:function:: int uv_get_process_title(char* buffer, size_t size) - Gets the title of the current process. + Gets the title of the current process. If `buffer` is `NULL` or `size` is + zero, `UV_EINVAL` is returned. If `size` cannot accommodate the process + title and terminating `NULL` character, the function returns `UV_ENOBUFS`. .. c:function:: int uv_set_process_title(const char* title) diff --git a/src/unix/aix.c b/src/unix/aix.c index 2276985fc..652cd980f 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -156,7 +156,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { pqry.fd = pc.fd; rc = pollset_query(loop->backend_fd, &pqry); switch (rc) { - case -1: + case -1: assert(0 && "Failed to query pollset for file descriptor"); abort(); case 0: @@ -333,20 +333,20 @@ int uv_exepath(char* buffer, size_t* size) { pi.pi_pid = getpid(); res = getargs(&pi, sizeof(pi), args, sizeof(args)); - if (res < 0) + if (res < 0) return -EINVAL; /* * Possibilities for args: * i) an absolute path such as: /home/user/myprojects/nodejs/node * ii) a relative path such as: ./node or ../myprojects/nodejs/node - * iii) a bare filename such as "node", after exporting PATH variable + * iii) a bare filename such as "node", after exporting PATH variable * to its location. */ /* Case i) and ii) absolute or relative paths */ if (strchr(args, '/') != NULL) { - if (realpath(args, abspath) != abspath) + if (realpath(args, abspath) != abspath) return -errno; abspath_size = strlen(abspath); @@ -360,7 +360,7 @@ int uv_exepath(char* buffer, size_t* size) { return 0; } else { - /* Case iii). Search PATH environment variable */ + /* Case iii). Search PATH environment variable */ char trypath[PATH_MAX]; char *clonedpath = NULL; char *token = NULL; @@ -376,7 +376,7 @@ int uv_exepath(char* buffer, size_t* size) { token = strtok(clonedpath, ":"); while (token != NULL) { snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); - if (realpath(trypath, abspath) == abspath) { + if (realpath(trypath, abspath) == abspath) { /* Check the match is executable */ if (access(abspath, X_OK) == 0) { abspath_size = strlen(abspath); @@ -452,7 +452,7 @@ static char *uv__rawname(char *cp) { } -/* +/* * Determine whether given pathname is a directory * Returns 0 if the path is a directory, -1 if not * @@ -472,7 +472,7 @@ static int uv__path_is_a_directory(char* filename) { } -/* +/* * Check whether AHAFS is mounted. * Returns 0 if AHAFS is mounted, or an error code < 0 on failure */ @@ -547,7 +547,7 @@ static int uv__makedir_p(const char *dir) { return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); } -/* +/* * Creates necessary subdirectories in the AIX Event Infrastructure * file system for monitoring the object specified. * Returns code from mkdir call @@ -665,7 +665,7 @@ static int uv__skip_lines(char **p, int n) { /* * Parse the event occurrence data to figure out what event just occurred * and take proper action. - * + * * The buf is a pointer to the buffer containing the event occurrence data * Returns 0 on success, -1 if unrecoverable error in parsing * @@ -891,9 +891,10 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { - if (size > 0) { - buffer[0] = '\0'; - } + if (buffer == NULL || size == 0) + return -EINVAL; + + buffer[0] = '\0'; return 0; } diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index adc95235c..cba44a3e0 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -196,14 +196,24 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return -EINVAL; + if (process_title) { - strncpy(buffer, process_title, size); + len = strlen(process_title) + 1; + + if (size < len) + return -ENOBUFS; + + memcpy(buffer, process_title, len); } else { - if (size > 0) { - buffer[0] = '\0'; - } + len = 0; } + buffer[len] = '\0'; + return 0; } diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index ca48550f9..4a9e6cbc1 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -147,14 +147,24 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return -EINVAL; + if (process_title) { - strncpy(buffer, process_title, size); + len = strlen(process_title) + 1; + + if (size < len) + return -ENOBUFS; + + memcpy(buffer, process_title, len); } else { - if (size > 0) { - buffer[0] = '\0'; - } + len = 0; } + buffer[len] = '\0'; + return 0; } diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index 8c40bde40..909288cc8 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -169,14 +169,24 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return -EINVAL; + if (process_title) { - strncpy(buffer, process_title, size); + len = strlen(process_title) + 1; + + if (size < len) + return -ENOBUFS; + + memcpy(buffer, process_title, len); } else { - if (size > 0) { - buffer[0] = '\0'; - } + len = 0; } + buffer[len] = '\0'; + return 0; } diff --git a/src/unix/proctitle.c b/src/unix/proctitle.c index 19214e5ec..08d875f7a 100644 --- a/src/unix/proctitle.c +++ b/src/unix/proctitle.c @@ -87,10 +87,13 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { - if (process_title.len > 0) - strncpy(buffer, process_title.str, size); - else if (size > 0) - buffer[0] = '\0'; + if (buffer == NULL || size == 0) + return -EINVAL; + else if (size <= process_title.len) + return -ENOBUFS; + + memcpy(buffer, process_title.str, process_title.len + 1); + buffer[process_title.len] = '\0'; return 0; } diff --git a/src/unix/sunos.c b/src/unix/sunos.c index efadcea72..3e7a7592d 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -542,9 +542,10 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { - if (size > 0) { - buffer[0] = '\0'; - } + if (buffer == NULL || size == 0) + return -EINVAL; + + buffer[0] = '\0'; return 0; } diff --git a/src/win/util.c b/src/win/util.c index 4cebad390..84a0e467e 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -416,6 +416,11 @@ static int uv__get_process_title() { int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + uv__once_init(); EnterCriticalSection(&process_title_lock); @@ -429,7 +434,14 @@ int uv_get_process_title(char* buffer, size_t size) { } assert(process_title); - strncpy(buffer, process_title, size); + len = strlen(process_title) + 1; + + if (size < len) { + LeaveCriticalSection(&process_title_lock); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); LeaveCriticalSection(&process_title_lock); return 0; diff --git a/test/test-process-title.c b/test/test-process-title.c index 42ade4416..00f164a41 100644 --- a/test/test-process-title.c +++ b/test/test-process-title.c @@ -41,6 +41,24 @@ static void set_title(const char* title) { } +static void uv_get_process_title_edge_cases() { + char buffer[512]; + int r; + + /* Test a NULL buffer */ + r = uv_get_process_title(NULL, 100); + ASSERT(r == UV_EINVAL); + + /* Test size of zero */ + r = uv_get_process_title(buffer, 0); + ASSERT(r == UV_EINVAL); + + /* Test for insufficient buffer size */ + r = uv_get_process_title(buffer, 1); + ASSERT(r == UV_ENOBUFS); +} + + TEST_IMPL(process_title) { #if defined(__sun) || defined(_AIX) RETURN_SKIP("uv_(get|set)_process_title is not implemented."); @@ -48,6 +66,10 @@ TEST_IMPL(process_title) { /* Check for format string vulnerabilities. */ set_title("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"); set_title("new title"); + + /* Check uv_get_process_title() edge cases */ + uv_get_process_title_edge_cases(); + return 0; #endif } From 4b58985370cd6aa13f10b390b7694e891abff974 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Sat, 9 Jul 2016 14:45:32 -0400 Subject: [PATCH 204/632] test: close server before initiating new connection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/944 Reviewed-By: Imran Iqbal Reviewed-By: Saúl Ibarra Corretgé --- test/test-tcp-close-accept.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test-tcp-close-accept.c b/test/test-tcp-close-accept.c index 0729d46dc..e4878398c 100644 --- a/test/test-tcp-close-accept.c +++ b/test/test-tcp-close-accept.c @@ -102,6 +102,9 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { uv_close((uv_handle_t*) &tcp_incoming[i], close_cb); } + /* Close server, so no one will connect to it */ + 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, @@ -109,9 +112,6 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { (const struct sockaddr*) &addr, connect_cb)); ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb)); - - /* Close server, so no one will connect to it */ - uv_close((uv_handle_t*) &tcp_server, close_cb); } static void connection_cb(uv_stream_t* server, int status) { From 00dab91ce58c2399f2db5f484e6f718faba51de6 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Fri, 8 Jul 2016 21:42:13 -0400 Subject: [PATCH 205/632] test: account for multiple handles in one ipc read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/940 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- test/test-ipc-send-recv.c | 139 ++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 67 deletions(-) diff --git a/test/test-ipc-send-recv.c b/test/test-ipc-send-recv.c index c445483fa..133ae9014 100644 --- a/test/test-ipc-send-recv.c +++ b/test/test-ipc-send-recv.c @@ -68,8 +68,8 @@ static struct echo_ctx ctx2; /* Used in write2_cb to decide if we need to cleanup or not */ static int is_child_process; static int is_in_process; -static int read_cb_called; -static int recv_cb_called; +static int read_cb_count; +static int recv_cb_count; static int write2_cb_called; @@ -91,43 +91,46 @@ static void recv_cb(uv_stream_t* handle, int r; union handles* recv; - if (++recv_cb_called == 1) { - recv = &ctx.recv; - } else { - recv = &ctx.recv2; - } - pipe = (uv_pipe_t*) handle; ASSERT(pipe == &ctx.channel); - /* Depending on the OS, the final recv_cb can be called after the child - * process has terminated which can result in nread being UV_EOF instead of - * the number of bytes read. Since the other end of the pipe has closed this - * UV_EOF is an acceptable value. */ - if (nread == UV_EOF) { - /* UV_EOF is only acceptable for the final recv_cb call */ - ASSERT(recv_cb_called == 2); - } else { - ASSERT(nread >= 0); - ASSERT(1 == uv_pipe_pending_count(pipe)); - - pending = uv_pipe_pending_type(pipe); - ASSERT(pending == ctx.expected_type); - - if (pending == UV_NAMED_PIPE) - r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0); - else if (pending == UV_TCP) - r = uv_tcp_init(ctx.channel.loop, &recv->tcp); - else - abort(); - ASSERT(r == 0); - - r = uv_accept(handle, &recv->stream); - ASSERT(r == 0); - } + do { + if (++recv_cb_count == 1) { + recv = &ctx.recv; + } else { + recv = &ctx.recv2; + } + + /* Depending on the OS, the final recv_cb can be called after + * the child process has terminated which can result in nread + * being UV_EOF instead of the number of bytes read. Since + * the other end of the pipe has closed this UV_EOF is an + * acceptable value. */ + if (nread == UV_EOF) { + /* UV_EOF is only acceptable for the final recv_cb call */ + ASSERT(recv_cb_count == 2); + } else { + ASSERT(nread >= 0); + ASSERT(uv_pipe_pending_count(pipe) > 0); + + pending = uv_pipe_pending_type(pipe); + ASSERT(pending == ctx.expected_type); + + if (pending == UV_NAMED_PIPE) + r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0); + else if (pending == UV_TCP) + r = uv_tcp_init(ctx.channel.loop, &recv->tcp); + else + abort(); + ASSERT(r == 0); + + r = uv_accept(handle, &recv->stream); + ASSERT(r == 0); + } + } while (uv_pipe_pending_count(pipe) > 0); /* Close after two writes received */ - if (recv_cb_called == 2) { + if (recv_cb_count == 2) { uv_close((uv_handle_t*)&ctx.channel, NULL); } } @@ -186,7 +189,7 @@ static int run_test(int inprocess) { r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); - ASSERT(recv_cb_called == 2); + ASSERT(recv_cb_count == 2); if (inprocess) { r = uv_thread_join(&tid); @@ -293,41 +296,43 @@ static void read_cb(uv_stream_t* handle, return; } - if (++read_cb_called == 2) { - recv = &ctx2.recv; - write_req = &ctx2.write_req; - } else { - recv = &ctx2.recv2; - write_req = &ctx2.write_req2; - } - pipe = (uv_pipe_t*) handle; - ASSERT(pipe == &ctx2.channel); - ASSERT(nread >= 0); - ASSERT(1 == uv_pipe_pending_count(pipe)); - - pending = uv_pipe_pending_type(pipe); - ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP); - - if (pending == UV_NAMED_PIPE) - r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0); - else if (pending == UV_TCP) - r = uv_tcp_init(ctx2.channel.loop, &recv->tcp); - else - abort(); - ASSERT(r == 0); + do { + if (++read_cb_count == 2) { + recv = &ctx2.recv; + write_req = &ctx2.write_req; + } else { + recv = &ctx2.recv2; + write_req = &ctx2.write_req2; + } + + ASSERT(pipe == &ctx2.channel); + ASSERT(nread >= 0); + ASSERT(uv_pipe_pending_count(pipe) > 0); - r = uv_accept(handle, &recv->stream); - ASSERT(r == 0); + pending = uv_pipe_pending_type(pipe); + ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP); - wrbuf = uv_buf_init(".", 1); - r = uv_write2(write_req, - (uv_stream_t*)&ctx2.channel, - &wrbuf, - 1, - &recv->stream, - write2_cb); - ASSERT(r == 0); + if (pending == UV_NAMED_PIPE) + r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0); + else if (pending == UV_TCP) + r = uv_tcp_init(ctx2.channel.loop, &recv->tcp); + else + abort(); + ASSERT(r == 0); + + r = uv_accept(handle, &recv->stream); + ASSERT(r == 0); + + wrbuf = uv_buf_init(".", 1); + r = uv_write2(write_req, + (uv_stream_t*)&ctx2.channel, + &wrbuf, + 1, + &recv->stream, + write2_cb); + ASSERT(r == 0); + } while (uv_pipe_pending_count(pipe) > 0); } static void send_recv_start() { From 3a4f2d31550037c96ea0113fe294e4fdc69a1f99 Mon Sep 17 00:00:00 2001 From: liuxiaobo Date: Mon, 4 Jul 2016 17:08:46 +0800 Subject: [PATCH 206/632] unix: fix errno and retval conflict MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We not only check the return value, but also check the errno != 0. Because in rare cases connect() will return -1 but the errno is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227) and actually the tcp three-way handshake is completed. PR-URL: https://github.com/libuv/libuv/pull/936 Reviewed-By: Ben Noordhuis Reviewed-By: Imran Iqbal Reviewed-By: Saúl Ibarra Corretgé --- src/unix/tcp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 793e4c7d6..46d8cd25b 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -158,11 +158,17 @@ int uv__tcp_connect(uv_connect_t* req, handle->delayed_error = 0; - do + do { + errno = 0; r = connect(uv__stream_fd(handle), addr, addrlen); - while (r == -1 && errno == EINTR); + } while (r == -1 && errno == EINTR); - if (r == -1) { + /* We not only check the return value, but also check the errno != 0. + * Because in rare cases connect() will return -1 but the errno + * is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227) + * and actually the tcp three-way handshake is completed. + */ + if (r == -1 && errno != 0) { if (errno == EINPROGRESS) ; /* not an error */ else if (errno == ECONNREFUSED) From f001a67e1d68e89a0b59dd7bc63587fba7ed914f Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Tue, 26 Jul 2016 14:24:20 +0200 Subject: [PATCH 207/632] doc: add missing entry in uv_fs_type enum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/958 Reviewed-By: Saúl Ibarra Corretgé --- docs/src/fs.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index f810319ca..50c0de468 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -91,7 +91,8 @@ Data types UV_FS_SYMLINK, UV_FS_READLINK, UV_FS_CHOWN, - UV_FS_FCHOWN + UV_FS_FCHOWN, + UV_FS_REALPATH } uv_fs_type; .. c:type:: uv_dirent_t From ff0ae10496da1e0012e79e8980b12a25fd1ea6b2 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 20 Jul 2016 14:18:50 +0200 Subject: [PATCH 208/632] unix: preserve loop->data across loop init/done MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Libuv leaves loop->data unchanged in uv_loop_init() and uv_loop_done() on Windows but it clobbered it on UNIX platforms. This commit fixes that inconsistency. PR-URL: https://github.com/libuv/libuv/pull/951 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/unix/loop.c | 4 ++++ src/uv-common.c | 3 +++ test/test-loop-close.c | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/src/unix/loop.c b/src/unix/loop.c index 92e96f09e..bd63c2f9d 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -28,11 +28,15 @@ #include int uv_loop_init(uv_loop_t* loop) { + void* saved_data; int err; uv__signal_global_once_init(); + saved_data = loop->data; memset(loop, 0, sizeof(*loop)); + loop->data = saved_data; + heap_init((struct heap*) &loop->timer_heap); QUEUE_INIT(&loop->wq); QUEUE_INIT(&loop->active_reqs); diff --git a/src/uv-common.c b/src/uv-common.c index ba2644691..434a5029c 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -613,6 +613,7 @@ uv_loop_t* uv_loop_new(void) { int uv_loop_close(uv_loop_t* loop) { QUEUE* q; uv_handle_t* h; + void* saved_data; if (!QUEUE_EMPTY(&(loop)->active_reqs)) return UV_EBUSY; @@ -626,7 +627,9 @@ int uv_loop_close(uv_loop_t* loop) { uv__loop_close(loop); #ifndef NDEBUG + saved_data = loop->data; memset(loop, -1, sizeof(*loop)); + loop->data = saved_data; #endif if (loop == default_loop_ptr) default_loop_ptr = NULL; diff --git a/test/test-loop-close.c b/test/test-loop-close.c index 5aec234ed..971c9d725 100644 --- a/test/test-loop-close.c +++ b/test/test-loop-close.c @@ -34,7 +34,9 @@ TEST_IMPL(loop_close) { int r; uv_loop_t loop; + loop.data = &loop; ASSERT(0 == uv_loop_init(&loop)); + ASSERT(loop.data == (void*) &loop); uv_timer_init(&loop, &timer_handle); uv_timer_start(&timer_handle, timer_cb, 100, 100); @@ -47,7 +49,9 @@ TEST_IMPL(loop_close) { r = uv_run(&loop, UV_RUN_DEFAULT); ASSERT(r == 0); + ASSERT(loop.data == (void*) &loop); ASSERT(0 == uv_loop_close(&loop)); + ASSERT(loop.data == (void*) &loop); return 0; } From ef6f3e8e8d91b19da2c97005c0c8bda04158b54a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 9 Jul 2016 10:00:04 +0200 Subject: [PATCH 209/632] win: return UV_EINVAL on bad uv_tty_mode mode arg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/941 PR-URL: https://github.com/libuv/libuv/pull/942 Reviewed-By: Saúl Ibarra Corretgé --- src/win/tty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/win/tty.c b/src/win/tty.c index 59a991c6a..daa303f13 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -297,6 +297,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { break; case UV_TTY_MODE_IO: return UV_ENOTSUP; + default: + return UV_EINVAL; } if (!SetConsoleMode(tty->handle, flags)) { From f614b43a69693022119807709a62d361b7c5517d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 9 Jul 2016 10:02:06 +0200 Subject: [PATCH 210/632] win: simplify memory copy logic in fs.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hopefully shuts up a -Wmaybe-uninitialized warning about the path_len variable. Fixes: https://github.com/libuv/libuv/issues/941 PR-URL: https://github.com/libuv/libuv/pull/942 Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 24c608475..b6d439215 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -204,14 +204,11 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path, req->fs.info.new_pathw = NULL; } - if (!copy_path) { - req->path = path; - } else if (path) { + req->path = path; + if (path != NULL && copy_path) { memcpy(pos, path, path_len); assert(path_len == buf_sz - (pos - buf)); req->path = pos; - } else { - req->path = NULL; } req->flags |= UV_FS_FREE_PATHS; From fc8cc42e8f6418fb4fba7eabc021dad6404c58c7 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Wed, 3 Aug 2016 16:54:56 +0200 Subject: [PATCH 211/632] win: fix compilation on mingw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds missing define for UNLEN. PR-URL: https://github.com/libuv/libuv/pull/968 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/win/util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/win/util.c b/src/win/util.c index 84a0e467e..4a2e50121 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -54,6 +54,10 @@ /* The number of nanoseconds in one second. */ #define UV__NANOSEC 1000000000 +/* Max user name length, from iphlpapi.h */ +#ifndef UNLEN +# define UNLEN 256 +#endif /* Cached copy of the process title, plus a mutex guarding it. */ static char *process_title; From 7b07d18ad91ed2db58644185f1eaa60fdc7303af Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 1 Aug 2016 18:25:47 +0200 Subject: [PATCH 212/632] win: ensure 32-bit printf precision This commit removes a printf warning by casting a 64-bit value to 32 bits. Fixes: https://github.com/libuv/libuv/issues/955 PR-URL: https://github.com/libuv/libuv/pull/963 Reviewed-By: Colin Ihrig --- src/win/fs-event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index f96a7bfd9..03e4adc05 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -425,7 +425,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw, - file_info->FileNameLength / sizeof(WCHAR), + file_info->FileNameLength / (DWORD)sizeof(WCHAR), file_info->FileName); filenamew[size - 1] = L'\0'; From 39ee4121a1e921dd1dd23d05eb641f7f9174172b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 6 Aug 2016 06:19:41 +0200 Subject: [PATCH 213/632] darwin: handle EINTR in /dev/tty workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On OS X, special files like /dev/null and /dev/tty don't work with kqueue. Libuv falls back to select() in that case but the initial probe didn't handle EINTR. Introduced in August 2012 in commit 731adaca ("unix: use select() for specific fds on OS X"), this bug was only ten days away from celebrating its fourth birthday. PR-URL: https://github.com/libuv/libuv/pull/979 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/unix/stream.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 2143cd88d..d0c2f1ad2 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -291,7 +291,10 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { timeout.tv_sec = 0; timeout.tv_nsec = 1; - ret = kevent(kq, filter, 1, events, 1, &timeout); + do + ret = kevent(kq, filter, 1, events, 1, &timeout); + while (ret == -1 && errno == EINTR); + uv__close(kq); if (ret == -1) From a6acc822452b07564c0440bdb7909b7edc805013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 9 Aug 2016 12:21:07 +0100 Subject: [PATCH 214/632] test: fix OOB buffer access The test uses an annonymous pipe, which means the returned length will be 0. Fixes: https://github.com/libuv/libuv/issues/376 Fixes: https://github.com/libuv/libuv/issues/529 Refs: https://github.com/libuv/libuv/issues/264 PR-URL: https://github.com/libuv/libuv/pull/981 Reviewed-By: Ben Noordhuis --- test/test-pipe-getsockname.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index 58041c026..e42931ea0 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -231,7 +231,7 @@ TEST_IMPL(pipe_getsockname_blocking) { len1 = sizeof buf1; r = uv_pipe_getsockname(&pipe_client, buf1, &len1); ASSERT(r == 0); - ASSERT(buf1[len1 - 1] != 0); + ASSERT(len1 == 0); /* It's an annonymous pipe. */ r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL); ASSERT(r == 0); @@ -240,7 +240,7 @@ TEST_IMPL(pipe_getsockname_blocking) { len2 = sizeof buf2; r = uv_pipe_getsockname(&pipe_client, buf2, &len2); ASSERT(r == 0); - ASSERT(buf2[len2 - 1] != 0); + ASSERT(len2 == 0); /* It's an annonymous pipe. */ r = uv_read_stop((uv_stream_t*)&pipe_client); ASSERT(r == 0); From 63ab64144e94bfe94999071316f24f5764207ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 11 Aug 2016 00:53:29 +0100 Subject: [PATCH 215/632] test: don't close CRT fd handed off to uv_pipe_t After 4ed29c2498408c99079f25bfc0c6aec5bfbf42c4 got fixed, when a CRT fd is handed off to a pipe handle using uv_pipe_open libuv will close it properly, so it's an error to do so ourselves. PR-URL: https://github.com/libuv/libuv/pull/992 Reviewed-By: Ben Noordhuis --- test/test-pipe-getsockname.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index e42931ea0..4b4ceccc4 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -255,7 +255,6 @@ TEST_IMPL(pipe_getsockname_blocking) { ASSERT(pipe_close_cb_called == 1); - _close(readfd); CloseHandle(writeh); #endif From 791c817891fdfde806a3814e1eeed94502eb56b8 Mon Sep 17 00:00:00 2001 From: "sunjin.lee" Date: Fri, 5 Aug 2016 09:52:07 +0900 Subject: [PATCH 216/632] test: fix android build error. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not compile 'tty_pty' test for android. PR-URL: https://github.com/libuv/libuv/pull/975 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- test/test-tty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-tty.c b/test/test-tty.c index 5787d1dae..c93fe75a7 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -28,7 +28,7 @@ #else /* Unix */ # include # include -# if defined(__linux__) +# if defined(__linux__) && !defined(__ANDROID__) # include # elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) # include @@ -260,7 +260,7 @@ TEST_IMPL(tty_file) { } TEST_IMPL(tty_pty) { -# if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ +# if defined(__linux__) && !defined(__ANDROID__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) int master_fd, slave_fd, r; struct winsize w; From 6fa3524ea7ad8d54ce733a6e7da283701c9c06fc Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Tue, 26 Jul 2016 16:14:30 +0200 Subject: [PATCH 217/632] win: evaluate timers when system wakes up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When Windows resumes after sleep GetQueuedCompletionStatus timeout is not updated. This commit adds a method for signaling all loops to wake up and update their timers. Fixes: https://github.com/nodejs/node/issues/6763 PR-URL: https://github.com/libuv/libuv/pull/962 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 1 + Makefile.mingw | 1 + src/win/core.c | 115 ++++++++++++++++++++++++++++++++++++++-- src/win/detect-wakeup.c | 35 ++++++++++++ src/win/internal.h | 10 ++++ src/win/winapi.c | 13 +++++ src/win/winapi.h | 38 +++++++++++++ uv.gyp | 1 + 8 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 src/win/detect-wakeup.c diff --git a/Makefile.am b/Makefile.am index 882bbef53..5462aca59 100644 --- a/Makefile.am +++ b/Makefile.am @@ -48,6 +48,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/win \ libuv_la_SOURCES += src/win/async.c \ src/win/atomicops-inl.h \ src/win/core.c \ + src/win/detect-wakeup.c \ src/win/dl.c \ src/win/error.c \ src/win/fs-event.c \ diff --git a/Makefile.mingw b/Makefile.mingw index 156f15dab..8139138fc 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -48,6 +48,7 @@ OBJS = src/fs-poll.o \ src/version.o \ src/win/async.o \ src/win/core.o \ + src/win/detect-wakeup.o \ src/win/dl.o \ src/win/error.o \ src/win/fs-event.o \ diff --git a/src/win/core.c b/src/win/core.c index ba306ebc0..9d00afc6b 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -31,6 +31,7 @@ #include "uv.h" #include "internal.h" +#include "queue.h" #include "handle-inl.h" #include "req-inl.h" @@ -80,6 +81,98 @@ static void uv__crt_invalid_parameter_handler(const wchar_t* expression, } #endif +static uv_loop_t** uv__loops; +static int uv__loops_size; +static int uv__loops_capacity; +#define UV__LOOPS_CHUNK_SIZE 8 +static uv_mutex_t uv__loops_lock; + +static void uv__loops_init() { + uv_mutex_init(&uv__loops_lock); + uv__loops = uv__calloc(UV__LOOPS_CHUNK_SIZE, sizeof(uv_loop_t*)); + if (!uv__loops) + uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); + uv__loops_size = 0; + uv__loops_capacity = UV__LOOPS_CHUNK_SIZE; +} + +static int uv__loops_add(uv_loop_t* loop) { + uv_loop_t** new_loops; + int new_capacity, i; + + uv_mutex_lock(&uv__loops_lock); + + if (uv__loops_size == uv__loops_capacity) { + new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE; + new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity); + if (!new_loops) + goto failed_loops_realloc; + uv__loops = new_loops; + for (i = uv__loops_capacity; i < new_capacity; ++i) + uv__loops[i] = NULL; + uv__loops_capacity = new_capacity; + } + uv__loops[uv__loops_size] = loop; + ++uv__loops_size; + + uv_mutex_unlock(&uv__loops_lock); + return 0; + +failed_loops_realloc: + uv_mutex_unlock(&uv__loops_lock); + return ERROR_OUTOFMEMORY; +} + +static void uv__loops_remove(uv_loop_t* loop) { + int loop_index; + int smaller_capacity; + uv_loop_t** new_loops; + + uv_mutex_lock(&uv__loops_lock); + + for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) { + if (uv__loops[loop_index] == loop) + break; + } + /* If loop was not found, ignore */ + if (loop_index == uv__loops_size) + goto loop_removed; + + uv__loops[loop_index] = uv__loops[uv__loops_size - 1]; + uv__loops[uv__loops_size - 1] = NULL; + --uv__loops_size; + + /* If we didn't grow to big skip downsizing */ + if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE) + goto loop_removed; + + /* Downsize only if more than half of buffer is free */ + smaller_capacity = uv__loops_capacity / 2; + if (uv__loops_size >= smaller_capacity) + goto loop_removed; + new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity); + if (!new_loops) + goto loop_removed; + uv__loops = new_loops; + uv__loops_capacity = smaller_capacity; + +loop_removed: + uv_mutex_unlock(&uv__loops_lock); +} + +void uv__wake_all_loops() { + int i; + uv_loop_t* loop; + + uv_mutex_lock(&uv__loops_lock); + for (i = 0; i < uv__loops_size; ++i) { + loop = uv__loops[i]; + assert(loop); + if (loop->iocp != INVALID_HANDLE_VALUE) + PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL); + } + uv_mutex_unlock(&uv__loops_lock); +} static void uv_init(void) { /* Tell Windows that we will handle critical errors. */ @@ -101,6 +194,9 @@ static void uv_init(void) { _CrtSetReportHook(uv__crt_dbg_report_handler); #endif + /* Initialize tracking of all uv loops */ + uv__loops_init(); + /* Fetch winapi function pointers. This must be done first because other * initialization code might need these function pointers to be loaded. */ @@ -120,6 +216,9 @@ static void uv_init(void) { /* Initialize utilities */ uv__util_init(); + + /* Initialize system wakeup detection */ + uv__init_detect_system_wakeup(); } @@ -178,6 +277,10 @@ int uv_loop_init(uv_loop_t* loop) { uv__handle_unref(&loop->wq_async); loop->wq_async.flags |= UV__HANDLE_INTERNAL; + err = uv__loops_add(loop); + if (err) + goto fail_async_init; + return 0; fail_async_init: @@ -199,6 +302,8 @@ void uv__once_init(void) { void uv__loop_close(uv_loop_t* loop) { size_t i; + uv__loops_remove(loop); + /* close the async handle without needing an extra loop iteration */ assert(!loop->wq_async.async_sent); loop->wq_async.close_cb = NULL; @@ -323,9 +428,13 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { if (success) { for (i = 0; i < count; i++) { - /* Package was dequeued */ - req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); - uv_insert_pending_req(loop, req); + /* Package was dequeued, but see if it is not a empty package + * meant only to wake us up. + */ + if (overlappeds[i].lpOverlapped) { + req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); + uv_insert_pending_req(loop, req); + } } /* Some time might have passed waiting for I/O, diff --git a/src/win/detect-wakeup.c b/src/win/detect-wakeup.c new file mode 100644 index 000000000..a12179f79 --- /dev/null +++ b/src/win/detect-wakeup.c @@ -0,0 +1,35 @@ +#include "uv.h" +#include "internal.h" +#include "winapi.h" + +static void uv__register_system_resume_callback(); + +void uv__init_detect_system_wakeup() { + /* Try registering system power event callback. This is the cleanest + * method, but it will only work on Win8 and above. + */ + uv__register_system_resume_callback(); +} + +static ULONG CALLBACK uv__system_resume_callback(PVOID Context, + ULONG Type, + PVOID Setting) { + if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC) + uv__wake_all_loops(); + + return 0; +} + +static void uv__register_system_resume_callback() { + _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient; + _HPOWERNOTIFY registration_handle; + + if (pPowerRegisterSuspendResumeNotification == NULL) + return; + + recipient.Callback = uv__system_resume_callback; + recipient.Context = NULL; + (*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK, + &recipient, + ®istration_handle); +} diff --git a/src/win/internal.h b/src/win/internal.h index 0a7c9404f..b8cfde90e 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -381,4 +381,14 @@ extern int uv_tcp_non_ifs_lsp_ipv6; extern struct sockaddr_in uv_addr_ip4_any_; extern struct sockaddr_in6 uv_addr_ip6_any_; +/* + * Wake all loops with fake message + */ +void uv__wake_all_loops(); + +/* + * Init system wake-up detection + */ +void uv__init_detect_system_wakeup(); + #endif /* UV_WIN_INTERNAL_H_ */ diff --git a/src/win/winapi.c b/src/win/winapi.c index 26bd06486..1fa179b57 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -49,9 +49,14 @@ sCancelSynchronousIo pCancelSynchronousIo; sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; +/* Powrprof.dll function pointer */ +sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + + void uv_winapi_init() { HMODULE ntdll_module; HMODULE kernel32_module; + HMODULE powrprof_module; ntdll_module = GetModuleHandleA("ntdll.dll"); if (ntdll_module == NULL) { @@ -143,4 +148,12 @@ void uv_winapi_init() { pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW) GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW"); + + + powrprof_module = LoadLibraryA("powrprof.dll"); + if (powrprof_module != NULL) { + pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) + GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification"); + } + } diff --git a/src/win/winapi.h b/src/win/winapi.h index 122198a6d..16d9365cc 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4684,6 +4684,40 @@ typedef DWORD (WINAPI* sGetFinalPathNameByHandleW) DWORD cchFilePath, DWORD dwFlags); +/* from powerbase.h */ +#ifndef DEVICE_NOTIFY_CALLBACK +# define DEVICE_NOTIFY_CALLBACK 2 +#endif + +#ifndef PBT_APMRESUMEAUTOMATIC +# define PBT_APMRESUMEAUTOMATIC 18 +#endif + +#ifndef PBT_APMRESUMESUSPEND +# define PBT_APMRESUMESUSPEND 7 +#endif + +typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE( + PVOID Context, + ULONG Type, + PVOID Setting +); +typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE; + +typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS { + _PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback; + PVOID Context; +} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS; + +typedef PVOID _HPOWERNOTIFY; +typedef _HPOWERNOTIFY *_PHPOWERNOTIFY; + +typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification) + (DWORD Flags, + HANDLE Recipient, + _PHPOWERNOTIFY RegistrationHandle); + + /* Ntdll function pointers */ extern sRtlNtStatusToDosError pRtlNtStatusToDosError; extern sNtDeviceIoControlFile pNtDeviceIoControlFile; @@ -4707,4 +4741,8 @@ extern sWakeConditionVariable pWakeConditionVariable; extern sCancelSynchronousIo pCancelSynchronousIo; extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; + +/* Powrprof.dll function pointer */ +extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; + #endif /* UV_WIN_WINAPI_H_ */ diff --git a/uv.gyp b/uv.gyp index aa4a42445..b83f82b0f 100644 --- a/uv.gyp +++ b/uv.gyp @@ -75,6 +75,7 @@ 'src/win/async.c', 'src/win/atomicops-inl.h', 'src/win/core.c', + 'src/win/detect-wakeup.c', 'src/win/dl.c', 'src/win/error.c', 'src/win/fs.c', From be0e24c1e85ed27c03df4e500299ceedac57bab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 10 Aug 2016 23:28:57 +0100 Subject: [PATCH 218/632] doc: add supported platforms description Closes: https://github.com/libuv/libuv/issues/983 PR-URL: https://github.com/libuv/libuv/pull/991 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- README.md | 14 +-------- SUPPORTED_PLATFORMS.md | 70 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 SUPPORTED_PLATFORMS.md diff --git a/README.md b/README.md index 1b40e76ea..29b94db12 100644 --- a/README.md +++ b/README.md @@ -224,18 +224,7 @@ Run: ## Supported Platforms -Microsoft Windows operating systems since Windows XP SP2. It can be built -with either Visual Studio or MinGW. Consider using -[Visual Studio Express 2010][] or later if you do not have a full Visual -Studio license. - -Linux using the GCC toolchain. - -OS X using the GCC or XCode toolchain. - -Solaris 121 and later using GCC toolchain. - -AIX 6 and later using GCC toolchain (see notes). +Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md). ### AIX Notes @@ -254,7 +243,6 @@ See the [guidelines for contributing][]. [node.js]: http://nodejs.org/ [GYP]: http://code.google.com/p/gyp/ [Python]: https://www.python.org/downloads/ -[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express [guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md [libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png [x32]: https://en.wikipedia.org/wiki/X32_ABI diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md new file mode 100644 index 000000000..bff1050d6 --- /dev/null +++ b/SUPPORTED_PLATFORMS.md @@ -0,0 +1,70 @@ +# Supported platforms + +| System | Support type | Supported versions | Notes | +|---|---|---|---| +| GNU/Linux | Tier 1 | Linux >= 2.6.18 with glibc >= 2.5 | | +| macOS | Tier 1 | macOS >= 10.7 | | +| Windows | Tier 1 | Windows >= XP SP1 | MSVC 2008 and later are supported | +| FreeBSD | Tier 1 | >= 9 (see note) | | +| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | +| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | +| Linux with musl | Tier 2 | musl >= 1.0 | | +| SunOS | Tier 2 | Solaris 121 and later | Maintainers: @libuv/sunos | +| MinGW | Tier 3 | MinGW32 and MinGW-w64 | | +| Other | Tier 3 | N/A | | + +#### Note on FreeBSD 9 + +While FreeBSD is supported as Tier 1, FreeBSD 9 will get Tier 2 support until +it reaches end of life, in December 2016. + +## Support types + +* **Tier 1**: Officially supported and tested with CI. Any contributed patch + MUST NOT break such systems. These are supported by @libuv/collaborators. + +* **Tier 2**: Officially supported, but not necessarily tested with CI. These + systems are maintained to the best of @libuv/collaborators ability, + without being a top priority. + +* **Tier 3**: Community maintained. These systems may inadvertently break and the + community and interested parties are expected to help with the maintenance. + +## Adding support for a new platform + +**IMPORTANT**: Before attempting to add support for a new platform please open +an issue about it for discussion. + +### Unix + +I/O handling is abstracted by an internal `uv__io_t` handle. The new platform +will need to implement some of the functions, the prototypes are in +``src/unix/internal.h``. + +If the new platform requires extra fields for any handle structure, create a +new include file in ``include/`` with the name ``uv-theplatform.h`` and add +the appropriate defines there. + +All functionality related to the new platform must be implemented in its own +file inside ``src/unix/`` unless it's already done in a common file, in which +case adding an `ifdef` is fine. + +Two build systems are supported: autotools and GYP. Ideally both need to be +supported, but if GYP does not support the new platform it can be left out. + +### Windows + +Windows is treated as a single platform, so adding support for a new platform +would mean adding support for a new version. + +Compilation and runtime must succeed for the minimum supported version. If a +new API is to be used, it must be done optionally, only in supported versions. + +### Common + +Some common notes when adding support for new platforms: + +* Generally libuv tries to avoid compile time checks. Do not add any to the + autotools based build system or use version checking macros. + Dynamically load functions and symbols if they are not supported by the + minimum supported version. From 7ae4b1ad7f6d09f5994403b253a0494a6642c8f2 Mon Sep 17 00:00:00 2001 From: Jason Ginchereau Date: Sat, 13 Aug 2016 00:12:21 -0700 Subject: [PATCH 219/632] win: fix lstat reparse point without link data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/995 Fixes: https://github.com/nodejs/node/issues/5160 PR-URL: https://github.com/libuv/libuv/pull/996 Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index b6d439215..6a4157bfe 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1088,17 +1088,28 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { statbuf->st_mode = 0; if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - statbuf->st_mode |= S_IFLNK; - if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) + /* + * It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have + * any link data. In that case DeviceIoControl() in fs__readlink_handle() sets + * the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode + * calculated below will indicate a normal directory or file, as if + * FILE_ATTRIBUTE_REPARSE_POINT was not present. + */ + if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) { + statbuf->st_mode |= S_IFLNK; + } else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) { return -1; + } + } - } else if (file_info.BasicInformation.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; + if (statbuf->st_mode == 0) { + if (file_info.BasicInformation.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; + } } if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY) From d796bedf5ba0e4c5ed431257836692adc6c19349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 16 Aug 2016 00:15:54 +0200 Subject: [PATCH 220/632] unix,win: make on_alloc_cb failures more resilient Treat both the base being NULL or the length being 0 as ENOBUFS. PR-URL: https://github.com/libuv/libuv/pull/997 Reviewed-By: Ben Noordhuis --- Makefile.am | 2 + src/unix/stream.c | 3 +- src/unix/udp.c | 3 +- src/win/pipe.c | 3 +- src/win/tcp.c | 7 +- src/win/tty.c | 7 +- src/win/udp.c | 6 +- test/test-list.h | 5 + test/test-tcp-alloc-cb-fail.c | 123 +++++++++++++++++++ test/test-tcp-write-queue-order.c | 4 +- test/test-udp-alloc-cb-fail.c | 197 ++++++++++++++++++++++++++++++ uv.gyp | 2 + 12 files changed, 351 insertions(+), 11 deletions(-) create mode 100644 test/test-tcp-alloc-cb-fail.c create mode 100644 test/test-udp-alloc-cb-fail.c diff --git a/Makefile.am b/Makefile.am index 5462aca59..a04373596 100644 --- a/Makefile.am +++ b/Makefile.am @@ -216,6 +216,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-socket-buffer-size.c \ test/test-spawn.c \ test/test-stdio-over-pipes.c \ + test/test-tcp-alloc-cb-fail.c \ test/test-tcp-bind-error.c \ test/test-tcp-bind6-error.c \ test/test-tcp-close-accept.c \ @@ -247,6 +248,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-timer.c \ test/test-tmpdir.c \ test/test-tty.c \ + test/test-udp-alloc-cb-fail.c \ test/test-udp-bind.c \ test/test-udp-create-socket-early.c \ test/test-udp-dgram-too-big.c \ diff --git a/src/unix/stream.c b/src/unix/stream.c index d0c2f1ad2..5dc2f83f4 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1124,8 +1124,9 @@ static void uv__read(uv_stream_t* stream) { && (count-- > 0)) { assert(stream->alloc_cb != NULL); + buf = uv_buf_init(NULL, 0); stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf); - if (buf.len == 0) { + if (buf.base == NULL || buf.len == 0) { /* User indicates it can't or won't handle the read. */ stream->read_cb(stream, UV_ENOBUFS, &buf); return; diff --git a/src/unix/udp.c b/src/unix/udp.c index 4527bba1f..f5d7ed14b 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -165,8 +165,9 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { h.msg_name = &peer; do { + buf = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf); - if (buf.len == 0) { + if (buf.base == NULL || buf.len == 0) { handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); return; } diff --git a/src/win/pipe.c b/src/win/pipe.c index 2a949e79b..2442be730 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1634,8 +1634,9 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, } } + buf = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, avail, &buf); - if (buf.len == 0) { + if (buf.base == NULL || buf.len == 0) { handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); break; } diff --git a/src/win/tcp.c b/src/win/tcp.c index 0f5654863..0709696ff 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -496,8 +496,10 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { */ 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.len == 0) { + 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; } @@ -1004,8 +1006,9 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, /* Do nonblocking reads until the buffer is empty */ while (handle->flags & UV_HANDLE_READING) { + buf = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); - if (buf.len == 0) { + if (buf.base == NULL || buf.len == 0) { handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); break; } diff --git a/src/win/tty.c b/src/win/tty.c index daa303f13..9bb7879db 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -509,8 +509,10 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { req = &handle->read_req; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); + handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer); - if (handle->tty.rd.read_line_buffer.len == 0) { + if (handle->tty.rd.read_line_buffer.base == NULL || + handle->tty.rd.read_line_buffer.len == 0) { handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tty.rd.read_line_buffer); @@ -833,8 +835,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) { /* Allocate a buffer if needed */ if (buf_used == 0) { + buf = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 1024, &buf); - if (buf.len == 0) { + if (buf.base == NULL || buf.len == 0) { handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); goto out; } diff --git a/src/win/udp.c b/src/win/udp.c index 24792ec06..9bf1453e5 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -289,8 +289,9 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { 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, 65536, &handle->recv_buffer); - if (handle->recv_buffer.len == 0) { + if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) { handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0); return; } @@ -506,8 +507,9 @@ 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); - if (buf.len == 0) { + if (buf.base == NULL || buf.len == 0) { handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0); goto done; } diff --git a/test/test-list.h b/test/test-list.h index 41ed64c69..2f19b3279 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -61,6 +61,7 @@ TEST_DECLARE (ipc_send_recv_pipe_inprocess) TEST_DECLARE (ipc_send_recv_tcp) TEST_DECLARE (ipc_send_recv_tcp_inprocess) TEST_DECLARE (ipc_tcp_connection) +TEST_DECLARE (tcp_alloc_cb_fail) TEST_DECLARE (tcp_ping_pong) TEST_DECLARE (tcp_ping_pong_v6) TEST_DECLARE (pipe_ping_pong) @@ -106,6 +107,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 (udp_alloc_cb_fail) TEST_DECLARE (udp_bind) TEST_DECLARE (udp_bind_reuseaddr) TEST_DECLARE (udp_create_early) @@ -416,6 +418,8 @@ TASK_LIST_START TEST_ENTRY (ipc_send_recv_tcp_inprocess) TEST_ENTRY (ipc_tcp_connection) + TEST_ENTRY (tcp_alloc_cb_fail) + TEST_ENTRY (tcp_ping_pong) TEST_HELPER (tcp_ping_pong, tcp4_echo_server) @@ -483,6 +487,7 @@ TASK_LIST_START TEST_ENTRY (tcp_bind6_error_inval) TEST_ENTRY (tcp_bind6_localhost_ok) + TEST_ENTRY (udp_alloc_cb_fail) TEST_ENTRY (udp_bind) TEST_ENTRY (udp_bind_reuseaddr) TEST_ENTRY (udp_create_early) diff --git a/test/test-tcp-alloc-cb-fail.c b/test/test-tcp-alloc-cb-fail.c new file mode 100644 index 000000000..61ca667ac --- /dev/null +++ b/test/test-tcp-alloc-cb-fail.c @@ -0,0 +1,123 @@ +/* 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 +#include +#include + +#include "uv.h" +#include "task.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 uv_write_t write_req; + +static char hello[] = "HELLO!"; + + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + +static void write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); +} + +static void conn_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + /* Do nothing, read_cb should be called with UV_ENOBUFS. */ +} + +static void conn_read_cb(uv_stream_t* stream, + ssize_t nread, + const uv_buf_t* buf) { + ASSERT(nread == UV_ENOBUFS); + ASSERT(buf->base == NULL); + ASSERT(buf->len == 0); + + uv_close((uv_handle_t*) &incoming, close_cb); + uv_close((uv_handle_t*) &client, close_cb); + uv_close((uv_handle_t*) &server, close_cb); +} + +static void connect_cb(uv_connect_t* req, int status) { + int r; + uv_buf_t buf; + + ASSERT(status == 0); + connect_cb_called++; + + buf = uv_buf_init(hello, sizeof(hello)); + r = uv_write(&write_req, req->handle, &buf, 1, write_cb); + ASSERT(r == 0); +} + + +static void connection_cb(uv_stream_t* tcp, int status) { + ASSERT(status == 0); + + 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)); + + connection_cb_called++; +} + + +static void start_server(void) { + struct sockaddr_in addr; + + ASSERT(0 == 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)); +} + + +TEST_IMPL(tcp_alloc_cb_fail) { + uv_connect_t connect_req; + struct sockaddr_in addr; + + 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_run(uv_default_loop(), UV_RUN_DEFAULT)); + + ASSERT(connect_cb_called == 1); + ASSERT(connection_cb_called == 1); + ASSERT(close_cb_called == 3); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-tcp-write-queue-order.c b/test/test-tcp-write-queue-order.c index 8a98ab836..d50289c3c 100644 --- a/test/test-tcp-write-queue-order.c +++ b/test/test-tcp-write-queue-order.c @@ -46,13 +46,13 @@ static void close_cb(uv_handle_t* handle) { close_cb_called++; } -void timer_cb(uv_timer_t* handle) { +static void timer_cb(uv_timer_t* handle) { uv_close((uv_handle_t*) &client, close_cb); uv_close((uv_handle_t*) &server, close_cb); uv_close((uv_handle_t*) &incoming, close_cb); } -void write_cb(uv_write_t* req, int status) { +static void write_cb(uv_write_t* req, int status) { if (status == 0) write_callbacks++; else if (status == UV_ECANCELED) diff --git a/test/test-udp-alloc-cb-fail.c b/test/test-udp-alloc-cb-fail.c new file mode 100644 index 000000000..05b871e92 --- /dev/null +++ b/test/test-udp-alloc-cb-fail.c @@ -0,0 +1,197 @@ +/* Copyright libuv project 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 + +#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 int cl_send_cb_called; +static int cl_recv_cb_called; + +static int sv_send_cb_called; +static int sv_recv_cb_called; + +static int close_cb_called; + + +static void sv_alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + CHECK_HANDLE(handle); + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void cl_alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + /* Do nothing, recv_cb should be called with UV_ENOBUFS. */ +} + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + ASSERT(1 == uv_is_closing(handle)); + close_cb_called++; +} + + +static void cl_recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* buf, + const struct sockaddr* addr, + unsigned flags) { + CHECK_HANDLE(handle); + ASSERT(flags == 0); + ASSERT(nread == UV_ENOBUFS); + + cl_recv_cb_called++; + + uv_close((uv_handle_t*) handle, close_cb); +} + + +static void cl_send_cb(uv_udp_send_t* req, int status) { + int r; + + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + + r = uv_udp_recv_start(req->handle, cl_alloc_cb, cl_recv_cb); + ASSERT(r == 0); + + cl_send_cb_called++; +} + + +static void sv_send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + + uv_close((uv_handle_t*) req->handle, close_cb); + free(req); + + sv_send_cb_called++; +} + + +static void sv_recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* rcvbuf, + const struct sockaddr* addr, + unsigned flags) { + uv_udp_send_t* req; + uv_buf_t sndbuf; + int r; + + if (nread < 0) { + ASSERT(0 && "unexpected error"); + } + + if (nread == 0) { + /* Returning unused buffer */ + /* Don't count towards sv_recv_cb_called */ + ASSERT(addr == NULL); + return; + } + + CHECK_HANDLE(handle); + ASSERT(flags == 0); + + ASSERT(addr != NULL); + ASSERT(nread == 4); + ASSERT(!memcmp("PING", rcvbuf->base, nread)); + + r = uv_udp_recv_stop(handle); + ASSERT(r == 0); + + req = malloc(sizeof *req); + ASSERT(req != NULL); + + sndbuf = uv_buf_init("PONG", 4); + r = uv_udp_send(req, handle, &sndbuf, 1, addr, sv_send_cb); + ASSERT(r == 0); + + sv_recv_cb_called++; +} + + +TEST_IMPL(udp_alloc_cb_fail) { + struct sockaddr_in addr; + uv_udp_send_t req; + uv_buf_t buf; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_udp_recv_start(&server, sv_alloc_cb, sv_recv_cb); + ASSERT(r == 0); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + buf = uv_buf_init("PING", 4); + r = uv_udp_send(&req, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + cl_send_cb); + ASSERT(r == 0); + + 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); + + 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); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/uv.gyp b/uv.gyp index b83f82b0f..953a6fdc8 100644 --- a/uv.gyp +++ b/uv.gyp @@ -364,6 +364,7 @@ 'test/test-spawn.c', 'test/test-fs-poll.c', 'test/test-stdio-over-pipes.c', + 'test/test-tcp-alloc-cb-fail.c', 'test/test-tcp-bind-error.c', 'test/test-tcp-bind6-error.c', 'test/test-tcp-close.c', @@ -398,6 +399,7 @@ 'test/test-timer-from-check.c', 'test/test-timer.c', 'test/test-tty.c', + 'test/test-udp-alloc-cb-fail.c', 'test/test-udp-bind.c', 'test/test-udp-create-socket-early.c', 'test/test-udp-dgram-too-big.c', From 1cff5b7557483164d980aa60e6e0225ecbbe7df1 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Tue, 5 Jul 2016 18:37:45 -0400 Subject: [PATCH 221/632] zos: add support for new platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - zos: disable test cases not applicable - zos: build options - zos: semaphore implementation - zos: use compare and swap builtins - zos: struct rusage not the same as other platforms - zos: backlog<=0 produces undefined behaviour Will redefine backlog in the following way * if backlog == 0, set it to 1 * if backlog < 0, set it to SOMAXCONN - zos: define IMAXBEL as empty flag and implement uv__tty_make_raw - zos: use udp multicast operations from aix - zos: ESC in ebcdic - zos: use LIBPATH for dynamic linker path - zos: uv_udp_set_ttl only works for ipv6 - zos: increase pthread stack size by factor of 4 - zos: return ENODEV instead of ENXIO errors for setsockopt - zos: use uv_cond_init the same way as aix - test: enable oob test for zos - zos: return EINVAL for zos error code EOPNOTSUPP PR-URL: https://github.com/libuv/libuv/pull/937 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 38 +++++++++++++++ common.gypi | 7 ++- configure.ac | 5 +- include/pthread-barrier.h | 2 + include/uv-os390.h | 27 +++++++++++ src/unix/atomic-ops.h | 12 +++++ src/unix/core.c | 6 +++ src/unix/pipe.c | 8 +++ src/unix/tcp.c | 4 ++ src/unix/thread.c | 86 ++++++++++++++++++++++++++++++++- src/unix/tty.c | 6 ++- src/unix/udp.c | 33 ++++++++++--- test/runner-unix.c | 8 +++ test/test-emfile.c | 4 +- test/test-fs-event.c | 42 ++++++++++++++++ test/test-fs.c | 2 +- test/test-poll.c | 14 +++--- test/test-process-title.c | 2 +- test/test-ref.c | 3 ++ test/test-spawn.c | 5 ++ test/test-udp-multicast-join6.c | 2 +- test/test-udp-options.c | 11 +++++ test/test-watcher-cross-stop.c | 3 ++ uv.gyp | 79 ++++++++++++++++++++++-------- 24 files changed, 366 insertions(+), 43 deletions(-) create mode 100644 include/uv-os390.h diff --git a/Makefile.am b/Makefile.am index a04373596..aab6b0c87 100644 --- a/Makefile.am +++ b/Makefile.am @@ -129,7 +129,11 @@ EXTRA_DIST = test/fixtures/empty_file \ TESTS = test/run-tests check_PROGRAMS = test/run-tests +if OS390 +test_run_tests_CFLAGS = +else test_run_tests_CFLAGS = -Wno-long-long +endif test_run_tests_LDFLAGS = test_run_tests_SOURCES = test/blackhole-server.c \ test/dns-server.c \ @@ -284,6 +288,21 @@ if SUNOS test_run_tests_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 endif +if OS390 +test_run_tests_CFLAGS += -D_UNIX03_THREADS \ + -D_UNIX03_SOURCE \ + -D_OPEN_SYS_IF_EXT=1 \ + -D_OPEN_SYS_SOCK_IPV6 \ + -D_OPEN_MSGQ_EXT \ + -D_XOPEN_SOURCE_EXTENDED \ + -D_ALL_SOURCE \ + -D_LARGE_TIME_API \ + -D_OPEN_SYS_FILE_EXT \ + -DPATH_MAX=255 \ + -qCHARS=signed \ + -qXPLINK \ + -qFLOAT=IEEE +endif if AIX libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT -D_THREAD_SAFE @@ -354,6 +373,25 @@ libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 libuv_la_SOURCES += src/unix/sunos.c endif +if OS390 +include_HEADERS += include/pthread-fixes.h include/pthread-barrier.h +libuv_la_CFLAGS += -D_UNIX03_THREADS \ + -D_UNIX03_SOURCE \ + -D_OPEN_SYS_IF_EXT=1 \ + -D_OPEN_MSGQ_EXT \ + -D_XOPEN_SOURCE_EXTENDED \ + -D_ALL_SOURCE \ + -D_LARGE_TIME_API \ + -D_OPEN_SYS_SOCK_IPV6 \ + -D_OPEN_SYS_FILE_EXT \ + -DUV_PLATFORM_SEM_T=int \ + -DPATH_MAX=255 \ + -qCHARS=signed \ + -qXPLINK \ + -qFLOAT=IEEE +libuv_la_LDFLAGS += -qXPLINK +endif + if HAVE_PKG_CONFIG pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = @PACKAGE_NAME@.pc diff --git a/common.gypi b/common.gypi index 56bca2948..44db701d6 100644 --- a/common.gypi +++ b/common.gypi @@ -11,7 +11,7 @@ 'configurations': { 'Debug': { 'defines': [ 'DEBUG', '_DEBUG' ], - 'cflags': [ '-g', '-O0', '-fwrapv' ], + 'cflags': [ '-g' ], 'msvs_settings': { 'VCCLCompilerTool': { 'target_conditions': [ @@ -35,6 +35,9 @@ 'OTHER_CFLAGS': [ '-Wno-strict-aliasing' ], }, 'conditions': [ + ['OS != "zos"', { + 'cflags': [ '-O0', '-fwrapv' ] + }], ['OS == "android"', { 'cflags': [ '-fPIE' ], 'ldflags': [ '-fPIE', '-pie' ] @@ -151,7 +154,7 @@ 'cflags': [ '-pthreads' ], 'ldflags': [ '-pthreads' ], }], - [ 'OS not in "solaris android"', { + [ 'OS not in "solaris android zos"', { 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], diff --git a/configure.ac b/configure.ac index 4a106bec9..239e919ca 100644 --- a/configure.ac +++ b/configure.ac @@ -24,10 +24,12 @@ AC_ENABLE_SHARED AC_ENABLE_STATIC AC_PROG_CC AM_PROG_CC_C_O +AS_IF([AS_CASE([$host_os],[openedition*], [false], [true])], [ + CC_CHECK_CFLAGS_APPEND([-pedantic]) +]) CC_FLAG_VISIBILITY #[-fvisibility=hidden] CC_CHECK_CFLAGS_APPEND([-g]) CC_CHECK_CFLAGS_APPEND([-std=gnu89]) -CC_CHECK_CFLAGS_APPEND([-pedantic]) CC_CHECK_CFLAGS_APPEND([-Wall]) CC_CHECK_CFLAGS_APPEND([-Wextra]) CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter]) @@ -56,6 +58,7 @@ AM_CONDITIONAL([FREEBSD], [AS_CASE([$host_os],[freebsd*], [true], [false]) AM_CONDITIONAL([LINUX], [AS_CASE([$host_os],[linux*], [true], [false])]) AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false])]) AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])]) +AM_CONDITIONAL([OS390], [AS_CASE([$host_os],[openedition*], [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*], [ diff --git a/include/pthread-barrier.h b/include/pthread-barrier.h index 084e1c2d5..68468ad2a 100644 --- a/include/pthread-barrier.h +++ b/include/pthread-barrier.h @@ -39,6 +39,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2 * sizeof(sem_t) + \ 2 * sizeof(unsigned int) - \ sizeof(void *) +#elif defined(__MVS__) +# define UV_BARRIER_STRUCT_PADDING 0 #endif typedef struct { diff --git a/include/uv-os390.h b/include/uv-os390.h new file mode 100644 index 000000000..b0b068f44 --- /dev/null +++ b/include/uv-os390.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_MVS_H +#define UV_MVS_H + +#define UV_PLATFORM_SEM_T int + +#endif /* UV_MVS_H */ diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h index 84e471838..334c343e8 100644 --- a/src/unix/atomic-ops.h +++ b/src/unix/atomic-ops.h @@ -42,6 +42,10 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { const int out = (*(volatile int*) ptr); __compare_and_swap(ptr, &oldval, newval); return out; +#elif defined(__MVS__) + const int out = (*(volatile int*) ptr); + cs((cs_t*)&oldval, (cs_t*)ptr, *(cs_t*)(&newval)); + return out; #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif @@ -63,6 +67,14 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) { __compare_and_swap(ptr, &oldval, newval); # endif /* if defined(__64BIT__) */ return out; +#elif defined (__MVS__) + const long out = (*(volatile int*) ptr); +# ifdef _LP64 + cds((cds_t*)(&oldval), (cds_t*)ptr, *(cds_t*)(&newval)); +# else + cs((cs_t*)&oldval, (cs_t*)ptr, *(cs_t*)(&newval)); +# endif + return out; #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif diff --git a/src/unix/core.c b/src/unix/core.c index 645223833..3df966e2b 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -74,6 +74,10 @@ # include /* for dlsym */ #endif +#if defined(__MVS__) +#include +#endif + static int uv__run_pending(uv_loop_t* loop); /* Verify that uv_buf_t is ABI-compatible with struct iovec. */ @@ -915,6 +919,7 @@ int uv_getrusage(uv_rusage_t* rusage) { rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec; rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec; +#if !defined(__MVS__) rusage->ru_maxrss = usage.ru_maxrss; rusage->ru_ixrss = usage.ru_ixrss; rusage->ru_idrss = usage.ru_idrss; @@ -929,6 +934,7 @@ int uv_getrusage(uv_rusage_t* rusage) { rusage->ru_nsignals = usage.ru_nsignals; rusage->ru_nvcsw = usage.ru_nvcsw; rusage->ru_nivcsw = usage.ru_nivcsw; +#endif return 0; } diff --git a/src/unix/pipe.c b/src/unix/pipe.c index c8d163dcc..a3797ddab 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -97,6 +97,14 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { if (uv__stream_fd(handle) == -1) return -EINVAL; +#if defined(__MVS__) + /* On zOS, backlog=0 has undefined behaviour */ + if (backlog == 0) + backlog = 1; + else if (backlog < 0) + backlog = SOMAXCONN; +#endif + if (listen(uv__stream_fd(handle), backlog)) return -errno; diff --git a/src/unix/tcp.c b/src/unix/tcp.c index 46d8cd25b..fa52a137e 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -115,6 +115,10 @@ int uv__tcp_bind(uv_tcp_t* tcp, IPV6_V6ONLY, &on, sizeof on) == -1) { +#if defined(__MVS__) + if (errno == EOPNOTSUPP) + return -EINVAL; +#endif return -errno; } } diff --git a/src/unix/thread.c b/src/unix/thread.c index 236f59139..52989f7f0 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -32,6 +32,11 @@ #include +#ifdef __MVS__ +#include +#include +#endif + #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) @@ -302,6 +307,85 @@ int uv_sem_trywait(uv_sem_t* sem) { return -EINVAL; /* Satisfy the compiler. */ } +#elif defined(__MVS__) + +int uv_sem_init(uv_sem_t* sem, unsigned int value) { + uv_sem_t semid; + struct sembuf buf; + int err; + + buf.sem_num = 0; + buf.sem_op = value; + buf.sem_flg = 0; + + semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); + if (semid == -1) + return -errno; + + if (-1 == semop(semid, &buf, 1)) { + err = errno; + if (-1 == semctl(*sem, 0, IPC_RMID)) + abort(); + return -err; + } + + *sem = semid; + return 0; +} + +void uv_sem_destroy(uv_sem_t* sem) { + if (-1 == semctl(*sem, 0, IPC_RMID)) + abort(); +} + +void uv_sem_post(uv_sem_t* sem) { + struct sembuf buf; + + buf.sem_num = 0; + buf.sem_op = 1; + buf.sem_flg = 0; + + if (-1 == semop(*sem, &buf, 1)) + abort(); +} + +void uv_sem_wait(uv_sem_t* sem) { + struct sembuf buf; + int op_status; + + buf.sem_num = 0; + buf.sem_op = -1; + buf.sem_flg = 0; + + do + op_status = semop(*sem, &buf, 1); + while (op_status == -1 && errno == EINTR); + + if (op_status) + abort(); +} + +int uv_sem_trywait(uv_sem_t* sem) { + struct sembuf buf; + int op_status; + + buf.sem_num = 0; + buf.sem_op = -1; + buf.sem_flg = IPC_NOWAIT; + + do + op_status = semop(*sem, &buf, 1); + while (op_status == -1 && errno == EINTR); + + if (op_status) { + if (errno == EAGAIN) + return -EAGAIN; + abort(); + } + + return 0; +} + #else /* !(defined(__APPLE__) && defined(__MACH__)) */ int uv_sem_init(uv_sem_t* sem, unsigned int value) { @@ -354,7 +438,7 @@ int uv_sem_trywait(uv_sem_t* sem) { #endif /* defined(__APPLE__) && defined(__MACH__) */ -#if defined(__APPLE__) && defined(__MACH__) +#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__) int uv_cond_init(uv_cond_t* cond) { return -pthread_cond_init(cond, NULL); diff --git a/src/unix/tty.c b/src/unix/tty.c index a56afe183..fd4bcbcf8 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -30,6 +30,10 @@ #include #include +#if defined(__MVS__) && !defined(IMAXBEL) +#define IMAXBEL 0 +#endif + static int orig_termios_fd = -1; static struct termios orig_termios; static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; @@ -168,7 +172,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { static void uv__tty_make_raw(struct termios* tio) { assert(tio != NULL); -#ifdef __sun +#if defined __sun || defined __MVS__ /* * This implementation of cfmakeraw for Solaris and derivatives is taken from * http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html. diff --git a/src/unix/udp.c b/src/unix/udp.c index f5d7ed14b..7c9dae99c 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -27,6 +27,9 @@ #include #include #include +#if defined(__MVS__) +#include +#endif #if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP) # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP @@ -508,6 +511,10 @@ static int uv__udp_set_membership4(uv_udp_t* handle, optname, &mreq, sizeof(mreq))) { +#if defined(__MVS__) + if (errno == ENXIO) + return -ENODEV; +#endif return -errno; } @@ -551,6 +558,10 @@ static int uv__udp_set_membership6(uv_udp_t* handle, optname, &mreq, sizeof(mreq))) { +#if defined(__MVS__) + if (errno == ENXIO) + return -ENODEV; +#endif return -errno; } @@ -669,7 +680,7 @@ static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option4, int option6, int val) { -#if defined(__sun) || defined(_AIX) +#if defined(__sun) || defined(_AIX) || defined(__MVS__) char arg = val; #elif defined(__OpenBSD__) unsigned char arg = val; @@ -701,19 +712,27 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { if (ttl < 1 || ttl > 255) return -EINVAL; +#if defined(__MVS__) + if (!(handle->flags & UV_HANDLE_IPV6)) + return -ENOTSUP; /* zOS does not support setting ttl for IPv4 */ +#endif + /* * On Solaris and derivatives such as SmartOS, the length of socket options * is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS, * so hardcode the size of these options on this platform, * and use the general uv__setsockopt_maybe_char call on other platforms. */ -#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) +#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) + return uv__setsockopt(handle, IP_TTL, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); -#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) */ +#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || + defined(__MVS__) */ return uv__setsockopt_maybe_char(handle, IP_TTL, @@ -729,14 +748,14 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case, * and use the general uv__setsockopt_maybe_char call otherwise. */ -#if defined(__sun) || defined(_AIX) +#if defined(__sun) || defined(_AIX) || defined(__MVS__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_TTL, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)); -#endif /* defined(__sun) || defined(_AIX) */ +#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ return uv__setsockopt_maybe_char(handle, IP_MULTICAST_TTL, @@ -752,14 +771,14 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case, * and use the general uv__setsockopt_maybe_char call otherwise. */ -#if defined(__sun) || defined(_AIX) +#if defined(__sun) || defined(_AIX) || defined(__MVS__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_LOOP, IPV6_MULTICAST_LOOP, &on, sizeof(on)); -#endif /* defined(__sun) || defined(_AIX) */ +#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ return uv__setsockopt_maybe_char(handle, IP_MULTICAST_LOOP, diff --git a/test/runner-unix.c b/test/runner-unix.c index 0edd671b9..63f801b59 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -201,7 +201,11 @@ int process_wait(process_info_t* vec, int n, int timeout) { if (pthread_attr_init(&attr)) abort(); +#if defined(__MVS__) + if (pthread_attr_setstacksize(&attr, 1024 * 1024)) +#else if (pthread_attr_setstacksize(&attr, 256 * 1024)) +#endif abort(); r = pthread_create(&tid, &attr, dowait, &args); @@ -372,7 +376,11 @@ void process_cleanup(process_info_t *p) { /* Move the console cursor one line up and back to the first column. */ void rewind_cursor(void) { +#if defined(__MVS__) + fprintf(stderr, "\047[2K\r"); +#else fprintf(stderr, "\033[2K\r"); +#endif } diff --git a/test/test-emfile.c b/test/test-emfile.c index 5f4dd9efd..8e44ac5c7 100644 --- a/test/test-emfile.c +++ b/test/test-emfile.c @@ -38,12 +38,12 @@ static uv_tcp_t client_handle; TEST_IMPL(emfile) { -#ifdef _AIX +#if defined(_AIX) || defined(__MVS__) /* On AIX, if a 'accept' call fails ECONNRESET is set on the socket * which causes uv__emfile_trick to not work as intended and this test * to fail. */ - RETURN_SKIP("uv__emfile_trick does not work on AIX"); + RETURN_SKIP("uv__emfile_trick does not work on this OS"); #endif struct sockaddr_in addr; struct rlimit limits; diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 25eef07b1..7dd2cb399 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -376,6 +376,10 @@ static void timer_cb_watch_twice(uv_timer_t* handle) { } TEST_IMPL(fs_event_watch_dir) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif + uv_loop_t* loop = uv_default_loop(); int r; @@ -455,6 +459,10 @@ TEST_IMPL(fs_event_watch_dir_recursive) { TEST_IMPL(fs_event_watch_file) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif + uv_loop_t* loop = uv_default_loop(); int r; @@ -495,6 +503,11 @@ TEST_IMPL(fs_event_watch_file_exact_path) { This test watches a file named "file.jsx" and modifies a file named "file.js". The test verifies that no events occur for file.jsx. */ + +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif + uv_loop_t* loop; int r; @@ -530,6 +543,9 @@ TEST_IMPL(fs_event_watch_file_exact_path) { } TEST_IMPL(fs_event_watch_file_twice) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif const char path[] = "test/fixtures/empty_file"; uv_fs_event_t watchers[2]; uv_timer_t timer; @@ -551,6 +567,9 @@ TEST_IMPL(fs_event_watch_file_twice) { } TEST_IMPL(fs_event_watch_file_current_dir) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_timer_t timer; uv_loop_t* loop; int r; @@ -621,6 +640,10 @@ TEST_IMPL(fs_event_watch_file_root_dir) { #endif TEST_IMPL(fs_event_no_callback_after_close) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif + uv_loop_t* loop = uv_default_loop(); int r; @@ -655,6 +678,10 @@ TEST_IMPL(fs_event_no_callback_after_close) { } TEST_IMPL(fs_event_no_callback_on_close) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif + uv_loop_t* loop = uv_default_loop(); int r; @@ -702,6 +729,9 @@ static void timer_cb(uv_timer_t* handle) { TEST_IMPL(fs_event_immediate_close) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_timer_t timer; uv_loop_t* loop; int r; @@ -724,6 +754,9 @@ TEST_IMPL(fs_event_immediate_close) { TEST_IMPL(fs_event_close_with_pending_event) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_loop_t* loop; int r; @@ -782,6 +815,9 @@ static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, TEST_IMPL(fs_event_close_in_callback) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_loop_t* loop; int r; @@ -826,6 +862,9 @@ TEST_IMPL(fs_event_close_in_callback) { #endif /* HAVE_KQUEUE || _AIX */ TEST_IMPL(fs_event_start_and_close) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_loop_t* loop; uv_fs_event_t fs_event1; uv_fs_event_t fs_event2; @@ -858,6 +897,9 @@ TEST_IMPL(fs_event_start_and_close) { } TEST_IMPL(fs_event_getpath) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_loop_t* loop = uv_default_loop(); int r; char buf[1024]; diff --git a/test/test-fs.c b/test/test-fs.c index 250d13501..7c3c6f209 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -29,7 +29,7 @@ /* FIXME we shouldn't need to branch in this file */ #if defined(__unix__) || defined(__POSIX__) || \ - defined(__APPLE__) || defined(_AIX) + defined(__APPLE__) || defined(_AIX) || defined(__MVS__) #include /* unlink, rmdir, etc. */ #else # include diff --git a/test/test-poll.c b/test/test-poll.c index 33d0761a6..848ce88ab 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -82,9 +82,9 @@ static int closed_connections = 0; static int valid_writable_wakeups = 0; static int spurious_writable_wakeups = 0; -#ifndef _AIX +#if !defined(_AIX) && !defined(__MVS__) static int disconnects = 0; -#endif /* !_AIX */ +#endif /* !_AIX && !__MVS__ */ static int got_eagain(void) { #ifdef _WIN32 @@ -388,7 +388,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { new_events &= ~UV_WRITABLE; } } -#ifndef _AIX +#if !defined(_AIX) && !defined(__MVS__) if (events & UV_DISCONNECT) { context->got_disconnect = 1; ++disconnects; @@ -396,9 +396,9 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { } if (context->got_fin && context->sent_fin && context->got_disconnect) { -#else /* _AIX */ +#else /* _AIX && __MVS__ */ if (context->got_fin && context->sent_fin) { -#endif /* !_AIx */ +#endif /* !_AIX && !__MVS__ */ /* Sent and received FIN. Close and destroy context. */ close_socket(context->sock); destroy_connection_context(context); @@ -566,7 +566,7 @@ static void start_poll_test(void) { spurious_writable_wakeups > 20); ASSERT(closed_connections == NUM_CLIENTS * 2); -#ifndef _AIX +#if !defined(_AIX) && !defined(__MVS__) ASSERT(disconnects == NUM_CLIENTS * 2); #endif MAKE_VALGRIND_HAPPY(); @@ -594,7 +594,7 @@ TEST_IMPL(poll_unidirectional) { */ TEST_IMPL(poll_bad_fdtype) { #if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \ - !defined(_AIX) + !defined(_AIX) && !defined(__MVS__) uv_poll_t poll_handle; int fd; diff --git a/test/test-process-title.c b/test/test-process-title.c index 00f164a41..21ab0ed4f 100644 --- a/test/test-process-title.c +++ b/test/test-process-title.c @@ -60,7 +60,7 @@ static void uv_get_process_title_edge_cases() { TEST_IMPL(process_title) { -#if defined(__sun) || defined(_AIX) +#if defined(__sun) || defined(_AIX) || defined(__MVS__) RETURN_SKIP("uv_(get|set)_process_title is not implemented."); #else /* Check for format string vulnerabilities. */ diff --git a/test/test-ref.c b/test/test-ref.c index ddaa17380..39f4b0fc7 100644 --- a/test/test-ref.c +++ b/test/test-ref.c @@ -194,6 +194,9 @@ TEST_IMPL(timer_ref2) { TEST_IMPL(fs_event_ref) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_fs_event_t h; uv_fs_event_init(uv_default_loop(), &h); uv_fs_event_start(&h, (uv_fs_event_cb)fail_cb, ".", 0); diff --git a/test/test-spawn.c b/test/test-spawn.c index eba54ae70..0e84ad6de 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1431,6 +1431,9 @@ TEST_IMPL(spawn_fs_open) { #ifndef _WIN32 TEST_IMPL(closed_fd_events) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif uv_stdio_container_t stdio[3]; uv_pipe_t pipe_handle; int fd[2]; @@ -1500,6 +1503,8 @@ TEST_IMPL(spawn_reads_child_path) { */ #if defined(__APPLE__) static const char dyld_path_var[] = "DYLD_LIBRARY_PATH"; +#elif defined __MVS__ + static const char dyld_path_var[] = "LIBPATH"; #else static const char dyld_path_var[] = "LD_LIBRARY_PATH"; #endif diff --git a/test/test-udp-multicast-join6.c b/test/test-udp-multicast-join6.c index f635bdb9e..26a27d600 100644 --- a/test/test-udp-multicast-join6.c +++ b/test/test-udp-multicast-join6.c @@ -119,7 +119,7 @@ TEST_IMPL(udp_multicast_join6) { ASSERT(r == 0); /* join the multicast channel */ -#if defined(__APPLE__) || defined(_AIX) +#if defined(__APPLE__) || defined(_AIX) || defined(__MVS__) r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP); #else r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP); diff --git a/test/test-udp-options.c b/test/test-udp-options.c index 0da1786f5..8f9136759 100644 --- a/test/test-udp-options.c +++ b/test/test-udp-options.c @@ -52,7 +52,14 @@ static int udp_options_test(const struct sockaddr* addr) { /* 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); + else + ASSERT(r == UV_ENOTSUP); +#else ASSERT(r == 0); +#endif } for (i = 0; i < (int) ARRAY_SIZE(invalid_ttls); i++) { @@ -113,7 +120,11 @@ TEST_IMPL(udp_no_autobind) { 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)); +#if defined(__MVS__) + ASSERT(UV_ENOTSUP == uv_udp_set_ttl(&h, 1)); +#else ASSERT(UV_EBADF == uv_udp_set_ttl(&h, 1)); +#endif ASSERT(UV_EBADF == uv_udp_set_multicast_loop(&h, 1)); ASSERT(UV_EBADF == uv_udp_set_multicast_interface(&h, "0.0.0.0")); diff --git a/test/test-watcher-cross-stop.c b/test/test-watcher-cross-stop.c index 910ed0fb6..6ff48d44c 100644 --- a/test/test-watcher-cross-stop.c +++ b/test/test-watcher-cross-stop.c @@ -59,6 +59,9 @@ static void close_cb(uv_handle_t* handle) { TEST_IMPL(watcher_cross_stop) { +#if defined(__MVS__) + RETURN_SKIP("zOS does not allow address or port reuse when using UDP sockets"); +#endif uv_loop_t* loop = uv_default_loop(); unsigned int i; struct sockaddr_in addr; diff --git a/uv.gyp b/uv.gyp index 953a6fdc8..3a480dea0 100644 --- a/uv.gyp +++ b/uv.gyp @@ -10,9 +10,25 @@ ['OS=="solaris"', { 'cflags': [ '-pthreads' ], }], - ['OS not in "solaris android"', { + ['OS not in "solaris android zos"', { 'cflags': [ '-pthread' ], }], + ['OS in "zos"', { + 'defines': [ + '_UNIX03_THREADS', + '_UNIX03_SOURCE', + '_OPEN_SYS_IF_EXT', + '_OPEN_SYS_SOCK_IPV6', + '_OPEN_MSGQ_EXT', + '_XOPEN_SOURCE_EXTENDED', + '_ALL_SOURCE', + '_LARGE_TIME_API', + '_OPEN_SYS_FILE_EXT', + '_AE_BIMODAL', + 'PATH_MAX=255' + ], + 'cflags': [ '-qxplink' ], + }] ], }], ], @@ -119,15 +135,6 @@ ], }, }, { # Not Windows i.e. POSIX - 'cflags': [ - '-fvisibility=hidden', - '-g', - '--std=gnu89', - '-pedantic', - '-Wall', - '-Wextra', - '-Wno-unused-parameter', - ], 'sources': [ 'include/uv-unix.h', 'include/uv-linux.h', @@ -163,16 +170,25 @@ ['OS=="solaris"', { 'ldflags': [ '-pthreads' ], }], - ['OS != "solaris" and OS != "android"', { + [ 'OS=="zos" and uv_library=="shared_library"', { + 'ldflags': [ '-Wl,DLL' ], + }], + ['OS != "solaris" and OS != "android" and OS != "zos"', { 'ldflags': [ '-pthread' ], }], ], }, 'conditions': [ ['uv_library=="shared_library"', { - 'cflags': [ '-fPIC' ], + 'conditions': [ + ['OS=="zos"', { + 'cflags': [ '-qexportall' ], + }, { + 'cflags': [ '-fPIC' ], + }], + ], }], - ['uv_library=="shared_library" and OS!="mac"', { + ['uv_library=="shared_library" and OS!="mac" and OS!="zos"', { # This will cause gyp to set soname # Must correspond with UV_VERSION_MAJOR # in include/uv-version.h @@ -183,6 +199,17 @@ [ 'OS in "linux mac ios android"', { 'sources': [ 'src/unix/proctitle.c' ], }], + [ 'OS != "zos"', { + 'cflags': [ + '-fvisibility=hidden', + '-g', + '--std=gnu89', + '-pedantic', + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + ], + }], [ 'OS in "mac ios"', { 'sources': [ 'src/unix/darwin.c', @@ -195,7 +222,7 @@ '_DARWIN_UNLIMITED_SELECT=1', ] }], - [ 'OS!="mac"', { + [ 'OS!="mac" and OS!="zos"', { # Enable on all platforms except OS X. The antique gcc/clang that # ships with Xcode emits waaaay too many false positives. 'cflags': [ '-Wstrict-aliasing' ], @@ -428,13 +455,17 @@ ], 'libraries': [ '-lws2_32' ] }, { # POSIX - 'defines': [ '_GNU_SOURCE' ], - 'cflags': [ '-Wno-long-long' ], 'sources': [ 'test/runner-unix.c', 'test/runner-unix.h', ], - }], + 'conditions': [ + [ 'OS != "zos"', { + 'defines': [ '_GNU_SOURCE' ], + 'cflags': [ '-Wno-long-long' ], + }], + ]}, + ], [ 'OS in "mac dragonflybsd freebsd linux netbsd openbsd".split()', { 'link_settings': { 'libraries': [ '-lutil' ], @@ -453,7 +484,12 @@ ], }], ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ] + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "zos"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], }], ], 'msvs-settings': { @@ -509,7 +545,12 @@ ] }], ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ] + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "zos"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], }], ], 'msvs-settings': { From e9940008349d2e7dcb1bde2fe9cf08d3ea806d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 18 Aug 2016 13:02:57 +0100 Subject: [PATCH 222/632] test: make tcp_close_while_connecting more resilient It's not impossible for connect() to succeed before the handle is fully closed, so handle that case too. PR-URL: https://github.com/libuv/libuv/pull/1005 Reviewed-By: Ben Noordhuis --- test/test-tcp-close-while-connecting.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-tcp-close-while-connecting.c b/test/test-tcp-close-while-connecting.c index 60df7a574..90a31f319 100644 --- a/test/test-tcp-close-while-connecting.c +++ b/test/test-tcp-close-while-connecting.c @@ -37,7 +37,7 @@ static void close_cb(uv_handle_t* handle) { static void connect_cb(uv_connect_t* req, int status) { - ASSERT(status == UV_ECANCELED); + ASSERT(status == UV_ECANCELED || status == 0); uv_timer_stop(&timer2_handle); connect_cb_called++; } From e5c93a1589fd1d39336854356f23b5cfa5cada52 Mon Sep 17 00:00:00 2001 From: Matt Clarkson Date: Thu, 11 Aug 2016 09:08:57 +0100 Subject: [PATCH 223/632] build: use '${prefix}' for pkg-config 'exec_prefix' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This follows common pkg-config configuration files and allows for certain pkg-config overrides to work. For example, when cross-compiling it is common to have to set a different pkg-config prefix through either '--define-prefix' or a 'PKG_CONFIG_LIBUV_PREFIX' environment variable. If the 'exec_prefix' is hardcoded to '@prefix@' then it will not pick up those pkg-config overrides. PR-URL: https://github.com/libuv/libuv/pull/993 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- libuv.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libuv.pc.in b/libuv.pc.in index 2933ec225..9174fe151 100644 --- a/libuv.pc.in +++ b/libuv.pc.in @@ -1,5 +1,5 @@ prefix=@prefix@ -exec_prefix=@prefix@ +exec_prefix=${prefix} libdir=@libdir@ includedir=@includedir@ From 0a4b51fcb408c47c6dfa2f5e04d8da44920772c4 Mon Sep 17 00:00:00 2001 From: Jeffrey Clark Date: Thu, 28 Jul 2016 14:26:01 -0500 Subject: [PATCH 224/632] build: GNU/kFreeBSD support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit autotools support only, gvp does not support kfreebsd detection. PR-URL: https://github.com/libuv/libuv/pull/960 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- configure.ac | 2 +- include/uv-errno.h | 1 + include/uv-unix.h | 7 ++++--- src/unix/core.c | 4 +++- src/unix/fs.c | 22 ++++++++++++++++++---- src/unix/internal.h | 1 + src/unix/process.c | 2 +- src/unix/tty.c | 2 +- test/test-embed.c | 1 + test/test-fs-event.c | 1 + test/test-poll.c | 2 +- test/test-tty.c | 12 +++++++++--- test/test-udp-ipv6.c | 6 +++--- test/test-udp-multicast-interface6.c | 2 +- test/test-udp-multicast-join6.c | 5 ++++- 15 files changed, 50 insertions(+), 20 deletions(-) diff --git a/configure.ac b/configure.ac index 239e919ca..90335b4ac 100644 --- a/configure.ac +++ b/configure.ac @@ -54,7 +54,7 @@ AM_CONDITIONAL([AIX], [AS_CASE([$host_os],[aix*], [true], [false]) AM_CONDITIONAL([ANDROID], [AS_CASE([$host_os],[linux-android*],[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([FREEBSD], [AS_CASE([$host_os],[*freebsd*], [true], [false])]) AM_CONDITIONAL([LINUX], [AS_CASE([$host_os],[linux*], [true], [false])]) AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false])]) AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])]) diff --git a/include/uv-errno.h b/include/uv-errno.h index 53f30296c..f1371517c 100644 --- a/include/uv-errno.h +++ b/include/uv-errno.h @@ -408,6 +408,7 @@ #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 a852c40e4..bca271447 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -50,9 +50,10 @@ # include "uv-sunos.h" #elif defined(__APPLE__) # include "uv-darwin.h" -#elif defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ +#elif defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__OpenBSD__) || \ defined(__NetBSD__) # include "uv-bsd.h" #endif diff --git a/src/unix/core.c b/src/unix/core.c index 3df966e2b..d88fc1de8 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -55,7 +55,9 @@ # endif #endif -#if defined(__FreeBSD__) || defined(__DragonFly__) +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) # include # include # include diff --git a/src/unix/fs.c b/src/unix/fs.c index 0b2505e4c..37f8e3b65 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -46,9 +46,10 @@ #include #include -#if defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ +#if defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel_) || \ + defined(__OpenBSD__) || \ defined(__NetBSD__) # define HAVE_PREADV 1 #else @@ -193,6 +194,7 @@ 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) @@ -595,7 +597,10 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { return -1; } -#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__) +#elif defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) { off_t len; ssize_t r; @@ -608,6 +613,15 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { #if defined(__FreeBSD__) || defined(__DragonFly__) 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. */ diff --git a/src/unix/internal.h b/src/unix/internal.h index 4cae73764..7cc8ee8b6 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -156,6 +156,7 @@ struct uv__stream_queued_fds_s { defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ defined(__linux__) #define uv__cloexec uv__cloexec_ioctl #define uv__nonblock uv__nonblock_ioctl diff --git a/src/unix/process.c b/src/unix/process.c index 8a010edc7..45f5b4526 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -40,7 +40,7 @@ extern char **environ; #endif -#ifdef __linux__ +#if defined(__linux__) || defined(__GLIBC__) # include #endif diff --git a/src/unix/tty.c b/src/unix/tty.c index fd4bcbcf8..b2d37f4c2 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -40,7 +40,7 @@ static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; static int uv__tty_is_slave(const int fd) { int result; -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) int dummy; result = ioctl(fd, TIOCGPTN, &dummy) != 0; diff --git a/test/test-embed.c b/test/test-embed.c index 06137456f..c6ddceb14 100644 --- a/test/test-embed.c +++ b/test/test-embed.c @@ -29,6 +29,7 @@ # if defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) # define HAVE_KQUEUE 1 diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 7dd2cb399..fc6e8ad92 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -29,6 +29,7 @@ # 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 848ce88ab..6c1f98b7e 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -594,7 +594,7 @@ TEST_IMPL(poll_unidirectional) { */ TEST_IMPL(poll_bad_fdtype) { #if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \ - !defined(_AIX) && !defined(__MVS__) + !defined(_AIX) && !defined(__MVS__) && !defined(__FreeBSD_kernel__) uv_poll_t poll_handle; int fd; diff --git a/test/test-tty.c b/test/test-tty.c index c93fe75a7..780968c4f 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -28,7 +28,7 @@ #else /* Unix */ # include # include -# if defined(__linux__) && !defined(__ANDROID__) +# if (defined(__linux__) || defined(__GLIBC__)) && !defined(__ANDROID__) # include # elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) # include @@ -260,8 +260,14 @@ TEST_IMPL(tty_file) { } TEST_IMPL(tty_pty) { -# if defined(__linux__) && !defined(__ANDROID__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ - defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) +#if defined(__ANDROID__) || \ + defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__linux__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) int master_fd, slave_fd, r; struct winsize w; uv_loop_t loop; diff --git a/test/test-udp-ipv6.c b/test/test-udp-ipv6.c index 1b0db78b8..a65f09e0c 100644 --- a/test/test-udp-ipv6.c +++ b/test/test-udp-ipv6.c @@ -26,7 +26,7 @@ #include #include -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #endif @@ -47,7 +47,7 @@ static int send_cb_called; static int recv_cb_called; static int close_cb_called; -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) static int can_ipv6_ipv4_dual() { int v6only; size_t size = sizeof(int); @@ -166,7 +166,7 @@ TEST_IMPL(udp_dual_stack) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) if (!can_ipv6_ipv4_dual()) RETURN_SKIP("IPv6-IPv4 dual stack not supported"); #endif diff --git a/test/test-udp-multicast-interface6.c b/test/test-udp-multicast-interface6.c index d3881e83b..40b05536d 100644 --- a/test/test-udp-multicast-interface6.c +++ b/test/test-udp-multicast-interface6.c @@ -72,7 +72,7 @@ TEST_IMPL(udp_multicast_interface6) { r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0); ASSERT(r == 0); -#if defined(__APPLE__) || defined(__FreeBSD__) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 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 26a27d600..2eb9e920e 100644 --- a/test/test-udp-multicast-join6.c +++ b/test/test-udp-multicast-join6.c @@ -119,7 +119,10 @@ TEST_IMPL(udp_multicast_join6) { ASSERT(r == 0); /* join the multicast channel */ -#if defined(__APPLE__) || defined(_AIX) || defined(__MVS__) +#if defined(__APPLE__) || \ + defined(_AIX) || \ + defined(__MVS__) || \ + defined(__FreeBSD_kernel__) r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP); #else r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP); From 841edfcd40fb2243ca434f7b87c0e10d1a40c7c1 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Sun, 21 Aug 2016 13:53:29 -0400 Subject: [PATCH 225/632] zos: use PLO instruction for atomic operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use builtins provided that perform compare and swap operations using the PLO instruction. PR-URL: https://github.com/libuv/libuv/pull/1008 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/atomic-ops.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h index 334c343e8..815e35523 100644 --- a/src/unix/atomic-ops.h +++ b/src/unix/atomic-ops.h @@ -43,9 +43,8 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { __compare_and_swap(ptr, &oldval, newval); return out; #elif defined(__MVS__) - const int out = (*(volatile int*) ptr); - cs((cs_t*)&oldval, (cs_t*)ptr, *(cs_t*)(&newval)); - return out; + return __plo_CS(ptr, (unsigned int*) ptr, + oldval, (unsigned int*) &newval); #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif @@ -68,13 +67,13 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) { # endif /* if defined(__64BIT__) */ return out; #elif defined (__MVS__) - const long out = (*(volatile int*) ptr); # ifdef _LP64 - cds((cds_t*)(&oldval), (cds_t*)ptr, *(cds_t*)(&newval)); + return __plo_CSGR(ptr, (unsigned long long*) ptr, + oldval, (unsigned long long*) &newval); # else - cs((cs_t*)&oldval, (cs_t*)ptr, *(cs_t*)(&newval)); + return __plo_CS(ptr, (unsigned int*) ptr, + oldval, (unsigned int*) &newval); # endif - return out; #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif From 00c0ff149d7a33801853f08dfcb6f175a8b6b576 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Sun, 24 Jul 2016 18:11:18 -0400 Subject: [PATCH 226/632] zos: use pthread helper functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit zOS does not implement some pthread_barrier functions. So we will use the provided helper functions in src/unix/pthread*. PR-URL: https://github.com/libuv/libuv/pull/954 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 2 ++ uv.gyp | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/Makefile.am b/Makefile.am index aab6b0c87..8d5e68b58 100644 --- a/Makefile.am +++ b/Makefile.am @@ -390,6 +390,8 @@ libuv_la_CFLAGS += -D_UNIX03_THREADS \ -qXPLINK \ -qFLOAT=IEEE libuv_la_LDFLAGS += -qXPLINK +libuv_la_SOURCES += src/unix/pthread-fixes.c \ + src/unix/pthread-barrier.c endif if HAVE_PKG_CONFIG diff --git a/uv.gyp b/uv.gyp index 3a480dea0..a2edc9ec9 100644 --- a/uv.gyp +++ b/uv.gyp @@ -302,6 +302,12 @@ ['uv_library=="shared_library"', { 'defines': [ 'BUILDING_UV_SHARED=1' ] }], + ['OS=="zos"', { + 'sources': [ + 'src/unix/pthread-fixes.c', + 'src/unix/pthread-barrier.c' + ] + }], ] }, From 404025721fe13d631c3fb65ddbf54d6263deeaf1 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Mon, 25 Jul 2016 09:14:17 -0400 Subject: [PATCH 227/632] zos: implement uv__fs_futime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do this using __fchattr syscall to change file attributes. PR-URL: https://github.com/libuv/libuv/pull/956 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index 37f8e3b65..216ef9709 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -215,6 +215,14 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { ts[1].tv_sec = req->mtime; ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; return futimens(req->file, ts); +#elif defined(__MVS__) + attrib_t atr; + memset(&atr, 0, sizeof(atr)); + atr.att_mtimechg = 1; + atr.att_atimechg = 1; + atr.att_mtime = req->mtime; + atr.att_atime = req->atime; + return __fchattr(req->file, &atr, sizeof(atr)); #else errno = ENOSYS; return -1; From e37f25d7762ca7f5cc71bf661bc06f405beb7309 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Tue, 19 Jul 2016 08:11:30 -0400 Subject: [PATCH 228/632] unix: expand range of values for usleep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uv_sleep uses only usleep which can only take integers in the range [0,1000000]. Avoid using boundary parameters such as 1000000 for portability reasons. Use sleep and usleep together to expand the acceptable range of values for uv_sleep. PR-URL: https://github.com/libuv/libuv/pull/950 Reviewed-By: Imran Iqbal Reviewed-By: Saúl Ibarra Corretgé --- test/runner-unix.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/runner-unix.c b/test/runner-unix.c index 63f801b59..2ff18ce75 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -386,5 +386,13 @@ void rewind_cursor(void) { /* Pause the calling thread for a number of milliseconds. */ void uv_sleep(int msec) { - usleep(msec * 1000); + int sec; + int usec; + + sec = msec / 1000; + usec = (msec % 1000) * 1000; + if (sec > 0) + sleep(sec); + if (usec > 0) + usleep(usec); } From f4ef8976666db685a22379e76b397ac6aefed900 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Tue, 19 Jul 2016 09:07:28 -0400 Subject: [PATCH 229/632] zos: track unbound handles and bind before listen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On zOS the listen call does not bind automatically if the socket is unbound. Hence the manual binding to an arbitrary port is required to be done manually. PR-URL: https://github.com/libuv/libuv/pull/949 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/internal.h | 3 ++- src/unix/pipe.c | 1 + src/unix/stream.c | 2 ++ src/unix/tcp.c | 23 +++++++++++++++++++++++ src/unix/udp.c | 2 ++ 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/unix/internal.h b/src/unix/internal.h index 7cc8ee8b6..c7b6019ed 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -132,7 +132,8 @@ enum { UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */ UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */ UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */ - UV_UDP_PROCESSING = 0x20000 /* Handle is running the send callback queue. */ + UV_UDP_PROCESSING = 0x20000, /* Handle is running the send callback queue. */ + UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */ }; /* loop flags */ diff --git a/src/unix/pipe.c b/src/unix/pipe.c index a3797ddab..b73994cb8 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -80,6 +80,7 @@ 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->io_watcher.fd = sockfd; return 0; diff --git a/src/unix/stream.c b/src/unix/stream.c index 5dc2f83f4..d20d0bcb3 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -604,6 +604,8 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { return -EINVAL; } + client->flags |= UV_HANDLE_BOUND; + done: /* Process queued fds */ if (server->queued_fds != NULL) { diff --git a/src/unix/tcp.c b/src/unix/tcp.c index fa52a137e..c423dcb15 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -134,6 +134,7 @@ int uv__tcp_bind(uv_tcp_t* tcp, } tcp->delayed_error = -errno; + tcp->flags |= UV_HANDLE_BOUND; if (addr->sa_family == AF_INET6) tcp->flags |= UV_HANDLE_IPV6; @@ -276,10 +277,32 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { if (err) return err; +#ifdef __MVS__ + /* on zOS the listen call does not bind automatically + if the socket is unbound. Hence the manual binding to + an arbitrary port is required to be done manually + */ + + if (!(tcp->flags & UV_HANDLE_BOUND)) { + struct sockaddr_storage saddr; + socklen_t slen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + + if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen)) + return -errno; + + if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen)) + return -errno; + + tcp->flags |= UV_HANDLE_BOUND; + } +#endif + if (listen(tcp->io_watcher.fd, backlog)) return -errno; tcp->connection_cb = cb; + tcp->flags |= UV_HANDLE_BOUND; /* Start listening for connections. */ tcp->io_watcher.cb = uv__server_io; diff --git a/src/unix/udp.c b/src/unix/udp.c index 7c9dae99c..1cd492578 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -335,6 +335,8 @@ int uv__udp_bind(uv_udp_t* handle, if (addr->sa_family == AF_INET6) handle->flags |= UV_HANDLE_IPV6; + handle->flags |= UV_HANDLE_BOUND; + return 0; out: From 282dc7bc227eed61df2c3b657de4be351995e972 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 22 Aug 2016 13:30:52 +0200 Subject: [PATCH 230/632] test: improve tap output on test failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print `errmsg` on TAP output. After making the TAP output the default, the info in `errmsg` was not being used anymore. PR-URL: https://github.com/libuv/libuv/pull/1012 Reviewed-By: Colin Ihrig Reviewed-By: Imran Iqbal Reviewed-By: Saúl Ibarra Corretgé --- test/runner.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/runner.c b/test/runner.c index 5e22c18f2..4f54f85e2 100644 --- a/test/runner.c +++ b/test/runner.c @@ -145,7 +145,7 @@ void log_tap_result(int test_count, int run_test(const char* test, int benchmark_output, int test_count) { - char errmsg[1024] = "no error"; + char errmsg[1024] = ""; process_info_t processes[1024]; process_info_t *main_proc; task_entry_t* task; @@ -274,6 +274,8 @@ 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); From ad20b96a8f258db79f67d7465a7373737e253802 Mon Sep 17 00:00:00 2001 From: Julien Gilli Date: Mon, 22 Aug 2016 10:08:45 -0700 Subject: [PATCH 231/632] test: refactor fs_event_close_in_callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change refactors the `fs_event_close_in_callback` test so that: 1. It creates directory entries instead of modifying them. This allows the test to work on operating systems that use event ports to handle fs events (e.g SmartOS and Solaris). When using event ports, watching only a directory does not allow to receive events for files modified within that directory, but events will be received for files _created_ within that directory. 2. it generates fs events _after_ the process entered the libuv event loop. This is also needed to make the test work on operating systems that use event ports to handle fs events (e.g SmartOS and Solaris), because events are polled as part of running the event loop. That also makes the test work on systems based on Kqueue and on AIX. Fixes: https://github.com/libuv/libuv/pull/808 PR-URL: https://github.com/libuv/libuv/pull/1011 Reviewed-By: Saúl Ibarra Corretgé --- test/test-fs-event.c | 45 +++++++++++--------------------------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index fc6e8ad92..5b7774b6b 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -788,20 +788,6 @@ TEST_IMPL(fs_event_close_with_pending_event) { return 0; } -#if defined(HAVE_KQUEUE) || defined(_AIX) - -/* kqueue doesn't register fs events if you don't have an active watcher. - * The file descriptor needs to be part of the kqueue set of interest and - * that's not the case until we actually enter the event loop. - * This is also observed on AIX with ahafs. - */ -TEST_IMPL(fs_event_close_in_callback) { - fprintf(stderr, "Skipping test, doesn't work with kqueue and AIX.\n"); - return 0; -} - -#else /* !HAVE_KQUEUE || !_AIX */ - static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, int events, int status) { ASSERT(status == 0); @@ -814,7 +800,6 @@ static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, } } - TEST_IMPL(fs_event_close_in_callback) { #if defined(__MVS__) RETURN_SKIP("Filesystem watching not supported on this platform."); @@ -824,44 +809,36 @@ TEST_IMPL(fs_event_close_in_callback) { loop = uv_default_loop(); + fs_event_unlink_files(NULL); create_dir("watch_dir"); - create_file("watch_dir/file1"); - create_file("watch_dir/file2"); - create_file("watch_dir/file3"); - create_file("watch_dir/file4"); - create_file("watch_dir/file5"); r = uv_fs_event_init(loop, &fs_event); ASSERT(r == 0); r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0); ASSERT(r == 0); - /* Generate a couple of fs events. */ - touch_file("watch_dir/file1"); - touch_file("watch_dir/file2"); - touch_file("watch_dir/file3"); - touch_file("watch_dir/file4"); - touch_file("watch_dir/file5"); + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + r = uv_timer_start(&timer, fs_event_create_files, 100, 0); + ASSERT(r == 0); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(close_cb_called == 1); + uv_close((uv_handle_t*)&timer, close_cb); + + uv_run(loop, UV_RUN_ONCE); + + ASSERT(close_cb_called == 2); ASSERT(fs_event_cb_called == 3); /* Clean up */ - remove("watch_dir/file1"); - remove("watch_dir/file2"); - remove("watch_dir/file3"); - remove("watch_dir/file4"); - remove("watch_dir/file5"); + fs_event_unlink_files(NULL); remove("watch_dir/"); MAKE_VALGRIND_HAPPY(); return 0; } -#endif /* HAVE_KQUEUE || _AIX */ - TEST_IMPL(fs_event_start_and_close) { #if defined(__MVS__) RETURN_SKIP("Filesystem watching not supported on this platform."); From 9e641d251fa48c74faabd2b5506f8d972bdb93f3 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Sun, 24 Jul 2016 21:54:08 -0400 Subject: [PATCH 232/632] zos: implement uv__io_check_fd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This method uses the poll syscall to determine whether POLLNVAL is flagged or not. PR-URL: https://github.com/libuv/libuv/pull/957 Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 1 + src/unix/os390.c | 42 ++++++++++++++++++++++++++++++++++++++++++ uv.gyp | 1 + 3 files changed, 44 insertions(+) create mode 100644 src/unix/os390.c diff --git a/Makefile.am b/Makefile.am index 8d5e68b58..adda22185 100644 --- a/Makefile.am +++ b/Makefile.am @@ -392,6 +392,7 @@ libuv_la_CFLAGS += -D_UNIX03_THREADS \ libuv_la_LDFLAGS += -qXPLINK libuv_la_SOURCES += src/unix/pthread-fixes.c \ src/unix/pthread-barrier.c +libuv_la_SOURCES += src/unix/os390.c endif if HAVE_PKG_CONFIG diff --git a/src/unix/os390.c b/src/unix/os390.c new file mode 100644 index 000000000..bcdbc4b6a --- /dev/null +++ b/src/unix/os390.c @@ -0,0 +1,42 @@ +/* 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 "internal.h" + +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct pollfd p[1]; + int rv; + + p[0].fd = fd; + p[0].events = POLLIN; + + do + rv = poll(p, 1, 0); + while (rv == -1 && errno == EINTR); + + if (rv == -1) + abort(); + + if (p[0].revents & POLLNVAL) + return -1; + + return 0; +} diff --git a/uv.gyp b/uv.gyp index a2edc9ec9..4d1a03463 100644 --- a/uv.gyp +++ b/uv.gyp @@ -306,6 +306,7 @@ 'sources': [ 'src/unix/pthread-fixes.c', 'src/unix/pthread-barrier.c' + 'src/unix/os390.c' ] }], ] From afc93d1ed607822f7ae77386f48d7226286d62c0 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Mon, 18 Jul 2016 15:46:55 -0400 Subject: [PATCH 233/632] unix: unneccessary use const qualifier in container_of MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The type parameter in the "container_of(ptr, type, member)" macro which uses builtin "offsetof(type, member)" should not require cv qualifier. Also note that for some platforms, the "offsetof" builtin does not recognize the cv qualifier in the type. PR-URL: https://github.com/libuv/libuv/pull/948 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/timer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/unix/timer.c b/src/unix/timer.c index ca3ec3db9..f46bdf4bf 100644 --- a/src/unix/timer.c +++ b/src/unix/timer.c @@ -31,8 +31,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, const uv_timer_t, heap_node); - b = container_of(hb, const uv_timer_t, heap_node); + a = container_of(ha, uv_timer_t, heap_node); + b = container_of(hb, uv_timer_t, heap_node); if (a->timeout < b->timeout) return 1; @@ -135,7 +135,7 @@ int uv__next_timeout(const uv_loop_t* loop) { if (heap_node == NULL) return -1; /* block indefinitely */ - handle = container_of(heap_node, const uv_timer_t, heap_node); + handle = container_of(heap_node, uv_timer_t, heap_node); if (handle->timeout <= loop->time) return 0; From 58ccfd4c210d3cc1a36dd82474976aac296589f2 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Tue, 17 May 2016 15:46:34 -0400 Subject: [PATCH 234/632] win,tty: add support for ANSI codes in win10 v1511 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/889 Reviewed-By: Saúl Ibarra Corretgé --- src/win/tty.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/win/tty.c b/src/win/tty.c index 9bb7879db..2a58a6f79 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -57,6 +57,9 @@ #define MAX_INPUT_BUFFER_LENGTH 8192 +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); @@ -121,6 +124,14 @@ static char uv_tty_default_fg_bright = 0; static char uv_tty_default_bg_bright = 0; static char uv_tty_default_inverse = 0; +typedef enum { + UV_SUPPORTED, + UV_UNCHECKED, + UV_UNSUPPORTED +} uv_vtermstate_t; +/* Determine whether or not ANSI support is enabled. */ +static vtermstate_t uv__vterm_state = UV_UNCHECKED; +static void uv__determine_vterm_state(HANDLE handle); void uv_console_init() { InitializeCriticalSection(&uv_tty_output_lock); @@ -163,6 +174,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { /* shared between all uv_tty_t handles. */ EnterCriticalSection(&uv_tty_output_lock); + if (uv__vterm_state == UV_UNCHECKED) + uv__determine_vterm_state(handle); + /* Store the global tty output handle. This handle is used by TTY read */ /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */ /* is received. */ @@ -1616,6 +1630,33 @@ static int uv_tty_write_bufs(uv_tty_t* handle, uv_buf_t buf = bufs[i]; unsigned int j; + if (uv__vterm_state == UV_SUPPORTED) { + utf16_buf_used = MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + NULL, + 0); + + if (utf16_buf_used == 0) { + *error = GetLastError(); + break; + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + utf16_buf, + utf16_buf_used)) { + *error = GetLastError(); + break; + } + + FLUSH_TEXT(); + continue; + } + for (j = 0; j < buf.len; j++) { unsigned char c = buf.base[j]; @@ -2173,3 +2214,24 @@ int uv_tty_reset_mode(void) { /* Not necessary to do anything. */ return 0; } + +/* Determine whether or not this version of windows supports + * proper ANSI color codes. Should be supported as of windows + * 10 version 1511, build number 10.0.10586. + */ +static void uv__determine_vterm_state(HANDLE handle) { + DWORD dwMode = 0; + + if (!GetConsoleMode(handle, &dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(handle, dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + uv__vterm_state = UV_SUPPORTED; +} From ee111770068fecb7e3d151cb59c851cddc9bea72 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 26 Aug 2016 00:18:48 +0200 Subject: [PATCH 235/632] doc: add santigimeno to maintainers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1016 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Imran Iqbal Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis --- MAINTAINERS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 5974d9d3f..f2f3db5a1 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -12,6 +12,8 @@ libuv is currently managed by the following individuals: - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny) * **Imran Iqbal** ([@iWuzHere](https://github.com/iWuzHere)) - GPG key: 9DFE AA5F 481B BF77 2D90 03CE D592 4925 2F8E C41A (pubkey-iwuzhere) +* **Santiago Gimeno** ([@santigimeno](https://github.com/santigimeno)) + - 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) From 0895ccfc8ced0c2442c8aab75ccef1f1a6b3938e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 26 Aug 2016 14:49:37 +0100 Subject: [PATCH 236/632] win: fix typo in type name Introduced in 58ccfd4c210d3cc1a36dd82474976aac296589f2, reviewed by yours truly :-( PR-URL: https://github.com/libuv/libuv/pull/1018 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- 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 2a58a6f79..0975b33d9 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -130,7 +130,7 @@ typedef enum { UV_UNSUPPORTED } uv_vtermstate_t; /* Determine whether or not ANSI support is enabled. */ -static vtermstate_t uv__vterm_state = UV_UNCHECKED; +static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED; static void uv__determine_vterm_state(HANDLE handle); void uv_console_init() { From 5d962778349e357e3b14ea92eb7d1844f301da93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sat, 27 Aug 2016 10:25:52 +0200 Subject: [PATCH 237/632] unix: always define pthread barrier fallback pad Fixes: https://github.com/libuv/libuv/issues/1019 PR-URL: https://github.com/libuv/libuv/pull/1020 Reviewed-By: Ben Noordhuis --- include/pthread-barrier.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pthread-barrier.h b/include/pthread-barrier.h index 68468ad2a..3e01705d9 100644 --- a/include/pthread-barrier.h +++ b/include/pthread-barrier.h @@ -39,7 +39,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2 * sizeof(sem_t) + \ 2 * sizeof(unsigned int) - \ sizeof(void *) -#elif defined(__MVS__) +#else # define UV_BARRIER_STRUCT_PADDING 0 #endif From 897738b160cd5950503a96c9fd5b1e9aab92b0ff Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 29 Aug 2016 11:29:28 +0200 Subject: [PATCH 238/632] test: use RETURN_SKIP in spawn_setuid_setgid test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1021 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Imran Iqbal Reviewed-By: Colin Ihrig --- test/test-spawn.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test-spawn.c b/test/test-spawn.c index 0e84ad6de..5df124204 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1230,8 +1230,7 @@ TEST_IMPL(spawn_setuid_setgid) { /* if not root, then this will fail. */ uv_uid_t uid = getuid(); if (uid != 0) { - fprintf(stderr, "spawn_setuid_setgid skipped: not root\n"); - return 0; + RETURN_SKIP("It should be run as root user"); } init_process_options("spawn_helper1", exit_cb); From a7dfee3b02c70ca872c750fc60860d238623be69 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Tue, 30 Aug 2016 15:53:41 -0400 Subject: [PATCH 239/632] win: add disk read/write count to uv_getrusage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs: https://github.com/libuv/libuv/issues/342 PR-URL: https://github.com/libuv/libuv/pull/1023 Reviewed-By: Saúl Ibarra Corretgé --- src/win/util.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/win/util.c b/src/win/util.c index 4a2e50121..050058afa 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1078,6 +1078,7 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { FILETIME createTime, exitTime, kernelTime, userTime; SYSTEMTIME kernelSystemTime, userSystemTime; PROCESS_MEMORY_COUNTERS memCounters; + IO_COUNTERS ioCounters; int ret; ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime); @@ -1102,6 +1103,11 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { return uv_translate_sys_error(GetLastError()); } + ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); + 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 + @@ -1117,6 +1123,9 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; + uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount; + uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount; + return 0; } From 6938f6b0bdbcfd40d7e0cdd3ff298cf46b3dca0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 1 Sep 2016 10:18:47 +0200 Subject: [PATCH 240/632] doc: document uv_fs_realpath caveats Fixes: https://github.com/libuv/libuv/issues/1017 PR-URL: https://github.com/libuv/libuv/pull/1026 Reviewed-By: Colin Ihrig Reviewed-By: Imran Iqbal --- docs/src/fs.rst | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 50c0de468..8e4a98f2d 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -288,7 +288,26 @@ 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 `GetFinalPathNameByHandle `_. + + .. warning:: + This function has certain platform specific caveats that were discovered when used in Node. + + * macOS and other BSDs: this function will fail with UV_ELOOP if more than 32 symlinks are + found while resolving the given path. This limit is hardcoded and cannot be sidestepped. + * Windows: while this function works in the common case, there are a number of corner cases + where it doesn't: + + - Paths in ramdisk volumes created by tools which sidestep the Volume Manager (such as ImDisk) + cannot be resolved. + - Inconsistent casing when using drive letters. + - Resolved path bypasses subst'd drives. + + While this function can still be used, it's not recommended if scenarios such as the + above need to be supported. + + 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. From 4a71e7747a4a2acc888a914033e648e5d8521024 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 30 Aug 2016 23:41:47 +0200 Subject: [PATCH 241/632] test: improve spawn_setuid_setgid test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check that the child process' uid and gid are correctly set. PR-URL: https://github.com/libuv/libuv/pull/1024 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Colin Ihrig --- test/run-tests.c | 13 +++++++++++++ test/test-spawn.c | 12 ++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/test/run-tests.c b/test/run-tests.c index b4be01f6f..1e344f050 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -56,6 +56,7 @@ int main(int argc, char **argv) { case 1: return run_tests(0); case 2: return maybe_run_test(argc, argv); case 3: return run_test_part(argv[1], argv[2]); + case 4: return maybe_run_test(argc, argv); default: fprintf(stderr, "Too many arguments.\n"); fflush(stderr); @@ -177,5 +178,17 @@ static int maybe_run_test(int argc, char **argv) { return spawn_stdin_stdout(); } +#ifndef _WIN32 + if (strcmp(argv[1], "spawn_helper_setuid_setgid") == 0) { + uv_uid_t uid = atoi(argv[2]); + uv_gid_t gid = atoi(argv[3]); + + ASSERT(uid == getuid()); + ASSERT(gid == getgid()); + + return 1; + } +#endif /* !_WIN32 */ + return run_test(argv[1], 0, 1); } diff --git a/test/test-spawn.c b/test/test-spawn.c index 5df124204..53a036969 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -46,7 +46,7 @@ static uv_timer_t timer; static uv_process_options_t options; static char exepath[1024]; static size_t exepath_size = 1024; -static char* args[3]; +static char* args[5]; static int no_term_signal; static int timer_counter; @@ -147,6 +147,8 @@ static void init_process_options(char* test, uv_exit_cb exit_cb) { args[0] = exepath; args[1] = test; args[2] = NULL; + args[3] = NULL; + args[4] = NULL; options.file = exepath; options.args = args; options.exit_cb = exit_cb; @@ -1226,6 +1228,8 @@ TEST_IMPL(spawn_with_an_odd_path) { TEST_IMPL(spawn_setuid_setgid) { int r; struct passwd* pw; + char uidstr[10]; + char gidstr[10]; /* if not root, then this will fail. */ uv_uid_t uid = getuid(); @@ -1233,13 +1237,17 @@ TEST_IMPL(spawn_setuid_setgid) { RETURN_SKIP("It should be run as root user"); } - init_process_options("spawn_helper1", exit_cb); + init_process_options("spawn_helper_setuid_setgid", exit_cb); /* become the "nobody" user. */ pw = getpwnam("nobody"); ASSERT(pw != NULL); options.uid = pw->pw_uid; options.gid = pw->pw_gid; + snprintf(uidstr, sizeof(uidstr), "%d", pw->pw_uid); + snprintf(gidstr, sizeof(gidstr), "%d", pw->pw_gid); + options.args[2] = uidstr; + options.args[3] = gidstr; options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID; r = uv_spawn(uv_default_loop(), &process, &options); From 2112e7a67c390f9b183bf69fa9d49345cc4a32af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 4 Sep 2016 20:46:59 +0200 Subject: [PATCH 242/632] test: fix building pty test on Android Fixes: https://github.com/libuv/libuv/issues/1029 PR-URL: https://github.com/libuv/libuv/pull/1030 Reviewed-By: Ben Noordhuis --- test/test-tty.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/test-tty.c b/test/test-tty.c index 780968c4f..d03f07a44 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -260,13 +260,12 @@ TEST_IMPL(tty_file) { } TEST_IMPL(tty_pty) { -#if defined(__ANDROID__) || \ - defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ - defined(__linux__) || \ - defined(__NetBSD__) || \ +#if defined(__APPLE__) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || \ + (defined(__linux__) && !defined(__ANDROID__)) || \ + defined(__NetBSD__) || \ defined(__OpenBSD__) int master_fd, slave_fd, r; struct winsize w; From f046ebb4092f371f46b6f4edc4e9b109081136a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 7 Sep 2016 09:39:02 +0200 Subject: [PATCH 243/632] doc: uv_buf_t members are not readonly This is probably a reminiscent of the usage in libuv 0.x, where alloc_cb used to return a uv_buf_t. Refs: https://github.com/libuv/libuv/issues/1027#issuecomment-244386298 PR-URL: https://github.com/libuv/libuv/pull/1033 Reviewed-By: Ben Noordhuis Reviewed-By: Fedor Indutny Reviewed-By: Imran Iqbal Reviewed-By: Santiago Gimeno --- docs/src/misc.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 3b7f31aac..d377cc8ed 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -17,11 +17,11 @@ Data types .. c:member:: char* uv_buf_t.base - Pointer to the base of the buffer. Readonly. + Pointer to the base of the buffer. .. c:member:: size_t uv_buf_t.len - Total bytes in the buffer. Readonly. + Total bytes in the buffer. .. note:: On Windows this field is ULONG. From bf0301c33ca7494eb0ac231dfee74e5690cbed3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 7 Sep 2016 09:48:36 +0200 Subject: [PATCH 244/632] doc: improve documentation on uv_alloc_cb Refs: https://github.com/libuv/libuv/issues/1027#issuecomment-244386298 PR-URL: https://github.com/libuv/libuv/pull/1033 Reviewed-By: Ben Noordhuis Reviewed-By: Fedor Indutny Reviewed-By: Imran Iqbal Reviewed-By: Santiago Gimeno --- docs/src/handle.rst | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/src/handle.rst b/docs/src/handle.rst index 6ba597a21..b0a123cf9 100644 --- a/docs/src/handle.rst +++ b/docs/src/handle.rst @@ -24,12 +24,28 @@ Data types .. c:type:: void (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) Type definition for callback passed to :c:func:`uv_read_start` and - :c:func:`uv_udp_recv_start`. The user must fill the supplied :c:type:`uv_buf_t` - structure with whatever size, as long as it's > 0. A suggested size (65536 at the moment) - is provided, but it doesn't need to be honored. Setting the buffer's length to 0 - will trigger a ``UV_ENOBUFS`` error in the :c:type:`uv_udp_recv_cb` or + :c:func:`uv_udp_recv_start`. The user must allocate memory and fill the supplied + :c:type:`uv_buf_t` structure. If NULL is assigned as the buffer's base or 0 as its length, + a ``UV_ENOBUFS`` error will be triggered in the :c:type:`uv_udp_recv_cb` or the :c:type:`uv_read_cb` callback. + A suggested size (65536 at the moment in most cases) is provided, but it's just an indication, + not related in any way to the pending data to be read. The user is free to allocate the amount + of memory they decide. + + As an example, applications with custom allocation schemes such as using freelists, allocation + pools or slab based allocators may decide to use a different size which matches the memory + chunks they already have. + + Example: + + :: + + static void my_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; + } + .. c:type:: void (*uv_close_cb)(uv_handle_t* handle) Type definition for callback passed to :c:func:`uv_close`. From 0d7f72f219d379a6f42ec96ffd8a90493a0d4210 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Thu, 8 Sep 2016 20:16:38 +0200 Subject: [PATCH 245/632] fs: fix uv_fs_fstat on platforms using musl libc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In `musl` libc, defining `_GNU_SOURCE` doesn't automatically define the other feature definitions, causing that `uv_fs_fstat` would not fill the `nsec` fields. For the same reason, compile the tests on linux with `-D_GNU_SOURCE` so the `fs_fstat` tests passes on `musl` platforms. PR-URL: https://github.com/libuv/libuv/pull/1039 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 4 ++++ src/unix/fs.c | 1 + test/test-fs.c | 1 + 3 files changed, 6 insertions(+) diff --git a/Makefile.am b/Makefile.am index adda22185..86500f76c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -284,6 +284,10 @@ if AIX test_run_tests_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT endif +if LINUX +test_run_tests_CFLAGS += -D_GNU_SOURCE +endif + if SUNOS test_run_tests_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 endif diff --git a/src/unix/fs.c b/src/unix/fs.c index 216ef9709..39495e316 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -790,6 +790,7 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_flags = 0; dst->st_gen = 0; #elif !defined(_AIX) && ( \ + defined(_GNU_SOURCE) || \ defined(_BSD_SOURCE) || \ defined(_SVID_SOURCE) || \ defined(_XOPEN_SOURCE) || \ diff --git a/test/test-fs.c b/test/test-fs.c index 7c3c6f209..4249ee723 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1135,6 +1135,7 @@ TEST_IMPL(fs_fstat) { ASSERT(s->st_ctim.tv_sec == t.st_ctime); ASSERT(s->st_ctim.tv_nsec == 0); #elif defined(__sun) || \ + defined(_GNU_SOURCE) || \ defined(_BSD_SOURCE) || \ defined(_SVID_SOURCE) || \ defined(_XOPEN_SOURCE) || \ From 30d852f9e0070c7334a8a5eae7a7b1bc38ad9050 Mon Sep 17 00:00:00 2001 From: Imran Iqbal Date: Thu, 8 Sep 2016 23:22:32 -0400 Subject: [PATCH 246/632] doc: update supported fields for uv_rusage_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/342 PR-URL: https://github.com/libuv/libuv/pull/1041 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Colin Ihrig --- docs/src/misc.rst | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index d377cc8ed..95237f49c 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -69,21 +69,24 @@ Data types uv_timeval_t ru_utime; /* user CPU time used */ uv_timeval_t ru_stime; /* system CPU time used */ uint64_t ru_maxrss; /* maximum resident set size */ - uint64_t ru_ixrss; /* integral shared memory size */ - uint64_t ru_idrss; /* integral unshared data size */ - uint64_t ru_isrss; /* integral unshared stack size */ - uint64_t ru_minflt; /* page reclaims (soft page faults) */ + uint64_t ru_ixrss; /* integral shared memory size (X) */ + uint64_t ru_idrss; /* integral unshared data size (X) */ + uint64_t ru_isrss; /* integral unshared stack size (X) */ + uint64_t ru_minflt; /* page reclaims (soft page faults) (X) */ uint64_t ru_majflt; /* page faults (hard page faults) */ - uint64_t ru_nswap; /* swaps */ + uint64_t ru_nswap; /* swaps (X) */ uint64_t ru_inblock; /* block input operations */ uint64_t ru_oublock; /* block output operations */ - uint64_t ru_msgsnd; /* IPC messages sent */ - uint64_t ru_msgrcv; /* IPC messages received */ - uint64_t ru_nsignals; /* signals received */ - uint64_t ru_nvcsw; /* voluntary context switches */ - uint64_t ru_nivcsw; /* involuntary context switches */ + uint64_t ru_msgsnd; /* IPC messages sent (X) */ + uint64_t ru_msgrcv; /* IPC messages received (X) */ + uint64_t ru_nsignals; /* signals received (X) */ + uint64_t ru_nvcsw; /* voluntary context switches (X) */ + uint64_t ru_nivcsw; /* involuntary context switches (X) */ } uv_rusage_t; + Members marked with `(X)` are unsupported on Windows. + See :man:`getrusage(2)` for supported fields on Unix + .. c:type:: uv_cpu_info_t Data type for CPU information. @@ -205,6 +208,7 @@ API .. note:: 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_cpu_info(uv_cpu_info_t** cpu_infos, int* count) From 6d7d57a983c6054bca2730586f96d809bc64d867 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sat, 3 Sep 2016 14:26:31 +0200 Subject: [PATCH 247/632] test: fix test-tcp-writealot flakiness on arm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Decrease the data sent for `arm` so the test doesn't timeout in the arm CI bots. PR-URL: https://github.com/libuv/libuv/pull/1038 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Colin Ihrig --- 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 6cfe2ebb1..7206fdc2f 100644 --- a/test/test-tcp-writealot.c +++ b/test/test-tcp-writealot.c @@ -26,7 +26,11 @@ #define WRITES 3 +#if defined(__arm__) /* Decrease the chunks so the test passes on arm CI bots */ +#define CHUNKS_PER_WRITE 2048 +#else #define CHUNKS_PER_WRITE 4096 +#endif #define CHUNK_SIZE 10024 /* 10 kb */ #define TOTAL_BYTES (WRITES * CHUNKS_PER_WRITE * CHUNK_SIZE) From 29138058a5a51c6e9e187d1109494d29a948d529 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sun, 4 Sep 2016 23:09:23 +0200 Subject: [PATCH 248/632] test: fix fs_event_watch_dir flakiness on arm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increase the time between file creations, so all the events are emitted. PR-URL: https://github.com/libuv/libuv/pull/1038 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Colin Ihrig --- test/test-fs-event.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index 5b7774b6b..aa4fcf19a 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -36,6 +36,12 @@ # 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; @@ -152,7 +158,10 @@ 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, 1, 0)); + ASSERT(0 == uv_timer_start(&timer, + fs_event_create_files, + CREATE_TIMEOUT, + 0)); } } From e7bc260c4260658517cab4de077e2195c0c7c235 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 12 Sep 2016 13:01:17 +0200 Subject: [PATCH 249/632] unix: don't use alphasort in uv_fs_scandir() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit alphasort() uses strcoll() in some libcs (notably glibc and musl) which makes it locale-sensitive. Replace it with a simple strcmp-based lexicographic comparison for consistent behavior across platforms. Remove the special-casing for OpenBSD. It has been exporting function prototypes conforming to POSIX.1-2008 since OpenBSD 5.3 and that was released more than three years ago. OS X 10.7 is now the only special case left. Fixes: https://github.com/libuv/libuv/issues/1045 PR-URL: https://github.com/libuv/libuv/pull/1046 Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fs.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 39495e316..3d478b790 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -346,22 +346,30 @@ static ssize_t uv__fs_read(uv_fs_t* req) { } -#if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8)) -static int uv__fs_scandir_filter(uv__dirent_t* dent) { +#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8) +#define UV_CONST_DIRENT uv__dirent_t #else -static int uv__fs_scandir_filter(const uv__dirent_t* dent) { +#define UV_CONST_DIRENT const uv__dirent_t #endif + + +static int uv__fs_scandir_filter(UV_CONST_DIRENT* 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) { + return strcmp((*a)->d_name, (*b)->d_name); +} + + static ssize_t uv__fs_scandir(uv_fs_t* req) { uv__dirent_t **dents; int saved_errno; int n; dents = NULL; - n = scandir(req->path, &dents, uv__fs_scandir_filter, alphasort); + n = scandir(req->path, &dents, uv__fs_scandir_filter, uv__fs_scandir_sort); /* NOTE: We will use nbufs as an index field */ req->nbufs = 0; From d38edefc73b2f14d592b6585462a0732deb3ee1e Mon Sep 17 00:00:00 2001 From: Bart Robinson Date: Wed, 14 Sep 2016 11:10:36 -0700 Subject: [PATCH 250/632] doc: fix confusing doc of uv_tcp_nodelay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous description implied enabling nodelay enabled Nagle, but it is the other way around. PR-URL: https://github.com/libuv/libuv/pull/1050 Reviewed-By: Saúl Ibarra Corretgé --- docs/src/tcp.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/tcp.rst b/docs/src/tcp.rst index ca0c9b4ac..a1a582456 100644 --- a/docs/src/tcp.rst +++ b/docs/src/tcp.rst @@ -53,7 +53,7 @@ API .. c:function:: int uv_tcp_nodelay(uv_tcp_t* handle, int enable) - Enable / disable Nagle's algorithm. + Enable `TCP_NODELAY`, which disables Nagle's algorithm. .. c:function:: int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) From 1a96fe33343f82721ba8bc93adb5a67ddcf70ec4 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 13 Sep 2016 20:44:27 +0200 Subject: [PATCH 251/632] build,osx: fix warnings on tests compilation with gyp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add `-Wno-long-long` to `WARNING_CFLAGS`. PR-URL: https://github.com/libuv/libuv/pull/1049 Reviewed-By: Saúl Ibarra Corretgé --- uv.gyp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uv.gyp b/uv.gyp index 4d1a03463..b969a8cd5 100644 --- a/uv.gyp +++ b/uv.gyp @@ -470,6 +470,9 @@ [ 'OS != "zos"', { 'defines': [ '_GNU_SOURCE' ], 'cflags': [ '-Wno-long-long' ], + 'xcode_settings': { + 'WARNING_CFLAGS': [ '-Wno-long-long' ] + } }], ]}, ], From 79e80e0f125b44b1a12b409259d5f01e94dafb89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 15 Sep 2016 10:32:48 +0200 Subject: [PATCH 252/632] doc: add ABI tracker link to README PR-URL: https://github.com/libuv/libuv/pull/1053 Reviewed-By: Colin Ihrig Reviewed-By: Fedor Indutny --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 29b94db12..284dfb47c 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,8 @@ Starting with version 1.0.0 libuv follows the [semantic versioning](http://semve scheme. The API change and backwards compatibility rules are those indicated by SemVer. libuv will keep a stable ABI across major releases. +The ABI/API changes can be tracked [here](http://abi-laboratory.pro/tracker/timeline/libuv/). + ## Licensing libuv is licensed under the MIT license. Check the [LICENSE file](LICENSE). From 84144036ce5f76f39bb042fa4fb45c24aa9473f4 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Thu, 15 Sep 2016 16:16:11 +0200 Subject: [PATCH 253/632] win,tty: fix uv_tty_set_mode race conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Additional synchronization is needed to ensure that the program cannot modify the screen state while a line read is getting cancelled. Also, we need to stop any pending reads *before* calling SetConsoleMode, or a call to ReadConsole could start while the console is still in raw mode. Credit: @orangemocha - Alexis Campailla Fixes: https://github.com/nodejs/node/issues/7837 PR-URL: https://github.com/libuv/libuv/pull/1054 Reviewed-By: Saúl Ibarra Corretgé --- src/win/tty.c | 94 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 37 deletions(-) diff --git a/src/win/tty.c b/src/win/tty.c index 0975b33d9..18d68d094 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -111,7 +111,11 @@ static int uv_tty_virtual_offset = -1; static int uv_tty_virtual_height = -1; static int uv_tty_virtual_width = -1; -static CRITICAL_SECTION uv_tty_output_lock; +/* We use a semaphore rather than a mutex or critical section because in some + cases (uv__cancel_read_console) we need take the lock in the main thread and + release it in another thread. Using a semaphore ensures that in such + scenario the main thread will still block when trying to acquire the lock. */ +static uv_sem_t uv_tty_output_lock; static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE; @@ -134,7 +138,8 @@ static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED; static void uv__determine_vterm_state(HANDLE handle); void uv_console_init() { - InitializeCriticalSection(&uv_tty_output_lock); + if (uv_sem_init(&uv_tty_output_lock, 1)) + abort(); } @@ -172,7 +177,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { /* Obtain the the tty_output_lock because the virtual window state is */ /* shared between all uv_tty_t handles. */ - EnterCriticalSection(&uv_tty_output_lock); + uv_sem_wait(&uv_tty_output_lock); if (uv__vterm_state == UV_UNCHECKED) uv__determine_vterm_state(handle); @@ -187,7 +192,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { uv_tty_update_virtual_window(&screen_buffer_info); - LeaveCriticalSection(&uv_tty_output_lock); + uv_sem_post(&uv_tty_output_lock); } @@ -315,10 +320,6 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { return UV_EINVAL; } - if (!SetConsoleMode(tty->handle, flags)) { - return uv_translate_sys_error(GetLastError()); - } - /* If currently reading, stop, and restart reading. */ if (tty->flags & UV_HANDLE_READING) { was_reading = 1; @@ -332,6 +333,14 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { was_reading = 0; } + uv_sem_wait(&uv_tty_output_lock); + if (!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; @@ -361,9 +370,9 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { return uv_translate_sys_error(GetLastError()); } - EnterCriticalSection(&uv_tty_output_lock); + uv_sem_wait(&uv_tty_output_lock); uv_tty_update_virtual_window(&info); - LeaveCriticalSection(&uv_tty_output_lock); + uv_sem_post(&uv_tty_output_lock); *width = uv_tty_virtual_width; *height = uv_tty_virtual_height; @@ -432,6 +441,7 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { DWORD chars, read_chars; LONG status; COORD pos; + BOOL read_console_success; assert(data); @@ -461,11 +471,13 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { return 0; } - if (ReadConsoleW(handle->handle, - (void*) utf16, - chars, - &read_chars, - NULL)) { + read_console_success = ReadConsoleW(handle->handle, + (void*) utf16, + chars, + &read_chars, + NULL); + + if (read_console_success) { read_bytes = WideCharToMultiByte(CP_UTF8, 0, utf16, @@ -480,33 +492,36 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { SET_REQ_ERROR(req, GetLastError()); } - InterlockedExchange(&uv__read_console_status, COMPLETED); + status = InterlockedExchange(&uv__read_console_status, COMPLETED); - /* If we canceled the read by sending a VK_RETURN event, restore the screen - state to undo the visual effect of the VK_RETURN*/ - if (InterlockedOr(&uv__restore_screen_state, 0)) { - HANDLE active_screen_buffer = CreateFileA("conout$", + if (status == TRAP_REQUESTED) { + /* If we canceled the read by sending a VK_RETURN event, restore the + screen state to undo the visual effect of the VK_RETURN */ + if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) { + HANDLE active_screen_buffer; + active_screen_buffer = CreateFileA("conout$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (active_screen_buffer != INVALID_HANDLE_VALUE) { - pos = uv__saved_screen_state.dwCursorPosition; - - /* If the cursor was at the bottom line of the screen buffer, the - VK_RETURN would have caused the buffer contents to scroll up by - one line. The right position to reset the cursor to is therefore one - line higher */ - if (pos.Y == uv__saved_screen_state.dwSize.Y - 1) - pos.Y--; - - SetConsoleCursorPosition(active_screen_buffer, pos); - CloseHandle(active_screen_buffer); + if (active_screen_buffer != INVALID_HANDLE_VALUE) { + pos = uv__saved_screen_state.dwCursorPosition; + + /* If the cursor was at the bottom line of the screen buffer, the + VK_RETURN would have caused the buffer contents to scroll up by one + line. The right position to reset the cursor to is therefore one line + higher */ + if (pos.Y == uv__saved_screen_state.dwSize.Y - 1) + pos.Y--; + + SetConsoleCursorPosition(active_screen_buffer, pos); + CloseHandle(active_screen_buffer); + } } + uv_sem_post(&uv_tty_output_lock); } - POST_COMPLETION_FOR_REQ(loop, req); return 0; } @@ -694,14 +709,14 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) { CONSOLE_SCREEN_BUFFER_INFO info; - EnterCriticalSection(&uv_tty_output_lock); + uv_sem_wait(&uv_tty_output_lock); if (uv_tty_output_handle != INVALID_HANDLE_VALUE && GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) { uv_tty_update_virtual_window(&info); } - LeaveCriticalSection(&uv_tty_output_lock); + uv_sem_post(&uv_tty_output_lock); continue; } @@ -1035,11 +1050,16 @@ static int uv__cancel_read_console(uv_tty_t* handle) { assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)); + /* Hold the output lock during the cancellation, to ensure that further + writes don't interfere with the screen state. It will be the ReadConsole + thread's responsibility to release the lock. */ + uv_sem_wait(&uv_tty_output_lock); status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED); if (status != IN_PROGRESS) { /* Either we have managed to set a trap for the other thread before ReadConsole is called, or ReadConsole has returned because the user has pressed ENTER. In either case, there is nothing else to do. */ + uv_sem_post(&uv_tty_output_lock); return 0; } @@ -1624,7 +1644,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, /* state. */ *error = ERROR_SUCCESS; - EnterCriticalSection(&uv_tty_output_lock); + uv_sem_wait(&uv_tty_output_lock); for (i = 0; i < nbufs; i++) { uv_buf_t buf = bufs[i]; @@ -2061,7 +2081,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, handle->tty.wr.previous_eol = previous_eol; handle->tty.wr.ansi_parser_state = ansi_parser_state; - LeaveCriticalSection(&uv_tty_output_lock); + uv_sem_post(&uv_tty_output_lock); if (*error == STATUS_SUCCESS) { return 0; From fa81a1b2d760528db46ec655b53f75ec3ef83dc4 Mon Sep 17 00:00:00 2001 From: Vit Gottwald Date: Sat, 17 Sep 2016 11:07:27 +0200 Subject: [PATCH 254/632] test: fix fs_fstat on Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/1051 PR-URL: https://github.com/libuv/libuv/pull/1056 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- test/test-fs.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/test-fs.c b/test/test-fs.c index 4249ee723..74abaf349 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1134,6 +1134,13 @@ TEST_IMPL(fs_fstat) { ASSERT(s->st_mtim.tv_nsec == 0); ASSERT(s->st_ctim.tv_sec == t.st_ctime); ASSERT(s->st_ctim.tv_nsec == 0); +#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); #elif defined(__sun) || \ defined(_GNU_SOURCE) || \ defined(_BSD_SOURCE) || \ From 468d44620a13447e3521ca7a6ad544100e6a0c5e Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Wed, 31 Aug 2016 16:03:49 +0200 Subject: [PATCH 255/632] win, test: fix fs_event_watch_dir_recursive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Under Windows uv_fs_event_start with UV_FS_EVENT_RECURSIVE will report new file creation and file deletion twice - once with the name of the file, and second time with the name of the directory itself. This will filter out callbacks with directory name, making observed callbacks count match expected values. Fixes: https://github.com/libuv/libuv/issues/1009 PR-URL: https://github.com/libuv/libuv/pull/1061 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- test/test-fs-event.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index aa4fcf19a..df8dc4c2f 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -272,6 +272,14 @@ static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle, const char* filename, int events, int status) { +#ifdef _WIN32 + /* Each file created (or deleted) will cause this callback to be called twice + * under Windows: once with the name of the file, and second time with the + * name of the directory. We will ignore the callback for the directory + * itself. */ + if (filename && strcmp(filename, file_prefix_in_subdir) == 0) + return; +#endif fs_event_cb_called++; ASSERT(handle == &fs_event); ASSERT(status == 0); From 20c9c0105be0682843641e671410abaeecd1efff Mon Sep 17 00:00:00 2001 From: Vit Gottwald Date: Sat, 17 Sep 2016 16:40:44 +0200 Subject: [PATCH 256/632] doc: add description of uv_handle_type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/1044 PR-URL: https://github.com/libuv/libuv/pull/1059 Reviewed-By: Saúl Ibarra Corretgé --- docs/src/handle.rst | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/src/handle.rst b/docs/src/handle.rst index b0a123cf9..14aec51ff 100644 --- a/docs/src/handle.rst +++ b/docs/src/handle.rst @@ -17,6 +17,34 @@ Data types The base libuv handle type. +.. c:type:: uv_handle_type + + The kind of the libuv handle. + + :: + + typedef enum { + UV_UNKNOWN_HANDLE = 0, + UV_ASYNC, + UV_CHECK, + UV_FS_EVENT, + UV_FS_POLL, + UV_HANDLE, + UV_IDLE, + UV_NAMED_PIPE, + UV_POLL, + UV_PREPARE, + UV_PROCESS, + UV_STREAM, + UV_TCP, + UV_TIMER, + UV_TTY, + UV_UDP, + UV_SIGNAL, + UV_FILE, + UV_HANDLE_TYPE_MAX + } uv_handle_type; + .. c:type:: uv_any_handle Union of all handle types. @@ -58,6 +86,10 @@ Public members Pointer to the :c:type:`uv_loop_t` where the handle is running on. Readonly. +.. c:member:: uv_loop_t* uv_handle_t.type + + Pointer to the :c:type:`uv_handle_type`. Readonly. + .. c:member:: void* uv_handle_t.data Space for user-defined arbitrary data. libuv does not use this field. From ca107b7f17fdbede154f00b63952eb523b003a4b Mon Sep 17 00:00:00 2001 From: Julien Gilli Date: Wed, 14 Sep 2016 14:42:09 -0700 Subject: [PATCH 257/632] build: use -pthreads for tests with autotools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prevents tests from using non-reentrant implementations of common APIs (e.g `errno`) when using POSIX threads and building with autotools. This is consistent with the way tests are builds when using gyp. The problem was found when investigating tests failures on SmartOS for one test added by https://github.com/libuv/libuv/pull/640. These failures were due to that test using POSIX threads and also using a non-reentrant errno global variable, instead of the reentrant `___errno` function. PR-URL: https://github.com/libuv/libuv/pull/1052 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 86500f76c..c232b6dbd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,7 +36,7 @@ libuv_la_SOURCES = src/fs-poll.c \ 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. -libuv_la_CFLAGS += -pthread +libuv_la_CFLAGS += -pthreads endif if WINNT @@ -134,6 +134,13 @@ test_run_tests_CFLAGS = else test_run_tests_CFLAGS = -Wno-long-long 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. +test_run_tests_CFLAGS += -pthreads +endif + test_run_tests_LDFLAGS = test_run_tests_SOURCES = test/blackhole-server.c \ test/dns-server.c \ From 8221f9b305c09205be575d8d34a5c493ba03d392 Mon Sep 17 00:00:00 2001 From: Jason Ginchereau Date: Fri, 23 Sep 2016 13:18:06 -0700 Subject: [PATCH 258/632] win: fix leaky fs request buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a large number of buffers (>4) is passed into `uv_fs_read()` or `uv_fs_write()`, a new buffer is dynamically allocated to hold a copy of the request data. This change adds code in `uv_fs_req_cleanup()` to free that buffer if it was allocated. Refs: https://github.com/nodejs/node/issues/7191 Fixes: https://github.com/libuv/libuv/issues/1069 PR-URL: https://github.com/libuv/libuv/pull/1070 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/win/fs.c b/src/win/fs.c index 6a4157bfe..f1711acf1 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -230,6 +230,7 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, req->ptr = NULL; req->path = NULL; req->cb = cb; + memset(&req->fs, 0, sizeof(req->fs)); } @@ -1893,9 +1894,13 @@ void uv_fs_req_cleanup(uv_fs_t* req) { uv__free(req->ptr); } + if (req->fs.info.bufs != req->fs.info.bufsml) + uv__free(req->fs.info.bufs); + req->path = NULL; req->file.pathw = NULL; req->fs.info.new_pathw = NULL; + req->fs.info.bufs = NULL; req->ptr = NULL; req->flags |= UV_FS_CLEANEDUP; From 1bcdca290d35bfb7a28f855d88a0e6791679ecc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20=C4=8Cun=C3=A1t?= Date: Thu, 29 Sep 2016 11:15:04 +0200 Subject: [PATCH 259/632] doc: note buffer lifetime requirements in uv_write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/1072 PR-URL: https://github.com/libuv/libuv/pull/1074 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno Reviewed-By: Colin Ihrig --- docs/src/stream.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/src/stream.rst b/docs/src/stream.rst index 7989cd4f8..de492b357 100644 --- a/docs/src/stream.rst +++ b/docs/src/stream.rst @@ -173,6 +173,10 @@ API uv_write(&req1, stream, a, 2, cb); uv_write(&req2, stream, b, 2, cb); + .. note:: + The memory pointed to by the buffers must remain valid until the callback gets called. + This also holds for :c:func:`uv_write2`. + .. c:function:: int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb) Extended write function for sending handles over a pipe. The pipe must be From 8ebecf6eabba00a28aef474d42fdfe51051b0de8 Mon Sep 17 00:00:00 2001 From: Alex Hultman Date: Wed, 5 Oct 2016 13:40:10 +0200 Subject: [PATCH 260/632] doc: add reference to uv_update_time on uv_timer_start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1079 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- docs/src/timer.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/timer.rst b/docs/src/timer.rst index 31d733efc..8e11f257f 100644 --- a/docs/src/timer.rst +++ b/docs/src/timer.rst @@ -42,6 +42,9 @@ API If `repeat` is non-zero, the callback fires first after `timeout` milliseconds and then repeatedly after `repeat` milliseconds. + .. note:: + Does not update the event loop's concept of "now". See :c:func:`uv_update_time` for more information. + .. c:function:: int uv_timer_stop(uv_timer_t* handle) Stop the timer, the callback will not be called anymore. From cfc192212eb671509791331508a8414b346f57e8 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 29 Sep 2016 14:44:48 -0400 Subject: [PATCH 261/632] win: fix winapi function pointer typedef syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the `PASCAL` calling convention marker from: typedef void PASCAL (*f)(...); to the proper place for a calling convention in a function pointer type: typedef void (PASCAL *f)(...); This is where the MS-provided winapi headers place it too. PR-URL: https://github.com/libuv/libuv/pull/1075 Reviewed-By: Saúl Ibarra Corretgé --- include/uv-win.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/uv-win.h b/include/uv-win.h index a75dba8d1..e8b9b15e2 100644 --- a/include/uv-win.h +++ b/include/uv-win.h @@ -116,7 +116,7 @@ typedef struct pollfd { {0xb5367df0, 0xcbac, 0x11cf, \ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} - typedef BOOL PASCAL (*LPFN_ACCEPTEX) + typedef BOOL (PASCAL *LPFN_ACCEPTEX) (SOCKET sListenSocket, SOCKET sAcceptSocket, PVOID lpOutputBuffer, @@ -126,7 +126,7 @@ typedef struct pollfd { LPDWORD lpdwBytesReceived, LPOVERLAPPED lpOverlapped); - typedef BOOL PASCAL (*LPFN_CONNECTEX) + typedef BOOL (PASCAL *LPFN_CONNECTEX) (SOCKET s, const struct sockaddr* name, int namelen, @@ -135,7 +135,7 @@ typedef struct pollfd { LPDWORD lpdwBytesSent, LPOVERLAPPED lpOverlapped); - typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS) + typedef void (PASCAL *LPFN_GETACCEPTEXSOCKADDRS) (PVOID lpOutputBuffer, DWORD dwReceiveDataLength, DWORD dwLocalAddressLength, @@ -145,13 +145,13 @@ typedef struct pollfd { LPSOCKADDR* RemoteSockaddr, LPINT RemoteSockaddrLength); - typedef BOOL PASCAL (*LPFN_DISCONNECTEX) + typedef BOOL (PASCAL *LPFN_DISCONNECTEX) (SOCKET hSocket, LPOVERLAPPED lpOverlapped, DWORD dwFlags, DWORD reserved); - typedef BOOL PASCAL (*LPFN_TRANSMITFILE) + typedef BOOL (PASCAL *LPFN_TRANSMITFILE) (SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, From e58f7535c8e7c318adbf45973008a4f8d81eaed7 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 12 Sep 2016 16:43:35 +0200 Subject: [PATCH 262/632] test: fix tcp_close_while_connecting CI failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The expected error is UV_ECANCELED but the test tries to connect to what is basically an arbitrary address in the expectation that no network path exists, so UV_ENETUNREACH is an equally plausible outcome. This commit undoes the change from commit e994000 ("test: make tcp_close_while_connecting more resilient") because I don't think the connection ever actually succeeds. PR-URL: https://github.com/libuv/libuv/pull/1048 Refs: https://github.com/libuv/libuv/pull/1005 Reviewed-By: Colin Ihrig Reviewed-By: Imran Iqbal Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- test/test-tcp-close-while-connecting.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/test-tcp-close-while-connecting.c b/test/test-tcp-close-while-connecting.c index 90a31f319..8d0b82706 100644 --- a/test/test-tcp-close-while-connecting.c +++ b/test/test-tcp-close-while-connecting.c @@ -29,6 +29,7 @@ static uv_tcp_t tcp_handle; static int connect_cb_called; static int timer1_cb_called; static int close_cb_called; +static int netunreach_errors; static void close_cb(uv_handle_t* handle) { @@ -37,9 +38,15 @@ static void close_cb(uv_handle_t* handle) { static void connect_cb(uv_connect_t* req, int status) { - ASSERT(status == UV_ECANCELED || status == 0); + /* The expected error is UV_ECANCELED but the test tries to connect to what + * is basically an arbitrary address in the expectation that no network path + * exists, so UV_ENETUNREACH is an equally plausible outcome. + */ + ASSERT(status == UV_ECANCELED || status == UV_ENETUNREACH); uv_timer_stop(&timer2_handle); connect_cb_called++; + if (status == UV_ENETUNREACH) + netunreach_errors++; } @@ -82,5 +89,9 @@ TEST_IMPL(tcp_close_while_connecting) { ASSERT(close_cb_called == 2); MAKE_VALGRIND_HAPPY(); + + if (netunreach_errors > 0) + RETURN_SKIP("Network unreachable."); + return 0; } From 39baaa58b70b35b75d7bc15ff266678ebd869c1c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 23 Aug 2016 11:50:58 +0200 Subject: [PATCH 263/632] test: make threadpool_cancel_single deterministic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Saturate the thread pool before trying to post-and-cancel the work request. Before this commit we simply posted requests in a loop, in the (sometimes idle) hope that one would get queued up instead of being dispatched right away. PR-URL: https://github.com/libuv/libuv/pull/1014 Refs: https://github.com/libuv/libuv/pull/1010 Reviewed-By: Saúl Ibarra Corretgé --- test/test-threadpool-cancel.c | 45 ++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index 784c1739f..5a07ebd40 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -37,6 +37,11 @@ struct cancel_info { uv_timer_t timer_handle; }; +struct suspend_req { + uv_work_t req; + uv_sem_t sem; +}; + static uv_cond_t signal_cond; static uv_mutex_t signal_mutex; static uv_mutex_t wait_mutex; @@ -166,12 +171,17 @@ static void timer_cb(uv_timer_t* handle) { } -static void nop_work_cb(uv_work_t* req) { +static void suspend(uv_work_t* req) { + struct suspend_req *s; + + s = container_of(req, struct suspend_req, req); + uv_sem_wait(&s->sem); } static void nop_done_cb(uv_work_t* req, int status) { - req->data = "OK"; + ASSERT(status == UV_ECANCELED); + done_cb_called++; } @@ -330,32 +340,23 @@ TEST_IMPL(threadpool_cancel_fs) { TEST_IMPL(threadpool_cancel_single) { + struct suspend_req s; uv_loop_t* loop; uv_work_t req; - int cancelled; - int i; - loop = uv_default_loop(); - for (i = 0; i < 5000; i++) { - req.data = NULL; - ASSERT(0 == uv_queue_work(loop, &req, nop_work_cb, nop_done_cb)); + putenv("UV_THREADPOOL_SIZE=1"); + ASSERT(0 == uv_sem_init(&s.sem, 0)); - cancelled = uv_cancel((uv_req_t*) &req); - if (cancelled == 0) - break; - - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - } - - if (cancelled != 0) { - fputs("Failed to cancel a work req in 5,000 iterations, giving up.\n", - stderr); - return 1; - } + loop = uv_default_loop(); + ASSERT(0 == uv_queue_work(loop, &s.req, suspend, NULL)); + ASSERT(0 == uv_queue_work(loop, &req, (uv_work_cb) abort, nop_done_cb)); + ASSERT(0 == uv_cancel((uv_req_t*) &req)); - ASSERT(req.data == NULL); + uv_sem_post(&s.sem); + ASSERT(0 == done_cb_called); ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - ASSERT(req.data != NULL); /* Should have been updated by nop_done_cb(). */ + ASSERT(1 == done_cb_called); + uv_sem_destroy(&s.sem); MAKE_VALGRIND_HAPPY(); return 0; From 538782fbdab81116a818c25d18c4df4da58ac18a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 23 Aug 2016 13:15:11 +0200 Subject: [PATCH 264/632] test: make threadpool saturation reliable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a deterministic approach for saturating the threadpool instead of depending on a timeout. Should help reduce the flakiness of the CI. PR-URL: https://github.com/libuv/libuv/pull/1014 Reviewed-By: Saúl Ibarra Corretgé --- test/test-threadpool-cancel.c | 98 +++++++---------------------------- 1 file changed, 20 insertions(+), 78 deletions(-) diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index 5a07ebd40..917f5f475 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -37,82 +37,45 @@ struct cancel_info { uv_timer_t timer_handle; }; -struct suspend_req { - uv_work_t req; - uv_sem_t sem; -}; - -static uv_cond_t signal_cond; -static uv_mutex_t signal_mutex; -static uv_mutex_t wait_mutex; -static unsigned num_threads; static unsigned fs_cb_called; -static unsigned work_cb_called; static unsigned done_cb_called; static unsigned done2_cb_called; static unsigned timer_cb_called; +static uv_work_t pause_reqs[4]; +static uv_sem_t pause_sems[ARRAY_SIZE(pause_reqs)]; static void work_cb(uv_work_t* req) { - uv_mutex_lock(&signal_mutex); - uv_cond_signal(&signal_cond); - uv_mutex_unlock(&signal_mutex); - - uv_mutex_lock(&wait_mutex); - uv_mutex_unlock(&wait_mutex); - - work_cb_called++; + uv_sem_wait(pause_sems + (req - pause_reqs)); } static void done_cb(uv_work_t* req, int status) { - done_cb_called++; - free(req); + uv_sem_destroy(pause_sems + (req - pause_reqs)); } static void saturate_threadpool(void) { - uv_work_t* req; - - ASSERT(0 == uv_cond_init(&signal_cond)); - ASSERT(0 == uv_mutex_init(&signal_mutex)); - ASSERT(0 == uv_mutex_init(&wait_mutex)); - - uv_mutex_lock(&signal_mutex); - uv_mutex_lock(&wait_mutex); - - for (num_threads = 0; /* empty */; num_threads++) { - req = malloc(sizeof(*req)); - ASSERT(req != NULL); - ASSERT(0 == uv_queue_work(uv_default_loop(), req, work_cb, done_cb)); - - /* Expect to get signalled within 350 ms, otherwise assume that - * the thread pool is saturated. As with any timing dependent test, - * this is obviously not ideal. - */ - if (uv_cond_timedwait(&signal_cond, - &signal_mutex, - (uint64_t) (350 * 1e6))) { - ASSERT(0 == uv_cancel((uv_req_t*) req)); - break; - } - } -} + uv_loop_t* loop; + char buf[64]; + size_t i; + snprintf(buf, sizeof(buf), "UV_THREADPOOL_SIZE=%zu", ARRAY_SIZE(pause_reqs)); + putenv(buf); -static void unblock_threadpool(void) { - uv_mutex_unlock(&signal_mutex); - uv_mutex_unlock(&wait_mutex); + 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)); + } } -static void cleanup_threadpool(void) { - ASSERT(done_cb_called == num_threads + 1); /* +1 == cancelled work req. */ - ASSERT(work_cb_called == num_threads); +static void unblock_threadpool(void) { + size_t i; - uv_cond_destroy(&signal_cond); - uv_mutex_destroy(&signal_mutex); - uv_mutex_destroy(&wait_mutex); + for (i = 0; i < ARRAY_SIZE(pause_reqs); i += 1) + uv_sem_post(pause_sems + i); } @@ -171,14 +134,6 @@ static void timer_cb(uv_timer_t* handle) { } -static void suspend(uv_work_t* req) { - struct suspend_req *s; - - s = container_of(req, struct suspend_req, req); - uv_sem_wait(&s->sem); -} - - static void nop_done_cb(uv_work_t* req, int status) { ASSERT(status == UV_ECANCELED); done_cb_called++; @@ -213,8 +168,6 @@ TEST_IMPL(threadpool_cancel_getaddrinfo) { ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(1 == timer_cb_called); - cleanup_threadpool(); - MAKE_VALGRIND_HAPPY(); return 0; } @@ -251,8 +204,6 @@ TEST_IMPL(threadpool_cancel_getnameinfo) { ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(1 == timer_cb_called); - cleanup_threadpool(); - MAKE_VALGRIND_HAPPY(); return 0; } @@ -277,8 +228,6 @@ TEST_IMPL(threadpool_cancel_work) { ASSERT(1 == timer_cb_called); ASSERT(ARRAY_SIZE(reqs) == done2_cb_called); - cleanup_threadpool(); - MAKE_VALGRIND_HAPPY(); return 0; } @@ -332,7 +281,6 @@ TEST_IMPL(threadpool_cancel_fs) { ASSERT(n == fs_cb_called); ASSERT(1 == timer_cb_called); - cleanup_threadpool(); MAKE_VALGRIND_HAPPY(); return 0; @@ -340,23 +288,17 @@ TEST_IMPL(threadpool_cancel_fs) { TEST_IMPL(threadpool_cancel_single) { - struct suspend_req s; uv_loop_t* loop; uv_work_t req; - putenv("UV_THREADPOOL_SIZE=1"); - ASSERT(0 == uv_sem_init(&s.sem, 0)); - + saturate_threadpool(); loop = uv_default_loop(); - ASSERT(0 == uv_queue_work(loop, &s.req, suspend, NULL)); ASSERT(0 == uv_queue_work(loop, &req, (uv_work_cb) abort, nop_done_cb)); ASSERT(0 == uv_cancel((uv_req_t*) &req)); - - uv_sem_post(&s.sem); ASSERT(0 == done_cb_called); + unblock_threadpool(); ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); ASSERT(1 == done_cb_called); - uv_sem_destroy(&s.sem); MAKE_VALGRIND_HAPPY(); return 0; From 3064ae98e5c3cee223f9e229ff20f86cb1b06b8b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 14 Oct 2016 09:59:39 +0200 Subject: [PATCH 265/632] unix: don't malloc in uv_thread_create() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify and optimize uv_thread_create() by casting the function pointer to the prototype that pthread_create() wants. Avoids the indirection of an intermediate callback and heap-allocating custom state that is really only there to placate the compiler. PR-URL: https://github.com/libuv/libuv/pull/1094 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/thread.c | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/src/unix/thread.c b/src/unix/thread.c index 52989f7f0..a9b5e4c02 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -40,28 +40,8 @@ #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) -struct thread_ctx { - void (*entry)(void* arg); - void* arg; -}; - - -static void* uv__thread_start(void *arg) -{ - struct thread_ctx *ctx_p; - struct thread_ctx ctx; - - ctx_p = arg; - ctx = *ctx_p; - uv__free(ctx_p); - ctx.entry(ctx.arg); - - return 0; -} - int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { - struct thread_ctx* ctx; int err; pthread_attr_t* attr; #if defined(__APPLE__) @@ -69,13 +49,6 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { struct rlimit lim; #endif - ctx = uv__malloc(sizeof(*ctx)); - if (ctx == NULL) - return UV_ENOMEM; - - ctx->entry = entry; - ctx->arg = arg; - /* On OSX threads other than the main thread are created with a reduced stack * size by default, adjust it to RLIMIT_STACK. */ @@ -99,14 +72,11 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { attr = NULL; #endif - err = pthread_create(tid, attr, uv__thread_start, ctx); + err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg); if (attr != NULL) pthread_attr_destroy(attr); - if (err) - uv__free(ctx); - return -err; } From 6b35ca86161a10cff7a5dee0a3042a5bd21b3bf3 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 29 Sep 2016 14:54:53 -0400 Subject: [PATCH 266/632] unix: don't include CoreServices globally on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In unix/internal.h, CoreServices is included for AvailabilityMacros.h. This commit just includes AvailabilityMacros.h directly instead. PR-URL: https://github.com/libuv/libuv/pull/1092 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- 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 c7b6019ed..ee76c837c 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -52,7 +52,7 @@ #endif /* _AIX */ #if defined(__APPLE__) && !TARGET_OS_IPHONE -# include +# include #endif #if defined(__ANDROID__) From f1863dae6bb27e31644307cf0905d42bd41251c9 Mon Sep 17 00:00:00 2001 From: Philippe Laferriere Date: Sun, 18 Sep 2016 15:18:48 -0400 Subject: [PATCH 267/632] unix,win: add uv_translate_sys_error() public API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uv_translate_sys_error() was a private function for Windows. This commit adds an equivalent function on other platforms, and exposes it as public API. Exposing this is useful in scenarios where the application uses both libuv functions and platform-specific system calls and wants to report errors uniformly as libuv errors. Fixes: https://github.com/libuv/libuv/issues/79 PR-URL: https://github.com/libuv/libuv/pull/1060 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- docs/src/errors.rst | 10 ++++++++++ include/uv.h | 2 ++ src/unix/core.c | 6 ++++++ test/test-error.c | 19 +++++++++++++++++++ test/test-list.h | 2 ++ 5 files changed, 39 insertions(+) diff --git a/docs/src/errors.rst b/docs/src/errors.rst index 2ebaf1e41..4e30447bf 100644 --- a/docs/src/errors.rst +++ b/docs/src/errors.rst @@ -332,3 +332,13 @@ API Returns the error name for the given error code. Leaks a few bytes of memory when you call it with an unknown error code. + +.. c:function:: int uv_translate_sys_error(int sys_errno) + + Returns the libuv error code equivalent to the given platform dependent error + code: POSIX error codes on Unix (the ones stored in `errno`), and Win32 error + codes on Windows (those returned by `GetLastError()` or `WSAGetLastError()`). + + If `sys_errno` is already a libuv error, it is simply returned. + + .. versionchanged:: 1.10.0 function declared public. diff --git a/include/uv.h b/include/uv.h index baa0b2812..31f09f0f6 100644 --- a/include/uv.h +++ b/include/uv.h @@ -363,6 +363,8 @@ typedef enum { } uv_membership; +UV_EXTERN int uv_translate_sys_error(int sys_errno); + UV_EXTERN const char* uv_strerror(int err); UV_EXTERN const char* uv_err_name(int err); diff --git a/src/unix/core.c b/src/unix/core.c index d88fc1de8..a2c07e6a4 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1236,3 +1236,9 @@ void uv_os_free_passwd(uv_passwd_t* pwd) { int uv_os_get_passwd(uv_passwd_t* pwd) { return uv__getpwuid_r(pwd); } + + +int uv_translate_sys_error(int sys_errno) { + /* If < 0 then it's already a libuv error. */ + return sys_errno <= 0 ? sys_errno : -sys_errno; +} diff --git a/test/test-error.c b/test/test-error.c index eb337e66f..4c4efa30c 100644 --- a/test/test-error.c +++ b/test/test-error.c @@ -48,3 +48,22 @@ TEST_IMPL(error_message) { return 0; } + + +TEST_IMPL(sys_error) { +#if defined(_WIN32) + ASSERT(uv_translate_sys_error(ERROR_NOACCESS) == UV_EACCES); + ASSERT(uv_translate_sys_error(WSAEADDRINUSE) == UV_EADDRINUSE); + ASSERT(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); +#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); + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 2f19b3279..08886a6f4 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -152,6 +152,7 @@ TEST_DECLARE (shutdown_eof) TEST_DECLARE (shutdown_twice) TEST_DECLARE (callback_stack) TEST_DECLARE (error_message) +TEST_DECLARE (sys_error) TEST_DECLARE (timer) TEST_DECLARE (timer_init) TEST_DECLARE (timer_again) @@ -542,6 +543,7 @@ TASK_LIST_START TEST_HELPER (callback_stack, tcp4_echo_server) TEST_ENTRY (error_message) + TEST_ENTRY (sys_error) TEST_ENTRY (timer) TEST_ENTRY (timer_init) From d00de9321b698e2074919b638d0a2ee087077a64 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 14 Oct 2016 12:43:02 +0200 Subject: [PATCH 268/632] win: remove unused static variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit default_loop_struct and default_loop_ptr seem to have been overlooked in commit 32747c7 ("win,unix: move loop functions which have identical implementations".) PR-URL: https://github.com/libuv/libuv/pull/1097 Reviewed-By: Andrius Bentkus Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/win/core.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/win/core.c b/src/win/core.c index 9d00afc6b..e84186d4e 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -35,10 +35,6 @@ #include "handle-inl.h" #include "req-inl.h" - -static uv_loop_t default_loop_struct; -static uv_loop_t* default_loop_ptr; - /* uv_once initialization guards */ static uv_once_t uv_init_guard_ = UV_ONCE_INIT; From d5db2773777d1002792ff9c807000e55c00c7611 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 14 Oct 2016 12:45:15 +0200 Subject: [PATCH 269/632] win: silence -Wmaybe-uninitialized warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The compiler is wrong about it being used uninitialized but the warning is sufficiently annoying that I decided to squelch it. PR-URL: https://github.com/libuv/libuv/pull/1097 Reviewed-By: Andrius Bentkus Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- 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 f1711acf1..dc0ac89a3 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -123,7 +123,7 @@ 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, pathw_len = 0, new_pathw_len = 0; + ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0; /* new_path can only be set if path is also set. */ assert(new_path == NULL || path != NULL); From 31e5d665d5f17c701c0fc7bdc0fc95bd177b460d Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sun, 16 Oct 2016 19:02:50 +0200 Subject: [PATCH 270/632] signal: replace pthread_once with uv_once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So it aborts in case `pthread_once` fails. PR-URL: https://github.com/libuv/libuv/pull/1098 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/signal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/signal.c b/src/unix/signal.c index d82b9b7cf..ccc1847aa 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -43,7 +43,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2); static void uv__signal_stop(uv_signal_t* handle); -static pthread_once_t uv__signal_global_init_guard = PTHREAD_ONCE_INIT; +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]; @@ -64,7 +64,7 @@ static void uv__signal_global_init(void) { void uv__signal_global_once_init(void) { - pthread_once(&uv__signal_global_init_guard, uv__signal_global_init); + uv_once(&uv__signal_global_init_guard, uv__signal_global_init); } From a35308306fc9614407194fd294fdc130c98b53a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 16 Oct 2016 10:46:54 +0200 Subject: [PATCH 271/632] unix,win: simplify calculating polling timeout PR-URL: https://github.com/libuv/libuv/pull/1096 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- src/unix/core.c | 5 +---- src/win/core.c | 9 +++------ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index a2c07e6a4..e8e256d9f 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -301,7 +301,7 @@ 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)) + if (!uv_loop_alive(loop)) return 0; if (!QUEUE_EMPTY(&loop->idle_handles)) @@ -310,9 +310,6 @@ int uv_backend_timeout(const uv_loop_t* loop) { if (!QUEUE_EMPTY(&loop->pending_queue)) return 0; - if (loop->closing_handles) - return 0; - return uv__next_timeout(loop); } diff --git a/src/win/core.c b/src/win/core.c index e84186d4e..d9c57a42c 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -336,15 +336,12 @@ 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)) + if (!uv_loop_alive(loop)) return 0; if (loop->pending_reqs_tail) return 0; - if (loop->endgame_handles) - return 0; - if (loop->idle_handles) return 0; @@ -463,8 +460,8 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { static int uv__loop_alive(const uv_loop_t* loop) { - return loop->active_handles > 0 || - !QUEUE_EMPTY(&loop->active_reqs) || + return uv__has_active_handles(loop) || + uv__has_active_reqs(loop) || loop->endgame_handles != NULL; } From cded27b663f65e90dd214390b2919e209ec6da52 Mon Sep 17 00:00:00 2001 From: Will Speak Date: Fri, 14 Oct 2016 07:53:15 +0100 Subject: [PATCH 272/632] test: fix sign-compare warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1089 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- 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 74abaf349..06718f285 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2631,7 +2631,7 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) { r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, offset, NULL); ASSERT(r >= 0); - ASSERT(read_req.result == sizeof(test_buf) * iovcount); + ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount); for (index = 0; index < iovcount; ++index) ASSERT(strncmp(buffer + index * sizeof(test_buf), From 0d586b7dd856f2088b477e58be5d481723fc105b Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 29 Sep 2016 14:57:01 -0400 Subject: [PATCH 273/632] common: fix unused variable warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The saved_data variable in uv_loop_close() is only used when NDEBUG is defined. This commit makes the variable declaration depend on NDEBUG as well. PR-URL: https://github.com/libuv/libuv/pull/1093 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/uv-common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/uv-common.c b/src/uv-common.c index 434a5029c..46d954673 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -613,7 +613,9 @@ uv_loop_t* uv_loop_new(void) { int uv_loop_close(uv_loop_t* loop) { QUEUE* q; uv_handle_t* h; +#ifndef NDEBUG void* saved_data; +#endif if (!QUEUE_EMPTY(&(loop)->active_reqs)) return UV_EBUSY; From b2e13b9f006bdc622018672d3ca33f49e60630e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 21 Oct 2016 10:08:06 -0300 Subject: [PATCH 274/632] Revert "unix,win: simplify calculating polling timeout" This reverts commit a35308306fc9614407194fd294fdc130c98b53a5. The original commit introduced unforeseen regressions. See https://github.com/libuv/libuv/pull/1096. Fixes: https://github.com/libuv/libuv/pull/1096 PR-URL: https://github.com/libuv/libuv/pull/1102 Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis --- src/unix/core.c | 5 ++++- src/win/core.c | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index e8e256d9f..a2c07e6a4 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -301,7 +301,7 @@ int uv_backend_timeout(const uv_loop_t* loop) { if (loop->stop_flag != 0) return 0; - if (!uv_loop_alive(loop)) + if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) return 0; if (!QUEUE_EMPTY(&loop->idle_handles)) @@ -310,6 +310,9 @@ int uv_backend_timeout(const uv_loop_t* loop) { if (!QUEUE_EMPTY(&loop->pending_queue)) return 0; + if (loop->closing_handles) + return 0; + return uv__next_timeout(loop); } diff --git a/src/win/core.c b/src/win/core.c index d9c57a42c..e84186d4e 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -336,12 +336,15 @@ int uv_backend_timeout(const uv_loop_t* loop) { if (loop->stop_flag != 0) return 0; - if (!uv_loop_alive(loop)) + if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) return 0; if (loop->pending_reqs_tail) return 0; + if (loop->endgame_handles) + return 0; + if (loop->idle_handles) return 0; @@ -460,8 +463,8 @@ static void uv_poll_ex(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) || + return loop->active_handles > 0 || + !QUEUE_EMPTY(&loop->active_reqs) || loop->endgame_handles != NULL; } From c8a373c729b4c9392e0e14fc53cd6b67b3051ab9 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 24 Oct 2016 09:52:33 -0400 Subject: [PATCH 275/632] 2016.10.25, Version 1.10.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.9.1: * Now working on version 1.9.2 (Saúl Ibarra Corretgé) * doc: add cjihrig GPG ID (cjihrig) * win,build: fix compilation on old Windows / MSVC (Saúl Ibarra Corretgé) * darwin: fix setting fd to non-blocking in select(() trick (Saúl Ibarra Corretgé) * unix: allow nesting of kqueue fds in uv_poll_start (Ben Noordhuis) * doc: fix generation the first time livehtml runs (Saúl Ibarra Corretgé) * test: fix test_close_accept flakiness on Centos5 (Santiago Gimeno) * license: libuv is no longer a Node project (Saúl Ibarra Corretgé) * license: add license text we've been using for a while (Saúl Ibarra Corretgé) * doc: add licensing information to README (Saúl Ibarra Corretgé) * win,pipe: fixed formatting, DWORD is long unsigned (Miodrag Milanovic) * win: support sub-second precision in uv_fs_futimes() (Jason Ginchereau) * unix: ignore EINPROGRESS in uv__close (Saúl Ibarra Corretgé) * doc: add Imran Iqbal (iWuzHere) to maintainers (Imran Iqbal) * doc: update docs with AIX related information (Imran Iqbal) * test: silence build warnings (Kári Tristan Helgason) * doc: add iWuzHere GPG ID (Imran Iqbal) * linux-core: fix uv_get_total/free_memory on uclibc (Nicolas Cavallari) * build: fix build on DragonFly (Michael Neumann) * unix: correctly detect named pipes on DragonFly (Michael Neumann) * test: make tap output the default (Ben Noordhuis) * test: don't dump output for skipped tests (Ben Noordhuis) * test: improve formatting of diagnostic messages (Ben Noordhuis) * test: remove unused RETURN_TODO macro (Ben Noordhuis) * doc: fix stream typos (Pierre-Marie de Rodat) * doc: update coding style link (Imran Iqbal) * unix,fs: use uint64_t instead of unsigned long (Imran Iqbal) * build: check for warnings for -fvisibility=hidden (Imran Iqbal) * unix: remove unneeded TODO note (Saúl Ibarra Corretgé) * test: skip tty_pty test if pty is not available (Luca Bruno) * sunos: set phys_addr of interface_address using ARP (Brian Maher) * doc: clarify callbacks won't be called in error case (Saúl Ibarra Corretgé) * unix: don't convert stat buffer when syscall fails (Ben Noordhuis) * win: compare entire filename in watch events (cjihrig) * doc: add a note on safe reuse of uv_write_t (neevek) * linux: fix potential event loop stall (Ben Noordhuis) * unix,win: make uv_get_process_title() stricter (cjihrig) * test: close server before initiating new connection (John Barboza) * test: account for multiple handles in one ipc read (John Barboza) * unix: fix errno and retval conflict (liuxiaobo) * doc: add missing entry in uv_fs_type enum (Michele Caini) * unix: preserve loop->data across loop init/done (Ben Noordhuis) * win: return UV_EINVAL on bad uv_tty_mode mode arg (Ben Noordhuis) * win: simplify memory copy logic in fs.c (Ben Noordhuis) * win: fix compilation on mingw (Bartosz Sosnowski) * win: ensure 32-bit printf precision (Matej Knopp) * darwin: handle EINTR in /dev/tty workaround (Ben Noordhuis) * test: fix OOB buffer access (Saúl Ibarra Corretgé) * test: don't close CRT fd handed off to uv_pipe_t (Saúl Ibarra Corretgé) * test: fix android build error. (sunjin.lee) * win: evaluate timers when system wakes up (Bartosz Sosnowski) * doc: add supported platforms description (Saúl Ibarra Corretgé) * win: fix lstat reparse point without link data (Jason Ginchereau) * unix,win: make on_alloc_cb failures more resilient (Saúl Ibarra Corretgé) * zos: add support for new platform (John Barboza) * test: make tcp_close_while_connecting more resilient (Saúl Ibarra Corretgé) * build: use '${prefix}' for pkg-config 'exec_prefix' (Matt Clarkson) * build: GNU/kFreeBSD support (Jeffrey Clark) * zos: use PLO instruction for atomic operations (John Barboza) * zos: use pthread helper functions (John Barboza) * zos: implement uv__fs_futime (John Barboza) * unix: expand range of values for usleep (John Barboza) * zos: track unbound handles and bind before listen (John Barboza) * test: improve tap output on test failures (Santiago Gimeno) * test: refactor fs_event_close_in_callback (Julien Gilli) * zos: implement uv__io_check_fd (John Barboza) * unix: unneccessary use const qualifier in container_of (John Barboza) * win,tty: add support for ANSI codes in win10 v1511 (Imran Iqbal) * doc: add santigimeno to maintainers (Santiago Gimeno) * win: fix typo in type name (Saúl Ibarra Corretgé) * unix: always define pthread barrier fallback pad (Saúl Ibarra Corretgé) * test: use RETURN_SKIP in spawn_setuid_setgid test (Santiago Gimeno) * win: add disk read/write count to uv_getrusage (Imran Iqbal) * doc: document uv_fs_realpath caveats (Saúl Ibarra Corretgé) * test: improve spawn_setuid_setgid test (Santiago Gimeno) * test: fix building pty test on Android (Saúl Ibarra Corretgé) * doc: uv_buf_t members are not readonly (Saúl Ibarra Corretgé) * doc: improve documentation on uv_alloc_cb (Saúl Ibarra Corretgé) * fs: fix uv_fs_fstat on platforms using musl libc (Santiago Gimeno) * doc: update supported fields for uv_rusage_t (Imran Iqbal) * test: fix test-tcp-writealot flakiness on arm (Santiago Gimeno) * test: fix fs_event_watch_dir flakiness on arm (Santiago Gimeno) * unix: don't use alphasort in uv_fs_scandir() (Ben Noordhuis) * doc: fix confusing doc of uv_tcp_nodelay (Bart Robinson) * build,osx: fix warnings on tests compilation with gyp (Santiago Gimeno) * doc: add ABI tracker link to README (Saúl Ibarra Corretgé) * win,tty: fix uv_tty_set_mode race conditions (Bartosz Sosnowski) * test: fix fs_fstat on Android (Vit Gottwald) * win, test: fix fs_event_watch_dir_recursive (Bartosz Sosnowski) * doc: add description of uv_handle_type (Vit Gottwald) * build: use -pthreads for tests with autotools (Julien Gilli) * win: fix leaky fs request buffer (Jason Ginchereau) * doc: note buffer lifetime requirements in uv_write (Vladimír Čunát) * doc: add reference to uv_update_time on uv_timer_start (Alex Hultman) * win: fix winapi function pointer typedef syntax (Brad King) * test: fix tcp_close_while_connecting CI failures (Ben Noordhuis) * test: make threadpool_cancel_single deterministic (Ben Noordhuis) * test: make threadpool saturation reliable (Ben Noordhuis) * unix: don't malloc in uv_thread_create() (Ben Noordhuis) * unix: don't include CoreServices globally on macOS (Brad King) * unix,win: add uv_translate_sys_error() public API (Philippe Laferriere) * win: remove unused static variables (Ben Noordhuis) * win: silence -Wmaybe-uninitialized warning (Ben Noordhuis) * signal: replace pthread_once with uv_once (Santiago Gimeno) * test: fix sign-compare warning (Will Speak) * common: fix unused variable warning (Brad King) --- AUTHORS | 20 ++++ ChangeLog | 218 +++++++++++++++++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 8 +- 5 files changed, 244 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7acee7c53..67aa17620 100644 --- a/AUTHORS +++ b/AUTHORS @@ -257,3 +257,23 @@ Michael Fero Robert Jefe Lindstaedt Myles Borins Tony Theodore +Jason Ginchereau +Nicolas Cavallari +Pierre-Marie de Rodat +Brian Maher +neevek +John Barboza +liuxiaobo +Michele Caini +Bartosz Sosnowski +Matej Knopp +sunjin.lee +Matt Clarkson +Jeffrey Clark +Bart Robinson +Vit Gottwald +Vladimír Čunát +Alex Hultman +Brad King +Philippe Laferriere +Will Speak diff --git a/ChangeLog b/ChangeLog index 3f376de6b..8c6675967 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,221 @@ +2016.10.25, Version 1.10.0 (Stable) + +Changes since version 1.9.1: + +* Now working on version 1.9.2 (Saúl Ibarra Corretgé) + +* doc: add cjihrig GPG ID (cjihrig) + +* win,build: fix compilation on old Windows / MSVC (Saúl Ibarra Corretgé) + +* darwin: fix setting fd to non-blocking in select(() trick (Saúl Ibarra + Corretgé) + +* unix: allow nesting of kqueue fds in uv_poll_start (Ben Noordhuis) + +* doc: fix generation the first time livehtml runs (Saúl Ibarra Corretgé) + +* test: fix test_close_accept flakiness on Centos5 (Santiago Gimeno) + +* license: libuv is no longer a Node project (Saúl Ibarra Corretgé) + +* license: add license text we've been using for a while (Saúl Ibarra Corretgé) + +* doc: add licensing information to README (Saúl Ibarra Corretgé) + +* win,pipe: fixed formatting, DWORD is long unsigned (Miodrag Milanovic) + +* win: support sub-second precision in uv_fs_futimes() (Jason Ginchereau) + +* unix: ignore EINPROGRESS in uv__close (Saúl Ibarra Corretgé) + +* doc: add Imran Iqbal (iWuzHere) to maintainers (Imran Iqbal) + +* doc: update docs with AIX related information (Imran Iqbal) + +* test: silence build warnings (Kári Tristan Helgason) + +* doc: add iWuzHere GPG ID (Imran Iqbal) + +* linux-core: fix uv_get_total/free_memory on uclibc (Nicolas Cavallari) + +* build: fix build on DragonFly (Michael Neumann) + +* unix: correctly detect named pipes on DragonFly (Michael Neumann) + +* test: make tap output the default (Ben Noordhuis) + +* test: don't dump output for skipped tests (Ben Noordhuis) + +* test: improve formatting of diagnostic messages (Ben Noordhuis) + +* test: remove unused RETURN_TODO macro (Ben Noordhuis) + +* doc: fix stream typos (Pierre-Marie de Rodat) + +* doc: update coding style link (Imran Iqbal) + +* unix,fs: use uint64_t instead of unsigned long (Imran Iqbal) + +* build: check for warnings for -fvisibility=hidden (Imran Iqbal) + +* unix: remove unneeded TODO note (Saúl Ibarra Corretgé) + +* test: skip tty_pty test if pty is not available (Luca Bruno) + +* sunos: set phys_addr of interface_address using ARP (Brian Maher) + +* doc: clarify callbacks won't be called in error case (Saúl Ibarra Corretgé) + +* unix: don't convert stat buffer when syscall fails (Ben Noordhuis) + +* win: compare entire filename in watch events (cjihrig) + +* doc: add a note on safe reuse of uv_write_t (neevek) + +* linux: fix potential event loop stall (Ben Noordhuis) + +* unix,win: make uv_get_process_title() stricter (cjihrig) + +* test: close server before initiating new connection (John Barboza) + +* test: account for multiple handles in one ipc read (John Barboza) + +* unix: fix errno and retval conflict (liuxiaobo) + +* doc: add missing entry in uv_fs_type enum (Michele Caini) + +* unix: preserve loop->data across loop init/done (Ben Noordhuis) + +* win: return UV_EINVAL on bad uv_tty_mode mode arg (Ben Noordhuis) + +* win: simplify memory copy logic in fs.c (Ben Noordhuis) + +* win: fix compilation on mingw (Bartosz Sosnowski) + +* win: ensure 32-bit printf precision (Matej Knopp) + +* darwin: handle EINTR in /dev/tty workaround (Ben Noordhuis) + +* test: fix OOB buffer access (Saúl Ibarra Corretgé) + +* test: don't close CRT fd handed off to uv_pipe_t (Saúl Ibarra Corretgé) + +* test: fix android build error. (sunjin.lee) + +* win: evaluate timers when system wakes up (Bartosz Sosnowski) + +* doc: add supported platforms description (Saúl Ibarra Corretgé) + +* win: fix lstat reparse point without link data (Jason Ginchereau) + +* unix,win: make on_alloc_cb failures more resilient (Saúl Ibarra Corretgé) + +* zos: add support for new platform (John Barboza) + +* test: make tcp_close_while_connecting more resilient (Saúl Ibarra Corretgé) + +* build: use '${prefix}' for pkg-config 'exec_prefix' (Matt Clarkson) + +* build: GNU/kFreeBSD support (Jeffrey Clark) + +* zos: use PLO instruction for atomic operations (John Barboza) + +* zos: use pthread helper functions (John Barboza) + +* zos: implement uv__fs_futime (John Barboza) + +* unix: expand range of values for usleep (John Barboza) + +* zos: track unbound handles and bind before listen (John Barboza) + +* test: improve tap output on test failures (Santiago Gimeno) + +* test: refactor fs_event_close_in_callback (Julien Gilli) + +* zos: implement uv__io_check_fd (John Barboza) + +* unix: unneccessary use const qualifier in container_of (John Barboza) + +* win,tty: add support for ANSI codes in win10 v1511 (Imran Iqbal) + +* doc: add santigimeno to maintainers (Santiago Gimeno) + +* win: fix typo in type name (Saúl Ibarra Corretgé) + +* unix: always define pthread barrier fallback pad (Saúl Ibarra Corretgé) + +* test: use RETURN_SKIP in spawn_setuid_setgid test (Santiago Gimeno) + +* win: add disk read/write count to uv_getrusage (Imran Iqbal) + +* doc: document uv_fs_realpath caveats (Saúl Ibarra Corretgé) + +* test: improve spawn_setuid_setgid test (Santiago Gimeno) + +* test: fix building pty test on Android (Saúl Ibarra Corretgé) + +* doc: uv_buf_t members are not readonly (Saúl Ibarra Corretgé) + +* doc: improve documentation on uv_alloc_cb (Saúl Ibarra Corretgé) + +* fs: fix uv_fs_fstat on platforms using musl libc (Santiago Gimeno) + +* doc: update supported fields for uv_rusage_t (Imran Iqbal) + +* test: fix test-tcp-writealot flakiness on arm (Santiago Gimeno) + +* test: fix fs_event_watch_dir flakiness on arm (Santiago Gimeno) + +* unix: don't use alphasort in uv_fs_scandir() (Ben Noordhuis) + +* doc: fix confusing doc of uv_tcp_nodelay (Bart Robinson) + +* build,osx: fix warnings on tests compilation with gyp (Santiago Gimeno) + +* doc: add ABI tracker link to README (Saúl Ibarra Corretgé) + +* win,tty: fix uv_tty_set_mode race conditions (Bartosz Sosnowski) + +* test: fix fs_fstat on Android (Vit Gottwald) + +* win, test: fix fs_event_watch_dir_recursive (Bartosz Sosnowski) + +* doc: add description of uv_handle_type (Vit Gottwald) + +* build: use -pthreads for tests with autotools (Julien Gilli) + +* win: fix leaky fs request buffer (Jason Ginchereau) + +* doc: note buffer lifetime requirements in uv_write (Vladimír Čunát) + +* doc: add reference to uv_update_time on uv_timer_start (Alex Hultman) + +* win: fix winapi function pointer typedef syntax (Brad King) + +* test: fix tcp_close_while_connecting CI failures (Ben Noordhuis) + +* test: make threadpool_cancel_single deterministic (Ben Noordhuis) + +* test: make threadpool saturation reliable (Ben Noordhuis) + +* unix: don't malloc in uv_thread_create() (Ben Noordhuis) + +* unix: don't include CoreServices globally on macOS (Brad King) + +* unix,win: add uv_translate_sys_error() public API (Philippe Laferriere) + +* win: remove unused static variables (Ben Noordhuis) + +* win: silence -Wmaybe-uninitialized warning (Ben Noordhuis) + +* signal: replace pthread_once with uv_once (Santiago Gimeno) + +* test: fix sign-compare warning (Will Speak) + +* common: fix unused variable warning (Brad King) + + 2016.05.17, Version 1.9.1 (Stable), d989902ac658b4323a4f4020446e6f4dc449e25c Changes since version 1.9.0: diff --git a/appveyor.yml b/appveyor.yml index c7ea73650..17609ad8c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.9.1.build{build} +version: v1.10.0.build{build} install: - cinst -y nsis diff --git a/configure.ac b/configure.ac index 90335b4ac..5abd8a19e 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.9.1], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.10.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 3cb9b5fdd..a5631e912 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 9 -#define UV_VERSION_PATCH 2 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 10 +#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 039101f32e0b49d5ea62fd87c9e65c19b4723d67 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 24 Oct 2016 09:52:34 -0400 Subject: [PATCH 276/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 8c6675967..38cadff40 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2016.10.25, Version 1.10.0 (Stable) +2016.10.25, Version 1.10.0 (Stable), c8a373c729b4c9392e0e14fc53cd6b67b3051ab9 Changes since version 1.9.1: From 531f06ecfe603517391340e585597bbc91b4a66b Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 24 Oct 2016 10:24:20 -0400 Subject: [PATCH 277/632] Now working on version 1.10.1 --- 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 a5631e912..57bf1f468 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 10 -#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 060877d483cfcbc0ede85059617be5ad7dae127a Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 29 Sep 2016 14:47:20 -0400 Subject: [PATCH 278/632] win: fix anonymous union syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove use of the DUMMYUNIONNAME macro from our definitions of internal winapi anonymous unions. This macro was added to winternl.h in Windows SDK v7.0a in combination with a conditional definition of DUMMYUNIONNAME to either empty or `u` depending on compiler support. libuv doesn't support any compilers that lack anonymous unions, but does support compilers such as VS 2008 that complain about the presence of the DUMMYUNIONNAME identifier on an anonymous union because their winapi headers do not define the macro publicly. PR-URL: https://github.com/libuv/libuv/pull/1090 Reviewed-By: João Reis Reviewed-By: Colin Ihrig --- src/win/winapi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/win/winapi.h b/src/win/winapi.h index 16d9365cc..341fcd084 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4145,7 +4145,7 @@ typedef const UNICODE_STRING *PCUNICODE_STRING; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; - } DUMMYUNIONNAME; + }; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; #endif @@ -4153,7 +4153,7 @@ typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; - } DUMMYUNIONNAME; + }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; From 668d24d88e9ad734c2bda5e29452b1b4d4e746ce Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 1 Nov 2016 23:09:14 +0100 Subject: [PATCH 279/632] unix: use uv__is_closing everywhere PR-URL: https://github.com/libuv/libuv/pull/1117 Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis --- src/unix/core.c | 2 +- src/unix/poll.c | 4 ++-- src/unix/signal.c | 4 ++-- src/unix/stream.c | 3 +-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index a2c07e6a4..6283ed3ec 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -98,7 +98,7 @@ uint64_t uv_hrtime(void) { void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { - assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + assert(!uv__is_closing(handle)); handle->flags |= UV_CLOSING; handle->close_cb = close_cb; diff --git a/src/unix/poll.c b/src/unix/poll.c index 4c0d478ee..370994bd5 100644 --- a/src/unix/poll.c +++ b/src/unix/poll.c @@ -92,7 +92,7 @@ static void uv__poll_stop(uv_poll_t* handle) { int uv_poll_stop(uv_poll_t* handle) { - assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + assert(!uv__is_closing(handle)); uv__poll_stop(handle); return 0; } @@ -102,7 +102,7 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { int events; assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); - assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + assert(!uv__is_closing(handle)); uv__poll_stop(handle); diff --git a/src/unix/signal.c b/src/unix/signal.c index ccc1847aa..dbd8f8644 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -290,7 +290,7 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { sigset_t saved_sigmask; int err; - assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + assert(!uv__is_closing(handle)); /* If the user supplies signum == 0, then return an error already. If the * signum is otherwise invalid then uv__signal_register will find out @@ -434,7 +434,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { int uv_signal_stop(uv_signal_t* handle) { - assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + assert(!uv__is_closing(handle)); uv__signal_stop(handle); return 0; } diff --git a/src/unix/stream.c b/src/unix/stream.c index d20d0bcb3..86f4eb7a5 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1221,8 +1221,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { if (!(stream->flags & UV_STREAM_WRITABLE) || stream->flags & UV_STREAM_SHUT || stream->flags & UV_STREAM_SHUTTING || - stream->flags & UV_CLOSED || - stream->flags & UV_CLOSING) { + uv__is_closing(stream)) { return -ENOTCONN; } From d9d207774ea1f734310982300e55dd64b3f5682b Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 3 Nov 2016 08:28:49 -0400 Subject: [PATCH 280/632] win: add missing break statement PR-URL: https://github.com/libuv/libuv/pull/1120 Reviewed-By: Ben Noordhuis --- src/win/process-stdio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win/process-stdio.c b/src/win/process-stdio.c index e3c06f57d..032e30935 100644 --- a/src/win/process-stdio.c +++ b/src/win/process-stdio.c @@ -372,6 +372,7 @@ int uv__stdio_create(uv_loop_t* loop, case FILE_TYPE_PIPE: CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; + break; case FILE_TYPE_CHAR: case FILE_TYPE_REMOTE: From 5f34766a14d9a397801378d4a8cd6564a410f329 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Fri, 11 Nov 2016 09:51:21 +0100 Subject: [PATCH 281/632] doc: fix wrong man page link for uv_fs_lstat() PR-URL: https://github.com/libuv/libuv/pull/1134 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Imran Iqbal --- docs/src/fs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 8e4a98f2d..192ecc705 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -223,7 +223,7 @@ API .. c:function:: int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) .. c:function:: int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) - Equivalent to :man:`stat(2)`, :man:`fstat(2)` and :man:`fstat(2)` respectively. + Equivalent to :man:`stat(2)`, :man:`fstat(2)` and :man:`lstat(2)` respectively. .. c:function:: int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) From d0c26414b4287628b2fef25aa7e3971240a92383 Mon Sep 17 00:00:00 2001 From: Hitesh Kanwathirtha Date: Sun, 13 Nov 2016 02:10:57 -0800 Subject: [PATCH 282/632] win, tty: handle empty buffer in uv_tty_write_bufs In uv_tty_write_bufs, if the console supports Virtual Terminal sequences, we try to convert the passed in utf8 buffer to utf16. However, we need to check if the buffer is of non-zero length- otherwise, MultiByteToWideChar returns an error. Fixes: https://github.com/libuv/libuv/issues/1135 Fixes: https://github.com/nodejs/node/issues/9542 PR-URL: https://github.com/libuv/libuv/pull/1139 Refs: https://github.com/libuv/libuv/pull/889 Reviewed-By: Bartosz Sosnowski Reviewed-By: Ben Noordhuis Reviewed-By: Imran Iqbal --- src/win/tty.c | 2 +- test/test-list.h | 2 ++ test/test-tty.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/win/tty.c b/src/win/tty.c index 18d68d094..1e397b44d 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -1650,7 +1650,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle, uv_buf_t buf = bufs[i]; unsigned int j; - if (uv__vterm_state == UV_SUPPORTED) { + if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) { utf16_buf_used = MultiByteToWideChar(CP_UTF8, 0, buf.base, diff --git a/test/test-list.h b/test/test-list.h index 08886a6f4..6ddd5ff27 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -47,6 +47,7 @@ TEST_DECLARE (semaphore_3) TEST_DECLARE (tty) #ifdef _WIN32 TEST_DECLARE (tty_raw) +TEST_DECLARE (tty_empty_write) #endif TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) @@ -404,6 +405,7 @@ TASK_LIST_START TEST_ENTRY (tty) #ifdef _WIN32 TEST_ENTRY (tty_raw) + TEST_ENTRY (tty_empty_write) #endif TEST_ENTRY (tty_file) TEST_ENTRY (tty_pty) diff --git a/test/test-tty.c b/test/test-tty.c index d03f07a44..68a03cd1f 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -212,6 +212,48 @@ TEST_IMPL(tty_raw) { MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(tty_empty_write) { + int r; + int ttyout_fd; + uv_tty_t tty_out; + uv_loop_t* loop = uv_default_loop(); + + /* Make sure we have an FD that refers to a tty */ + HANDLE handle; + + handle = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT(handle != INVALID_HANDLE_VALUE); + ttyout_fd = _open_osfhandle((intptr_t) handle, 0); + + ASSERT(ttyout_fd >= 0); + + ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + ASSERT(r == 0); + + char dummy[1]; + uv_buf_t bufs[1]; + bufs[0].len = 0; + bufs[0].base = &dummy; + + r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &tty_out, NULL); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} #endif From 5cbf733ab6a8a5d903f1d8e070b3ab52c17bf47e Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 15 Nov 2016 10:17:35 -0500 Subject: [PATCH 283/632] doc: add cjihrig alternative GPG ID The v1.10.0 release was signed with this key by mistake. Fixes: https://github.com/libuv/libuv/issues/1140 PR-URL: https://github.com/libuv/libuv/pull/1141 Reviewed-By: Ben Noordhuis --- MAINTAINERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index f2f3db5a1..27a3523ea 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -8,6 +8,7 @@ libuv is currently managed by the following individuals: * **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** ([@iWuzHere](https://github.com/iWuzHere)) From 8cbabaa81709562de68bcac0554e4e7af2f72cf6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 15 Nov 2016 16:38:29 +0100 Subject: [PATCH 284/632] Revert "win,tty: add support for ANSI codes in win10 v1511" Causes regressions on Windows 10 in applications that use ANSI codes. Also reverts commit 0895ccf ("win: fix typo in type name") and commit d0c2641 ("win, tty: handle empty buffer in uv_tty_write_bufs".) This reverts commit d0c26414b4287628b2fef25aa7e3971240a92383. This reverts commit 0895ccfc8ced0c2442c8aab75ccef1f1a6b3938e. This reverts commit 58ccfd4c210d3cc1a36dd82474976aac296589f2. PR-URL: https://github.com/libuv/libuv/pull/1138 Refs: https://github.com/libuv/libuv/issues/1135 Refs: https://github.com/libuv/libuv/pull/889 Refs: https://github.com/nodejs/node/issues/9542 Reviewed-By: Colin Ihrig Reviewed-By: Imran Iqbal Reviewed-By: Santiago Gimeno --- src/win/tty.c | 62 ------------------------------------------------ test/test-list.h | 2 -- test/test-tty.c | 42 -------------------------------- 3 files changed, 106 deletions(-) diff --git a/src/win/tty.c b/src/win/tty.c index 1e397b44d..76dc2fab8 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -57,9 +57,6 @@ #define MAX_INPUT_BUFFER_LENGTH 8192 -#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING -#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 -#endif static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); @@ -128,14 +125,6 @@ static char uv_tty_default_fg_bright = 0; static char uv_tty_default_bg_bright = 0; static char uv_tty_default_inverse = 0; -typedef enum { - UV_SUPPORTED, - UV_UNCHECKED, - UV_UNSUPPORTED -} uv_vtermstate_t; -/* Determine whether or not ANSI support is enabled. */ -static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED; -static void uv__determine_vterm_state(HANDLE handle); void uv_console_init() { if (uv_sem_init(&uv_tty_output_lock, 1)) @@ -179,9 +168,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { /* shared between all uv_tty_t handles. */ uv_sem_wait(&uv_tty_output_lock); - if (uv__vterm_state == UV_UNCHECKED) - uv__determine_vterm_state(handle); - /* Store the global tty output handle. This handle is used by TTY read */ /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */ /* is received. */ @@ -1650,33 +1636,6 @@ static int uv_tty_write_bufs(uv_tty_t* handle, uv_buf_t buf = bufs[i]; unsigned int j; - if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) { - utf16_buf_used = MultiByteToWideChar(CP_UTF8, - 0, - buf.base, - buf.len, - NULL, - 0); - - if (utf16_buf_used == 0) { - *error = GetLastError(); - break; - } - - if (!MultiByteToWideChar(CP_UTF8, - 0, - buf.base, - buf.len, - utf16_buf, - utf16_buf_used)) { - *error = GetLastError(); - break; - } - - FLUSH_TEXT(); - continue; - } - for (j = 0; j < buf.len; j++) { unsigned char c = buf.base[j]; @@ -2234,24 +2193,3 @@ int uv_tty_reset_mode(void) { /* Not necessary to do anything. */ return 0; } - -/* Determine whether or not this version of windows supports - * proper ANSI color codes. Should be supported as of windows - * 10 version 1511, build number 10.0.10586. - */ -static void uv__determine_vterm_state(HANDLE handle) { - DWORD dwMode = 0; - - if (!GetConsoleMode(handle, &dwMode)) { - uv__vterm_state = UV_UNSUPPORTED; - return; - } - - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - if (!SetConsoleMode(handle, dwMode)) { - uv__vterm_state = UV_UNSUPPORTED; - return; - } - - uv__vterm_state = UV_SUPPORTED; -} diff --git a/test/test-list.h b/test/test-list.h index 6ddd5ff27..08886a6f4 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -47,7 +47,6 @@ TEST_DECLARE (semaphore_3) TEST_DECLARE (tty) #ifdef _WIN32 TEST_DECLARE (tty_raw) -TEST_DECLARE (tty_empty_write) #endif TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) @@ -405,7 +404,6 @@ TASK_LIST_START TEST_ENTRY (tty) #ifdef _WIN32 TEST_ENTRY (tty_raw) - TEST_ENTRY (tty_empty_write) #endif TEST_ENTRY (tty_file) TEST_ENTRY (tty_pty) diff --git a/test/test-tty.c b/test/test-tty.c index 68a03cd1f..d03f07a44 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -212,48 +212,6 @@ TEST_IMPL(tty_raw) { MAKE_VALGRIND_HAPPY(); return 0; } - -TEST_IMPL(tty_empty_write) { - int r; - int ttyout_fd; - uv_tty_t tty_out; - uv_loop_t* loop = uv_default_loop(); - - /* Make sure we have an FD that refers to a tty */ - HANDLE handle; - - handle = CreateFileA("conout$", - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - ASSERT(handle != INVALID_HANDLE_VALUE); - ttyout_fd = _open_osfhandle((intptr_t) handle, 0); - - ASSERT(ttyout_fd >= 0); - - ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); - - r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ - ASSERT(r == 0); - - char dummy[1]; - uv_buf_t bufs[1]; - bufs[0].len = 0; - bufs[0].base = &dummy; - - r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); - ASSERT(r == 0); - - uv_close((uv_handle_t*) &tty_out, NULL); - - uv_run(loop, UV_RUN_DEFAULT); - - MAKE_VALGRIND_HAPPY(); - return 0; -} #endif From 2e49e332bdede6db7cf17fa784a902e8386d5d86 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 16 Nov 2016 13:03:50 -0500 Subject: [PATCH 285/632] 2016.11.17, Version 1.10.1 (Stable) Changes since version 1.10.0: * Now working on version 1.10.1 (cjihrig) * win: fix anonymous union syntax (Brad King) * unix: use uv__is_closing everywhere (Santiago Gimeno) * win: add missing break statement (cjihrig) * doc: fix wrong man page link for uv_fs_lstat() (Michele Caini) * win, tty: handle empty buffer in uv_tty_write_bufs (Hitesh Kanwathirtha) * doc: add cjihrig alternative GPG ID (cjihrig) * Revert "win,tty: add support for ANSI codes in win10 v1511" (Ben Noordhuis) --- AUTHORS | 1 + ChangeLog | 21 +++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 4 ++-- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 67aa17620..50916c67c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -277,3 +277,4 @@ Alex Hultman Brad King Philippe Laferriere Will Speak +Hitesh Kanwathirtha diff --git a/ChangeLog b/ChangeLog index 38cadff40..af673d2bd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2016.11.17, Version 1.10.1 (Stable) + +Changes since version 1.10.0: + +* Now working on version 1.10.1 (cjihrig) + +* win: fix anonymous union syntax (Brad King) + +* unix: use uv__is_closing everywhere (Santiago Gimeno) + +* win: add missing break statement (cjihrig) + +* doc: fix wrong man page link for uv_fs_lstat() (Michele Caini) + +* win, tty: handle empty buffer in uv_tty_write_bufs (Hitesh Kanwathirtha) + +* doc: add cjihrig alternative GPG ID (cjihrig) + +* Revert "win,tty: add support for ANSI codes in win10 v1511" (Ben Noordhuis) + + 2016.10.25, Version 1.10.0 (Stable), c8a373c729b4c9392e0e14fc53cd6b67b3051ab9 Changes since version 1.9.1: diff --git a/appveyor.yml b/appveyor.yml index 17609ad8c..6b7856115 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.10.0.build{build} +version: v1.10.1.build{build} install: - cinst -y nsis diff --git a/configure.ac b/configure.ac index 5abd8a19e..d3787c0d6 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.10.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.10.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 57bf1f468..63454a5d0 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -33,8 +33,8 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 10 #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 e7624d68cb183a848772965d88c4ff1fbb2c8c5f Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 16 Nov 2016 13:03:51 -0500 Subject: [PATCH 286/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index af673d2bd..b6f89af51 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2016.11.17, Version 1.10.1 (Stable) +2016.11.17, Version 1.10.1 (Stable), 2e49e332bdede6db7cf17fa784a902e8386d5d86 Changes since version 1.10.0: From a2a85f823f302ef879a0d5cfe060ef69cb803cf5 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 16 Nov 2016 13:19:32 -0500 Subject: [PATCH 287/632] Now working on version 1.10.2 --- 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 63454a5d0..189ec6355 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 10 -#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 c1c55ee1aa071ff566dc486ba274969ada2c7e18 Mon Sep 17 00:00:00 2001 From: Joran Dirk Greef Date: Fri, 4 Nov 2016 16:14:04 +0200 Subject: [PATCH 288/632] darwin: fix fsync and fdatasync Apple's fsync and fdatasync explicitly do NOT flush the drive write cache to the drive platters. This is in contrast to Linux's fsync and fdatasync which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent for flushing buffered data to permanent storage. PR-URL: https://github.com/libuv/libuv/pull/1124 Refs: https://github.com/nodejs/node/issues/9439 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/unix/fs.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 3d478b790..ba64cbbf5 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -129,8 +129,23 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { #if defined(__linux__) || defined(__sun) || defined(__NetBSD__) return fdatasync(req->file); -#elif defined(__APPLE__) && defined(SYS_fdatasync) - return syscall(SYS_fdatasync, req->file); +#elif defined(__APPLE__) + /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache + * to the drive platters. This is in contrast to Linux's fdatasync and fsync + * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent + * for flushing buffered data to permanent storage. + */ + return fcntl(req->file, F_FULLFSYNC); +#else + return fsync(req->file); +#endif +} + + +static ssize_t uv__fs_fsync(uv_fs_t* req) { +#if defined(__APPLE__) + /* See the comment in uv__fs_fdatasync. */ + return fcntl(req->file, F_FULLFSYNC); #else return fsync(req->file); #endif @@ -945,7 +960,7 @@ static void uv__fs_work(struct uv__work* w) { X(FCHOWN, fchown(req->file, req->uid, req->gid)); X(FDATASYNC, uv__fs_fdatasync(req)); X(FSTAT, uv__fs_fstat(req->file, &req->statbuf)); - X(FSYNC, fsync(req->file)); + X(FSYNC, uv__fs_fsync(req)); X(FTRUNCATE, ftruncate(req->file, req->off)); X(FUTIME, uv__fs_futime(req)); X(LSTAT, uv__fs_lstat(req->path, &req->statbuf)); From 445e3a1f06b2a049e2b50b7edf2992ce80167014 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 16 Nov 2016 16:16:54 +0100 Subject: [PATCH 289/632] Revert "Revert "win,tty: add support for ANSI codes in win10 v1511"" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To bring back support for ANSI codes in win10 v1511. This reverts commit 8cbabaa81709562de68bcac0554e4e7af2f72cf6. PR-URL: https://github.com/libuv/libuv/pull/1143 Refs: https://github.com/libuv/libuv/pull/1138 Refs: https://github.com/libuv/libuv/pull/889 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Imran Iqbal --- src/win/tty.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ test/test-tty.c | 42 ++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/src/win/tty.c b/src/win/tty.c index 76dc2fab8..1e397b44d 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -57,6 +57,9 @@ #define MAX_INPUT_BUFFER_LENGTH 8192 +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); @@ -125,6 +128,14 @@ static char uv_tty_default_fg_bright = 0; static char uv_tty_default_bg_bright = 0; static char uv_tty_default_inverse = 0; +typedef enum { + UV_SUPPORTED, + UV_UNCHECKED, + UV_UNSUPPORTED +} uv_vtermstate_t; +/* Determine whether or not ANSI support is enabled. */ +static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED; +static void uv__determine_vterm_state(HANDLE handle); void uv_console_init() { if (uv_sem_init(&uv_tty_output_lock, 1)) @@ -168,6 +179,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { /* shared between all uv_tty_t handles. */ uv_sem_wait(&uv_tty_output_lock); + if (uv__vterm_state == UV_UNCHECKED) + uv__determine_vterm_state(handle); + /* Store the global tty output handle. This handle is used by TTY read */ /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */ /* is received. */ @@ -1636,6 +1650,33 @@ static int uv_tty_write_bufs(uv_tty_t* handle, uv_buf_t buf = bufs[i]; unsigned int j; + if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) { + utf16_buf_used = MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + NULL, + 0); + + if (utf16_buf_used == 0) { + *error = GetLastError(); + break; + } + + if (!MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + utf16_buf, + utf16_buf_used)) { + *error = GetLastError(); + break; + } + + FLUSH_TEXT(); + continue; + } + for (j = 0; j < buf.len; j++) { unsigned char c = buf.base[j]; @@ -2193,3 +2234,24 @@ int uv_tty_reset_mode(void) { /* Not necessary to do anything. */ return 0; } + +/* Determine whether or not this version of windows supports + * proper ANSI color codes. Should be supported as of windows + * 10 version 1511, build number 10.0.10586. + */ +static void uv__determine_vterm_state(HANDLE handle) { + DWORD dwMode = 0; + + if (!GetConsoleMode(handle, &dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (!SetConsoleMode(handle, dwMode)) { + uv__vterm_state = UV_UNSUPPORTED; + return; + } + + uv__vterm_state = UV_SUPPORTED; +} diff --git a/test/test-list.h b/test/test-list.h index 08886a6f4..6ddd5ff27 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -47,6 +47,7 @@ TEST_DECLARE (semaphore_3) TEST_DECLARE (tty) #ifdef _WIN32 TEST_DECLARE (tty_raw) +TEST_DECLARE (tty_empty_write) #endif TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) @@ -404,6 +405,7 @@ TASK_LIST_START TEST_ENTRY (tty) #ifdef _WIN32 TEST_ENTRY (tty_raw) + TEST_ENTRY (tty_empty_write) #endif TEST_ENTRY (tty_file) TEST_ENTRY (tty_pty) diff --git a/test/test-tty.c b/test/test-tty.c index d03f07a44..68a03cd1f 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -212,6 +212,48 @@ TEST_IMPL(tty_raw) { MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(tty_empty_write) { + int r; + int ttyout_fd; + uv_tty_t tty_out; + uv_loop_t* loop = uv_default_loop(); + + /* Make sure we have an FD that refers to a tty */ + HANDLE handle; + + handle = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT(handle != INVALID_HANDLE_VALUE); + ttyout_fd = _open_osfhandle((intptr_t) handle, 0); + + ASSERT(ttyout_fd >= 0); + + ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + ASSERT(r == 0); + + char dummy[1]; + uv_buf_t bufs[1]; + bufs[0].len = 0; + bufs[0].base = &dummy; + + r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &tty_out, NULL); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} #endif From c2f0e4f64ef219fda1f52e2987430f1bea52231d Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 16 Nov 2016 16:17:12 +0100 Subject: [PATCH 290/632] win,tty: fix MultiByteToWideChar output buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure there's enough room in the output buffer by dynamically allocating memory in case the size of the buffer needs to be greater than 8192 characters. PR-URL: https://github.com/libuv/libuv/pull/1143 Refs: https://github.com/libuv/libuv/pull/1138 Refs: https://github.com/libuv/libuv/pull/889 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Imran Iqbal --- src/win/tty.c | 88 ++++++++++++++++++++++++++++++------------------ test/test-list.h | 2 ++ test/test-tty.c | 51 ++++++++++++++++++++++++++-- 3 files changed, 105 insertions(+), 36 deletions(-) diff --git a/src/win/tty.c b/src/win/tty.c index 1e397b44d..fa80674ef 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -56,6 +56,7 @@ #define ANSI_BACKSLASH_SEEN 0x80 #define MAX_INPUT_BUFFER_LENGTH 8192 +#define MAX_CONSOLE_CHAR 8192 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 @@ -1616,17 +1617,29 @@ static int uv_tty_write_bufs(uv_tty_t* handle, DWORD* error) { /* We can only write 8k characters at a time. Windows can't handle */ /* much more characters in a single console write anyway. */ - WCHAR utf16_buf[8192]; + WCHAR utf16_buf[MAX_CONSOLE_CHAR]; + WCHAR* utf16_buffer; DWORD utf16_buf_used = 0; - unsigned int i; - -#define FLUSH_TEXT() \ - do { \ - if (utf16_buf_used > 0) { \ - uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \ - utf16_buf_used = 0; \ - } \ - } while (0) + unsigned int i, len, max_len, pos; + int allocate = 0; + +#define FLUSH_TEXT() \ + do { \ + pos = 0; \ + do { \ + len = utf16_buf_used - pos; \ + if (len > MAX_CONSOLE_CHAR) \ + len = MAX_CONSOLE_CHAR; \ + uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \ + pos += len; \ + } while (pos < utf16_buf_used); \ + if (allocate) { \ + uv__free(utf16_buffer); \ + allocate = 0; \ + utf16_buffer = utf16_buf; \ + } \ + utf16_buf_used = 0; \ + } while (0) #define ENSURE_BUFFER_SPACE(wchars_needed) \ if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \ @@ -1644,38 +1657,47 @@ static int uv_tty_write_bufs(uv_tty_t* handle, /* state. */ *error = ERROR_SUCCESS; + utf16_buffer = utf16_buf; + uv_sem_wait(&uv_tty_output_lock); for (i = 0; i < nbufs; i++) { uv_buf_t buf = bufs[i]; unsigned int j; - if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) { - utf16_buf_used = MultiByteToWideChar(CP_UTF8, - 0, - buf.base, - buf.len, - NULL, - 0); + if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) { + utf16_buf_used = MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + NULL, + 0); + + if (utf16_buf_used == 0) { + *error = GetLastError(); + break; + } - if (utf16_buf_used == 0) { - *error = GetLastError(); - break; - } + max_len = (utf16_buf_used + 1) * sizeof(WCHAR); + allocate = max_len > MAX_CONSOLE_CHAR; + if (allocate) + utf16_buffer = uv__malloc(max_len); + if (!MultiByteToWideChar(CP_UTF8, + 0, + buf.base, + buf.len, + utf16_buffer, + utf16_buf_used)) { + if (allocate) + uv__free(utf16_buffer); + *error = GetLastError(); + break; + } - if (!MultiByteToWideChar(CP_UTF8, - 0, - buf.base, - buf.len, - utf16_buf, - utf16_buf_used)) { - *error = GetLastError(); - break; - } + FLUSH_TEXT(); - FLUSH_TEXT(); - continue; - } + continue; + } for (j = 0; j < buf.len; j++) { unsigned char c = buf.base[j]; diff --git a/test/test-list.h b/test/test-list.h index 6ddd5ff27..be3f9069c 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -48,6 +48,7 @@ TEST_DECLARE (tty) #ifdef _WIN32 TEST_DECLARE (tty_raw) TEST_DECLARE (tty_empty_write) +TEST_DECLARE (tty_large_write) #endif TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) @@ -406,6 +407,7 @@ TASK_LIST_START #ifdef _WIN32 TEST_ENTRY (tty_raw) TEST_ENTRY (tty_empty_write) + TEST_ENTRY (tty_large_write) #endif TEST_ENTRY (tty_file) TEST_ENTRY (tty_pty) diff --git a/test/test-tty.c b/test/test-tty.c index 68a03cd1f..d1f7deb23 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -217,11 +217,15 @@ TEST_IMPL(tty_empty_write) { int r; int ttyout_fd; uv_tty_t tty_out; - uv_loop_t* loop = uv_default_loop(); + char dummy[1]; + uv_buf_t bufs[1]; + uv_loop_t* loop; /* Make sure we have an FD that refers to a tty */ HANDLE handle; + loop = uv_default_loop(); + handle = CreateFileA("conout$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -239,8 +243,6 @@ TEST_IMPL(tty_empty_write) { r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ ASSERT(r == 0); - char dummy[1]; - uv_buf_t bufs[1]; bufs[0].len = 0; bufs[0].base = &dummy; @@ -254,6 +256,49 @@ TEST_IMPL(tty_empty_write) { MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(tty_large_write) { + int r; + int ttyout_fd; + uv_tty_t tty_out; + char dummy[10000]; + uv_buf_t bufs[1]; + uv_loop_t* loop; + + /* Make sure we have an FD that refers to a tty */ + HANDLE handle; + + loop = uv_default_loop(); + + handle = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT(handle != INVALID_HANDLE_VALUE); + ttyout_fd = _open_osfhandle((intptr_t) handle, 0); + + ASSERT(ttyout_fd >= 0); + + ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ + ASSERT(r == 0); + + bufs[0] = uv_buf_init(dummy, sizeof(dummy)); + + r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); + ASSERT(r == 10000); + + uv_close((uv_handle_t*) &tty_out, NULL); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} #endif From 7dfa54d6f8f2c5544829828b9da1dbf1aa77963e Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Wed, 23 Nov 2016 07:27:34 -0800 Subject: [PATCH 291/632] win: remove dead code related to BACKUP_SEMANTICS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove several conditionals which appear to carefully set or clear FILE_FLAG_BACKUP_SEMANTICS, but since 4365896, FILE_FLAG_BACKUP_SEMANTICS is unconditionally ORed into the attributes before CreateFileW() is called. PR-URL: https://github.com/libuv/libuv/pull/1149 Reviewed-By: Saúl Ibarra Corretgé Reviewed-by: Bert Belder --- src/win/fs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index dc0ac89a3..6902d4f1a 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -403,7 +403,6 @@ void fs__open(uv_fs_t* req) { switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { case _O_RDONLY: access = FILE_GENERIC_READ; - attributes |= FILE_FLAG_BACKUP_SEMANTICS; break; case _O_WRONLY: access = FILE_GENERIC_WRITE; @@ -418,7 +417,6 @@ void fs__open(uv_fs_t* req) { if (flags & _O_APPEND) { access &= ~FILE_WRITE_DATA; access |= FILE_APPEND_DATA; - attributes &= ~FILE_FLAG_BACKUP_SEMANTICS; } /* From 8658ef06c2aec1d7ea4cdaca3bbb709f73d3f730 Mon Sep 17 00:00:00 2001 From: Eric Sciple Date: Fri, 28 Oct 2016 22:29:59 -0400 Subject: [PATCH 292/632] win: fix comment in quote_cmd_arg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1113 Reviewed-By: Saúl Ibarra Corretgé Reviewed-by: Bert Belder --- src/win/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/process.c b/src/win/process.c index 855c37408..bdf88d2cd 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -492,7 +492,7 @@ WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) { * input : hello\\"world * output: "hello\\\\\"world" * input : hello world\ - * output: "hello world\" + * output: "hello world\\" */ *(target++) = L'"'; From f8d4805087944cb8543d98109f5f83f4938eb4b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 28 Sep 2016 18:07:32 +0100 Subject: [PATCH 293/632] darwin: use clock_gettime in macOS 10.12 PR-URL: https://github.com/libuv/libuv/pull/1073 Reviewed-By: Fedor Indutny Reviewed-By: Imran Iqbal --- src/unix/darwin.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/unix/darwin.c b/src/unix/darwin.c index cf95da216..b1ffbc37b 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -34,8 +34,12 @@ #include /* _NSGetExecutablePath */ #include #include +#include #include /* sysconf */ +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + int uv__platform_loop_init(uv_loop_t* loop) { loop->cf_state = NULL; @@ -53,6 +57,11 @@ void uv__platform_loop_delete(uv_loop_t* loop) { uint64_t uv__hrtime(uv_clocktype_t type) { +#ifdef MAC_OS_X_VERSION_10_12 + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); +#else static mach_timebase_info_data_t info; if ((ACCESS_ONCE(uint32_t, info.numer) == 0 || @@ -61,6 +70,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) { abort(); return mach_absolute_time() * info.numer / info.denom; +#endif } From 357b9a773365436c360b61aeed4368dfa7cd2d26 Mon Sep 17 00:00:00 2001 From: Nikolai Vavilov Date: Sun, 4 Dec 2016 21:21:45 +0200 Subject: [PATCH 294/632] win, tty: fix crash on restarting with pending data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When reading from tty is restarted while there is pending data, uv_tty_read_start calls uv_insert_pending_req instead of uv_tty_queue_read to avoid losing keypresses. But reading can be stopped and restarted multiple times before the req is handled, which caused an assertion error. Setting the UV_HANDLE_READ_PENDING flag prevents uv_insert_pending_req from being called again until the req is handled. Fixes: https://github.com/nodejs/node/issues/9690 PR-URL: https://github.com/libuv/libuv/pull/1158 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/win/tty.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/win/tty.c b/src/win/tty.c index fa80674ef..1b7adf64f 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -1004,6 +1004,9 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, 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); + /* 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; } From c02176a23062fbde2273579ee641aa47f35d6778 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Fri, 25 Nov 2016 22:14:05 +0100 Subject: [PATCH 295/632] fs: fix uv__to_stat on BSD platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the #ifdef logic to make sure all the available fields filled in the `stat` struct are correcly copied into the `uv_stat_t` struct. Before this change, the `n_sec` were being set to 0. PR-URL: https://github.com/libuv/libuv/pull/1152 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Ben Noordhuis --- src/unix/fs.c | 8 +++++--- test/test-fs.c | 20 +++++++++++--------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index ba64cbbf5..e047b6716 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -813,6 +813,10 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_flags = 0; dst->st_gen = 0; #elif !defined(_AIX) && ( \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) || \ defined(_GNU_SOURCE) || \ defined(_BSD_SOURCE) || \ defined(_SVID_SOURCE) || \ @@ -824,9 +828,7 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec; dst->st_ctim.tv_sec = src->st_ctim.tv_sec; dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec; -# if defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ +# if defined(__FreeBSD__) || \ defined(__NetBSD__) dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec; dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec; diff --git a/test/test-fs.c b/test/test-fs.c index 06718f285..70a239996 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1141,11 +1141,15 @@ TEST_IMPL(fs_fstat) { 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); -#elif defined(__sun) || \ - defined(_GNU_SOURCE) || \ - defined(_BSD_SOURCE) || \ - defined(_SVID_SOURCE) || \ - defined(_XOPEN_SOURCE) || \ +#elif defined(__sun) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) || \ + defined(_GNU_SOURCE) || \ + defined(_BSD_SOURCE) || \ + 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); @@ -1153,10 +1157,8 @@ TEST_IMPL(fs_fstat) { 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); -# if defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) +# 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(s->st_flags == t.st_flags); From 11ce5df5eadd67fa951b8c4c6293fa784d21cf80 Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Wed, 30 Nov 2016 20:00:32 +0000 Subject: [PATCH 296/632] win: map ERROR_ELEVATION_REQUIRED to UV_EACCES MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uv_spawn() on Windows will fail with ERROR_ELEVATION_REQUIRED if attempting to run an application that requires elevation. Fixes: https://github.com/nodejs/node/issues/9464 PR-URL: https://github.com/libuv/libuv/pull/1154 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/win/error.c | 1 + test/test-error.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/win/error.c b/src/win/error.c index c512f35af..642d1112e 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -71,6 +71,7 @@ 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_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; case WSAEADDRINUSE: return UV_EADDRINUSE; case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; diff --git a/test/test-error.c b/test/test-error.c index 4c4efa30c..ff53eb1d7 100644 --- a/test/test-error.c +++ b/test/test-error.c @@ -53,6 +53,7 @@ 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); #else From 7bfb5ae7f923ef185f528a4886c255017df51937 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 4 Nov 2016 00:21:04 +0100 Subject: [PATCH 297/632] win: fix free() on bad input in uv_getaddrinfo() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error path frees `req->alloc` but that hasn't been set yet when `service` and `node` are both NULL. Simply return instead of jumping to the error handling block. Fixes: https://github.com/libuv/libuv/issues/1122 PR-URL: https://github.com/libuv/libuv/pull/1123 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/win/getaddrinfo.c | 3 +-- test/test-getaddrinfo.c | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index 744f8e026..c13bfec35 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -262,8 +262,7 @@ int uv_getaddrinfo(uv_loop_t* loop, int err; if (req == NULL || (node == NULL && service == NULL)) { - err = WSAEINVAL; - goto error; + return UV_EINVAL; } uv_req_init(loop, (uv_req_t*)req); diff --git a/test/test-getaddrinfo.c b/test/test-getaddrinfo.c index 6b644a8d4..03dc12695 100644 --- a/test/test-getaddrinfo.c +++ b/test/test-getaddrinfo.c @@ -83,6 +83,13 @@ static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle, TEST_IMPL(getaddrinfo_fail) { uv_getaddrinfo_t req; + ASSERT(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, From cb9f579a454b8db592030ffa274ae58df78dbe20 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 9 Jan 2017 13:42:49 -0500 Subject: [PATCH 298/632] 2017.01.10, Version 1.10.2 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.10.1: * Now working on version 1.10.2 (cjihrig) * darwin: fix fsync and fdatasync (Joran Dirk Greef) * Revert "Revert "win,tty: add support for ANSI codes in win10 v1511"" (Santiago Gimeno) * win,tty: fix MultiByteToWideChar output buffer (Santiago Gimeno) * win: remove dead code related to BACKUP_SEMANTICS (Sam Roberts) * win: fix comment in quote_cmd_arg (Eric Sciple) * darwin: use clock_gettime in macOS 10.12 (Saúl Ibarra Corretgé) * win, tty: fix crash on restarting with pending data (Nicholas Vavilov) * fs: fix uv__to_stat on BSD platforms (Santiago Gimeno) * win: map ERROR_ELEVATION_REQUIRED to UV_EACCES (Richard Lau) * win: fix free() on bad input in uv_getaddrinfo() (Ben Noordhuis) --- AUTHORS | 1 + ChangeLog | 28 ++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 4 ++-- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 50916c67c..49c8e17f2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -278,3 +278,4 @@ Brad King Philippe Laferriere Will Speak Hitesh Kanwathirtha +Eric Sciple diff --git a/ChangeLog b/ChangeLog index b6f89af51..ad5ccf546 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2017.01.10, Version 1.10.2 (Stable) + +Changes since version 1.10.1: + +* Now working on version 1.10.2 (cjihrig) + +* darwin: fix fsync and fdatasync (Joran Dirk Greef) + +* Revert "Revert "win,tty: add support for ANSI codes in win10 v1511"" + (Santiago Gimeno) + +* win,tty: fix MultiByteToWideChar output buffer (Santiago Gimeno) + +* win: remove dead code related to BACKUP_SEMANTICS (Sam Roberts) + +* win: fix comment in quote_cmd_arg (Eric Sciple) + +* darwin: use clock_gettime in macOS 10.12 (Saúl Ibarra Corretgé) + +* win, tty: fix crash on restarting with pending data (Nicholas Vavilov) + +* fs: fix uv__to_stat on BSD platforms (Santiago Gimeno) + +* win: map ERROR_ELEVATION_REQUIRED to UV_EACCES (Richard Lau) + +* win: fix free() on bad input in uv_getaddrinfo() (Ben Noordhuis) + + 2016.11.17, Version 1.10.1 (Stable), 2e49e332bdede6db7cf17fa784a902e8386d5d86 Changes since version 1.10.0: diff --git a/appveyor.yml b/appveyor.yml index 6b7856115..632941378 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.10.1.build{build} +version: v1.10.2.build{build} install: - cinst -y nsis diff --git a/configure.ac b/configure.ac index d3787c0d6..abaf97177 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.10.1], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.10.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 189ec6355..99f7eb8c1 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -33,8 +33,8 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 10 #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 677e7ce1e1cd78fcc3759c9437ef7c5257a92f0c Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 9 Jan 2017 13:42:50 -0500 Subject: [PATCH 299/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ad5ccf546..d865f2266 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017.01.10, Version 1.10.2 (Stable) +2017.01.10, Version 1.10.2 (Stable), cb9f579a454b8db592030ffa274ae58df78dbe20 Changes since version 1.10.1: From 65751b5cd69f3f719a5e319ca9375cc8668e854f Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 9 Jan 2017 13:56:05 -0500 Subject: [PATCH 300/632] Now working on version 1.10.3 --- 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 99f7eb8c1..80f4ace0c 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 10 -#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 2e5ad25cadd9c12463f4150f04a6e99f40c3f880 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Tue, 8 Nov 2016 17:11:58 +0100 Subject: [PATCH 301/632] win: added fcntl.h to uv-win.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1130 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- include/uv-win.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uv-win.h b/include/uv-win.h index e8b9b15e2..9677ff164 100644 --- a/include/uv-win.h +++ b/include/uv-win.h @@ -49,6 +49,7 @@ typedef struct pollfd { #include #include +#include #include #if defined(_MSC_VER) && _MSC_VER < 1600 From 8f43417f0e33020880e1c8f6820b75a446563244 Mon Sep 17 00:00:00 2001 From: jBarz Date: Tue, 17 Jan 2017 10:42:42 -0500 Subject: [PATCH 302/632] unix: move function call out of assert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit assert expressions should only be scalar PR-URL: https://github.com/libuv/libuv/pull/1196 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/unix/pthread-barrier.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unix/pthread-barrier.c b/src/unix/pthread-barrier.c index f57bf2508..b6e604d46 100644 --- a/src/unix/pthread-barrier.c +++ b/src/unix/pthread-barrier.c @@ -73,7 +73,8 @@ int pthread_barrier_wait(pthread_barrier_t* barrier) { if (++b->in == b->threshold) { b->in = 0; b->out = b->threshold - 1; - assert(pthread_cond_signal(&b->cond) == 0); + rc = pthread_cond_signal(&b->cond); + assert(rc == 0); pthread_mutex_unlock(&b->mutex); return PTHREAD_BARRIER_SERIAL_THREAD; From d251dee33b0935ffbdcd94f4126870883aaac140 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sat, 7 Jan 2017 20:45:55 +0100 Subject: [PATCH 303/632] fs: cleanup uv__fs_scandir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `out` section is only reachable now if `scandir` returns 0. PR-URL: https://github.com/libuv/libuv/pull/1189 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fs.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index e047b6716..f9513ea55 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -380,7 +380,6 @@ static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) { static ssize_t uv__fs_scandir(uv_fs_t* req) { uv__dirent_t **dents; - int saved_errno; int n; dents = NULL; @@ -389,28 +388,17 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) { /* NOTE: We will use nbufs as an index field */ req->nbufs = 0; - if (n == 0) - goto out; /* osx still needs to deallocate some memory */ - else if (n == -1) - return n; - - req->ptr = dents; - - return n; - -out: - saved_errno = errno; - if (dents != NULL) { - int i; - - /* Memory was allocated using the system allocator, so use free() here. */ - for (i = 0; i < n; i++) - free(dents[i]); + if (n == 0) { + /* OS X still needs to deallocate some memory. + * Memory was allocated using the system allocator, so use free() here. + */ free(dents); + dents = NULL; + } else if (n == -1) { + return n; } - errno = saved_errno; - req->ptr = NULL; + req->ptr = dents; return n; } From c8ab24bb924bf3aa555cb4400ccbed31a6b3d8f0 Mon Sep 17 00:00:00 2001 From: muflub Date: Thu, 5 Jan 2017 15:16:48 -0800 Subject: [PATCH 304/632] fs: fix crash in uv_fs_scandir_next MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle the case when it's called after the request has ended, or in case it ended with an error. PR-URL: https://github.com/libuv/libuv/pull/1181 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/uv-common.c | 12 +++++++++++- test/test-fs.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/uv-common.c b/src/uv-common.c index 46d954673..bc7d1379d 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -512,8 +512,18 @@ void uv__fs_scandir_cleanup(uv_fs_t* req) { int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { uv__dirent_t** dents; uv__dirent_t* dent; + unsigned int* nbufs; - unsigned int* nbufs = uv__get_nbufs(req); + /* Check to see if req passed */ + if (req->result < 0) + return req->result; + + /* Ptr will be null if req was canceled or no files found */ + if (!req->ptr) + return UV_EOF; + + nbufs = uv__get_nbufs(req); + assert(nbufs); dents = req->ptr; diff --git a/test/test-fs.c b/test/test-fs.c index 70a239996..030245ead 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -510,6 +510,18 @@ static void empty_scandir_cb(uv_fs_t* req) { scandir_cb_count++; } +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(req->ptr == NULL); + ASSERT(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); @@ -2175,6 +2187,39 @@ TEST_IMPL(fs_scandir_empty_dir) { } +TEST_IMPL(fs_scandir_non_existent_dir) { + const char* path; + uv_fs_t req; + uv_dirent_t dent; + int r; + + path = "./non_existent_dir/"; + loop = uv_default_loop(); + + uv_fs_rmdir(NULL, &req, path, NULL); + uv_fs_req_cleanup(&req); + + /* Fill the req to ensure that required fields are cleaned up */ + memset(&req, 0xdb, sizeof(req)); + + r = uv_fs_scandir(NULL, &req, path, 0, NULL); + ASSERT(r == UV_ENOENT); + ASSERT(req.result == UV_ENOENT); + ASSERT(req.ptr == NULL); + ASSERT(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(scandir_cb_count == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(scandir_cb_count == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + TEST_IMPL(fs_scandir_file) { const char* path; int r; diff --git a/test/test-list.h b/test/test-list.h index be3f9069c..d2fc022b8 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -295,6 +295,7 @@ TEST_DECLARE (fs_event_start_and_close) TEST_DECLARE (fs_event_error_reporting) TEST_DECLARE (fs_event_getpath) TEST_DECLARE (fs_scandir_empty_dir) +TEST_DECLARE (fs_scandir_non_existent_dir) TEST_DECLARE (fs_scandir_file) TEST_DECLARE (fs_open_dir) TEST_DECLARE (fs_rename_to_existing_file) @@ -751,6 +752,7 @@ TASK_LIST_START TEST_ENTRY (fs_event_error_reporting) TEST_ENTRY (fs_event_getpath) TEST_ENTRY (fs_scandir_empty_dir) + TEST_ENTRY (fs_scandir_non_existent_dir) TEST_ENTRY (fs_scandir_file) TEST_ENTRY (fs_open_dir) TEST_ENTRY (fs_rename_to_existing_file) From c66f265b5d700bdd922316788545c0fb7956db1d Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Mon, 12 Dec 2016 11:34:42 +0100 Subject: [PATCH 305/632] win,signal: fix potential deadlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trying to remove the controller from the controller handle itself leads to deadlock. Fix it by always having the global signal handler engaged. Ref: https://github.com/nodejs/node/issues/10165 PR-URL: https://github.com/libuv/libuv/pull/1168 Reviewed-By: Saúl Ibarra Corretgé --- src/win/signal.c | 118 ++------------------------------------------- test/test-list.h | 2 + test/test-signal.c | 35 ++++++++++++-- 3 files changed, 38 insertions(+), 117 deletions(-) diff --git a/src/win/signal.c b/src/win/signal.c index 2c64a55dc..af7974c36 100644 --- a/src/win/signal.c +++ b/src/win/signal.c @@ -30,12 +30,14 @@ RB_HEAD(uv_signal_tree_s, uv_signal_s); static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); -static ssize_t volatile uv__signal_control_handler_refs = 0; static CRITICAL_SECTION uv__signal_lock; +static BOOL WINAPI uv__signal_control_handler(DWORD type); void uv_signals_init() { InitializeCriticalSection(&uv__signal_lock); + if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) + abort(); } @@ -125,102 +127,6 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) { } -static int uv__signal_register_control_handler() { - /* When this function is called, the uv__signal_lock must be held. */ - - /* If the console control handler has already been hooked, just add a */ - /* reference. */ - if (uv__signal_control_handler_refs > 0) { - uv__signal_control_handler_refs++; - return 0; - } - - if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) - return GetLastError(); - - uv__signal_control_handler_refs++; - - return 0; -} - - -static void uv__signal_unregister_control_handler() { - /* When this function is called, the uv__signal_lock must be held. */ - BOOL r; - - /* Don't unregister if the number of console control handlers exceeds one. */ - /* Just remove a reference in that case. */ - if (uv__signal_control_handler_refs > 1) { - uv__signal_control_handler_refs--; - return; - } - - assert(uv__signal_control_handler_refs == 1); - - r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE); - /* This should never fail; if it does it is probably a bug in libuv. */ - assert(r); - - uv__signal_control_handler_refs--; -} - - -static int uv__signal_register(int signum) { - switch (signum) { - case SIGINT: - case SIGBREAK: - case SIGHUP: - return uv__signal_register_control_handler(); - - case SIGWINCH: - /* SIGWINCH is generated in tty.c. No need to register anything. */ - return 0; - - case SIGILL: - case SIGABRT_COMPAT: - case SIGFPE: - case SIGSEGV: - case SIGTERM: - case SIGABRT: - /* Signal is never raised. */ - return 0; - - default: - /* Invalid signal. */ - return ERROR_INVALID_PARAMETER; - } -} - - -static void uv__signal_unregister(int signum) { - switch (signum) { - case SIGINT: - case SIGBREAK: - case SIGHUP: - uv__signal_unregister_control_handler(); - return; - - case SIGWINCH: - /* SIGWINCH is generated in tty.c. No need to unregister anything. */ - return; - - case SIGILL: - case SIGABRT_COMPAT: - case SIGFPE: - case SIGSEGV: - case SIGTERM: - case SIGABRT: - /* Nothing is registered for this signal. */ - return; - - default: - /* Libuv bug. */ - assert(0 && "Invalid signum"); - return; - } -} - - int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { uv_req_t* req; @@ -247,8 +153,6 @@ int uv_signal_stop(uv_signal_t* handle) { EnterCriticalSection(&uv__signal_lock); - uv__signal_unregister(handle->signum); - removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle); assert(removed_handle == handle); @@ -262,14 +166,9 @@ int uv_signal_stop(uv_signal_t* handle) { int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { - int err; - - /* If the user supplies signum == 0, then return an error already. If the */ - /* signum is otherwise invalid then uv__signal_register will find out */ - /* eventually. */ - if (signum == 0) { + /* Test for invalid signal values. */ + if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG)) return UV_EINVAL; - } /* Short circuit: if the signal watcher is already watching {signum} don't */ /* go through the process of deregistering and registering the handler. */ @@ -289,13 +188,6 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { EnterCriticalSection(&uv__signal_lock); - err = uv__signal_register(signum); - if (err) { - /* Uh-oh, didn't work. */ - LeaveCriticalSection(&uv__signal_lock); - return uv_translate_sys_error(err); - } - handle->signum = signum; RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle); diff --git a/test/test-list.h b/test/test-list.h index d2fc022b8..3a1e82a91 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -346,6 +346,7 @@ TEST_DECLARE (listen_no_simultaneous_accepts) TEST_DECLARE (fs_stat_root) TEST_DECLARE (spawn_with_an_odd_path) TEST_DECLARE (ipc_listen_after_bind_twice) +TEST_DECLARE (win32_signum_number) #else TEST_DECLARE (emfile) TEST_DECLARE (close_fd) @@ -695,6 +696,7 @@ TASK_LIST_START TEST_ENTRY (fs_stat_root) TEST_ENTRY (spawn_with_an_odd_path) TEST_ENTRY (ipc_listen_after_bind_twice) + TEST_ENTRY (win32_signum_number) #else TEST_ENTRY (emfile) TEST_ENTRY (close_fd) diff --git a/test/test-signal.c b/test/test-signal.c index fcdd8e4d2..c0424c60a 100644 --- a/test/test-signal.c +++ b/test/test-signal.c @@ -19,13 +19,40 @@ * IN THE SOFTWARE. */ - -/* This test does not pretend to be cross-platform. */ -#ifndef _WIN32 - #include "uv.h" #include "task.h" +/* For Windows we test only signum handling */ +#ifdef _WIN32 +static void signum_test_cb(uv_signal_t* handle, int signum) { + FATAL("signum_test_cb should not be called"); +} + +TEST_IMPL(win32_signum_number) { + uv_signal_t signal; + uv_loop_t* loop; + + 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); + MAKE_VALGRIND_HAPPY(); + return 0; +} +#else #include #include #include From 449933623dff1e9911af113e4bf8183c7222facb Mon Sep 17 00:00:00 2001 From: jBarz Date: Mon, 12 Dec 2016 16:52:43 -0500 Subject: [PATCH 306/632] unix: use async-signal safe functions between fork and exec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs: https://github.com/libuv/libuv/issues/998 PR-URL: https://github.com/libuv/libuv/pull/1167 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/unix/process.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index 45f5b4526..f2fe30521 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -323,7 +323,7 @@ static void uv__process_child_init(const uv_process_options_t* options, } if (fd == use_fd) - uv__cloexec(use_fd, 0); + uv__cloexec_fcntl(use_fd, 0); else fd = dup2(use_fd, fd); @@ -333,7 +333,7 @@ static void uv__process_child_init(const uv_process_options_t* options, } if (fd <= 2) - uv__nonblock(fd, 0); + uv__nonblock_fcntl(fd, 0); if (close_fd >= stdio_count) uv__close(close_fd); From 36ba7eb6bcb50eab5f5afe1d00f4138b2126c7f0 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 1 Dec 2016 13:51:57 +0100 Subject: [PATCH 307/632] sunos: fix SUNOS_NO_IFADDRS build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't compile uv__set_phys_addr() if SUNOS_NO_IFADDRS is defined, it has been reported to break the build on Solaris 10. Bug introduced in commit d75e334 ("sunos: set phys_addr of interface_address using ARP") from last June. Fixes: https://github.com/nodejs/node/issues/9856 PR-URL: https://github.com/libuv/libuv/pull/1155 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/unix/sunos.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 3e7a7592d..a43f7f1b1 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -695,6 +695,11 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } +#ifdef SUNOS_NO_IFADDRS +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + return -ENOSYS; +} +#else /* SUNOS_NO_IFADDRS */ /* * Inspired By: * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris @@ -742,9 +747,6 @@ static int uv__set_phys_addr(uv_interface_address_t* address, } int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { -#ifdef SUNOS_NO_IFADDRS - return -ENOSYS; -#else uv_interface_address_t* address; struct ifaddrs* addrs; struct ifaddrs* ent; @@ -805,9 +807,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { freeifaddrs(addrs); return 0; -#endif /* SUNOS_NO_IFADDRS */ } - +#endif /* SUNOS_NO_IFADDRS */ void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) { From 011e02e3e5bfde5aae662fbc72608fa98122682f Mon Sep 17 00:00:00 2001 From: John Barboza Date: Tue, 30 Aug 2016 15:20:34 -0400 Subject: [PATCH 308/632] zos: make platform functional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix all functional test cases: * use PLO compare,swap,store for atomic instruction * do not use semaphore.h * use xplink flag when linking * scandir implementation * nanosleep implementation * add proctitle * uv_loadavg * uv_fs_event_init/start * uv_fs_event_stop * uv_exepath using __getthent syscall * read free/total memory from mvs data areas * uv_resident_set_memory implementation * network interfaces implementation * cpu_info implementation * implement uv__hrtime * make uv__fs_mkdtemp implementation * epoll implementation for asyncio * uv__fs_event_close implementation * set process title * read ancillary data that remains on queue * ancillary data * implement uv__fs_access * use /dev/urandom for temporary directory name * disable proctitle on zos completely PR-URL: https://github.com/libuv/libuv/pull/1037 Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 6 +- include/pthread-barrier.h | 2 + include/uv-os390.h | 3 + include/uv-unix.h | 4 + src/unix/atomic-ops.h | 27 +- src/unix/core.c | 3 + src/unix/internal.h | 4 + src/unix/os390-syscalls.c | 334 +++++++++++++++ src/unix/os390-syscalls.h | 69 ++++ src/unix/os390.c | 837 ++++++++++++++++++++++++++++++++++++++ src/unix/stream.c | 28 +- uv.gyp | 7 +- 12 files changed, 1309 insertions(+), 15 deletions(-) create mode 100644 src/unix/os390-syscalls.c create mode 100644 src/unix/os390-syscalls.h diff --git a/Makefile.am b/Makefile.am index c232b6dbd..2637ef3f7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -402,8 +402,10 @@ libuv_la_CFLAGS += -D_UNIX03_THREADS \ -qFLOAT=IEEE libuv_la_LDFLAGS += -qXPLINK libuv_la_SOURCES += src/unix/pthread-fixes.c \ - src/unix/pthread-barrier.c -libuv_la_SOURCES += src/unix/os390.c + src/unix/pthread-barrier.c \ + src/unix/os390.c \ + src/unix/os390-syscalls.c \ + src/unix/proctitle.c endif if HAVE_PKG_CONFIG diff --git a/include/pthread-barrier.h b/include/pthread-barrier.h index 3e01705d9..900ebedd3 100644 --- a/include/pthread-barrier.h +++ b/include/pthread-barrier.h @@ -18,7 +18,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define _UV_PTHREAD_BARRIER_ #include #include +#if !defined(__MVS__) #include /* sem_t */ +#endif #define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 diff --git a/include/uv-os390.h b/include/uv-os390.h index b0b068f44..58f926111 100644 --- a/include/uv-os390.h +++ b/include/uv-os390.h @@ -24,4 +24,7 @@ #define UV_PLATFORM_SEM_T int +#define UV_PLATFORM_LOOP_FIELDS \ + void* ep; \ + #endif /* UV_MVS_H */ diff --git a/include/uv-unix.h b/include/uv-unix.h index bca271447..3030f719a 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -36,7 +36,9 @@ #include #include +#if !defined(__MVS__) #include +#endif #include #include @@ -44,6 +46,8 @@ #if defined(__linux__) # include "uv-linux.h" +#elif defined (__MVS__) +# include "uv-os390.h" #elif defined(_AIX) # include "uv-aix.h" #elif defined(__sun) diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h index 815e35523..9dac2557f 100644 --- a/src/unix/atomic-ops.h +++ b/src/unix/atomic-ops.h @@ -43,8 +43,12 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { __compare_and_swap(ptr, &oldval, newval); return out; #elif defined(__MVS__) - return __plo_CS(ptr, (unsigned int*) ptr, - oldval, (unsigned int*) &newval); + unsigned int op4; + if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, + (unsigned int*) ptr, *ptr, &op4)) + return oldval; + else + return op4; #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif @@ -67,13 +71,18 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) { # endif /* if defined(__64BIT__) */ return out; #elif defined (__MVS__) -# ifdef _LP64 - return __plo_CSGR(ptr, (unsigned long long*) ptr, - oldval, (unsigned long long*) &newval); -# else - return __plo_CS(ptr, (unsigned int*) ptr, - oldval, (unsigned int*) &newval); -# endif +#ifdef _LP64 + unsigned long long op4; + if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval, + (unsigned long long*) ptr, *ptr, &op4)) +#else + unsigned long op4; + if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, + (unsigned int*) ptr, *ptr, &op4)) +#endif + return oldval; + else + return op4; #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif diff --git a/src/unix/core.c b/src/unix/core.c index 6283ed3ec..1ec549ccc 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -517,6 +517,9 @@ int uv__close_nocheckstdio(int fd) { int uv__close(int fd) { assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ +#if defined(__MVS__) + epoll_file_close(fd); +#endif return uv__close_nocheckstdio(fd); } diff --git a/src/unix/internal.h b/src/unix/internal.h index ee76c837c..1188e8fe7 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -38,6 +38,10 @@ # include "linux-syscalls.h" #endif /* __linux__ */ +#if defined(__MVS__) +# include "os390-syscalls.h" +#endif /* __MVS__ */ + #if defined(__sun) # include # include diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c new file mode 100644 index 000000000..2bf3b7381 --- /dev/null +++ b/src/unix/os390-syscalls.c @@ -0,0 +1,334 @@ +/* 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 "os390-syscalls.h" +#include +#include +#include +#include + +#define CW_CONDVAR 32 + +#pragma linkage(BPX4CTW, OS) +#pragma linkage(BPX1CTW, OS) + +static int number_of_epolls; +static QUEUE global_epoll_queue; +static uv_mutex_t global_epoll_lock; +static uv_once_t once = UV_ONCE_INIT; + +int scandir(const char* maindir, struct dirent*** namelist, + int (*filter)(const struct dirent*), + int (*compar)(const struct dirent**, + const struct dirent **)) { + struct dirent** nl; + struct dirent* dirent; + unsigned count; + size_t allocated; + DIR* mdir; + + nl = NULL; + count = 0; + allocated = 0; + mdir = opendir(maindir); + if (!mdir) + return -1; + + while (1) { + dirent = readdir(mdir); + if (!dirent) + break; + if (!filter || filter(dirent)) { + struct dirent* copy; + copy = uv__malloc(sizeof(*copy)); + if (!copy) { + while (count) { + dirent = nl[--count]; + uv__free(dirent); + } + uv__free(nl); + closedir(mdir); + errno = ENOMEM; + return -1; + } + memcpy(copy, dirent, sizeof(*copy)); + + nl = uv__realloc(nl, sizeof(*copy) * (count + 1)); + nl[count++] = copy; + } + } + + qsort(nl, count, sizeof(struct dirent *), + (int (*)(const void *, const void *)) compar); + + closedir(mdir); + + *namelist = nl; + return count; +} + + +static unsigned int next_power_of_two(unsigned int val) { + val -= 1; + val |= val >> 1; + val |= val >> 2; + val |= val >> 4; + val |= val >> 8; + val |= val >> 16; + val += 1; + return val; +} + + +static void maybe_resize(uv__os390_epoll* lst, unsigned int len) { + unsigned int newsize; + unsigned int i; + struct pollfd* newlst; + + if (len <= lst->size) + return; + + newsize = next_power_of_two(len); + newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0])); + + if (newlst == NULL) + abort(); + for (i = lst->size; i < newsize; ++i) + newlst[i].fd = -1; + + lst->items = newlst; + lst->size = newsize; +} + + +static void epoll_init() { + QUEUE_INIT(&global_epoll_queue); + if (uv_mutex_init(&global_epoll_lock)) + abort(); +} + + +uv__os390_epoll* epoll_create1(int flags) { + uv__os390_epoll* lst; + + uv_once(&once, epoll_init); + uv_mutex_lock(&global_epoll_lock); + lst = uv__malloc(sizeof(*lst)); + if (lst == -1) + return NULL; + QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); + uv_mutex_unlock(&global_epoll_lock); + + /* initialize list */ + lst->size = 0; + lst->items = NULL; + return lst; +} + + +int epoll_ctl(uv__os390_epoll* lst, + int op, + int fd, + struct epoll_event *event) { + if(op == EPOLL_CTL_DEL) { + if (fd >= lst->size || lst->items[fd].fd == -1) { + errno = ENOENT; + return -1; + } + lst->items[fd].fd = -1; + } else if(op == EPOLL_CTL_ADD) { + maybe_resize(lst, fd + 1); + if (lst->items[fd].fd != -1) { + errno = EEXIST; + return -1; + } + lst->items[fd].fd = fd; + lst->items[fd].events = event->events; + } else if(op == EPOLL_CTL_MOD) { + if (fd >= lst->size || lst->items[fd].fd == -1) { + errno = ENOENT; + return -1; + } + lst->items[fd].events = event->events; + } else + abort(); + + return 0; +} + + +int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, + int maxevents, int timeout) { + size_t size; + struct pollfd* pfds; + int pollret; + int reventcount; + + uv_mutex_lock(&global_epoll_lock); + uv_mutex_unlock(&global_epoll_lock); + size = lst->size; + pfds = lst->items; + pollret = poll(pfds, size, timeout); + if(pollret == -1) + return pollret; + + reventcount = 0; + for (int i = 0; i < lst->size && i < maxevents; ++i) { + struct epoll_event ev; + + ev.events = 0; + ev.fd = pfds[i].fd; + if(!pfds[i].revents) + continue; + + if(pfds[i].revents & POLLRDNORM) + ev.events = ev.events | POLLIN; + + if(pfds[i].revents & POLLWRNORM) + ev.events = ev.events | POLLOUT; + + if(pfds[i].revents & POLLHUP) + ev.events = ev.events | POLLHUP; + + pfds[i].revents = 0; + events[reventcount++] = ev; + } + + return reventcount; +} + + +int epoll_file_close(int fd) { + QUEUE* q; + + uv_once(&once, epoll_init); + uv_mutex_lock(&global_epoll_lock); + QUEUE_FOREACH(q, &global_epoll_queue) { + uv__os390_epoll* lst; + + lst = QUEUE_DATA(q, uv__os390_epoll, member); + if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1) + lst->items[fd].fd = -1; + } + + uv_mutex_unlock(&global_epoll_lock); + return 0; +} + +void epoll_queue_close(uv__os390_epoll* lst) { + uv_mutex_lock(&global_epoll_lock); + QUEUE_REMOVE(&lst->member); + uv_mutex_unlock(&global_epoll_lock); + uv__free(lst->items); + lst->items = NULL; +} + + +int nanosleep(const struct timespec* req, struct timespec* rem) { + unsigned nano; + unsigned seconds; + unsigned events; + unsigned secrem; + unsigned nanorem; + int rv; + int rc; + int rsn; + + nano = (int)req->tv_nsec; + seconds = req->tv_sec; + events = CW_CONDVAR; + +#if defined(_LP64) + BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn); +#else + BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn); +#endif + + assert(rv == -1 && errno == EAGAIN); + + if(rem != NULL) { + rem->tv_nsec = nanorem; + rem->tv_sec = secrem; + } + + return 0; +} + + +char* mkdtemp(char* path) { + static const char* tempchars = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + static const size_t num_chars = 62; + static const size_t num_x = 6; + char *ep, *cp; + unsigned int tries, i; + size_t len; + uint64_t v; + int fd; + int retval; + int saved_errno; + + len = strlen(path); + ep = path + len; + if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) { + errno = EINVAL; + return NULL; + } + + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1) + return NULL; + + tries = TMP_MAX; + retval = -1; + do { + if (read(fd, &v, sizeof(v)) != sizeof(v)) + break; + + cp = ep - num_x; + for (i = 0; i < num_x; i++) { + *cp++ = tempchars[v % num_chars]; + v /= num_chars; + } + + if (mkdir(path, S_IRWXU) == 0) { + retval = 0; + break; + } + else if (errno != EEXIST) + break; + } while (--tries); + + saved_errno = errno; + uv__close(fd); + if (tries == 0) { + errno = EEXIST; + return NULL; + } + + if (retval == -1) { + errno = saved_errno; + return NULL; + } + + return path; +} diff --git a/src/unix/os390-syscalls.h b/src/unix/os390-syscalls.h new file mode 100644 index 000000000..61a7cee83 --- /dev/null +++ b/src/unix/os390-syscalls.h @@ -0,0 +1,69 @@ +/* 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_OS390_SYSCALL_H_ +#define UV_OS390_SYSCALL_H_ + +#include "uv.h" +#include "internal.h" +#include +#include +#include + +#define EPOLL_CTL_ADD 1 +#define EPOLL_CTL_DEL 2 +#define EPOLL_CTL_MOD 3 +#define MAX_EPOLL_INSTANCES 256 +#define MAX_ITEMS_PER_EPOLL 1024 + +#define UV__O_CLOEXEC 0x80000 +#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC +#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD +#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL +#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD + +struct epoll_event { + int events; + int fd; +}; + +typedef struct { + QUEUE member; + struct pollfd* items; + unsigned long size; +} uv__os390_epoll; + +/* epoll api */ +uv__os390_epoll* epoll_create1(int flags); +int epoll_ctl(uv__os390_epoll* ep, int op, int fd, struct epoll_event *event); +int epoll_wait(uv__os390_epoll* ep, struct epoll_event *events, int maxevents, int timeout); +int epoll_file_close(int fd); + +/* utility functions */ +int nanosleep(const struct timespec* req, struct timespec* rem); +int scandir(const char* maindir, struct dirent*** namelist, + int (*filter)(const struct dirent *), + int (*compar)(const struct dirent **, + const struct dirent **)); +char *mkdtemp(char* path); + +#endif /* UV_OS390_SYSCALL_H_ */ diff --git a/src/unix/os390.c b/src/unix/os390.c index bcdbc4b6a..d3a9abfa6 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -20,6 +20,628 @@ */ #include "internal.h" +#include +#include +#include +#include +#include +#if defined(__clang__) +#include "csrsic.h" +#else +#include "//'SYS1.SAMPLIB(CSRSIC)'" +#endif + +#define CVT_PTR 0x10 +#define CSD_OFFSET 0x294 + +/* + Long-term average CPU service used by this logical partition, + in millions of service units per hour. If this value is above + the partition's defined capacity, the partition will be capped. + It is calculated using the physical CPU adjustment factor + (RCTPCPUA) so it may not match other measures of service which + are based on the logical CPU adjustment factor. It is available + if the hardware supports LPAR cluster. +*/ +#define RCTLACS_OFFSET 0xC4 + +/* 32-bit count of alive CPUs. This includes both CPs and IFAs */ +#define CSD_NUMBER_ONLINE_CPUS 0xD4 + +/* Address of system resources manager (SRM) control table */ +#define CVTOPCTP_OFFSET 0x25C + +/* Address of the RCT table */ +#define RMCTRCT_OFFSET 0xE4 + +/* Address of the rsm control and enumeration area. */ +#define CVTRCEP_OFFSET 0x490 + +/* + Number of frames currently available to system. + Excluded are frames backing perm storage, frames offline, and bad frames. +*/ +#define RCEPOOL_OFFSET 0x004 + +/* 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 + +/* Thread Entry constants */ +#define PGTH_CURRENT 1 +#define PGTH_LEN 26 +#define PGTHAPATH 0x20 +#pragma linkage(BPX4GTH, OS) +#pragma linkage(BPX1GTH, OS) + +typedef unsigned data_area_ptr_assign_type; + +typedef union { + struct { +#if defined(_LP64) + data_area_ptr_assign_type lower; +#endif + data_area_ptr_assign_type assign; + }; + char* deref; +} data_area_ptr; + + +void uv_loadavg(double avg[3]) { + /* TODO: implement the following */ + avg[0] = 0; + avg[1] = 0; + avg[2] = 0; +} + + +int uv__platform_loop_init(uv_loop_t* loop) { + uv__os390_epoll* ep; + + ep = epoll_create1(UV__EPOLL_CLOEXEC); + loop->ep = ep; + if (ep == NULL) + return -errno; + + return 0; +} + + +void uv__platform_loop_delete(uv_loop_t* loop) { + if (loop->ep != NULL) { + epoll_queue_close(loop->ep); + loop->ep = NULL; + } +} + + +uint64_t uv__hrtime(uv_clocktype_t type) { + struct timeval time; + gettimeofday(&time, NULL); + return (uint64_t) time.tv_sec * 1e9 + time.tv_usec * 1e3; +} + + +/* + Get the exe path using the thread entry information + in the address space. +*/ +static int getexe(const int pid, char* buf, size_t len) { + struct { + int pid; + int thid[2]; + char accesspid; + char accessthid; + char asid[2]; + char loginname[8]; + char flag; + char len; + } Input_data; + + union { + struct { + char gthb[4]; + int pid; + int thid[2]; + char accesspid; + char accessthid[3]; + int lenused; + int offsetProcess; + int offsetConTTY; + int offsetPath; + int offsetCommand; + int offsetFileData; + int offsetThread; + } Output_data; + char buf[2048]; + } Output_buf; + + struct Output_path_type { + char gthe[4]; + short int len; + char path[1024]; + }; + + int Input_length; + int Output_length; + void* Input_address; + void* Output_address; + struct Output_path_type* Output_path; + int rv; + int rc; + int rsn; + + Input_length = PGTH_LEN; + Output_length = sizeof(Output_buf); + Output_address = &Output_buf; + Input_address = &Input_data; + memset(&Input_data, 0, sizeof Input_data); + Input_data.flag |= PGTHAPATH; + Input_data.pid = pid; + Input_data.accesspid = PGTH_CURRENT; + +#ifdef _LP64 + BPX4GTH(&Input_length, + &Input_address, + &Output_length, + &Output_address, + &rv, + &rc, + &rsn); +#else + BPX1GTH(&Input_length, + &Input_address, + &Output_length, + &Output_address, + &rv, + &rc, + &rsn); +#endif + + if (rv == -1) { + errno = rc; + return -1; + } + + /* Check highest byte to ensure data availability */ + assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A'); + + /* Get the offset from the lowest 3 bytes */ + Output_path = (char*)(&Output_buf) + + (Output_buf.Output_data.offsetPath & 0x00FFFFFF); + + if (Output_path->len >= len) { + errno = ENOBUFS; + return -1; + } + + strncpy(buf, Output_path->path, len); + + return 0; +} + + +/* + * We could use a static buffer for the path manipulations that we need outside + * of the function, but this function could be called by multiple consumers and + * we don't want to potentially create a race condition in the use of snprintf. + * There is no direct way of getting the exe path in zOS - either through /procfs + * or through some libc APIs. The below approach is to parse the argv[0]'s pattern + * and use it in conjunction with PATH environment variable to craft one. + */ +int uv_exepath(char* buffer, size_t* size) { + int res; + char args[PATH_MAX]; + char abspath[PATH_MAX]; + size_t abspath_size; + int pid; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + pid = getpid(); + res = getexe(pid, args, sizeof(args)); + if (res < 0) + return -EINVAL; + + /* + * Possibilities for args: + * i) an absolute path such as: /home/user/myprojects/nodejs/node + * ii) a relative path such as: ./node or ../myprojects/nodejs/node + * iii) a bare filename such as "node", after exporting PATH variable + * to its location. + */ + + /* Case i) and ii) absolute or relative paths */ + if (strchr(args, '/') != NULL) { + if (realpath(args, abspath) != abspath) + return -errno; + + abspath_size = strlen(abspath); + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; + } else { + /* Case iii). Search PATH environment variable */ + char trypath[PATH_MAX]; + char* clonedpath = NULL; + char* token = NULL; + char* path = getenv("PATH"); + + if (path == NULL) + return -EINVAL; + + clonedpath = uv__strdup(path); + if (clonedpath == NULL) + return -ENOMEM; + + token = strtok(clonedpath, ":"); + while (token != NULL) { + snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); + if (realpath(trypath, abspath) == abspath) { + /* Check the match is executable */ + if (access(abspath, X_OK) == 0) { + abspath_size = strlen(abspath); + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + uv__free(clonedpath); + return 0; + } + } + token = strtok(NULL, ":"); + } + uv__free(clonedpath); + + /* Out of tokens (path entries), and no match found */ + return -EINVAL; + } +} + + +uint64_t uv_get_free_memory(void) { + uint64_t freeram; + + data_area_ptr cvt = {0}; + data_area_ptr rcep = {0}; + cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); + rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET); + freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4; + return freeram; +} + + +uint64_t uv_get_total_memory(void) { + uint64_t totalram; + + data_area_ptr cvt = {0}; + data_area_ptr rcep = {0}; + cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); + rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET); + totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4; + return totalram; +} + + +int uv_resident_set_memory(size_t* rss) { + W_PSPROC buf; + + memset(&buf, 0, sizeof(buf)); + if (w_getpsent(0, &buf, sizeof(W_PSPROC)) == -1) + return -EINVAL; + + *rss = buf.ps_size; + return 0; +} + + +int uv_uptime(double* uptime) { + struct utmpx u ; + struct utmpx *v; + time64_t t; + + u.ut_type = BOOT_TIME; + v = getutxid(&u); + if (v == NULL) + return -1; + *uptime = difftime64(time64(&t), v->ut_tv.tv_sec); + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + uv_cpu_info_t* cpu_info; + int result; + int idx; + siv1v2 info; + data_area_ptr cvt = {0}; + data_area_ptr csd = {0}; + data_area_ptr rmctrct = {0}; + data_area_ptr cvtopctp = {0}; + int cpu_usage_avg; + + cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR); + + csd.assign = *((data_area_ptr_assign_type *) (cvt.deref + CSD_OFFSET)); + cvtopctp.assign = *((data_area_ptr_assign_type *) (cvt.deref + CVTOPCTP_OFFSET)); + rmctrct.assign = *((data_area_ptr_assign_type *) (cvtopctp.deref + RMCTRCT_OFFSET)); + + *count = *((int*) (csd.deref + CSD_NUMBER_ONLINE_CPUS)); + cpu_usage_avg = *((unsigned short int*) (rmctrct.deref + RCTLACS_OFFSET)); + + *cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) + return -ENOMEM; + + cpu_info = *cpu_infos; + 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->cpu_times.user = cpu_usage_avg; + /* TODO: implement the following */ + cpu_info->cpu_times.sys = 0; + cpu_info->cpu_times.idle = 0; + cpu_info->cpu_times.irq = 0; + cpu_info->cpu_times.nice = 0; + ++cpu_info; + ++idx; + } + + return 0; +} + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + for (int i = 0; i < count; ++i) + uv__free(cpu_infos[i].model); + uv__free(cpu_infos); +} + + +static int uv__interface_addresses_v6(uv_interface_address_t** addresses, + int* count) { + uv_interface_address_t* address; + int sockfd; + int maxsize; + __net_ifconf6header_t ifc; + __net_ifconf6entry_t* ifr; + __net_ifconf6entry_t* p; + __net_ifconf6entry_t flg; + + *count = 0; + /* Assume maximum buffer size allowable */ + maxsize = 16384; + + if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) + return -errno; + + ifc.__nif6h_version = 1; + ifc.__nif6h_buflen = maxsize; + ifc.__nif6h_buffer = uv__calloc(1, maxsize);; + + if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) { + uv__close(sockfd); + return -errno; + } + + + *count = 0; + ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); + while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { + 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)) + continue; + + if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) + continue; + + ++(*count); + } + + /* Alloc the return interface structs */ + *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); + if (!(*addresses)) { + uv__close(sockfd); + return -ENOMEM; + } + address = *addresses; + + ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); + while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { + 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)) + continue; + + if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) + continue; + + /* 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); + + /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ + + address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0; + + address++; + } + + uv__close(sockfd); + return 0; +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + uv_interface_address_t* address; + int sockfd; + int maxsize; + struct ifconf ifc; + struct ifreq flg; + struct ifreq* ifr; + struct ifreq* p; + int count_v6; + + /* get the ipv6 addresses first */ + uv_interface_address_t* addresses_v6; + uv__interface_addresses_v6(&addresses_v6, &count_v6); + + /* now get the ipv4 addresses */ + *count = 0; + + /* Assume maximum buffer size allowable */ + maxsize = 16384; + + sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (0 > sockfd) + return -errno; + + ifc.ifc_req = uv__calloc(1, maxsize); + ifc.ifc_len = maxsize; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { + uv__close(sockfd); + return -errno; + } + +#define MAX(a,b) (((a)>(b))?(a):(b)) +#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) + + /* Count all up and running ipv4/ipv6 addresses */ + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return -errno; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + (*count)++; + } + + /* Alloc the return interface structs */ + *addresses = uv__malloc((*count + count_v6) * + sizeof(uv_interface_address_t)); + + if (!(*addresses)) { + uv__close(sockfd); + return -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); + + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return -ENOSYS; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + /* 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); + } + + address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; + address++; + } + +#undef ADDR_SIZE +#undef MAX + + uv__close(sockfd); + return 0; +} + + +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); +} + + +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); + + 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 ((int) events[i].fd == fd) + events[i].fd = -1; + + /* Remove the file descriptor from the epoll. */ + if (loop->ep != NULL) + epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy); +} + int uv__io_check_fd(uv_loop_t* loop, int fd) { struct pollfd p[1]; @@ -40,3 +662,218 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { return 0; } + + +void uv__fs_event_close(uv_fs_event_t* handle) { + UNREACHABLE(); +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + return -ENOSYS; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, + const char* filename, unsigned int flags) { + return -ENOSYS; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + return -ENOSYS; +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + static const int max_safe_timeout = 1789569; + struct epoll_event events[1024]; + struct epoll_event* pe; + struct epoll_event e; + int real_timeout; + QUEUE* q; + uv__io_t* w; + uint64_t base; + int count; + int nfds; + int fd; + int op; + int i; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + while (!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); + + assert(w->pevents != 0); + assert(w->fd >= 0); + + stream= container_of(w, uv_stream_t, io_watcher); + + assert(w->fd < (int) loop->nwatchers); + + e.events = w->pevents; + e.fd = w->fd; + + if (w->events == 0) + op = UV__EPOLL_CTL_ADD; + else + op = UV__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->ep, op, w->fd, &e)) { + if (errno != EEXIST) + abort(); + + assert(op == UV__EPOLL_CTL_ADD); + + /* We've reactivated a file descriptor that's been watched before. */ + if (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e)) + abort(); + } + + w->events = w->pevents; + } + + assert(timeout >= -1); + base = loop->time; + count = 48; /* Benchmarks suggest this gives the best throughput. */ + real_timeout = timeout; + int nevents = 0; + + nfds = 0; + for (;;) { + if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) + timeout = max_safe_timeout; + + nfds = epoll_wait(loop->ep, events, + ARRAY_SIZE(events), timeout); + + /* 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. + */ + base = loop->time; + SAVE_ERRNO(uv__update_time(loop)); + if (nfds == 0) { + assert(timeout != -1); + timeout = real_timeout - timeout; + if (timeout > 0) + continue; + + return; + } + + if (nfds == -1) { + + if (errno != EINTR) + abort(); + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + + 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->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->ep, UV__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; + + if (pe->events == POLLERR || pe->events == POLLHUP) + pe->events |= w->pevents & (POLLIN | POLLOUT); + + if (pe->events != 0) { + w->cb(loop, w, pe->events); + nevents++; + } + } + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; + + 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; + } +} + +char** uv_setup_args(int argc, char** argv) { + return argv; +} + + +int uv_set_process_title(const char* title) { + return ENOSYS; +} + + +int uv_get_process_title(char* buffer, size_t size) { + if (buffer == NULL || size == 0) + return -EINVAL; + + buffer[0] = '\0'; + return ENOSYS; +} diff --git a/src/unix/stream.c b/src/unix/stream.c index 86f4eb7a5..7059df16a 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -390,7 +390,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { int uv__stream_open(uv_stream_t* stream, int fd, int flags) { -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__MVS__) int enable; #endif @@ -409,7 +409,7 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { return -errno; } -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__MVS__) enable = 1; if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) && errno != ENOTSOCK && @@ -1194,6 +1194,30 @@ static void uv__read(uv_stream_t* stream) { return; } } + +#if defined(__MVS__) + if (is_ipc && msg.msg_controllen > 0) { + uv_buf_t blankbuf; + int nread; + struct iovec *old; + + blankbuf.base = 0; + blankbuf.len = 0; + old = msg.msg_iov; + msg.msg_iov = (struct iovec*) &blankbuf; + nread = 0; + do { + nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); + err = uv__stream_recv_cmsg(stream, &msg); + if (err != 0) { + stream->read_cb(stream, err, &buf); + msg.msg_iov = old; + return; + } + } while (nread == 0 && msg.msg_controllen > 0); + msg.msg_iov = old; + } +#endif stream->read_cb(stream, nread, &buf); /* Return if we didn't fill the buffer, there is no more data to read. */ diff --git a/uv.gyp b/uv.gyp index b969a8cd5..969423f82 100644 --- a/uv.gyp +++ b/uv.gyp @@ -17,6 +17,7 @@ 'defines': [ '_UNIX03_THREADS', '_UNIX03_SOURCE', + '_UNIX03_WITHDRAWN', '_OPEN_SYS_IF_EXT', '_OPEN_SYS_SOCK_IPV6', '_OPEN_MSGQ_EXT', @@ -28,6 +29,7 @@ 'PATH_MAX=255' ], 'cflags': [ '-qxplink' ], + 'ldflags': [ '-qxplink' ], }] ], }], @@ -305,8 +307,9 @@ ['OS=="zos"', { 'sources': [ 'src/unix/pthread-fixes.c', - 'src/unix/pthread-barrier.c' - 'src/unix/os390.c' + 'src/unix/pthread-barrier.c', + 'src/unix/os390.c', + 'src/unix/os390-syscalls.c' ] }], ] From c722b8d2784c8a9f99c810c0263e6833e480ec7b Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Fri, 20 Jan 2017 14:05:42 +0100 Subject: [PATCH 309/632] doc: add repitition qualifier to version regexs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the libuv version is reported as unknown on the website. This is because the UV_VERSION_MINOR is no longer a single digit and the regex is not getting a match for the minor number. This commit makes the version regexs capture multiple digit numbers. PR-URL: https://github.com/libuv/libuv/pull/1205 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- docs/src/conf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/conf.py b/docs/src/conf.py index b9eaa1374..3f8689d2e 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -21,11 +21,11 @@ def get_libuv_version(): with open('../../include/uv-version.h') as f: data = f.read() try: - m = re.search(r"""^#define UV_VERSION_MAJOR (\d)$""", data, re.MULTILINE) + m = re.search(r"""^#define UV_VERSION_MAJOR (\d+)$""", data, re.MULTILINE) major = int(m.group(1)) - m = re.search(r"""^#define UV_VERSION_MINOR (\d)$""", data, re.MULTILINE) + m = re.search(r"""^#define UV_VERSION_MINOR (\d+)$""", data, re.MULTILINE) minor = int(m.group(1)) - m = re.search(r"""^#define UV_VERSION_PATCH (\d)$""", data, re.MULTILINE) + m = re.search(r"""^#define UV_VERSION_PATCH (\d+)$""", data, re.MULTILINE) patch = int(m.group(1)) m = re.search(r"""^#define UV_VERSION_IS_RELEASE (\d)$""", data, re.MULTILINE) is_release = int(m.group(1)) From c5bb773bddc778baceb2621c89ac9b230b9b30e6 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Fri, 20 Jan 2017 17:57:33 -0500 Subject: [PATCH 310/632] zos: use gyp OS label "os390" on z/OS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is what `uname` on the system actually displays. Also, other gyp based projects use 'os390' PR-URL: https://github.com/libuv/libuv/pull/1207 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- common.gypi | 4 ++-- uv.gyp | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/common.gypi b/common.gypi index 44db701d6..470b73385 100644 --- a/common.gypi +++ b/common.gypi @@ -35,7 +35,7 @@ 'OTHER_CFLAGS': [ '-Wno-strict-aliasing' ], }, 'conditions': [ - ['OS != "zos"', { + ['OS != "os390"', { 'cflags': [ '-O0', '-fwrapv' ] }], ['OS == "android"', { @@ -154,7 +154,7 @@ 'cflags': [ '-pthreads' ], 'ldflags': [ '-pthreads' ], }], - [ 'OS not in "solaris android zos"', { + [ 'OS not in "solaris android os390"', { 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], diff --git a/uv.gyp b/uv.gyp index 969423f82..3e9063ecd 100644 --- a/uv.gyp +++ b/uv.gyp @@ -10,10 +10,10 @@ ['OS=="solaris"', { 'cflags': [ '-pthreads' ], }], - ['OS not in "solaris android zos"', { + ['OS not in "solaris android os390"', { 'cflags': [ '-pthread' ], }], - ['OS in "zos"', { + ['OS in "os390"', { 'defines': [ '_UNIX03_THREADS', '_UNIX03_SOURCE', @@ -172,10 +172,10 @@ ['OS=="solaris"', { 'ldflags': [ '-pthreads' ], }], - [ 'OS=="zos" and uv_library=="shared_library"', { + [ 'OS=="os390" and uv_library=="shared_library"', { 'ldflags': [ '-Wl,DLL' ], }], - ['OS != "solaris" and OS != "android" and OS != "zos"', { + ['OS != "solaris" and OS != "android" and OS != "os390"', { 'ldflags': [ '-pthread' ], }], ], @@ -183,14 +183,14 @@ 'conditions': [ ['uv_library=="shared_library"', { 'conditions': [ - ['OS=="zos"', { + ['OS=="os390"', { 'cflags': [ '-qexportall' ], }, { 'cflags': [ '-fPIC' ], }], ], }], - ['uv_library=="shared_library" and OS!="mac" and OS!="zos"', { + ['uv_library=="shared_library" and OS!="mac" and OS!="os390"', { # This will cause gyp to set soname # Must correspond with UV_VERSION_MAJOR # in include/uv-version.h @@ -201,7 +201,7 @@ [ 'OS in "linux mac ios android"', { 'sources': [ 'src/unix/proctitle.c' ], }], - [ 'OS != "zos"', { + [ 'OS != "os390"', { 'cflags': [ '-fvisibility=hidden', '-g', @@ -224,7 +224,7 @@ '_DARWIN_UNLIMITED_SELECT=1', ] }], - [ 'OS!="mac" and OS!="zos"', { + [ 'OS!="mac" and OS!="os390"', { # Enable on all platforms except OS X. The antique gcc/clang that # ships with Xcode emits waaaay too many false positives. 'cflags': [ '-Wstrict-aliasing' ], @@ -304,7 +304,7 @@ ['uv_library=="shared_library"', { 'defines': [ 'BUILDING_UV_SHARED=1' ] }], - ['OS=="zos"', { + ['OS=="os390"', { 'sources': [ 'src/unix/pthread-fixes.c', 'src/unix/pthread-barrier.c', @@ -470,7 +470,7 @@ 'test/runner-unix.h', ], 'conditions': [ - [ 'OS != "zos"', { + [ 'OS != "os390"', { 'defines': [ '_GNU_SOURCE' ], 'cflags': [ '-Wno-long-long' ], 'xcode_settings': { @@ -499,7 +499,7 @@ ['uv_library=="shared_library"', { 'defines': [ 'USING_UV_SHARED=1' ], 'conditions': [ - [ 'OS == "zos"', { + [ 'OS == "os390"', { 'cflags': [ '-Wc,DLL' ], }], ], @@ -560,7 +560,7 @@ ['uv_library=="shared_library"', { 'defines': [ 'USING_UV_SHARED=1' ], 'conditions': [ - [ 'OS == "zos"', { + [ 'OS == "os390"', { 'cflags': [ '-Wc,DLL' ], }], ], From d6427e4bebb540201f7fc04ae6270238936f5d4f Mon Sep 17 00:00:00 2001 From: Howard Hellyer Date: Thu, 12 Jan 2017 04:50:17 -0500 Subject: [PATCH 311/632] aix: enable uv_get/set_process_title This patch enables querying and setting the process title on AIX. libuv takes ownership of the memory for argv and returns a deep copy of the array and its contents. It also enables the process_title test case. The process title can be changed on AIX but is handled differently to Linux/Mac. Commands like ps read the original argv array passed to the process instead of the memory at argv[0]. To change the process title we need to update argv[0] to point at a new string and set argv[1] to NULL (if it exists). This means the process title can be set to a string of any length. PR-URL: https://github.com/libuv/libuv/pull/1187 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- docs/src/misc.rst | 6 ++- src/unix/aix.c | 79 ++++++++++++++++++++++++++++++++++++++- test/test-process-title.c | 2 +- 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 95237f49c..719346946 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -192,7 +192,11 @@ API .. c:function:: int uv_set_process_title(const char* title) - Sets the current process title. + Sets the current process title. On platforms with a fixed size buffer for the + process title the contents of `title` will be copied to the buffer and + truncated if larger than the available space. Other platforms will return + `UV_ENOMEM` if they cannot allocate enough space to duplicate the contents of + `title`. .. c:function:: int uv_resident_set_memory(size_t* rss) diff --git a/src/unix/aix.c b/src/unix/aix.c index 652cd980f..80d63301a 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -64,6 +64,11 @@ #define RDWR_BUF_SIZE 4096 #define EQ(a,b) (strcmp(a,b) == 0) +static void* args_mem = NULL; +static char** process_argv = NULL; +static int process_argc = 0; +static char* process_title_ptr = NULL; + int uv__platform_loop_init(uv_loop_t* loop) { loop->fs_fd = -1; @@ -881,24 +886,94 @@ void uv__fs_event_close(uv_fs_event_t* handle) { char** uv_setup_args(int argc, char** argv) { - return argv; + char** new_argv; + size_t size; + char* s; + int i; + + if (argc <= 0) + return argv; + + /* Save the original pointer to argv. + * AIX uses argv to read the process name. + * (Not the memory pointed to by argv[0..n] as on Linux.) + */ + process_argv = argv; + process_argc = argc; + + /* Calculate how much memory we need for the argv strings. */ + size = 0; + for (i = 0; i < argc; i++) + size += strlen(argv[i]) + 1; + + /* Add space for the argv pointers. */ + size += (argc + 1) * sizeof(char*); + + new_argv = uv__malloc(size); + if (new_argv == NULL) + return argv; + args_mem = new_argv; + + /* Copy over the strings and set up the pointer table. */ + s = (char*) &new_argv[argc + 1]; + for (i = 0; i < argc; i++) { + size = strlen(argv[i]) + 1; + memcpy(s, argv[i], size); + new_argv[i] = s; + s += size; + } + new_argv[i] = NULL; + + return new_argv; } int uv_set_process_title(const char* title) { + char* new_title; + + /* We cannot free this pointer when libuv shuts down, + * the process may still be using it. + */ + new_title = uv__strdup(title); + if (new_title == NULL) + return -ENOMEM; + + /* If this is the first time this is set, + * don't free and set argv[1] to NULL. + */ + if (process_title_ptr != NULL) + uv__free(process_title_ptr); + + process_title_ptr = new_title; + + process_argv[0] = process_title_ptr; + if (process_argc > 1) + process_argv[1] = NULL; + return 0; } int uv_get_process_title(char* buffer, size_t size) { + size_t len; + len = strlen(process_argv[0]); if (buffer == NULL || size == 0) return -EINVAL; + else if (size <= len) + return -ENOBUFS; + + memcpy(buffer, process_argv[0], len + 1); - buffer[0] = '\0'; return 0; } +UV_DESTRUCTOR(static void free_args_mem(void)) { + uv__free(args_mem); /* Keep valgrind happy. */ + args_mem = NULL; +} + + int uv_resident_set_memory(size_t* rss) { char pp[64]; psinfo_t psinfo; diff --git a/test/test-process-title.c b/test/test-process-title.c index 21ab0ed4f..96fe719b5 100644 --- a/test/test-process-title.c +++ b/test/test-process-title.c @@ -60,7 +60,7 @@ static void uv_get_process_title_edge_cases() { TEST_IMPL(process_title) { -#if defined(__sun) || defined(_AIX) || defined(__MVS__) +#if defined(__sun) || defined(__MVS__) RETURN_SKIP("uv_(get|set)_process_title is not implemented."); #else /* Check for format string vulnerabilities. */ From f9484cf5152ce89bba3d52aea661e6f1fff27e54 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Mon, 23 Jan 2017 11:02:23 -0500 Subject: [PATCH 312/632] zos: use built-in proctitle implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use built-in proctitle implementation because there is no such thing as a process title on zOS. PR-URL: https://github.com/libuv/libuv/pull/1208 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/os390.c | 18 ++---------------- src/unix/proctitle.c | 6 ++++++ test/test-process-title.c | 2 +- uv.gyp | 2 +- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index d3a9abfa6..be325a923 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -860,20 +860,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } } -char** uv_setup_args(int argc, char** argv) { - return argv; -} - - -int uv_set_process_title(const char* title) { - return ENOSYS; -} - - -int uv_get_process_title(char* buffer, size_t size) { - if (buffer == NULL || size == 0) - return -EINVAL; - - buffer[0] = '\0'; - return ENOSYS; +void uv__set_process_title(const char* title) { + /* do nothing */ } diff --git a/src/unix/proctitle.c b/src/unix/proctitle.c index 08d875f7a..9160f7eaf 100644 --- a/src/unix/proctitle.c +++ b/src/unix/proctitle.c @@ -48,9 +48,15 @@ char** uv_setup_args(int argc, char** argv) { for (i = 0; i < argc; i++) size += strlen(argv[i]) + 1; +#if defined(__MVS__) + /* argv is not adjacent. So just use argv[0] */ + process_title.str = argv[0]; + process_title.len = strlen(argv[0]); +#else process_title.str = argv[0]; process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0]; assert(process_title.len + 1 == size); /* argv memory should be adjacent. */ +#endif /* Add space for the argv pointers. */ size += (argc + 1) * sizeof(char*); diff --git a/test/test-process-title.c b/test/test-process-title.c index 96fe719b5..5d5ede9d6 100644 --- a/test/test-process-title.c +++ b/test/test-process-title.c @@ -60,7 +60,7 @@ static void uv_get_process_title_edge_cases() { TEST_IMPL(process_title) { -#if defined(__sun) || defined(__MVS__) +#if defined(__sun) RETURN_SKIP("uv_(get|set)_process_title is not implemented."); #else /* Check for format string vulnerabilities. */ diff --git a/uv.gyp b/uv.gyp index 3e9063ecd..60fd5c126 100644 --- a/uv.gyp +++ b/uv.gyp @@ -198,7 +198,7 @@ }], ], }], - [ 'OS in "linux mac ios android"', { + [ 'OS in "linux mac ios android os390"', { 'sources': [ 'src/unix/proctitle.c' ], }], [ 'OS != "os390"', { From f35674fe7f9560a5cc39c99e6d396cdcfda1ecfe Mon Sep 17 00:00:00 2001 From: Chris Araman Date: Fri, 27 Jan 2017 13:15:54 -0800 Subject: [PATCH 313/632] Revert "darwin: use clock_gettime in macOS 10.12" This reverts commit f8d4805087944cb8543d98109f5f83f4938eb4b5, which causes run-time link errors when compiled with macOS 10.12 SDK, but run on 10.11 or earlier. Refs: https://github.com/libuv/libuv/pull/1073 PR-URL: https://github.com/libuv/libuv/pull/1202 Reviewed-By: Colin Ihrig --- src/unix/darwin.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/unix/darwin.c b/src/unix/darwin.c index b1ffbc37b..cf95da216 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -34,12 +34,8 @@ #include /* _NSGetExecutablePath */ #include #include -#include #include /* sysconf */ -#undef NANOSEC -#define NANOSEC ((uint64_t) 1e9) - int uv__platform_loop_init(uv_loop_t* loop) { loop->cf_state = NULL; @@ -57,11 +53,6 @@ void uv__platform_loop_delete(uv_loop_t* loop) { uint64_t uv__hrtime(uv_clocktype_t type) { -#ifdef MAC_OS_X_VERSION_10_12 - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); -#else static mach_timebase_info_data_t info; if ((ACCESS_ONCE(uint32_t, info.numer) == 0 || @@ -70,7 +61,6 @@ uint64_t uv__hrtime(uv_clocktype_t type) { abort(); return mach_absolute_time() * info.numer / info.denom; -#endif } From 67a5c86b86d97ec16d89ef9aee6951094230dede Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sun, 29 Jan 2017 22:45:06 -0800 Subject: [PATCH 314/632] win,test: don't write uninitialized buffer to tty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes an issue where the Windows-only tty_large_write attempts to write an uninitialized buffer to the console. PR-URL: https://github.com/libuv/libuv/pull/1212 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno --- test/test-tty.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test-tty.c b/test/test-tty.c index d1f7deb23..6fc2c95c9 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -287,6 +287,9 @@ TEST_IMPL(tty_large_write) { r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ ASSERT(r == 0); + memset(dummy, '.', sizeof(dummy) - 1); + dummy[sizeof(dummy) - 1] = '\n'; + bufs[0] = uv_buf_init(dummy, sizeof(dummy)); r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); From 12bfad9c6d5c0ed51304a89781dd841fffc3dd2b Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Mon, 16 Jan 2017 18:38:06 +0000 Subject: [PATCH 315/632] win: define ERROR_ELEVATION_REQUIRED for MinGW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs: https://github.com/libuv/libuv/issues/1194 PR-URL: https://github.com/libuv/libuv/pull/1195 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/win/winapi.h | 4 ++++ test/test-error.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/win/winapi.h b/src/win/winapi.h index 341fcd084..9401676fb 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4606,6 +4606,10 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile) #endif /* from winerror.h */ +#ifndef ERROR_ELEVATION_REQUIRED +# define ERROR_ELEVATION_REQUIRED 740 +#endif + #ifndef ERROR_SYMLINK_NOT_SUPPORTED # define ERROR_SYMLINK_NOT_SUPPORTED 1464 #endif diff --git a/test/test-error.c b/test/test-error.c index ff53eb1d7..a2d559a4e 100644 --- a/test/test-error.c +++ b/test/test-error.c @@ -21,6 +21,9 @@ #include "uv.h" #include "task.h" +#if defined(_WIN32) +# include "../src/win/winapi.h" +#endif #include #include From fb0f87b6d705397160288232a297ea9785fa7258 Mon Sep 17 00:00:00 2001 From: Gireesh Punathil Date: Fri, 2 Dec 2016 22:28:22 -0500 Subject: [PATCH 316/632] aix: re-enable fs watch facility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On AIX, watch feature depends on AHAFS based Event infrastructure. While in principle the watch use case is same across platforms, there are subtle differences in the way AIX deals with this, with few behavioral changes (external). This commit opens up the AIX code for watch feature which was masked under a macro HAVE_SYS_AHAFS_EVPRODS_H and addresses an assertion failure on folder watch. PR-URL: https://github.com/libuv/libuv/pull/1156 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Michael Dawson --- Makefile.am | 6 +++++- src/unix/aix.c | 7 +++++++ uv.gyp | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 2637ef3f7..036464e71 100644 --- a/Makefile.am +++ b/Makefile.am @@ -316,7 +316,11 @@ test_run_tests_CFLAGS += -D_UNIX03_THREADS \ endif if AIX -libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT -D_THREAD_SAFE +libuv_la_CFLAGS += -D_ALL_SOURCE \ + -D_XOPEN_SOURCE=500 \ + -D_LINUX_SOURCE_COMPAT \ + -D_THREAD_SAFE \ + -DHAVE_SYS_AHAFS_EVPRODS_H include_HEADERS += include/uv-aix.h libuv_la_SOURCES += src/unix/aix.c endif diff --git a/src/unix/aix.c b/src/unix/aix.c index 80d63301a..1d2cd4a80 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -758,6 +758,13 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file"); + /* In file / directory move cases, AIX Event infrastructure + * produces a second event with no data. + * Ignore it and return gracefully. + */ + if(bytes == 0) + return; + /* Parse the data */ if(bytes > 0) rc = uv__parse_data(result_data, &events, handle); diff --git a/uv.gyp b/uv.gyp index 60fd5c126..49d5d22f9 100644 --- a/uv.gyp +++ b/uv.gyp @@ -277,6 +277,7 @@ '_XOPEN_SOURCE=500', '_LINUX_SOURCE_COMPAT', '_THREAD_SAFE', + 'HAVE_SYS_AHAFS_EVPRODS_H', ], 'link_settings': { 'libraries': [ From 7452ef4e06a4f99ee26b694c65476401534f2725 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 31 Jan 2017 19:38:56 -0500 Subject: [PATCH 317/632] 2017.02.02, Version 1.11.0 (Stable) Changes since version 1.10.2: * Now working on version 1.10.3 (cjihrig) * win: added fcntl.h to uv-win.h (Michele Caini) * unix: move function call out of assert (jBarz) * fs: cleanup uv__fs_scandir (Santiago Gimeno) * fs: fix crash in uv_fs_scandir_next (muflub) * win,signal: fix potential deadlock (Bartosz Sosnowski) * unix: use async-signal safe functions between fork and exec (jBarz) * sunos: fix SUNOS_NO_IFADDRS build (Ben Noordhuis) * zos: make platform functional (John Barboza) * doc: add repitition qualifier to version regexs (Daniel Bevenius) * zos: use gyp OS label "os390" on z/OS (John Barboza) * aix: enable uv_get/set_process_title (Howard Hellyer) * zos: use built-in proctitle implementation (John Barboza) * Revert "darwin: use clock_gettime in macOS 10.12" (Chris Araman) * win,test: don't write uninitialized buffer to tty (Bert Belder) * win: define ERROR_ELEVATION_REQUIRED for MinGW (Richard Lau) * aix: re-enable fs watch facility (Gireesh Punathil) --- .mailmap | 1 + AUTHORS | 5 +++++ ChangeLog | 39 +++++++++++++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 8 ++++---- 6 files changed, 51 insertions(+), 6 deletions(-) diff --git a/.mailmap b/.mailmap index 4966caf5f..8acf8fecd 100644 --- a/.mailmap +++ b/.mailmap @@ -1,6 +1,7 @@ Aaron Bieber Alan Gutierrez Andrius Bentkus +Bert Belder Bert Belder Bert Belder Brandon Philips diff --git a/AUTHORS b/AUTHORS index 49c8e17f2..4719d2368 100644 --- a/AUTHORS +++ b/AUTHORS @@ -279,3 +279,8 @@ Philippe Laferriere Will Speak Hitesh Kanwathirtha Eric Sciple +jBarz +muflub +Daniel Bevenius +Howard Hellyer +Chris Araman diff --git a/ChangeLog b/ChangeLog index d865f2266..a795a4d22 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +2017.02.02, Version 1.11.0 (Stable) + +Changes since version 1.10.2: + +* Now working on version 1.10.3 (cjihrig) + +* win: added fcntl.h to uv-win.h (Michele Caini) + +* unix: move function call out of assert (jBarz) + +* fs: cleanup uv__fs_scandir (Santiago Gimeno) + +* fs: fix crash in uv_fs_scandir_next (muflub) + +* win,signal: fix potential deadlock (Bartosz Sosnowski) + +* unix: use async-signal safe functions between fork and exec (jBarz) + +* sunos: fix SUNOS_NO_IFADDRS build (Ben Noordhuis) + +* zos: make platform functional (John Barboza) + +* doc: add repitition qualifier to version regexs (Daniel Bevenius) + +* zos: use gyp OS label "os390" on z/OS (John Barboza) + +* aix: enable uv_get/set_process_title (Howard Hellyer) + +* zos: use built-in proctitle implementation (John Barboza) + +* Revert "darwin: use clock_gettime in macOS 10.12" (Chris Araman) + +* win,test: don't write uninitialized buffer to tty (Bert Belder) + +* win: define ERROR_ELEVATION_REQUIRED for MinGW (Richard Lau) + +* aix: re-enable fs watch facility (Gireesh Punathil) + + 2017.01.10, Version 1.10.2 (Stable), cb9f579a454b8db592030ffa274ae58df78dbe20 Changes since version 1.10.1: diff --git a/appveyor.yml b/appveyor.yml index 632941378..e8e79f051 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.10.2.build{build} +version: v1.11.0.build{build} install: - cinst -y nsis diff --git a/configure.ac b/configure.ac index abaf97177..360652198 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.10.2], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.11.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 80f4ace0c..cf0004879 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 10 -#define UV_VERSION_PATCH 3 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 11 +#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 60823103332df5732dcbe92535ceb3aa916084c9 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 31 Jan 2017 19:38:57 -0500 Subject: [PATCH 318/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index a795a4d22..da4c3b13f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017.02.02, Version 1.11.0 (Stable) +2017.02.02, Version 1.11.0 (Stable), 7452ef4e06a4f99ee26b694c65476401534f2725 Changes since version 1.10.2: From c42d31ba53dba89b27104a9cdbe86d5894eb6c9e Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 31 Jan 2017 19:50:51 -0500 Subject: [PATCH 319/632] Now working on version 1.11.1 --- 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 cf0004879..e16580903 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 11 -#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 c355c8b1a64f155a4bcfed748b45e6f43cb4dc23 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 6 Feb 2017 15:25:12 +0100 Subject: [PATCH 320/632] test: fix tests on OpenBSD It fixes `process_title`, `poll_bad_fdtype` and `poll_nested_kqueue` tests. Fixes: https://github.com/libuv/libuv/issues/1216 PR-URL: https://github.com/libuv/libuv/pull/1218 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/unix/internal.h | 3 ++- src/unix/openbsd.c | 2 +- test/test-poll.c | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/unix/internal.h b/src/unix/internal.h index 1188e8fe7..b48f8fa59 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -162,7 +162,8 @@ struct uv__stream_queued_fds_s { defined(__DragonFly__) || \ defined(__FreeBSD__) || \ defined(__FreeBSD_kernel__) || \ - defined(__linux__) + defined(__linux__) || \ + defined(__OpenBSD__) #define uv__cloexec uv__cloexec_ioctl #define uv__nonblock uv__nonblock_ioctl #else diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index 909288cc8..ac28b690d 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -163,7 +163,7 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { uv__free(process_title); process_title = uv__strdup(title); - setproctitle(title); + setproctitle("%s", title); return 0; } diff --git a/test/test-poll.c b/test/test-poll.c index 6c1f98b7e..71948dee7 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -594,7 +594,8 @@ 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(__FreeBSD_kernel__) && \ + !defined(__OpenBSD__) uv_poll_t poll_handle; int fd; From 309d603382159eacdf52cbf0fa936deb60552d32 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 7 Feb 2017 18:03:20 +0100 Subject: [PATCH 321/632] test: fix -Wformat warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Substitute the `z` length modifier with `l` to avoid warnings, as the `z` modifier is defined in the C99 standard. PR-URL: https://github.com/libuv/libuv/pull/1220 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- test/test-threadpool-cancel.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test-threadpool-cancel.c b/test/test-threadpool-cancel.c index 917f5f475..dd13d8ae4 100644 --- a/test/test-threadpool-cancel.c +++ b/test/test-threadpool-cancel.c @@ -60,7 +60,10 @@ static void saturate_threadpool(void) { char buf[64]; size_t i; - snprintf(buf, sizeof(buf), "UV_THREADPOOL_SIZE=%zu", ARRAY_SIZE(pause_reqs)); + snprintf(buf, + sizeof(buf), + "UV_THREADPOOL_SIZE=%lu", + (unsigned long)ARRAY_SIZE(pause_reqs)); putenv(buf); loop = uv_default_loop(); From 02dcde08386441d5a89dbcb602a1ad367a506cc0 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 9 Feb 2017 11:41:36 -0800 Subject: [PATCH 322/632] win,fs: avoid double freeing uv_fs_event_t.dirw Set `dirw` to `pathw` after `uv_fs_event_start` is known to be completed successfully. Fixes: https://github.com/libuv/libuv/issues/1221 PR-URL: https://github.com/libuv/libuv/pull/1222 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- src/win/fs-event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 03e4adc05..05fc1d016 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -188,7 +188,6 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (is_path_dir) { /* path is a directory, so that's the directory that we will watch. */ - handle->dirw = pathw; dir_to_watch = pathw; } else { /* @@ -274,6 +273,8 @@ int uv_fs_event_start(uv_fs_event_t* handle, goto error; } + assert(is_path_dir ? pathw != NULL : pathw == NULL); + handle->dirw = pathw; handle->req_pending = 1; return 0; From 52ae826492f50f151138ed115faa5e0ac8c803ce Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Wed, 15 Feb 2017 00:44:41 -0500 Subject: [PATCH 323/632] unix: remove unused code in `uv__io_start` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code path in `uv__io_start` cannot be reached because `pevents` is always non-zero at that point. PR-URL: https://github.com/libuv/libuv/pull/1227 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis --- src/unix/core.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index 1ec549ccc..9ef713491 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -839,13 +839,8 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { * every tick of the event loop but the other backends allow us to * short-circuit here if the event mask is unchanged. */ - if (w->events == w->pevents) { - if (w->events == 0 && !QUEUE_EMPTY(&w->watcher_queue)) { - QUEUE_REMOVE(&w->watcher_queue); - QUEUE_INIT(&w->watcher_queue); - } + if (w->events == w->pevents) return; - } #endif if (QUEUE_EMPTY(&w->watcher_queue)) From 45616f542da523b3d87a8d379bb116ffc3a97845 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sun, 23 Oct 2016 14:47:31 +0200 Subject: [PATCH 324/632] signal: add uv_signal_start_oneshot method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It behaves as `uv_signal_start` but it resets the signal handler as soon as the signal is received. Fixes: https://github.com/libuv/libuv/issues/1104 PR-URL: https://github.com/libuv/libuv/pull/1106 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Bartosz Sosnowski --- docs/src/signal.rst | 7 +++ include/uv.h | 3 + src/unix/signal.c | 63 +++++++++++++++++-- src/uv-common.h | 11 ++-- src/win/signal.c | 35 ++++++++++- test/test-list.h | 4 ++ test/test-signal.c | 146 +++++++++++++++++++++++++++++++++++++++++--- 7 files changed, 250 insertions(+), 19 deletions(-) diff --git a/docs/src/signal.rst b/docs/src/signal.rst index dc1223b90..5b3b352bd 100644 --- a/docs/src/signal.rst +++ b/docs/src/signal.rst @@ -70,6 +70,13 @@ API Start the handle with the given callback, watching for the given signal. +.. c:function:: int uv_signal_start_oneshot(uv_signal_t* signal, uv_signal_cb cb, int signum) + + .. versionadded:: 1.12.0 + + Same functionality as :c:func:`uv_signal_start` but the signal handler is reset the moment + the signal is received. + .. c:function:: int uv_signal_stop(uv_signal_t* signal) Stop the handle, the callback will no longer be called. diff --git a/include/uv.h b/include/uv.h index 31f09f0f6..e5230bb50 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1324,6 +1324,9 @@ UV_EXTERN int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle); UV_EXTERN int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum); +UV_EXTERN int uv_signal_start_oneshot(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum); UV_EXTERN int uv_signal_stop(uv_signal_t* handle); UV_EXTERN void uv_loadavg(double avg[3]); diff --git a/src/unix/signal.c b/src/unix/signal.c index dbd8f8644..63032dcb7 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -38,9 +38,14 @@ RB_HEAD(uv__signal_tree_s, uv_signal_s); static int uv__signal_unlock(void); +static int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot); static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events); 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 uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT; @@ -122,6 +127,7 @@ static uv_signal_t* uv__signal_first_handle(int signum) { uv_signal_t* handle; lookup.signum = signum; + lookup.flags = 0; lookup.loop = NULL; handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup); @@ -174,7 +180,7 @@ static void uv__signal_handler(int signum) { } -static int uv__signal_register_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; @@ -183,6 +189,7 @@ static int uv__signal_register_handler(int signum) { if (sigfillset(&sa.sa_mask)) abort(); sa.sa_handler = uv__signal_handler; + sa.sa_flags = oneshot ? SA_RESETHAND : 0; /* XXX save old action so we can restore it later on? */ if (sigaction(signum, &sa, NULL)) @@ -287,8 +294,24 @@ void uv__signal_close(uv_signal_t* handle) { int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + return uv__signal_start(handle, signal_cb, signum, 0); +} + + +int uv_signal_start_oneshot(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum) { + return uv__signal_start(handle, signal_cb, signum, 1); +} + + +static int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot) { sigset_t saved_sigmask; int err; + uv_signal_t* first_handle; assert(!uv__is_closing(handle)); @@ -318,9 +341,12 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { /* If at this point there are no active signal watchers for this signum (in * any of the loops), it's time to try and register a handler for it here. + * Also in case there's only one-shot handlers and a regular handler comes in. */ - if (uv__signal_first_handle(signum) == NULL) { - err = uv__signal_register_handler(signum); + first_handle = uv__signal_first_handle(signum); + if (first_handle == NULL || + (!oneshot && (first_handle->flags & UV__SIGNAL_ONE_SHOT))) { + err = uv__signal_register_handler(signum, oneshot); if (err) { /* Registering the signal handler failed. Must be an invalid signal. */ uv__signal_unlock_and_unblock(&saved_sigmask); @@ -329,6 +355,9 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { } handle->signum = signum; + if (oneshot) + handle->flags |= UV__SIGNAL_ONE_SHOT; + RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle); uv__signal_unlock_and_unblock(&saved_sigmask); @@ -390,6 +419,9 @@ static void uv__signal_event(uv_loop_t* loop, handle->dispatched_signals++; + if (handle->flags & UV__SIGNAL_ONE_SHOT) + uv__signal_stop(handle); + /* If uv_close was called while there were caught signals that were not * yet dispatched, the uv__finish_close was deferred. Make close pending * now if this has happened. @@ -414,12 +446,22 @@ static void uv__signal_event(uv_loop_t* loop, static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { + int f1; + int f2; /* Compare signums first so all watchers with the same signnum end up * adjacent. */ if (w1->signum < w2->signum) return -1; if (w1->signum > w2->signum) return 1; + /* Handlers without UV__SIGNAL_ONE_SHOT set will come first, so if the first + * handler returned is a one-shot handler, the rest will be too. + */ + f1 = w1->flags & UV__SIGNAL_ONE_SHOT; + f2 = w2->flags & UV__SIGNAL_ONE_SHOT; + if (f1 < f2) return -1; + if (f1 > f2) return 1; + /* Sort by loop pointer, so we can easily look up the first item after * { .signum = x, .loop = NULL }. */ @@ -443,6 +485,10 @@ int uv_signal_stop(uv_signal_t* handle) { static void uv__signal_stop(uv_signal_t* handle) { uv_signal_t* removed_handle; sigset_t saved_sigmask; + uv_signal_t* first_handle; + int rem_oneshot; + int first_oneshot; + int ret; /* If the watcher wasn't started, this is a no-op. */ if (handle->signum == 0) @@ -457,8 +503,17 @@ static void uv__signal_stop(uv_signal_t* handle) { /* Check if there are other active signal watchers observing this signal. If * not, unregister the signal handler. */ - if (uv__signal_first_handle(handle->signum) == NULL) + first_handle = uv__signal_first_handle(handle->signum); + if (first_handle == NULL) { uv__signal_unregister_handler(handle->signum); + } else { + rem_oneshot = handle->flags & UV__SIGNAL_ONE_SHOT; + first_oneshot = first_handle->flags & UV__SIGNAL_ONE_SHOT; + if (first_oneshot && !rem_oneshot) { + ret = uv__signal_register_handler(handle->signum, 1); + assert(ret == 0); + } + } uv__signal_unlock_and_unblock(&saved_sigmask); diff --git a/src/uv-common.h b/src/uv-common.h index 27902fdf8..b2b98e3bf 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -55,16 +55,19 @@ extern int snprintf(char*, size_t, const char*, ...); #ifndef _WIN32 enum { + UV__SIGNAL_ONE_SHOT = 0x80000, /* On signal reception remove sighandler */ UV__HANDLE_INTERNAL = 0x8000, UV__HANDLE_ACTIVE = 0x4000, UV__HANDLE_REF = 0x2000, UV__HANDLE_CLOSING = 0 /* no-op on unix */ }; #else -# define UV__HANDLE_INTERNAL 0x80 -# define UV__HANDLE_ACTIVE 0x40 -# define UV__HANDLE_REF 0x20 -# define UV__HANDLE_CLOSING 0x01 +# define UV__SIGNAL_ONE_SHOT_DISPATCHED 0x200 +# define UV__SIGNAL_ONE_SHOT 0x100 +# define UV__HANDLE_INTERNAL 0x80 +# define UV__HANDLE_ACTIVE 0x40 +# define UV__HANDLE_REF 0x20 +# define UV__HANDLE_CLOSING 0x01 #endif int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); diff --git a/src/win/signal.c b/src/win/signal.c index af7974c36..571563cb2 100644 --- a/src/win/signal.c +++ b/src/win/signal.c @@ -34,6 +34,11 @@ static CRITICAL_SECTION uv__signal_lock; static BOOL WINAPI uv__signal_control_handler(DWORD type); +int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot); + void uv_signals_init() { InitializeCriticalSection(&uv__signal_lock); if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) @@ -70,7 +75,9 @@ RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare int uv__signal_dispatch(int signum) { uv_signal_t lookup; uv_signal_t* handle; - int dispatched = 0; + int dispatched; + + dispatched = 0; EnterCriticalSection(&uv__signal_lock); @@ -83,11 +90,16 @@ int uv__signal_dispatch(int signum) { unsigned long previous = InterlockedExchange( (volatile LONG*) &handle->pending_signum, signum); + if (handle->flags & UV__SIGNAL_ONE_SHOT_DISPATCHED) + continue; + if (!previous) { POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req); } dispatched = 1; + if (handle->flags & UV__SIGNAL_ONE_SHOT) + handle->flags |= UV__SIGNAL_ONE_SHOT_DISPATCHED; } LeaveCriticalSection(&uv__signal_lock); @@ -166,6 +178,21 @@ int uv_signal_stop(uv_signal_t* handle) { int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + return uv__signal_start(handle, signal_cb, signum, 0); +} + + +int uv_signal_start_oneshot(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum) { + return uv__signal_start(handle, signal_cb, signum, 1); +} + + +int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot) { /* Test for invalid signal values. */ if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG)) return UV_EINVAL; @@ -189,6 +216,9 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { EnterCriticalSection(&uv__signal_lock); handle->signum = signum; + if (oneshot) + handle->flags |= UV__SIGNAL_ONE_SHOT; + RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle); LeaveCriticalSection(&uv__signal_lock); @@ -217,6 +247,9 @@ void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, if (dispatched_signum == handle->signum) handle->signal_cb(handle, dispatched_signum); + if (handle->flags & UV__SIGNAL_ONE_SHOT) + uv_signal_stop(handle); + if (handle->flags & UV__HANDLE_CLOSING) { /* When it is closing, it must be stopped at this point. */ assert(handle->signum == 0); diff --git a/test/test-list.h b/test/test-list.h index 3a1e82a91..35656a760 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -354,6 +354,8 @@ TEST_DECLARE (spawn_fs_open) TEST_DECLARE (spawn_setuid_setgid) TEST_DECLARE (we_get_signal) TEST_DECLARE (we_get_signals) +TEST_DECLARE (we_get_signal_one_shot) +TEST_DECLARE (we_get_signals_mixed) TEST_DECLARE (signal_multiple_loops) TEST_DECLARE (closed_fd_events) #endif @@ -704,6 +706,8 @@ TASK_LIST_START TEST_ENTRY (spawn_setuid_setgid) TEST_ENTRY (we_get_signal) TEST_ENTRY (we_get_signals) + TEST_ENTRY (we_get_signal_one_shot) + TEST_ENTRY (we_get_signals_mixed) TEST_ENTRY (signal_multiple_loops) TEST_ENTRY (closed_fd_events) #endif diff --git a/test/test-signal.c b/test/test-signal.c index c0424c60a..9a881510c 100644 --- a/test/test-signal.c +++ b/test/test-signal.c @@ -70,17 +70,17 @@ struct timer_ctx { }; struct signal_ctx { - enum { CLOSE, STOP } stop_or_close; + enum { CLOSE, STOP, NOOP } stop_or_close; unsigned int ncalls; uv_signal_t handle; int signum; + int one_shot; }; 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); - if (++ctx->ncalls == NSIGNALS) { if (ctx->stop_or_close == STOP) uv_signal_stop(handle); @@ -91,6 +91,14 @@ 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); + if (ctx->stop_or_close == CLOSE) + uv_close((uv_handle_t*)handle, NULL); +} + static void timer_cb(uv_timer_t* handle) { struct timer_ctx* ctx = container_of(handle, struct timer_ctx, handle); @@ -102,15 +110,21 @@ static void timer_cb(uv_timer_t* handle) { } -static void start_watcher(uv_loop_t* loop, int signum, struct signal_ctx* ctx) { +static void start_watcher(uv_loop_t* loop, + int signum, + struct signal_ctx* ctx, + int one_shot) { ctx->ncalls = 0; ctx->signum = signum; ctx->stop_or_close = CLOSE; + ctx->one_shot = one_shot; ASSERT(0 == uv_signal_init(loop, &ctx->handle)); - ASSERT(0 == uv_signal_start(&ctx->handle, signal_cb, signum)); + if (one_shot) + ASSERT(0 == uv_signal_start_oneshot(&ctx->handle, signal_cb_one_shot, signum)); + else + ASSERT(0 == 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; @@ -126,7 +140,7 @@ TEST_IMPL(we_get_signal) { loop = uv_default_loop(); start_timer(loop, SIGCHLD, &tc); - start_watcher(loop, SIGCHLD, &sc); + 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); @@ -158,10 +172,10 @@ TEST_IMPL(we_get_signals) { unsigned int i; loop = uv_default_loop(); - start_watcher(loop, SIGUSR1, sc + 0); - start_watcher(loop, SIGUSR1, sc + 1); - start_watcher(loop, SIGUSR2, sc + 2); - start_watcher(loop, SIGUSR2, sc + 3); + start_watcher(loop, SIGUSR1, sc + 0, 0); + start_watcher(loop, SIGUSR1, sc + 1, 0); + start_watcher(loop, SIGUSR2, sc + 2, 0); + 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)); @@ -176,4 +190,116 @@ TEST_IMPL(we_get_signals) { return 0; } +TEST_IMPL(we_get_signal_one_shot) { + struct signal_ctx sc; + struct timer_ctx tc; + uv_loop_t* loop; + + loop = uv_default_loop(); + 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); + + start_timer(loop, SIGCHLD, &tc); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(sc.ncalls == 1); + + 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); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(we_get_signals_mixed) { + struct signal_ctx sc[4]; + struct timer_ctx tc; + uv_loop_t* loop; + + loop = uv_default_loop(); + + /* 2 one-shot */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 1); + 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); + + /* 2 one-shot, 1 normal then remove normal */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 1); + start_watcher(loop, SIGCHLD, sc + 1, 1); + sc[0].stop_or_close = CLOSE; + 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); + + /* 2 normal, 1 one-shot then remove one-shot */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 0); + start_watcher(loop, SIGCHLD, sc + 1, 0); + sc[0].stop_or_close = CLOSE; + 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); + + /* 2 normal, 2 one-shot then remove 2 normal */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 0); + start_watcher(loop, SIGCHLD, sc + 1, 0); + start_watcher(loop, SIGCHLD, sc + 2, 1); + start_watcher(loop, SIGCHLD, sc + 3, 1); + sc[2].stop_or_close = CLOSE; + 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); + + /* 1 normal, 1 one-shot, 2 normal then remove 1st normal, 2nd normal */ + start_timer(loop, SIGCHLD, &tc); + start_watcher(loop, SIGCHLD, sc + 0, 0); + start_watcher(loop, SIGCHLD, sc + 1, 1); + start_watcher(loop, SIGCHLD, sc + 2, 0); + start_watcher(loop, SIGCHLD, sc + 3, 0); + 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); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + #endif /* _WIN32 */ From 2ba39be67e948f8b99af7cf408828f1507371fd5 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 16 Feb 2017 16:31:42 -0500 Subject: [PATCH 325/632] unix: factor out reusable POSIX hrtime impl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a dedicated source file to share among platforms on which we implement hrtime using POSIX `clock_gettime`. De-duplicate our existing copies of this implementation on such platforms. PR-URL: https://github.com/libuv/libuv/pull/1239 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 16 ++++++++++++---- src/unix/freebsd.c | 10 ---------- src/unix/netbsd.c | 10 ---------- src/unix/openbsd.c | 10 ---------- src/unix/posix-hrtime.c | 35 +++++++++++++++++++++++++++++++++++ uv.gyp | 1 + 6 files changed, 48 insertions(+), 34 deletions(-) create mode 100644 src/unix/posix-hrtime.c diff --git a/Makefile.am b/Makefile.am index 036464e71..1986b1a8c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -349,13 +349,17 @@ endif if DRAGONFLY include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c +libuv_la_SOURCES += src/unix/freebsd.c \ + src/unix/kqueue.c \ + src/unix/posix-hrtime.c test_run_tests_LDFLAGS += -lutil endif if FREEBSD include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c +libuv_la_SOURCES += src/unix/freebsd.c \ + src/unix/kqueue.c \ + src/unix/posix-hrtime.c test_run_tests_LDFLAGS += -lutil endif @@ -372,13 +376,17 @@ endif if NETBSD include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/kqueue.c src/unix/netbsd.c +libuv_la_SOURCES += src/unix/kqueue.c \ + src/unix/netbsd.c \ + src/unix/posix-hrtime.c test_run_tests_LDFLAGS += -lutil endif if OPENBSD include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/kqueue.c src/unix/openbsd.c +libuv_la_SOURCES += src/unix/kqueue.c \ + src/unix/openbsd.c \ + src/unix/posix-hrtime.c test_run_tests_LDFLAGS += -lutil endif diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index cba44a3e0..4862cb484 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -41,9 +41,6 @@ #include /* sysconf */ #include -#undef NANOSEC -#define NANOSEC ((uint64_t) 1e9) - #ifndef CPUSTATES # define CPUSTATES 5U #endif @@ -67,13 +64,6 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } -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); -} - - #ifdef __DragonFly__ int uv_exepath(char* buffer, size_t* size) { char abspath[PATH_MAX * 2 + 1]; diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index 4a9e6cbc1..95400687d 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -43,9 +43,6 @@ #include #include -#undef NANOSEC -#define NANOSEC ((uint64_t) 1e9) - static char *process_title; @@ -58,13 +55,6 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } -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); -} - - void uv_loadavg(double avg[3]) { struct loadavg info; size_t size = sizeof(info); diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index ac28b690d..2c2a46eaa 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -40,9 +40,6 @@ #include #include -#undef NANOSEC -#define NANOSEC ((uint64_t) 1e9) - static char *process_title; @@ -56,13 +53,6 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } -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); -} - - void uv_loadavg(double avg[3]) { struct loadavg info; size_t size = sizeof(info); diff --git a/src/unix/posix-hrtime.c b/src/unix/posix-hrtime.c new file mode 100644 index 000000000..323dfc203 --- /dev/null +++ b/src/unix/posix-hrtime.c @@ -0,0 +1,35 @@ +/* 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 "internal.h" + +#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); +} diff --git a/uv.gyp b/uv.gyp index 49d5d22f9..9bbadd2ea 100644 --- a/uv.gyp +++ b/uv.gyp @@ -298,6 +298,7 @@ 'link_settings': { 'libraries': [ '-lkvm' ], }, + 'sources': [ 'src/unix/posix-hrtime.c' ], }], [ 'OS in "ios mac freebsd dragonflybsd openbsd netbsd".split()', { 'sources': [ 'src/unix/kqueue.c' ], From ee02f60c90bbf01e2107b3800b3dfbbe090484ab Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 28 Feb 2017 00:21:26 -0500 Subject: [PATCH 326/632] unix,win: add uv_os_{get,set,unset}env() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These functions are used to create, retrieve, update, and delete environment variables. Fixes: https://github.com/libuv/libuv/issues/1198 PR-URL: https://github.com/libuv/libuv/pull/1234 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno --- Makefile.am | 1 + checksparse.sh | 1 + docs/src/misc.rst | 35 +++++++++ include/uv.h | 4 + src/unix/core.c | 45 +++++++++++ src/win/util.c | 180 +++++++++++++++++++++++++++++++++++++++++++ test/test-env-vars.c | 88 +++++++++++++++++++++ test/test-list.h | 3 + uv.gyp | 1 + 9 files changed, 358 insertions(+) create mode 100644 test/test-env-vars.c diff --git a/Makefile.am b/Makefile.am index 1986b1a8c..356dbf004 100644 --- a/Makefile.am +++ b/Makefile.am @@ -166,6 +166,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-eintr-handling.c \ test/test-embed.c \ test/test-emfile.c \ + test/test-env-vars.c \ test/test-error.c \ test/test-fail-always.c \ test/test-fs-event.c \ diff --git a/checksparse.sh b/checksparse.sh index 68e3bde39..5e0220716 100755 --- a/checksparse.sh +++ b/checksparse.sh @@ -93,6 +93,7 @@ test/test-cwd-and-chdir.c test/test-delayed-accept.c test/test-dlerror.c test/test-embed.c +test/test-env-vars.c test/test-error.c test/test-fail-always.c test/test-fs-event.c diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 719346946..5827787eb 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -386,3 +386,38 @@ API stability guarantees. .. versionadded:: 1.8.0 + +.. c:function:: int uv_os_getenv(const char* name, char* buffer, size_t* size) + + Retrieves the environment variable specified by `name`, copies its value + into `buffer`, and sets `size` to the string length of the value. When + calling this function, `size` must be set to the amount of storage available + in `buffer`, including the null terminator. If the environment variable + exceeds the storage available in `buffer`, `UV_ENOBUFS` is returned, and + `size` is set to the amount of storage required to hold the value. If no + matching environment variable exists, `UV_ENOENT` is returned. + + .. warning:: + This function is not thread safe. + + .. versionadded:: 1.12.0 + +.. c:function:: int uv_os_setenv(const char* name, const char* value) + + Creates or updates the environment variable specified by `name` with + `value`. + + .. warning:: + This function is not thread safe. + + .. versionadded:: 1.12.0 + +.. c:function:: int uv_os_unsetenv(const char* name) + + Deletes the environment variable specified by `name`. If no such environment + variable exists, this function returns successfully. + + .. warning:: + This function is not thread safe. + + .. versionadded:: 1.12.0 diff --git a/include/uv.h b/include/uv.h index e5230bb50..9745bd290 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1073,6 +1073,10 @@ UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses, UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses, int count); +UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size); +UV_EXTERN int uv_os_setenv(const char* name, const char* value); +UV_EXTERN int uv_os_unsetenv(const char* name); + typedef enum { UV_FS_UNKNOWN = -1, diff --git a/src/unix/core.c b/src/unix/core.c index 9ef713491..2a7a64202 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1240,3 +1240,48 @@ int uv_translate_sys_error(int sys_errno) { /* If < 0 then it's already a libuv error. */ return sys_errno <= 0 ? sys_errno : -sys_errno; } + + +int uv_os_getenv(const char* name, char* buffer, size_t* size) { + char* var; + size_t len; + + if (name == NULL || buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + var = getenv(name); + + if (var == NULL) + return -ENOENT; + + len = strlen(var); + + if (len >= *size) { + *size = len + 1; + return -ENOBUFS; + } + + memcpy(buffer, var, len + 1); + *size = len; + + return 0; +} + + +int uv_os_setenv(const char* name, const char* value) { + if (value == NULL) + return -EINVAL; + + if (setenv(name, value, 1) != 0) + return -errno; + + return 0; +} + + +int uv_os_unsetenv(const char* name) { + if (unsetenv(name) != 0) + return -errno; + + return 0; +} diff --git a/src/win/util.c b/src/win/util.c index 050058afa..39f670c4a 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -59,6 +59,9 @@ # define UNLEN 256 #endif +/* Maximum environment variable size, including the terminating null */ +#define MAX_ENV_VAR_LENGTH 32767 + /* Cached copy of the process title, plus a mutex guarding it. */ static char *process_title; static CRITICAL_SECTION process_title_lock; @@ -1387,3 +1390,180 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { int uv_os_get_passwd(uv_passwd_t* pwd) { return uv__getpwuid_r(pwd); } + + +int uv_os_getenv(const char* name, char* buffer, size_t* size) { + wchar_t var[MAX_ENV_VAR_LENGTH]; + wchar_t* name_w; + DWORD bufsize; + size_t len; + int r; + + if (name == NULL || buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + /* Determine the size of the wide character name */ + bufsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + /* Convert the environment variable name to a wide character string */ + name_w = uv__malloc(sizeof(wchar_t) * bufsize); + + if (name_w == NULL) + return UV_ENOMEM; + + bufsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, name_w, bufsize); + + if (bufsize == 0) { + uv__free(name_w); + return uv_translate_sys_error(GetLastError()); + } + + len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH); + uv__free(name_w); + assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */ + + if (len == 0) { + r = GetLastError(); + + if (r == ERROR_ENVVAR_NOT_FOUND) + return UV_ENOENT; + + return uv_translate_sys_error(r); + } + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -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, + var, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; +} + + +int uv_os_setenv(const char* name, const char* value) { + wchar_t* name_w; + wchar_t* value_w; + DWORD bufsize; + int r; + + if (name == NULL || value == NULL) + return UV_EINVAL; + + name_w = NULL; + value_w = NULL; + r = 0; + + /* Determine the size of the wide character name */ + bufsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); + + if (bufsize == 0) { + r = uv_translate_sys_error(GetLastError()); + goto out; + } + + /* Convert the environment variable name to a wide character string */ + name_w = uv__malloc(sizeof(wchar_t) * bufsize); + + if (name_w == NULL) { + r = UV_ENOMEM; + goto out; + } + + bufsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, name_w, bufsize); + + if (bufsize == 0) { + r = uv_translate_sys_error(GetLastError()); + goto out; + } + + /* Determine the size of the wide character value */ + bufsize = MultiByteToWideChar(CP_UTF8, 0, value, -1, NULL, 0); + + if (bufsize == 0) { + r = uv_translate_sys_error(GetLastError()); + goto out; + } + + /* Convert the environment variable value to a wide character string */ + value_w = uv__malloc(sizeof(wchar_t) * bufsize); + + if (value_w == NULL) { + r = UV_ENOMEM; + goto out; + } + + bufsize = MultiByteToWideChar(CP_UTF8, 0, value, -1, value_w, bufsize); + + if (bufsize == 0) { + r = uv_translate_sys_error(GetLastError()); + goto out; + } + + if (SetEnvironmentVariableW(name_w, value_w) == 0) + r = uv_translate_sys_error(GetLastError()); + +out: + uv__free(name_w); + uv__free(value_w); + + return r; +} + + +int uv_os_unsetenv(const char* name) { + wchar_t* name_w; + DWORD bufsize; + int r; + + if (name == NULL) + return UV_EINVAL; + + /* Determine the size of the wide character name */ + bufsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + /* Convert the environment variable name to a wide character string */ + name_w = uv__malloc(sizeof(wchar_t) * bufsize); + + if (name_w == NULL) + return UV_ENOMEM; + + bufsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, name_w, bufsize); + + if (bufsize == 0) { + uv__free(name_w); + return uv_translate_sys_error(GetLastError()); + } + + r = SetEnvironmentVariableW(name_w, NULL); + uv__free(name_w); + + if (r == 0) + return uv_translate_sys_error(GetLastError()); + + return 0; +} diff --git a/test/test-env-vars.c b/test/test-env-vars.c new file mode 100644 index 000000000..7aa5881a2 --- /dev/null +++ b/test/test-env-vars.c @@ -0,0 +1,88 @@ +/* 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 + +#define BUF_SIZE 10 + +TEST_IMPL(env_vars) { + const char* name = "UV_TEST_FOO"; + char buf[BUF_SIZE]; + size_t size; + int r; + + /* Reject invalid inputs when setting an environment variable */ + r = uv_os_setenv(NULL, "foo"); + ASSERT(r == UV_EINVAL); + r = uv_os_setenv(name, NULL); + ASSERT(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); + r = uv_os_getenv(name, NULL, &size); + ASSERT(r == UV_EINVAL); + r = uv_os_getenv(name, buf, NULL); + ASSERT(r == UV_EINVAL); + size = 0; + r = uv_os_getenv(name, buf, &size); + ASSERT(r == UV_EINVAL); + + /* Reject invalid inputs when deleting an environment variable */ + r = uv_os_unsetenv(NULL); + ASSERT(r == UV_EINVAL); + + /* Successfully set an environment variable */ + r = uv_os_setenv(name, "123456789"); + ASSERT(r == 0); + + /* 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); + + /* 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); + + /* Successfully delete an environment variable */ + r = uv_os_unsetenv(name); + ASSERT(r == 0); + + /* Return UV_ENOENT retrieving an environment variable that does not exist */ + r = uv_os_getenv(name, buf, &size); + ASSERT(r == UV_ENOENT); + + /* Successfully delete an environment variable that does not exist */ + r = uv_os_unsetenv(name); + ASSERT(r == 0); + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 35656a760..46da5fdae 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -153,6 +153,7 @@ TEST_DECLARE (shutdown_close_pipe) TEST_DECLARE (shutdown_eof) TEST_DECLARE (shutdown_twice) TEST_DECLARE (callback_stack) +TEST_DECLARE (env_vars) TEST_DECLARE (error_message) TEST_DECLARE (sys_error) TEST_DECLARE (timer) @@ -550,6 +551,8 @@ TASK_LIST_START TEST_ENTRY (callback_stack) TEST_HELPER (callback_stack, tcp4_echo_server) + TEST_ENTRY (env_vars) + TEST_ENTRY (error_message) TEST_ENTRY (sys_error) diff --git a/uv.gyp b/uv.gyp index 9bbadd2ea..e25ee25aa 100644 --- a/uv.gyp +++ b/uv.gyp @@ -344,6 +344,7 @@ 'test/test-error.c', 'test/test-embed.c', 'test/test-emfile.c', + 'test/test-env-vars.c', 'test/test-fail-always.c', 'test/test-fs.c', 'test/test-fs-event.c', From 53995a3825d23eacd01e2bcfa35642c4a188d32b Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 1 Mar 2017 15:56:36 -0500 Subject: [PATCH 327/632] win: add uv__convert_utf8_to_utf16() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is an internal helper function for converting UTF-8 strings to UTF-16 strings. It performs the inverse operation of the existing uv__convert_utf16_to_utf8() function. Fixes: https://github.com/libuv/libuv/issues/1198 PR-URL: https://github.com/libuv/libuv/pull/1234 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno --- src/win/internal.h | 1 + src/win/util.c | 145 ++++++++++++++++++--------------------------- 2 files changed, 60 insertions(+), 86 deletions(-) diff --git a/src/win/internal.h b/src/win/internal.h index b8cfde90e..23764da34 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -331,6 +331,7 @@ int uv_current_pid(); __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 39f670c4a..a289457fa 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1325,6 +1325,47 @@ int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) { } +/* + * 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 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()); + + /* 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)); + + if (*utf16 == NULL) + return UV_ENOMEM; + + /* Convert to UTF-16 */ + bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize); + + if (bufsize == 0) { + uv__free(*utf16); + *utf16 = NULL; + return uv_translate_sys_error(GetLastError()); + } + + (*utf16)[bufsize] = '\0'; + return 0; +} + + int uv__getpwuid_r(uv_passwd_t* pwd) { HANDLE token; wchar_t username[UNLEN + 1]; @@ -1402,24 +1443,10 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { if (name == NULL || buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; - /* Determine the size of the wide character name */ - bufsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); + r = uv__convert_utf8_to_utf16(name, -1, &name_w); - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - /* Convert the environment variable name to a wide character string */ - name_w = uv__malloc(sizeof(wchar_t) * bufsize); - - if (name_w == NULL) - return UV_ENOMEM; - - bufsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, name_w, bufsize); - - if (bufsize == 0) { - uv__free(name_w); - return uv_translate_sys_error(GetLastError()); - } + if (r != 0) + return r; len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH); uv__free(name_w); @@ -1465,99 +1492,45 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { int uv_os_setenv(const char* name, const char* value) { wchar_t* name_w; wchar_t* value_w; - DWORD bufsize; int r; if (name == NULL || value == NULL) return UV_EINVAL; - name_w = NULL; - value_w = NULL; - r = 0; - - /* Determine the size of the wide character name */ - bufsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); + r = uv__convert_utf8_to_utf16(name, -1, &name_w); - if (bufsize == 0) { - r = uv_translate_sys_error(GetLastError()); - goto out; - } - - /* Convert the environment variable name to a wide character string */ - name_w = uv__malloc(sizeof(wchar_t) * bufsize); - - if (name_w == NULL) { - r = UV_ENOMEM; - goto out; - } - - bufsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, name_w, bufsize); - - if (bufsize == 0) { - r = uv_translate_sys_error(GetLastError()); - goto out; - } - - /* Determine the size of the wide character value */ - bufsize = MultiByteToWideChar(CP_UTF8, 0, value, -1, NULL, 0); - - if (bufsize == 0) { - r = uv_translate_sys_error(GetLastError()); - goto out; - } - - /* Convert the environment variable value to a wide character string */ - value_w = uv__malloc(sizeof(wchar_t) * bufsize); - - if (value_w == NULL) { - r = UV_ENOMEM; - goto out; - } + if (r != 0) + return r; - bufsize = MultiByteToWideChar(CP_UTF8, 0, value, -1, value_w, bufsize); + r = uv__convert_utf8_to_utf16(value, -1, &value_w); - if (bufsize == 0) { - r = uv_translate_sys_error(GetLastError()); - goto out; + if (r != 0) { + uv__free(name_w); + return r; } - if (SetEnvironmentVariableW(name_w, value_w) == 0) - r = uv_translate_sys_error(GetLastError()); - -out: + r = SetEnvironmentVariableW(name_w, value_w); uv__free(name_w); uv__free(value_w); - return r; + if (r == 0) + return uv_translate_sys_error(GetLastError()); + + return 0; } int uv_os_unsetenv(const char* name) { wchar_t* name_w; - DWORD bufsize; int r; if (name == NULL) return UV_EINVAL; - /* Determine the size of the wide character name */ - bufsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); - - if (bufsize == 0) - return uv_translate_sys_error(GetLastError()); - - /* Convert the environment variable name to a wide character string */ - name_w = uv__malloc(sizeof(wchar_t) * bufsize); - - if (name_w == NULL) - return UV_ENOMEM; + r = uv__convert_utf8_to_utf16(name, -1, &name_w); - bufsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, name_w, bufsize); - - if (bufsize == 0) { - uv__free(name_w); - return uv_translate_sys_error(GetLastError()); - } + if (r != 0) + return r; r = SetEnvironmentVariableW(name_w, NULL); uv__free(name_w); From c4bd9f48e0b3c1b58606a6c53613165fcd5a4f74 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 28 Feb 2017 12:32:15 -0500 Subject: [PATCH 328/632] docs: improve UV_ENOBUFS scenario documentation This commit adds additional documentation to the UV_ENOBUFS scenario for several methods. Fixes: https://github.com/libuv/libuv/issues/1179 PR-URL: https://github.com/libuv/libuv/pull/1235 Reviewed-By: Santiago Gimeno --- docs/src/fs_event.rst | 8 ++++++-- docs/src/fs_poll.rst | 9 +++++++-- docs/src/misc.rst | 10 +++++++++- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/docs/src/fs_event.rst b/docs/src/fs_event.rst index c08ade2ef..fb855b0bc 100644 --- a/docs/src/fs_event.rst +++ b/docs/src/fs_event.rst @@ -113,10 +113,14 @@ API Get the path being monitored by the handle. The buffer must be preallocated by the user. Returns 0 on success or an error code < 0 in case of failure. On success, `buffer` will contain the path and `size` its length. If the buffer - is not big enough UV_ENOBUFS will be returned and len will be set to the - required size. + is not big enough `UV_ENOBUFS` will be returned and `size` will be set to + the required size, including the null terminator. .. versionchanged:: 1.3.0 the returned length no longer includes the terminating null byte, and the buffer is not null terminated. + .. versionchanged:: 1.9.0 the returned length includes the terminating null + byte on `UV_ENOBUFS`, and the buffer is null terminated + on success. + .. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/docs/src/fs_poll.rst b/docs/src/fs_poll.rst index 4efb2440e..2912bad93 100644 --- a/docs/src/fs_poll.rst +++ b/docs/src/fs_poll.rst @@ -63,10 +63,15 @@ API Get the path being monitored by the handle. The buffer must be preallocated by the user. Returns 0 on success or an error code < 0 in case of failure. On success, `buffer` will contain the path and `size` its length. If the buffer - is not big enough UV_ENOBUFS will be returned and len will be set to the - required size. + is not big enough `UV_ENOBUFS` will be returned and `size` will be set to + the required size. .. versionchanged:: 1.3.0 the returned length no longer includes the terminating null byte, and the buffer is not null terminated. + .. versionchanged:: 1.9.0 the returned length includes the terminating null + byte on `UV_ENOBUFS`, and the buffer is null terminated + on success. + + .. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 5827787eb..a92b74f46 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -270,12 +270,20 @@ API .. c:function:: int uv_cwd(char* buffer, size_t* size) - Gets the current working directory. + Gets the current working directory, and stores it in `buffer`. If the + current working directory is too large to fit in `buffer`, this function + returns `UV_ENOBUFS`, and sets `size` to the required length, including the + null terminator. .. versionchanged:: 1.1.0 On Unix the path no longer ends in a slash. + .. versionchanged:: 1.9.0 the returned length includes the terminating null + byte on `UV_ENOBUFS`, and the buffer is null terminated + on success. + + .. c:function:: int uv_chdir(const char* dir) Changes the current working directory. From 399b08aa9f02362a14f8d2975ac7f70b91bb0963 Mon Sep 17 00:00:00 2001 From: jBarz Date: Thu, 9 Mar 2017 09:32:25 -0500 Subject: [PATCH 329/632] unix: return UV_EINVAL for NULL env name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "setenv" on z/OS returns successfully on a NULL ptr argument for name. Check for this on all unixes. PR-URL: https://github.com/libuv/libuv/pull/1243 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/unix/core.c | 2 +- test/test-env-vars.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/unix/core.c b/src/unix/core.c index 2a7a64202..96495b864 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1269,7 +1269,7 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { int uv_os_setenv(const char* name, const char* value) { - if (value == NULL) + if (name == NULL || value == NULL) return -EINVAL; if (setenv(name, value, 1) != 0) diff --git a/test/test-env-vars.c b/test/test-env-vars.c index 7aa5881a2..641050e67 100644 --- a/test/test-env-vars.c +++ b/test/test-env-vars.c @@ -36,6 +36,8 @@ TEST_IMPL(env_vars) { ASSERT(r == UV_EINVAL); r = uv_os_setenv(name, NULL); ASSERT(r == UV_EINVAL); + r = uv_os_setenv(NULL, NULL); + ASSERT(r == UV_EINVAL); /* Reject invalid inputs when retrieving an environment variable */ size = BUF_SIZE; From 80c4cf6b6238eadab1466eb69bce9f01a51ad98c Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 17 Feb 2017 20:54:46 -0500 Subject: [PATCH 330/632] unix: filter getifaddrs results consistently MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We loop over getifaddrs results multiple times. Fix the filter conditions to be consistent for all passes. PR-URL: https://github.com/libuv/libuv/pull/1240 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/unix/netbsd.c | 2 +- src/unix/openbsd.c | 2 +- src/unix/sunos.c | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index 95400687d..e6dc9db5f 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -338,7 +338,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != AF_LINK)) { + (ent->ifa_addr->sa_family != PF_INET)) { continue; } diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index 2c2a46eaa..c8369058e 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -353,7 +353,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != AF_LINK)) { + (ent->ifa_addr->sa_family != PF_INET)) { continue; } diff --git a/src/unix/sunos.c b/src/unix/sunos.c index a43f7f1b1..0f592a270 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -783,6 +783,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (ent->ifa_addr == NULL) continue; + if (ent->ifa_addr->sa_family == PF_PACKET) + continue; + address->name = uv__strdup(ent->ifa_name); if (ent->ifa_addr->sa_family == AF_INET6) { From 0f84c305e0bf54d3b5b5e324f0e117625016adb6 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 17 Feb 2017 20:58:22 -0500 Subject: [PATCH 331/632] unix: factor out getifaddrs result filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On platforms using getifaddrs we iterate over the interfaces two or three times. First we count them, then we enumerate them, and then we fill in physical addresses. Each loop needs to do the same filtering, so factor out the exclusion test into a helper function for each platform. PR-URL: https://github.com/libuv/libuv/pull/1240 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/unix/darwin.c | 37 +++++++++++++++++-------------------- src/unix/freebsd.c | 36 ++++++++++++++++-------------------- src/unix/linux-core.c | 35 ++++++++++++++++------------------- src/unix/netbsd.c | 28 +++++++++++++--------------- src/unix/openbsd.c | 27 ++++++++++++--------------- src/unix/sunos.c | 25 +++++++++++++------------ 6 files changed, 87 insertions(+), 101 deletions(-) diff --git a/src/unix/darwin.c b/src/unix/darwin.c index cf95da216..5027174a2 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -235,6 +235,20 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { } +static int uv__ifaddr_exclude(struct ifaddrs *ent) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; + /* + * On Mac OS X getifaddrs returns information related to Mac Addresses for + * various devices, such as firewire, etc. These are not relevant here. + */ + if (ent->ifa_addr->sa_family == AF_LINK) + return 1; + return 0; +} + int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifaddrs *addrs, *ent; uv_interface_address_t* address; @@ -248,12 +262,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family == AF_LINK)) { + if (uv__ifaddr_exclude(ent)) continue; - } - (*count)++; } @@ -266,17 +276,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - continue; - - if (ent->ifa_addr == NULL) - continue; - - /* - * On Mac OS X getifaddrs returns information related to Mac Addresses for - * various devices, such as firewire, etc. These are not relevant here. - */ - if (ent->ifa_addr->sa_family == AF_LINK) + if (uv__ifaddr_exclude(ent)) continue; address->name = uv__strdup(ent->ifa_name); @@ -300,11 +300,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != AF_LINK)) { + if (uv__ifaddr_exclude(ent)) continue; - } address = *addresses; diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index 4862cb484..8f67f33ac 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -349,6 +349,19 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } +static int uv__ifaddr_exclude(struct ifaddrs *ent) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; + /* + * On FreeBSD getifaddrs returns information related to the raw underlying + * devices. We're not interested in this information yet. + */ + if (ent->ifa_addr->sa_family == AF_LINK) + return 1; + return 0; +} int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifaddrs *addrs, *ent; @@ -363,12 +376,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family == AF_LINK)) { + if (uv__ifaddr_exclude(ent)) continue; - } - (*count)++; } @@ -381,17 +390,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - continue; - - if (ent->ifa_addr == NULL) - continue; - - /* - * On FreeBSD getifaddrs returns information related to the raw underlying - * devices. We're not interested in this information yet. - */ - if (ent->ifa_addr->sa_family == AF_LINK) + if (uv__ifaddr_exclude(ent)) continue; address->name = uv__strdup(ent->ifa_name); @@ -415,11 +414,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != AF_LINK)) { + if (uv__ifaddr_exclude(ent)) continue; - } address = *addresses; diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 58dd813dd..96b150de6 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -868,6 +868,19 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } +static int uv__ifaddr_exclude(struct ifaddrs *ent) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; + /* + * On Linux getifaddrs returns information related to the raw underlying + * devices. We're not interested in this information yet. + */ + if (ent->ifa_addr->sa_family == PF_PACKET) + return 1; + return 0; +} int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { @@ -887,11 +900,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family == PF_PACKET)) { + if (uv__ifaddr_exclude(ent)) continue; - } (*count)++; } @@ -908,17 +918,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - continue; - - if (ent->ifa_addr == NULL) - continue; - - /* - * On Linux getifaddrs returns information related to the raw underlying - * devices. We're not interested in this information yet. - */ - if (ent->ifa_addr->sa_family == PF_PACKET) + if (uv__ifaddr_exclude(ent)) continue; address->name = uv__strdup(ent->ifa_name); @@ -942,11 +942,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != PF_PACKET)) { + if (uv__ifaddr_exclude(ent)) continue; - } address = *addresses; diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index e6dc9db5f..22eb52e6d 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -274,6 +274,16 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } +static int uv__ifaddr_exclude(struct ifaddrs *ent) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; + if (ent->ifa_addr->sa_family != PF_INET) + return 1; + return 0; +} + int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifaddrs *addrs, *ent; @@ -288,11 +298,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != PF_INET)) { + if (uv__ifaddr_exclude(ent)) continue; - } (*count)++; } @@ -306,13 +313,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - continue; - - if (ent->ifa_addr == NULL) - continue; - - if (ent->ifa_addr->sa_family != PF_INET) + if (uv__ifaddr_exclude(ent)) continue; address->name = uv__strdup(ent->ifa_name); @@ -336,11 +337,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != PF_INET)) { + if (uv__ifaddr_exclude(ent)) continue; - } address = *addresses; diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index c8369058e..980cbb588 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -288,6 +288,15 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } +static int uv__ifaddr_exclude(struct ifaddrs *ent) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; + if (ent->ifa_addr->sa_family != PF_INET) + return 1; + return 0; +} int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { @@ -303,11 +312,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != PF_INET)) { + if (uv__ifaddr_exclude(ent)) continue; - } (*count)++; } @@ -321,13 +327,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - continue; - - if (ent->ifa_addr == NULL) - continue; - - if (ent->ifa_addr->sa_family != PF_INET) + if (uv__ifaddr_exclude(ent)) continue; address->name = uv__strdup(ent->ifa_name); @@ -351,11 +351,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != PF_INET)) { + if (uv__ifaddr_exclude(ent)) continue; - } address = *addresses; diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 0f592a270..a76a08bd9 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -746,6 +746,17 @@ static int uv__set_phys_addr(uv_interface_address_t* address, return 0; } + +static int uv__ifaddr_exclude(struct ifaddrs *ent) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; + if (ent->ifa_addr->sa_family == PF_PACKET) + return 1; + return 0; +} + int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; struct ifaddrs* addrs; @@ -759,12 +770,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family == PF_PACKET)) { + if (uv__ifaddr_exclude(ent)) continue; - } - (*count)++; } @@ -777,13 +784,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - continue; - - if (ent->ifa_addr == NULL) - continue; - - if (ent->ifa_addr->sa_family == PF_PACKET) + if (uv__ifaddr_exclude(ent)) continue; address->name = uv__strdup(ent->ifa_name); From f277cb6f920f0abbb2fb314861b3d79ef1de02fd Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 20 Feb 2017 19:42:00 -0500 Subject: [PATCH 332/632] unix: factor out reusable BSD ifaddrs impl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a dedicated source file to share among platforms on which we find ifaddrs using the BSD getifaddrs API. De-duplicate our existing copies of this implementation on such platforms. PR-URL: https://github.com/libuv/libuv/pull/1240 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 15 +++-- src/unix/bsd-ifaddrs.c | 133 +++++++++++++++++++++++++++++++++++++++++ src/unix/darwin.c | 101 ------------------------------- src/unix/freebsd.c | 100 ------------------------------- src/unix/netbsd.c | 96 ----------------------------- src/unix/openbsd.c | 98 ------------------------------ uv.gyp | 5 +- 7 files changed, 147 insertions(+), 401 deletions(-) create mode 100644 src/unix/bsd-ifaddrs.c diff --git a/Makefile.am b/Makefile.am index 356dbf004..85e7aaa83 100644 --- a/Makefile.am +++ b/Makefile.am @@ -339,7 +339,8 @@ include_HEADERS += include/uv-darwin.h \ include/pthread-barrier.h libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1 -libuv_la_SOURCES += src/unix/darwin.c \ +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/darwin.c \ src/unix/darwin-proctitle.c \ src/unix/fsevents.c \ src/unix/kqueue.c \ @@ -350,7 +351,8 @@ endif if DRAGONFLY include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/freebsd.c \ +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/freebsd.c \ src/unix/kqueue.c \ src/unix/posix-hrtime.c test_run_tests_LDFLAGS += -lutil @@ -358,7 +360,8 @@ endif if FREEBSD include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/freebsd.c \ +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/freebsd.c \ src/unix/kqueue.c \ src/unix/posix-hrtime.c test_run_tests_LDFLAGS += -lutil @@ -377,7 +380,8 @@ endif if NETBSD include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/kqueue.c \ +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/kqueue.c \ src/unix/netbsd.c \ src/unix/posix-hrtime.c test_run_tests_LDFLAGS += -lutil @@ -385,7 +389,8 @@ endif if OPENBSD include_HEADERS += include/uv-bsd.h -libuv_la_SOURCES += src/unix/kqueue.c \ +libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ + src/unix/kqueue.c \ src/unix/openbsd.c \ src/unix/posix-hrtime.c test_run_tests_LDFLAGS += -lutil diff --git a/src/unix/bsd-ifaddrs.c b/src/unix/bsd-ifaddrs.c new file mode 100644 index 000000000..0b5653d0a --- /dev/null +++ b/src/unix/bsd-ifaddrs.c @@ -0,0 +1,133 @@ +/* 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 "internal.h" + +#include +#include + +#include +#include +#include + +static int uv__ifaddr_exclude(struct ifaddrs *ent) { + if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) + return 1; + if (ent->ifa_addr == NULL) + return 1; +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) + /* + * On BSD getifaddrs returns information related to the raw underlying + * devices. We're not interested in this information. + */ + if (ent->ifa_addr->sa_family == AF_LINK) + return 1; +#elif defined(__NetBSD__) || defined(__OpenBSD__) + if (ent->ifa_addr->sa_family != PF_INET) + return 1; +#endif + return 0; +} + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + struct ifaddrs* addrs; + struct ifaddrs* ent; + uv_interface_address_t* address; + int i; + + if (getifaddrs(&addrs) != 0) + return -errno; + + *count = 0; + + /* Count the number of interfaces */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent)) + continue; + (*count)++; + } + + *addresses = uv__malloc(*count * sizeof(**addresses)); + + if (*addresses == NULL) { + freeifaddrs(addrs); + return -ENOMEM; + } + + address = *addresses; + + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent)) + continue; + + address->name = uv__strdup(ent->ifa_name); + + if (ent->ifa_addr->sa_family == AF_INET6) { + address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); + } else { + address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); + } + + if (ent->ifa_netmask->sa_family == AF_INET6) { + address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); + } else { + address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); + } + + address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); + + address++; + } + + /* Fill in physical addresses for each interface */ + for (ent = addrs; ent != NULL; ent = ent->ifa_next) { + if (uv__ifaddr_exclude(ent)) + continue; + + address = *addresses; + + for (i = 0; i < *count; i++) { + if (strcmp(address->name, ent->ifa_name) == 0) { + struct sockaddr_dl* sa_addr; + sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + } + address++; + } + } + + freeifaddrs(addrs); + + return 0; +} + + +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/darwin.c b/src/unix/darwin.c index 5027174a2..df6dd1c61 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -25,10 +25,6 @@ #include #include -#include -#include -#include - #include #include #include /* _NSGetExecutablePath */ @@ -233,100 +229,3 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } - - -static int uv__ifaddr_exclude(struct ifaddrs *ent) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - return 1; - if (ent->ifa_addr == NULL) - return 1; - /* - * On Mac OS X getifaddrs returns information related to Mac Addresses for - * various devices, such as firewire, etc. These are not relevant here. - */ - if (ent->ifa_addr->sa_family == AF_LINK) - return 1; - return 0; -} - -int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - struct ifaddrs *addrs, *ent; - uv_interface_address_t* address; - int i; - struct sockaddr_dl *sa_addr; - - if (getifaddrs(&addrs)) - return -errno; - - *count = 0; - - /* Count the number of interfaces */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - (*count)++; - } - - *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) { - freeifaddrs(addrs); - return -ENOMEM; - } - - address = *addresses; - - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - - address->name = uv__strdup(ent->ifa_name); - - if (ent->ifa_addr->sa_family == AF_INET6) { - address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); - } else { - address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); - } - - if (ent->ifa_netmask->sa_family == AF_INET6) { - address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); - } else { - address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); - } - - address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); - - address++; - } - - /* Fill in physical addresses for each interface */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - - address = *addresses; - - for (i = 0; i < (*count); i++) { - if (strcmp(address->name, ent->ifa_name) == 0) { - sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); - memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); - } - address++; - } - } - - freeifaddrs(addrs); - - return 0; -} - - -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/freebsd.c b/src/unix/freebsd.c index 8f67f33ac..e52ae99db 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -25,10 +25,6 @@ #include #include -#include -#include -#include - #include #include #include @@ -348,99 +344,3 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } - -static int uv__ifaddr_exclude(struct ifaddrs *ent) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - return 1; - if (ent->ifa_addr == NULL) - return 1; - /* - * On FreeBSD getifaddrs returns information related to the raw underlying - * devices. We're not interested in this information yet. - */ - if (ent->ifa_addr->sa_family == AF_LINK) - return 1; - return 0; -} - -int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - struct ifaddrs *addrs, *ent; - uv_interface_address_t* address; - int i; - struct sockaddr_dl *sa_addr; - - if (getifaddrs(&addrs)) - return -errno; - - *count = 0; - - /* Count the number of interfaces */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - (*count)++; - } - - *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) { - freeifaddrs(addrs); - return -ENOMEM; - } - - address = *addresses; - - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - - address->name = uv__strdup(ent->ifa_name); - - if (ent->ifa_addr->sa_family == AF_INET6) { - address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); - } else { - address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); - } - - if (ent->ifa_netmask->sa_family == AF_INET6) { - address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); - } else { - address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); - } - - address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); - - address++; - } - - /* Fill in physical addresses for each interface */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - - address = *addresses; - - for (i = 0; i < (*count); i++) { - if (strcmp(address->name, ent->ifa_name) == 0) { - sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); - memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); - } - address++; - } - } - - freeifaddrs(addrs); - - return 0; -} - - -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/netbsd.c b/src/unix/netbsd.c index 22eb52e6d..9b5546b7e 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -27,14 +27,11 @@ #include #include -#include #include #include #include #include -#include -#include #include #include #include @@ -273,96 +270,3 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } - -static int uv__ifaddr_exclude(struct ifaddrs *ent) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - return 1; - if (ent->ifa_addr == NULL) - return 1; - if (ent->ifa_addr->sa_family != PF_INET) - return 1; - return 0; -} - - -int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - struct ifaddrs *addrs, *ent; - uv_interface_address_t* address; - int i; - struct sockaddr_dl *sa_addr; - - if (getifaddrs(&addrs)) - return -errno; - - *count = 0; - - /* Count the number of interfaces */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - (*count)++; - } - - *addresses = uv__malloc(*count * sizeof(**addresses)); - - if (!(*addresses)) { - freeifaddrs(addrs); - return -ENOMEM; - } - - address = *addresses; - - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - - address->name = uv__strdup(ent->ifa_name); - - if (ent->ifa_addr->sa_family == AF_INET6) { - address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); - } else { - address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); - } - - if (ent->ifa_netmask->sa_family == AF_INET6) { - address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); - } else { - address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); - } - - address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); - - address++; - } - - /* Fill in physical addresses for each interface */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - - address = *addresses; - - for (i = 0; i < (*count); i++) { - if (strcmp(address->name, ent->ifa_name) == 0) { - sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); - memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); - } - address++; - } - } - - freeifaddrs(addrs); - - return 0; -} - - -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/openbsd.c b/src/unix/openbsd.c index 980cbb588..7e4b253b4 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -28,10 +28,6 @@ #include #include -#include -#include -#include - #include #include #include @@ -287,97 +283,3 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } - -static int uv__ifaddr_exclude(struct ifaddrs *ent) { - if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) - return 1; - if (ent->ifa_addr == NULL) - return 1; - if (ent->ifa_addr->sa_family != PF_INET) - return 1; - return 0; -} - -int uv_interface_addresses(uv_interface_address_t** addresses, - int* count) { - struct ifaddrs *addrs, *ent; - uv_interface_address_t* address; - int i; - struct sockaddr_dl *sa_addr; - - if (getifaddrs(&addrs) != 0) - return -errno; - - *count = 0; - - /* Count the number of interfaces */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - (*count)++; - } - - *addresses = uv__malloc(*count * sizeof(**addresses)); - - if (!(*addresses)) { - freeifaddrs(addrs); - return -ENOMEM; - } - - address = *addresses; - - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - - address->name = uv__strdup(ent->ifa_name); - - if (ent->ifa_addr->sa_family == AF_INET6) { - address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); - } else { - address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); - } - - if (ent->ifa_netmask->sa_family == AF_INET6) { - address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); - } else { - address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); - } - - address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); - - address++; - } - - /* Fill in physical addresses for each interface */ - for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) - continue; - - address = *addresses; - - for (i = 0; i < (*count); i++) { - if (strcmp(address->name, ent->ifa_name) == 0) { - sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); - memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); - } - address++; - } - } - - freeifaddrs(addrs); - - return 0; -} - - -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/uv.gyp b/uv.gyp index e25ee25aa..41cae412f 100644 --- a/uv.gyp +++ b/uv.gyp @@ -301,7 +301,10 @@ 'sources': [ 'src/unix/posix-hrtime.c' ], }], [ 'OS in "ios mac freebsd dragonflybsd openbsd netbsd".split()', { - 'sources': [ 'src/unix/kqueue.c' ], + 'sources': [ + 'src/unix/bsd-ifaddrs.c', + 'src/unix/kqueue.c', + ], }], ['uv_library=="shared_library"', { 'defines': [ 'BUILDING_UV_SHARED=1' ] From d7cf771072b3153e7641a9cef61160974cee8a39 Mon Sep 17 00:00:00 2001 From: jBarz Date: Fri, 27 Jan 2017 09:49:41 -0500 Subject: [PATCH 333/632] unix: use union to follow strict aliasing rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With strict-aliasing rules, a char* type can be cast to any other pointer type. However, that does not necessarily mean char array type. So instead of de-referencing a char array, use a union with an additional char member for aliasing. PR-URL: https://github.com/libuv/libuv/pull/1211 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/stream.c | 9 +++++++-- src/unix/udp.c | 12 ++++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 7059df16a..dbd04f2be 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -785,7 +785,12 @@ static void uv__write(uv_stream_t* stream) { struct msghdr msg; struct cmsghdr *cmsg; int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); - char scratch[64] = {0}; + union { + char data[64]; + struct cmsghdr alias; + } scratch; + + memset(&scratch, 0, sizeof(scratch)); assert(fd_to_send >= 0); @@ -795,7 +800,7 @@ static void uv__write(uv_stream_t* stream) { msg.msg_iovlen = iovcnt; msg.msg_flags = 0; - msg.msg_control = (void*) scratch; + msg.msg_control = &scratch.alias; msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send)); cmsg = CMSG_FIRSTHDR(&msg); diff --git a/src/unix/udp.c b/src/unix/udp.c index 1cd492578..f9630c85c 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -349,7 +349,11 @@ int uv__udp_bind(uv_udp_t* handle, static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain, unsigned int flags) { - unsigned char taddr[sizeof(struct sockaddr_in6)]; + union { + struct sockaddr_in6 in6; + struct sockaddr_in in; + struct sockaddr addr; + } taddr; socklen_t addrlen; if (handle->io_watcher.fd != -1) @@ -358,7 +362,7 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, switch (domain) { case AF_INET: { - struct sockaddr_in* addr = (void*)&taddr; + struct sockaddr_in* addr = &taddr.in; memset(addr, 0, sizeof *addr); addr->sin_family = AF_INET; addr->sin_addr.s_addr = INADDR_ANY; @@ -367,7 +371,7 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, } case AF_INET6: { - struct sockaddr_in6* addr = (void*)&taddr; + struct sockaddr_in6* addr = &taddr.in6; memset(addr, 0, sizeof *addr); addr->sin6_family = AF_INET6; addr->sin6_addr = in6addr_any; @@ -379,7 +383,7 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, abort(); } - return uv__udp_bind(handle, (const struct sockaddr*) &taddr, addrlen, flags); + return uv__udp_bind(handle, &taddr.addr, addrlen, flags); } From 5fc8aecd81dbb31e76bd80834bb73b0e9b1e5c4c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 14 Mar 2017 10:01:35 +0100 Subject: [PATCH 334/632] unix: simplify async watcher dispatch logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the unused `nevents` parameter from `uv__async_event()` and remove the indirection of having a separate `uv__async` type. There is only one instance per event loop these days. This incidentally removes the `assert(n == sizeof(val))` in a Linux-specific code path that some users seem to hit from time to time. The cause is not well-understood and I've never been able to reproduce it myself. Presumably libuv gets an EAGAIN when trying to read from the eventfd but when and why that happens is unclear. Since the byte count is unused, removing the assert seems safe. Worst case, libuv sometimes iterates over the async watcher list when it doesn't have to. Fixes: https://github.com/libuv/libuv/issues/1171 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé Supersedes: https://github.com/libuv/libuv/pull/1214 --- include/uv-unix.h | 15 ++---- src/unix/async.c | 109 ++++++++++++++++---------------------------- src/unix/internal.h | 5 +- src/unix/loop.c | 5 +- 4 files changed, 46 insertions(+), 88 deletions(-) diff --git a/include/uv-unix.h b/include/uv-unix.h index 3030f719a..544072959 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -79,7 +79,6 @@ #endif struct uv__io_s; -struct uv__async; struct uv_loop_s; typedef void (*uv__io_cb)(struct uv_loop_s* loop, @@ -97,16 +96,6 @@ struct uv__io_s { UV_IO_PRIVATE_PLATFORM_FIELDS }; -typedef void (*uv__async_cb)(struct uv_loop_s* loop, - struct uv__async* w, - unsigned int nevents); - -struct uv__async { - uv__async_cb cb; - uv__io_t io_watcher; - int wfd; -}; - #ifndef UV_PLATFORM_SEM_T # define UV_PLATFORM_SEM_T sem_t #endif @@ -216,7 +205,9 @@ typedef struct { void* check_handles[2]; \ void* idle_handles[2]; \ void* async_handles[2]; \ - struct uv__async async_watcher; \ + void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \ + uv__io_t async_io_watcher; \ + int async_wfd; \ struct { \ void* min; \ unsigned int nelts; \ diff --git a/src/unix/async.c b/src/unix/async.c index 393cdebd4..61180dc95 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -33,16 +33,15 @@ #include #include -static void uv__async_event(uv_loop_t* loop, - struct uv__async* w, - unsigned int nevents); +static void uv__async_send(uv_loop_t* loop); +static int uv__async_start(uv_loop_t* loop); static int uv__async_eventfd(void); int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { int err; - err = uv__async_start(loop, &loop->async_watcher, uv__async_event); + err = uv__async_start(loop); if (err) return err; @@ -63,7 +62,7 @@ int uv_async_send(uv_async_t* handle) { return 0; if (cmpxchgi(&handle->pending, 0, 1) == 0) - uv__async_send(&handle->loop->async_watcher); + uv__async_send(handle->loop); return 0; } @@ -75,44 +74,18 @@ void uv__async_close(uv_async_t* handle) { } -static void uv__async_event(uv_loop_t* loop, - struct uv__async* w, - unsigned int nevents) { +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; uv_async_t* h; - 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); - - if (cmpxchgi(&h->pending, 1, 0) == 0) - continue; - - if (h->async_cb == NULL) - continue; - h->async_cb(h); - } -} - - -static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - struct uv__async* wa; - char buf[1024]; - unsigned n; - ssize_t r; + assert(w == &loop->async_io_watcher); - n = 0; for (;;) { r = read(w->fd, buf, sizeof(buf)); - if (r > 0) - n += r; - if (r == sizeof(buf)) continue; @@ -128,23 +101,26 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { abort(); } - wa = container_of(w, struct uv__async, io_watcher); + QUEUE_MOVE(&loop->async_handles, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); + h = QUEUE_DATA(q, uv_async_t, queue); -#if defined(__linux__) - if (wa->wfd == -1) { - uint64_t val; - assert(n == sizeof(val)); - memcpy(&val, buf, sizeof(val)); /* Avoid alignment issues. */ - wa->cb(loop, wa, val); - return; - } -#endif + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&loop->async_handles, q); - wa->cb(loop, wa, n); + if (cmpxchgi(&h->pending, 1, 0) == 0) + continue; + + if (h->async_cb == NULL) + continue; + + h->async_cb(h); + } } -void uv__async_send(struct uv__async* wa) { +static void uv__async_send(uv_loop_t* loop) { const void* buf; ssize_t len; int fd; @@ -152,14 +128,14 @@ void uv__async_send(struct uv__async* wa) { buf = ""; len = 1; - fd = wa->wfd; + fd = loop->async_wfd; #if defined(__linux__) if (fd == -1) { static const uint64_t val = 1; buf = &val; len = sizeof(val); - fd = wa->io_watcher.fd; /* eventfd */ + fd = loop->async_io_watcher.fd; /* eventfd */ } #endif @@ -178,17 +154,11 @@ void uv__async_send(struct uv__async* wa) { } -void uv__async_init(struct uv__async* wa) { - wa->io_watcher.fd = -1; - wa->wfd = -1; -} - - -int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) { +static int uv__async_start(uv_loop_t* loop) { int pipefd[2]; int err; - if (wa->io_watcher.fd != -1) + if (loop->async_io_watcher.fd != -1) return 0; err = uv__async_eventfd(); @@ -222,28 +192,27 @@ int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) { if (err < 0) return err; - uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]); - uv__io_start(loop, &wa->io_watcher, POLLIN); - wa->wfd = pipefd[1]; - wa->cb = cb; + uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]); + uv__io_start(loop, &loop->async_io_watcher, POLLIN); + loop->async_wfd = pipefd[1]; return 0; } -void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) { - if (wa->io_watcher.fd == -1) +void uv__async_stop(uv_loop_t* loop) { + if (loop->async_io_watcher.fd == -1) return; - if (wa->wfd != -1) { - if (wa->wfd != wa->io_watcher.fd) - uv__close(wa->wfd); - wa->wfd = -1; + 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, &wa->io_watcher, POLLIN); - uv__close(wa->io_watcher.fd); - wa->io_watcher.fd = -1; + uv__io_stop(loop, &loop->async_io_watcher, POLLIN); + uv__close(loop->async_io_watcher.fd); + loop->async_io_watcher.fd = -1; } diff --git a/src/unix/internal.h b/src/unix/internal.h index b48f8fa59..8e05fc853 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -194,10 +194,7 @@ int uv__io_check_fd(uv_loop_t* loop, int fd); void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ /* async */ -void uv__async_send(struct uv__async* wa); -void uv__async_init(struct uv__async* wa); -int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb); -void uv__async_stop(uv_loop_t* loop, struct uv__async* wa); +void uv__async_stop(uv_loop_t* loop); /* loop */ void uv__run_idle(uv_loop_t* loop); diff --git a/src/unix/loop.c b/src/unix/loop.c index bd63c2f9d..d620bf2c8 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -54,7 +54,8 @@ int uv_loop_init(uv_loop_t* loop) { loop->closing_handles = NULL; uv__update_time(loop); - uv__async_init(&loop->async_watcher); + loop->async_io_watcher.fd = -1; + loop->async_wfd = -1; loop->signal_pipefd[0] = -1; loop->signal_pipefd[1] = -1; loop->backend_fd = -1; @@ -111,7 +112,7 @@ int uv_loop_init(uv_loop_t* loop) { void uv__loop_close(uv_loop_t* loop) { uv__signal_loop_cleanup(loop); uv__platform_loop_delete(loop); - uv__async_stop(loop, &loop->async_watcher); + uv__async_stop(loop); if (loop->emfile_fd != -1) { uv__close(loop->emfile_fd); From 7b9f379923fc97817c873e25b34d46bb68897f8e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 15 Mar 2017 12:00:57 +0100 Subject: [PATCH 335/632] samples: update timer callback prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The socks5 proxy sample application was still using the old prototype where timer callbacks take a second 'status' parameter but that was removed in commit db2a9072 ("unix, windows: removed unused status parameter") from March 2014. PR-URL: https://github.com/libuv/libuv/pull/1250 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- samples/socks5-proxy/client.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/samples/socks5-proxy/client.c b/samples/socks5-proxy/client.c index ae9913a1c..aa2a91c9a 100644 --- a/samples/socks5-proxy/client.c +++ b/samples/socks5-proxy/client.c @@ -95,7 +95,7 @@ static int do_kill(client_ctx *cx); static int do_almost_dead(client_ctx *cx); static int conn_cycle(const char *who, conn *a, conn *b); static void conn_timer_reset(conn *c); -static void conn_timer_expire(uv_timer_t *handle, int status); +static void conn_timer_expire(uv_timer_t *handle); static void conn_getaddrinfo(conn *c, const char *hostname); static void conn_getaddrinfo_done(uv_getaddrinfo_t *req, int status, @@ -582,10 +582,9 @@ static void conn_timer_reset(conn *c) { 0)); } -static void conn_timer_expire(uv_timer_t *handle, int status) { +static void conn_timer_expire(uv_timer_t *handle) { conn *c; - CHECK(0 == status); c = CONTAINER_OF(handle, conn, timer_handle); c->result = UV_ETIMEDOUT; do_next(c->client); From fd7ce57f2b14651482c227898f6999664db937de Mon Sep 17 00:00:00 2001 From: Jason Madden Date: Fri, 22 Apr 2016 14:16:31 -0500 Subject: [PATCH 336/632] unix: make loops and watchers usable after fork() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added the uv_loop_fork() API that must be called in a child process to continue using an existing loop. Internally this calls a uv__io_fork function for each supported platform, similar to the way uv__platform_loop_init works. After this call, existing and new IO, async and signal watchers will contiue working as before on all platforms, as will the threadpool (although any threads it was using are of course gone). On Linux and BSDs that use kqueue, existing and new fsevent watchers will also continue to work as expected. On OS X, though, directory fsevents will not be able to use the optimized CoreFoundation path if they had already been used in the parent process, instead falling back to the kqueue path used on other BSDs. Existing fsevent watchers will not function on AIX or SunOS. This could be relatively easily fixed by someone with AIX knowledge in the future, but SunOS will require some additional work to keep track if the watchers. A new test file, test/test-fork.c, was added to contain fork-related tests to verify functionality in the child process. PR-URL: https://github.com/libuv/libuv/pull/846 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 1 + docs/src/loop.rst | 49 +++ include/uv.h | 1 + src/threadpool.c | 23 +- src/unix/aix.c | 7 + src/unix/async.c | 10 + src/unix/internal.h | 8 + src/unix/kqueue.c | 36 ++- src/unix/linux-core.c | 18 ++ src/unix/linux-inotify.c | 67 ++++ src/unix/loop.c | 33 ++ src/unix/signal.c | 37 +++ src/unix/sunos.c | 12 + src/win/core.c | 5 + test/test-fork.c | 669 +++++++++++++++++++++++++++++++++++++++ test/test-list.h | 24 ++ uv.gyp | 1 + 17 files changed, 999 insertions(+), 2 deletions(-) create mode 100644 test/test-fork.c diff --git a/Makefile.am b/Makefile.am index 85e7aaa83..c84859f60 100644 --- a/Makefile.am +++ b/Makefile.am @@ -172,6 +172,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-fs-event.c \ test/test-fs-poll.c \ test/test-fs.c \ + test/test-fork.c \ test/test-get-currentexe.c \ test/test-get-loadavg.c \ test/test-get-memory.c \ diff --git a/docs/src/loop.rst b/docs/src/loop.rst index 1f504cb39..b3fa069ef 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -165,3 +165,52 @@ API .. c:function:: void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) Walk the list of handles: `walk_cb` will be executed with the given `arg`. + +.. c:function:: int uv_loop_fork(uv_loop_t* loop) + + .. versionadded:: 1.12.0 + + Reinitialize any kernel state necessary in the child process after + a :man:`fork(2)` system call. + + Previously started watchers will continue to be started in the + child process. + + It is necessary to explicitly call this function on every event + loop created in the parent process that you plan to continue to + use in the child, including the default loop (even if you don't + continue to use it in the parent). This function must be called + before calling :c:func:`uv_run` or any other API function using + the loop in the child. Failure to do so will result in undefined + behaviour, possibly including duplicate events delivered to both + parent and child or aborting the child process. + + When possible, it is preferred to create a new loop in the child + process instead of reusing a loop created in the parent. New loops + created in the child process after the fork should not use this + function. + + This function is not implemented on Windows, where it returns ``UV_ENOSYS``. + + .. note:: + + On Mac OS X, if directory FS event handles were in use in the + parent process *for any event loop*, the child process will no + longer be able to use the most efficient FSEvent + implementation. Instead, uses of directory FS event handles in + the child will fall back to the same implementation used for + files and on other kqueue-based systems. + + .. caution:: + + On AIX and SunOS, FS event handles that were already started in + the parent process at the time of forking will *not* deliver + events in the child process; they must be closed and restarted. + On all other platforms, they will continue to work normally + without any further intervention. + + .. caution:: + + Any previous value returned from :c:func`uv_backend_fd` is now + invalid. That function must be called again to determine the + correct backend file descriptor. diff --git a/include/uv.h b/include/uv.h index 9745bd290..14e09e449 100644 --- a/include/uv.h +++ b/include/uv.h @@ -274,6 +274,7 @@ UV_EXTERN void uv_loop_delete(uv_loop_t*); UV_EXTERN size_t uv_loop_size(void); UV_EXTERN int uv_loop_alive(const uv_loop_t* loop); UV_EXTERN int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...); +UV_EXTERN int uv_loop_fork(uv_loop_t* loop); UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode); UV_EXTERN void uv_stop(uv_loop_t*); diff --git a/src/threadpool.c b/src/threadpool.c index 2c5152b42..a89400697 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -139,7 +139,7 @@ UV_DESTRUCTOR(static void cleanup(void)) { #endif -static void init_once(void) { +static void init_threads(void) { unsigned int i; const char* val; @@ -177,6 +177,27 @@ static void init_once(void) { } +#ifndef _WIN32 +static void reset_once(void) { + uv_once_t child_once = UV_ONCE_INIT; + memcpy(&once, &child_once, sizeof(child_once)); +} +#endif + + +static void init_once(void) { +#ifndef _WIN32 + /* Re-initialize the threadpool after fork. + * Note that this discards the global mutex and condition as well + * as the work queue. + */ + if (pthread_atfork(NULL, NULL, &reset_once)) + abort(); +#endif + init_threads(); +} + + void uv__work_submit(uv_loop_t* loop, struct uv__work* w, void (*work)(struct uv__work* w), diff --git a/src/unix/aix.c b/src/unix/aix.c index 1d2cd4a80..388c9cca9 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -96,6 +96,13 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } +int uv__io_fork(uv_loop_t* loop) { + uv__platform_loop_delete(loop); + + return uv__platform_loop_init(loop); +} + + int uv__io_check_fd(uv_loop_t* loop, int fd) { struct poll_ctl pc; diff --git a/src/unix/async.c b/src/unix/async.c index 61180dc95..2cb00579c 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -200,6 +200,16 @@ static int uv__async_start(uv_loop_t* loop) { } +int uv__async_fork(uv_loop_t* loop) { + if (loop->async_io_watcher.fd == -1) /* never started */ + return 0; + + uv__async_stop(loop); + + return uv__async_start(loop); +} + + void uv__async_stop(uv_loop_t* loop) { if (loop->async_io_watcher.fd == -1) return; diff --git a/src/unix/internal.h b/src/unix/internal.h index 8e05fc853..10bc3d222 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -192,9 +192,12 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w); int uv__io_active(const uv__io_t* w, unsigned int events); int uv__io_check_fd(uv_loop_t* loop, int fd); void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ +int uv__io_fork(uv_loop_t* loop); /* async */ void uv__async_stop(uv_loop_t* loop); +int uv__async_fork(uv_loop_t* loop); + /* loop */ void uv__run_idle(uv_loop_t* loop); @@ -230,6 +233,7 @@ int uv__next_timeout(const uv_loop_t* loop); void uv__signal_close(uv_signal_t* handle); void uv__signal_global_once_init(void); void uv__signal_loop_cleanup(uv_loop_t* loop); +int uv__signal_loop_fork(uv_loop_t* loop); /* platform specific */ uint64_t uv__hrtime(uv_clocktype_t type); @@ -324,4 +328,8 @@ UV_UNUSED(static char* uv__basename_r(const char* path)) { return s + 1; } +#if defined(__linux__) +int uv__inotify_fork(uv_loop_t* loop, void* old_watchers); +#endif + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index fffd4626f..6bc60bbe4 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -48,6 +48,37 @@ int uv__kqueue_init(uv_loop_t* loop) { } +static int uv__has_forked_with_cfrunloop; + +int uv__io_fork(uv_loop_t* loop) { + int err; + uv__close(loop->backend_fd); + loop->backend_fd = -1; + err = uv__kqueue_init(loop); + if (err) + return err; + +#if defined(__APPLE__) + if (loop->cf_state != NULL) { + /* We cannot start another CFRunloop and/or thread in the child + process; CF aborts if you try or if you try to touch the thread + at all to kill it. So the best we can do is ignore it from now + on. This means we can't watch directories in the same way + anymore (like other BSDs). It also means we cannot properly + clean up the allocated resources; calling + uv__fsevents_loop_delete from uv_loop_close will crash the + process. So we sidestep the issue by pretending like we never + started it in the first place. + */ + uv__has_forked_with_cfrunloop = 1; + uv__free(loop->cf_state); + loop->cf_state = NULL; + } +#endif + return err; +} + + int uv__io_check_fd(uv_loop_t* loop, int fd) { struct kevent ev; int rc; @@ -404,6 +435,9 @@ int uv_fs_event_start(uv_fs_event_t* handle, handle->cb = cb; #if defined(__APPLE__) + if (uv__has_forked_with_cfrunloop) + goto fallback; + /* Nullify field to perform checks later */ handle->cf_cb = NULL; handle->realpath = NULL; @@ -438,7 +472,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { uv__handle_stop(handle); #if defined(__APPLE__) - if (uv__fsevents_close(handle)) + if (uv__has_forked_with_cfrunloop || uv__fsevents_close(handle)) #endif /* defined(__APPLE__) */ { uv__io_close(handle->loop, &handle->event_watcher); diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 96b150de6..646be4fb1 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -107,6 +107,24 @@ int uv__platform_loop_init(uv_loop_t* loop) { } +int uv__io_fork(uv_loop_t* loop) { + int err; + void* old_watchers; + + old_watchers = loop->inotify_watchers; + + uv__close(loop->backend_fd); + loop->backend_fd = -1; + uv__platform_loop_delete(loop); + + err = uv__platform_loop_init(loop); + if (err) + return err; + + return uv__inotify_fork(loop, old_watchers); +} + + void uv__platform_loop_delete(uv_loop_t* loop) { if (loop->inotify_fd == -1) return; uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN); diff --git a/src/unix/linux-inotify.c b/src/unix/linux-inotify.c index 4708c051d..5934c5d8c 100644 --- a/src/unix/linux-inotify.c +++ b/src/unix/linux-inotify.c @@ -61,6 +61,8 @@ 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 new_inotify_fd(void) { int err; @@ -108,6 +110,71 @@ static int init_inotify(uv_loop_t* loop) { } +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; diff --git a/src/unix/loop.c b/src/unix/loop.c index d620bf2c8..bcd49242c 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -109,6 +109,39 @@ int uv_loop_init(uv_loop_t* loop) { } +int uv_loop_fork(uv_loop_t* loop) { + int err; + unsigned int i; + uv__io_t* w; + + err = uv__io_fork(loop); + if (err) + return err; + + err = uv__async_fork(loop); + if (err) + return err; + + err = uv__signal_loop_fork(loop); + if (err) + return err; + + /* Rearm all the watchers that aren't re-queued by the above. */ + for (i = 0; i < loop->nwatchers; i++) { + w = loop->watchers[i]; + if (w == NULL) + continue; + + if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) { + w->events = 0; /* Force re-registration in uv__io_poll. */ + QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); + } + } + + return 0; +} + + void uv__loop_close(uv_loop_t* loop) { uv__signal_loop_cleanup(loop); uv__platform_loop_delete(loop); diff --git a/src/unix/signal.c b/src/unix/signal.c index 63032dcb7..cb09ead50 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -58,8 +58,19 @@ RB_GENERATE_STATIC(uv__signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare) +static void uv__signal_global_reinit(void); static void uv__signal_global_init(void) { + if (!uv__signal_lock_pipefd[0]) + /* pthread_atfork can register before and after handlers, one + * for each child. This only registers one for the child. That + * state is both persistent and cumulative, so if we keep doing + * it the handler functions will be called multiple times. Thus + * we only want to do it once. + */ + if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit)) + abort(); + if (uv__make_pipe(uv__signal_lock_pipefd, 0)) abort(); @@ -68,6 +79,22 @@ static void uv__signal_global_init(void) { } +static void uv__signal_global_reinit(void) { + /* We can only use signal-safe functions here. + * That includes read/write and close, fortunately. + * We do all of this directly here instead of resetting + * uv__signal_global_init_guard because + * uv__signal_global_once_init is only called from uv_loop_init + * and this needs to function in existing loops. + */ + uv__close(uv__signal_lock_pipefd[0]); + uv__signal_lock_pipefd[0] = -1; + uv__close(uv__signal_lock_pipefd[1]); + uv__signal_lock_pipefd[1] = -1; + uv__signal_global_init(); +} + + void uv__signal_global_once_init(void) { uv_once(&uv__signal_global_init_guard, uv__signal_global_init); } @@ -235,6 +262,16 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) { } +int uv__signal_loop_fork(uv_loop_t* loop) { + uv__io_stop(loop, &loop->signal_io_watcher, POLLIN); + uv__close(loop->signal_pipefd[0]); + uv__close(loop->signal_pipefd[1]); + loop->signal_pipefd[0] = -1; + loop->signal_pipefd[1] = -1; + return uv__signal_loop_once_init(loop); +} + + void uv__signal_loop_cleanup(uv_loop_t* loop) { QUEUE* q; diff --git a/src/unix/sunos.c b/src/unix/sunos.c index a76a08bd9..b310247fc 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -99,6 +99,18 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } +int uv__io_fork(uv_loop_t* loop) { +#if defined(PORT_SOURCE_FILE) + if (loop->fs_fd != -1) { + /* stop the watcher before we blow away its fileno */ + uv__io_stop(loop, &loop->fs_event_watcher, POLLIN); + } +#endif + uv__platform_loop_delete(loop); + return uv__platform_loop_init(loop); +} + + void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { struct port_event* events; uintptr_t i; diff --git a/src/win/core.c b/src/win/core.c index e84186d4e..cd480034f 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -332,6 +332,11 @@ int uv_backend_fd(const uv_loop_t* loop) { } +int uv_loop_fork(uv_loop_t* loop) { + return UV_ENOSYS; +} + + int uv_backend_timeout(const uv_loop_t* loop) { if (loop->stop_flag != 0) return 0; diff --git a/test/test-fork.c b/test/test-fork.c new file mode 100644 index 000000000..24e74c80a --- /dev/null +++ b/test/test-fork.c @@ -0,0 +1,669 @@ +/* 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. + */ + +/* These tests are Unix only. */ +#ifndef _WIN32 + +#include +#include +#include +#include + +#include "uv.h" +#include "task.h" + +static int timer_cb_called; +static int socket_cb_called; + +static void timer_cb(uv_timer_t* timer) { + timer_cb_called++; + uv_close((uv_handle_t*) timer, NULL); +} + + +static int socket_cb_read_fd; +static int socket_cb_read_size; +static char socket_cb_read_buf[1024]; + + +static void socket_cb(uv_poll_t* poll, int status, int events) { + ssize_t cnt; + cnt = 0; + socket_cb_called++; + ASSERT(0 == status); + printf("Socket cb got events %d\n", events); + ASSERT(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); + } + uv_close((uv_handle_t*) poll, NULL); +} + + +static void run_timer_loop_once(void) { + uv_loop_t* loop; + uv_timer_t timer_handle; + + loop = uv_default_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); +} + + +static void assert_wait_child(pid_t child_pid) { + pid_t waited_pid; + int child_stat; + + waited_pid = waitpid(child_pid, &child_stat, 0); + printf("Waited pid is %d with status %d\n", waited_pid, child_stat); + if (waited_pid == -1) { + perror("Failed to wait"); + } + ASSERT(child_pid == waited_pid); + ASSERT(WIFEXITED(child_stat)); /* Clean exit, not a signal. */ + ASSERT(!WIFSIGNALED(child_stat)); + ASSERT(0 == WEXITSTATUS(child_stat)); +} + + +TEST_IMPL(fork_timer) { + /* Timers continue to work after we fork. */ + + /* + * Establish the loop before we fork to make sure that it + * has state to get reset after the fork. + */ + pid_t child_pid; + + run_timer_loop_once(); + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + assert_wait_child(child_pid); + } else { + /* child */ + ASSERT(0 == uv_loop_fork(uv_default_loop())); + run_timer_loop_once(); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fork_socketpair) { + /* A socket opened in the parent and accept'd in the + child works after a fork. */ + pid_t child_pid; + int socket_fds[2]; + uv_poll_t poll_handle; + + /* Prime the loop. */ + run_timer_loop_once(); + + ASSERT(0 == 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])); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + ASSERT(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)); + 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); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fork_socketpair_started) { + /* A socket opened in the parent and accept'd in the + child works after a fork, even if the watcher was already + started, and then stopped in the parent. */ + pid_t child_pid; + int socket_fds[2]; + int sync_pipe[2]; + char sync_buf[1]; + uv_poll_t poll_handle; + + ASSERT(0 == pipe(sync_pipe)); + + /* Prime the loop. */ + run_timer_loop_once(); + + ASSERT(0 == 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)); + + /* 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)); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + ASSERT(0 == 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(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(0 == 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); + + 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); + printf("Buf %s\n", socket_cb_read_buf); + ASSERT(0 == strcmp("hi\n", socket_cb_read_buf)); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static int fork_signal_cb_called; + +void fork_signal_to_child_cb(uv_signal_t* handle, int signum) +{ + fork_signal_cb_called = signum; + uv_close((uv_handle_t*)handle, NULL); +} + + +TEST_IMPL(fork_signal_to_child) { + /* A signal handler installed before forking + is run only in the child when the child is signalled. */ + uv_signal_t signal_handle; + pid_t child_pid; + int sync_pipe[2]; + char sync_buf[1]; + + fork_signal_cb_called = 0; /* reset */ + + ASSERT(0 == 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)); + + child_pid = fork(); + ASSERT(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)); + /* 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); + 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 */ + /* Get the signal. */ + ASSERT(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); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(fork_signal_to_child_closed) { + /* A signal handler installed before forking + doesn't get received anywhere when the child is signalled, + but isnt running the loop. */ + uv_signal_t signal_handle; + pid_t child_pid; + int sync_pipe[2]; + int sync_pipe2[2]; + char sync_buf[1]; + + fork_signal_cb_called = 0; /* reset */ + + ASSERT(0 == pipe(sync_pipe)); + ASSERT(0 == 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)); + + child_pid = fork(); + ASSERT(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 */ + printf("Parent killing child\n"); + ASSERT(0 == 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)); + 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 */ + 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())); + printf("Checking loop in child\n"); + ASSERT(0 != uv_loop_alive(uv_default_loop())); + printf("Alerting parent in child\n"); + ASSERT(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 + and exited, so this isn't in an ASSERT. + */ + read(sync_pipe2[0], sync_buf, 1); + ASSERT(0 == 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, + * so the child default loop can't be cleanly closed. + * We need te explicitly exit to avoid an automatic failure + * in that case. + */ + exit(0); + } + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static void create_file(const char* name) { + int r; + uv_file file; + uv_fs_t req; + + r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); + ASSERT(r >= 0); + file = r; + uv_fs_req_cleanup(&req); + r = uv_fs_close(NULL, &req, file, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); +} + + +static void touch_file(const char* name) { + int r; + uv_file file; + uv_fs_t req; + uv_buf_t buf; + + r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL); + ASSERT(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); + uv_fs_req_cleanup(&req); + + r = uv_fs_close(NULL, &req, file, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); +} + + +static int timer_cb_touch_called; + +static void timer_cb_touch(uv_timer_t* timer) { + uv_close((uv_handle_t*)timer, NULL); + touch_file("watch_file"); + timer_cb_touch_called++; +} + + +static int fs_event_cb_called; + +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(status == 0); +#if defined(__APPLE__) || defined(__linux__) + ASSERT(strcmp(filename, "watch_file") == 0); +#else + ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0); +#endif + uv_close((uv_handle_t*)handle, NULL); +} + + +static void assert_watch_file_current_dir(uv_loop_t* const loop, int file_or_dir) { + uv_timer_t timer; + uv_fs_event_t fs_event; + int r; + + /* Setup */ + remove("watch_file"); + create_file("watch_file"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + /* 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); + + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb_touch, 100, 0); + ASSERT(r == 0); + + ASSERT(timer_cb_touch_called == 0); + ASSERT(fs_event_cb_called == 0); + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(timer_cb_touch_called == 1); + ASSERT(fs_event_cb_called == 1); + + /* Cleanup */ + remove("watch_file"); + fs_event_cb_called = 0; + timer_cb_touch_called = 0; + uv_run(loop, UV_RUN_DEFAULT); /* flush pending closes */ +} + + +#define FS_TEST_FILE 0 +#define FS_TEST_DIR 1 + +static int _do_fork_fs_events_child(int file_or_dir) { + /* basic fsevents work in the child after a fork */ + pid_t child_pid; + uv_loop_t loop; + + /* Watch in the parent, prime the loop and/or threads. */ + assert_watch_file_current_dir(uv_default_loop(), file_or_dir); + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + assert_wait_child(child_pid); + } else { + /* child */ + /* Ee can watch in a new loop, but dirs only work + if we're on linux. */ +#if defined(__APPLE__) + file_or_dir = FS_TEST_FILE; +#endif + printf("Running child\n"); + uv_loop_init(&loop); + printf("Child first watch\n"); + assert_watch_file_current_dir(&loop, file_or_dir); + ASSERT(0 == 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())); + /* 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 + * a general race. + */ + uv_update_time(uv_default_loop()); + assert_watch_file_current_dir(uv_default_loop(), file_or_dir); + + /* We can close the parent loop successfully too. This is + 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())); + + printf("Exiting child \n"); + } + + MAKE_VALGRIND_HAPPY(); + return 0; + +} + + +TEST_IMPL(fork_fs_events_child) { + return _do_fork_fs_events_child(FS_TEST_FILE); +} + + +TEST_IMPL(fork_fs_events_child_dir) { +#if defined(__APPLE__) || defined (__linux__) + return _do_fork_fs_events_child(FS_TEST_DIR); +#else + /* You can't spin up a cfrunloop thread on an apple platform + and then fork. See + http://objectivistc.tumblr.com/post/16187948939/you-must-exec-a-core-foundation-fork-safety-tale + */ + return 0; +#endif +} + + +TEST_IMPL(fork_fs_events_file_parent_child) { +#if defined(__sun) || defined(_AIX) + /* It's not possible to implement this without additional + * bookkeeping on SunOS. For AIX it is possible, but has to be + * written. See https://github.com/libuv/libuv/pull/846#issuecomment-287170420 + */ + return 0; +#else + /* Establishing a started fs events watcher in the parent should + still work in the child. */ + uv_timer_t timer; + uv_fs_event_t fs_event; + int r; + pid_t child_pid; + uv_loop_t* loop; + + loop = uv_default_loop(); + + /* Setup */ + remove("watch_file"); + create_file("watch_file"); + + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, + fs_event_cb_file_current_dir, + "watch_file", + 0); + ASSERT(r == 0); + + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + + child_pid = fork(); + ASSERT(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)); + + r = uv_timer_start(&timer, timer_cb_touch, 100, 0); + ASSERT(r == 0); + + ASSERT(timer_cb_touch_called == 0); + ASSERT(fs_event_cb_called == 0); + printf("Running loop in child \n"); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(timer_cb_touch_called == 1); + ASSERT(fs_event_cb_called == 1); + + /* Cleanup */ + remove("watch_file"); + fs_event_cb_called = 0; + timer_cb_touch_called = 0; + uv_run(loop, UV_RUN_DEFAULT); /* Flush pending closes. */ + } + + + MAKE_VALGRIND_HAPPY(); + return 0; +#endif +} + + +static int work_cb_count; +static int after_work_cb_count; + + +static void work_cb(uv_work_t* req) { + work_cb_count++; +} + + +static void after_work_cb(uv_work_t* req, int status) { + ASSERT(status == 0); + after_work_cb_count++; +} + + +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); + printf("Queue in %d\n", getpid()); + r = uv_queue_work(loop, &work_req, work_cb, after_work_cb); + ASSERT(r == 0); + printf("Running in %d\n", getpid()); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(work_cb_count == 1); + ASSERT(after_work_cb_count == 1); + + /* cleanup */ + work_cb_count = 0; + after_work_cb_count = 0; +} + + +TEST_IMPL(fork_threadpool_queue_work_simple) { + /* The threadpool works in a child process. */ + + pid_t child_pid; + uv_loop_t loop; + + /* Prime the pool and default loop. */ + assert_run_work(uv_default_loop()); + + child_pid = fork(); + ASSERT(child_pid != -1); + + if (child_pid != 0) { + /* parent */ + /* We can still run work. */ + assert_run_work(uv_default_loop()); + assert_wait_child(child_pid); + } else { + /* child */ + /* We can work in a new loop. */ + printf("Running child in %d\n", getpid()); + uv_loop_init(&loop); + printf("Child first watch\n"); + assert_run_work(&loop); + 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_run_work(uv_default_loop()); + printf("Exiting child \n"); + } + + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +#endif /* !_WIN32 */ diff --git a/test/test-list.h b/test/test-list.h index 46da5fdae..ecbcb7b5c 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -371,6 +371,18 @@ HELPER_DECLARE (pipe_echo_server) TEST_DECLARE (queue_foreach_delete) +#ifndef _WIN32 +TEST_DECLARE (fork_timer) +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_fs_events_child) +TEST_DECLARE (fork_fs_events_child_dir) +TEST_DECLARE (fork_fs_events_file_parent_child) +TEST_DECLARE (fork_threadpool_queue_work_simple) +#endif + TASK_LIST_START TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000) @@ -797,6 +809,18 @@ TASK_LIST_START TEST_ENTRY (queue_foreach_delete) +#ifndef _WIN32 + TEST_ENTRY (fork_timer) + TEST_ENTRY (fork_socketpair) + TEST_ENTRY (fork_socketpair_started) + TEST_ENTRY (fork_signal_to_child) + TEST_ENTRY (fork_signal_to_child_closed) + TEST_ENTRY (fork_fs_events_child) + TEST_ENTRY (fork_fs_events_child_dir) + TEST_ENTRY (fork_fs_events_file_parent_child) + TEST_ENTRY (fork_threadpool_queue_work_simple) +#endif + #if 0 /* These are for testing the test runner. */ TEST_ENTRY (fail_always) diff --git a/uv.gyp b/uv.gyp index 41cae412f..71ad2dd48 100644 --- a/uv.gyp +++ b/uv.gyp @@ -349,6 +349,7 @@ 'test/test-emfile.c', 'test/test-env-vars.c', 'test/test-fail-always.c', + 'test/test-fork.c', 'test/test-fs.c', 'test/test-fs-event.c', 'test/test-get-currentexe.c', From e7a7ffb1524326d6a431f219b07278ceaebac915 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 17 Mar 2017 14:02:10 -0400 Subject: [PATCH 337/632] win: free uv__loops once empty This commit moves the allocation of uv__loops into uv__loops_add() and frees all of the memory associated with uv__loops in uv__loops_remove() once the loop count reaches zero. Fixes: https://github.com/libuv/libuv/issues/1125 Fixes: https://github.com/libuv/libuv/issues/1252 PR-URL: https://github.com/libuv/libuv/pull/1262 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- src/win/core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/win/core.c b/src/win/core.c index cd480034f..cc8418720 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -85,11 +85,6 @@ static uv_mutex_t uv__loops_lock; static void uv__loops_init() { uv_mutex_init(&uv__loops_lock); - uv__loops = uv__calloc(UV__LOOPS_CHUNK_SIZE, sizeof(uv_loop_t*)); - if (!uv__loops) - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - uv__loops_size = 0; - uv__loops_capacity = UV__LOOPS_CHUNK_SIZE; } static int uv__loops_add(uv_loop_t* loop) { @@ -138,6 +133,13 @@ static void uv__loops_remove(uv_loop_t* loop) { uv__loops[uv__loops_size - 1] = NULL; --uv__loops_size; + if (uv__loops_size == 0) { + uv__loops_capacity = 0; + uv__free(uv__loops); + uv__loops = NULL; + goto loop_removed; + } + /* If we didn't grow to big skip downsizing */ if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE) goto loop_removed; From 7e36c94e564c3b04134b2d07d10f98ae0ed218f8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 15 Mar 2017 19:20:01 +0100 Subject: [PATCH 338/632] tools: add make_dist_html.py script Add a script to generate the http://dist.libuv.org/ download page from the tags in the git repository. The HTML is a work of tearful beauty. PR-URL: https://github.com/libuv/libuv/pull/1251 Reviewed-By: Colin Ihrig --- tools/make_dist_html.py | 124 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 tools/make_dist_html.py diff --git a/tools/make_dist_html.py b/tools/make_dist_html.py new file mode 100644 index 000000000..7a19d3e11 --- /dev/null +++ b/tools/make_dist_html.py @@ -0,0 +1,124 @@ +#!/usr/bin/python + +from __future__ import print_function + +import itertools +import os +import re +import subprocess + +HTML = r''' + + + + + + + + + {groups}
+ + +''' + +GROUPS = r''' + + {groups[0]} + {groups[1]} + {groups[2]} + {groups[3]} + +''' + +GROUP = r''' + + + + + + + + {rows} +
versiontarballgpgwindows
+''' + +ROW = r''' + + + {tag} + + + tarball + + {maybe_gpg} + {maybe_exe} + +''' + +GPG = r''' +gpg +''' + +# The binaries don't have a predictable name, link to the directory instead. +EXE = r''' +exe +''' + +def version(tag): + return map(int, re.match('^v(\d+)\.(\d+)\.(\d+)', tag).groups()) + +def major_minor(tag): + return version(tag)[:2] + +def row_for(tag): + maybe_gpg = '' + maybe_exe = '' + # We didn't start signing releases and producing Windows installers + # until v1.7.0. + if version(tag) >= version('v1.7.0'): + maybe_gpg = GPG.format(**locals()) + maybe_exe = EXE.format(**locals()) + return ROW.format(**locals()) + +def group_for(tags): + rows = ''.join(row_for(tag) for tag in tags) + return GROUP.format(rows=rows) + +# Partition in groups of |n|. +def groups_for(groups, n=4): + html = '' + groups = groups[:] + [''] * (n - 1) + while len(groups) >= n: + html += GROUPS.format(groups=groups) + groups = groups[n:] + return html + +if __name__ == '__main__': + os.chdir(os.path.dirname(__file__)) + tags = subprocess.check_output(['git', 'tag']) + tags = [tag for tag in tags.split('\n') if tag.startswith('v')] + tags.sort(key=version, reverse=True) + groups = [group_for(list(g)) for _, g in itertools.groupby(tags, major_minor)] + groups = groups_for(groups) + html = HTML.format(groups=groups).strip() + html = re.sub('>\\s+<', '><', html) + print(html) From 463800ffc1bf35138c3407c385b2474b743ee579 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 16 Mar 2017 21:20:11 -0400 Subject: [PATCH 339/632] win,sunos: stop handle on uv_fs_event_start() err This commit stops the handle in uv_fs_event_start() when an error occurs. Fixes: https://github.com/libuv/libuv/issues/1253 PR-URL: https://github.com/libuv/libuv/pull/1257 Reviewed-By: Santiago Gimeno --- src/unix/sunos.c | 4 +++- src/win/fs-event.c | 3 +++ test/test-fs-event.c | 18 ++++++++++++++++++ test/test-list.h | 2 ++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/unix/sunos.c b/src/unix/sunos.c index b310247fc..c34b870ec 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -481,8 +481,10 @@ int uv_fs_event_start(uv_fs_event_t* handle, memset(&handle->fo, 0, sizeof handle->fo); handle->fo.fo_name = handle->path; err = uv__fs_event_rearm(handle); - if (err != 0) + if (err != 0) { + uv_fs_event_stop(handle); return err; + } if (first_run) { uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd); diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 05fc1d016..675b5bda9 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -306,6 +306,9 @@ int uv_fs_event_start(uv_fs_event_t* handle, handle->buffer = NULL; } + if (uv__is_active(handle)) + uv__handle_stop(handle); + return uv_translate_sys_error(last_error); } diff --git a/test/test-fs-event.c b/test/test-fs-event.c index df8dc4c2f..c78b34669 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -1027,3 +1027,21 @@ TEST_IMPL(fs_event_error_reporting) { } #endif /* defined(__APPLE__) */ + +TEST_IMPL(fs_event_watch_invalid_path) { +#if defined(MVS) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif + + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + 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(); + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index ecbcb7b5c..8b19b6c31 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -287,6 +287,7 @@ TEST_DECLARE (fs_event_watch_file_current_dir) #ifdef _WIN32 TEST_DECLARE (fs_event_watch_file_root_dir) #endif +TEST_DECLARE (fs_event_watch_invalid_path) TEST_DECLARE (fs_event_no_callback_after_close) TEST_DECLARE (fs_event_no_callback_on_close) TEST_DECLARE (fs_event_immediate_close) @@ -764,6 +765,7 @@ TASK_LIST_START #ifdef _WIN32 TEST_ENTRY (fs_event_watch_file_root_dir) #endif + TEST_ENTRY (fs_event_watch_invalid_path) TEST_ENTRY (fs_event_no_callback_after_close) TEST_ENTRY (fs_event_no_callback_on_close) TEST_ENTRY (fs_event_immediate_close) From 87df1448a48fb64c2b9ebe37e3344f7e5b81dd88 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 14 Oct 2016 05:08:13 +0200 Subject: [PATCH 340/632] unix,windows: refactor request init logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a TODO in src/threadpool.c. Updates the Windows code to drop the unused `loop` parameter in calls to uv_req_init(). PR-URL: https://github.com/libuv/libuv/pull/1091 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/threadpool.c | 12 ------------ src/unix/internal.h | 9 --------- src/uv-common.h | 24 ++++++++++++++++++++++++ src/win/async.c | 3 +-- src/win/fs-event.c | 3 +-- src/win/fs.c | 4 +--- src/win/getaddrinfo.c | 4 +--- src/win/getnameinfo.c | 3 +-- src/win/pipe.c | 14 +++++--------- src/win/poll.c | 6 ++---- src/win/process.c | 3 +-- src/win/req-inl.h | 9 +++------ src/win/signal.c | 8 ++------ src/win/stream-inl.h | 3 +-- src/win/stream.c | 3 +-- src/win/tcp.c | 13 ++++--------- src/win/tty.c | 3 +-- src/win/udp.c | 6 ++---- 18 files changed, 51 insertions(+), 79 deletions(-) diff --git a/src/threadpool.c b/src/threadpool.c index a89400697..108934112 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -23,18 +23,6 @@ #if !defined(_WIN32) # include "unix/internal.h" -#else -# include "win/req-inl.h" -/* TODO(saghul): unify internal req functions */ -static void uv__req_init(uv_loop_t* loop, - uv_req_t* req, - uv_req_type type) { - uv_req_init(loop, req); - req->type = type; - uv__req_register(loop, req); -} -# define uv__req_init(loop, req, type) \ - uv__req_init((loop), (uv_req_t*)(req), (type)) #endif #include diff --git a/src/unix/internal.h b/src/unix/internal.h index 10bc3d222..2e3afa6c8 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -303,15 +303,6 @@ static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000; #endif /* defined(__APPLE__) */ -UV_UNUSED(static void uv__req_init(uv_loop_t* loop, - uv_req_t* req, - uv_req_type type)) { - req->type = type; - uv__req_register(loop, req); -} -#define uv__req_init(loop, req, type) \ - uv__req_init((loop), (uv_req_t*)(req), (type)) - UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) { /* Use a fast time source if available. We only need millisecond precision. */ diff --git a/src/uv-common.h b/src/uv-common.h index b2b98e3bf..781a8559d 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -218,6 +218,30 @@ void uv__fs_scandir_cleanup(uv_fs_t* req); } \ while (0) +/* Note: uses an open-coded version of SET_REQ_SUCCESS() because of + * a circular dependency between src/uv-common.h and src/win/internal.h. + */ +#if defined(_WIN32) +# define UV_REQ_INIT(req, typ) \ + do { \ + (req)->type = (typ); \ + (req)->u.io.overlapped.Internal = 0; /* SET_REQ_SUCCESS() */ \ + } \ + while (0) +#else +# define UV_REQ_INIT(req, typ) \ + do { \ + (req)->type = (typ); \ + } \ + while (0) +#endif + +#define uv__req_init(loop, req, typ) \ + do { \ + UV_REQ_INIT(req, typ); \ + uv__req_register(loop, req); \ + } \ + while (0) /* Allocator prototypes */ void *uv__calloc(size_t count, size_t size); diff --git a/src/win/async.c b/src/win/async.c index ad240ab89..0b636ed1e 100644 --- a/src/win/async.c +++ b/src/win/async.c @@ -45,8 +45,7 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { handle->async_cb = async_cb; req = &handle->async_req; - uv_req_init(loop, req); - req->type = UV_WAKEUP; + UV_REQ_INIT(req, UV_WAKEUP); req->data = handle; uv__handle_start(handle); diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 675b5bda9..80a7c2398 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -131,8 +131,7 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { handle->short_filew = NULL; handle->dirw = NULL; - uv_req_init(loop, (uv_req_t*)&handle->req); - handle->req.type = UV_FS_EVENT_REQ; + UV_REQ_INIT(&handle->req, UV_FS_EVENT_REQ); handle->req.data = handle; return 0; diff --git a/src/win/fs.c b/src/win/fs.c index 6902d4f1a..7b87187a3 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -220,9 +220,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, uv_fs_type fs_type, const uv_fs_cb cb) { - uv_req_init(loop, (uv_req_t*) req); - - req->type = UV_FS; + UV_REQ_INIT(req, UV_FS); req->loop = loop; req->flags = 0; req->fs_type = fs_type; diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index c13bfec35..baab83889 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -265,11 +265,9 @@ int uv_getaddrinfo(uv_loop_t* loop, return UV_EINVAL; } - uv_req_init(loop, (uv_req_t*)req); - + UV_REQ_INIT(req, UV_GETADDRINFO); req->getaddrinfo_cb = getaddrinfo_cb; req->addrinfo = NULL; - req->type = UV_GETADDRINFO; req->loop = loop; req->retcode = 0; diff --git a/src/win/getnameinfo.c b/src/win/getnameinfo.c index 66b64b883..9f10cd2a5 100644 --- a/src/win/getnameinfo.c +++ b/src/win/getnameinfo.c @@ -127,12 +127,11 @@ int uv_getnameinfo(uv_loop_t* loop, return UV_EINVAL; } - uv_req_init(loop, (uv_req_t*)req); + UV_REQ_INIT(req, UV_GETNAMEINFO); uv__req_register(loop, req); req->getnameinfo_cb = getnameinfo_cb; req->flags = flags; - req->type = UV_GETNAMEINFO; req->loop = loop; req->retcode = 0; diff --git a/src/win/pipe.c b/src/win/pipe.c index 2442be730..473f1fc56 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -103,7 +103,7 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { handle->pipe.conn.non_overlapped_writes_tail = NULL; handle->pipe.conn.readfile_thread = NULL; - uv_req_init(loop, (uv_req_t*) &handle->pipe.conn.ipc_header_write_req); + UV_REQ_INIT(&handle->pipe.conn.ipc_header_write_req, UV_UNKNOWN_REQ); return 0; } @@ -505,8 +505,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { for (i = 0; i < handle->pipe.serv.pending_instances; i++) { req = &handle->pipe.serv.accept_reqs[i]; - uv_req_init(loop, (uv_req_t*) req); - req->type = UV_ACCEPT; + UV_REQ_INIT(req, UV_ACCEPT); req->data = handle; req->pipeHandle = INVALID_HANDLE_VALUE; req->next_pending = NULL; @@ -626,8 +625,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; - uv_req_init(loop, (uv_req_t*) req); - req->type = UV_CONNECT; + UV_REQ_INIT(req, UV_CONNECT); req->handle = (uv_stream_t*) handle; req->cb = cb; @@ -1239,8 +1237,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, assert(handle->handle != INVALID_HANDLE_VALUE); - uv_req_init(loop, (uv_req_t*) req); - req->type = UV_WRITE; + UV_REQ_INIT(req, UV_WRITE); req->handle = (uv_stream_t*) handle; req->cb = cb; req->ipc_header = 0; @@ -1301,8 +1298,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, } } - uv_req_init(loop, (uv_req_t*) ipc_header_req); - ipc_header_req->type = UV_WRITE; + UV_REQ_INIT(ipc_header_req, UV_WRITE); ipc_header_req->handle = (uv_stream_t*) handle; ipc_header_req->cb = NULL; ipc_header_req->ipc_header = 1; diff --git a/src/win/poll.c b/src/win/poll.c index d479e521e..0ade79a8b 100644 --- a/src/win/poll.c +++ b/src/win/poll.c @@ -572,13 +572,11 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, /* Initialize 2 poll reqs. */ handle->submitted_events_1 = 0; - uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1)); - handle->poll_req_1.type = UV_POLL_REQ; + UV_REQ_INIT(&handle->poll_req_1, UV_POLL_REQ); handle->poll_req_1.data = handle; handle->submitted_events_2 = 0; - uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2)); - handle->poll_req_2.type = UV_POLL_REQ; + UV_REQ_INIT(&handle->poll_req_2, UV_POLL_REQ); handle->poll_req_2.data = handle; return 0; diff --git a/src/win/process.c b/src/win/process.c index bdf88d2cd..d14160160 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -148,8 +148,7 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { handle->child_stdio_buffer = NULL; handle->exit_cb_pending = 0; - uv_req_init(loop, (uv_req_t*)&handle->exit_req); - handle->exit_req.type = UV_PROCESS_EXIT; + UV_REQ_INIT(&handle->exit_req, UV_PROCESS_EXIT); handle->exit_req.data = handle; } diff --git a/src/win/req-inl.h b/src/win/req-inl.h index b5e502eef..f2513b7d3 100644 --- a/src/win/req-inl.h +++ b/src/win/req-inl.h @@ -34,6 +34,9 @@ #define SET_REQ_ERROR(req, error) \ SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error))) +/* Note: used open-coded in UV_REQ_INIT() because of a circular dependency + * between src/uv-common.h and src/win/internal.h. + */ #define SET_REQ_SUCCESS(req) \ SET_REQ_STATUS((req), STATUS_SUCCESS) @@ -79,12 +82,6 @@ } -INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) { - req->type = UV_UNKNOWN_REQ; - SET_REQ_SUCCESS(req); -} - - INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) { return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped); } diff --git a/src/win/signal.c b/src/win/signal.c index 571563cb2..023fbf281 100644 --- a/src/win/signal.c +++ b/src/win/signal.c @@ -140,17 +140,13 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) { int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { - uv_req_t* req; - uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL); handle->pending_signum = 0; handle->signum = 0; handle->signal_cb = NULL; - req = &handle->signal_req; - uv_req_init(loop, req); - req->type = UV_SIGNAL_REQ; - req->data = handle; + UV_REQ_INIT(&handle->signal_req, UV_SIGNAL_REQ); + handle->signal_req.data = handle; return 0; } diff --git a/src/win/stream-inl.h b/src/win/stream-inl.h index b7a3c1195..bf12148af 100644 --- a/src/win/stream-inl.h +++ b/src/win/stream-inl.h @@ -43,10 +43,9 @@ INLINE static void uv_connection_init(uv_stream_t* handle) { handle->flags |= UV_HANDLE_CONNECTION; handle->stream.conn.write_reqs_pending = 0; - uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req)); + UV_REQ_INIT(&handle->read_req, UV_READ); handle->read_req.event_handle = NULL; handle->read_req.wait_handle = INVALID_HANDLE_VALUE; - handle->read_req.type = UV_READ; handle->read_req.data = handle; handle->stream.conn.shutdown_req = NULL; diff --git a/src/win/stream.c b/src/win/stream.c index a2466e5e9..13cbfdcb9 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -210,8 +210,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { return UV_EPIPE; } - uv_req_init(loop, (uv_req_t*) req); - req->type = UV_SHUTDOWN; + UV_REQ_INIT(req, UV_SHUTDOWN); req->handle = handle; req->cb = cb; diff --git a/src/win/tcp.c b/src/win/tcp.c index 0709696ff..972539f4d 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -555,7 +555,6 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { - uv_loop_t* loop = handle->loop; unsigned int i, simultaneous_accepts; uv_tcp_accept_t* req; int err; @@ -612,8 +611,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { for (i = 0; i < simultaneous_accepts; i++) { req = &handle->tcp.serv.accept_reqs[i]; - uv_req_init(loop, (uv_req_t*)req); - req->type = UV_ACCEPT; + UV_REQ_INIT(req, UV_ACCEPT); req->accept_socket = INVALID_SOCKET; req->data = handle; @@ -635,8 +633,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { /* try to clean up {uv_simultaneous_server_accepts} requests. */ for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) { req = &handle->tcp.serv.accept_reqs[i]; - uv_req_init(loop, (uv_req_t*) req); - req->type = UV_ACCEPT; + UV_REQ_INIT(req, UV_ACCEPT); req->accept_socket = INVALID_SOCKET; req->data = handle; req->wait_handle = INVALID_HANDLE_VALUE; @@ -779,8 +776,7 @@ static int uv_tcp_try_connect(uv_connect_t* req, } } - uv_req_init(loop, (uv_req_t*) req); - req->type = UV_CONNECT; + UV_REQ_INIT(req, UV_CONNECT); req->handle = (uv_stream_t*) handle; req->cb = cb; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); @@ -863,8 +859,7 @@ int uv_tcp_write(uv_loop_t* loop, int result; DWORD bytes; - uv_req_init(loop, (uv_req_t*) req); - req->type = UV_WRITE; + UV_REQ_INIT(req, UV_WRITE); req->handle = (uv_stream_t*) handle; req->cb = cb; diff --git a/src/win/tty.c b/src/win/tty.c index 1b7adf64f..cdd2ba066 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -2126,8 +2126,7 @@ int uv_tty_write(uv_loop_t* loop, uv_write_cb cb) { DWORD error; - uv_req_init(loop, (uv_req_t*) req); - req->type = UV_WRITE; + UV_REQ_INIT(req, UV_WRITE); req->handle = (uv_stream_t*) handle; req->cb = cb; diff --git a/src/win/udp.c b/src/win/udp.c index 9bf1453e5..2fd15cfa9 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -142,8 +142,7 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { handle->func_wsarecvfrom = WSARecvFrom; handle->send_queue_size = 0; handle->send_queue_count = 0; - uv_req_init(loop, (uv_req_t*) &(handle->recv_req)); - handle->recv_req.type = UV_UDP_RECV; + UV_REQ_INIT(&handle->recv_req, UV_UDP_RECV); handle->recv_req.data = handle; /* If anything fails beyond this point we need to remove the handle from @@ -417,8 +416,7 @@ static int uv__send(uv_udp_send_t* req, uv_loop_t* loop = handle->loop; DWORD result, bytes; - uv_req_init(loop, (uv_req_t*) req); - req->type = UV_UDP_SEND; + UV_REQ_INIT(req, UV_UDP_SEND); req->handle = handle; req->cb = cb; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); From 9d94fd978fc3fa8b32721ce523e46262ab88e392 Mon Sep 17 00:00:00 2001 From: Andreas Hauptmann Date: Mon, 20 Mar 2017 19:46:32 +0100 Subject: [PATCH 341/632] win: fix memory leak inside uv__pipe_getname MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1265 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/win/pipe.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index 473f1fc56..d64fadf63 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -2072,7 +2072,6 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) buffer[addrlen] = '\0'; err = 0; - goto cleanup; error: uv__free(name_info); From 671ad7839dc776235e8ee4126f4d3dd6c89611fd Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Tue, 21 Mar 2017 11:28:25 +0100 Subject: [PATCH 342/632] fsevent: support for files without short name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A call to GetShortPathName can fail as files are not guaranteed to have short name. This adds support for such case. Fixes: https://github.com/libuv/libuv/issues/1258 PR-URL: https://github.com/libuv/libuv/pull/1267 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs-event.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 80a7c2398..95f843ad0 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -81,8 +81,17 @@ static void uv_relative_path(const WCHAR* filename, static int uv_split_path(const WCHAR* filename, WCHAR** dir, WCHAR** file) { - int len = wcslen(filename); - int i = len; + size_t len, i; + + if (filename == NULL) { + if (dir != NULL) + *dir = NULL; + *file = NULL; + return 0; + } + + len = wcslen(filename); + i = len; while (i > 0 && filename[--i] != '\\' && filename[i] != '/'); if (i == 0) { @@ -145,7 +154,8 @@ int uv_fs_event_start(uv_fs_event_t* handle, int name_size, is_path_dir; DWORD attr, last_error; WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL; - WCHAR short_path[MAX_PATH]; + WCHAR short_path_buffer[MAX_PATH]; + WCHAR* short_path; if (uv__is_active(handle)) return UV_EINVAL; @@ -195,9 +205,9 @@ int uv_fs_event_start(uv_fs_event_t* handle, */ /* Convert to short path. */ + short_path = short_path_buffer; if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) { - last_error = GetLastError(); - goto error; + short_path = NULL; } if (uv_split_path(pathw, &dir, &handle->filew) != 0) { @@ -347,8 +357,11 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { } -static int file_info_cmp(WCHAR* str, WCHAR* file_name, int file_name_len) { - int str_len; +static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) { + size_t str_len; + + if (str == NULL) + return -1; str_len = wcslen(str); From eb8509210df264d30644a93d83d5fbdf5d580231 Mon Sep 17 00:00:00 2001 From: Jamie Davis Date: Tue, 28 Mar 2017 11:44:40 -0400 Subject: [PATCH 343/632] doc: fix multiple doc typos Use "file system" instead of "filesystem" throughout the document and some other minor fixes. PR-URL: https://github.com/libuv/libuv/pull/1278 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Gibson Fahnestock --- docs/src/design.rst | 2 +- docs/src/fs.rst | 14 +++++++------- docs/src/fs_event.rst | 4 ++-- docs/src/threadpool.rst | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/src/design.rst b/docs/src/design.rst index 34c3cff68..ecf2609ba 100644 --- a/docs/src/design.rst +++ b/docs/src/design.rst @@ -128,7 +128,7 @@ For a thorough explanation of the cross-platform file I/O landscape, checkout libuv currently uses a global thread pool on which all loops can queue work on. 3 types of operations are currently run on this pool: - * Filesystem operations + * File system operations * DNS functions (getaddrinfo and getnameinfo) * User specified code via :c:func:`uv_queue_work` diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 192ecc705..17e328c73 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -1,15 +1,15 @@ .. _fs: -Filesystem operations +File system operations ===================== -libuv provides a wide variety of cross-platform sync and async filesystem +libuv provides a wide variety of cross-platform sync and async file system operations. All functions defined in this document take a callback, which is allowed to be NULL. If the callback is NULL the request is completed synchronously, otherwise it will be performed asynchronously. -All file operations are run on the threadpool, see :ref:`threadpool` for information +All file operations are run on the threadpool. See :ref:`threadpool` for information on the threadpool size. @@ -18,7 +18,7 @@ Data types .. c:type:: uv_fs_t - Filesystem request type. + File system request type. .. c:type:: uv_timespec_t @@ -58,7 +58,7 @@ Data types .. c:type:: uv_fs_type - Filesystem request type. + File system request type. :: @@ -216,7 +216,7 @@ API Unlike `scandir(3)`, this function does not return the "." and ".." entries. .. note:: - On Linux, getting the type of an entry is only supported by some filesystems (btrfs, ext2, + On Linux, getting the type of an entry is only supported by some file systems (btrfs, ext2, ext3 and ext4 at the time of this writing), check the :man:`getdents(2)` man page. .. c:function:: int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) @@ -291,7 +291,7 @@ API Equivalent to :man:`realpath(3)` on Unix. Windows uses `GetFinalPathNameByHandle `_. .. warning:: - This function has certain platform specific caveats that were discovered when used in Node. + This function has certain platform-specific caveats that were discovered when used in Node. * macOS and other BSDs: this function will fail with UV_ELOOP if more than 32 symlinks are found while resolving the given path. This limit is hardcoded and cannot be sidestepped. diff --git a/docs/src/fs_event.rst b/docs/src/fs_event.rst index fb855b0bc..2af3e9802 100644 --- a/docs/src/fs_event.rst +++ b/docs/src/fs_event.rst @@ -66,7 +66,7 @@ Data types UV_FS_EVENT_WATCH_ENTRY = 1, /* * By default uv_fs_event will try to use a kernel interface such as inotify - * or kqueue to detect events. This may not work on remote filesystems such + * or kqueue to detect events. This may not work on remote file systems such * as NFS mounts. This flag makes fs_event fall back to calling stat() on a * regular interval. * This flag is currently not implemented yet on any backend. @@ -74,7 +74,7 @@ Data types UV_FS_EVENT_STAT = 2, /* * By default, event watcher, when watching directory, is not registering - * (is ignoring) changes in it's subdirectories. + * (is ignoring) changes in its subdirectories. * This flag will override this behaviour on platforms that support it. */ UV_FS_EVENT_RECURSIVE = 4 diff --git a/docs/src/threadpool.rst b/docs/src/threadpool.rst index 18949507e..93bd236d3 100644 --- a/docs/src/threadpool.rst +++ b/docs/src/threadpool.rst @@ -5,7 +5,7 @@ Thread pool work scheduling =========================== libuv provides a threadpool which can be used to run user code and get notified -in the loop thread. This thread pool is internally used to run all filesystem +in the loop thread. This thread pool is internally used to run all file system operations, as well as getaddrinfo and getnameinfo requests. Its default size is 4, but it can be changed at startup time by setting the From cd37fd0fd28d042df2562a1d315b2a7ca52967fa Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sat, 1 Apr 2017 20:04:08 +0200 Subject: [PATCH 344/632] test,osx: fix flaky kill test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least starting with Darwin Kernel Version 16.4.0, sending a SIGTERM to a process that is still starting up kills it with SIGKILL instead of SIGTERM. Fixes: https://github.com/libuv/libuv/issues/1226 PR-URL: https://github.com/libuv/libuv/pull/1282 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Gibson Fahnestock --- test/test-spawn.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/test-spawn.c b/test/test-spawn.c index 53a036969..e6f1ceb70 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -90,7 +90,16 @@ static void kill_cb(uv_process_t* process, #else ASSERT(exit_status == 0); #endif - ASSERT(no_term_signal || term_signal == 15); +#if defined(__APPLE__) + /* + * At least starting with Darwin Kernel Version 16.4.0, sending a SIGTERM to a + * process that is still starting up kills it with SIGKILL instead of SIGTERM. + * See: https://github.com/libuv/libuv/issues/1226 + */ + ASSERT(no_term_signal || term_signal == SIGTERM || term_signal == SIGKILL); +#else + ASSERT(no_term_signal || term_signal == SIGTERM); +#endif uv_close((uv_handle_t*)process, close_cb); /* From 36d6b1f445935f7b8247be422a0616b288091ccd Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 4 Apr 2017 09:56:29 -0400 Subject: [PATCH 345/632] unix: inline uv_pipe_bind() err_bind goto target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This goto target is only one line, and is only reached from one place. PR-URL: https://github.com/libuv/libuv/pull/1289 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/unix/pipe.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index b73994cb8..ff0b70940 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -76,7 +76,9 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { /* Convert ENOENT to EACCES for compatibility with Windows. */ if (err == -ENOENT) err = -EACCES; - goto err_bind; + + uv__close(sockfd); + goto err_socket; } /* Success. */ @@ -85,9 +87,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { handle->io_watcher.fd = sockfd; return 0; -err_bind: - uv__close(sockfd); - err_socket: uv__free((void*)pipe_fname); return err; From cd676e2dbcb47b699ce07795d543ad241d2ec0a2 Mon Sep 17 00:00:00 2001 From: Rasmus Christian Pedersen Date: Tue, 4 Apr 2017 01:32:57 +0200 Subject: [PATCH 346/632] unix,test: deadstore fixes Fixes deadstore in uv_pipe_bind as 'sockfd' is no longer used. Fixes deadstore in test related to unused variables or missing assert. PR-URL: https://github.com/libuv/libuv/pull/1288 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/unix/pipe.c | 1 - test/test-fork.c | 1 - test/test-fs.c | 1 + test/test-shutdown-twice.c | 1 + test/test-udp-send-immediate.c | 1 + 5 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index ff0b70940..dd3d034f5 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -47,7 +47,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { int err; pipe_fname = NULL; - sockfd = -1; /* Already bound? */ if (uv__stream_fd(handle) >= 0) diff --git a/test/test-fork.c b/test/test-fork.c index 24e74c80a..3a3c90fb6 100644 --- a/test/test-fork.c +++ b/test/test-fork.c @@ -46,7 +46,6 @@ static char socket_cb_read_buf[1024]; static void socket_cb(uv_poll_t* poll, int status, int events) { ssize_t cnt; - cnt = 0; socket_cb_called++; ASSERT(0 == status); printf("Socket cb got events %d\n", events); diff --git a/test/test-fs.c b/test/test-fs.c index 030245ead..a92feb915 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1485,6 +1485,7 @@ TEST_IMPL(fs_chown) { /* chown to root (fail) */ chown_cb_count = 0; r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb); + ASSERT(r == 0); uv_run(loop, UV_RUN_DEFAULT); ASSERT(chown_cb_count == 1); diff --git a/test/test-shutdown-twice.c b/test/test-shutdown-twice.c index 75c054354..d7aae8991 100644 --- a/test/test-shutdown-twice.c +++ b/test/test-shutdown-twice.c @@ -67,6 +67,7 @@ TEST_IMPL(shutdown_twice) { loop = uv_default_loop(); r = uv_tcp_init(loop, &h); + ASSERT(r == 0); r = uv_tcp_connect(&connect_req, &h, diff --git a/test/test-udp-send-immediate.c b/test/test-udp-send-immediate.c index 0999f6b34..215f72257 100644 --- a/test/test-udp-send-immediate.c +++ b/test/test-udp-send-immediate.c @@ -136,6 +136,7 @@ TEST_IMPL(udp_send_immediate) { 1, (const struct sockaddr*) &addr, cl_send_cb); + ASSERT(r == 0); uv_run(uv_default_loop(), UV_RUN_DEFAULT); From cd937833a7e08d119f41f89f7bed8d78b594e9e4 Mon Sep 17 00:00:00 2001 From: Andreas Hauptmann Date: Mon, 20 Mar 2017 18:27:54 +0100 Subject: [PATCH 347/632] win: fix memory leak inside uv_fs_access() PR-URL: https://github.com/libuv/libuv/pull/1263 Reviewed-By: Colin Ihrig --- src/win/fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 7b87187a3..de95ec547 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1371,7 +1371,7 @@ static void fs__access(uv_fs_t* req) { * - or it's a directory. * (Directories cannot be read-only on Windows.) */ - if (!(req->flags & W_OK) || + if (!(req->fs.info.mode & W_OK) || !(attr & FILE_ATTRIBUTE_READONLY) || (attr & FILE_ATTRIBUTE_DIRECTORY)) { SET_REQ_RESULT(req, 0); @@ -2398,7 +2398,7 @@ int uv_fs_access(uv_loop_t* loop, if (err) return uv_translate_sys_error(err); - req->flags = flags; + req->fs.info.mode = flags; if (cb) { QUEUE_FS_TP_JOB(loop, req); From 5e5ac86a540be90479cd77a2e593174c21a380c0 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 11 Apr 2017 12:41:59 +0200 Subject: [PATCH 348/632] doc: fix docs/src/fs.rst build warning This commit fixes a warning about the title underline being too short. PR-URL: https://github.com/libuv/libuv/pull/1300 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/fs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 17e328c73..234713ecc 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -2,7 +2,7 @@ .. _fs: File system operations -===================== +====================== libuv provides a wide variety of cross-platform sync and async file system operations. All functions defined in this document take a callback, which is From a3d9d8ed7376f0a07e892a2d9ffe67d2a815aee5 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 11 Apr 2017 12:58:48 +0200 Subject: [PATCH 349/632] doc: minor grammar fix in Installation section PR-URL: https://github.com/libuv/libuv/pull/1301 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- 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 fa89c4bff..4ccb3392f 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -46,7 +46,7 @@ libuv can be downloaded from `here `_. Installation ------------ -Installation instructions can be found on `the README `_. +Installation instructions can be found in `the README `_. Upgrading From 12f18159cf2f40fe12c62eb7a0ae22b6dd5548d5 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 11 Apr 2017 13:35:24 +0200 Subject: [PATCH 350/632] doc: suggestions for design page While reading the design page I came across a few sentences that could perhaps be improved, and this commit contains suggestions for such improvements. PR-URL: https://github.com/libuv/libuv/pull/1302 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/design.rst | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/src/design.rst b/docs/src/design.rst index ecf2609ba..487d08ba6 100644 --- a/docs/src/design.rst +++ b/docs/src/design.rst @@ -7,7 +7,7 @@ Design overview libuv is cross-platform support library which was originally written for NodeJS. It's designed around the event-driven asynchronous I/O model. -The library provides much more than simply abstraction over different I/O polling mechanisms: +The library provides much more than a simple abstraction over different I/O polling mechanisms: 'handles' and 'streams' provide a high level abstraction for sockets and other entities; cross-platform file I/O and threading functionality is also provided, amongst other things. @@ -25,9 +25,10 @@ Handles and requests libuv provides users with 2 abstractions to work with, in combination with the event loop: handles and requests. -Handles represent long-lived objects capable of performing certain operations while active. Some -examples: a prepare handle gets its callback called once every loop iteration when active, and -a TCP server handle get its connection callback called every time there is a new connection. +Handles represent long-lived objects capable of performing certain operations while active. Some examples: + +- A prepare handle gets its callback called once every loop iteration when active. +- A TCP server handle that gets its connection callback called every time there is a new connection. Requests represent (typically) short-lived operations. These operations can be performed over a handle: write requests are used to write data on a handle; or standalone: getaddrinfo requests @@ -85,11 +86,11 @@ stages of a loop iteration: * If there are no active handles or requests, the timeout is 0. * If there are any idle handles active, the timeout is 0. * If there are any handles pending to be closed, the timeout is 0. - * If none of the above cases was matched, the timeout of the closest timer is taken, or + * If none of the above cases matches, the timeout of the closest timer is taken, or if there are no active timers, infinity. -#. The loop blocks for I/O. At this point the loop will block for I/O for the timeout calculated - on the previous step. All I/O related handles that were monitoring a given file descriptor +#. The loop blocks for I/O. At this point the loop will block for I/O for the duration calculated + in the previous step. All I/O related handles that were monitoring a given file descriptor for a read or write operation get their callbacks called at this point. #. Check handle callbacks are called. Check handles get their callbacks called right after the @@ -103,7 +104,7 @@ stages of a loop iteration: so there might be timers which are due, those timers get their callbacks called. #. Iteration ends. If the loop was run with ``UV_RUN_NOWAIT`` or ``UV_RUN_ONCE`` modes the - iteration is ended and :c:func:`uv_run` will return. If the loop was run with ``UV_RUN_DEFAULT`` + iteration ends and :c:func:`uv_run` will return. If the loop was run with ``UV_RUN_DEFAULT`` it will continue from the start if it's still *alive*, otherwise it will also end. From a76e7830ca43123e593941bd5e9782d18913a0d6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 11 Apr 2017 12:11:36 +0200 Subject: [PATCH 351/632] doc: libuv does not touch uv_loop_t.data Mea culpa, I forgot to update the documentation in commit ff0ae10 ("unix: preserve loop->data across loop init/done") from July 2016. PR-URL: https://github.com/libuv/libuv/pull/1299 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/loop.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/src/loop.rst b/docs/src/loop.rst index b3fa069ef..74f96341d 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -38,9 +38,8 @@ Public members .. c:member:: void* uv_loop_t.data - Space for user-defined arbitrary data. libuv does not use this field. libuv does, however, - initialize it to NULL in :c:func:`uv_loop_init`, and it poisons the value (on debug builds) - on :c:func:`uv_loop_close`. + Space for user-defined arbitrary data. libuv does not use and does not + touch this field. API From b678fb6191de0d9f7155ee3b5b94a00f698a4aa6 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 18 Apr 2017 10:53:54 +0200 Subject: [PATCH 352/632] github: add ISSUE_TEMPLATE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a ISSUE_TEMPLATE that redirects people to libuv/help for questions. PR-URL: https://github.com/libuv/libuv/pull/1309 Refs: https://github.com/libuv/libuv/issues/1305 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- .github/ISSUE_TEMPLATE.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..c060a606a --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,9 @@ + +* **Version**: +* **Platform**: From 8fd1e406063046760b8c2af0cf7366f29c80f135 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 18 Apr 2017 10:57:53 +0200 Subject: [PATCH 353/632] doc: add link to libuv/help to README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1309 Refs: https://github.com/libuv/libuv/issues/1305 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 284dfb47c..7cf96dd23 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ libuv is licensed under the MIT license. Check the [LICENSE file](LICENSE). ## Community + * [Support](https://github.com/libuv/help) * [Mailing list](http://groups.google.com/group/libuv) * [IRC chatroom (#libuv@irc.freenode.org)](http://webchat.freenode.net?channels=libuv&uio=d4) From 0cbad54f182fc9059fa54486cc464fcd99384c24 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Mon, 17 Apr 2017 19:12:56 -0400 Subject: [PATCH 354/632] udp: fix fast path in uv_udp_send() on unix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "Fast" path in `uv_udp_send()` attempts to write the data straight away without queueing the fd with epoll/kqueue/... However, in some cases this is not possible when `sendmsg()` returns `EAGAIN`. In such event libuv has to queue the fd anyway. PR-URL: https://github.com/libuv/libuv/pull/1308 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno --- src/unix/udp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/unix/udp.c b/src/unix/udp.c index f9630c85c..73f2bc4e5 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -433,6 +433,13 @@ int uv__udp_send(uv_udp_send_t* req, if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) { uv__udp_sendmsg(handle); + + /* `uv__udp_sendmsg` may not be able to do non-blocking write straight + * away. In such cases the `io_watcher` has to be queued for asynchronous + * write. + */ + if (!QUEUE_EMPTY(&handle->write_queue)) + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); } else { uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); } From d898a1f6f87ba30e7803fe402121464553b2ffaf Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Tue, 18 Apr 2017 17:59:32 -0600 Subject: [PATCH 355/632] test: add test for uv_udp_send() fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test that the fast path will continue writing. On failure, this test will timeout. PR-URL: https://github.com/libuv/libuv/pull/1308 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno --- Makefile.am | 1 + checksparse.sh | 1 + test/test-list.h | 2 + test/test-udp-send-hang-loop.c | 99 ++++++++++++++++++++++++++++++++++ uv.gyp | 1 + 5 files changed, 104 insertions(+) create mode 100644 test/test-udp-send-hang-loop.c diff --git a/Makefile.am b/Makefile.am index c84859f60..211cfe21b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -274,6 +274,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-udp-open.c \ test/test-udp-options.c \ test/test-udp-send-and-recv.c \ + test/test-udp-send-hang-loop.c \ test/test-udp-send-immediate.c \ test/test-udp-send-unreachable.c \ test/test-udp-try-send.c \ diff --git a/checksparse.sh b/checksparse.sh index 5e0220716..372061d88 100755 --- a/checksparse.sh +++ b/checksparse.sh @@ -166,6 +166,7 @@ test/test-udp-multicast-ttl.c test/test-udp-open.c test/test-udp-options.c test/test-udp-send-and-recv.c +test/test-udp-send-hang-loop.c test/test-walk-handles.c test/test-watcher-cross-stop.c " diff --git a/test/test-list.h b/test/test-list.h index 8b19b6c31..87c54a1af 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -116,6 +116,7 @@ TEST_DECLARE (udp_create_early) TEST_DECLARE (udp_create_early_bad_bind) TEST_DECLARE (udp_create_early_bad_domain) TEST_DECLARE (udp_send_and_recv) +TEST_DECLARE (udp_send_hang_loop) TEST_DECLARE (udp_send_immediate) TEST_DECLARE (udp_send_unreachable) TEST_DECLARE (udp_multicast_join) @@ -517,6 +518,7 @@ TASK_LIST_START TEST_ENTRY (udp_create_early_bad_bind) TEST_ENTRY (udp_create_early_bad_domain) TEST_ENTRY (udp_send_and_recv) + TEST_ENTRY (udp_send_hang_loop) TEST_ENTRY (udp_send_immediate) TEST_ENTRY (udp_send_unreachable) TEST_ENTRY (udp_dgram_too_big) diff --git a/test/test-udp-send-hang-loop.c b/test/test-udp-send-hang-loop.c new file mode 100644 index 000000000..6253ff7a4 --- /dev/null +++ b/test/test-udp-send-hang-loop.c @@ -0,0 +1,99 @@ +/* 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 + +#define CHECK_OBJECT(handle, type, parent) \ + ASSERT((type*)(handle) == &(parent)) + +static uv_udp_t client; +static uv_idle_t idle_handle; +static uv_udp_send_t send_req; +static uv_buf_t buf; +static struct sockaddr_in addr; +static char send_data[1024]; + +static int loop_hang_called; + +static void send_cb(uv_udp_send_t* req, int status); + + +static void idle_cb(uv_idle_t* handle) { + int r; + + ASSERT(send_req.handle == NULL); + CHECK_OBJECT(handle, uv_idle_t, idle_handle); + ASSERT(0 == uv_idle_stop(handle)); + + /* It probably would have stalled by now if it's going to stall at all. */ + if (++loop_hang_called > 1000) { + uv_close((uv_handle_t*) &client, NULL); + uv_close((uv_handle_t*) &idle_handle, NULL); + return; + } + + r = uv_udp_send(&send_req, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + send_cb); + ASSERT(r == 0); +} + + +static void send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_OBJECT(req->handle, uv_udp_t, client); + CHECK_OBJECT(req, uv_udp_send_t, send_req); + req->handle = NULL; + + ASSERT(0 == uv_idle_start(&idle_handle, idle_cb)); +} + + +TEST_IMPL(udp_send_hang_loop) { + ASSERT(0 == 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(0 == 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)); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(loop_hang_called > 1000); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/uv.gyp b/uv.gyp index 71ad2dd48..720002578 100644 --- a/uv.gyp +++ b/uv.gyp @@ -451,6 +451,7 @@ 'test/test-udp-open.c', 'test/test-udp-options.c', 'test/test-udp-send-and-recv.c', + 'test/test-udp-send-hang-loop.c', 'test/test-udp-send-immediate.c', 'test/test-udp-send-unreachable.c', 'test/test-udp-multicast-join.c', From e4bc694b365665fb6cc47fd1544f1b5597228d19 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Mon, 24 Apr 2017 11:33:17 -0400 Subject: [PATCH 356/632] doc: fix documentation for uv_handle_t.type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1316 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- docs/src/handle.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/handle.rst b/docs/src/handle.rst index 14aec51ff..a0f3d05fd 100644 --- a/docs/src/handle.rst +++ b/docs/src/handle.rst @@ -86,9 +86,9 @@ Public members Pointer to the :c:type:`uv_loop_t` where the handle is running on. Readonly. -.. c:member:: uv_loop_t* uv_handle_t.type +.. c:member:: uv_handle_type uv_handle_t.type - Pointer to the :c:type:`uv_handle_type`. Readonly. + The :c:type:`uv_handle_type`, indicating the type of the underlying handle. Readonly. .. c:member:: void* uv_handle_t.data From 710989b08737c6cccfdd8e33d6ceeba0e295ddec Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 20 Apr 2017 12:50:39 +0200 Subject: [PATCH 357/632] zos: use proper prototype for epoll_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `int epoll_init()` declares a function that takes any number of arguments, use `int epoll_init(void)` instead. PR-URL: https://github.com/libuv/libuv/pull/1314 Reviewed-By: Colin Ihrig Reviewed-By: Colin Ihrig Reviewed-By: John Barboza Reviewed-By: Saúl Ibarra Corretgé --- src/unix/os390-syscalls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c index 2bf3b7381..7edf2358d 100644 --- a/src/unix/os390-syscalls.c +++ b/src/unix/os390-syscalls.c @@ -120,7 +120,7 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) { } -static void epoll_init() { +static void epoll_init(void) { QUEUE_INIT(&global_epoll_queue); if (uv_mutex_init(&global_epoll_lock)) abort(); From 93415e662befe8b692021c440d148272bd6e6b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 12 Mar 2017 22:24:05 +0100 Subject: [PATCH 358/632] doc: rename docs to "libuv documentation" PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/conf.py | 14 +++++++------- docs/src/index.rst | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/src/conf.py b/docs/src/conf.py index 3f8689d2e..4f6eae64f 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# libuv API documentation documentation build configuration file, created by +# libuv documentation documentation build configuration file, created by # sphinx-quickstart on Sun Jul 27 11:47:51 2014. # # This file is execfile()d with the current directory set to its @@ -130,10 +130,10 @@ def get_libuv_version(): # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -html_title = 'libuv API documentation' +html_title = 'libuv documentation' # A shorter title for the navigation bar. Default is the same as html_title. -html_short_title = 'libuv %s API documentation' % version +html_short_title = 'libuv %s documentation' % version # The name of an image file (relative to this directory) to place at the top # of the sidebar. @@ -216,7 +216,7 @@ def get_libuv_version(): # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'libuv.tex', u'libuv API documentation', + ('index', 'libuv.tex', u'libuv documentation', u'libuv contributors', 'manual'), ] @@ -246,7 +246,7 @@ def get_libuv_version(): # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'libuv', u'libuv API documentation', + ('index', 'libuv', u'libuv documentation', [u'libuv contributors'], 1) ] @@ -260,7 +260,7 @@ def get_libuv_version(): # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'libuv', u'libuv API documentation', + ('index', 'libuv', u'libuv documentation', u'libuv contributors', 'libuv', 'Cross-platform asynchronous I/O', 'Miscellaneous'), ] @@ -281,7 +281,7 @@ def get_libuv_version(): # -- Options for Epub output ---------------------------------------------- # Bibliographic Dublin Core info. -epub_title = u'libuv API documentation' +epub_title = u'libuv documentation' epub_author = u'libuv contributors' epub_publisher = u'libuv contributors' epub_copyright = u'2014, libuv contributors' diff --git a/docs/src/index.rst b/docs/src/index.rst index 4ccb3392f..84531713f 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -1,6 +1,6 @@ -Welcome to the libuv API documentation -====================================== +Welcome to the libuv documentation +================================== Overview -------- From d2eca716f12c4d914c42f5ab76fab192632ba3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 12 Mar 2017 22:25:58 +0100 Subject: [PATCH 359/632] doc: update copyright years PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/conf.py b/docs/src/conf.py index 4f6eae64f..c9b4ea38c 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -64,7 +64,7 @@ def get_libuv_version(): # General information about the project. project = u'libuv API documentation' -copyright = u'libuv contributors' +copyright = u'2014-present, libuv contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -284,7 +284,7 @@ def get_libuv_version(): epub_title = u'libuv documentation' epub_author = u'libuv contributors' epub_publisher = u'libuv contributors' -epub_copyright = u'2014, libuv contributors' +epub_copyright = u'2014-present, libuv contributors' # The basename for the epub file. It defaults to the project name. epub_basename = u'libuv' From 8e95cba17539dd57c708f7a84680a7bb92c280d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 12 Mar 2017 22:30:36 +0100 Subject: [PATCH 360/632] doc: move TOC to a dedicated document PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/api.rst | 35 +++++++++++++++++++++++++++++++++++ docs/src/index.rst | 27 +-------------------------- 2 files changed, 36 insertions(+), 26 deletions(-) create mode 100644 docs/src/api.rst diff --git a/docs/src/api.rst b/docs/src/api.rst new file mode 100644 index 000000000..22f0640f5 --- /dev/null +++ b/docs/src/api.rst @@ -0,0 +1,35 @@ +.. _api: + +API documentation +================= + +.. toctree:: + :maxdepth: 1 + + errors + version + loop + handle + request + timer + prepare + check + idle + async + poll + signal + process + stream + tcp + pipe + tty + udp + fs_event + fs_poll + fs + threadpool + dns + dll + threading + misc + diff --git a/docs/src/index.rst b/docs/src/index.rst index 84531713f..73d218959 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -67,29 +67,4 @@ Documentation :maxdepth: 1 design - errors - version - loop - handle - request - timer - prepare - check - idle - async - poll - signal - process - stream - tcp - pipe - tty - udp - fs_event - fs_poll - fs - threadpool - dns - dll - threading - misc + api From afb37ce45185d5255b118abfa888cfce02912666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 12 Mar 2017 22:32:50 +0100 Subject: [PATCH 361/632] doc: move documentation section up PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/index.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/src/index.rst b/docs/src/index.rst index 73d218959..165816d5e 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -37,6 +37,16 @@ Features * Threading and synchronization primitives +Documentation +------------- + +.. toctree:: + :maxdepth: 1 + + design + api + + Downloads --------- @@ -58,13 +68,3 @@ Migration guides for different libuv versions, starting with 1.0. :maxdepth: 1 migration_010_100 - - -Documentation -------------- - -.. toctree:: - :maxdepth: 1 - - design - api From 521146dac4935683c91eb64216a3e7c4aa4b3441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 12 Mar 2017 22:35:12 +0100 Subject: [PATCH 362/632] doc: move "upgrading" to a standalone document PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/index.rst | 11 +---------- docs/src/upgrading.rst | 11 +++++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 docs/src/upgrading.rst diff --git a/docs/src/index.rst b/docs/src/index.rst index 165816d5e..d89f251fd 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -45,6 +45,7 @@ Documentation design api + upgrading Downloads @@ -58,13 +59,3 @@ Installation Installation instructions can be found in `the README `_. - -Upgrading ---------- - -Migration guides for different libuv versions, starting with 1.0. - -.. toctree:: - :maxdepth: 1 - - migration_010_100 diff --git a/docs/src/upgrading.rst b/docs/src/upgrading.rst new file mode 100644 index 000000000..32840c269 --- /dev/null +++ b/docs/src/upgrading.rst @@ -0,0 +1,11 @@ +.. _upgrading: + +Upgrading +========= + +Migration guides for different libuv versions, starting with 1.0. + +.. toctree:: + :maxdepth: 1 + + migration_010_100 From b80106de45850b1fc0e407bdc7d15621b8891e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 12 Mar 2017 22:47:19 +0100 Subject: [PATCH 363/632] doc: add initial version of the User Guide This is a fresh import of uvbook [0], as is. It is to be considered "beta", as the entire content hasn't been revised / adapted yet. PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/guide.rst | 17 ++ docs/src/guide/about.rst | 25 ++ docs/src/guide/basics.rst | 188 ++++++++++++++ docs/src/guide/eventloops.rst | 48 ++++ docs/src/guide/filesystem.rst | 287 +++++++++++++++++++++ docs/src/guide/index.rst | 36 +++ docs/src/guide/introduction.rst | 75 ++++++ docs/src/guide/networking.rst | 249 ++++++++++++++++++ docs/src/guide/processes.rst | 389 ++++++++++++++++++++++++++++ docs/src/guide/threads.rst | 379 ++++++++++++++++++++++++++++ docs/src/guide/utilities.rst | 433 ++++++++++++++++++++++++++++++++ docs/src/index.rst | 1 + 12 files changed, 2127 insertions(+) create mode 100644 docs/src/guide.rst create mode 100644 docs/src/guide/about.rst create mode 100644 docs/src/guide/basics.rst create mode 100644 docs/src/guide/eventloops.rst create mode 100644 docs/src/guide/filesystem.rst create mode 100644 docs/src/guide/index.rst create mode 100644 docs/src/guide/introduction.rst create mode 100644 docs/src/guide/networking.rst create mode 100644 docs/src/guide/processes.rst create mode 100644 docs/src/guide/threads.rst create mode 100644 docs/src/guide/utilities.rst diff --git a/docs/src/guide.rst b/docs/src/guide.rst new file mode 100644 index 000000000..5f6c285aa --- /dev/null +++ b/docs/src/guide.rst @@ -0,0 +1,17 @@ +.. _guide: + +User guide +========== + +.. toctree:: + :maxdepth: 2 + + guide/introduction + guide/basics + guide/filesystem + guide/networking + guide/threads + guide/processes + guide/eventloops + guide/utilities + guide/about diff --git a/docs/src/guide/about.rst b/docs/src/guide/about.rst new file mode 100644 index 000000000..8efa51782 --- /dev/null +++ b/docs/src/guide/about.rst @@ -0,0 +1,25 @@ +About +===== + +`Nikhil Marathe `_ started writing this book one +afternoon (June 16, 2012) when he didn't feel like programming. He had recently +been stung by the lack of good documentation on libuv while working on +`node-taglib `_. Although reference +documentation was present, there were no comprehensive tutorials. This book is +the output of that need and tries to be accurate. That said, the book may have +mistakes. Pull requests are encouraged. You may also `email him +`_ if you find an error. + +Nikhil is indebted to Marc Lehmann's comprehensive `man page +`_ about libev which +describes much of the semantics of the two libraries. + +This book was made using `Sphinx `_ and `vim +`_. + +Licensing +--------- + +The contents of this book are licensed as `Creative Commons - Attribution +`_. All code is in the **public +domain**. diff --git a/docs/src/guide/basics.rst b/docs/src/guide/basics.rst new file mode 100644 index 000000000..55798bff2 --- /dev/null +++ b/docs/src/guide/basics.rst @@ -0,0 +1,188 @@ +Basics of libuv +=============== + +libuv enforces an **asynchronous**, **event-driven** style of programming. Its +core job is to provide an event loop and callback based notifications of I/O +and other activities. libuv offers core utilities like timers, non-blocking +networking support, asynchronous file system access, child processes and more. + +Event loops +----------- + +In event-driven programming, an application expresses interest in certain events +and respond to them when they occur. The responsibility of gathering events +from the operating system or monitoring other sources of events is handled by +libuv, and the user can register callbacks to be invoked when an event occurs. +The event-loop usually keeps running *forever*. In pseudocode: + +.. code-block:: python + + while there are still events to process: + e = get the next event + if there is a callback associated with e: + call the callback + +Some examples of events are: + +* File is ready for writing +* A socket has data ready to be read +* A timer has timed out + +This event loop is encapsulated by ``uv_run()`` -- the end-all function when using +libuv. + +The most common activity of systems programs is to deal with input and output, +rather than a lot of number-crunching. The problem with using conventional +input/output functions (``read``, ``fprintf``, etc.) is that they are +**blocking**. The actual write to a hard disk or reading from a network, takes +a disproportionately long time compared to the speed of the processor. The +functions don't return until the task is done, so that your program is doing +nothing. For programs which require high performance this is a major roadblock +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, +which actually needs the CPU. + +The approach followed by libuv uses another style, which is the **asynchronous, +non-blocking** style. Most modern operating systems provide event notification +subsystems. For example, a normal ``read`` call on a socket would block until +the sender actually sent something. Instead, the application can request the +operating system to watch the socket and put an event notification in the +queue. The application can inspect the events at its convenience (perhaps doing +some number crunching before to use the processor to the maximum) and grab the +data. It is **asynchronous** because the application expressed interest at one +point, then used the data at another point (in time and space). It is +**non-blocking** because the application process was free to do other tasks. +This fits in well with libuv's event-loop approach, since the operating system +events can be treated as just another libuv event. The non-blocking ensures +that other events can continue to be handled as fast as they come in [#]_. + +.. NOTE:: + + How the I/O is run in the background is not of our concern, but due to the + way our computer hardware works, with the thread as the basic unit of the + processor, libuv and OSes will usually run background/worker threads and/or + polling to perform tasks in a non-blocking manner. + +Bert Belder, one of the libuv core developers has a small video explaining the +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 + + + +Hello World +----------- + +With the basics out of the way, lets write our first libuv program. It does +nothing, except start a loop which will exit immediately. + +.. rubric:: helloworld/main.c +.. literalinclude:: ../code/helloworld/main.c + :linenos: + +This program quits immediately because it has no events to process. A libuv +event loop has to be told to watch out for events using the various API +functions. + +Starting with libuv v1.0, users should allocate the memory for the loops before +initializing it with ``uv_loop_init(uv_loop_t *)``. This allows you to plug in +custom memory management. Remember to de-initialize the loop using +``uv_loop_close(uv_loop_t *)`` and then delete the storage. The examples never +close loops since the program quits after the loop ends and the system will +reclaim memory. Production grade projects, especially long running systems +programs, should take care to release correctly. + +Default loop +++++++++++++ + +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. + +.. note:: + + node.js uses the default loop as its main loop. If you are writing bindings + you should be aware of this. + +.. _libuv-error-handling: + +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`_. + +.. _constants: http://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. + +I/O read callbacks (such as for files and sockets) are passed a parameter ``nread``. If ``nread`` is less than 0, there was an error (UV_EOF is the end of file error, which you may want to handle differently). + +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. + +.. rubric:: libuv watchers +.. literalinclude:: ../libuv/include/uv.h + :lines: 197-230 + +Handles represent long-lived objects. Async operations on such handles are +identified using **requests**. A request is short-lived (usually used across +only one callback) and usually indicates one I/O operation on a handle. +Requests are used to preserve context between the initiation and the callback +of individual actions. For example, an UDP socket is represented by +a ``uv_udp_t``, while individual writes to the socket use a ``uv_udp_send_t`` +structure that is passed to the callback after the write is done. + +Handles are setup by a corresponding:: + + uv_TYPE_init(uv_loop_t *, uv_TYPE_t *) + +function. + +Callbacks are functions which are called by libuv whenever an event the watcher +is interested in has taken place. Application specific logic will usually be +implemented in the callback. For example, an IO watcher's callback will receive +the data read from a file, a timer callback will be triggered on timeout and so +on. + +Idling +++++++ + +Here is an example of using an idle handle. The callback is called once on +every turn of the event loop. A use case for idle handles is discussed in +:doc:`utilities`. Let us use an idle watcher to look at the watcher life cycle +and see how ``uv_run()`` will now block because a watcher is present. The idle +watcher is stopped when the count is reached and ``uv_run()`` exits since no +event watchers are active. + +.. rubric:: idle-basic/main.c +.. literalinclude:: ../code/idle-basic/main.c + :emphasize-lines: 6,10,14-17 + +Storing context ++++++++++++++++ + +In callback based programming style you'll often want to pass some 'context' -- +application specific information -- between the call site and the callback. All +handles and requests have a ``void* data`` member which you can set to the +context and cast back in the callback. This is a common pattern used throughout +the C library ecosystem. In addition ``uv_loop_t`` also has a similar data +member. + +---- + +.. [#] Depending on the capacity of the hardware of course. diff --git a/docs/src/guide/eventloops.rst b/docs/src/guide/eventloops.rst new file mode 100644 index 000000000..2413163a9 --- /dev/null +++ b/docs/src/guide/eventloops.rst @@ -0,0 +1,48 @@ +Advanced event loops +==================== + +libuv provides considerable user control over event loops, and you can achieve +interesting results by juggling multiple loops. You can also embed libuv's +event loop into another event loop based library -- imagine a Qt based UI, and +Qt's event loop driving a libuv backend which does intensive system level +tasks. + +Stopping an event loop +~~~~~~~~~~~~~~~~~~~~~~ + +``uv_stop()`` can be used to stop an event loop. The earliest the loop will +stop running is *on the next iteration*, possibly later. This means that events +that are ready to be processed in this iteration of the loop will still be +processed, so ``uv_stop()`` can't be used as a kill switch. When ``uv_stop()`` +is called, the loop **won't** block for i/o on this iteration. The semantics of +these things can be a bit difficult to understand, so let's look at +``uv_run()`` where all the control flow occurs. + +.. rubric:: src/unix/core.c - uv_run +.. literalinclude:: ../libuv/src/unix/core.c + :linenos: + :lines: 304-324 + :emphasize-lines: 10,19,21 + +``stop_flag`` is set by ``uv_stop()``. Now all libuv callbacks are invoked +within the event loop, which is why invoking ``uv_stop()`` in them will still +lead to this iteration of the loop occurring. First libuv updates timers, then +runs pending timer, idle and prepare callbacks, and invokes any pending I/O +callbacks. If you were to call ``uv_stop()`` in any of them, ``stop_flag`` +would be set. This causes ``uv_backend_timeout()`` to return ``0``, which is +why the loop does not block on I/O. If on the other hand, you called +``uv_stop()`` in one of the check handlers, I/O has already finished and is not +affected. + +``uv_stop()`` is useful to shutdown a loop when a result has been computed or +there is an error, without having to ensure that all handlers are stopped one +by one. + +Here is a simple example that stops the loop and demonstrates how the current +iteration of the loop still takes places. + +.. rubric:: uvstop/main.c +.. literalinclude:: ../code/uvstop/main.c + :linenos: + :emphasize-lines: 11 + diff --git a/docs/src/guide/filesystem.rst b/docs/src/guide/filesystem.rst new file mode 100644 index 000000000..f4004c460 --- /dev/null +++ b/docs/src/guide/filesystem.rst @@ -0,0 +1,287 @@ +Filesystem +========== + +Simple filesystem read/write is achieved using the ``uv_fs_*`` functions and the +``uv_fs_t`` struct. + +.. note:: + + The libuv filesystem operations are different from :doc:`socket operations + `. Socket operations use the non-blocking operations provided + by the operating system. Filesystem operations use blocking functions + internally, but invoke these functions in a `thread pool`_ and notify + 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 + +All filesystem functions have two forms - *synchronous* and *asynchronous*. + +The *synchronous* forms automatically get called (and **block**) if the +callback is null. The return value of functions is a :ref:`libuv error code +`. This is usually only useful for synchronous calls. +The *asynchronous* form is called when a callback is passed and the return +value is 0. + +Reading/Writing files +--------------------- + +A file descriptor is obtained using + +.. code-block:: c + + int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb) + +``flags`` and ``mode`` are standard +`Unix flags `_. +libuv takes care of converting to the appropriate Windows flags. + +File descriptors are closed using + +.. code-block:: c + + int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) + + +Filesystem operation callbacks have the signature: + +.. code-block:: c + + void callback(uv_fs_t* req); + +Let's see a simple implementation of ``cat``. We start with registering +a callback for when the file is opened: + +.. rubric:: uvcat/main.c - opening a file +.. literalinclude:: ../code/uvcat/main.c + :linenos: + :lines: 41-53 + :emphasize-lines: 4, 6-7 + +The ``result`` field of a ``uv_fs_t`` is the file descriptor in case of the +``uv_fs_open`` callback. If the file is successfully opened, we start reading it. + +.. rubric:: uvcat/main.c - read callback +.. literalinclude:: ../code/uvcat/main.c + :linenos: + :lines: 26-40 + :emphasize-lines: 2,8,12 + +In the case of a read call, you should pass an *initialized* buffer which will +be filled with data before the read callback is triggered. The ``uv_fs_*`` +operations map almost directly to certain POSIX functions, so EOF is indicated +in this case by ``result`` being 0. In the case of streams or pipes, the +``UV_EOF`` constant would have been passed as a status instead. + +Here you see a common pattern when writing asynchronous programs. The +``uv_fs_close()`` call is performed synchronously. *Usually tasks which are +one-off, or are done as part of the startup or shutdown stage are performed +synchronously, since we are interested in fast I/O when the program is going +about its primary task and dealing with multiple I/O sources*. For solo tasks +the performance difference usually is negligible and may lead to simpler code. + +Filesystem writing is similarly simple using ``uv_fs_write()``. *Your callback +will be triggered after the write is complete*. In our case the callback +simply drives the next read. Thus read and write proceed in lockstep via +callbacks. + +.. rubric:: uvcat/main.c - write callback +.. literalinclude:: ../code/uvcat/main.c + :linenos: + :lines: 16-24 + :emphasize-lines: 6 + +.. warning:: + + Due to the way filesystems and disk drives are configured for performance, + a write that 'succeeds' may not be committed to disk yet. + +We set the dominos rolling in ``main()``: + +.. rubric:: uvcat/main.c +.. literalinclude:: ../code/uvcat/main.c + :linenos: + :lines: 55- + :emphasize-lines: 2 + +.. warning:: + + The ``uv_fs_req_cleanup()`` function must always be called on filesystem + requests to free internal memory allocations in libuv. + +Filesystem operations +--------------------- + +All the standard filesystem operations like ``unlink``, ``rmdir``, ``stat`` are +supported asynchronously and have intuitive argument order. They follow the +same patterns as the read/write/open calls, returning the result in the +``uv_fs_t.result`` field. The full list: + +.. rubric:: Filesystem operations +.. literalinclude:: ../libuv/include/uv.h + :lines: 1084-1195 + +.. _buffers-and-streams: + +Buffers and Streams +------------------- + +The basic I/O handle in libuv is the stream (``uv_stream_t``). TCP sockets, UDP +sockets, and pipes for file I/O and IPC are all treated as stream subclasses. + +Streams are initialized using custom functions for each subclass, then operated +upon using + +.. code-block:: c + + int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb, uv_read_cb read_cb); + int uv_read_stop(uv_stream_t*); + int uv_write(uv_write_t* req, uv_stream_t* handle, + const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); + +The stream based functions are simpler to use than the filesystem ones and +libuv will automatically keep reading from a stream when ``uv_read_start()`` is +called once, until ``uv_read_stop()`` is called. + +The discrete unit of data is the buffer -- ``uv_buf_t``. This is simply +a collection of a pointer to bytes (``uv_buf_t.base``) and the length +(``uv_buf_t.len``). The ``uv_buf_t`` is lightweight and passed around by value. +What does require management is the actual bytes, which have to be allocated +and freed by the application. + +.. ERROR:: + + 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 +asynchronously shows the power of evented I/O. The two writes won't block each +other, but we have to be careful to copy over the buffer data to ensure we don't +free a buffer until it has been written. + +The program is to be executed as:: + + ./uvtee + +We start off opening pipes on the files we require. libuv pipes to a file are +opened as bidirectional by default. + +.. rubric:: uvtee/main.c - read on pipes +.. literalinclude:: ../code/uvtee/main.c + :linenos: + :lines: 61-80 + :emphasize-lines: 4,5,15 + +The third argument of ``uv_pipe_init()`` should be set to 1 for IPC using named +pipes. This is covered in :doc:`processes`. The ``uv_pipe_open()`` call +associates the pipe with the file descriptor, in this case ``0`` (standard +input). + +We start monitoring ``stdin``. The ``alloc_buffer`` callback is invoked as new +buffers are required to hold incoming data. ``read_stdin`` will be called with +these buffers. + +.. rubric:: uvtee/main.c - reading buffers +.. literalinclude:: ../code/uvtee/main.c + :linenos: + :lines: 19-22,44-60 + +The standard ``malloc`` is sufficient here, but you can use any memory allocation +scheme. For example, node.js uses its own slab allocator which associates +buffers with V8 objects. + +The read callback ``nread`` parameter is less than 0 on any error. This error +might be EOF, in which case we close all the streams, using the generic close +function ``uv_close()`` which deals with the handle based on its internal type. +Otherwise ``nread`` is a non-negative number and we can attempt to write that +many bytes to the output streams. Finally remember that buffer allocation and +deallocation is application responsibility, so we free the data. + +The allocation callback may return a buffer with length zero if it fails to +allocate memory. In this case, the read callback is invoked with error +UV_ENOBUFS. libuv will continue to attempt to read the stream though, so you +must explicitly call ``uv_close()`` if you want to stop when allocation fails. + +The read callback may be called with ``nread = 0``, indicating that at this +point there is nothing to be read. Most applications will just ignore this. + +.. rubric:: uvtee/main.c - Write to pipe +.. literalinclude:: ../code/uvtee/main.c + :linenos: + :lines: 9-13,23-42 + +``write_data()`` makes a copy of the buffer obtained from read. This buffer +does not get passed through to the write callback trigged on write completion. To +get around this we wrap a write request and a buffer in ``write_req_t`` and +unwrap it in the callbacks. We make a copy so we can free the two buffers from +the two calls to ``write_data`` independently of each other. While acceptable +for a demo program like this, you'll probably want smarter memory management, +like reference counted buffers or a pool of buffers in any major application. + +.. WARNING:: + + If your program is meant to be used with other programs it may knowingly or + unknowingly be writing to a pipe. This makes it susceptible to `aborting on + receiving a SIGPIPE`_. It is a good idea to insert:: + + signal(SIGPIPE, SIG_IGN) + + in the initialization stages of your application. + +.. _aborting on receiving a SIGPIPE: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#The_special_problem_of_SIGPIPE + +File change events +------------------ + +All modern operating systems provide APIs to put watches on individual files or +directories and be informed when the files are modified. libuv wraps common +file change notification libraries [#fsnotify]_. This is one of the more +inconsistent parts of libuv. File change notification systems are themselves +extremely varied across platforms so getting everything working everywhere is +difficult. To demonstrate, I'm going to build a simple utility which runs +a command whenever any of the watched files change:: + + ./onchange [file2] ... + +The file change notification is started using ``uv_fs_event_init()``: + +.. rubric:: onchange/main.c - The setup +.. literalinclude:: ../code/onchange/main.c + :linenos: + :lines: 26- + :emphasize-lines: 15 + +The third argument is the actual file or directory to monitor. The last +argument, ``flags``, can be: + +.. literalinclude:: ../libuv/include/uv.h + :lines: 1299, 1308, 1315 + +``UV_FS_EVENT_WATCH_ENTRY`` and ``UV_FS_EVENT_STAT`` don't do anything (yet). +``UV_FS_EVENT_RECURSIVE`` will start watching subdirectories as well on +supported platforms. + +The callback will receive the following arguments: + + #. ``uv_fs_event_t *handle`` - The handle. The ``path`` field of the handle + is the file on which the watch was set. + #. ``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. + +In our example we simply print the arguments and run the command using +``system()``. + +.. rubric:: onchange/main.c - file change notification callback +.. literalinclude:: ../code/onchange/main.c + :linenos: + :lines: 9-24 + +---- + +.. [#fsnotify] inotify on Linux, FSEvents on Darwin, kqueue on BSDs, + ReadDirectoryChangesW on Windows, event ports on Solaris, unsupported on Cygwin +.. [#] see :ref:`pipes` diff --git a/docs/src/guide/index.rst b/docs/src/guide/index.rst new file mode 100644 index 000000000..5c9a2b670 --- /dev/null +++ b/docs/src/guide/index.rst @@ -0,0 +1,36 @@ +.. An Introduction to libuv documentation master file, created by + sphinx-quickstart on Sat Jun 16 16:39:14 2012. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Table of Contents +================= + +.. toctree:: + :maxdepth: 2 + + introduction + basics + filesystem + networking + threads + processes + eventloops + utilities + about + +Alternate formats +----------------- + +The book is also available in: + +.. raw:: html + + diff --git a/docs/src/guide/introduction.rst b/docs/src/guide/introduction.rst new file mode 100644 index 000000000..f57cdd9cb --- /dev/null +++ b/docs/src/guide/introduction.rst @@ -0,0 +1,75 @@ +Introduction +============ + +This 'book' is a small set of tutorials about using libuv_ as +a high performance evented I/O library which offers the same API on Windows and Unix. + +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/ + +This book is still a work in progress, so sections may be incomplete, but +I hope you will enjoy it as it grows. + +Who this book is for +-------------------- + +If you are reading this book, you are either: + +1) a systems programmer, creating low-level programs such as daemons or network + services and clients. You have found that the event loop approach is well + suited for your application and decided to use libuv. + +2) a node.js module writer, who wants to wrap platform APIs + written in C or C++ with a set of (a)synchronous APIs that are exposed to + JavaScript. You will use libuv purely in the context of node.js. For + this you will require some other resources as the book does not cover parts + specific to v8/node.js. + +This book assumes that you are comfortable with the C programming language. + +Background +---------- + +The node.js_ project began in 2009 as a JavaScript environment decoupled +from the browser. Using Google's V8_ and Marc Lehmann's libev_, node.js +combined a model of I/O -- evented -- with a language that was well suited to +the style of programming; due to the way it had been shaped by browsers. As +node.js grew in popularity, it was important to make it work on Windows, but +libev ran only on Unix. The Windows equivalent of kernel event notification +mechanisms like kqueue or (e)poll is IOCP. libuv was an abstraction around libev +or IOCP depending on the platform, providing users an API based on libev. +In the node-v0.9.0 version of libuv `libev was removed`_. + +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`_. + +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:: + + cd libuv + ./autogen.sh + ./configure + make + +There is no need to ``make install``. To build the examples run ``make`` in the +``code/`` directory. + +.. _Clone: https://github.com/nikhilm/uvbook +.. _Download: https://github.com/nikhilm/uvbook/downloads +.. _v1.3.0: https://github.com/libuv/libuv/tags +.. _V8: http://code.google.com/p/v8/ +.. _libev: http://software.schmorp.de/pkg/libev.html +.. _libuv: https://github.com/libuv/libuv +.. _node.js: http://www.nodejs.org +.. _libev was removed: https://github.com/joyent/libuv/issues/485 +.. _Rust: http://rust-lang.org +.. _variety: https://github.com/libuv/libuv/wiki/Projects-that-use-libuv diff --git a/docs/src/guide/networking.rst b/docs/src/guide/networking.rst new file mode 100644 index 000000000..f3463dfea --- /dev/null +++ b/docs/src/guide/networking.rst @@ -0,0 +1,249 @@ +Networking +========== + +Networking in libuv is not much different from directly using the BSD socket +interface, some things are easier, all are non-blocking, but the concepts stay +the same. In addition libuv offers utility functions to abstract the annoying, +repetitive and low-level tasks like setting up sockets using the BSD socket +structures, DNS lookup, and tweaking various socket parameters. + +The ``uv_tcp_t`` and ``uv_udp_t`` structures are used for network I/O. + +.. NOTE:: + + The code samples in this chapter exist to show certain libuv APIs. They are + not examples of good quality code. They leak memory and don't always close + connections properly. + +TCP +--- + +TCP is a connection oriented, stream protocol and is therefore based on the +libuv streams infrastructure. + +Server +++++++ + +Server sockets proceed by: + +1. ``uv_tcp_init`` the TCP handle. +2. ``uv_tcp_bind`` it. +3. Call ``uv_listen`` on the handle to have a callback invoked whenever a new + connection is established by a client. +4. Use ``uv_accept`` to accept the connection. +5. Use :ref:`stream operations ` to communicate with the + client. + +Here is a simple echo server + +.. rubric:: tcp-echo-server/main.c - The listen socket +.. literalinclude:: ../code/tcp-echo-server/main.c + :linenos: + :lines: 68- + :emphasize-lines: 4-5,7-10 + +You can see the utility function ``uv_ip4_addr`` being used to convert from +a human readable IP address, port pair to the sockaddr_in structure required by +the BSD socket APIs. The reverse can be obtained using ``uv_ip4_name``. + +.. NOTE:: + + There are ``uv_ip6_*`` analogues for the ip4 functions. + +Most of the setup functions are synchronous since they are CPU-bound. +``uv_listen`` is where we return to libuv's callback style. The second +arguments is the backlog queue -- the maximum length of queued connections. + +When a connection is initiated by clients, the callback is required to set up +a handle for the client socket and associate the handle using ``uv_accept``. +In this case we also establish interest in reading from this stream. + +.. rubric:: tcp-echo-server/main.c - Accepting the client +.. literalinclude:: ../code/tcp-echo-server/main.c + :linenos: + :lines: 51-66 + :emphasize-lines: 9-10 + +The remaining set of functions is very similar to the streams example and can +be found in the code. Just remember to call ``uv_close`` when the socket isn't +required. This can be done even in the ``uv_listen`` callback if you are not +interested in accepting the connection. + +Client +++++++ + +Where you do bind/listen/accept on the server, on the client side it's simply +a matter of calling ``uv_tcp_connect``. The same ``uv_connect_cb`` style +callback of ``uv_listen`` is used by ``uv_tcp_connect``. Try:: + + uv_tcp_t* socket = (uv_tcp_t*)malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, socket); + + uv_connect_t* connect = (uv_connect_t*)malloc(sizeof(uv_connect_t)); + + struct sockaddr_in dest; + uv_ip4_addr("127.0.0.1", 80, &dest); + + uv_tcp_connect(connect, socket, (const struct sockaddr*)&dest, on_connect); + +where ``on_connect`` will be called after the connection is established. The +callback receives the ``uv_connect_t`` struct, which has a member ``.handle`` +pointing to the socket. + +UDP +--- + +The `User Datagram Protocol`_ offers connectionless, unreliable network +communication. Hence libuv doesn't offer a stream. Instead libuv provides +non-blocking UDP support via the `uv_udp_t` handle (for receiving) and +`uv_udp_send_t` request (for sending) and related functions. That said, the +actual API for reading/writing is very similar to normal stream reads. To look +at how UDP can be used, the example shows the first stage of obtaining an IP +address from a `DHCP`_ server -- DHCP Discover. + +.. note:: + + You will have to run `udp-dhcp` as **root** since it uses well known port + numbers below 1024. + +.. rubric:: udp-dhcp/main.c - Setup and send UDP packets +.. literalinclude:: ../code/udp-dhcp/main.c + :linenos: + :lines: 7-11,104- + :emphasize-lines: 8,10-11,17-18,21 + +.. note:: + + The IP address ``0.0.0.0`` is used to bind to all interfaces. The IP + address ``255.255.255.255`` is a broadcast address meaning that packets + will be sent to all interfaces on the subnet. port ``0`` means that the OS + randomly assigns a port. + +First we setup the receiving socket to bind on all interfaces on port 68 (DHCP +client) and start a read on it. This will read back responses from any DHCP +server that replies. We use the UV_UDP_REUSEADDR flag to play nice with any +other system DHCP clients that are running on this computer on the same port. +Then we setup a similar send socket and use ``uv_udp_send`` to send +a *broadcast message* on port 67 (DHCP server). + +It is **necessary** to set the broadcast flag, otherwise you will get an +``EACCES`` error [#]_. The exact message being sent is not relevant to this +book and you can study the code if you are interested. As usual the read and +write callbacks will receive a status code of < 0 if something went wrong. + +Since UDP sockets are not connected to a particular peer, the read callback +receives an extra parameter about the sender of the packet. + +``nread`` may be zero if there is no more data to be read. If ``addr`` is NULL, +it indicates there is nothing to read (the callback shouldn't do anything), if +not NULL, it indicates that an empty datagram was received from the host at +``addr``. The ``flags`` parameter may be ``UV_UDP_PARTIAL`` if the buffer +provided by your allocator was not large enough to hold the data. *In this case +the OS will discard the data that could not fit* (That's UDP for you!). + +.. rubric:: udp-dhcp/main.c - Reading packets +.. literalinclude:: ../code/udp-dhcp/main.c + :linenos: + :lines: 17-40 + :emphasize-lines: 1,23 + +UDP Options ++++++++++++ + +Time-to-live +~~~~~~~~~~~~ + +The TTL of packets sent on the socket can be changed using ``uv_udp_set_ttl``. + +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`` [#]_. + +Multicast +~~~~~~~~~ + +A socket can (un)subscribe to a multicast group using: + +.. literalinclude:: ../libuv/include/uv.h + :lines: 594-597 + +where ``membership`` is ``UV_JOIN_GROUP`` or ``UV_LEAVE_GROUP``. + +The concepts of multicasting are nicely explained in `this guide`_. + +.. _this guide: http://www.tldp.org/HOWTO/Multicast-HOWTO-2.html + +Local loopback of multicast packets is enabled by default [#]_, use +``uv_udp_set_multicast_loop`` to switch it off. + +The packet time-to-live for multicast packets can be changed using +``uv_udp_set_multicast_ttl``. + +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. + +.. rubric:: dns/main.c +.. literalinclude:: ../code/dns/main.c + :linenos: + :lines: 61- + :emphasize-lines: 12 + +If ``uv_getaddrinfo`` returns non-zero, something went wrong in the setup and +your callback won't be invoked at all. All arguments can be freed immediately +after ``uv_getaddrinfo`` returns. The `hostname`, `servname` and `hints` +structures are documented in `the getaddrinfo man page `_. The +callback can be ``NULL`` in which case the function will run synchronously. + +In the resolver callback, you can pick any IP from the linked list of ``struct +addrinfo(s)``. This also demonstrates ``uv_tcp_connect``. It is necessary to +call ``uv_freeaddrinfo`` in the callback. + +.. rubric:: dns/main.c +.. literalinclude:: ../code/dns/main.c + :linenos: + :lines: 42-60 + :emphasize-lines: 8,16 + +libuv also provides the inverse `uv_getnameinfo`_. + +.. _uv_getnameinfo: http://docs.libuv.org/en/v1.x/dns.html#c.uv_getnameinfo + +Network interfaces +------------------ + +Information about the system's network interfaces can be obtained through libuv +using ``uv_interface_addresses``. This simple program just prints out all the +interface details so you get an idea of the fields that are available. This is +useful to allow your service to bind to IP addresses when it starts. + +.. rubric:: interfaces/main.c +.. literalinclude:: ../code/interfaces/main.c + :linenos: + :emphasize-lines: 9,17 + +``is_internal`` is true for loopback interfaces. Note that if a physical +interface has multiple IPv4/IPv6 addresses, the name will be reported multiple +times, with each address being reported once. + +.. _c-ares: http://c-ares.haxx.se +.. _getaddrinfo: http://www.kernel.org/doc/man-pages/online/pages/man3/getaddrinfo.3.html + +.. _User Datagram Protocol: http://en.wikipedia.org/wiki/User_Datagram_Protocol +.. _DHCP: http://tools.ietf.org/html/rfc2131 + +---- + +.. [#] http://beej.us/guide/bgnet/output/html/multipage/advanced.html#broadcast +.. [#] on Windows only supported on Windows Vista and later. +.. [#] http://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 + removed in v0.9.0. diff --git a/docs/src/guide/processes.rst b/docs/src/guide/processes.rst new file mode 100644 index 000000000..bbe13bc0c --- /dev/null +++ b/docs/src/guide/processes.rst @@ -0,0 +1,389 @@ +Processes +========= + +libuv offers considerable child process management, abstracting the platform +differences and allowing communication with the child process using streams or +named pipes. + +A common idiom in Unix is for every process to do one thing and do it well. In +such a case, a process often uses multiple child processes to achieve tasks +(similar to using pipes in shells). A multi-process model with messages +may also be easier to reason about compared to one with threads and shared +memory. + +A common refrain against event-based programs is that they cannot take +advantage of multiple cores in modern computers. In a multi-threaded program +the kernel can perform scheduling and assign different threads to different +cores, improving performance. But an event loop has only one thread. The +workaround can be to launch multiple processes instead, with each process +running an event loop, and each process getting assigned to a separate CPU +core. + +Spawning child processes +------------------------ + +The simplest case is when you simply want to launch a process and know when it +exits. This is achieved using ``uv_spawn``. + +.. rubric:: spawn/main.c +.. literalinclude:: ../code/spawn/main.c + :linenos: + :lines: 6-8,15- + :emphasize-lines: 11,13-17 + +.. NOTE:: + + ``options`` is implicitly initialized with zeros since it is a global + variable. If you change ``options`` to a local variable, remember to + initialize it to null out all unused fields:: + + uv_process_options_t options = {0}; + +The ``uv_process_t`` struct only acts as the handle, all options are set via +``uv_process_options_t``. To simply launch a process, you need to set only the +``file`` and ``args`` fields. ``file`` is the program to execute. Since +``uv_spawn`` uses execvp_ internally, there is no need to supply the full +path. Finally as per underlying conventions, **the arguments array has to be +one larger than the number of arguments, with the last element being NULL**. + +.. _execvp: http://www.kernel.org/doc/man-pages/online/pages/man3/exec.3.html + +After the call to ``uv_spawn``, ``uv_process_t.pid`` will contain the process +ID of the child process. + +The exit callback will be invoked with the *exit status* and the type of *signal* +which caused the exit. + +.. rubric:: spawn/main.c +.. literalinclude:: ../code/spawn/main.c + :linenos: + :lines: 9-12 + :emphasize-lines: 3 + +It is **required** to close the process watcher after the process exits. + +Changing process parameters +--------------------------- + +Before the child process is launched you can control the execution environment +using fields in ``uv_process_options_t``. + +Change execution directory +++++++++++++++++++++++++++ + +Set ``uv_process_options_t.cwd`` to the corresponding directory. + +Set environment variables ++++++++++++++++++++++++++ + +``uv_process_options_t.env`` is a null-terminated array of strings, each of the +form ``VAR=VALUE`` used to set up the environment variables for the process. Set +this to ``NULL`` to inherit the environment from the parent (this) process. + +Option flags +++++++++++++ + +Setting ``uv_process_options_t.flags`` to a bitwise OR of the following flags, +modifies the child process behaviour: + +* ``UV_PROCESS_SETUID`` - sets the child's execution user ID to ``uv_process_options_t.uid``. +* ``UV_PROCESS_SETGID`` - sets the child's execution group ID to ``uv_process_options_t.gid``. + +Changing the UID/GID is only supported on Unix, ``uv_spawn`` will fail on +Windows with ``UV_ENOTSUP``. + +* ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` - No quoting or escaping of + ``uv_process_options_t.args`` is done on Windows. Ignored on Unix. +* ``UV_PROCESS_DETACHED`` - Starts the child process in a new session, which + will keep running after the parent process exits. See example below. + +Detaching processes +------------------- + +Passing the flag ``UV_PROCESS_DETACHED`` can be used to launch daemons, or +child processes which are independent of the parent so that the parent exiting +does not affect it. + +.. rubric:: detach/main.c +.. literalinclude:: ../code/detach/main.c + :linenos: + :lines: 9-30 + :emphasize-lines: 12,19 + +Just remember that the handle is still monitoring the child, so your program +won't exit. Use ``uv_unref()`` if you want to be more *fire-and-forget*. + +Sending signals to processes +---------------------------- + +libuv wraps the standard ``kill(2)`` system call on Unix and implements one +with similar semantics on Windows, with *one caveat*: all of ``SIGTERM``, +``SIGINT`` and ``SIGKILL``, lead to termination of the process. The signature +of ``uv_kill`` is:: + + uv_err_t uv_kill(int pid, int signum); + +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. + +Signals +------- + +libuv provides wrappers around Unix signals with `some Windows support +`_ as well. + +Use ``uv_signal_init()`` to initialize +a handle and associate it with a loop. To listen for particular signals on +that handler, use ``uv_signal_start()`` with the handler function. Each handler +can only be associated with one signal number, with subsequent calls to +``uv_signal_start()`` overwriting earlier associations. Use ``uv_signal_stop()`` to +stop watching. Here is a small example demonstrating the various possibilities: + +.. rubric:: signal/main.c +.. literalinclude:: ../code/signal/main.c + :linenos: + :emphasize-lines: 17-18,27-28 + +.. NOTE:: + + ``uv_run(loop, UV_RUN_NOWAIT)`` is similar to ``uv_run(loop, UV_RUN_ONCE)`` + in that it will process only one event. UV_RUN_ONCE blocks if there are no + pending events, while UV_RUN_NOWAIT will return immediately. We use NOWAIT + so that one of the loops isn't starved because the other one has no pending + activity. + +Send ``SIGUSR1`` to the process, and you'll find the handler being invoked +4 times, one for each ``uv_signal_t``. The handler just stops each handle, +so that the program exits. This sort of dispatch to all handlers is very +useful. A server using multiple event loops could ensure that all data was +safely saved before termination, simply by every loop adding a watcher for +``SIGINT``. + +Child Process I/O +----------------- + +A normal, newly spawned process has its own set of file descriptors, with 0, +1 and 2 being ``stdin``, ``stdout`` and ``stderr`` respectively. Sometimes you +may want to share file descriptors with the child. For example, perhaps your +applications launches a sub-command and you want any errors to go in the log +file, but ignore ``stdout``. For this you'd like to have ``stderr`` of the +child be the same as the stderr of the parent. In this case, libuv supports +*inheriting* file descriptors. In this sample, we invoke the test program, +which is: + +.. rubric:: proc-streams/test.c +.. literalinclude:: ../code/proc-streams/test.c + +The actual program ``proc-streams`` runs this while sharing only ``stderr``. +The file descriptors of the child process are set using the ``stdio`` field in +``uv_process_options_t``. First set the ``stdio_count`` field to the number of +file descriptors being set. ``uv_process_options_t.stdio`` is an array of +``uv_stdio_container_t``, which is: + +.. literalinclude:: ../libuv/include/uv.h + :lines: 826-834 + +where flags can have several values. Use ``UV_IGNORE`` if it isn't going to be +used. If the first three ``stdio`` fields are marked as ``UV_IGNORE`` they'll +redirect to ``/dev/null``. + +Since we want to pass on an existing descriptor, we'll use ``UV_INHERIT_FD``. +Then we set the ``fd`` to ``stderr``. + +.. rubric:: proc-streams/main.c +.. literalinclude:: ../code/proc-streams/main.c + :linenos: + :lines: 15-17,27- + :emphasize-lines: 6,10,11,12 + +If you run ``proc-stream`` you'll see that only the line "This is stderr" will +be displayed. Try marking ``stdout`` as being inherited and see the output. + +It is dead simple to apply this redirection to streams. By setting ``flags`` +to ``UV_INHERIT_STREAM`` and setting ``data.stream`` to the stream in the +parent process, the child process can treat that stream as standard I/O. This +can be used to implement something like CGI_. + +.. _CGI: http://en.wikipedia.org/wiki/Common_Gateway_Interface + +A sample CGI script/executable is: + +.. rubric:: cgi/tick.c +.. literalinclude:: ../code/cgi/tick.c + +The CGI server combines the concepts from this chapter and :doc:`networking` so +that every client is sent ten ticks after which that connection is closed. + +.. rubric:: cgi/main.c +.. literalinclude:: ../code/cgi/main.c + :linenos: + :lines: 49-63 + :emphasize-lines: 10 + +Here we simply accept the TCP connection and pass on the socket (*stream*) to +``invoke_cgi_script``. + +.. rubric:: cgi/main.c +.. literalinclude:: ../code/cgi/main.c + :linenos: + :lines: 16, 25-45 + :emphasize-lines: 8-9,18,20 + +The ``stdout`` of the CGI script is set to the socket so that whatever our tick +script prints, gets sent to the client. By using processes, we can offload the +read/write buffering to the operating system, so in terms of convenience this +is great. Just be warned that creating processes is a costly task. + +.. _pipes: + +Pipes +----- + +libuv's ``uv_pipe_t`` structure is slightly confusing to Unix programmers, +because it immediately conjures up ``|`` and `pipe(7)`_. But ``uv_pipe_t`` is +not related to anonymous pipes, rather it is an IPC mechanism. ``uv_pipe_t`` +can be backed by a `Unix Domain Socket`_ or `Windows Named Pipe`_ to allow +multiple processes to communicate. This is discussed below. + +.. _pipe(7): http://www.kernel.org/doc/man-pages/online/pages/man7/pipe.7.html +.. _Unix Domain Socket: http://www.kernel.org/doc/man-pages/online/pages/man7/unix.7.html +.. _Windows Named Pipe: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365590(v=vs.85).aspx + +Parent-child IPC +++++++++++++++++ + +A parent and child can have one or two way communication over a pipe created by +settings ``uv_stdio_container_t.flags`` to a bit-wise combination of +``UV_CREATE_PIPE`` and ``UV_READABLE_PIPE`` or ``UV_WRITABLE_PIPE``. The +read/write flag is from the perspective of the child process. + +Arbitrary process IPC ++++++++++++++++++++++ + +Since domain sockets [#]_ can have a well known name and a location in the +file-system they can be used for IPC between unrelated processes. The D-BUS_ +system used by open source desktop environments uses domain sockets for event +notification. Various applications can then react when a contact comes online +or new hardware is detected. The MySQL server also runs a domain socket on +which clients can interact with it. + +.. _D-BUS: http://www.freedesktop.org/wiki/Software/dbus + +When using domain sockets, a client-server pattern is usually followed with the +creator/owner of the socket acting as the server. After the initial setup, +messaging is no different from TCP, so we'll re-use the echo server example. + +.. rubric:: pipe-echo-server/main.c +.. literalinclude:: ../code/pipe-echo-server/main.c + :linenos: + :lines: 70- + :emphasize-lines: 5,10,14 + +We name the socket ``echo.sock`` which means it will be created in the local +directory. This socket now behaves no different from TCP sockets as far as +the stream API is concerned. You can test this server using `socat`_:: + + $ socat - /path/to/socket + +A client which wants to connect to a domain socket will use:: + + void uv_pipe_connect(uv_connect_t *req, uv_pipe_t *handle, const char *name, uv_connect_cb cb); + +where ``name`` will be ``echo.sock`` or similar. + +.. _socat: http://www.dest-unreach.org/socat/ + +Sending file descriptors over pipes ++++++++++++++++++++++++++++++++++++ + +The cool thing about domain sockets is that file descriptors can be exchanged +between processes by sending them over a domain socket. This allows processes +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 +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. + +The worker process is quite simple, since the file-descriptor is handed over to +it by the master. + +.. rubric:: multi-echo-server/worker.c +.. literalinclude:: ../code/multi-echo-server/worker.c + :linenos: + :lines: 7-9,81- + :emphasize-lines: 6-8 + +``queue`` is the pipe connected to the master process on the other end, along +which new file descriptors get sent. It is important to set the ``ipc`` +argument of ``uv_pipe_init`` to 1 to indicate this pipe will be used for +inter-process communication! Since the master will write the file handle to the +standard input of the worker, we connect the pipe to ``stdin`` using +``uv_pipe_open``. + +.. rubric:: multi-echo-server/worker.c +.. literalinclude:: ../code/multi-echo-server/worker.c + :linenos: + :lines: 51-79 + :emphasize-lines: 10,15,20 + +First we call ``uv_pipe_pending_count()`` to ensure that a handle is available +to read out. If your program could deal with different types of handles, +``uv_pipe_pending_type()`` can be used to determine the type. +Although ``accept`` seems odd in this code, it actually makes sense. What +``accept`` traditionally does is get a file descriptor (the client) from +another file descriptor (The listening socket). Which is exactly what we do +here. Fetch the file descriptor (``client``) from ``queue``. From this point +the worker does standard echo server stuff. + +Turning now to the master, let's take a look at how the workers are launched to +allow load balancing. + +.. rubric:: multi-echo-server/main.c +.. literalinclude:: ../code/multi-echo-server/main.c + :linenos: + :lines: 9-13 + +The ``child_worker`` structure wraps the process, and the pipe between the +master and the individual process. + +.. rubric:: multi-echo-server/main.c +.. literalinclude:: ../code/multi-echo-server/main.c + :linenos: + :lines: 51,61-95 + :emphasize-lines: 17,20-21 + +In setting up the workers, we use the nifty libuv function ``uv_cpu_info`` to +get the number of CPUs so we can launch an equal number of workers. Again it is +important to initialize the pipe acting as the IPC channel with the third +argument as 1. We then indicate that the child process' ``stdin`` is to be +a readable pipe (from the point of view of the child). Everything is +straightforward till here. The workers are launched and waiting for file +descriptors to be written to their standard input. + +It is in ``on_new_connection`` (the TCP infrastructure is initialized in +``main()``), that we accept the client socket and pass it along to the next +worker in the round-robin. + +.. rubric:: multi-echo-server/main.c +.. literalinclude:: ../code/multi-echo-server/main.c + :linenos: + :lines: 31-49 + :emphasize-lines: 9,12-13 + +The ``uv_write2`` call handles all the abstraction and it is simply a matter of +passing in the handle (``client``) as the right argument. With this our +multi-process echo server is operational. + +Thanks to Kyle for `pointing out`_ that ``uv_write2()`` requires a non-empty +buffer even when sending handles. + +.. _pointing out: https://github.com/nikhilm/uvbook/issues/56 + +---- + +.. [#] In this section domain sockets stands in for named pipes on Windows as + well. diff --git a/docs/src/guide/threads.rst b/docs/src/guide/threads.rst new file mode 100644 index 000000000..4117cc7ef --- /dev/null +++ b/docs/src/guide/threads.rst @@ -0,0 +1,379 @@ +Threads +======= + +Wait a minute? Why are we on threads? Aren't event loops supposed to be **the +way** to do *web-scale programming*? Well... no. Threads are still the medium in +which processors do their jobs. Threads are therefore mighty useful sometimes, even +though you might have to wade through various synchronization primitives. + +Threads are used internally to fake the asynchronous nature of all of the system +calls. libuv also uses threads to allow you, the application, to perform a task +asynchronously that is actually blocking, by spawning a thread and collecting +the result when it is done. + +Today there are two predominant thread libraries: the Windows threads +implementation and POSIX's `pthreads`_. libuv's thread API is analogous to +the pthreads API and often has similar semantics. + +A notable aspect of libuv's thread facilities is that it is a self contained +section within libuv. Whereas other features intimately depend on the event +loop and callback principles, threads are complete agnostic, they block as +required, signal errors directly via return values, and, as shown in the +:ref:`first example `, don't even require a running +event loop. + +libuv's thread API is also very limited since the semantics and syntax of +threads are different on all platforms, with different levels of completeness. + +This chapter makes the following assumption: **There is only one event loop, +running in one thread (the main thread)**. No other thread interacts +with the event loop (except using ``uv_async_send``). + +Core thread operations +---------------------- + +There isn't much here, you just start a thread using ``uv_thread_create()`` and +wait for it to close using ``uv_thread_join()``. + +.. _thread-create-example: + +.. rubric:: thread-create/main.c +.. literalinclude:: ../code/thread-create/main.c + :linenos: + :lines: 26-37 + :emphasize-lines: 3-7 + +.. tip:: + + ``uv_thread_t`` is just an alias for ``pthread_t`` on Unix, but this is an + implementation detail, avoid depending on it to always be true. + +The second parameter is the function which will serve as the entry point for +the thread, the last parameter is a ``void *`` argument which can be used to pass +custom parameters to the thread. The function ``hare`` will now run in a separate +thread, scheduled pre-emptively by the operating system: + +.. rubric:: thread-create/main.c +.. literalinclude:: ../code/thread-create/main.c + :linenos: + :lines: 6-14 + :emphasize-lines: 2 + +Unlike ``pthread_join()`` which allows the target thread to pass back a value to +the calling thread using a second parameter, ``uv_thread_join()`` does not. To +send values use :ref:`inter-thread-communication`. + +Synchronization Primitives +-------------------------- + +This section is purposely spartan. This book is not about threads, so I only +catalogue any surprises in the libuv APIs here. For the rest you can look at +the pthreads `man pages `_. + +Mutexes +~~~~~~~ + +The mutex functions are a **direct** map to the pthread equivalents. + +.. rubric:: libuv mutex functions +.. literalinclude:: ../libuv/include/uv.h + :lines: 1355-1360 + +The ``uv_mutex_init()`` and ``uv_mutex_trylock()`` functions will return 0 on +success, and an error code otherwise. + +If `libuv` has been compiled with debugging enabled, ``uv_mutex_destroy()``, +``uv_mutex_lock()`` and ``uv_mutex_unlock()`` will ``abort()`` on error. +Similarly ``uv_mutex_trylock()`` will abort if the error is anything *other +than* ``EAGAIN`` or ``EBUSY``. + +Recursive mutexes are supported by some platforms, but you should not rely on +them. The BSD mutex implementation will raise an error if a thread which has +locked a mutex attempts to lock it again. For example, a construct like:: + + uv_mutex_lock(a_mutex); + uv_thread_create(thread_id, entry, (void *)a_mutex); + uv_mutex_lock(a_mutex); + // more things here + +can be used to wait until another thread initializes some stuff and then +unlocks ``a_mutex`` but will lead to your program crashing if in debug mode, or +return an error in the second call to ``uv_mutex_lock()``. + +.. note:: + + Mutexes on linux support attributes for a recursive mutex, but the API is + not exposed via libuv. + +Locks +~~~~~ + +Read-write locks are a more granular access mechanism. Two readers can access +shared memory at the same time. A writer may not acquire the lock when it is +held by a reader. A reader or writer may not acquire a lock when a writer is +holding it. Read-write locks are frequently used in databases. Here is a toy +example. + +.. rubric:: locks/main.c - simple rwlocks +.. literalinclude:: ../code/locks/main.c + :linenos: + :emphasize-lines: 13,16,27,31,42,55 + +Run this and observe how the readers will sometimes overlap. In case of +multiple writers, schedulers will usually give them higher priority, so if you +add two writers, you'll see that both writers tend to finish first before the +readers get a chance again. + +We also use barriers in the above example so that the main thread can wait for +all readers and writers to indicate they have ended. + +Others +~~~~~~ + +libuv also supports semaphores_, `condition variables`_ and barriers_ with APIs +very similar to their pthread counterparts. + +.. _semaphores: http://en.wikipedia.org/wiki/Semaphore_(programming) +.. _condition variables: http://en.wikipedia.org/wiki/Condition_variable#Waiting_and_signaling +.. _barriers: http://en.wikipedia.org/wiki/Barrier_(computer_science) + +In addition, libuv provides a convenience function ``uv_once()``. Multiple +threads can attempt to call ``uv_once()`` with a given guard and a function +pointer, **only the first one will win, the function will be called once and +only once**:: + + /* Initialize guard */ + static uv_once_t once_only = UV_ONCE_INIT; + + int i = 0; + + void increment() { + i++; + } + + void thread1() { + /* ... work */ + uv_once(once_only, increment); + } + + void thread2() { + /* ... work */ + uv_once(once_only, increment); + } + + int main() { + /* ... spawn threads */ + } + +After all threads are done, ``i == 1``. + +.. _libuv-work-queue: + +libuv v0.11.11 onwards also added a ``uv_key_t`` struct and api_ for +thread-local storage. + +.. _api: http://docs.libuv.org/en/v1.x/threading.html#thread-local-storage + +libuv work queue +---------------- + +``uv_queue_work()`` is a convenience function that allows an application to run +a task in a separate thread, and have a callback that is triggered when the +task is done. A seemingly simple function, what makes ``uv_queue_work()`` +tempting is that it allows potentially any third-party libraries to be used +with the event-loop paradigm. When you use event loops, it is *imperative to +make sure that no function which runs periodically in the loop thread blocks +when performing I/O or is a serious CPU hog*, because this means that the loop +slows down and events are not being handled at full capacity. + +However, a lot of existing code out there features blocking functions (for example +a routine which performs I/O under the hood) to be used with threads if you +want responsiveness (the classic 'one thread per client' server model), and +getting them to play with an event loop library generally involves rolling your +own system of running the task in a separate thread. libuv just provides +a convenient abstraction for this. + +Here is a simple example inspired by `node.js is cancer`_. We are going to +calculate fibonacci numbers, sleeping a bit along the way, but run it in +a separate thread so that the blocking and CPU bound task does not prevent the +event loop from performing other activities. + +.. rubric:: queue-work/main.c - lazy fibonacci +.. literalinclude:: ../code/queue-work/main.c + :linenos: + :lines: 17-29 + +The actual task function is simple, nothing to show that it is going to be +run in a separate thread. The ``uv_work_t`` structure is the clue. You can pass +arbitrary data through it using the ``void* data`` field and use it to +communicate to and from the thread. But be sure you are using proper locks if +you are changing things while both threads may be running. + +The trigger is ``uv_queue_work``: + +.. rubric:: queue-work/main.c +.. literalinclude:: ../code/queue-work/main.c + :linenos: + :lines: 31-44 + :emphasize-lines: 40 + +The thread function will be launched in a separate thread, passed the +``uv_work_t`` structure and once the function returns, the *after* function +will be called on the thread the event loop is running in. It will be passed +the same structure. + +For writing wrappers to blocking libraries, a common :ref:`pattern ` +is to use a baton to exchange data. + +Since libuv version `0.9.4` an additional function, ``uv_cancel()``, is +available. This allows you to cancel tasks on the libuv work queue. Only tasks +that *are yet to be started* can be cancelled. If a task has *already started +executing, or it has finished executing*, ``uv_cancel()`` **will fail**. + +``uv_cancel()`` is useful to cleanup pending tasks if the user requests +termination. For example, a music player may queue up multiple directories to +be scanned for audio files. If the user terminates the program, it should quit +quickly and not wait until all pending requests are run. + +Let's modify the fibonacci example to demonstrate ``uv_cancel()``. We first set +up a signal handler for termination. + +.. rubric:: queue-cancel/main.c +.. literalinclude:: ../code/queue-cancel/main.c + :linenos: + :lines: 43- + +When the user triggers the signal by pressing ``Ctrl+C`` we send +``uv_cancel()`` to all the workers. ``uv_cancel()`` will return ``0`` for those that are already executing or finished. + +.. rubric:: queue-cancel/main.c +.. literalinclude:: ../code/queue-cancel/main.c + :linenos: + :lines: 33-41 + :emphasize-lines: 6 + +For tasks that do get cancelled successfully, the *after* function is called +with ``status`` set to ``UV_ECANCELED``. + +.. rubric:: queue-cancel/main.c +.. literalinclude:: ../code/queue-cancel/main.c + :linenos: + :lines: 28-31 + :emphasize-lines: 2 + +``uv_cancel()`` can also be used with ``uv_fs_t`` and ``uv_getaddrinfo_t`` +requests. For the filesystem family of functions, ``uv_fs_t.errorno`` will be +set to ``UV_ECANCELED``. + +.. TIP:: + + A well designed program would have a way to terminate long running workers + that have already started executing. Such a worker could periodically check + for a variable that only the main process sets to signal termination. + +.. _inter-thread-communication: + +Inter-thread communication +-------------------------- + +Sometimes you want various threads to actually send each other messages *while* +they are running. For example you might be running some long duration task in +a separate thread (perhaps using ``uv_queue_work``) but want to notify progress +to the main thread. This is a simple example of having a download manager +informing the user of the status of running downloads. + +.. rubric:: progress/main.c +.. literalinclude:: ../code/progress/main.c + :linenos: + :lines: 7-8,34- + :emphasize-lines: 2,11 + +The async thread communication works *on loops* so although any thread can be +the message sender, only threads with libuv loops can be receivers (or rather +the loop is the receiver). libuv will invoke the callback (``print_progress``) +with the async watcher whenever it receives a message. + +.. warning:: + + It is important to realize that since the message send is *async*, the callback + may be invoked immediately after ``uv_async_send`` is called in another + thread, or it may be invoked after some time. libuv may also combine + multiple calls to ``uv_async_send`` and invoke your callback only once. The + only guarantee that libuv makes is -- The callback function is called *at + least once* after the call to ``uv_async_send``. If you have no pending + calls to ``uv_async_send``, the callback won't be called. If you make two + or more calls, and libuv hasn't had a chance to run the callback yet, it + *may* invoke your callback *only once* for the multiple invocations of + ``uv_async_send``. Your callback will never be called twice for just one + event. + +.. rubric:: progress/main.c +.. literalinclude:: ../code/progress/main.c + :linenos: + :lines: 10-23 + :emphasize-lines: 7-8 + +In the download function, we modify the progress indicator and queue the message +for delivery with ``uv_async_send``. Remember: ``uv_async_send`` is also +non-blocking and will return immediately. + +.. rubric:: progress/main.c +.. literalinclude:: ../code/progress/main.c + :linenos: + :lines: 30-33 + +The callback is a standard libuv pattern, extracting the data from the watcher. + +Finally it is important to remember to clean up the watcher. + +.. rubric:: progress/main.c +.. literalinclude:: ../code/progress/main.c + :linenos: + :lines: 25-28 + :emphasize-lines: 3 + +After this example, which showed the abuse of the ``data`` field, bnoordhuis_ +pointed out that using the ``data`` field is not thread safe, and +``uv_async_send()`` is actually only meant to wake up the event loop. Use +a mutex or rwlock to ensure accesses are performed in the right order. + +.. note:: + + mutexes and rwlocks **DO NOT** work inside a signal handler, whereas + ``uv_async_send`` does. + +One use case where ``uv_async_send`` is required is when interoperating with +libraries that require thread affinity for their functionality. For example in +node.js, a v8 engine instance, contexts and its objects are bound to the thread +that the v8 instance was started in. Interacting with v8 data structures from +another thread can lead to undefined results. Now consider some node.js module +which binds a third party library. It may go something like this: + +1. In node, the third party library is set up with a JavaScript callback to be + invoked for more information:: + + var lib = require('lib'); + lib.on_progress(function() { + console.log("Progress"); + }); + + lib.do(); + + // do other stuff + +2. ``lib.do`` is supposed to be non-blocking but the third party lib is + blocking, so the binding uses ``uv_queue_work``. + +3. The actual work being done in a separate thread wants to invoke the progress + callback, but cannot directly call into v8 to interact with JavaScript. So + it uses ``uv_async_send``. + +4. The async callback, invoked in the main loop thread, which is the v8 thread, + then interacts with v8 to invoke the JavaScript callback. + +.. _pthreads: http://man7.org/linux/man-pages/man7/pthreads.7.html + +---- + +.. _node.js is cancer: http://teddziuba.github.io/2011/10/node-js-is-cancer.html +.. _bnoordhuis: https://github.com/bnoordhuis diff --git a/docs/src/guide/utilities.rst b/docs/src/guide/utilities.rst new file mode 100644 index 000000000..fe3c0da6b --- /dev/null +++ b/docs/src/guide/utilities.rst @@ -0,0 +1,433 @@ +Utilities +========= + +This chapter catalogues tools and techniques which are useful for common tasks. +The `libev man page`_ already covers some patterns which can be adopted to +libuv through simple API changes. It also covers parts of the libuv API that +don't require entire chapters dedicated to them. + +Timers +------ + +Timers invoke the callback after a certain time has elapsed since the timer was +started. libuv timers can also be set to invoke at regular intervals instead of +just once. + +Simple use is to init a watcher and start it with a ``timeout``, and optional ``repeat``. +Timers can be stopped at any time. + +.. code-block:: c + + uv_timer_t timer_req; + + uv_timer_init(loop, &timer_req); + uv_timer_start(&timer_req, callback, 5000, 2000); + +will start a repeating timer, which first starts 5 seconds (the ``timeout``) after the execution +of ``uv_timer_start``, then repeats every 2 seconds (the ``repeat``). Use: + +.. code-block:: c + + uv_timer_stop(&timer_req); + +to stop the timer. This can be used safely from within the callback as well. + +The repeat interval can be modified at any time with:: + + uv_timer_set_repeat(uv_timer_t *timer, int64_t repeat); + +which will take effect **when possible**. If this function is called from +a timer callback, it means: + +* If the timer was non-repeating, the timer has already been stopped. Use + ``uv_timer_start`` again. +* If the timer is repeating, the next timeout has already been scheduled, so + the old repeat interval will be used once more before the timer switches to + the new interval. + +The utility function:: + + int uv_timer_again(uv_timer_t *) + +applies **only to repeating timers** and is equivalent to stopping the timer +and then starting it with both initial ``timeout`` and ``repeat`` set to the +old ``repeat`` value. If the timer hasn't been started it fails (error code +``UV_EINVAL``) and returns -1. + +An actual timer example is in the :ref:`reference count section +`. + +.. _reference-count: + +Event loop reference count +-------------------------- + +The event loop only runs as long as there are active handles. This system +works by having every handle increase the reference count of the event loop +when it is started and decreasing the reference count when stopped. It is also +possible to manually change the reference count of handles using:: + + void uv_ref(uv_handle_t*); + void uv_unref(uv_handle_t*); + +These functions can be used to allow a loop to exit even when a watcher is +active or to use custom objects to keep the loop alive. + +The latter can be used with interval timers. You might have a garbage collector +which runs every X seconds, or your network service might send a heartbeat to +others periodically, but you don't want to have to stop them along all clean +exit paths or error scenarios. Or you want the program to exit when all your +other watchers are done. In that case just unref the timer immediately after +creation so that if it is the only watcher running then ``uv_run`` will still +exit. + +This is also used in node.js where some libuv methods are being bubbled up to +the JS API. A ``uv_handle_t`` (the superclass of all watchers) is created per +JS object and can be ref/unrefed. + +.. rubric:: ref-timer/main.c +.. literalinclude:: ../code/ref-timer/main.c + :linenos: + :lines: 5-8, 17- + :emphasize-lines: 9 + +We initialize the garbage collector timer, then immediately ``unref`` it. +Observe how after 9 seconds, when the fake job is done, the program +automatically exits, even though the garbage collector is still running. + +Idler pattern +------------- + +The callbacks of idle handles are invoked once per event loop. The idle +callback can be used to perform some very low priority activity. For example, +you could dispatch a summary of the daily application performance to the +developers for analysis during periods of idleness, or use the application's +CPU time to perform SETI calculations :) An idle watcher is also useful in +a GUI application. Say you are using an event loop for a file download. If the +TCP socket is still being established and no other events are present your +event loop will pause (**block**), which means your progress bar will freeze +and the user will face an unresponsive application. In such a case queue up and +idle watcher to keep the UI operational. + +.. rubric:: idle-compute/main.c +.. literalinclude:: ../code/idle-compute/main.c + :linenos: + :lines: 5-9, 34- + :emphasize-lines: 13 + +Here we initialize the idle watcher and queue it up along with the actual +events we are interested in. ``crunch_away`` will now be called repeatedly +until the user types something and presses Return. Then it will be interrupted +for a brief amount as the loop deals with the input data, after which it will +keep calling the idle callback again. + +.. rubric:: idle-compute/main.c +.. literalinclude:: ../code/idle-compute/main.c + :linenos: + :lines: 10-19 + +.. _baton: + +Passing data to worker thread +----------------------------- + +When using ``uv_queue_work`` you'll usually need to pass complex data through +to the worker thread. The solution is to use a ``struct`` and set +``uv_work_t.data`` to point to it. A slight variation is to have the +``uv_work_t`` itself as the first member of this struct (called a baton [#]_). +This allows cleaning up the work request and all the data in one free call. + +.. code-block:: c + :linenos: + :emphasize-lines: 2 + + struct ftp_baton { + uv_work_t req; + char *host; + int port; + char *username; + char *password; + } + +.. code-block:: c + :linenos: + :emphasize-lines: 2 + + ftp_baton *baton = (ftp_baton*) malloc(sizeof(ftp_baton)); + baton->req.data = (void*) baton; + baton->host = strdup("my.webhost.com"); + baton->port = 21; + // ... + + uv_queue_work(loop, &baton->req, ftp_session, ftp_cleanup); + +Here we create the baton and queue the task. + +Now the task function can extract the data it needs: + +.. code-block:: c + :linenos: + :emphasize-lines: 2, 12 + + void ftp_session(uv_work_t *req) { + ftp_baton *baton = (ftp_baton*) req->data; + + fprintf(stderr, "Connecting to %s\n", baton->host); + } + + void ftp_cleanup(uv_work_t *req) { + ftp_baton *baton = (ftp_baton*) req->data; + + free(baton->host); + // ... + free(baton); + } + +We then free the baton which also frees the watcher. + +External I/O with polling +------------------------- + +Usually third-party libraries will handle their own I/O, and keep track of +their sockets and other files internally. In this case it isn't possible to use +the standard stream I/O operations, but the library can still be integrated +into the libuv event loop. All that is required is that the library allow you +to access the underlying file descriptors and provide functions that process +tasks in small increments as decided by your application. Some libraries though +will not allow such access, providing only a standard blocking function which +will perform the entire I/O transaction and only then return. It is unwise to +use these in the event loop thread, use the :ref:`libuv-work-queue` instead. Of +course, this will also mean losing granular control on the library. + +The ``uv_poll`` section of libuv simply watches file descriptors using the +operating system notification mechanism. In some sense, all the I/O operations +that libuv implements itself are also backed by ``uv_poll`` like code. Whenever +the OS notices a change of state in file descriptors being polled, libuv will +invoke the associated callback. + +Here we will walk through a simple download manager that will use libcurl_ to +download files. Rather than give all control to libcurl, we'll instead be +using the libuv event loop, and use the non-blocking, async multi_ interface to +progress with the download whenever libuv notifies of I/O readiness. + +.. _libcurl: http://curl.haxx.se/libcurl/ +.. _multi: http://curl.haxx.se/libcurl/c/libcurl-multi.html + +.. rubric:: uvwget/main.c - The setup +.. literalinclude:: ../code/uvwget/main.c + :linenos: + :lines: 1-9,140- + :emphasize-lines: 7,21,24-25 + +The way each library is integrated with libuv will vary. In the case of +libcurl, we can register two callbacks. The socket callback ``handle_socket`` +is invoked whenever the state of a socket changes and we have to start polling +it. ``start_timeout`` is called by libcurl to notify us of the next timeout +interval, after which we should drive libcurl forward regardless of I/O status. +This is so that libcurl can handle errors or do whatever else is required to +get the download moving. + +Our downloader is to be invoked as:: + + $ ./uvwget [url1] [url2] ... + +So we add each argument as an URL + +.. rubric:: uvwget/main.c - Adding urls +.. literalinclude:: ../code/uvwget/main.c + :linenos: + :lines: 39-56 + :emphasize-lines: 13-14 + +We let libcurl directly write the data to a file, but much more is possible if +you so desire. + +``start_timeout`` will be called immediately the first time by libcurl, so +things are set in motion. This simply starts a libuv `timer `_ which +drives ``curl_multi_socket_action`` with ``CURL_SOCKET_TIMEOUT`` whenever it +times out. ``curl_multi_socket_action`` is what drives libcurl, and what we +call whenever sockets change state. But before we go into that, we need to poll +on sockets whenever ``handle_socket`` is called. + +.. rubric:: uvwget/main.c - Setting up polling +.. literalinclude:: ../code/uvwget/main.c + :linenos: + :lines: 102-140 + :emphasize-lines: 9,11,15,21,24 + +We are interested in the socket fd ``s``, and the ``action``. For every socket +we create a ``uv_poll_t`` handle if it doesn't exist, and associate it with the +socket using ``curl_multi_assign``. This way ``socketp`` points to it whenever +the callback is invoked. + +In the case that the download is done or fails, libcurl requests removal of the +poll. So we stop and free the poll handle. + +Depending on what events libcurl wishes to watch for, we start polling with +``UV_READABLE`` or ``UV_WRITABLE``. Now libuv will invoke the poll callback +whenever the socket is ready for reading or writing. Calling ``uv_poll_start`` +multiple times on the same handle is acceptable, it will just update the events +mask with the new value. ``curl_perform`` is the crux of this program. + +.. rubric:: uvwget/main.c - Driving libcurl. +.. literalinclude:: ../code/uvwget/main.c + :linenos: + :lines: 81-95 + :emphasize-lines: 2,6-7,12,18,20 + +The first thing we do is to stop the timer, since there has been some progress +in the interval. Then depending on what event triggered the callback, we set +the correct flags. Then we call ``curl_multi_socket_action`` with the socket +that progressed and the flags informing about what events happened. At this +point libcurl does all of its internal tasks in small increments, and will +attempt to return as fast as possible, which is exactly what an evented program +wants in its main thread. libcurl keeps queueing messages into its own queue +about transfer progress. In our case we are only interested in transfers that +are completed. So we extract these messages, and clean up handles whose +transfers are done. + +.. rubric:: uvwget/main.c - Reading transfer status. +.. literalinclude:: ../code/uvwget/main.c + :linenos: + :lines: 58-79 + :emphasize-lines: 6,9-10,13-14 + +Check & Prepare watchers +------------------------ + +TODO + +Loading libraries +----------------- + +libuv provides a cross platform API to dynamically load `shared libraries`_. +This can be used to implement your own plugin/extension/module system and is +used by node.js to implement ``require()`` support for bindings. The usage is +quite simple as long as your library exports the right symbols. Be careful with +sanity and security checks when loading third party code, otherwise your +program will behave unpredictably. This example implements a very simple +plugin system which does nothing except print the name of the plugin. + +Let us first look at the interface provided to plugin authors. + +.. rubric:: plugin/plugin.h +.. literalinclude:: ../code/plugin/plugin.h + :linenos: + +You can similarly add more functions that plugin authors can use to do useful +things in your application [#]_. A sample plugin using this API is: + +.. rubric:: plugin/hello.c +.. literalinclude:: ../code/plugin/hello.c + :linenos: + +Our interface defines that all plugins should have an ``initialize`` function +which will be called by the application. This plugin is compiled as a shared +library and can be loaded by running our application:: + + $ ./plugin libhello.dylib + Loading libhello.dylib + Registered plugin "Hello World!" + +.. NOTE:: + + The shared library filename will be different depending on platforms. On + Linux it is ``libhello.so``. + +This is done by using ``uv_dlopen`` to first load the shared library +``libhello.dylib``. Then we get access to the ``initialize`` function using +``uv_dlsym`` and invoke it. + +.. rubric:: plugin/main.c +.. literalinclude:: ../code/plugin/main.c + :linenos: + :lines: 7- + :emphasize-lines: 15, 18, 24 + +``uv_dlopen`` expects a path to the shared library and sets the opaque +``uv_lib_t`` pointer. It returns 0 on success, -1 on error. Use ``uv_dlerror`` +to get the error message. + +``uv_dlsym`` stores a pointer to the symbol in the second argument in the third +argument. ``init_plugin_function`` is a function pointer to the sort of +function we are looking for in the application's plugins. + +.. _shared libraries: http://en.wikipedia.org/wiki/Shared_library#Shared_libraries + +TTY +--- + +Text terminals have supported basic formatting for a long time, with a `pretty +standardised`_ command set. This formatting is often used by programs to +improve the readability of terminal output. For example ``grep --colour``. +libuv provides the ``uv_tty_t`` abstraction (a stream) and related functions to +implement the ANSI escape codes across all platforms. By this I mean that libuv +converts ANSI codes to the Windows equivalent, and provides functions to get +terminal information. + +.. _pretty standardised: http://en.wikipedia.org/wiki/ANSI_escape_sequences + +The first thing to do is to initialize a ``uv_tty_t`` with the file descriptor +it reads/writes from. This is achieved with:: + + int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable) + +Set ``readable`` to true if you plan to use ``uv_read_start()`` on the stream. + +It is then best to use ``uv_tty_set_mode`` to set the mode to *normal* +which enables most TTY formatting, flow-control and other settings. Other_ modes +are also available. + +.. _Other: http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_mode_t + +Remember to call ``uv_tty_reset_mode`` when your program exits to restore the +state of the terminal. Just good manners. Another set of good manners is to be +aware of redirection. If the user redirects the output of your command to +a file, control sequences should not be written as they impede readability and +``grep``. To check if the file descriptor is indeed a TTY, call +``uv_guess_handle`` with the file descriptor and compare the return value with +``UV_TTY``. + +Here is a simple example which prints white text on a red background: + +.. rubric:: tty/main.c +.. literalinclude:: ../code/tty/main.c + :linenos: + :emphasize-lines: 11-12,14,17,27 + +The final TTY helper is ``uv_tty_get_winsize()`` which is used to get the +width and height of the terminal and returns ``0`` on success. Here is a small +program which does some animation using the function and character position +escape codes. + +.. rubric:: tty-gravity/main.c +.. literalinclude:: ../code/tty-gravity/main.c + :linenos: + :emphasize-lines: 19,25,38 + +The escape codes are: + +====== ======================= +Code Meaning +====== ======================= +*2* J Clear part of the screen, 2 is entire screen +H Moves cursor to certain position, default top-left +*n* B Moves cursor down by n lines +*n* C Moves cursor right by n columns +m Obeys string of display settings, in this case green background (40+2), white text (30+7) +====== ======================= + +As you can see this is very useful to produce nicely formatted output, or even +console based arcade games if that tickles your fancy. For fancier control you +can try `ncurses`_. + +.. _ncurses: http://www.gnu.org/software/ncurses/ncurses.html + +---- + +.. [#] I was first introduced to the term baton in this context, in Konstantin + Käfer's excellent slides on writing node.js bindings -- + http://kkaefer.github.com/node-cpp-modules/#baton +.. [#] mfp is My Fancy Plugin + +.. _libev man page: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#COMMON_OR_USEFUL_IDIOMS_OR_BOTH diff --git a/docs/src/index.rst b/docs/src/index.rst index d89f251fd..5ec2beb51 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -45,6 +45,7 @@ Documentation design api + guide upgrading From a94f83e4d8332d9bb6b59bd941f9ef717a8e8bf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 12 Mar 2017 22:50:17 +0100 Subject: [PATCH 364/632] doc: removed unused file We use guide.rst as our index, so there is no need for a secondary one. PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/guide/index.rst | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 docs/src/guide/index.rst diff --git a/docs/src/guide/index.rst b/docs/src/guide/index.rst deleted file mode 100644 index 5c9a2b670..000000000 --- a/docs/src/guide/index.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. An Introduction to libuv documentation master file, created by - sphinx-quickstart on Sat Jun 16 16:39:14 2012. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Table of Contents -================= - -.. toctree:: - :maxdepth: 2 - - introduction - basics - filesystem - networking - threads - processes - eventloops - utilities - about - -Alternate formats ------------------ - -The book is also available in: - -.. raw:: html - - From 1caae80cd6ff22105da564c6b4e88bf1f25208f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 12 Mar 2017 22:54:52 +0100 Subject: [PATCH 365/632] doc: update guide/about and mention new maintainership PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/guide/about.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/src/guide/about.rst b/docs/src/guide/about.rst index 8efa51782..8dc58cbee 100644 --- a/docs/src/guide/about.rst +++ b/docs/src/guide/about.rst @@ -7,8 +7,7 @@ been stung by the lack of good documentation on libuv while working on `node-taglib `_. Although reference documentation was present, there were no comprehensive tutorials. This book is the output of that need and tries to be accurate. That said, the book may have -mistakes. Pull requests are encouraged. You may also `email him -`_ if you find an error. +mistakes. Pull requests are encouraged. Nikhil is indebted to Marc Lehmann's comprehensive `man page `_ about libev which @@ -17,6 +16,10 @@ describes much of the semantics of the two libraries. This book was made using `Sphinx `_ and `vim `_. +.. note:: + In 2017 the libuv project incorporated the Nikhil's work into the official + documentation and it's maintained there henceforth. + Licensing --------- From 481f45440300c803d1a60e21a1d40b43338cfc35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 12 Mar 2017 22:55:43 +0100 Subject: [PATCH 366/632] doc: remove licensing note from guide/about PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/guide/about.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/src/guide/about.rst b/docs/src/guide/about.rst index 8dc58cbee..2de658d5d 100644 --- a/docs/src/guide/about.rst +++ b/docs/src/guide/about.rst @@ -20,9 +20,3 @@ This book was made using `Sphinx `_ and `vim In 2017 the libuv project incorporated the Nikhil's work into the official documentation and it's maintained there henceforth. -Licensing ---------- - -The contents of this book are licensed as `Creative Commons - Attribution -`_. All code is in the **public -domain**. From 022706048916ce50e084eb65aec003406d4ba147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 12 Mar 2017 23:00:19 +0100 Subject: [PATCH 367/632] doc: add warning note to user guide PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/guide.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/src/guide.rst b/docs/src/guide.rst index 5f6c285aa..126e08082 100644 --- a/docs/src/guide.rst +++ b/docs/src/guide.rst @@ -3,6 +3,11 @@ User guide ========== +.. warning:: + The contents of this guide have been recently incorporated into the libuv documentation + and it hasn't gone through thorough review yet. If you spot a mistake please file an + issue, or better yet, open a pull request! + .. toctree:: :maxdepth: 2 From ed76c055cdbd0e949e527966a58f0ff9adaa7fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 25 Apr 2017 08:24:17 +0200 Subject: [PATCH 368/632] doc: change license to CC BY 4.0 Text taken from: https://creativecommons.org/licenses/by/4.0/legalcode.txt Fixes: https://github.com/libuv/libuv/issues/1254 PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- LICENSE-docs | 396 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 1 + 2 files changed, 397 insertions(+) create mode 100644 LICENSE-docs diff --git a/LICENSE-docs b/LICENSE-docs new file mode 100644 index 000000000..53883b1c7 --- /dev/null +++ b/LICENSE-docs @@ -0,0 +1,396 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/README.md b/README.md index 7cf96dd23..0fecdfd45 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ 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). ## Community From 2ce5734d76a8bfbf01af4a4854edf1e3cc42e029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 25 Apr 2017 08:26:25 +0200 Subject: [PATCH 369/632] doc: remove ubvook reference from README PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 0fecdfd45..e5d94faf0 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ The documentation is licensed under the CC BY 4.0 license. Check the [LICENSE-do ## Documentation -### Official API documentation +### Official documentation Located in the docs/ subdirectory. It uses the [Sphinx](http://sphinx-doc.org/) framework, which makes it possible to build the documentation in multiple @@ -90,8 +90,6 @@ also serve as API specification and usage examples. ### Other resources - * [An Introduction to libuv](http://nikhilm.github.com/uvbook/) - — An overview of libuv with tutorials. * [LXJS 2012 talk](http://www.youtube.com/watch?v=nGn60vDSxQ4) — High-level introductory talk about libuv. * [libuv-dox](https://github.com/thlorenz/libuv-dox) From d59d6e6f22b4c11c37e34843d111a748df73bda2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 25 Apr 2017 08:27:52 +0200 Subject: [PATCH 370/632] doc: add code samples from uvbook (unadapted) PR-URL: https://github.com/libuv/libuv/pull/1246 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/code/cgi/main.c | 81 +++++++++++++ docs/code/cgi/tick.c | 13 ++ docs/code/detach/main.c | 31 +++++ docs/code/dns/main.c | 80 +++++++++++++ docs/code/helloworld/main.c | 15 +++ docs/code/idle-basic/main.c | 24 ++++ docs/code/idle-compute/main.c | 43 +++++++ docs/code/interfaces/main.c | 33 +++++ docs/code/locks/main.c | 57 +++++++++ docs/code/multi-echo-server/hammer.js | 20 ++++ docs/code/multi-echo-server/main.c | 114 ++++++++++++++++++ docs/code/multi-echo-server/worker.c | 88 ++++++++++++++ docs/code/onchange/main.c | 44 +++++++ docs/code/pipe-echo-server/main.c | 88 ++++++++++++++ docs/code/plugin/hello.c | 5 + docs/code/plugin/main.c | 39 ++++++ docs/code/plugin/plugin.h | 7 ++ docs/code/proc-streams/main.c | 49 ++++++++ docs/code/proc-streams/test.c | 8 ++ docs/code/progress/main.c | 47 ++++++++ docs/code/queue-cancel/main.c | 59 +++++++++ docs/code/queue-work/main.c | 44 +++++++ docs/code/ref-timer/main.c | 29 +++++ docs/code/signal/main.c | 66 ++++++++++ docs/code/spawn/main.c | 36 ++++++ docs/code/tcp-echo-server/main.c | 83 +++++++++++++ docs/code/thread-create/main.c | 36 ++++++ docs/code/tty-gravity/main.c | 48 ++++++++ docs/code/tty/main.c | 29 +++++ docs/code/udp-dhcp/main.c | 127 ++++++++++++++++++++ docs/code/uvcat/main.c | 63 ++++++++++ docs/code/uvstop/main.c | 33 +++++ docs/code/uvtee/main.c | 80 +++++++++++++ docs/code/uvwget/main.c | 166 ++++++++++++++++++++++++++ 34 files changed, 1785 insertions(+) create mode 100644 docs/code/cgi/main.c create mode 100644 docs/code/cgi/tick.c create mode 100644 docs/code/detach/main.c create mode 100644 docs/code/dns/main.c create mode 100644 docs/code/helloworld/main.c create mode 100644 docs/code/idle-basic/main.c create mode 100644 docs/code/idle-compute/main.c create mode 100644 docs/code/interfaces/main.c create mode 100644 docs/code/locks/main.c create mode 100644 docs/code/multi-echo-server/hammer.js create mode 100644 docs/code/multi-echo-server/main.c create mode 100644 docs/code/multi-echo-server/worker.c create mode 100644 docs/code/onchange/main.c create mode 100644 docs/code/pipe-echo-server/main.c create mode 100644 docs/code/plugin/hello.c create mode 100644 docs/code/plugin/main.c create mode 100644 docs/code/plugin/plugin.h create mode 100644 docs/code/proc-streams/main.c create mode 100644 docs/code/proc-streams/test.c create mode 100644 docs/code/progress/main.c create mode 100644 docs/code/queue-cancel/main.c create mode 100644 docs/code/queue-work/main.c create mode 100644 docs/code/ref-timer/main.c create mode 100644 docs/code/signal/main.c create mode 100644 docs/code/spawn/main.c create mode 100644 docs/code/tcp-echo-server/main.c create mode 100644 docs/code/thread-create/main.c create mode 100644 docs/code/tty-gravity/main.c create mode 100644 docs/code/tty/main.c create mode 100644 docs/code/udp-dhcp/main.c create mode 100644 docs/code/uvcat/main.c create mode 100644 docs/code/uvstop/main.c create mode 100644 docs/code/uvtee/main.c create mode 100644 docs/code/uvwget/main.c diff --git a/docs/code/cgi/main.c b/docs/code/cgi/main.c new file mode 100644 index 000000000..d2e34265a --- /dev/null +++ b/docs/code/cgi/main.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include + +uv_loop_t *loop; +uv_process_t child_req; +uv_process_options_t options; + +void cleanup_handles(uv_process_t *req, int64_t exit_status, int term_signal) { + fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); + uv_close((uv_handle_t*) req->data, NULL); + uv_close((uv_handle_t*) req, NULL); +} + +void invoke_cgi_script(uv_tcp_t *client) { + size_t size = 500; + char path[size]; + uv_exepath(path, &size); + strcpy(path + (strlen(path) - strlen("cgi")), "tick"); + + char* args[2]; + args[0] = path; + args[1] = NULL; + + /* ... finding the executable path and setting up arguments ... */ + + options.stdio_count = 3; + uv_stdio_container_t child_stdio[3]; + child_stdio[0].flags = UV_IGNORE; + child_stdio[1].flags = UV_INHERIT_STREAM; + child_stdio[1].data.stream = (uv_stream_t*) client; + child_stdio[2].flags = UV_IGNORE; + options.stdio = child_stdio; + + options.exit_cb = cleanup_handles; + options.file = args[0]; + options.args = args; + + // Set this so we can close the socket after the child process exits. + child_req.data = (void*) client; + int r; + if ((r = uv_spawn(loop, &child_req, &options))) { + fprintf(stderr, "%s\n", uv_strerror(r)); + return; + } +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status == -1) { + // error! + return; + } + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + invoke_cgi_script(client); + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +int main() { + loop = uv_default_loop(); + + uv_tcp_t server; + uv_tcp_init(loop, &server); + + struct sockaddr_in bind_addr; + uv_ip4_addr("0.0.0.0", 7000, &bind_addr); + uv_tcp_bind(&server, (const struct sockaddr *)&bind_addr, 0); + int r = uv_listen((uv_stream_t*) &server, 128, on_new_connection); + if (r) { + fprintf(stderr, "Listen error %s\n", uv_err_name(r)); + return 1; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/cgi/tick.c b/docs/code/cgi/tick.c new file mode 100644 index 000000000..0b498edf5 --- /dev/null +++ b/docs/code/cgi/tick.c @@ -0,0 +1,13 @@ +#include +#include + +int main() { + int i; + for (i = 0; i < 10; i++) { + printf("tick\n"); + fflush(stdout); + sleep(1); + } + printf("BOOM!\n"); + return 0; +} diff --git a/docs/code/detach/main.c b/docs/code/detach/main.c new file mode 100644 index 000000000..3c88fff4e --- /dev/null +++ b/docs/code/detach/main.c @@ -0,0 +1,31 @@ +#include + +#include + +uv_loop_t *loop; +uv_process_t child_req; +uv_process_options_t options; + +int main() { + loop = uv_default_loop(); + + char* args[3]; + args[0] = "sleep"; + args[1] = "100"; + args[2] = NULL; + + options.exit_cb = NULL; + options.file = "sleep"; + options.args = args; + options.flags = UV_PROCESS_DETACHED; + + int r; + if ((r = uv_spawn(loop, &child_req, &options))) { + fprintf(stderr, "%s\n", uv_strerror(r)); + return 1; + } + fprintf(stderr, "Launched sleep with PID %d\n", child_req.pid); + uv_unref((uv_handle_t*) &child_req); + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/dns/main.c b/docs/code/dns/main.c new file mode 100644 index 000000000..77a7005f4 --- /dev/null +++ b/docs/code/dns/main.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +uv_loop_t *loop; + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void on_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, NULL); + free(buf->base); + free(client); + return; + } + + char *data = (char*) malloc(sizeof(char) * (nread+1)); + data[nread] = '\0'; + strncpy(data, buf->base, nread); + + fprintf(stderr, "%s", data); + free(data); + free(buf->base); +} + +void on_connect(uv_connect_t *req, int status) { + if (status < 0) { + fprintf(stderr, "connect failed error %s\n", uv_err_name(status)); + free(req); + return; + } + + uv_read_start((uv_stream_t*) req->handle, alloc_buffer, on_read); + free(req); +} + +void on_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) { + if (status < 0) { + fprintf(stderr, "getaddrinfo callback error %s\n", uv_err_name(status)); + return; + } + + char addr[17] = {'\0'}; + uv_ip4_name((struct sockaddr_in*) res->ai_addr, addr, 16); + fprintf(stderr, "%s\n", addr); + + uv_connect_t *connect_req = (uv_connect_t*) malloc(sizeof(uv_connect_t)); + uv_tcp_t *socket = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, socket); + + uv_tcp_connect(connect_req, socket, (const struct sockaddr*) res->ai_addr, on_connect); + + uv_freeaddrinfo(res); +} + +int main() { + loop = uv_default_loop(); + + struct addrinfo hints; + hints.ai_family = PF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + 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); + + if (r) { + fprintf(stderr, "getaddrinfo call error %s\n", uv_err_name(r)); + return 1; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/helloworld/main.c b/docs/code/helloworld/main.c new file mode 100644 index 000000000..a31bf88a3 --- /dev/null +++ b/docs/code/helloworld/main.c @@ -0,0 +1,15 @@ +#include +#include +#include + +int main() { + uv_loop_t *loop = malloc(sizeof(uv_loop_t)); + uv_loop_init(loop); + + printf("Now quitting.\n"); + uv_run(loop, UV_RUN_DEFAULT); + + uv_loop_close(loop); + free(loop); + return 0; +} diff --git a/docs/code/idle-basic/main.c b/docs/code/idle-basic/main.c new file mode 100644 index 000000000..77ba31cf5 --- /dev/null +++ b/docs/code/idle-basic/main.c @@ -0,0 +1,24 @@ +#include +#include + +int64_t counter = 0; + +void wait_for_a_while(uv_idle_t* handle) { + counter++; + + if (counter >= 10e6) + uv_idle_stop(handle); +} + +int main() { + uv_idle_t idler; + + uv_idle_init(uv_default_loop(), &idler); + uv_idle_start(&idler, wait_for_a_while); + + printf("Idling...\n"); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + uv_loop_close(uv_default_loop()); + return 0; +} diff --git a/docs/code/idle-compute/main.c b/docs/code/idle-compute/main.c new file mode 100644 index 000000000..ff44b6946 --- /dev/null +++ b/docs/code/idle-compute/main.c @@ -0,0 +1,43 @@ +#include + +#include + +uv_loop_t *loop; +uv_fs_t stdin_watcher; +uv_idle_t idler; +char buffer[1024]; + +void crunch_away(uv_idle_t* handle) { + // Compute extra-terrestrial life + // fold proteins + // computer another digit of PI + // or similar + fprintf(stderr, "Computing PI...\n"); + // just to avoid overwhelming your terminal emulator + uv_idle_stop(handle); +} + +void on_type(uv_fs_t *req) { + if (stdin_watcher.result > 0) { + buffer[stdin_watcher.result] = '\0'; + printf("Typed %s\n", buffer); + + uv_buf_t buf = uv_buf_init(buffer, 1024); + uv_fs_read(loop, &stdin_watcher, 0, &buf, 1, -1, on_type); + uv_idle_start(&idler, crunch_away); + } + else if (stdin_watcher.result < 0) { + fprintf(stderr, "error opening file: %s\n", uv_strerror(req->result)); + } +} + +int main() { + loop = uv_default_loop(); + + uv_idle_init(loop, &idler); + + uv_buf_t buf = uv_buf_init(buffer, 1024); + uv_fs_read(loop, &stdin_watcher, 0, &buf, 1, -1, on_type); + uv_idle_start(&idler, crunch_away); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/interfaces/main.c b/docs/code/interfaces/main.c new file mode 100644 index 000000000..cac12c266 --- /dev/null +++ b/docs/code/interfaces/main.c @@ -0,0 +1,33 @@ +#include +#include + +int main() { + char buf[512]; + uv_interface_address_t *info; + int count, i; + + uv_interface_addresses(&info, &count); + i = count; + + printf("Number of interfaces: %d\n", count); + while (i--) { + uv_interface_address_t interface = info[i]; + + printf("Name: %s\n", interface.name); + printf("Internal? %s\n", interface.is_internal ? "Yes" : "No"); + + if (interface.address.address4.sin_family == AF_INET) { + uv_ip4_name(&interface.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)); + printf("IPv6 address: %s\n", buf); + } + + printf("\n"); + } + + uv_free_interface_addresses(info, count); + return 0; +} diff --git a/docs/code/locks/main.c b/docs/code/locks/main.c new file mode 100644 index 000000000..2b1f8ca7c --- /dev/null +++ b/docs/code/locks/main.c @@ -0,0 +1,57 @@ +#include +#include + +uv_barrier_t blocker; +uv_rwlock_t numlock; +int shared_num; + +void reader(void *n) +{ + int num = *(int *)n; + int i; + for (i = 0; i < 20; i++) { + uv_rwlock_rdlock(&numlock); + printf("Reader %d: acquired lock\n", num); + printf("Reader %d: shared num = %d\n", num, shared_num); + uv_rwlock_rdunlock(&numlock); + printf("Reader %d: released lock\n", num); + } + uv_barrier_wait(&blocker); +} + +void writer(void *n) +{ + int num = *(int *)n; + int i; + for (i = 0; i < 20; i++) { + uv_rwlock_wrlock(&numlock); + printf("Writer %d: acquired lock\n", num); + shared_num++; + printf("Writer %d: incremented shared num = %d\n", num, shared_num); + uv_rwlock_wrunlock(&numlock); + printf("Writer %d: released lock\n", num); + } + uv_barrier_wait(&blocker); +} + +int main() +{ + uv_barrier_init(&blocker, 4); + + shared_num = 0; + uv_rwlock_init(&numlock); + + uv_thread_t threads[3]; + + int thread_nums[] = {1, 2, 1}; + uv_thread_create(&threads[0], reader, &thread_nums[0]); + uv_thread_create(&threads[1], reader, &thread_nums[1]); + + uv_thread_create(&threads[2], writer, &thread_nums[2]); + + uv_barrier_wait(&blocker); + uv_barrier_destroy(&blocker); + + uv_rwlock_destroy(&numlock); + return 0; +} diff --git a/docs/code/multi-echo-server/hammer.js b/docs/code/multi-echo-server/hammer.js new file mode 100644 index 000000000..5df345b78 --- /dev/null +++ b/docs/code/multi-echo-server/hammer.js @@ -0,0 +1,20 @@ +var net = require('net'); + +var PHRASE = "hello world"; +var write = function(socket) { + socket.write(PHRASE, 'utf8'); +} + +for (var i = 0; i < 1000; i++) { +(function() { + var socket = net.connect(7000, 'localhost', function() { + socket.on('data', function(reply) { + if (reply.toString().indexOf(PHRASE) != 0) + console.error("Problem! '" + reply + "'" + " '" + PHRASE + "'"); + else + write(socket); + }); + write(socket); + }); +})(); +} diff --git a/docs/code/multi-echo-server/main.c b/docs/code/multi-echo-server/main.c new file mode 100644 index 000000000..25f496123 --- /dev/null +++ b/docs/code/multi-echo-server/main.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include + +uv_loop_t *loop; + +struct child_worker { + uv_process_t req; + uv_process_options_t options; + uv_pipe_t pipe; +} *workers; + +int round_robin_counter; +int child_worker_count; + +uv_buf_t dummy_buf; +char worker_path[500]; + +void close_process_handle(uv_process_t *req, int64_t exit_status, int term_signal) { + fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); + uv_close((uv_handle_t*) req, NULL); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status == -1) { + // error! + return; + } + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + uv_write_t *write_req = (uv_write_t*) malloc(sizeof(uv_write_t)); + dummy_buf = uv_buf_init("a", 1); + struct child_worker *worker = &workers[round_robin_counter]; + uv_write2(write_req, (uv_stream_t*) &worker->pipe, &dummy_buf, 1, (uv_stream_t*) client, NULL); + round_robin_counter = (round_robin_counter + 1) % child_worker_count; + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +void setup_workers() { + size_t path_size = 500; + uv_exepath(worker_path, &path_size); + strcpy(worker_path + (strlen(worker_path) - strlen("multi-echo-server")), "worker"); + fprintf(stderr, "Worker path: %s\n", worker_path); + + char* args[2]; + args[0] = worker_path; + args[1] = NULL; + + round_robin_counter = 0; + + // ... + + // launch same number of workers as number of CPUs + uv_cpu_info_t *info; + int cpu_count; + uv_cpu_info(&info, &cpu_count); + uv_free_cpu_info(info, cpu_count); + + child_worker_count = cpu_count; + + workers = calloc(sizeof(struct child_worker), cpu_count); + while (cpu_count--) { + struct child_worker *worker = &workers[cpu_count]; + uv_pipe_init(loop, &worker->pipe, 1); + + uv_stdio_container_t child_stdio[3]; + child_stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE; + child_stdio[0].data.stream = (uv_stream_t*) &worker->pipe; + child_stdio[1].flags = UV_IGNORE; + child_stdio[2].flags = UV_INHERIT_FD; + child_stdio[2].data.fd = 2; + + worker->options.stdio = child_stdio; + worker->options.stdio_count = 3; + + worker->options.exit_cb = close_process_handle; + worker->options.file = args[0]; + worker->options.args = args; + + uv_spawn(loop, &worker->req, &worker->options); + fprintf(stderr, "Started worker %d\n", worker->req.pid); + } +} + +int main() { + loop = uv_default_loop(); + + setup_workers(); + + uv_tcp_t server; + uv_tcp_init(loop, &server); + + struct sockaddr_in bind_addr; + uv_ip4_addr("0.0.0.0", 7000, &bind_addr); + uv_tcp_bind(&server, (const struct sockaddr *)&bind_addr, 0); + int r; + if ((r = uv_listen((uv_stream_t*) &server, 128, on_new_connection))) { + fprintf(stderr, "Listen error %s\n", uv_err_name(r)); + return 2; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/multi-echo-server/worker.c b/docs/code/multi-echo-server/worker.c new file mode 100644 index 000000000..1c4657598 --- /dev/null +++ b/docs/code/multi-echo-server/worker.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include + +uv_loop_t *loop; +uv_pipe_t queue; + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void echo_write(uv_write_t *req, int status) { + if (status) { + fprintf(stderr, "Write error %s\n", uv_err_name(status)); + } + free_write_req(req); +} + +void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread > 0) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init(buf->base, nread); + uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); + return; + } + + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, NULL); + } + + free(buf->base); +} + +void on_new_connection(uv_stream_t *q, ssize_t nread, const uv_buf_t *buf) { + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) q, NULL); + return; + } + + uv_pipe_t *pipe = (uv_pipe_t*) q; + if (!uv_pipe_pending_count(pipe)) { + fprintf(stderr, "No pending count\n"); + return; + } + + uv_handle_type pending = uv_pipe_pending_type(pipe); + assert(pending == UV_TCP); + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(q, (uv_stream_t*) client) == 0) { + uv_os_fd_t fd; + uv_fileno((const uv_handle_t*) client, &fd); + fprintf(stderr, "Worker %d: Accepted fd %d\n", getpid(), fd); + uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +int main() { + loop = uv_default_loop(); + + uv_pipe_init(loop, &queue, 1 /* ipc */); + uv_pipe_open(&queue, 0); + uv_read_start((uv_stream_t*)&queue, alloc_buffer, on_new_connection); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/onchange/main.c b/docs/code/onchange/main.c new file mode 100644 index 000000000..40bdaa52a --- /dev/null +++ b/docs/code/onchange/main.c @@ -0,0 +1,44 @@ +#include +#include + +#include + +uv_loop_t *loop; +const char *command; + +void run_command(uv_fs_event_t *handle, const char *filename, int events, int status) { + char path[1024]; + size_t size = 1023; + // Does not handle error if path is longer than 1023. + uv_fs_event_getpath(handle, path, &size); + path[size] = '\0'; + + fprintf(stderr, "Change detected in %s: ", path); + if (events & UV_RENAME) + fprintf(stderr, "renamed"); + if (events & UV_CHANGE) + fprintf(stderr, "changed"); + + fprintf(stderr, " %s\n", filename ? filename : ""); + system(command); +} + +int main(int argc, char **argv) { + if (argc <= 2) { + fprintf(stderr, "Usage: %s [file2 ...]\n", argv[0]); + return 1; + } + + loop = uv_default_loop(); + command = argv[1]; + + while (argc-- > 2) { + fprintf(stderr, "Adding watch on %s\n", argv[argc]); + uv_fs_event_t *fs_event_req = malloc(sizeof(uv_fs_event_t)); + uv_fs_event_init(loop, fs_event_req); + // The recursive flag watches subdirectories too. + uv_fs_event_start(fs_event_req, run_command, argv[argc], UV_FS_EVENT_RECURSIVE); + } + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/pipe-echo-server/main.c b/docs/code/pipe-echo-server/main.c new file mode 100644 index 000000000..4ba4246e7 --- /dev/null +++ b/docs/code/pipe-echo-server/main.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include + +uv_loop_t *loop; + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void echo_write(uv_write_t *req, int status) { + if (status < 0) { + fprintf(stderr, "Write error %s\n", uv_err_name(status)); + } + free_write_req(req); +} + +void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread > 0) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init(buf->base, nread); + uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); + return; + } + + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, NULL); + } + + free(buf->base); +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status == -1) { + // error! + return; + } + + uv_pipe_t *client = (uv_pipe_t*) malloc(sizeof(uv_pipe_t)); + uv_pipe_init(loop, client, 0); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +void remove_sock(int sig) { + uv_fs_t req; + uv_fs_unlink(loop, &req, "echo.sock", NULL); + exit(0); +} + +int main() { + loop = uv_default_loop(); + + uv_pipe_t server; + uv_pipe_init(loop, &server, 0); + + signal(SIGINT, remove_sock); + + int r; + if ((r = uv_pipe_bind(&server, "echo.sock"))) { + fprintf(stderr, "Bind error %s\n", uv_err_name(r)); + return 1; + } + if ((r = uv_listen((uv_stream_t*) &server, 128, on_new_connection))) { + fprintf(stderr, "Listen error %s\n", uv_err_name(r)); + return 2; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/plugin/hello.c b/docs/code/plugin/hello.c new file mode 100644 index 000000000..7b2861d7d --- /dev/null +++ b/docs/code/plugin/hello.c @@ -0,0 +1,5 @@ +#include "plugin.h" + +void initialize() { + mfp_register("Hello World!"); +} diff --git a/docs/code/plugin/main.c b/docs/code/plugin/main.c new file mode 100644 index 000000000..06e581e63 --- /dev/null +++ b/docs/code/plugin/main.c @@ -0,0 +1,39 @@ +#include +#include +#include + +#include + +#include "plugin.h" + +typedef void (*init_plugin_function)(); + +void mfp_register(const char *name) { + fprintf(stderr, "Registered plugin \"%s\"\n", name); +} + +int main(int argc, char **argv) { + if (argc == 1) { + fprintf(stderr, "Usage: %s [plugin1] [plugin2] ...\n", argv[0]); + return 0; + } + + uv_lib_t *lib = (uv_lib_t*) malloc(sizeof(uv_lib_t)); + while (--argc) { + fprintf(stderr, "Loading %s\n", argv[argc]); + 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)); + continue; + } + + init_plugin(); + } + + return 0; +} diff --git a/docs/code/plugin/plugin.h b/docs/code/plugin/plugin.h new file mode 100644 index 000000000..21f194e67 --- /dev/null +++ b/docs/code/plugin/plugin.h @@ -0,0 +1,7 @@ +#ifndef UVBOOK_PLUGIN_SYSTEM +#define UVBOOK_PLUGIN_SYSTEM + +// Plugin authors should use this to register their plugins with mfp. +void mfp_register(const char *name); + +#endif diff --git a/docs/code/proc-streams/main.c b/docs/code/proc-streams/main.c new file mode 100644 index 000000000..b8a65212e --- /dev/null +++ b/docs/code/proc-streams/main.c @@ -0,0 +1,49 @@ +#include +#include +#include + +#include + +uv_loop_t *loop; +uv_process_t child_req; +uv_process_options_t options; + +void on_exit(uv_process_t *req, int64_t exit_status, int term_signal) { + fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); + uv_close((uv_handle_t*) req, NULL); +} + +int main() { + loop = uv_default_loop(); + + size_t size = 500; + char path[size]; + uv_exepath(path, &size); + strcpy(path + (strlen(path) - strlen("proc-streams")), "test"); + + char* args[2]; + args[0] = path; + args[1] = NULL; + + /* ... */ + + options.stdio_count = 3; + uv_stdio_container_t child_stdio[3]; + child_stdio[0].flags = UV_IGNORE; + child_stdio[1].flags = UV_IGNORE; + child_stdio[2].flags = UV_INHERIT_FD; + child_stdio[2].data.fd = 2; + options.stdio = child_stdio; + + options.exit_cb = on_exit; + options.file = args[0]; + options.args = args; + + int r; + if ((r = uv_spawn(loop, &child_req, &options))) { + fprintf(stderr, "%s\n", uv_strerror(r)); + return 1; + } + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/proc-streams/test.c b/docs/code/proc-streams/test.c new file mode 100644 index 000000000..7c45c1fdc --- /dev/null +++ b/docs/code/proc-streams/test.c @@ -0,0 +1,8 @@ +#include + +int main() +{ + fprintf(stderr, "This is stderr\n"); + printf("This is stdout\n"); + return 0; +} diff --git a/docs/code/progress/main.c b/docs/code/progress/main.c new file mode 100644 index 000000000..5af01f143 --- /dev/null +++ b/docs/code/progress/main.c @@ -0,0 +1,47 @@ +#include +#include +#include + +#include + +uv_loop_t *loop; +uv_async_t async; + +double percentage; + +void fake_download(uv_work_t *req) { + int size = *((int*) req->data); + int downloaded = 0; + while (downloaded < size) { + percentage = downloaded*100.0/size; + async.data = (void*) &percentage; + uv_async_send(&async); + + sleep(1); + downloaded += (200+random())%1000; // can only download max 1000bytes/sec, + // but at least a 200; + } +} + +void after(uv_work_t *req, int status) { + fprintf(stderr, "Download complete\n"); + uv_close((uv_handle_t*) &async, NULL); +} + +void print_progress(uv_async_t *handle) { + double percentage = *((double*) handle->data); + fprintf(stderr, "Downloaded %.2f%%\n", percentage); +} + +int main() { + loop = uv_default_loop(); + + uv_work_t req; + int size = 10240; + req.data = (void*) &size; + + uv_async_init(loop, &async, print_progress); + uv_queue_work(loop, &req, fake_download, after); + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/queue-cancel/main.c b/docs/code/queue-cancel/main.c new file mode 100644 index 000000000..3f7836cbf --- /dev/null +++ b/docs/code/queue-cancel/main.c @@ -0,0 +1,59 @@ +#include +#include +#include + +#include + +#define FIB_UNTIL 25 +uv_loop_t *loop; +uv_work_t fib_reqs[FIB_UNTIL]; + +long fib_(long t) { + if (t == 0 || t == 1) + return 1; + else + return fib_(t-1) + fib_(t-2); +} + +void fib(uv_work_t *req) { + int n = *(int *) req->data; + if (random() % 2) + sleep(1); + else + sleep(3); + long fib = fib_(n); + fprintf(stderr, "%dth fibonacci is %lu\n", n, fib); +} + +void after_fib(uv_work_t *req, int status) { + if (status == UV_ECANCELED) + fprintf(stderr, "Calculation of %d cancelled.\n", *(int *) req->data); +} + +void signal_handler(uv_signal_t *req, int signum) +{ + printf("Signal received!\n"); + int i; + for (i = 0; i < FIB_UNTIL; i++) { + uv_cancel((uv_req_t*) &fib_reqs[i]); + } + uv_signal_stop(req); +} + +int main() { + loop = uv_default_loop(); + + int data[FIB_UNTIL]; + int i; + for (i = 0; i < FIB_UNTIL; i++) { + data[i] = i; + fib_reqs[i].data = (void *) &data[i]; + uv_queue_work(loop, &fib_reqs[i], fib, after_fib); + } + + uv_signal_t sig; + uv_signal_init(loop, &sig); + uv_signal_start(&sig, signal_handler, SIGINT); + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/queue-work/main.c b/docs/code/queue-work/main.c new file mode 100644 index 000000000..55675ea02 --- /dev/null +++ b/docs/code/queue-work/main.c @@ -0,0 +1,44 @@ +#include +#include +#include + +#include + +#define FIB_UNTIL 25 +uv_loop_t *loop; + +long fib_(long t) { + if (t == 0 || t == 1) + return 1; + else + return fib_(t-1) + fib_(t-2); +} + +void fib(uv_work_t *req) { + int n = *(int *) req->data; + if (random() % 2) + sleep(1); + else + sleep(3); + long fib = fib_(n); + fprintf(stderr, "%dth fibonacci is %lu\n", n, fib); +} + +void after_fib(uv_work_t *req, int status) { + fprintf(stderr, "Done calculating %dth fibonacci\n", *(int *) req->data); +} + +int main() { + loop = uv_default_loop(); + + int data[FIB_UNTIL]; + uv_work_t req[FIB_UNTIL]; + int i; + for (i = 0; i < FIB_UNTIL; i++) { + data[i] = i; + req[i].data = (void *) &data[i]; + uv_queue_work(loop, &req[i], fib, after_fib); + } + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/ref-timer/main.c b/docs/code/ref-timer/main.c new file mode 100644 index 000000000..ad7c8295f --- /dev/null +++ b/docs/code/ref-timer/main.c @@ -0,0 +1,29 @@ +#include + +#include + +uv_loop_t *loop; +uv_timer_t gc_req; +uv_timer_t fake_job_req; + +void gc(uv_timer_t *handle) { + fprintf(stderr, "Freeing unused objects\n"); +} + +void fake_job(uv_timer_t *handle) { + fprintf(stdout, "Fake job done\n"); +} + +int main() { + loop = uv_default_loop(); + + uv_timer_init(loop, &gc_req); + uv_unref((uv_handle_t*) &gc_req); + + uv_timer_start(&gc_req, gc, 0, 2000); + + // could actually be a TCP download or something + uv_timer_init(loop, &fake_job_req); + uv_timer_start(&fake_job_req, fake_job, 9000, 0); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/signal/main.c b/docs/code/signal/main.c new file mode 100644 index 000000000..1b982c5a7 --- /dev/null +++ b/docs/code/signal/main.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +uv_loop_t* create_loop() +{ + uv_loop_t *loop = malloc(sizeof(uv_loop_t)); + if (loop) { + uv_loop_init(loop); + } + return loop; +} + +void signal_handler(uv_signal_t *handle, int signum) +{ + printf("Signal received: %d\n", signum); + uv_signal_stop(handle); +} + +// two signal handlers in one loop +void thread1_worker(void *userp) +{ + uv_loop_t *loop1 = create_loop(); + + uv_signal_t sig1a, sig1b; + uv_signal_init(loop1, &sig1a); + uv_signal_start(&sig1a, signal_handler, SIGUSR1); + + uv_signal_init(loop1, &sig1b); + uv_signal_start(&sig1b, signal_handler, SIGUSR1); + + uv_run(loop1, UV_RUN_DEFAULT); +} + +// two signal handlers, each in its own loop +void thread2_worker(void *userp) +{ + uv_loop_t *loop2 = create_loop(); + uv_loop_t *loop3 = create_loop(); + + uv_signal_t sig2; + uv_signal_init(loop2, &sig2); + uv_signal_start(&sig2, signal_handler, SIGUSR1); + + uv_signal_t sig3; + uv_signal_init(loop3, &sig3); + uv_signal_start(&sig3, signal_handler, SIGUSR1); + + while (uv_run(loop2, UV_RUN_NOWAIT) || uv_run(loop3, UV_RUN_NOWAIT)) { + } +} + +int main() +{ + printf("PID %d\n", getpid()); + + uv_thread_t thread1, thread2; + + uv_thread_create(&thread1, thread1_worker, 0); + uv_thread_create(&thread2, thread2_worker, 0); + + uv_thread_join(&thread1); + uv_thread_join(&thread2); + return 0; +} diff --git a/docs/code/spawn/main.c b/docs/code/spawn/main.c new file mode 100644 index 000000000..dedfe00c0 --- /dev/null +++ b/docs/code/spawn/main.c @@ -0,0 +1,36 @@ +#include +#include + +#include + +uv_loop_t *loop; +uv_process_t child_req; +uv_process_options_t options; + +void on_exit(uv_process_t *req, int64_t exit_status, int term_signal) { + fprintf(stderr, "Process exited with status %" PRId64 ", signal %d\n", exit_status, term_signal); + uv_close((uv_handle_t*) req, NULL); +} + +int main() { + loop = uv_default_loop(); + + char* args[3]; + args[0] = "mkdir"; + args[1] = "test-dir"; + args[2] = NULL; + + options.exit_cb = on_exit; + options.file = "mkdir"; + options.args = args; + + int r; + if ((r = uv_spawn(loop, &child_req, &options))) { + fprintf(stderr, "%s\n", uv_strerror(r)); + return 1; + } else { + fprintf(stderr, "Launched process with ID %d\n", child_req.pid); + } + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/tcp-echo-server/main.c b/docs/code/tcp-echo-server/main.c new file mode 100644 index 000000000..63965bd9a --- /dev/null +++ b/docs/code/tcp-echo-server/main.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +#define DEFAULT_PORT 7000 +#define DEFAULT_BACKLOG 128 + +uv_loop_t *loop; +struct sockaddr_in addr; + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = (char*) malloc(suggested_size); + buf->len = suggested_size; +} + +void echo_write(uv_write_t *req, int status) { + if (status) { + fprintf(stderr, "Write error %s\n", uv_strerror(status)); + } + free_write_req(req); +} + +void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread > 0) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init(buf->base, nread); + uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); + return; + } + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, NULL); + } + + free(buf->base); +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status < 0) { + fprintf(stderr, "New connection error %s\n", uv_strerror(status)); + // error! + return; + } + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); + } + else { + uv_close((uv_handle_t*) client, NULL); + } +} + +int main() { + loop = uv_default_loop(); + + uv_tcp_t server; + uv_tcp_init(loop, &server); + + uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &addr); + + uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0); + int r = uv_listen((uv_stream_t*) &server, DEFAULT_BACKLOG, on_new_connection); + if (r) { + fprintf(stderr, "Listen error %s\n", uv_strerror(r)); + return 1; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/thread-create/main.c b/docs/code/thread-create/main.c new file mode 100644 index 000000000..70224c1e2 --- /dev/null +++ b/docs/code/thread-create/main.c @@ -0,0 +1,36 @@ +#include +#include + +#include + +void hare(void *arg) { + int tracklen = *((int *) arg); + while (tracklen) { + tracklen--; + sleep(1); + fprintf(stderr, "Hare ran another step\n"); + } + fprintf(stderr, "Hare done running!\n"); +} + +void tortoise(void *arg) { + int tracklen = *((int *) arg); + while (tracklen) { + tracklen--; + fprintf(stderr, "Tortoise ran another step\n"); + sleep(3); + } + fprintf(stderr, "Tortoise done running!\n"); +} + +int main() { + int tracklen = 10; + uv_thread_t hare_id; + uv_thread_t tortoise_id; + uv_thread_create(&hare_id, hare, &tracklen); + uv_thread_create(&tortoise_id, tortoise, &tracklen); + + uv_thread_join(&hare_id); + uv_thread_join(&tortoise_id); + return 0; +} diff --git a/docs/code/tty-gravity/main.c b/docs/code/tty-gravity/main.c new file mode 100644 index 000000000..053e7e597 --- /dev/null +++ b/docs/code/tty-gravity/main.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +uv_loop_t *loop; +uv_tty_t tty; +uv_timer_t tick; +uv_write_t write_req; +int width, height; +int pos = 0; +char *message = " Hello TTY "; + +void update(uv_timer_t *req) { + char data[500]; + + uv_buf_t buf; + buf.base = data; + buf.len = sprintf(data, "\033[2J\033[H\033[%dB\033[%luC\033[42;37m%s", + pos, + (unsigned long) (width-strlen(message))/2, + message); + uv_write(&write_req, (uv_stream_t*) &tty, &buf, 1, NULL); + + pos++; + if (pos > height) { + uv_tty_reset_mode(); + uv_timer_stop(&tick); + } +} + +int main() { + loop = uv_default_loop(); + + uv_tty_init(loop, &tty, 1, 0); + uv_tty_set_mode(&tty, 0); + + if (uv_tty_get_winsize(&tty, &width, &height)) { + fprintf(stderr, "Could not get TTY information\n"); + uv_tty_reset_mode(); + return 1; + } + + fprintf(stderr, "Width %d, height %d\n", width, height); + uv_timer_init(loop, &tick); + uv_timer_start(&tick, update, 200, 200); + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/tty/main.c b/docs/code/tty/main.c new file mode 100644 index 000000000..03b26fbc1 --- /dev/null +++ b/docs/code/tty/main.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include + +uv_loop_t *loop; +uv_tty_t tty; +int main() { + loop = uv_default_loop(); + + uv_tty_init(loop, &tty, 1, 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); + } + + 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); +} diff --git a/docs/code/udp-dhcp/main.c b/docs/code/udp-dhcp/main.c new file mode 100644 index 000000000..fc2ca0c8a --- /dev/null +++ b/docs/code/udp-dhcp/main.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include + +#include + +uv_loop_t *loop; +uv_udp_t send_socket; +uv_udp_t recv_socket; + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +void on_read(uv_udp_t *req, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags) { + if (nread < 0) { + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) req, NULL); + free(buf->base); + return; + } + + char sender[17] = { 0 }; + uv_ip4_name((const struct sockaddr_in*) addr, sender, 16); + fprintf(stderr, "Recv from %s\n", sender); + + // ... DHCP specific code + unsigned int *as_integer = (unsigned int*)buf->base; + unsigned int ipbin = ntohl(as_integer[4]); + unsigned char ip[4] = {0}; + int i; + for (i = 0; i < 4; i++) + ip[i] = (ipbin >> i*8) & 0xff; + fprintf(stderr, "Offered IP %d.%d.%d.%d\n", ip[3], ip[2], ip[1], ip[0]); + + free(buf->base); + uv_udp_recv_stop(req); +} + +uv_buf_t make_discover_msg() { + uv_buf_t buffer; + alloc_buffer(NULL, 256, &buffer); + memset(buffer.base, 0, buffer.len); + + // BOOTREQUEST + buffer.base[0] = 0x1; + // HTYPE ethernet + buffer.base[1] = 0x1; + // HLEN + buffer.base[2] = 0x6; + // HOPS + buffer.base[3] = 0x0; + // XID 4 bytes + buffer.base[4] = (unsigned int) random(); + // SECS + buffer.base[8] = 0x0; + // FLAGS + buffer.base[10] = 0x80; + // CIADDR 12-15 is all zeros + // YIADDR 16-19 is all zeros + // SIADDR 20-23 is all zeros + // GIADDR 24-27 is all zeros + // CHADDR 28-43 is the MAC address, use your own + buffer.base[28] = 0xe4; + buffer.base[29] = 0xce; + buffer.base[30] = 0x8f; + buffer.base[31] = 0x13; + buffer.base[32] = 0xf6; + buffer.base[33] = 0xd4; + // SNAME 64 bytes zero + // FILE 128 bytes zero + // OPTIONS + // - magic cookie + buffer.base[236] = 99; + buffer.base[237] = 130; + buffer.base[238] = 83; + buffer.base[239] = 99; + + // DHCP Message type + buffer.base[240] = 53; + buffer.base[241] = 1; + buffer.base[242] = 1; // DHCPDISCOVER + + // DHCP Parameter request list + buffer.base[243] = 55; + buffer.base[244] = 4; + buffer.base[245] = 1; + buffer.base[246] = 3; + buffer.base[247] = 15; + buffer.base[248] = 6; + + return buffer; +} + +void on_send(uv_udp_send_t *req, int status) { + if (status) { + fprintf(stderr, "Send error %s\n", uv_strerror(status)); + return; + } +} + +int main() { + loop = uv_default_loop(); + + uv_udp_init(loop, &recv_socket); + struct sockaddr_in recv_addr; + uv_ip4_addr("0.0.0.0", 68, &recv_addr); + uv_udp_bind(&recv_socket, (const struct sockaddr *)&recv_addr, UV_UDP_REUSEADDR); + uv_udp_recv_start(&recv_socket, alloc_buffer, on_read); + + uv_udp_init(loop, &send_socket); + struct sockaddr_in broadcast_addr; + uv_ip4_addr("0.0.0.0", 0, &broadcast_addr); + uv_udp_bind(&send_socket, (const struct sockaddr *)&broadcast_addr, 0); + uv_udp_set_broadcast(&send_socket, 1); + + uv_udp_send_t send_req; + uv_buf_t discover_msg = make_discover_msg(); + + struct sockaddr_in send_addr; + uv_ip4_addr("255.255.255.255", 67, &send_addr); + uv_udp_send(&send_req, &send_socket, &discover_msg, 1, (const struct sockaddr *)&send_addr, on_send); + + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/docs/code/uvcat/main.c b/docs/code/uvcat/main.c new file mode 100644 index 000000000..b03b09449 --- /dev/null +++ b/docs/code/uvcat/main.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include + +void on_read(uv_fs_t *req); + +uv_fs_t open_req; +uv_fs_t read_req; +uv_fs_t write_req; + +static char buffer[1024]; + +static uv_buf_t iov; + +void on_write(uv_fs_t *req) { + if (req->result < 0) { + fprintf(stderr, "Write error: %s\n", uv_strerror((int)req->result)); + } + else { + uv_fs_read(uv_default_loop(), &read_req, open_req.result, &iov, 1, -1, on_read); + } +} + +void on_read(uv_fs_t *req) { + if (req->result < 0) { + fprintf(stderr, "Read error: %s\n", uv_strerror(req->result)); + } + else if (req->result == 0) { + uv_fs_t close_req; + // synchronous + uv_fs_close(uv_default_loop(), &close_req, open_req.result, NULL); + } + else if (req->result > 0) { + iov.len = req->result; + uv_fs_write(uv_default_loop(), &write_req, 1, &iov, 1, -1, on_write); + } +} + +void on_open(uv_fs_t *req) { + // The request passed to the callback is the same as the one the call setup + // function was passed. + assert(req == &open_req); + if (req->result >= 0) { + iov = uv_buf_init(buffer, sizeof(buffer)); + uv_fs_read(uv_default_loop(), &read_req, req->result, + &iov, 1, -1, on_read); + } + else { + fprintf(stderr, "error opening file: %s\n", uv_strerror((int)req->result)); + } +} + +int main(int argc, char **argv) { + uv_fs_open(uv_default_loop(), &open_req, argv[1], O_RDONLY, 0, on_open); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + uv_fs_req_cleanup(&open_req); + uv_fs_req_cleanup(&read_req); + uv_fs_req_cleanup(&write_req); + return 0; +} diff --git a/docs/code/uvstop/main.c b/docs/code/uvstop/main.c new file mode 100644 index 000000000..7aa53b761 --- /dev/null +++ b/docs/code/uvstop/main.c @@ -0,0 +1,33 @@ +#include +#include + +int64_t counter = 0; + +void idle_cb(uv_idle_t *handle) { + printf("Idle callback\n"); + counter++; + + if (counter >= 5) { + uv_stop(uv_default_loop()); + printf("uv_stop() called\n"); + } +} + +void prep_cb(uv_prepare_t *handle) { + printf("Prep callback\n"); +} + +int main() { + uv_idle_t idler; + uv_prepare_t prep; + + uv_idle_init(uv_default_loop(), &idler); + uv_idle_start(&idler, idle_cb); + + uv_prepare_init(uv_default_loop(), &prep); + uv_prepare_start(&prep, prep_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + return 0; +} diff --git a/docs/code/uvtee/main.c b/docs/code/uvtee/main.c new file mode 100644 index 000000000..6216c2eb4 --- /dev/null +++ b/docs/code/uvtee/main.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include + +#include + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +uv_loop_t *loop; +uv_pipe_t stdin_pipe; +uv_pipe_t stdout_pipe; +uv_pipe_t file_pipe; + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + *buf = uv_buf_init((char*) malloc(suggested_size), suggested_size); +} + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void on_stdout_write(uv_write_t *req, int status) { + free_write_req(req); +} + +void on_file_write(uv_write_t *req, int status) { + free_write_req(req); +} + +void write_data(uv_stream_t *dest, size_t size, uv_buf_t buf, uv_write_cb cb) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init((char*) malloc(size), size); + memcpy(req->buf.base, buf.base, size); + uv_write((uv_write_t*) req, (uv_stream_t*)dest, &req->buf, 1, cb); +} + +void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { + if (nread < 0){ + if (nread == UV_EOF){ + // end of file + uv_close((uv_handle_t *)&stdin_pipe, NULL); + uv_close((uv_handle_t *)&stdout_pipe, NULL); + uv_close((uv_handle_t *)&file_pipe, NULL); + } + } else if (nread > 0) { + write_data((uv_stream_t *)&stdout_pipe, nread, *buf, on_stdout_write); + write_data((uv_stream_t *)&file_pipe, nread, *buf, on_file_write); + } + + // OK to free buffer as write_data copies it. + if (buf->base) + free(buf->base); +} + +int main(int argc, char **argv) { + loop = uv_default_loop(); + + uv_pipe_init(loop, &stdin_pipe, 0); + uv_pipe_open(&stdin_pipe, 0); + + uv_pipe_init(loop, &stdout_pipe, 0); + uv_pipe_open(&stdout_pipe, 1); + + uv_fs_t file_req; + int fd = uv_fs_open(loop, &file_req, argv[1], O_CREAT | O_RDWR, 0644, NULL); + uv_pipe_init(loop, &file_pipe, 0); + uv_pipe_open(&file_pipe, fd); + + uv_read_start((uv_stream_t*)&stdin_pipe, alloc_buffer, read_stdin); + + uv_run(loop, UV_RUN_DEFAULT); + return 0; +} diff --git a/docs/code/uvwget/main.c b/docs/code/uvwget/main.c new file mode 100644 index 000000000..40186241b --- /dev/null +++ b/docs/code/uvwget/main.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include + +uv_loop_t *loop; +CURLM *curl_handle; +uv_timer_t timeout; + +typedef struct curl_context_s { + uv_poll_t poll_handle; + curl_socket_t sockfd; +} curl_context_t; + +curl_context_t *create_curl_context(curl_socket_t sockfd) { + curl_context_t *context; + + context = (curl_context_t*) malloc(sizeof *context); + + context->sockfd = sockfd; + + int r = uv_poll_init_socket(loop, &context->poll_handle, sockfd); + assert(r == 0); + context->poll_handle.data = context; + + return context; +} + +void curl_close_cb(uv_handle_t *handle) { + curl_context_t *context = (curl_context_t*) handle->data; + free(context); +} + +void destroy_curl_context(curl_context_t *context) { + uv_close((uv_handle_t*) &context->poll_handle, curl_close_cb); +} + + +void add_download(const char *url, int num) { + char filename[50]; + sprintf(filename, "%d.download", num); + FILE *file; + + file = fopen(filename, "w"); + if (file == NULL) { + fprintf(stderr, "Error opening %s\n", filename); + return; + } + + CURL *handle = curl_easy_init(); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, file); + curl_easy_setopt(handle, CURLOPT_URL, url); + curl_multi_add_handle(curl_handle, handle); + fprintf(stderr, "Added download %s -> %s\n", url, filename); +} + +void check_multi_info(void) { + char *done_url; + CURLMsg *message; + int pending; + + while ((message = curl_multi_info_read(curl_handle, &pending))) { + switch (message->msg) { + case CURLMSG_DONE: + curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL, + &done_url); + printf("%s DONE\n", done_url); + + curl_multi_remove_handle(curl_handle, message->easy_handle); + curl_easy_cleanup(message->easy_handle); + break; + + default: + fprintf(stderr, "CURLMSG default\n"); + abort(); + } + } +} + +void curl_perform(uv_poll_t *req, int status, int events) { + uv_timer_stop(&timeout); + int running_handles; + int flags = 0; + if (status < 0) flags = CURL_CSELECT_ERR; + if (!status && events & UV_READABLE) flags |= CURL_CSELECT_IN; + if (!status && events & UV_WRITABLE) flags |= CURL_CSELECT_OUT; + + curl_context_t *context; + + context = (curl_context_t*)req; + + curl_multi_socket_action(curl_handle, context->sockfd, flags, &running_handles); + check_multi_info(); +} + +void on_timeout(uv_timer_t *req) { + int running_handles; + curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0, &running_handles); + check_multi_info(); +} + +void start_timeout(CURLM *multi, long timeout_ms, void *userp) { + if (timeout_ms <= 0) + timeout_ms = 1; /* 0 means directly call socket_action, but we'll do it in a bit */ + uv_timer_start(&timeout, on_timeout, timeout_ms, 0); +} + +int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp, void *socketp) { + curl_context_t *curl_context; + if (action == CURL_POLL_IN || action == CURL_POLL_OUT) { + if (socketp) { + curl_context = (curl_context_t*) socketp; + } + else { + curl_context = create_curl_context(s); + curl_multi_assign(curl_handle, s, (void *) curl_context); + } + } + + switch (action) { + case CURL_POLL_IN: + uv_poll_start(&curl_context->poll_handle, UV_READABLE, curl_perform); + break; + case CURL_POLL_OUT: + uv_poll_start(&curl_context->poll_handle, UV_WRITABLE, curl_perform); + break; + case CURL_POLL_REMOVE: + if (socketp) { + uv_poll_stop(&((curl_context_t*)socketp)->poll_handle); + destroy_curl_context((curl_context_t*) socketp); + curl_multi_assign(curl_handle, s, NULL); + } + break; + default: + abort(); + } + + return 0; +} + +int main(int argc, char **argv) { + loop = uv_default_loop(); + + if (argc <= 1) + return 0; + + if (curl_global_init(CURL_GLOBAL_ALL)) { + fprintf(stderr, "Could not init cURL\n"); + return 1; + } + + uv_timer_init(loop, &timeout); + + curl_handle = curl_multi_init(); + curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket); + curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout); + + while (argc-- > 1) { + add_download(argv[argc], argc); + } + + uv_run(loop, UV_RUN_DEFAULT); + curl_multi_cleanup(curl_handle); + return 0; +} From 4e6101388015c6d0879308d566f0a4b79edc0c13 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 27 Apr 2017 05:01:49 +0200 Subject: [PATCH 371/632] doc: update supported linux/glibc baseline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that RHEL/CentOS 5 is end-of-life, update the baseline from linux >= 2.6.18 + glibc >= 2.5 to linux >= 2.6.32 + glibc >= 2.12. PR-URL: https://github.com/libuv/libuv/pull/1324 Refs: https://github.com/nodejs/node/pull/12672 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- SUPPORTED_PLATFORMS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index bff1050d6..3a000c5dd 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -2,7 +2,7 @@ | System | Support type | Supported versions | Notes | |---|---|---|---| -| GNU/Linux | Tier 1 | Linux >= 2.6.18 with glibc >= 2.5 | | +| GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | | | macOS | Tier 1 | macOS >= 10.7 | | | Windows | Tier 1 | Windows >= XP SP1 | MSVC 2008 and later are supported | | FreeBSD | Tier 1 | >= 9 (see note) | | From 735064493969444cce2375c2ac1e741ca07057d8 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 26 Apr 2017 12:53:32 -0400 Subject: [PATCH 372/632] win: avoid leaking pipe handles to child processes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs: https://github.com/joyent/libuv/issues/1313 PR-URL: https://github.com/libuv/libuv/pull/1321 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno --- src/win/pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index d64fadf63..edf300212 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -960,7 +960,7 @@ static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) { uv_mutex_lock(m); /* mutex controls *setting* of readfile_thread */ if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hThread, - 0, TRUE, DUPLICATE_SAME_ACCESS)) { + 0, FALSE, DUPLICATE_SAME_ACCESS)) { handle->pipe.conn.readfile_thread = hThread; } else { hThread = NULL; From bcf6202921731c5f0e0bd57018a8d7ea03ee0875 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Thu, 27 Apr 2017 12:28:12 +0200 Subject: [PATCH 373/632] win,test: support stdout output larger than 1kb Fix a bug in process_copy_output that would cause output larger than 1kb to be incorrectly split into lines. PR-URL: https://github.com/libuv/libuv/pull/1325 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- test/runner-win.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/test/runner-win.c b/test/runner-win.c index 1b4a569ae..0f1b56e77 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -209,22 +209,30 @@ long int process_output_size(process_info_t *p) { int process_copy_output(process_info_t* p, FILE* stream) { - DWORD read; char buf[1024]; + int fd, r; + FILE* f; - if (SetFilePointer(p->stdio_out, - 0, - 0, - FILE_BEGIN) == INVALID_SET_FILE_POINTER) { + fd = _open_osfhandle((intptr_t)p->stdio_out, _O_RDONLY | _O_TEXT); + if (fd == -1) + return -1; + f = _fdopen(fd, "rt"); + if (f == NULL) { + _close(fd); return -1; } - while (ReadFile(p->stdio_out, &buf, sizeof(buf), &read, NULL) && read > 0) - print_lines(buf, read, stream); + r = fseek(f, 0, SEEK_SET); + if (r < 0) + return -1; - if (GetLastError() != ERROR_HANDLE_EOF) + while (fgets(buf, sizeof(buf), f) != NULL) + print_lines(buf, strlen(buf), stream); + + if (ferror(f)) return -1; + fclose(f); return 0; } From 196eb8b94f7c5543e9057cac7a417fa5c0c5b8af Mon Sep 17 00:00:00 2001 From: Keane Date: Fri, 14 Apr 2017 14:42:44 -0700 Subject: [PATCH 374/632] win: remove __declspec(inline) from atomic op __declspec(inline) is completely undocumented, as well as unnecessary. The INLINE preprocessor macro is used throughout libuv, so this simply replaces the only instance of declspec(inline) with the macro version. PR-URL: https://github.com/libuv/libuv/pull/1307 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/win/atomicops-inl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/win/atomicops-inl.h b/src/win/atomicops-inl.h index 61e006026..6d8126f69 100644 --- a/src/win/atomicops-inl.h +++ b/src/win/atomicops-inl.h @@ -23,6 +23,7 @@ #define UV_WIN_ATOMICOPS_INL_H_ #include "uv.h" +#include "internal.h" /* Atomic set operation on char */ @@ -34,7 +35,7 @@ /* target to be aligned. */ #pragma intrinsic(_InterlockedOr8) -static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) { +static char INLINE uv__atomic_exchange_set(char volatile* target) { return _InterlockedOr8(target, 1); } From 51f3f56f346900f2618bb15f83a437c182da1cb7 Mon Sep 17 00:00:00 2001 From: Rasmus Christian Pedersen Date: Wed, 5 Apr 2017 13:50:46 +0200 Subject: [PATCH 375/632] test: fix VC++ compilation warning This commit fixes the following warning: warning C4047: char *' differs in levels of indirection from 'char (*)[1]' PR-URL: https://github.com/libuv/libuv/pull/1290 Reviewed-By: Colin Ihrig --- test/test-tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-tty.c b/test/test-tty.c index 6fc2c95c9..e761822fa 100644 --- a/test/test-tty.c +++ b/test/test-tty.c @@ -244,7 +244,7 @@ TEST_IMPL(tty_empty_write) { ASSERT(r == 0); bufs[0].len = 0; - bufs[0].base = &dummy; + bufs[0].base = &dummy[0]; r = uv_try_write((uv_stream_t*) &tty_out, bufs, 1); ASSERT(r == 0); From fd39cec4b848b27be6bf3f8a3e0bce29474366bb Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 27 Apr 2017 10:23:46 -0400 Subject: [PATCH 376/632] build: add -Wstrict-prototypes Fixes: https://github.com/libuv/libuv/pull/1320 PR-URL: https://github.com/libuv/libuv/pull/1326 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- Makefile.mingw | 1 + common.gypi | 1 + configure.ac | 1 + src/unix/async.c | 2 +- src/win/core.c | 4 ++-- src/win/detect-wakeup.c | 6 +++--- src/win/fs.c | 2 +- src/win/internal.h | 22 +++++++++++----------- src/win/poll.c | 4 ++-- src/win/signal.c | 2 +- src/win/tty.c | 2 +- src/win/util.c | 8 ++++---- src/win/winapi.c | 2 +- src/win/winsock.c | 2 +- uv.gyp | 3 ++- 15 files changed, 33 insertions(+), 29 deletions(-) diff --git a/Makefile.mingw b/Makefile.mingw index 8139138fc..3acf9e14a 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -17,6 +17,7 @@ CC ?= gcc CFLAGS += -Wall \ -Wextra \ -Wno-unused-parameter \ + -Wstrict-prototypes \ -Iinclude \ -Isrc \ -Isrc/win \ diff --git a/common.gypi b/common.gypi index 470b73385..94e760030 100644 --- a/common.gypi +++ b/common.gypi @@ -180,6 +180,7 @@ '-Wendif-labels', '-W', '-Wno-unused-parameter', + '-Wstrict-prototypes', ], }, 'conditions': [ diff --git a/configure.ac b/configure.ac index 360652198..6ec3125c2 100644 --- a/configure.ac +++ b/configure.ac @@ -33,6 +33,7 @@ CC_CHECK_CFLAGS_APPEND([-std=gnu89]) CC_CHECK_CFLAGS_APPEND([-Wall]) CC_CHECK_CFLAGS_APPEND([-Wextra]) CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter]) +CC_CHECK_CFLAGS_APPEND([-Wstrict-prototypes]) # AM_PROG_AR is not available in automake v0.11 but it's essential in v0.12. m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) # autoconf complains if AC_PROG_LIBTOOL precedes AM_PROG_AR. diff --git a/src/unix/async.c b/src/unix/async.c index 2cb00579c..45c088ea1 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -226,7 +226,7 @@ void uv__async_stop(uv_loop_t* loop) { } -static int uv__async_eventfd() { +static int uv__async_eventfd(void) { #if defined(__linux__) static int no_eventfd2; static int no_eventfd; diff --git a/src/win/core.c b/src/win/core.c index cc8418720..9ed4e824c 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -83,7 +83,7 @@ static int uv__loops_capacity; #define UV__LOOPS_CHUNK_SIZE 8 static uv_mutex_t uv__loops_lock; -static void uv__loops_init() { +static void uv__loops_init(void) { uv_mutex_init(&uv__loops_lock); } @@ -158,7 +158,7 @@ static void uv__loops_remove(uv_loop_t* loop) { uv_mutex_unlock(&uv__loops_lock); } -void uv__wake_all_loops() { +void uv__wake_all_loops(void) { int i; uv_loop_t* loop; diff --git a/src/win/detect-wakeup.c b/src/win/detect-wakeup.c index a12179f79..72dfb7a17 100644 --- a/src/win/detect-wakeup.c +++ b/src/win/detect-wakeup.c @@ -2,9 +2,9 @@ #include "internal.h" #include "winapi.h" -static void uv__register_system_resume_callback(); +static void uv__register_system_resume_callback(void); -void uv__init_detect_system_wakeup() { +void uv__init_detect_system_wakeup(void) { /* Try registering system power event callback. This is the cleanest * method, but it will only work on Win8 and above. */ @@ -20,7 +20,7 @@ static ULONG CALLBACK uv__system_resume_callback(PVOID Context, return 0; } -static void uv__register_system_resume_callback() { +static void uv__register_system_resume_callback(void) { _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient; _HPOWERNOTIFY registration_handle; diff --git a/src/win/fs.c b/src/win/fs.c index de95ec547..2d72cdc70 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -114,7 +114,7 @@ const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\"; const WCHAR UNC_PATH_PREFIX_LEN = 8; -void uv_fs_init() { +void uv_fs_init(void) { _fmode = _O_BINARY; } diff --git a/src/win/internal.h b/src/win/internal.h index 23764da34..444327d64 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -206,7 +206,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); /* * TTY */ -void uv_console_init(); +void uv_console_init(void); int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb); @@ -259,7 +259,7 @@ 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 uv__once_init(void); /* @@ -275,7 +275,7 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, /* * Signal watcher */ -void uv_signals_init(); +void uv_signals_init(void); int uv__signal_dispatch(int signum); void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle); @@ -302,7 +302,7 @@ int uv_translate_sys_error(int sys_errno); /* * FS */ -void uv_fs_init(); +void uv_fs_init(void); /* @@ -323,11 +323,11 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle); /* * Utilities. */ -void uv__util_init(); +void uv__util_init(void); uint64_t uv__hrtime(double scale); -int uv_parent_pid(); -int uv_current_pid(); +int uv_parent_pid(void); +int uv_current_pid(void); __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); @@ -350,13 +350,13 @@ HANDLE uv__stdio_handle(BYTE* buffer, int fd); /* * Winapi and ntapi utility functions */ -void uv_winapi_init(); +void uv_winapi_init(void); /* * Winsock utility functions */ -void uv_winsock_init(); +void uv_winsock_init(void); int uv_ntstatus_to_winsock_error(NTSTATUS status); @@ -385,11 +385,11 @@ extern struct sockaddr_in6 uv_addr_ip6_any_; /* * Wake all loops with fake message */ -void uv__wake_all_loops(); +void uv__wake_all_loops(void); /* * Init system wake-up detection */ -void uv__init_detect_system_wakeup(); +void uv__init_detect_system_wakeup(void); #endif /* UV_WIN_INTERNAL_H_ */ diff --git a/src/win/poll.c b/src/win/poll.c index 0ade79a8b..a648ba711 100644 --- a/src/win/poll.c +++ b/src/win/poll.c @@ -61,13 +61,13 @@ static void uv__init_overlapped_dummy(void) { } -static OVERLAPPED* uv__get_overlapped_dummy() { +static OVERLAPPED* uv__get_overlapped_dummy(void) { uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy); return &overlapped_dummy_; } -static AFD_POLL_INFO* uv__get_afd_poll_info_dummy() { +static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) { return &afd_poll_info_dummy_; } diff --git a/src/win/signal.c b/src/win/signal.c index 023fbf281..7b42dd992 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 uv_signals_init(void) { InitializeCriticalSection(&uv__signal_lock); if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) abort(); diff --git a/src/win/tty.c b/src/win/tty.c index cdd2ba066..a6f583956 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -138,7 +138,7 @@ typedef enum { static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED; static void uv__determine_vterm_state(HANDLE handle); -void uv_console_init() { +void uv_console_init(void) { if (uv_sem_init(&uv_tty_output_lock, 1)) abort(); } diff --git a/src/win/util.c b/src/win/util.c index a289457fa..1d64d4c8f 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -77,7 +77,7 @@ static double hrtime_interval_ = 0; /* * One-time initialization code for functionality defined in util.c. */ -void uv__util_init() { +void uv__util_init(void) { LARGE_INTEGER perf_frequency; /* Initialize process title access mutex. */ @@ -323,7 +323,7 @@ uint64_t uv_get_total_memory(void) { } -int uv_parent_pid() { +int uv_parent_pid(void) { int parent_pid = -1; HANDLE handle; PROCESSENTRY32 pe; @@ -346,7 +346,7 @@ int uv_parent_pid() { } -int uv_current_pid() { +int uv_current_pid(void) { if (current_pid == 0) { current_pid = GetCurrentProcessId(); } @@ -408,7 +408,7 @@ int uv_set_process_title(const char* title) { } -static int uv__get_process_title() { +static int uv__get_process_title(void) { WCHAR title_w[MAX_TITLE_LENGTH]; if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { diff --git a/src/win/winapi.c b/src/win/winapi.c index 1fa179b57..aa5d719fb 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -53,7 +53,7 @@ sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; -void uv_winapi_init() { +void uv_winapi_init(void) { HMODULE ntdll_module; HMODULE kernel32_module; HMODULE powrprof_module; diff --git a/src/win/winsock.c b/src/win/winsock.c index d2e667e9f..e86d76b13 100644 --- a/src/win/winsock.c +++ b/src/win/winsock.c @@ -80,7 +80,7 @@ static int error_means_no_support(DWORD error) { } -void uv_winsock_init() { +void uv_winsock_init(void) { WSADATA wsa_data; int errorno; SOCKET dummy; diff --git a/uv.gyp b/uv.gyp index 720002578..e14279928 100644 --- a/uv.gyp +++ b/uv.gyp @@ -36,7 +36,7 @@ ], 'xcode_settings': { 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden - 'WARNING_CFLAGS': [ '-Wall', '-Wextra', '-Wno-unused-parameter' ], + 'WARNING_CFLAGS': [ '-Wall', '-Wextra', '-Wno-unused-parameter', '-Wstrict-prototypes' ], 'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ], } }, @@ -210,6 +210,7 @@ '-Wall', '-Wextra', '-Wno-unused-parameter', + '-Wstrict-prototypes', ], }], [ 'OS in "mac ios"', { From cb0cc7346d1c2b5bdf2bd89e4006a50fb6f9c3dd Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 12 Apr 2017 08:17:11 -0400 Subject: [PATCH 377/632] zos: implement uv__io_fork, skip fs event tests Basic implementation of uv__io_fork on z/OS. As of now, since filesystem events are not supported, skip all of those tests on z/OS. PR-URL: https://github.com/libuv/libuv/pull/1303 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/unix/os390.c | 6 ++++++ test/test-fork.c | 11 +++++++++-- test/test-fs-event.c | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index be325a923..e9ba90c66 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -863,3 +863,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { void uv__set_process_title(const char* title) { /* do nothing */ } + +int uv__io_fork(uv_loop_t* loop) { + uv__platform_loop_delete(loop); + + return uv__platform_loop_init(loop); +} diff --git a/test/test-fork.c b/test/test-fork.c index 3a3c90fb6..c760de89e 100644 --- a/test/test-fork.c +++ b/test/test-fork.c @@ -506,12 +506,17 @@ static int _do_fork_fs_events_child(int file_or_dir) { TEST_IMPL(fork_fs_events_child) { +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#endif return _do_fork_fs_events_child(FS_TEST_FILE); } TEST_IMPL(fork_fs_events_child_dir) { -#if defined(__APPLE__) || defined (__linux__) +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#elif defined(__APPLE__) || defined (__linux__) return _do_fork_fs_events_child(FS_TEST_DIR); #else /* You can't spin up a cfrunloop thread on an apple platform @@ -524,7 +529,9 @@ TEST_IMPL(fork_fs_events_child_dir) { TEST_IMPL(fork_fs_events_file_parent_child) { -#if defined(__sun) || defined(_AIX) +#if defined(__MVS__) + RETURN_SKIP("Filesystem watching not supported on this platform."); +#elif defined(__sun) || defined(_AIX) /* It's not possible to implement this without additional * bookkeeping on SunOS. For AIX it is possible, but has to be * written. See https://github.com/libuv/libuv/pull/846#issuecomment-287170420 diff --git a/test/test-fs-event.c b/test/test-fs-event.c index c78b34669..cefa5b9f3 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -1029,7 +1029,7 @@ TEST_IMPL(fs_event_error_reporting) { #endif /* defined(__APPLE__) */ TEST_IMPL(fs_event_watch_invalid_path) { -#if defined(MVS) +#if defined(__MVS__) RETURN_SKIP("Filesystem watching not supported on this platform."); #endif From e11dcd4377185359874e67f4962995fdb7e83d19 Mon Sep 17 00:00:00 2001 From: Marc Schlaich Date: Mon, 8 May 2017 12:06:07 +0200 Subject: [PATCH 378/632] unix: do not close udp sockets on bind error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes Unix behave in the same way as Windows. Fixes: https://github.com/libuv/libuv/issues/1336 PR-URL: https://github.com/libuv/libuv/pull/1337 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno --- src/unix/udp.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index 73f2bc4e5..c556325de 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -307,7 +307,7 @@ int uv__udp_bind(uv_udp_t* handle, if (flags & UV_UDP_REUSEADDR) { err = uv__set_reuse(fd); if (err) - goto out; + return err; } if (flags & UV_UDP_IPV6ONLY) { @@ -315,11 +315,11 @@ int uv__udp_bind(uv_udp_t* handle, yes = 1; if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { err = -errno; - goto out; + return err; } #else err = -ENOTSUP; - goto out; + return err; #endif } @@ -329,20 +329,14 @@ int uv__udp_bind(uv_udp_t* handle, /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a * socket created with AF_INET to an AF_INET6 address or vice versa. */ err = -EINVAL; - goto out; + return err; } if (addr->sa_family == AF_INET6) handle->flags |= UV_HANDLE_IPV6; handle->flags |= UV_HANDLE_BOUND; - return 0; - -out: - uv__close(handle->io_watcher.fd); - handle->io_watcher.fd = -1; - return err; } From 1217832e6faa8f97605aa60bbdb6ab195f7daf89 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 15 May 2017 12:11:42 -0400 Subject: [PATCH 379/632] unix: remove FSEventStreamFlushSync() call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This call, in the context of file watching, appears to trigger assertion warnings on some macOS configurations. Refs: https://github.com/nodejs/node/issues/854 Fixes: https://github.com/libuv/libuv/issues/1334 PR-URL: https://github.com/libuv/libuv/pull/1349 Reviewed-By: Fedor Indutny Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fsevents.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c index d331a1317..643e233cf 100644 --- a/src/unix/fsevents.c +++ b/src/unix/fsevents.c @@ -378,9 +378,6 @@ static void uv__fsevents_destroy_stream(uv_loop_t* loop) { if (state->fsevent_stream == NULL) return; - /* Flush all accumulated events */ - pFSEventStreamFlushSync(state->fsevent_stream); - /* Stop emitting events */ pFSEventStreamStop(state->fsevent_stream); From 22fc92856d8a354b7f26ca7fe2d3597a2bd57865 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Fri, 12 May 2017 23:25:06 -0400 Subject: [PATCH 380/632] build,openbsd: remove kvm-related code Remove the kvm.h include since 38323c9fb replaced the use of kvm_open() with sysctl(), Conditionally check for kvm_open() on non-OpenBSD platforms so LIBS (and libuv.pc) does not unnecessarily contain "-lkvm". Fixes: https://github.com/libuv/libuv/issues/1340 PR-URL: https://github.com/libuv/libuv/pull/1344 Reviewed-By: Santiago Gimeno --- configure.ac | 4 +++- src/unix/openbsd.c | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 6ec3125c2..963b4f15c 100644 --- a/configure.ac +++ b/configure.ac @@ -43,7 +43,6 @@ LT_INIT # TODO(bnoordhuis) Check for -pthread vs. -pthreads AC_CHECK_LIB([dl], [dlopen]) AC_CHECK_LIB([kstat], [kstat_lookup]) -AC_CHECK_LIB([kvm], [kvm_open]) AC_CHECK_LIB([nsl], [gethostbyname]) AC_CHECK_LIB([perfstat], [perfstat_cpu]) AC_CHECK_LIB([pthread], [pthread_mutex_init]) @@ -65,6 +64,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], [openbsd*], [], [ + AC_CHECK_LIB([kvm], [kvm_open]) +]) AC_CHECK_HEADERS([sys/ahafs_evProds.h]) AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes) AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" != "x"]) diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index 7e4b253b4..56f0af15c 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include From 4d0054145d19ac654976ddf9476756c67481ff2a Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 9 May 2017 08:29:02 +0200 Subject: [PATCH 381/632] test: fix flaky tcp-write-queue-order Delay the timer start to be sure all handles are created when `timer_cb` is executed. In some cases this was not the case causing the following error: ``` not ok 51 - tcp_write_queue_order exit code 134 Output from process `tcp_write_queue_order`: lt-run-tests: src/unix/core.c:166: uv_close: Assertion `0' failed. ``` PR-URL: https://github.com/libuv/libuv/pull/1338 Reviewed-By: Colin Ihrig Reviewed-By: Andrius Bentkus --- test/test-tcp-write-queue-order.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test-tcp-write-queue-order.c b/test/test-tcp-write-queue-order.c index d50289c3c..5119be6d3 100644 --- a/test/test-tcp-write-queue-order.c +++ b/test/test-tcp-write-queue-order.c @@ -89,6 +89,9 @@ static void connection_cb(uv_stream_t* tcp, int status) { ASSERT(0 == uv_tcp_init(tcp->loop, &incoming)); ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming)); + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); + ASSERT(0 == uv_timer_start(&timer, timer_cb, 1, 0)); + connection_cb_called++; } @@ -120,9 +123,6 @@ TEST_IMPL(tcp_write_queue_order) { connect_cb)); ASSERT(0 == uv_send_buffer_size((uv_handle_t*) &client, &buffer_size)); - ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); - ASSERT(0 == uv_timer_start(&timer, timer_cb, 100, 0)); - ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT(connect_cb_called == 1); From d8cd08bd985b0d4f16f76c6c726b5b938b2ee9ee Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 12 May 2017 13:41:22 -0400 Subject: [PATCH 382/632] unix,win: add uv_os_gethostname() Fixes: https://github.com/libuv/libuv/issues/1315 PR-URL: https://github.com/libuv/libuv/pull/1342 Reviewed-By: Santiago Gimeno Reviewed-By: Sam Roberts --- Makefile.am | 1 + checksparse.sh | 1 + docs/src/misc.rst | 11 ++++++++ include/uv.h | 2 ++ src/unix/core.c | 37 ++++++++++++++++++++++++ src/win/util.c | 34 ++++++++++++++++++++++ test/test-gethostname.c | 62 +++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 3 ++ uv.gyp | 1 + 9 files changed, 152 insertions(+) create mode 100644 test/test-gethostname.c diff --git a/Makefile.am b/Makefile.am index 211cfe21b..e70c7cfc1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -178,6 +178,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-get-memory.c \ test/test-get-passwd.c \ test/test-getaddrinfo.c \ + test/test-gethostname.c \ test/test-getnameinfo.c \ test/test-getsockname.c \ test/test-handle-fileno.c \ diff --git a/checksparse.sh b/checksparse.sh index 372061d88..9782718a2 100755 --- a/checksparse.sh +++ b/checksparse.sh @@ -104,6 +104,7 @@ test/test-get-loadavg.c test/test-get-memory.c test/test-get-passwd.c test/test-getaddrinfo.c +test/test-gethostname.c test/test-getsockname.c test/test-homedir.c test/test-hrtime.c diff --git a/docs/src/misc.rst b/docs/src/misc.rst index a92b74f46..9d7c3617e 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -429,3 +429,14 @@ API This function is not thread safe. .. versionadded:: 1.12.0 + +.. c:function:: int uv_os_gethostname(char* buffer, size_t* size) + + Returns the hostname as a null-terminated string in `buffer`, and sets + `size` to the string length of the hostname. When calling this function, + `size` must be set to the amount of storage available in `buffer`, including + the null terminator. If the hostname exceeds the storage available in + `buffer`, `UV_ENOBUFS` is returned, and `size` is set to the amount of + storage required to hold the value. + + .. versionadded:: 1.12.0 diff --git a/include/uv.h b/include/uv.h index 14e09e449..40f5a4bd5 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1078,6 +1078,8 @@ UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size); UV_EXTERN int uv_os_setenv(const char* name, const char* value); UV_EXTERN int uv_os_unsetenv(const char* name); +UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size); + typedef enum { UV_FS_UNKNOWN = -1, diff --git a/src/unix/core.c b/src/unix/core.c index 96495b864..9754403c4 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -28,6 +28,7 @@ #include #include #include +#include /* MAXHOSTNAMELEN on Linux and the BSDs */ #include #include #include @@ -42,6 +43,7 @@ #include #ifdef __sun +# include /* MAXHOSTNAMELEN on Solaris */ # include # include # include @@ -80,6 +82,11 @@ #include #endif +/* Fallback for the maximum hostname length */ +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + static int uv__run_pending(uv_loop_t* loop); /* Verify that uv_buf_t is ABI-compatible with struct iovec. */ @@ -1285,3 +1292,33 @@ int uv_os_unsetenv(const char* name) { return 0; } + + +int uv_os_gethostname(char* buffer, size_t* size) { + /* + On some platforms, if the input buffer is not large enough, gethostname() + succeeds, but truncates the result. libuv can detect this and return ENOBUFS + instead by creating a large enough buffer and comparing the hostname length + to the size input. + */ + char buf[MAXHOSTNAMELEN + 1]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + if (gethostname(buf, sizeof(buf)) != 0) + return -errno; + + buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return -ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + return 0; +} diff --git a/src/win/util.c b/src/win/util.c index 1d64d4c8f..d2e7f772c 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -59,6 +59,14 @@ # define UNLEN 256 #endif +/* + Max hostname length. The Windows gethostname() documentation states that 256 + bytes will always be large enough to hold the null-terminated hostname. +*/ +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + /* Maximum environment variable size, including the terminating null */ #define MAX_ENV_VAR_LENGTH 32767 @@ -1540,3 +1548,29 @@ int uv_os_unsetenv(const char* name) { return 0; } + + +int uv_os_gethostname(char* buffer, size_t* size) { + char buf[MAXHOSTNAMELEN + 1]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + uv__once_init(); /* Initialize winsock */ + + if (gethostname(buf, sizeof(buf)) != 0) + return uv_translate_sys_error(WSAGetLastError()); + + buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ + len = strlen(buf); + + if (len >= *size) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, buf, len + 1); + *size = len; + return 0; +} diff --git a/test/test-gethostname.c b/test/test-gethostname.c new file mode 100644 index 000000000..5229804b5 --- /dev/null +++ b/test/test-gethostname.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 + +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + +TEST_IMPL(gethostname) { + char buf[MAXHOSTNAMELEN + 1]; + size_t size; + size_t enobufs_size; + int r; + + /* Reject invalid inputs */ + size = 1; + r = uv_os_gethostname(NULL, &size); + ASSERT(r == UV_EINVAL); + r = uv_os_gethostname(buf, NULL); + ASSERT(r == UV_EINVAL); + size = 0; + r = uv_os_gethostname(buf, &size); + ASSERT(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(r == UV_ENOBUFS); + ASSERT(buf[0] == '\0'); + ASSERT(enobufs_size > 1); + + /* Successfully get the hostname */ + size = MAXHOSTNAMELEN + 1; + r = uv_os_gethostname(buf, &size); + ASSERT(r == 0); + ASSERT(size > 1 && size == strlen(buf)); + ASSERT(size + 1 == enobufs_size); + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 87c54a1af..19febe904 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -220,6 +220,7 @@ TEST_DECLARE (getaddrinfo_fail_sync) TEST_DECLARE (getaddrinfo_basic) TEST_DECLARE (getaddrinfo_basic_sync) TEST_DECLARE (getaddrinfo_concurrent) +TEST_DECLARE (gethostname) TEST_DECLARE (getnameinfo_basic_ip4) TEST_DECLARE (getnameinfo_basic_ip4_sync) TEST_DECLARE (getnameinfo_basic_ip6) @@ -655,6 +656,8 @@ TASK_LIST_START TEST_ENTRY (getaddrinfo_basic_sync) TEST_ENTRY (getaddrinfo_concurrent) + TEST_ENTRY (gethostname) + TEST_ENTRY (getnameinfo_basic_ip4) TEST_ENTRY (getnameinfo_basic_ip4_sync) TEST_ENTRY (getnameinfo_basic_ip6) diff --git a/uv.gyp b/uv.gyp index e14279928..eac8677f3 100644 --- a/uv.gyp +++ b/uv.gyp @@ -357,6 +357,7 @@ 'test/test-get-memory.c', 'test/test-get-passwd.c', 'test/test-getaddrinfo.c', + 'test/test-gethostname.c', 'test/test-getnameinfo.c', 'test/test-getsockname.c', 'test/test-handle-fileno.c', From 573e7fe8fc70a5e053778c465d35efe317b91036 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 3 May 2017 16:50:28 -0400 Subject: [PATCH 383/632] zos: increase timeout for tcp_writealot A small timeout resulted in flaky behaviour on the z/OS test machine. PR-URL: https://github.com/libuv/libuv/pull/1353 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- test/test-list.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test-list.h b/test/test-list.h index 19febe904..76cb71e16 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -461,7 +461,11 @@ TASK_LIST_START TEST_ENTRY (tcp_write_after_connect) #endif +#ifdef __MVS__ + TEST_ENTRY_CUSTOM (tcp_writealot, 0, 0, 20000) +#else TEST_ENTRY (tcp_writealot) +#endif TEST_HELPER (tcp_writealot, tcp4_echo_server) TEST_ENTRY (tcp_write_fail) From ff360e7f142c6811567e7362e948a3befb4a23f8 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 3 May 2017 16:50:28 -0400 Subject: [PATCH 384/632] zos: do not inline OOB data by default It was previously assumed that OOB data had to be inlined but that is incorrect. PR-URL: https://github.com/libuv/libuv/pull/1347 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/unix/stream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index dbd04f2be..c1ec48669 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -390,7 +390,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { int uv__stream_open(uv_stream_t* stream, int fd, int flags) { -#if defined(__APPLE__) || defined(__MVS__) +#if defined(__APPLE__) int enable; #endif @@ -409,7 +409,7 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { return -errno; } -#if defined(__APPLE__) || defined(__MVS__) +#if defined(__APPLE__) enable = 1; if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) && errno != ENOTSOCK && From 6c2fe3d946dc3b29ebc24ad50f8f48156fe4a5c5 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 19 May 2017 10:56:35 +0200 Subject: [PATCH 385/632] test: fix -Wstrict-prototypes compiler warnings PR-URL: https://github.com/libuv/libuv/pull/1354 Reviewed-By: Colin Ihrig Reviewed-By: Gibson Fahnestock Reviewed-By: Santiago Gimeno --- test/test-ipc-send-recv.c | 2 +- test/test-process-title.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-ipc-send-recv.c b/test/test-ipc-send-recv.c index 133ae9014..5826e9e64 100644 --- a/test/test-ipc-send-recv.c +++ b/test/test-ipc-send-recv.c @@ -335,7 +335,7 @@ static void read_cb(uv_stream_t* handle, } while (uv_pipe_pending_count(pipe) > 0); } -static void send_recv_start() { +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)); diff --git a/test/test-process-title.c b/test/test-process-title.c index 5d5ede9d6..f7a0bf611 100644 --- a/test/test-process-title.c +++ b/test/test-process-title.c @@ -41,7 +41,7 @@ static void set_title(const char* title) { } -static void uv_get_process_title_edge_cases() { +static void uv_get_process_title_edge_cases(void) { char buffer[512]; int r; From 470b0258b0fc9e6249e289b0daae53e8418847ff Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 20 Feb 2017 19:48:25 -0500 Subject: [PATCH 386/632] unix: factor out reusable no-proctitle impl On SunOS we implement no support for proctitle. Other platforms may not support proctitle either, so provide a dedicated source file to use in this case. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- Makefile.am | 3 ++- src/unix/no-proctitle.c | 42 +++++++++++++++++++++++++++++++++++++++++ src/unix/sunos.c | 19 ------------------- uv.gyp | 5 ++++- 4 files changed, 48 insertions(+), 21 deletions(-) create mode 100644 src/unix/no-proctitle.c diff --git a/Makefile.am b/Makefile.am index e70c7cfc1..cbabbab4e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -402,7 +402,8 @@ endif if SUNOS include_HEADERS += include/uv-sunos.h libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 -libuv_la_SOURCES += src/unix/sunos.c +libuv_la_SOURCES += src/unix/no-proctitle.c \ + src/unix/sunos.c endif if OS390 diff --git a/src/unix/no-proctitle.c b/src/unix/no-proctitle.c new file mode 100644 index 000000000..a5c19fbff --- /dev/null +++ b/src/unix/no-proctitle.c @@ -0,0 +1,42 @@ +/* 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 "internal.h" + +#include +#include + +char** uv_setup_args(int argc, char** argv) { + return argv; +} + +int uv_set_process_title(const char* title) { + return 0; +} + +int uv_get_process_title(char* buffer, size_t size) { + if (buffer == NULL || size == 0) + return -EINVAL; + + buffer[0] = '\0'; + return 0; +} diff --git a/src/unix/sunos.c b/src/unix/sunos.c index c34b870ec..2dc02ae45 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -545,25 +545,6 @@ void uv__fs_event_close(uv_fs_event_t* handle) { #endif /* defined(PORT_SOURCE_FILE) */ -char** uv_setup_args(int argc, char** argv) { - return argv; -} - - -int uv_set_process_title(const char* title) { - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - if (buffer == NULL || size == 0) - return -EINVAL; - - buffer[0] = '\0'; - return 0; -} - - int uv_resident_set_memory(size_t* rss) { psinfo_t psinfo; int err; diff --git a/uv.gyp b/uv.gyp index eac8677f3..773122003 100644 --- a/uv.gyp +++ b/uv.gyp @@ -257,7 +257,10 @@ }, }], [ 'OS=="solaris"', { - 'sources': [ 'src/unix/sunos.c' ], + 'sources': [ + 'src/unix/no-proctitle.c', + 'src/unix/sunos.c', + ], 'defines': [ '__EXTENSIONS__', '_XOPEN_SOURCE=500', From f4f1f57e7ce6751b91d234d9bb8cbdcc0fa901b6 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 20 Feb 2017 22:03:11 -0500 Subject: [PATCH 387/632] test: factor out fsevents skip explanation Factor out a dedicated test macro for use on platforms that do not support fsevents instead of duplicating the os390 platform condition and explanation text. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- test/task.h | 4 ++++ test/test-fs-event.c | 52 ++++++++++++++++++++++---------------------- test/test-ref.c | 4 ++-- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/test/task.h b/test/task.h index 65a1132e4..9d59dbbb1 100644 --- a/test/task.h +++ b/test/task.h @@ -209,4 +209,8 @@ UNUSED static int can_ipv6(void) { return supported; } +#if defined(__MVS__) +# define NO_FS_EVENTS "Filesystem watching not supported on this platform." +#endif + #endif /* TASK_H_ */ diff --git a/test/test-fs-event.c b/test/test-fs-event.c index cefa5b9f3..fba6b5440 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -394,8 +394,8 @@ static void timer_cb_watch_twice(uv_timer_t* handle) { } TEST_IMPL(fs_event_watch_dir) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_loop_t* loop = uv_default_loop(); @@ -477,8 +477,8 @@ TEST_IMPL(fs_event_watch_dir_recursive) { TEST_IMPL(fs_event_watch_file) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_loop_t* loop = uv_default_loop(); @@ -522,8 +522,8 @@ TEST_IMPL(fs_event_watch_file_exact_path) { "file.js". The test verifies that no events occur for file.jsx. */ -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_loop_t* loop; @@ -561,8 +561,8 @@ TEST_IMPL(fs_event_watch_file_exact_path) { } TEST_IMPL(fs_event_watch_file_twice) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif const char path[] = "test/fixtures/empty_file"; uv_fs_event_t watchers[2]; @@ -585,8 +585,8 @@ TEST_IMPL(fs_event_watch_file_twice) { } TEST_IMPL(fs_event_watch_file_current_dir) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_timer_t timer; uv_loop_t* loop; @@ -658,8 +658,8 @@ TEST_IMPL(fs_event_watch_file_root_dir) { #endif TEST_IMPL(fs_event_no_callback_after_close) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_loop_t* loop = uv_default_loop(); @@ -696,8 +696,8 @@ TEST_IMPL(fs_event_no_callback_after_close) { } TEST_IMPL(fs_event_no_callback_on_close) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_loop_t* loop = uv_default_loop(); @@ -747,8 +747,8 @@ static void timer_cb(uv_timer_t* handle) { TEST_IMPL(fs_event_immediate_close) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_timer_t timer; uv_loop_t* loop; @@ -772,8 +772,8 @@ TEST_IMPL(fs_event_immediate_close) { TEST_IMPL(fs_event_close_with_pending_event) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_loop_t* loop; int r; @@ -818,8 +818,8 @@ static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, } TEST_IMPL(fs_event_close_in_callback) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_loop_t* loop; int r; @@ -857,8 +857,8 @@ TEST_IMPL(fs_event_close_in_callback) { } TEST_IMPL(fs_event_start_and_close) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_loop_t* loop; uv_fs_event_t fs_event1; @@ -892,8 +892,8 @@ TEST_IMPL(fs_event_start_and_close) { } TEST_IMPL(fs_event_getpath) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_loop_t* loop = uv_default_loop(); int r; @@ -1029,8 +1029,8 @@ TEST_IMPL(fs_event_error_reporting) { #endif /* defined(__APPLE__) */ TEST_IMPL(fs_event_watch_invalid_path) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_loop_t* loop; diff --git a/test/test-ref.c b/test/test-ref.c index 39f4b0fc7..05728c833 100644 --- a/test/test-ref.c +++ b/test/test-ref.c @@ -194,8 +194,8 @@ TEST_IMPL(timer_ref2) { TEST_IMPL(fs_event_ref) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif uv_fs_event_t h; uv_fs_event_init(uv_default_loop(), &h); From 773d678c6a772b9e771530dfea4239b9c7615bf7 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 20 Feb 2017 22:03:11 -0500 Subject: [PATCH 388/632] test: skip fork fsevent cases when lacking support On platforms not supporting fsevents do not run the fork fsevent tests. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- test/test-fork.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/test/test-fork.c b/test/test-fork.c index c760de89e..3716a3ad9 100644 --- a/test/test-fork.c +++ b/test/test-fork.c @@ -506,17 +506,18 @@ static int _do_fork_fs_events_child(int file_or_dir) { TEST_IMPL(fork_fs_events_child) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); #endif return _do_fork_fs_events_child(FS_TEST_FILE); } TEST_IMPL(fork_fs_events_child_dir) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); -#elif defined(__APPLE__) || defined (__linux__) +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif +#if defined(__APPLE__) || defined (__linux__) return _do_fork_fs_events_child(FS_TEST_DIR); #else /* You can't spin up a cfrunloop thread on an apple platform @@ -529,9 +530,10 @@ TEST_IMPL(fork_fs_events_child_dir) { TEST_IMPL(fork_fs_events_file_parent_child) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); -#elif defined(__sun) || defined(_AIX) +#if defined(NO_FS_EVENTS) + RETURN_SKIP(NO_FS_EVENTS); +#endif +#if defined(__sun) || defined(_AIX) /* It's not possible to implement this without additional * bookkeeping on SunOS. For AIX it is possible, but has to be * written. See https://github.com/libuv/libuv/pull/846#issuecomment-287170420 From 32ef58bf72a7c020f6907435ce9d7ca512772797 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 20 Feb 2017 22:03:11 -0500 Subject: [PATCH 389/632] unix: factor out reusable no-fsevents impl On os390 we implement no support for fsevents. Other platforms may not support fsevents either, so provide a dedicated source file to use in this case. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- Makefile.am | 1 + src/unix/no-fsevents.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/unix/os390.c | 22 ---------------------- uv.gyp | 1 + 4 files changed, 44 insertions(+), 22 deletions(-) create mode 100644 src/unix/no-fsevents.c diff --git a/Makefile.am b/Makefile.am index cbabbab4e..81bffb87e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -425,6 +425,7 @@ libuv_la_CFLAGS += -D_UNIX03_THREADS \ libuv_la_LDFLAGS += -qXPLINK libuv_la_SOURCES += src/unix/pthread-fixes.c \ src/unix/pthread-barrier.c \ + src/unix/no-fsevents.c \ src/unix/os390.c \ src/unix/os390-syscalls.c \ src/unix/proctitle.c diff --git a/src/unix/no-fsevents.c b/src/unix/no-fsevents.c new file mode 100644 index 000000000..38fb6ab0b --- /dev/null +++ b/src/unix/no-fsevents.c @@ -0,0 +1,42 @@ +/* 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 "internal.h" + +#include + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + return -ENOSYS; +} + +int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, + const char* filename, unsigned int flags) { + return -ENOSYS; +} + +int uv_fs_event_stop(uv_fs_event_t* handle) { + return -ENOSYS; +} + +void uv__fs_event_close(uv_fs_event_t* handle) { + UNREACHABLE(); +} diff --git a/src/unix/os390.c b/src/unix/os390.c index e9ba90c66..2ba5abf35 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -663,28 +663,6 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { return 0; } - -void uv__fs_event_close(uv_fs_event_t* handle) { - UNREACHABLE(); -} - - -int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { - return -ENOSYS; -} - - -int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, - const char* filename, unsigned int flags) { - return -ENOSYS; -} - - -int uv_fs_event_stop(uv_fs_event_t* handle) { - return -ENOSYS; -} - - void uv__io_poll(uv_loop_t* loop, int timeout) { static const int max_safe_timeout = 1789569; struct epoll_event events[1024]; diff --git a/uv.gyp b/uv.gyp index 773122003..8c3686381 100644 --- a/uv.gyp +++ b/uv.gyp @@ -317,6 +317,7 @@ 'sources': [ 'src/unix/pthread-fixes.c', 'src/unix/pthread-barrier.c', + 'src/unix/no-fsevents.c', 'src/unix/os390.c', 'src/unix/os390-syscalls.c' ] From ea795b29ef28123d2acbd7e7e4a74a6f682e6662 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 4 Apr 2017 15:22:24 -0400 Subject: [PATCH 390/632] unix: factor out reusable sysinfo memory lookup On Linux we use `sysinfo(2)` to look up available memory. Factor out a dedicated source file to make this implementation available for use on other platforms that support it. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- Makefile.am | 3 ++- src/unix/linux-core.c | 18 ----------------- src/unix/sysinfo-memory.c | 42 +++++++++++++++++++++++++++++++++++++++ uv.gyp | 2 ++ 4 files changed, 46 insertions(+), 19 deletions(-) create mode 100644 src/unix/sysinfo-memory.c diff --git a/Makefile.am b/Makefile.am index 81bffb87e..13e6fe73e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -377,7 +377,8 @@ libuv_la_SOURCES += src/unix/linux-core.c \ src/unix/linux-inotify.c \ src/unix/linux-syscalls.c \ src/unix/linux-syscalls.h \ - src/unix/proctitle.c + src/unix/proctitle.c \ + src/unix/sysinfo-memory.c test_run_tests_LDFLAGS += -lutil endif diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 646be4fb1..1953f4959 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -503,24 +503,6 @@ int uv_exepath(char* buffer, size_t* size) { } -uint64_t uv_get_free_memory(void) { - struct sysinfo info; - - if (sysinfo(&info) == 0) - return (uint64_t) info.freeram * info.mem_unit; - return 0; -} - - -uint64_t uv_get_total_memory(void) { - struct sysinfo info; - - if (sysinfo(&info) == 0) - return (uint64_t) info.totalram * info.mem_unit; - return 0; -} - - int uv_resident_set_memory(size_t* rss) { char buf[1024]; const char* s; diff --git a/src/unix/sysinfo-memory.c b/src/unix/sysinfo-memory.c new file mode 100644 index 000000000..23b4fc6e9 --- /dev/null +++ b/src/unix/sysinfo-memory.c @@ -0,0 +1,42 @@ +/* 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 "internal.h" + +#include +#include + +uint64_t uv_get_free_memory(void) { + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.freeram * info.mem_unit; + return 0; +} + +uint64_t uv_get_total_memory(void) { + struct sysinfo info; + + if (sysinfo(&info) == 0) + return (uint64_t) info.totalram * info.mem_unit; + return 0; +} diff --git a/uv.gyp b/uv.gyp index 8c3686381..2cd78cb73 100644 --- a/uv.gyp +++ b/uv.gyp @@ -237,6 +237,7 @@ 'src/unix/linux-inotify.c', 'src/unix/linux-syscalls.c', 'src/unix/linux-syscalls.h', + 'src/unix/sysinfo-memory.c', ], 'link_settings': { 'libraries': [ '-ldl', '-lrt' ], @@ -251,6 +252,7 @@ 'src/unix/pthread-fixes.c', 'src/unix/android-ifaddrs.c', 'src/unix/pthread-barrier.c' + 'src/unix/sysinfo-memory.c', ], 'link_settings': { 'libraries': [ '-ldl' ], From 76bcf9f91d8dc13b2051b20e8e21cb7f62b52874 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 4 Apr 2017 15:39:36 -0400 Subject: [PATCH 391/632] unix: factor out reusable sysinfo loadavg impl On Linux we use `sysinfo(2)` to look up the load average. Factor out a dedicated source file to make this implementation available for use on other platforms that support it. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- Makefile.am | 1 + src/unix/linux-core.c | 11 ----------- src/unix/sysinfo-loadavg.c | 36 ++++++++++++++++++++++++++++++++++++ uv.gyp | 2 ++ 4 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 src/unix/sysinfo-loadavg.c diff --git a/Makefile.am b/Makefile.am index 13e6fe73e..2bf216a93 100644 --- a/Makefile.am +++ b/Makefile.am @@ -378,6 +378,7 @@ libuv_la_SOURCES += src/unix/linux-core.c \ src/unix/linux-syscalls.c \ src/unix/linux-syscalls.h \ src/unix/proctitle.c \ + src/unix/sysinfo-loadavg.c \ src/unix/sysinfo-memory.c test_run_tests_LDFLAGS += -lutil endif diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 1953f4959..11fe23067 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -472,17 +472,6 @@ uint64_t uv__hrtime(uv_clocktype_t type) { } -void uv_loadavg(double avg[3]) { - struct sysinfo info; - - if (sysinfo(&info) < 0) return; - - avg[0] = (double) info.loads[0] / 65536.0; - avg[1] = (double) info.loads[1] / 65536.0; - avg[2] = (double) info.loads[2] / 65536.0; -} - - int uv_exepath(char* buffer, size_t* size) { ssize_t n; diff --git a/src/unix/sysinfo-loadavg.c b/src/unix/sysinfo-loadavg.c new file mode 100644 index 000000000..ebad0e89d --- /dev/null +++ b/src/unix/sysinfo-loadavg.c @@ -0,0 +1,36 @@ +/* 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 "internal.h" + +#include +#include + +void uv_loadavg(double avg[3]) { + struct sysinfo info; + + if (sysinfo(&info) < 0) return; + + avg[0] = (double) info.loads[0] / 65536.0; + avg[1] = (double) info.loads[1] / 65536.0; + avg[2] = (double) info.loads[2] / 65536.0; +} diff --git a/uv.gyp b/uv.gyp index 2cd78cb73..12770b13f 100644 --- a/uv.gyp +++ b/uv.gyp @@ -237,6 +237,7 @@ 'src/unix/linux-inotify.c', 'src/unix/linux-syscalls.c', 'src/unix/linux-syscalls.h', + 'src/unix/sysinfo-loadavg.c', 'src/unix/sysinfo-memory.c', ], 'link_settings': { @@ -252,6 +253,7 @@ 'src/unix/pthread-fixes.c', 'src/unix/android-ifaddrs.c', 'src/unix/pthread-barrier.c' + 'src/unix/sysinfo-loadavg.c', 'src/unix/sysinfo-memory.c', ], 'link_settings': { From 77326e86a263457c286d6a0fa696a33f24e61dfc Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 4 Apr 2017 16:22:29 -0400 Subject: [PATCH 392/632] unix: factor out reusable procfs exepath impl On Linux we read `/proc/self/exe` for the path to the executable. Factor out a dedicated source file to make this implementation available for use on other platforms that support it. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- Makefile.am | 1 + src/unix/linux-core.c | 20 ----------------- src/unix/procfs-exepath.c | 45 +++++++++++++++++++++++++++++++++++++++ uv.gyp | 2 ++ 4 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 src/unix/procfs-exepath.c diff --git a/Makefile.am b/Makefile.am index 2bf216a93..7db9c306e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -377,6 +377,7 @@ libuv_la_SOURCES += src/unix/linux-core.c \ src/unix/linux-inotify.c \ src/unix/linux-syscalls.c \ src/unix/linux-syscalls.h \ + src/unix/procfs-exepath.c \ src/unix/proctitle.c \ src/unix/sysinfo-loadavg.c \ src/unix/sysinfo-memory.c diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 11fe23067..2866e9385 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -472,26 +472,6 @@ uint64_t uv__hrtime(uv_clocktype_t type) { } -int uv_exepath(char* buffer, size_t* size) { - ssize_t n; - - if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; - - n = *size - 1; - if (n > 0) - n = readlink("/proc/self/exe", buffer, n); - - if (n == -1) - return -errno; - - buffer[n] = '\0'; - *size = n; - - return 0; -} - - int uv_resident_set_memory(size_t* rss) { char buf[1024]; const char* s; diff --git a/src/unix/procfs-exepath.c b/src/unix/procfs-exepath.c new file mode 100644 index 000000000..5fdb61155 --- /dev/null +++ b/src/unix/procfs-exepath.c @@ -0,0 +1,45 @@ +/* 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 "internal.h" + +#include +#include + +int uv_exepath(char* buffer, size_t* size) { + ssize_t n; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + n = *size - 1; + if (n > 0) + n = readlink("/proc/self/exe", buffer, n); + + if (n == -1) + return -errno; + + buffer[n] = '\0'; + *size = n; + + return 0; +} diff --git a/uv.gyp b/uv.gyp index 12770b13f..a3a42787b 100644 --- a/uv.gyp +++ b/uv.gyp @@ -237,6 +237,7 @@ 'src/unix/linux-inotify.c', 'src/unix/linux-syscalls.c', 'src/unix/linux-syscalls.h', + 'src/unix/procfs-exepath.c', 'src/unix/sysinfo-loadavg.c', 'src/unix/sysinfo-memory.c', ], @@ -253,6 +254,7 @@ 'src/unix/pthread-fixes.c', 'src/unix/android-ifaddrs.c', 'src/unix/pthread-barrier.c' + 'src/unix/procfs-exepath.c', 'src/unix/sysinfo-loadavg.c', 'src/unix/sysinfo-memory.c', ], From c108137d7cac64588ddac3a9c6a1245dce192bb4 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 16 Feb 2017 14:12:00 -0500 Subject: [PATCH 393/632] unix: add a uv__io_poll impl using POSIX poll(2) POSIX defines `poll()` as a portable way to wait on file descriptors. Use it to provide an implementation of our poll abstraction for use on platforms that do not provide a more specialized polling method. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- include/uv-posix.h | 31 ++++ src/unix/posix-poll.c | 324 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 355 insertions(+) create mode 100644 include/uv-posix.h create mode 100644 src/unix/posix-poll.c diff --git a/include/uv-posix.h b/include/uv-posix.h new file mode 100644 index 000000000..9a96634db --- /dev/null +++ b/include/uv-posix.h @@ -0,0 +1,31 @@ +/* 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_POSIX_H +#define UV_POSIX_H + +#define UV_PLATFORM_LOOP_FIELDS \ + struct pollfd* poll_fds; \ + size_t poll_fds_used; \ + size_t poll_fds_size; \ + unsigned char poll_fds_iterating; \ + +#endif /* UV_POSIX_H */ diff --git a/src/unix/posix-poll.c b/src/unix/posix-poll.c new file mode 100644 index 000000000..3fba96e1b --- /dev/null +++ b/src/unix/posix-poll.c @@ -0,0 +1,324 @@ +/* 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 "internal.h" + +/* POSIX defines poll() as a portable way to wait on file descriptors. + * Here we maintain a dynamically sized array of file descriptors and + * events to pass as the first argument to poll(). + */ + +#include +#include +#include +#include +#include + +int uv__platform_loop_init(uv_loop_t* loop) { + loop->poll_fds = NULL; + loop->poll_fds_used = 0; + loop->poll_fds_size = 0; + loop->poll_fds_iterating = 0; + return 0; +} + +void uv__platform_loop_delete(uv_loop_t* loop) { + uv__free(loop->poll_fds); + loop->poll_fds = NULL; +} + +int uv__io_fork(uv_loop_t* loop) { + uv__platform_loop_delete(loop); + return uv__platform_loop_init(loop); +} + +/* Allocate or dynamically resize our poll fds array. */ +static void uv__pollfds_maybe_resize(uv_loop_t* loop) { + size_t i; + size_t n; + struct pollfd* p; + + if (loop->poll_fds_used < loop->poll_fds_size) + return; + + n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64; + p = uv__realloc(loop->poll_fds, n * sizeof(*loop->poll_fds)); + if (p == NULL) + abort(); + + loop->poll_fds = p; + for (i = loop->poll_fds_size; i < n; i++) { + loop->poll_fds[i].fd = -1; + loop->poll_fds[i].events = 0; + loop->poll_fds[i].revents = 0; + } + loop->poll_fds_size = n; +} + +/* Primitive swap operation on poll fds array elements. */ +static void uv__pollfds_swap(uv_loop_t* loop, size_t l, size_t r) { + struct pollfd pfd; + pfd = loop->poll_fds[l]; + loop->poll_fds[l] = loop->poll_fds[r]; + loop->poll_fds[r] = pfd; +} + +/* Add a watcher's fd to our poll fds array with its pending events. */ +static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) { + size_t i; + struct pollfd* pe; + + /* If the fd is already in the set just update its events. */ + assert(!loop->poll_fds_iterating); + for (i = 0; i < loop->poll_fds_used; ++i) { + if (loop->poll_fds[i].fd == w->fd) { + loop->poll_fds[i].events = w->pevents; + return; + } + } + + /* Otherwise, allocate a new slot in the set for the fd. */ + uv__pollfds_maybe_resize(loop); + pe = &loop->poll_fds[loop->poll_fds_used++]; + pe->fd = w->fd; + pe->events = w->pevents; +} + +/* Remove a watcher's fd from our poll fds array. */ +static void uv__pollfds_del(uv_loop_t* loop, int fd) { + size_t i; + assert(!loop->poll_fds_iterating); + for (i = 0; i < loop->poll_fds_used; ++i) { + if (loop->poll_fds[i].fd == fd) { + /* swap to last position and remove */ + --loop->poll_fds_used; + uv__pollfds_swap(loop, i, loop->poll_fds_used); + loop->poll_fds[loop->poll_fds_used].fd = -1; + loop->poll_fds[loop->poll_fds_used].events = 0; + loop->poll_fds[loop->poll_fds_used].revents = 0; + return; + } + } +} + + +void uv__io_poll(uv_loop_t* loop, int timeout) { + sigset_t* pset; + sigset_t set; + uint64_t time_base; + uint64_t time_diff; + QUEUE* q; + uv__io_t* w; + size_t i; + unsigned int nevents; + int nfds; + int have_signals; + struct pollfd* pe; + int fd; + + if (loop->nfds == 0) { + assert(QUEUE_EMPTY(&loop->watcher_queue)); + return; + } + + /* 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); + + w = QUEUE_DATA(q, uv__io_t, watcher_queue); + assert(w->pevents != 0); + assert(w->fd >= 0); + assert(w->fd < (int) loop->nwatchers); + + uv__pollfds_add(loop, w); + + w->events = w->pevents; + } + + /* Prepare a set of signals to block around poll(), if any. */ + pset = NULL; + if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { + pset = &set; + sigemptyset(pset); + sigaddset(pset, SIGPROF); + } + + assert(timeout >= -1); + time_base = loop->time; + + /* Loop calls to poll() and processing of results. If we get some + * results from poll() but they turn out not to be interesting to + * our caller then we need to loop around and poll() again. + */ + for (;;) { + if (pset != NULL) + if (pthread_sigmask(SIG_BLOCK, pset, NULL)) + abort(); + nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout); + if (pset != NULL) + if (pthread_sigmask(SIG_UNBLOCK, pset, 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); + return; + } + + if (nfds == -1) { + if (errno != EINTR) + abort(); + + if (timeout == -1) + continue; + + if (timeout == 0) + return; + + /* Interrupted by a signal. Update timeout and poll again. */ + goto update_timeout; + } + + /* Tell uv__platform_invalidate_fd not to manipulate our array + * while we are iterating over it. + */ + loop->poll_fds_iterating = 1; + + /* Initialize a count of events that we care about. */ + nevents = 0; + have_signals = 0; + + /* Loop over the entire poll fds array looking for returned events. */ + for (i = 0; i < loop->poll_fds_used; i++) { + pe = loop->poll_fds + i; + fd = pe->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, ignore. */ + uv__platform_invalidate_fd(loop, fd); + continue; + } + + /* Filter out events that user has not requested us to watch + * (e.g. POLLNVAL). + */ + pe->revents &= w->pevents | POLLERR | POLLHUP; + + if (pe->revents != 0) { + /* Run signal watchers last. */ + if (w == &loop->signal_io_watcher) { + have_signals = 1; + } else { + w->cb(loop, w, pe->revents); + } + + nevents++; + } + } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + + loop->poll_fds_iterating = 0; + + /* Purge invalidated fds from our poll fds array. */ + uv__pollfds_del(loop, -1); + + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + + if (nevents != 0) + return; + + if (timeout == 0) + return; + + if (timeout == -1) + continue; + +update_timeout: + assert(timeout > 0); + + time_diff = loop->time - time_base; + if (time_diff >= (uint64_t) timeout) + return; + + timeout -= time_diff; + } +} + +/* Remove the given fd from our poll fds array because no one + * is interested in its events anymore. + */ +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + size_t i; + + if (loop->poll_fds_iterating) { + /* uv__io_poll is currently iterating. Just invalidate fd. */ + for (i = 0; i < loop->poll_fds_used; i++) + if (loop->poll_fds[i].fd == fd) { + loop->poll_fds[i].fd = -1; + loop->poll_fds[i].events = 0; + loop->poll_fds[i].revents = 0; + } + } else { + /* uv__io_poll is not iterating. Delete fd from the set. */ + uv__pollfds_del(loop, fd); + } +} + +/* Check whether the given fd is supported by poll(). */ +int uv__io_check_fd(uv_loop_t* loop, int fd) { + struct pollfd p[1]; + int rv; + + p[0].fd = fd; + p[0].events = POLLIN; + + do + rv = poll(p, 1, 0); + while (rv == -1 && (errno == EINTR || errno == EAGAIN)); + + if (rv == -1) + return -errno; + + if (p[0].revents & POLLNVAL) + return -EINVAL; + + return 0; +} From 6398251aff527f0e45ddae4138249d8fdcc2ebbf Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 6 Apr 2017 21:56:34 -0400 Subject: [PATCH 394/632] cygwin: implement support for cygwin and msys2 Cygwin and MSYS2 are POSIX layers implemented on top of Windows. Use our POSIX `poll(2)` implementation of our poll abstraction. For most other components we already have dedicated sources implementing them in terms of APIs available on Cygwin or providing non-implementations of components not supported. This leaves only three components that need Cygwin-specific implementations: * uv_uptime: implement using sysinfo * uv_resident_set_memory: add a placeholder returning UV_ENOSYS * uv_cpu_info: add a placeholder returning UV_ENOSYS Update our test suite to account for features not available due to Cygwin platform limitations or our placeholders. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- Makefile.am | 26 ++++++++++++++ configure.ac | 2 ++ include/uv-unix.h | 2 ++ src/unix/bsd-ifaddrs.c | 6 ++++ src/unix/core.c | 2 ++ src/unix/cygwin.c | 54 +++++++++++++++++++++++++++++ test/task.h | 2 +- test/test-fs.c | 29 ++++++++++++++-- test/test-ip6-addr.c | 4 +++ test/test-ping-pong.c | 4 +++ test/test-platform-output.c | 8 +++++ test/test-poll.c | 2 +- test/test-process-title.c | 2 +- test/test-signal-multiple-loops.c | 7 ++++ test/test-spawn.c | 19 ++++++++++ test/test-tcp-create-socket-early.c | 2 +- test/test-udp-create-socket-early.c | 2 +- test/test-udp-ipv6.c | 5 +++ test/test-watcher-cross-stop.c | 5 +++ 19 files changed, 176 insertions(+), 7 deletions(-) create mode 100644 src/unix/cygwin.c diff --git a/Makefile.am b/Makefile.am index 7db9c306e..404674baf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -337,6 +337,19 @@ libuv_la_SOURCES += src/unix/android-ifaddrs.c \ src/unix/pthread-barrier.c endif +if CYGWIN +libuv_la_CFLAGS += -D_GNU_SOURCE +libuv_la_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 DARWIN include_HEADERS += include/uv-darwin.h \ include/pthread-barrier.h @@ -384,6 +397,19 @@ libuv_la_SOURCES += src/unix/linux-core.c \ test_run_tests_LDFLAGS += -lutil endif +if MSYS +libuv_la_CFLAGS += -D_GNU_SOURCE +libuv_la_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 NETBSD include_HEADERS += include/uv-bsd.h libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ diff --git a/configure.ac b/configure.ac index 963b4f15c..593a6196c 100644 --- a/configure.ac +++ b/configure.ac @@ -52,10 +52,12 @@ AC_CHECK_LIB([socket], [socket]) AC_SYS_LARGEFILE AM_CONDITIONAL([AIX], [AS_CASE([$host_os],[aix*], [true], [false])]) 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([LINUX], [AS_CASE([$host_os],[linux*], [true], [false])]) +AM_CONDITIONAL([MSYS], [AS_CASE([$host_os],[msys*], [true], [false])]) AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false])]) AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])]) AM_CONDITIONAL([OS390], [AS_CASE([$host_os],[openedition*], [true], [false])]) diff --git a/include/uv-unix.h b/include/uv-unix.h index 544072959..d7754509b 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -60,6 +60,8 @@ defined(__OpenBSD__) || \ defined(__NetBSD__) # include "uv-bsd.h" +#elif defined(__CYGWIN__) || defined(__MSYS__) +# include "uv-posix.h" #endif #ifndef PTHREAD_BARRIER_SERIAL_THREAD diff --git a/src/unix/bsd-ifaddrs.c b/src/unix/bsd-ifaddrs.c index 0b5653d0a..414789451 100644 --- a/src/unix/bsd-ifaddrs.c +++ b/src/unix/bsd-ifaddrs.c @@ -27,7 +27,9 @@ #include #include +#if !defined(__CYGWIN__) && !defined(__MSYS__) #include +#endif static int uv__ifaddr_exclude(struct ifaddrs *ent) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) @@ -107,9 +109,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { for (i = 0; i < *count; i++) { if (strcmp(address->name, ent->ifa_name) == 0) { +#if defined(__CYGWIN__) || defined(__MSYS__) + memset(address->phys_addr, 0, sizeof(address->phys_addr)); +#else struct sockaddr_dl* sa_addr; sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); +#endif } address++; } diff --git a/src/unix/core.c b/src/unix/core.c index 9754403c4..30cdaef7b 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -545,6 +545,7 @@ int uv__nonblock_ioctl(int fd, int set) { } +#if !defined(__CYGWIN__) && !defined(__MSYS__) int uv__cloexec_ioctl(int fd, int set) { int r; @@ -557,6 +558,7 @@ int uv__cloexec_ioctl(int fd, int set) { return 0; } +#endif int uv__nonblock_fcntl(int fd, int set) { diff --git a/src/unix/cygwin.c b/src/unix/cygwin.c new file mode 100644 index 000000000..5a887dd4c --- /dev/null +++ b/src/unix/cygwin.c @@ -0,0 +1,54 @@ +/* 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 "internal.h" + +#include +#include + +int uv_uptime(double* uptime) { + struct sysinfo info; + + if (sysinfo(&info) < 0) + return -errno; + + *uptime = info.uptime; + return 0; +} + +int uv_resident_set_memory(size_t* rss) { + /* FIXME: read /proc/meminfo? */ + *rss = 0; + return UV_ENOSYS; +} + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + /* FIXME: read /proc/stat? */ + *cpu_infos = NULL; + *count = 0; + return UV_ENOSYS; +} + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + (void)cpu_infos; + (void)count; +} diff --git a/test/task.h b/test/task.h index 9d59dbbb1..b2d2418d6 100644 --- a/test/task.h +++ b/test/task.h @@ -209,7 +209,7 @@ UNUSED static int can_ipv6(void) { return supported; } -#if defined(__MVS__) +#if defined(__MVS__) || defined(__CYGWIN__) || defined(__MSYS__) # define NO_FS_EVENTS "Filesystem watching not supported on this platform." #endif diff --git a/test/test-fs.c b/test/test-fs.c index a92feb915..ce39ebd43 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -125,7 +125,7 @@ static void check_permission(const char* filename, unsigned int mode) { ASSERT(req.result == 0); s = &req.statbuf; -#ifdef _WIN32 +#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__) /* * On Windows, chmod can only modify S_IWUSR (_S_IWRITE) bit, * so only testing for the specified flags. @@ -240,7 +240,7 @@ static void chown_cb(uv_fs_t* req) { static void chown_root_cb(uv_fs_t* req) { ASSERT(req->fs_type == UV_FS_CHOWN); -#ifdef _WIN32 +#if defined(_WIN32) || defined(__MSYS__) /* On windows, chown is a no-op and always succeeds. */ ASSERT(req->result == 0); #else @@ -250,7 +250,12 @@ static void chown_root_cb(uv_fs_t* req) { if (geteuid() == 0) ASSERT(req->result == 0); else +# if defined(__CYGWIN__) + /* On Cygwin, uid 0 is invalid (no root). */ + ASSERT(req->result == UV_EINVAL); +# else ASSERT(req->result == UV_EPERM); +# endif #endif chown_cb_count++; uv_fs_req_cleanup(req); @@ -641,6 +646,11 @@ TEST_IMPL(fs_file_loop) { */ if (r == UV_ENOTSUP || r == UV_EPERM) return 0; +#elif defined(__MSYS__) + /* MSYS2's approximation of symlinks with copies does not work for broken + links. */ + if (r == UV_ENOENT) + return 0; #endif ASSERT(r == 0); uv_fs_req_cleanup(&req); @@ -1735,6 +1745,10 @@ TEST_IMPL(fs_symlink) { ASSERT(r == 0); uv_fs_req_cleanup(&req); +#if defined(__MSYS__) + RETURN_SKIP("symlink reading is not supported on MSYS2"); +#endif + r = uv_fs_readlink(NULL, &req, "test_file_symlink_symlink", NULL); ASSERT(r == 0); ASSERT(strcmp(req.ptr, "test_file_symlink") == 0); @@ -1878,6 +1892,9 @@ TEST_IMPL(fs_symlink_dir) { r = uv_fs_lstat(NULL, &req, "test_dir_symlink", NULL); ASSERT(r == 0); +#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)); @@ -2103,8 +2120,13 @@ TEST_IMPL(fs_futime) { uv_fs_req_cleanup(&req); r = uv_fs_futime(NULL, &req, file, atime, mtime, NULL); +#if defined(__CYGWIN__) || defined(__MSYS__) + ASSERT(r == UV_ENOSYS); + RETURN_SKIP("futime not supported on Cygwin"); +#else ASSERT(r == 0); ASSERT(req.result == 0); +#endif uv_fs_req_cleanup(&req); r = uv_fs_stat(NULL, &req, path, NULL); @@ -2413,6 +2435,9 @@ TEST_IMPL(fs_rename_to_existing_file) { TEST_IMPL(fs_read_file_eof) { +#if defined(__CYGWIN__) || defined(__MSYS__) + RETURN_SKIP("Cygwin pread at EOF may (incorrectly) return data!"); +#endif int r; /* Setup. */ diff --git a/test/test-ip6-addr.c b/test/test-ip6-addr.c index 869b099e0..156fccde3 100644 --- a/test/test-ip6-addr.c +++ b/test/test-ip6-addr.c @@ -32,6 +32,10 @@ TEST_IMPL(ip6_addr_link_local) { +#if defined(__CYGWIN__) || defined(__MSYS__) + /* FIXME: Does Cygwin support this? */ + RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); +#endif char string_address[INET6_ADDRSTRLEN]; uv_interface_address_t* addresses; uv_interface_address_t* address; diff --git a/test/test-ping-pong.c b/test/test-ping-pong.c index c07417854..bdc967151 100644 --- a/test/test-ping-pong.c +++ b/test/test-ping-pong.c @@ -27,7 +27,11 @@ static int completed_pingers = 0; +#if defined(__CYGWIN__) || defined(__MSYS__) +#define NUM_PINGS 100 /* fewer pings to avoid timeout */ +#else #define NUM_PINGS 1000 +#endif /* 64 bytes is enough for a pinger */ #define BUFSIZE 10240 diff --git a/test/test-platform-output.c b/test/test-platform-output.c index b89550801..72c176edc 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -47,8 +47,12 @@ TEST_IMPL(platform_output) { printf("uv_cwd: %s\n", buffer); err = uv_resident_set_memory(&rss); +#if defined(__CYGWIN__) || defined(__MSYS__) + ASSERT(err == UV_ENOSYS); +#else ASSERT(err == 0); printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss); +#endif err = uv_uptime(&uptime); ASSERT(err == 0); @@ -73,6 +77,9 @@ TEST_IMPL(platform_output) { (unsigned long long) rusage.ru_maxrss); err = uv_cpu_info(&cpus, &count); +#if defined(__CYGWIN__) || defined(__MSYS__) + ASSERT(err == UV_ENOSYS); +#else ASSERT(err == 0); printf("uv_cpu_info:\n"); @@ -88,6 +95,7 @@ TEST_IMPL(platform_output) { printf(" times.nice: %llu\n", (unsigned long long) cpus[i].cpu_times.nice); } +#endif uv_free_cpu_info(cpus, count); err = uv_interface_addresses(&interfaces, &count); diff --git a/test/test-poll.c b/test/test-poll.c index 71948dee7..0cf6740fb 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -595,7 +595,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(__OpenBSD__) + !defined(__OpenBSD__) && !defined(__CYGWIN__) && !defined(__MSYS__) uv_poll_t poll_handle; int fd; diff --git a/test/test-process-title.c b/test/test-process-title.c index f7a0bf611..886f83a7d 100644 --- a/test/test-process-title.c +++ b/test/test-process-title.c @@ -60,7 +60,7 @@ static void uv_get_process_title_edge_cases(void) { TEST_IMPL(process_title) { -#if defined(__sun) +#if defined(__sun) || defined(__CYGWIN__) || defined(__MSYS__) RETURN_SKIP("uv_(get|set)_process_title is not implemented."); #else /* Check for format string vulnerabilities. */ diff --git a/test/test-signal-multiple-loops.c b/test/test-signal-multiple-loops.c index 158129919..11193dcf5 100644 --- a/test/test-signal-multiple-loops.c +++ b/test/test-signal-multiple-loops.c @@ -193,6 +193,13 @@ static void loop_creating_worker(void* context) { TEST_IMPL(signal_multiple_loops) { +#if defined(__CYGWIN__) || defined(__MSYS__) + /* FIXME: This test needs more investigation. Somehow the `read` in + uv__signal_lock fails spuriously with EACCES or even EAGAIN even + though it is supposed to be blocking. Also the test hangs during + thread setup occasionally. */ + RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); +#endif uv_thread_t loop_creating_threads[NUM_LOOP_CREATING_THREADS]; uv_thread_t signal_handling_threads[NUM_SIGNAL_HANDLING_THREADS]; enum signal_action action; diff --git a/test/test-spawn.c b/test/test-spawn.c index e6f1ceb70..52fc7f6cc 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1297,7 +1297,11 @@ TEST_IMPL(spawn_setuid_fails) { options.uid = 0; r = uv_spawn(uv_default_loop(), &process, &options); +#if defined(__CYGWIN__) + ASSERT(r == UV_EINVAL); +#else ASSERT(r == UV_EPERM); +#endif r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); @@ -1328,7 +1332,11 @@ TEST_IMPL(spawn_setgid_fails) { options.gid = 0; r = uv_spawn(uv_default_loop(), &process, &options); +#if defined(__CYGWIN__) + ASSERT(r == UV_EINVAL); +#else ASSERT(r == UV_EPERM); +#endif r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); @@ -1537,6 +1545,17 @@ TEST_IMPL(spawn_reads_child_path) { exepath[len] = 0; strcpy(path, "PATH="); strcpy(path + 5, exepath); +#if defined(__CYGWIN__) || defined(__MSYS__) + /* Carry over the dynamic linker path in case the test runner + is linked against cyguv-1.dll or msys-uv-1.dll, see above. */ + { + char* syspath = getenv("PATH"); + if (syspath != NULL) { + strcat(path, ":"); + strcat(path, syspath); + } + } +#endif env[0] = path; env[1] = getenv(dyld_path_var); diff --git a/test/test-tcp-create-socket-early.c b/test/test-tcp-create-socket-early.c index 1a508e474..b87e73241 100644 --- a/test/test-tcp-create-socket-early.c +++ b/test/test-tcp-create-socket-early.c @@ -164,7 +164,7 @@ TEST_IMPL(tcp_create_early_bad_bind) { #endif r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0); -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MSYS__) ASSERT(r == UV_EINVAL); #else ASSERT(r == UV_EFAULT); diff --git a/test/test-udp-create-socket-early.c b/test/test-udp-create-socket-early.c index 3f3027404..f7e46abc9 100644 --- a/test/test-udp-create-socket-early.c +++ b/test/test-udp-create-socket-early.c @@ -104,7 +104,7 @@ TEST_IMPL(udp_create_early_bad_bind) { #endif r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MSYS__) ASSERT(r == UV_EINVAL); #else ASSERT(r == UV_EFAULT); diff --git a/test/test-udp-ipv6.c b/test/test-udp-ipv6.c index a65f09e0c..54b364da9 100644 --- a/test/test-udp-ipv6.c +++ b/test/test-udp-ipv6.c @@ -163,6 +163,11 @@ static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) { TEST_IMPL(udp_dual_stack) { +#if defined(__CYGWIN__) || defined(__MSYS__) + /* FIXME: Does Cygwin support this? */ + RETURN_SKIP("FIXME: This test needs more investigation on Cygwin"); +#endif + if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); diff --git a/test/test-watcher-cross-stop.c b/test/test-watcher-cross-stop.c index 6ff48d44c..29a82a5c3 100644 --- a/test/test-watcher-cross-stop.c +++ b/test/test-watcher-cross-stop.c @@ -26,7 +26,12 @@ #include /* NOTE: Number should be big enough to trigger this problem */ +#if defined(__CYGWIN__) || defined(__MSYS__) +/* Cygwin crashes or hangs in socket() with too many AF_INET sockets. */ +static uv_udp_t sockets[1250]; +#else static uv_udp_t sockets[2500]; +#endif static uv_udp_send_t reqs[ARRAY_SIZE(sockets)]; static char slab[1]; static unsigned int recv_cb_called; From 2e197418c3ece95922dc3c32a5a6d4f014a3a844 Mon Sep 17 00:00:00 2001 From: Brad King Date: Sat, 8 Apr 2017 19:14:51 -0400 Subject: [PATCH 395/632] cygwin: recognize EOF on named pipe closure On Cygwin a named pipe closed by terminating a child process may be reported via `ECONNRESET` on the next read. Teach `uv__read` to interpret this as end of file. This fixes the `spawn_and_kill_with_std` test. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- src/unix/stream.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/unix/stream.c b/src/unix/stream.c index c1ec48669..77c5cfab6 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1173,6 +1173,11 @@ static void uv__read(uv_stream_t* stream) { uv__stream_osx_interrupt_select(stream); } stream->read_cb(stream, 0, &buf); +#if defined(__CYGWIN__) || defined(__MSYS__) + } else if (errno == ECONNRESET && stream->type == UV_NAMED_PIPE) { + uv__stream_eof(stream, &buf); + return; +#endif } else { /* Error. User should call uv_close(). */ stream->read_cb(stream, -errno, &buf); From 317fc756a5769f5862b9ebed4c5d5d665c7f769f Mon Sep 17 00:00:00 2001 From: Brad King Date: Sun, 9 Apr 2017 09:44:28 -0400 Subject: [PATCH 396/632] cygwin: fix uv_pipe_connect report of ENOTSOCK On Cygwin a `connect` to a file that is not a socket fails with `EBADF` instead of `ENOTSOCK` even though the former is supposed to be for a bad socket fd. Translate the error. This fixes the `pipe_connect_to_file` to file test. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- src/unix/pipe.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/unix/pipe.c b/src/unix/pipe.c index dd3d034f5..4a812955b 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -181,6 +181,14 @@ void uv_pipe_connect(uv_connect_t* req, if (r == -1 && errno != EINPROGRESS) { err = -errno; +#if defined(__CYGWIN__) || defined(__MSYS__) + /* EBADF is supposed to mean that the socket fd is bad, but + Cygwin reports EBADF instead of ENOTSOCK when the file is + not a socket. We do not expect to see a bad fd here + (e.g. due to new_sock), so translate the error. */ + if (err == -EBADF) + err = -ENOTSOCK; +#endif goto out; } From 580f0327370381363fe842db0c9424f9346810f5 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 10 Apr 2017 22:13:48 -0400 Subject: [PATCH 397/632] cygwin: disable non-functional ipc handle send On Cygwin `recvmsg` always sets `msg_controllen` to zero on a message received from a named pipe. Therefore we cannot use `sendmsg` to send handles for ipc. Return failure early from this code path as `ENOSYS`. Skip tests requiring this feature since it is not available. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- src/unix/stream.c | 6 ++++++ test/task.h | 8 ++++++++ test/test-ipc-send-recv.c | 12 ++++++++++++ test/test-ipc.c | 12 ++++++++++++ test/test-pipe-sendmsg.c | 3 +++ 5 files changed, 41 insertions(+) diff --git a/src/unix/stream.c b/src/unix/stream.c index 77c5cfab6..7b23d16ec 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1410,6 +1410,12 @@ int uv_write2(uv_write_t* req, */ if (uv__handle_fd((uv_handle_t*) send_handle) < 0) return -EBADF; + +#if defined(__CYGWIN__) || defined(__MSYS__) + /* Cygwin recvmsg always sets msg_controllen to zero, so we cannot send it. + See https://github.com/mirror/newlib-cygwin/blob/86fc4bf0/winsup/cygwin/fhandler_socket.cc#L1736-L1743 */ + return -ENOSYS; +#endif } /* It's legal for write_queue_size > 0 even when the write_queue is empty; diff --git a/test/task.h b/test/task.h index b2d2418d6..824832073 100644 --- a/test/task.h +++ b/test/task.h @@ -213,4 +213,12 @@ UNUSED static int can_ipv6(void) { # define NO_FS_EVENTS "Filesystem watching not supported on this platform." #endif +#if defined(__MSYS__) +# define NO_SEND_HANDLE_ON_PIPE \ + "MSYS2 runtime does not support sending handles on pipes." +#elif defined(__CYGWIN__) +# define NO_SEND_HANDLE_ON_PIPE \ + "Cygwin runtime does not support sending handles on pipes." +#endif + #endif /* TASK_H_ */ diff --git a/test/test-ipc-send-recv.c b/test/test-ipc-send-recv.c index 5826e9e64..160c23507 100644 --- a/test/test-ipc-send-recv.c +++ b/test/test-ipc-send-recv.c @@ -224,10 +224,16 @@ static int run_ipc_send_recv_pipe(int inprocess) { } TEST_IMPL(ipc_send_recv_pipe) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif return run_ipc_send_recv_pipe(0); } TEST_IMPL(ipc_send_recv_pipe_inprocess) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif return run_ipc_send_recv_pipe(1); } @@ -259,10 +265,16 @@ static int run_ipc_send_recv_tcp(int inprocess) { } TEST_IMPL(ipc_send_recv_tcp) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif return run_ipc_send_recv_tcp(0); } TEST_IMPL(ipc_send_recv_tcp_inprocess) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif return run_ipc_send_recv_tcp(1); } diff --git a/test/test-ipc.c b/test/test-ipc.c index f018c2d4d..a2fda2458 100644 --- a/test/test-ipc.c +++ b/test/test-ipc.c @@ -411,6 +411,9 @@ static int run_ipc_test(const char* helper, uv_read_cb read_cb) { TEST_IMPL(ipc_listen_before_write) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif int r = run_ipc_test("ipc_helper_listen_before_write", on_read); ASSERT(local_conn_accepted == 1); ASSERT(remote_conn_accepted == 1); @@ -421,6 +424,9 @@ TEST_IMPL(ipc_listen_before_write) { TEST_IMPL(ipc_listen_after_write) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif int r = run_ipc_test("ipc_helper_listen_after_write", on_read); ASSERT(local_conn_accepted == 1); ASSERT(remote_conn_accepted == 1); @@ -431,6 +437,9 @@ TEST_IMPL(ipc_listen_after_write) { TEST_IMPL(ipc_tcp_connection) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif int r = run_ipc_test("ipc_helper_tcp_connection", on_read_connection); ASSERT(read_cb_called == 1); ASSERT(tcp_write_cb_called == 1); @@ -491,6 +500,9 @@ TEST_IMPL(listen_no_simultaneous_accepts) { } TEST_IMPL(ipc_listen_after_bind_twice) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif int r = run_ipc_test("ipc_helper_bind_twice", on_read_listen_after_bound_twice); ASSERT(read_cb_called == 2); ASSERT(exit_cb_called == 1); diff --git a/test/test-pipe-sendmsg.c b/test/test-pipe-sendmsg.c index f6d893b44..3bf427f8a 100644 --- a/test/test-pipe-sendmsg.c +++ b/test/test-pipe-sendmsg.c @@ -102,6 +102,9 @@ static void read_cb(uv_stream_t* handle, TEST_IMPL(pipe_sendmsg) { +#if defined(NO_SEND_HANDLE_ON_PIPE) + RETURN_SKIP(NO_SEND_HANDLE_ON_PIPE); +#endif uv_pipe_t p; int r; int fds[2]; From 621655352c4f591946207e7cf58664a6c4ad03e4 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 6 Apr 2017 21:59:24 -0400 Subject: [PATCH 398/632] test: skip self-connecting tests on cygwin The cygwin runtime library fails to connect a socket client to a listening server within the same thread. Test cases that use this approach hang while waiting for the connection to complete. This can be reproduced independent of libuv in a simple example using both socket/bind/listen and socket/connect in a single thread. Avoid this problem in our test suite by skipping such tests on cygwin. PR-URL: https://github.com/libuv/libuv/pull/1312 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- test/task.h | 8 ++++++++ test/test-pipe-bind-error.c | 3 +++ test/test-pipe-connect-multiple.c | 3 +++ test/test-pipe-getsockname.c | 3 +++ test/test-pipe-server-close.c | 3 +++ test/test-poll.c | 6 ++++++ 6 files changed, 26 insertions(+) diff --git a/test/task.h b/test/task.h index 824832073..67eb98049 100644 --- a/test/task.h +++ b/test/task.h @@ -221,4 +221,12 @@ UNUSED static int can_ipv6(void) { "Cygwin runtime does not support sending handles on pipes." #endif +#if defined(__MSYS__) +# define NO_SELF_CONNECT \ + "MSYS2 runtime hangs on listen+connect in same process." +#elif defined(__CYGWIN__) +# define NO_SELF_CONNECT \ + "Cygwin runtime hangs on listen+connect in same process." +#endif + #endif /* TASK_H_ */ diff --git a/test/test-pipe-bind-error.c b/test/test-pipe-bind-error.c index 38b57db69..9cf93165e 100644 --- a/test/test-pipe-bind-error.c +++ b/test/test-pipe-bind-error.c @@ -116,6 +116,9 @@ TEST_IMPL(pipe_bind_error_inval) { TEST_IMPL(pipe_listen_without_bind) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif uv_pipe_t server; int r; diff --git a/test/test-pipe-connect-multiple.c b/test/test-pipe-connect-multiple.c index 3de5a9a0b..0a60d4a96 100644 --- a/test/test-pipe-connect-multiple.c +++ b/test/test-pipe-connect-multiple.c @@ -70,6 +70,9 @@ static void connect_cb(uv_connect_t* connect_req, int status) { TEST_IMPL(pipe_connect_multiple) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif int i; int r; uv_loop_t* loop; diff --git a/test/test-pipe-getsockname.c b/test/test-pipe-getsockname.c index 4b4ceccc4..d1628a67d 100644 --- a/test/test-pipe-getsockname.c +++ b/test/test-pipe-getsockname.c @@ -87,6 +87,9 @@ static void pipe_server_connection_cb(uv_stream_t* handle, int status) { TEST_IMPL(pipe_getsockname) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif uv_loop_t* loop; char buf[1024]; size_t len; diff --git a/test/test-pipe-server-close.c b/test/test-pipe-server-close.c index 1dcdfffaf..ea9977dd8 100644 --- a/test/test-pipe-server-close.c +++ b/test/test-pipe-server-close.c @@ -61,6 +61,9 @@ static void pipe_server_connection_cb(uv_stream_t* handle, int status) { TEST_IMPL(pipe_server_close) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif uv_loop_t* loop; int r; diff --git a/test/test-poll.c b/test/test-poll.c index 0cf6740fb..7cfc159a2 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -574,6 +574,9 @@ static void start_poll_test(void) { TEST_IMPL(poll_duplex) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif test_mode = DUPLEX; start_poll_test(); return 0; @@ -581,6 +584,9 @@ TEST_IMPL(poll_duplex) { TEST_IMPL(poll_unidirectional) { +#if defined(NO_SELF_CONNECT) + RETURN_SKIP(NO_SELF_CONNECT); +#endif test_mode = UNIDIRECTIONAL; start_poll_test(); return 0; From 6c2fd34e396de7fde8dfbb5ebbcc63306077fbea Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 22 May 2017 12:25:11 -0400 Subject: [PATCH 399/632] doc: mark uv_loop_fork() as experimental uv_loop_fork() was recently added, but is known to contain bugs. This commit marks the function as experimental so that bugs can be addressed without blocking further libuv releases. Refs: https://github.com/libuv/libuv/pull/846 Refs: https://github.com/libuv/libuv/pull/1269 Refs: https://github.com/libuv/libuv/issues/1264 PR-URL: https://github.com/libuv/libuv/pull/1356 Reviewed-By: Santiago Gimeno Reviewed-By: Ben Noordhuis --- docs/src/loop.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/src/loop.rst b/docs/src/loop.rst index 74f96341d..02543171d 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -191,6 +191,11 @@ API This function is not implemented on Windows, where it returns ``UV_ENOSYS``. + .. caution:: + + This function is experimental. It may contain bugs, and is subject to + change or removal. API and ABI stability is not guaranteed. + .. note:: On Mac OS X, if directory FS event handles were in use in the From dc596109d5a22db1dbf57098630eebd30fce8068 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Thu, 25 May 2017 17:51:45 +0200 Subject: [PATCH 400/632] doc: add bzoz to maintainers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1358 Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Colin Ihrig --- MAINTAINERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 27a3523ea..d85deb006 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -3,6 +3,7 @@ libuv is currently managed by the following individuals: +* **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)) From ce770a6c3bc88f11913b1a4067b9c026b63723e1 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Fri, 26 May 2017 14:14:36 +0000 Subject: [PATCH 401/632] doc: fix memory leak in tcp-echo-server example Fixes: https://github.com/libuv/help/issues/4 PR-URL: https://github.com/libuv/libuv/pull/1363 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- docs/code/tcp-echo-server/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/code/tcp-echo-server/main.c b/docs/code/tcp-echo-server/main.c index 63965bd9a..5d7b49937 100644 --- a/docs/code/tcp-echo-server/main.c +++ b/docs/code/tcp-echo-server/main.c @@ -25,6 +25,10 @@ void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { buf->len = suggested_size; } +void on_close(uv_handle_t* handle) { + free(handle); +} + void echo_write(uv_write_t *req, int status) { if (status) { fprintf(stderr, "Write error %s\n", uv_strerror(status)); @@ -42,7 +46,7 @@ void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { if (nread < 0) { if (nread != UV_EOF) fprintf(stderr, "Read error %s\n", uv_err_name(nread)); - uv_close((uv_handle_t*) client, NULL); + uv_close((uv_handle_t*) client, on_close); } free(buf->base); @@ -61,7 +65,7 @@ void on_new_connection(uv_stream_t *server, int status) { uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); } else { - uv_close((uv_handle_t*) client, NULL); + uv_close((uv_handle_t*) client, on_close); } } From e133923e935acc3a0b6371372c4ec56f797c8cae Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Fri, 28 Apr 2017 10:58:35 -0400 Subject: [PATCH 402/632] win: make uv__get_osfhandle() public MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The uv__get_osfhandle() function is a private functio of the Windows subsystem, and its used to get a Windows HANDLE out of a file descriptor number. The motivation behind making this function public is to allow Node.js programs to pass file descriptors created using fs.open() to native Node.js C++ add-ons, and be able to successfully convert them to Windows HANDLEs. Refs: https://github.com/libuv/libuv/pull/1166 Refs: https://github.com/nodejs/node/issues/6369 Fixes: https://github.com/libuv/libuv/issues/1291 PR-URL: https://github.com/libuv/libuv/pull/1323 Reviewed-By: Santiago Gimeno Reviewed-By: Bartosz Sosnowski Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Colin Ihrig --- docs/src/fs.rst | 12 ++++++++++++ include/uv.h | 1 + src/unix/core.c | 5 +++++ src/win/handle.c | 5 +++++ test/test-fs.c | 39 +++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 6 files changed, 64 insertions(+) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 234713ecc..3f766e393 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -324,3 +324,15 @@ API These functions are not implemented on Windows. .. seealso:: The :c:type:`uv_req_t` API functions also apply. + +Helper functions +---------------- + +.. c:function:: uv_os_fd_t uv_get_osfhandle(int fd) + + For a file descriptor in the C runtime, get the OS-dependent handle. + On UNIX, returns the ``fd`` intact. On Windows, this calls `_get_osfhandle `_. + Note that the return value is still owned by the C runtime, + any attempts to close it or to use it after closing the fd may lead to malfunction. + + .. versionadded:: 1.12.0 diff --git a/include/uv.h b/include/uv.h index 40f5a4bd5..f076094cc 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1034,6 +1034,7 @@ UV_EXTERN int uv_get_process_title(char* buffer, size_t size); 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); typedef struct { long tv_sec; diff --git a/src/unix/core.c b/src/unix/core.c index 30cdaef7b..8276c6041 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1324,3 +1324,8 @@ int uv_os_gethostname(char* buffer, size_t* size) { *size = len; return 0; } + + +uv_os_fd_t uv_get_osfhandle(int fd) { + return fd; +} diff --git a/src/win/handle.c b/src/win/handle.c index 72b49d979..39150702d 100644 --- a/src/win/handle.c +++ b/src/win/handle.c @@ -152,3 +152,8 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { int uv_is_closing(const uv_handle_t* handle) { return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED)); } + + +uv_os_fd_t uv_get_osfhandle(int fd) { + return uv__get_osfhandle(fd); +} diff --git a/test/test-fs.c b/test/test-fs.c index ce39ebd43..c482ab5c7 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2765,3 +2765,42 @@ TEST_IMPL(fs_read_write_null_arguments) { return 0; } + + +TEST_IMPL(get_osfhandle_valid_handle) { + int r; + uv_os_fd_t 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); + + fd = uv_get_osfhandle(open_req1.result); +#ifdef _WIN32 + ASSERT(fd != INVALID_HANDLE_VALUE); +#else + ASSERT(fd >= 0); +#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; +} diff --git a/test/test-list.h b/test/test-list.h index 76cb71e16..3571aa230 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -305,6 +305,7 @@ TEST_DECLARE (fs_open_dir) 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 (fs_write_alotof_bufs) TEST_DECLARE (fs_write_alotof_bufs_with_offset) TEST_DECLARE (threadpool_queue_work_simple) @@ -792,6 +793,7 @@ TASK_LIST_START TEST_ENTRY (fs_write_alotof_bufs) TEST_ENTRY (fs_write_alotof_bufs_with_offset) TEST_ENTRY (fs_read_write_null_arguments) + TEST_ENTRY (get_osfhandle_valid_handle) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) #if defined(__PPC__) || defined(__PPC64__) /* For linux PPC and AIX */ From f737f941c50fb5331657a2b0664f74f37f8a0a74 Mon Sep 17 00:00:00 2001 From: Bernardo Ramos Date: Sat, 29 Apr 2017 18:35:54 +0000 Subject: [PATCH 403/632] doc: use valid pipe name in pipe-echo-server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1330 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Colin Ihrig --- docs/code/pipe-echo-server/main.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/code/pipe-echo-server/main.c b/docs/code/pipe-echo-server/main.c index 4ba4246e7..4f28fd03e 100644 --- a/docs/code/pipe-echo-server/main.c +++ b/docs/code/pipe-echo-server/main.c @@ -3,6 +3,12 @@ #include #include +#ifdef _WIN32 +#define PIPENAME "\\\\?\\pipe\\echo.sock" +#else +#define PIPENAME "/tmp/echo.sock" +#endif + uv_loop_t *loop; typedef struct { @@ -63,7 +69,7 @@ void on_new_connection(uv_stream_t *server, int status) { void remove_sock(int sig) { uv_fs_t req; - uv_fs_unlink(loop, &req, "echo.sock", NULL); + uv_fs_unlink(loop, &req, PIPENAME, NULL); exit(0); } @@ -76,7 +82,7 @@ int main() { signal(SIGINT, remove_sock); int r; - if ((r = uv_pipe_bind(&server, "echo.sock"))) { + if ((r = uv_pipe_bind(&server, PIPENAME))) { fprintf(stderr, "Bind error %s\n", uv_err_name(r)); return 1; } From d6ac141ac674657049598c36604f26e031fae917 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 30 May 2017 12:18:19 -0400 Subject: [PATCH 404/632] 2017.05.31, Version 1.12.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.11.0: * Now working on version 1.11.1 (cjihrig) * test: fix tests on OpenBSD (Santiago Gimeno) * test: fix -Wformat warning (Santiago Gimeno) * win,fs: avoid double freeing uv_fs_event_t.dirw (Vladimir Matveev) * unix: remove unused code in `uv__io_start` (Fedor Indutny) * signal: add uv_signal_start_oneshot method (Santiago Gimeno) * unix: factor out reusable POSIX hrtime impl (Brad King) * unix,win: add uv_os_{get,set,unset}env() (cjihrig) * win: add uv__convert_utf8_to_utf16() (cjihrig) * docs: improve UV_ENOBUFS scenario documentation (cjihrig) * unix: return UV_EINVAL for NULL env name (jBarz) * unix: filter getifaddrs results consistently (Brad King) * unix: factor out getifaddrs result filter (Brad King) * unix: factor out reusable BSD ifaddrs impl (Brad King) * unix: use union to follow strict aliasing rules (jBarz) * unix: simplify async watcher dispatch logic (Ben Noordhuis) * samples: update timer callback prototype (Ben Noordhuis) * unix: make loops and watchers usable after fork() (Jason Madden) * win: free uv__loops once empty (cjihrig) * tools: add make_dist_html.py script (Ben Noordhuis) * win,sunos: stop handle on uv_fs_event_start() err (cjihrig) * unix,windows: refactor request init logic (Ben Noordhuis) * win: fix memory leak inside uv__pipe_getname (A. Hauptmann) * fsevent: support for files without short name (Bartosz Sosnowski) * doc: fix multiple doc typos (Jamie Davis) * test,osx: fix flaky kill test (Santiago Gimeno) * unix: inline uv_pipe_bind() err_bind goto target (cjihrig) * unix,test: deadstore fixes (Rasmus Christian Pedersen) * win: fix memory leak inside uv_fs_access() (A. Hauptmann) * doc: fix docs/src/fs.rst build warning (Daniel Bevenius) * doc: minor grammar fix in Installation section (Daniel Bevenius) * doc: suggestions for design page (Daniel Bevenius) * doc: libuv does not touch uv_loop_t.data (Ben Noordhuis) * github: add ISSUE_TEMPLATE.md (Ben Noordhuis) * doc: add link to libuv/help to README (Ben Noordhuis) * udp: fix fast path in uv_udp_send() on unix (Fedor Indutny) * test: add test for uv_udp_send() fix (Trevor Norris) * doc: fix documentation for uv_handle_t.type (Daniel Kahn Gillmor) * zos: use proper prototype for epoll_init() (Ben Noordhuis) * doc: rename docs to "libuv documentation" (Saúl Ibarra Corretgé) * doc: update copyright years (Saúl Ibarra Corretgé) * doc: move TOC to a dedicated document (Saúl Ibarra Corretgé) * doc: move documentation section up (Saúl Ibarra Corretgé) * doc: move "upgrading" to a standalone document (Saúl Ibarra Corretgé) * doc: add initial version of the User Guide (Saúl Ibarra Corretgé) * doc: removed unused file (Saúl Ibarra Corretgé) * doc: update guide/about and mention new maintainership (Saúl Ibarra Corretgé) * doc: remove licensing note from guide/about (Saúl Ibarra Corretgé) * doc: add warning note to user guide (Saúl Ibarra Corretgé) * doc: change license to CC BY 4.0 (Saúl Ibarra Corretgé) * doc: remove ubvook reference from README (Saúl Ibarra Corretgé) * doc: add code samples from uvbook (unadapted) (Saúl Ibarra Corretgé) * doc: update supported linux/glibc baseline (Ben Noordhuis) * win: avoid leaking pipe handles to child processes (Jameson Nash) * win,test: support stdout output larger than 1kb (Bartosz Sosnowski) * win: remove __declspec(inline) from atomic op (Keane) * test: fix VC++ compilation warning (Rasmus Christian Pedersen) * build: add -Wstrict-prototypes (Jameson Nash) * zos: implement uv__io_fork, skip fs event tests (jBarz) * unix: do not close udp sockets on bind error (Marc Schlaich) * unix: remove FSEventStreamFlushSync() call (cjihrig) * build,openbsd: remove kvm-related code (James McCoy) * test: fix flaky tcp-write-queue-order (Santiago Gimeno) * unix,win: add uv_os_gethostname() (cjihrig) * zos: increase timeout for tcp_writealot (jBarz) * zos: do not inline OOB data by default (jBarz) * test: fix -Wstrict-prototypes compiler warnings (Ben Noordhuis) * unix: factor out reusable no-proctitle impl (Brad King) * test: factor out fsevents skip explanation (Brad King) * test: skip fork fsevent cases when lacking support (Brad King) * unix: factor out reusable no-fsevents impl (Brad King) * unix: factor out reusable sysinfo memory lookup (Brad King) * unix: factor out reusable sysinfo loadavg impl (Brad King) * unix: factor out reusable procfs exepath impl (Brad King) * unix: add a uv__io_poll impl using POSIX poll(2) (Brad King) * cygwin: implement support for cygwin and msys2 (Brad King) * cygwin: recognize EOF on named pipe closure (Brad King) * cygwin: fix uv_pipe_connect report of ENOTSOCK (Brad King) * cygwin: disable non-functional ipc handle send (Brad King) * test: skip self-connecting tests on cygwin (Brad King) * doc: mark uv_loop_fork() as experimental (cjihrig) * doc: add bzoz to maintainers (Bartosz Sosnowski) * doc: fix memory leak in tcp-echo-server example (Bernardo Ramos) * win: make uv__get_osfhandle() public (Juan Cruz Viotti) * doc: use valid pipe name in pipe-echo-server (Bernardo Ramos) --- .mailmap | 2 + AUTHORS | 8 ++ ChangeLog | 175 +++++++++++++++++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 8 +- 6 files changed, 191 insertions(+), 6 deletions(-) diff --git a/.mailmap b/.mailmap index 8acf8fecd..618274c0d 100644 --- a/.mailmap +++ b/.mailmap @@ -1,3 +1,4 @@ +A. Hauptmann Aaron Bieber Alan Gutierrez Andrius Bentkus @@ -39,3 +40,4 @@ Timothy J. Fontaine Yasuhiro Matsumoto Yazhong Liu Yuki Okumura +jBarz diff --git a/AUTHORS b/AUTHORS index 4719d2368..ab4e099f1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -284,3 +284,11 @@ muflub Daniel Bevenius Howard Hellyer Chris Araman +Vladimir Matveev +Jason Madden +Jamie Davis +Daniel Kahn Gillmor +Keane +James McCoy +Bernardo Ramos +Juan Cruz Viotti diff --git a/ChangeLog b/ChangeLog index da4c3b13f..1d1614cab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,178 @@ +2017.05.31, Version 1.12.0 (Stable) + +Changes since version 1.11.0: + +* Now working on version 1.11.1 (cjihrig) + +* test: fix tests on OpenBSD (Santiago Gimeno) + +* test: fix -Wformat warning (Santiago Gimeno) + +* win,fs: avoid double freeing uv_fs_event_t.dirw (Vladimir Matveev) + +* unix: remove unused code in `uv__io_start` (Fedor Indutny) + +* signal: add uv_signal_start_oneshot method (Santiago Gimeno) + +* unix: factor out reusable POSIX hrtime impl (Brad King) + +* unix,win: add uv_os_{get,set,unset}env() (cjihrig) + +* win: add uv__convert_utf8_to_utf16() (cjihrig) + +* docs: improve UV_ENOBUFS scenario documentation (cjihrig) + +* unix: return UV_EINVAL for NULL env name (jBarz) + +* unix: filter getifaddrs results consistently (Brad King) + +* unix: factor out getifaddrs result filter (Brad King) + +* unix: factor out reusable BSD ifaddrs impl (Brad King) + +* unix: use union to follow strict aliasing rules (jBarz) + +* unix: simplify async watcher dispatch logic (Ben Noordhuis) + +* samples: update timer callback prototype (Ben Noordhuis) + +* unix: make loops and watchers usable after fork() (Jason Madden) + +* win: free uv__loops once empty (cjihrig) + +* tools: add make_dist_html.py script (Ben Noordhuis) + +* win,sunos: stop handle on uv_fs_event_start() err (cjihrig) + +* unix,windows: refactor request init logic (Ben Noordhuis) + +* win: fix memory leak inside uv__pipe_getname (A. Hauptmann) + +* fsevent: support for files without short name (Bartosz Sosnowski) + +* doc: fix multiple doc typos (Jamie Davis) + +* test,osx: fix flaky kill test (Santiago Gimeno) + +* unix: inline uv_pipe_bind() err_bind goto target (cjihrig) + +* unix,test: deadstore fixes (Rasmus Christian Pedersen) + +* win: fix memory leak inside uv_fs_access() (A. Hauptmann) + +* doc: fix docs/src/fs.rst build warning (Daniel Bevenius) + +* doc: minor grammar fix in Installation section (Daniel Bevenius) + +* doc: suggestions for design page (Daniel Bevenius) + +* doc: libuv does not touch uv_loop_t.data (Ben Noordhuis) + +* github: add ISSUE_TEMPLATE.md (Ben Noordhuis) + +* doc: add link to libuv/help to README (Ben Noordhuis) + +* udp: fix fast path in uv_udp_send() on unix (Fedor Indutny) + +* test: add test for uv_udp_send() fix (Trevor Norris) + +* doc: fix documentation for uv_handle_t.type (Daniel Kahn Gillmor) + +* zos: use proper prototype for epoll_init() (Ben Noordhuis) + +* doc: rename docs to "libuv documentation" (Saúl Ibarra Corretgé) + +* doc: update copyright years (Saúl Ibarra Corretgé) + +* doc: move TOC to a dedicated document (Saúl Ibarra Corretgé) + +* doc: move documentation section up (Saúl Ibarra Corretgé) + +* doc: move "upgrading" to a standalone document (Saúl Ibarra Corretgé) + +* doc: add initial version of the User Guide (Saúl Ibarra Corretgé) + +* doc: removed unused file (Saúl Ibarra Corretgé) + +* doc: update guide/about and mention new maintainership (Saúl Ibarra Corretgé) + +* doc: remove licensing note from guide/about (Saúl Ibarra Corretgé) + +* doc: add warning note to user guide (Saúl Ibarra Corretgé) + +* doc: change license to CC BY 4.0 (Saúl Ibarra Corretgé) + +* doc: remove ubvook reference from README (Saúl Ibarra Corretgé) + +* doc: add code samples from uvbook (unadapted) (Saúl Ibarra Corretgé) + +* doc: update supported linux/glibc baseline (Ben Noordhuis) + +* win: avoid leaking pipe handles to child processes (Jameson Nash) + +* win,test: support stdout output larger than 1kb (Bartosz Sosnowski) + +* win: remove __declspec(inline) from atomic op (Keane) + +* test: fix VC++ compilation warning (Rasmus Christian Pedersen) + +* build: add -Wstrict-prototypes (Jameson Nash) + +* zos: implement uv__io_fork, skip fs event tests (jBarz) + +* unix: do not close udp sockets on bind error (Marc Schlaich) + +* unix: remove FSEventStreamFlushSync() call (cjihrig) + +* build,openbsd: remove kvm-related code (James McCoy) + +* test: fix flaky tcp-write-queue-order (Santiago Gimeno) + +* unix,win: add uv_os_gethostname() (cjihrig) + +* zos: increase timeout for tcp_writealot (jBarz) + +* zos: do not inline OOB data by default (jBarz) + +* test: fix -Wstrict-prototypes compiler warnings (Ben Noordhuis) + +* unix: factor out reusable no-proctitle impl (Brad King) + +* test: factor out fsevents skip explanation (Brad King) + +* test: skip fork fsevent cases when lacking support (Brad King) + +* unix: factor out reusable no-fsevents impl (Brad King) + +* unix: factor out reusable sysinfo memory lookup (Brad King) + +* unix: factor out reusable sysinfo loadavg impl (Brad King) + +* unix: factor out reusable procfs exepath impl (Brad King) + +* unix: add a uv__io_poll impl using POSIX poll(2) (Brad King) + +* cygwin: implement support for cygwin and msys2 (Brad King) + +* cygwin: recognize EOF on named pipe closure (Brad King) + +* cygwin: fix uv_pipe_connect report of ENOTSOCK (Brad King) + +* cygwin: disable non-functional ipc handle send (Brad King) + +* test: skip self-connecting tests on cygwin (Brad King) + +* doc: mark uv_loop_fork() as experimental (cjihrig) + +* doc: add bzoz to maintainers (Bartosz Sosnowski) + +* doc: fix memory leak in tcp-echo-server example (Bernardo Ramos) + +* win: make uv__get_osfhandle() public (Juan Cruz Viotti) + +* doc: use valid pipe name in pipe-echo-server (Bernardo Ramos) + + 2017.02.02, Version 1.11.0 (Stable), 7452ef4e06a4f99ee26b694c65476401534f2725 Changes since version 1.10.2: diff --git a/appveyor.yml b/appveyor.yml index e8e79f051..c542e34b9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.11.0.build{build} +version: v1.12.0.build{build} install: - cinst -y nsis diff --git a/configure.ac b/configure.ac index 593a6196c..8ac06f7fc 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.11.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.12.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 e16580903..34d4a43f9 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 11 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 12 +#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 e05d171682b5155be0446af915588d7e0d203ebb Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 30 May 2017 12:18:20 -0400 Subject: [PATCH 405/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 1d1614cab..71b210f44 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017.05.31, Version 1.12.0 (Stable) +2017.05.31, Version 1.12.0 (Stable), d6ac141ac674657049598c36604f26e031fae917 Changes since version 1.11.0: From 42bf398b8019041e6f5c07a0709add4e09b3a586 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 30 May 2017 12:36:19 -0400 Subject: [PATCH 406/632] Now working on version 1.12.1 --- 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 34d4a43f9..77bd262f4 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 12 -#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 f2756500ed8fc14ba11cf5bf0a3cee6f3b66eecb Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Thu, 25 May 2017 08:58:24 +0200 Subject: [PATCH 407/632] unix: avoid segfault in uv_get_process_title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/1359 PR-URL: https://github.com/libuv/libuv/pull/1360 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/unix/proctitle.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/unix/proctitle.c b/src/unix/proctitle.c index 9160f7eaf..2ed0b21c6 100644 --- a/src/unix/proctitle.c +++ b/src/unix/proctitle.c @@ -98,7 +98,9 @@ int uv_get_process_title(char* buffer, size_t size) { else if (size <= process_title.len) return -ENOBUFS; - memcpy(buffer, process_title.str, process_title.len + 1); + if (process_title.len != 0) + memcpy(buffer, process_title.str, process_title.len + 1); + buffer[process_title.len] = '\0'; return 0; From 57f4180cf3e8c26417913b8f8da20eceead3d890 Mon Sep 17 00:00:00 2001 From: Gemini Wen Date: Sat, 3 Jun 2017 18:45:32 +0800 Subject: [PATCH 408/632] build: add a comma to uv.gyp PR-URL: https://github.com/libuv/libuv/pull/1368 Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis --- uv.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.gyp b/uv.gyp index a3a42787b..55edf2237 100644 --- a/uv.gyp +++ b/uv.gyp @@ -253,7 +253,7 @@ 'src/unix/linux-syscalls.h', 'src/unix/pthread-fixes.c', 'src/unix/android-ifaddrs.c', - 'src/unix/pthread-barrier.c' + 'src/unix/pthread-barrier.c', 'src/unix/procfs-exepath.c', 'src/unix/sysinfo-loadavg.c', 'src/unix/sysinfo-memory.c', From 0bd8f5bf36b4164b071af6b0bb68c814cf7dedf8 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Wed, 21 Jun 2017 12:47:00 +0200 Subject: [PATCH 409/632] win: restore file pos after positional read/write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit File read or write from specified position will move file pointer on Windows but not on POSIX. This makes Windows behave as other supported platforms. Ref: https://github.com/nodejs/node/issues/9671 PR-URL: https://github.com/libuv/libuv/pull/1357 Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs.c | 24 ++++++++++++++++++++++++ test/test-fs.c | 40 ++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 3 files changed, 66 insertions(+) diff --git a/src/win/fs.c b/src/win/fs.c index 2d72cdc70..8223d6f65 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -556,9 +556,14 @@ void fs__read(uv_fs_t* req) { DWORD error; int result; unsigned int index; + LARGE_INTEGER original_position; + LARGE_INTEGER zero_offset; + int restore_position; VERIFY_FD(fd, req); + zero_offset.QuadPart = 0; + restore_position = 0; handle = uv__get_osfhandle(fd); if (handle == INVALID_HANDLE_VALUE) { @@ -569,6 +574,10 @@ void fs__read(uv_fs_t* req) { if (offset != -1) { memset(&overlapped, 0, sizeof overlapped); overlapped_ptr = &overlapped; + if (SetFilePointerEx(handle, zero_offset, &original_position, + FILE_CURRENT)) { + restore_position = 1; + } } else { overlapped_ptr = NULL; } @@ -593,6 +602,9 @@ void fs__read(uv_fs_t* req) { ++index; } while (result && index < req->fs.info.nbufs); + if (restore_position) + SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN); + if (result || bytes > 0) { SET_REQ_RESULT(req, bytes); } else { @@ -615,9 +627,14 @@ void fs__write(uv_fs_t* req) { DWORD bytes; int result; unsigned int index; + LARGE_INTEGER original_position; + LARGE_INTEGER zero_offset; + int restore_position; VERIFY_FD(fd, req); + zero_offset.QuadPart = 0; + restore_position = 0; handle = uv__get_osfhandle(fd); if (handle == INVALID_HANDLE_VALUE) { SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE); @@ -627,6 +644,10 @@ void fs__write(uv_fs_t* req) { if (offset != -1) { memset(&overlapped, 0, sizeof overlapped); overlapped_ptr = &overlapped; + if (SetFilePointerEx(handle, zero_offset, &original_position, + FILE_CURRENT)) { + restore_position = 1; + } } else { overlapped_ptr = NULL; } @@ -651,6 +672,9 @@ void fs__write(uv_fs_t* req) { ++index; } while (result && index < req->fs.info.nbufs); + if (restore_position) + SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN); + if (result || bytes > 0) { SET_REQ_RESULT(req, bytes); } else { diff --git a/test/test-fs.c b/test/test-fs.c index c482ab5c7..404d0426f 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2804,3 +2804,43 @@ TEST_IMPL(get_osfhandle_valid_handle) { MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(fs_file_pos_after_op_with_offset) { + int r; + + /* Setup. */ + unlink("test_file"); + loop = uv_default_loop(); + + r = uv_fs_open(loop, + &open_req1, + "test_file", + O_RDWR | O_CREAT, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(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); + 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); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_close(NULL, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + + /* Cleanup */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 3571aa230..9477e0de1 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -308,6 +308,7 @@ TEST_DECLARE (fs_read_write_null_arguments) TEST_DECLARE (get_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) TEST_DECLARE (threadpool_queue_work_simple) TEST_DECLARE (threadpool_queue_work_einval) TEST_DECLARE (threadpool_multiple_event_loops) @@ -793,6 +794,7 @@ TASK_LIST_START TEST_ENTRY (fs_write_alotof_bufs) TEST_ENTRY (fs_write_alotof_bufs_with_offset) TEST_ENTRY (fs_read_write_null_arguments) + TEST_ENTRY (fs_file_pos_after_op_with_offset) TEST_ENTRY (get_osfhandle_valid_handle) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) From 404ee42706084025b53e9fd98ba42fddc35c6132 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sun, 14 May 2017 17:23:16 +0200 Subject: [PATCH 410/632] unix,stream: return error on closed handle passing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return `EBADF` when trying to send a handle which, while enqueued, was closed. Fixes: https://github.com/libuv/libuv/issues/806 PR-URL: https://github.com/libuv/libuv/pull/1352 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/unix/stream.c | 30 ++++++++++----- test/run-tests.c | 5 +++ test/test-ipc.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 6 +++ 4 files changed, 128 insertions(+), 9 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 7b23d16ec..f8e95ea3e 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -750,6 +750,7 @@ static void uv__write(uv_stream_t* stream) { int iovmax; int iovcnt; ssize_t n; + int err; start: @@ -782,14 +783,21 @@ static void uv__write(uv_stream_t* stream) { */ if (req->send_handle) { + int fd_to_send; struct msghdr msg; struct cmsghdr *cmsg; - int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); union { char data[64]; struct cmsghdr alias; } scratch; + if (uv__is_closing(req->send_handle)) { + err = -EBADF; + goto error; + } + + fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); + memset(&scratch, 0, sizeof(scratch)); assert(fd_to_send >= 0); @@ -852,14 +860,8 @@ static void uv__write(uv_stream_t* stream) { if (n < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { - /* Error */ - req->error = -errno; - 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); - return; + err = -errno; + goto error; } else if (stream->flags & UV_STREAM_BLOCKING) { /* If this is a blocking stream, try again. */ goto start; @@ -923,6 +925,16 @@ static void uv__write(uv_stream_t* stream) { /* Notify select() thread about state change */ uv__stream_osx_interrupt_select(stream); + + return; + +error: + req->error = err; + 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); } diff --git a/test/run-tests.c b/test/run-tests.c index 1e344f050..4e10b68f3 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -38,6 +38,7 @@ int ipc_helper(int listen_after_write); 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 stdio_over_pipes_helper(void); @@ -89,6 +90,10 @@ 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 a2fda2458..88d63d4dc 100644 --- a/test/test-ipc.c +++ b/test/test-ipc.c @@ -44,6 +44,7 @@ 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; typedef struct { uv_connect_t conn_req; @@ -53,6 +54,7 @@ typedef struct { #define CONN_COUNT 100 #define BACKLOG 128 +#define LARGE_SIZE 1000000 static void close_server_conn_cb(uv_handle_t* handle) { @@ -395,6 +397,26 @@ 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 int run_ipc_test(const char* helper, uv_read_cb read_cb) { uv_process_t process; int r; @@ -448,6 +470,15 @@ 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(r == 0); + return 0; +} +#endif + #ifdef _WIN32 TEST_IMPL(listen_with_simultaneous_accepts) { @@ -536,6 +567,17 @@ 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(status == 0); + ASSERT(closed_handle_data_read = LARGE_SIZE); +} + + +static void closed_handle_write_cb(uv_write_t* req, int status) { + ASSERT(status == UV_EBADF); +} + + static void on_tcp_child_process_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { @@ -742,6 +784,60 @@ int ipc_helper_tcp_connection(void) { return 0; } + +int ipc_helper_closed_handle(void) { + int r; + struct sockaddr_in addr; + uv_write_t write_req; + uv_write_t write_req2; + uv_buf_t buf; + char buffer[LARGE_SIZE]; + + r = uv_pipe_init(uv_default_loop(), &channel, 1); + ASSERT(r == 0); + + uv_pipe_open(&channel, 0); + + ASSERT(1 == uv_is_readable((uv_stream_t*) &channel)); + ASSERT(1 == uv_is_writable((uv_stream_t*) &channel)); + ASSERT(0 == uv_is_closing((uv_handle_t*) &channel)); + + memset(buffer, '.', LARGE_SIZE); + buf = uv_buf_init(buffer, LARGE_SIZE); + + r = uv_tcp_init(uv_default_loop(), &tcp_server); + ASSERT(r == 0); + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + + r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_write(&write_req, + (uv_stream_t*)&channel, + &buf, + 1, + closed_handle_large_write_cb); + ASSERT(r == 0); + + r = uv_write2(&write_req2, + (uv_stream_t*)&channel, + &buf, + 1, + (uv_stream_t*)&tcp_server, + closed_handle_write_cb); + ASSERT(r == 0); + + uv_close((uv_handle_t*)&tcp_server, NULL); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + 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 9477e0de1..0c32d84d2 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -63,6 +63,9 @@ TEST_DECLARE (ipc_send_recv_pipe_inprocess) TEST_DECLARE (ipc_send_recv_tcp) TEST_DECLARE (ipc_send_recv_tcp_inprocess) TEST_DECLARE (ipc_tcp_connection) +#ifndef _WIN32 +TEST_DECLARE (ipc_closed_handle) +#endif TEST_DECLARE (tcp_alloc_cb_fail) TEST_DECLARE (tcp_ping_pong) TEST_DECLARE (tcp_ping_pong_v6) @@ -444,6 +447,9 @@ TASK_LIST_START TEST_ENTRY (ipc_send_recv_tcp) TEST_ENTRY (ipc_send_recv_tcp_inprocess) TEST_ENTRY (ipc_tcp_connection) +#ifndef _WIN32 + TEST_ENTRY (ipc_closed_handle) +#endif TEST_ENTRY (tcp_alloc_cb_fail) From d4f3a42ec74e8596fb88c1c56db57a86cc6470bb Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 31 May 2017 06:08:44 -0400 Subject: [PATCH 411/632] unix,benchmark: use fd instead of FILE* after fork The FILE* object is not guaranteed to be in the same state after a fork. Instead store the file descriptor instead and use that in the child process. PR-URL: https://github.com/libuv/libuv/pull/1369 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- test/runner-unix.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/runner-unix.c b/test/runner-unix.c index 2ff18ce75..3167ed44b 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -61,12 +61,14 @@ int platform_init(int argc, char **argv) { /* Make sure that all stdio output of the processes is buffered up. */ int process_start(char* name, char* part, process_info_t* p, int is_helper) { FILE* stdout_file; + int stdout_fd; const char* arg; char* args[16]; int n; pid_t pid; stdout_file = tmpfile(); + stdout_fd = fileno(stdout_file); if (!stdout_file) { perror("tmpfile"); return -1; @@ -103,8 +105,8 @@ int process_start(char* name, char* part, process_info_t* p, int is_helper) { args[n++] = part; args[n++] = NULL; - dup2(fileno(stdout_file), STDOUT_FILENO); - dup2(fileno(stdout_file), STDERR_FILENO); + dup2(stdout_fd, STDOUT_FILENO); + dup2(stdout_fd, STDERR_FILENO); execvp(args[0], args); perror("execvp()"); _exit(127); From d5fc593b5f511386bef526cd454b473614de4a1f Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 31 May 2017 06:08:44 -0400 Subject: [PATCH 412/632] zos: avoid compiler warnings Some of these compiler flags are not supported. So don't use them. PR-URL: https://github.com/libuv/libuv/pull/1373 Reviewed-By: Colin Ihrig --- common.gypi | 12 +++++++++--- src/unix/core.c | 5 ++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/common.gypi b/common.gypi index 94e760030..ec482340c 100644 --- a/common.gypi +++ b/common.gypi @@ -49,9 +49,6 @@ 'cflags': [ '-O3', '-fstrict-aliasing', - '-fomit-frame-pointer', - '-fdata-sections', - '-ffunction-sections', ], 'msvs_settings': { 'VCCLCompilerTool': { @@ -82,6 +79,15 @@ 'LinkIncremental': 1, # disable incremental linking }, }, + 'conditions': [ + ['OS != "os390"', { + 'cflags': [ + '-fomit-frame-pointer', + '-fdata-sections', + '-ffunction-sections', + ], + }], + ] } }, 'msvs_settings': { diff --git a/src/unix/core.c b/src/unix/core.c index 8276c6041..4c744925e 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -28,7 +28,6 @@ #include #include #include -#include /* MAXHOSTNAMELEN on Linux and the BSDs */ #include #include #include @@ -82,6 +81,10 @@ #include #endif +#if !defined(__MVS__) +#include /* MAXHOSTNAMELEN on Linux and the BSDs */ +#endif + /* Fallback for the maximum hostname length */ #ifndef MAXHOSTNAMELEN # define MAXHOSTNAMELEN 256 From c42a4ca372b8476c78c026cab856694830735490 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 16 Jul 2015 01:54:28 -0400 Subject: [PATCH 413/632] win,pipe: race condition canceling readfile thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a race condition where if uv_read_stop was called shortly after uv_read_start or a successful read and before the uv_pipe_zero_readfile_thread_proc thread started, that thread would call the blocking ReadFile call after the HANDLE_READING flag had already been cleared. Also ignores EINTR to be more consistent with unix (although we generally don't expect to see this condition on windows). PR-URL: https://github.com/libuv/libuv/pull/1322 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Bartosz Sosnowski --- src/win/pipe.c | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index edf300212..9b10cc9fe 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -968,27 +968,31 @@ static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) { uv_mutex_unlock(m); } restart_readfile: - result = ReadFile(handle->handle, - &uv_zero_, - 0, - &bytes, - NULL); - if (!result) { - err = GetLastError(); - if (err == ERROR_OPERATION_ABORTED && - handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { - if (handle->flags & UV_HANDLE_READING) { - /* just a brief break to do something else */ - handle->pipe.conn.readfile_thread = NULL; - /* resume after it is finished */ - uv_mutex_lock(m); - handle->pipe.conn.readfile_thread = hThread; - uv_mutex_unlock(m); - goto restart_readfile; - } else { - result = 1; /* successfully stopped reading */ + if (handle->flags & UV_HANDLE_READING) { + result = ReadFile(handle->handle, + &uv_zero_, + 0, + &bytes, + NULL); + if (!result) { + err = GetLastError(); + if (err == ERROR_OPERATION_ABORTED && + handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { + if (handle->flags & UV_HANDLE_READING) { + /* just a brief break to do something else */ + handle->pipe.conn.readfile_thread = NULL; + /* resume after it is finished */ + uv_mutex_lock(m); + handle->pipe.conn.readfile_thread = hThread; + uv_mutex_unlock(m); + goto restart_readfile; + } else { + result = 1; /* successfully stopped reading */ + } } } + } else { + result = 1; /* successfully aborted read before it even started */ } if (hThread) { assert(hThread == handle->pipe.conn.readfile_thread); @@ -1515,7 +1519,10 @@ 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) { - if (error == ERROR_BROKEN_PIPE) { + if (error == ERROR_OPERATION_ABORTED) { + /* do nothing (equivalent to EINTR) */ + } + else if (error == ERROR_BROKEN_PIPE) { uv_pipe_read_eof(loop, handle, buf); } else { uv_pipe_read_error(loop, handle, error, buf); From 26daa99e2c93db2692933e8d141e44661a444e68 Mon Sep 17 00:00:00 2001 From: Sebastian Wiedenroth Date: Mon, 26 Jun 2017 23:29:00 +0200 Subject: [PATCH 414/632] sunos: filter out non-IPv4/IPv6 interfaces Filter out anything that is not an IPv4 or IPv6 interface in uv_interface_addresses(). PR-URL: https://github.com/libuv/libuv/pull/1387 Reviewed-By: Ben Noordhuis --- src/unix/sunos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 2dc02ae45..49de5a7fc 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -747,7 +747,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) { return 1; if (ent->ifa_addr == NULL) return 1; - if (ent->ifa_addr->sa_family == PF_PACKET) + if (ent->ifa_addr->sa_family != AF_INET && + ent->ifa_addr->sa_family != AF_INET6) return 1; return 0; } From d0a27baa7d46efe2dd26bcd103af847a6bc8b349 Mon Sep 17 00:00:00 2001 From: Sai Ke WANG Date: Thu, 25 May 2017 15:18:24 -0400 Subject: [PATCH 415/632] sunos: fix cmpxchgi and cmpxchgl type error atomic_cas_ptr() is for compare-and-swap pointer addresses. So when building 64 bit: 1. `ptr` is used casted to a pointer value (4-byte into 8-byte). 2. atomic_cas_ptr reads 8-byte at `ptr` and returns In the case of `uv_async_send`, if handle->pending is 0, cmpxchgi() actually returns the value of the 4-bytes past handle->pending, causing uv__async_send to never be called. The modified test-async-null-cb.c hangs at uv_run in this case. PR-URL: https://github.com/libuv/libuv/pull/1361 Reviewed-By: Ben Noordhuis --- src/unix/atomic-ops.h | 5 ++++- test/test-async-null-cb.c | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/unix/atomic-ops.h b/src/unix/atomic-ops.h index 9dac2557f..7cac1f988 100644 --- a/src/unix/atomic-ops.h +++ b/src/unix/atomic-ops.h @@ -20,7 +20,6 @@ #if defined(__SUNPRO_C) || defined(__SUNPRO_CC) #include -#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n) #endif UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)); @@ -49,6 +48,8 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { return oldval; else return op4; +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) + return atomic_cas_uint(ptr, oldval, newval); #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif @@ -83,6 +84,8 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) { return oldval; else return op4; +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) + return atomic_cas_ulong(ptr, oldval, newval); #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif diff --git a/test/test-async-null-cb.c b/test/test-async-null-cb.c index 757944a27..52652d91e 100644 --- a/test/test-async-null-cb.c +++ b/test/test-async-null-cb.c @@ -21,6 +21,7 @@ #include "uv.h" #include "task.h" +#include static uv_async_t async_handle; static uv_check_t check_handle; @@ -43,6 +44,14 @@ static void check_cb(uv_check_t* handle) { TEST_IMPL(async_null_cb) { + /* + * Fill async_handle with garbage values. + * uv_async_init() should properly initialize struct fields regardless of + * initial values. + * This is added to verify paddings between fields do not affect behavior. + */ + 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)); From 28eb1d44f58b02548258209e764b02aabdbda50b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 14 Jun 2017 12:15:40 +0200 Subject: [PATCH 416/632] unix: reset signal disposition before execve() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signal dispositions are inherited by child processes. Libuv itself does not touch them (if you don't use uv_signal_start(), that is) but the embedder might and probably does in the case of SIGPIPE. Reset the disposition for signals 1-31 to their defaults right before execve'ing into the new process. Fixes: https://github.com/nodejs/node/issues/13662 PR-URL: https://github.com/libuv/libuv/pull/1376 Reviewed-By: Colin Ihrig Reviewed-By: Fedor Indutny Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/unix/process.c | 17 +++++++++++++++++ test/test-spawn.c | 9 +++++++++ 2 files changed, 26 insertions(+) diff --git a/src/unix/process.c b/src/unix/process.c index f2fe30521..af44bc5d4 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -282,6 +282,7 @@ static void uv__process_child_init(const uv_process_options_t* options, int close_fd; int use_fd; int fd; + int n; if (options->flags & UV_PROCESS_DETACHED) setsid(); @@ -376,6 +377,22 @@ 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 (SIG_ERR != signal(n, SIG_DFL)) + continue; + + uv__write_int(error_fd, -errno); + _exit(127); + } + execvp(options->file, options->args); uv__write_int(error_fd, -errno); _exit(127); diff --git a/test/test-spawn.c b/test/test-spawn.c index 52fc7f6cc..1ec6bc13f 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -929,9 +929,18 @@ TEST_IMPL(kill) { init_process_options("spawn_helper4", kill_cb); + /* Verify that uv_spawn() resets the signal disposition. */ +#ifndef _WIN32 + ASSERT(SIG_ERR != signal(SIGTERM, SIG_IGN)); +#endif + r = uv_spawn(uv_default_loop(), &process, &options); ASSERT(r == 0); +#ifndef _WIN32 + ASSERT(SIG_ERR != signal(SIGTERM, SIG_DFL)); +#endif + /* Sending signum == 0 should check if the * child process is still alive, not kill it. */ From 11563e179f2670b0918575e3ba7553c9e27b1aac Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 14 Jun 2017 12:32:40 +0200 Subject: [PATCH 417/632] unix: reset signal mask before execve() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like the previous commit, except now the signal mask is reset instead of the signal disposition. This does open a race window where blocked signals can get delivered in the interval between the pthread_sigmask() call and the execve() call (and may end up terminating the process) but that cannot be helped; the same caveat applies to the previous commit. Fixes: https://github.com/nodejs/node/issues/13662 PR-URL: https://github.com/libuv/libuv/pull/1376 Reviewed-By: Colin Ihrig Reviewed-By: Fedor Indutny Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/unix/process.c | 11 +++++++++++ test/test-spawn.c | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/unix/process.c b/src/unix/process.c index af44bc5d4..80b9686ec 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -279,8 +279,10 @@ static void uv__process_child_init(const uv_process_options_t* options, int stdio_count, int (*pipes)[2], int error_fd) { + sigset_t set; int close_fd; int use_fd; + int err; int fd; int n; @@ -393,6 +395,15 @@ static void uv__process_child_init(const uv_process_options_t* options, _exit(127); } + /* Reset signal mask. */ + sigemptyset(&set); + err = pthread_sigmask(SIG_SETMASK, &set, NULL); + + if (err != 0) { + uv__write_int(error_fd, -err); + _exit(127); + } + execvp(options->file, options->args); uv__write_int(error_fd, -errno); _exit(127); diff --git a/test/test-spawn.c b/test/test-spawn.c index 1ec6bc13f..bb35e32b2 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -931,6 +931,12 @@ TEST_IMPL(kill) { /* Verify that uv_spawn() resets the signal disposition. */ #ifndef _WIN32 + { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGTERM); + ASSERT(0 == pthread_sigmask(SIG_BLOCK, &set, NULL)); + } ASSERT(SIG_ERR != signal(SIGTERM, SIG_IGN)); #endif @@ -938,6 +944,12 @@ TEST_IMPL(kill) { ASSERT(r == 0); #ifndef _WIN32 + { + sigset_t set; + sigemptyset(&set); + sigaddset(&set, SIGTERM); + ASSERT(0 == pthread_sigmask(SIG_UNBLOCK, &set, NULL)); + } ASSERT(SIG_ERR != signal(SIGTERM, SIG_DFL)); #endif From 391e818c4a1000ef00644ec419f757b09784b584 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Tue, 27 Jun 2017 02:41:45 -0400 Subject: [PATCH 418/632] unix: fix POLLIN assertion on server read Certain systems like z/OS have more than one bit turned on for POLLIN events. (e.g. #define POLLIN 0x03). Asserting that all bits are turned on would be invalid. Instead, assert that *any* of those bits are turned on. PR-URL: https://github.com/libuv/libuv/pull/1390 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/unix/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index f8e95ea3e..c502098dc 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -514,7 +514,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int err; stream = container_of(w, uv_stream_t, io_watcher); - assert(events == POLLIN); + assert(events & POLLIN); assert(stream->accepted_fd == -1); assert(!(stream->flags & UV_CLOSING)); From 4776195cdf6e787c42c3e1c7bafaab1e9bc1f419 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Tue, 27 Jun 2017 02:16:42 -0400 Subject: [PATCH 419/632] zos: use stckf builtin for high-res timer Instead of gettimeofday which is too heavy for a fast monotonic clock implementation. PR-URL: https://github.com/libuv/libuv/pull/1394 Reviewed-By: Ben Noordhuis --- src/unix/os390.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index 2ba5abf35..de7df9116 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -25,6 +25,7 @@ #include #include #include +#include #if defined(__clang__) #include "csrsic.h" #else @@ -118,9 +119,10 @@ void uv__platform_loop_delete(uv_loop_t* loop) { uint64_t uv__hrtime(uv_clocktype_t type) { - struct timeval time; - gettimeofday(&time, NULL); - return (uint64_t) time.tv_sec * 1e9 + time.tv_usec * 1e3; + unsigned long long timestamp; + __stckf(×tamp); + /* Convert to nanoseconds */ + return timestamp / 10; } From c33fe9874a4982f47644706ef72b8333e1650232 Mon Sep 17 00:00:00 2001 From: Barnabas Gema Date: Thu, 26 Jan 2017 16:40:56 +0100 Subject: [PATCH 420/632] win,udp: implements uv_udp_try_send MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1385 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno --- src/win/udp.c | 37 ++++++++++++++++++++++++++++++++++++- test/test-udp-try-send.c | 12 ------------ 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/win/udp.c b/src/win/udp.c index 2fd15cfa9..72be23c6d 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -922,5 +922,40 @@ int uv__udp_try_send(uv_udp_t* handle, unsigned int nbufs, const struct sockaddr* addr, unsigned int addrlen) { - return UV_ENOSYS; + DWORD bytes; + const struct sockaddr* bind_addr; + int err; + + assert(nbufs > 0); + + /* Already sending a message.*/ + if (handle->send_queue_count != 0) + return UV_EAGAIN; + + if (!(handle->flags & UV_HANDLE_BOUND)) { + if (addrlen == sizeof(uv_addr_ip4_any_)) + bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_; + else if (addrlen == sizeof(uv_addr_ip6_any_)) + bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; + else + abort(); + err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); + if (err) + return uv_translate_sys_error(err); + } + + err = WSASendTo(handle->socket, + (WSABUF*)bufs, + nbufs, + &bytes, + 0, + addr, + addrlen, + NULL, + NULL); + + if (err) + return uv_translate_sys_error(WSAGetLastError()); + + return bytes; } diff --git a/test/test-udp-try-send.c b/test/test-udp-try-send.c index 7b6de3654..a31d38229 100644 --- a/test/test-udp-try-send.c +++ b/test/test-udp-try-send.c @@ -26,16 +26,6 @@ #include #include -#ifdef _WIN32 - -TEST_IMPL(udp_try_send) { - - MAKE_VALGRIND_HAPPY(); - return 0; -} - -#else /* !_WIN32 */ - #define CHECK_HANDLE(handle) \ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) @@ -129,5 +119,3 @@ TEST_IMPL(udp_try_send) { MAKE_VALGRIND_HAPPY(); return 0; } - -#endif /* !_WIN32 */ From 500a1f96ebc2b26055518af6f30a12be036f1ab3 Mon Sep 17 00:00:00 2001 From: Romain Caire Date: Mon, 26 Jun 2017 12:47:14 +0200 Subject: [PATCH 421/632] win,udp: return UV_EINVAL instead of aborting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1385 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno --- src/win/udp.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/win/udp.c b/src/win/udp.c index 72be23c6d..21348f379 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -897,13 +897,12 @@ int uv__udp_send(uv_udp_send_t* req, int err; if (!(handle->flags & UV_HANDLE_BOUND)) { - if (addrlen == sizeof(uv_addr_ip4_any_)) { + if (addrlen == sizeof(uv_addr_ip4_any_)) bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_; - } else if (addrlen == sizeof(uv_addr_ip6_any_)) { + else if (addrlen == sizeof(uv_addr_ip6_any_)) bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; - } else { - abort(); - } + else + return UV_EINVAL; err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); if (err) return uv_translate_sys_error(err); @@ -938,7 +937,7 @@ int uv__udp_try_send(uv_udp_t* handle, else if (addrlen == sizeof(uv_addr_ip6_any_)) bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; else - abort(); + return UV_EINVAL; err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); if (err) return uv_translate_sys_error(err); From 4987b6325b40b4bb06e8597956da0f0d0c5dbcbb Mon Sep 17 00:00:00 2001 From: Robert Ayrapetyan Date: Wed, 14 Jun 2017 16:35:14 -0700 Subject: [PATCH 422/632] freebsd: replace kvm with sysctl PR-URL: https://github.com/libuv/libuv/pull/1377 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- configure.ac | 4 +--- src/unix/freebsd.c | 35 +++++++++++++++-------------------- uv.gyp | 6 +++--- 3 files changed, 19 insertions(+), 26 deletions(-) diff --git a/configure.ac b/configure.ac index 8ac06f7fc..ebe35aced 100644 --- a/configure.ac +++ b/configure.ac @@ -66,9 +66,7 @@ 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], [openbsd*], [], [ - AC_CHECK_LIB([kvm], [kvm_open]) -]) +AS_CASE([$host_os], [netbsd*], [AC_CHECK_LIB([kvm], [kvm_open])]) AC_CHECK_HEADERS([sys/ahafs_evProds.h]) AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes) AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" != "x"]) diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index e52ae99db..c3c4902be 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -203,35 +202,31 @@ int uv_get_process_title(char* buffer, size_t size) { return 0; } - int uv_resident_set_memory(size_t* rss) { - kvm_t *kd = NULL; - struct kinfo_proc *kinfo = NULL; - pid_t pid; - int nprocs; - size_t page_size = getpagesize(); + struct kinfo_proc kinfo; + size_t page_size; + size_t kinfo_size; + int mib[4]; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); - pid = getpid(); + kinfo_size = sizeof(kinfo); - kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); - if (kd == NULL) goto error; + if (sysctl(mib, 4, &kinfo, &kinfo_size, NULL, 0)) + return -errno; - kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs); - if (kinfo == NULL) goto error; + page_size = getpagesize(); #ifdef __DragonFly__ - *rss = kinfo->kp_vm_rssize * page_size; + *rss = kinfo.kp_vm_rssize * page_size; #else - *rss = kinfo->ki_rssize * page_size; + *rss = kinfo.ki_rssize * page_size; #endif - kvm_close(kd); - return 0; - -error: - if (kd) kvm_close(kd); - return -EPERM; } diff --git a/uv.gyp b/uv.gyp index 55edf2237..6f61d725a 100644 --- a/uv.gyp +++ b/uv.gyp @@ -302,12 +302,12 @@ 'sources': [ 'src/unix/openbsd.c' ], }], [ 'OS=="netbsd"', { - 'sources': [ 'src/unix/netbsd.c' ], - }], - [ 'OS in "freebsd dragonflybsd openbsd netbsd".split()', { 'link_settings': { 'libraries': [ '-lkvm' ], }, + 'sources': [ 'src/unix/netbsd.c' ], + }], + [ 'OS in "freebsd dragonflybsd openbsd netbsd".split()', { 'sources': [ 'src/unix/posix-hrtime.c' ], }], [ 'OS in "ios mac freebsd dragonflybsd openbsd netbsd".split()', { From 09444560fe59df5ceaaa89f745a3b042925b71e5 Mon Sep 17 00:00:00 2001 From: Gireesh Punathil Date: Tue, 4 Jul 2017 09:40:47 -0400 Subject: [PATCH 423/632] aix: fix un-initialized pointer field in fs handle On AIX, uv_fs_event_start() didn't always initialize handle->dir_filename. In this scenario, uv_fs_event_stop() would free the uninitialized pointer. This commit initialized handle->dir_filename to NULL in all cases. Fixes: https://github.com/nodejs/node/issues/13577 PR-URL: https://github.com/libuv/libuv/pull/1400 Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis --- src/unix/aix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/unix/aix.c b/src/unix/aix.c index 388c9cca9..426f7f473 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -855,6 +855,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv__io_init(&handle->event_watcher, uv__ahafs_event, fd); handle->path = uv__strdup(filename); handle->cb = cb; + handle->dir_filename = NULL; uv__io_start(handle->loop, &handle->event_watcher, POLLIN); From 19c896dd086abb351361eab54b7e88ed5ce8af08 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Mon, 3 Apr 2017 07:57:21 -0400 Subject: [PATCH 424/632] win,build: support building with VS2017 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detection is attempted with `vswhere`. PR-URL: https://github.com/libuv/libuv/pull/1284 Reviewed-By: Bartosz Sosnowski Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- tools/vswhere_usability_wrapper.cmd | 33 +++++++++++++++++++++++++++++ vcbuild.bat | 28 ++++++++++++++++++++---- 2 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 tools/vswhere_usability_wrapper.cmd diff --git a/tools/vswhere_usability_wrapper.cmd b/tools/vswhere_usability_wrapper.cmd new file mode 100644 index 000000000..e4acf03e1 --- /dev/null +++ b/tools/vswhere_usability_wrapper.cmd @@ -0,0 +1,33 @@ +:: Copyright 2017 - Refael Ackermann +:: Distributed under MIT style license or the libuv license +:: See accompanying file LICENSE at https://github.com/node4good/windows-autoconf +:: or libuv LICENSE file at https://github.com/libuv/libuv +:: version: 1.15.3 + +@if not defined DEBUG_HELPER @ECHO OFF +setlocal +set "InstallerPath=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer" +if not exist "%InstallerPath%" set "InstallerPath=%ProgramFiles%\Microsoft Visual Studio\Installer" +if not exist "%InstallerPath%" exit goto :no-vswhere +:: Manipulate %Path% for easier " handeling +set Path=%Path%;%InstallerPath% +where vswhere 2> nul > nul +if errorlevel 1 goto :no-vswhere +set VSWHERE_REQ=-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 +set VSWHERE_PRP=-property installationPath +set VSWHERE_LMT=-version "[15.0,16.0)" +vswhere -prerelease > nul +if "%~1"=="prerelase" set VSWHERE_WITH_PRERELASE=1 +if not errorlevel 1 if "%VSWHERE_WITH_PRERELASE%"=="1" set "VSWHERE_LMT=%VSWHERE_LMT% -prerelease" +SET VSWHERE_ARGS=-latest -products * %VSWHERE_REQ% %VSWHERE_PRP% %VSWHERE_LMT% +for /f "usebackq tokens=*" %%i in (`vswhere %VSWHERE_ARGS%`) do ( + endlocal + set "VCINSTALLDIR=%%i\VC\" + set "VS150COMNTOOLS=%%i\Common7\Tools\" + exit /B 0 +) + +:no-vswhere +endlocal +echo could not find "vswhere" +exit /B 1 \ No newline at end of file diff --git a/vcbuild.bat b/vcbuild.bat index 91f45b721..a86e23698 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -14,10 +14,11 @@ if /i "%1"=="/?" goto help @rem Process arguments. set config= set target=Build +set target_arch=ia32 +set target_env= set noprojgen= set nobuild= set run= -set target_arch=ia32 set vs_toolset=x86 set msbuild_platform=WIN32 set library=static_library @@ -29,6 +30,7 @@ if /i "%1"=="release" set config=Release&goto arg-ok if /i "%1"=="test" set run=run-tests.exe&goto arg-ok if /i "%1"=="bench" set run=run-benchmarks.exe&goto arg-ok if /i "%1"=="clean" set target=Clean&goto arg-ok +if /i "%1"=="vs2017" set target_env=vs2017&goto arg-ok if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok if /i "%1"=="nobuild" set nobuild=1&goto arg-ok if /i "%1"=="x86" set target_arch=ia32&set msbuild_platform=WIN32&set vs_toolset=x86&goto arg-ok @@ -41,10 +43,28 @@ shift goto next-arg :args-done -if defined WindowsSDKDir goto select-target -if defined VCINSTALLDIR goto select-target +@rem Look for Visual Studio 2017 only if explicitly requested. +if "%target_env%" NEQ "vs2017" goto vs-set-2015 +echo Looking for Visual Studio 2017 +@rem Check if VS2017 is already setup, and for the requested arch. +if "_%VisualStudioVersion%_" == "_15.0_" if "_%VSCMD_ARG_TGT_ARCH%_"=="_%vs_toolset%_" goto found_vs2017 +set "VSINSTALLDIR=" +call tools\vswhere_usability_wrapper.cmd +if "_%VCINSTALLDIR%_" == "__" goto vs-set-2015 +@rem Need to clear VSINSTALLDIR for vcvarsall to work as expected. +set vcvars_call="%VCINSTALLDIR%\Auxiliary\Build\vcvarsall.bat" %vs_toolset% +echo calling: %vcvars_call% +call %vcvars_call% + +:found_vs2017 +echo Found MSVS version %VisualStudioVersion% +if %VSCMD_ARG_TGT_ARCH%==x64 set target_arch=x64&set msbuild_platform=x64&set vs_toolset=x64 +set GYP_MSVS_VERSION=2017 +goto select-target + @rem Look for Visual Studio 2015 +:vs-set-2015 if not defined VS140COMNTOOLS goto vc-set-2013 if not exist "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2013 call "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% @@ -148,7 +168,7 @@ echo Failed to create vc project files. exit /b 1 :help -echo vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [x86/x64] [static/shared] +echo vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [vs2017] [x86/x64] [static/shared] echo Examples: echo vcbuild.bat : builds debug build echo vcbuild.bat test : builds debug build and runs tests From 0953bf0dad50d0dc77fec2deefe1c5b6c5c3f020 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Tue, 4 Jul 2017 09:07:29 -0400 Subject: [PATCH 425/632] doc: add instructions for building on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1284 Reviewed-By: Bartosz Sosnowski Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- README.md | 66 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index e5d94faf0..1b74d39e0 100644 --- a/README.md +++ b/README.md @@ -152,18 +152,56 @@ To build with autotools: ### Windows -First, [Python][] 2.6 or 2.7 must be installed as it is required by [GYP][]. -If python is not in your path, set the environment variable `PYTHON` to its -location. For example: `set PYTHON=C:\Python27\python.exe` +Prerequisites: + +* [Python 2.6 or 2.7][] as it is required + by [GYP][]. + If python is not in your path, set the environment variable `PYTHON` to its + location. For example: `set PYTHON=C:\Python27\python.exe` +* One of: + * [Visual C++ Build Tools][] + * [Visual Studio 2015 Update 3][], all editions + including the Community edition (remember to select + "Common Tools for Visual C++ 2015" feature during installation). + * [Visual Studio 2017][], any edition (including the Build Tools SKU). + **Required Components:** "MSbuild", "VC++ 2017 v141 toolset" and one of the + Windows SDKs (10 or 8.1). +* Basic Unix tools required for some tests, + [Git for Windows][] includes Git Bash + and tools which can be included in the global `PATH`. + +To build, launch a git shell (e.g. Cmd or PowerShell), run `vcbuild.bat` +(to build with VS2017 you need to explicitly add a `vs2017` argument), +which will checkout the GYP code into `build/gyp`, generate `uv.sln` +as well as the necesery related project files, and start building. + +```console +> vcbuild +``` + +Or: + +```console +> vcbuild vs2017 +``` + +To run the tests: + +```console +> vcbuild test +``` + +To see all the options that could passed to `vcbuild`: + +```console +> vcbuild help +vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [vs2017] [x86/x64] [static/shared] +Examples: + vcbuild.bat : builds debug build + vcbuild.bat test : builds debug build and runs tests + vcbuild.bat release bench: builds release build and runs benchmarks +``` -To build with Visual Studio, launch a git shell (e.g. Cmd or PowerShell) -and run vcbuild.bat which will checkout the GYP code into build/gyp and -generate uv.sln as well as related project files. - -To have GYP generate build script for another system, checkout GYP into the -project tree manually: - - $ git clone https://chromium.googlesource.com/external/gyp.git build/gyp ### Unix @@ -244,7 +282,11 @@ See the [guidelines for contributing][]. [node.js]: http://nodejs.org/ [GYP]: http://code.google.com/p/gyp/ -[Python]: https://www.python.org/downloads/ [guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md [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 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 From 80d3b95f57e4509d93b3470e60d090b0cddb216a Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Tue, 4 Jul 2017 09:08:34 -0400 Subject: [PATCH 426/632] doc: format README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1284 Reviewed-By: Bartosz Sosnowski Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- README.md | 99 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 1b74d39e0..372d514e0 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,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](http://nodejs.org), but it's also +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). @@ -62,24 +62,34 @@ formats. Show different supported building options: - $ make help +```bash +$ make help +``` Build documentation as HTML: - $ make html +```bash +$ make html +``` Build documentation as HTML and live reload it when it changes (this requires sphinx-autobuild to be installed and is only supported on Unix): - $ make livehtml +```bash +$ make livehtml +``` Build documentation as man pages: - $ make man +```bash +$ make man +``` Build documentation as ePub: - $ make epub +```bash +$ make epub +``` NOTE: Windows users need to use make.bat instead of plain 'make'. @@ -116,25 +126,32 @@ file, but are also available as git blob objects for easier use. Importing a key the usual way: - $ gpg --keyserver pool.sks-keyservers.net \ - --recv-keys AE9BC059 +```bash +$ gpg --keyserver pool.sks-keyservers.net --recv-keys AE9BC059 +``` Importing a key from a git blob object: - $ git show pubkey-saghul | gpg --import +```bash +$ git show pubkey-saghul | gpg --import +``` ### Verifying releases Git tags are signed with the developer's key, they can be verified as follows: - $ git verify-tag v1.6.1 +```bash +$ git verify-tag v1.6.1 +``` Starting with libuv 1.7.0, the tarballs stored in the [downloads site](http://dist.libuv.org/dist/) are signed and an accompanying signature file sit alongside each. Once both the release tarball and the signature file are downloaded, the file can be verified as follows: - $ gpg --verify libuv-1.7.0.tar.gz.sign +```bash +$ gpg --verify libuv-1.7.0.tar.gz.sign +``` ## Build Instructions @@ -144,18 +161,20 @@ backends. It is best used for integration into other projects. To build with autotools: - $ sh autogen.sh - $ ./configure - $ make - $ make check - $ make install +```bash +$ sh autogen.sh +$ ./configure +$ make +$ make check +$ make install +``` ### Windows Prerequisites: * [Python 2.6 or 2.7][] as it is required - by [GYP][]. + by [GYP][]. If python is not in your path, set the environment variable `PYTHON` to its location. For example: `set PYTHON=C:\Python27\python.exe` * One of: @@ -207,13 +226,17 @@ Examples: For Debug builds (recommended) run: - $ ./gyp_uv.py -f make - $ make -C out +```bash +$ ./gyp_uv.py -f make +$ make -C out +``` For Release builds run: - $ ./gyp_uv.py -f make - $ BUILDTYPE=Release make -C out +```bash +$ ./gyp_uv.py -f make +$ BUILDTYPE=Release make -C out +``` Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries. @@ -221,13 +244,17 @@ Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries. Run: - $ ./gyp_uv.py -f xcode - $ xcodebuild -ARCHS="x86_64" -project uv.xcodeproj \ - -configuration Release -target All +```bash +$ ./gyp_uv.py -f xcode +$ xcodebuild -ARCHS="x86_64" -project uv.xcodeproj \ + -configuration Release -target All +``` Using Homebrew: - $ brew install --HEAD libuv +```bash +$ brew install --HEAD libuv +``` Note to OS X users: @@ -239,8 +266,10 @@ Make sure that you specify the architecture you wish to build for in the Run: - $ source ./android-configure NDK_PATH gyp - $ make -C out +```bash +$ source ./android-configure NDK_PATH gyp +$ make -C out +``` Note for UNIX users: compile your project with `-D_LARGEFILE_SOURCE` and `-D_FILE_OFFSET_BITS=64`. GYP builds take care of that automatically. @@ -249,18 +278,22 @@ Note for UNIX users: compile your project with `-D_LARGEFILE_SOURCE` and To use ninja for build on ninja supported platforms, run: - $ ./gyp_uv.py -f ninja - $ ninja -C out/Debug #for debug build OR - $ ninja -C out/Release +```bash +$ ./gyp_uv.py -f ninja +$ ninja -C out/Debug #for debug build OR +$ ninja -C out/Release +``` ### Running tests Run: - $ ./gyp_uv.py -f make - $ make -C out - $ ./out/Debug/run-tests +```bash +$ ./gyp_uv.py -f make +$ make -C out +$ ./out/Debug/run-tests +``` ## Supported Platforms From 8342fcaab815f33b988c1910ea988f28dfe27edb Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 5 Jul 2017 11:55:39 -0400 Subject: [PATCH 427/632] 2017.07.06, Version 1.13.0 (Stable) Changes since version 1.12.0: * Now working on version 1.12.1 (cjihrig) * unix: avoid segfault in uv_get_process_title (Michele Caini) * build: add a comma to uv.gyp (Gemini Wen) * win: restore file pos after positional read/write (Bartosz Sosnowski) * unix,stream: return error on closed handle passing (Santiago Gimeno) * unix,benchmark: use fd instead of FILE* after fork (jBarz) * zos: avoid compiler warnings (jBarz) * win,pipe: race condition canceling readfile thread (Jameson Nash) * sunos: filter out non-IPv4/IPv6 interfaces (Sebastian Wiedenroth) * sunos: fix cmpxchgi and cmpxchgl type error (Sai Ke WANG) * unix: reset signal disposition before execve() (Ben Noordhuis) * unix: reset signal mask before execve() (Ben Noordhuis) * unix: fix POLLIN assertion on server read (jBarz) * zos: use stckf builtin for high-res timer (jBarz) * win,udp: implements uv_udp_try_send (Barnabas Gema) * win,udp: return UV_EINVAL instead of aborting (Romain Caire) * freebsd: replace kvm with sysctl (Robert Ayrapetyan) * aix: fix un-initialized pointer field in fs handle (Gireesh Punathil) * win,build: support building with VS2017 (Refael Ackermann) * doc: add instructions for building on Windows (Refael Ackermann) * doc: format README (Refael Ackermann) --- .mailmap | 1 + AUTHORS | 7 +++++++ ChangeLog | 47 ++++++++++++++++++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 8 ++++---- 6 files changed, 61 insertions(+), 6 deletions(-) diff --git a/.mailmap b/.mailmap index 618274c0d..896d4065b 100644 --- a/.mailmap +++ b/.mailmap @@ -41,3 +41,4 @@ Yasuhiro Matsumoto Yazhong Liu Yuki Okumura jBarz +jBarz diff --git a/AUTHORS b/AUTHORS index ab4e099f1..4ef241092 100644 --- a/AUTHORS +++ b/AUTHORS @@ -292,3 +292,10 @@ Keane James McCoy Bernardo Ramos Juan Cruz Viotti +Gemini Wen +Sebastian Wiedenroth +Sai Ke WANG +Barnabas Gema +Romain Caire +Robert Ayrapetyan +Refael Ackermann diff --git a/ChangeLog b/ChangeLog index 71b210f44..3f07c10ef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,50 @@ +2017.07.06, Version 1.13.0 (Stable) + +Changes since version 1.12.0: + +* Now working on version 1.12.1 (cjihrig) + +* unix: avoid segfault in uv_get_process_title (Michele Caini) + +* build: add a comma to uv.gyp (Gemini Wen) + +* win: restore file pos after positional read/write (Bartosz Sosnowski) + +* unix,stream: return error on closed handle passing (Santiago Gimeno) + +* unix,benchmark: use fd instead of FILE* after fork (jBarz) + +* zos: avoid compiler warnings (jBarz) + +* win,pipe: race condition canceling readfile thread (Jameson Nash) + +* sunos: filter out non-IPv4/IPv6 interfaces (Sebastian Wiedenroth) + +* sunos: fix cmpxchgi and cmpxchgl type error (Sai Ke WANG) + +* unix: reset signal disposition before execve() (Ben Noordhuis) + +* unix: reset signal mask before execve() (Ben Noordhuis) + +* unix: fix POLLIN assertion on server read (jBarz) + +* zos: use stckf builtin for high-res timer (jBarz) + +* win,udp: implements uv_udp_try_send (Barnabas Gema) + +* win,udp: return UV_EINVAL instead of aborting (Romain Caire) + +* freebsd: replace kvm with sysctl (Robert Ayrapetyan) + +* aix: fix un-initialized pointer field in fs handle (Gireesh Punathil) + +* win,build: support building with VS2017 (Refael Ackermann) + +* doc: add instructions for building on Windows (Refael Ackermann) + +* doc: format README (Refael Ackermann) + + 2017.05.31, Version 1.12.0 (Stable), d6ac141ac674657049598c36604f26e031fae917 Changes since version 1.11.0: diff --git a/appveyor.yml b/appveyor.yml index c542e34b9..1760e2110 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.12.0.build{build} +version: v1.13.0.build{build} install: - cinst -y nsis diff --git a/configure.ac b/configure.ac index ebe35aced..1b371ede5 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.12.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.13.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 77bd262f4..5c0b7e24d 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 12 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 13 +#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 d3a958d444e35fa7f05bd7c6a826bc04221553e0 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 5 Jul 2017 11:55:40 -0400 Subject: [PATCH 428/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 3f07c10ef..e34a03035 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017.07.06, Version 1.13.0 (Stable) +2017.07.06, Version 1.13.0 (Stable), 8342fcaab815f33b988c1910ea988f28dfe27edb Changes since version 1.12.0: From a7aa05711389cfacf3a447df32c0aa1c3de87571 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 5 Jul 2017 16:47:53 -0400 Subject: [PATCH 429/632] Now working on version 1.13.1 --- 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 5c0b7e24d..30609b049 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 13 -#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 87ae1b490e4eea8544e6a03882151e789830cf4d Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Wed, 5 Jul 2017 21:14:49 -0400 Subject: [PATCH 430/632] build: workaround AppVeyor quirk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes the AppVeyor issues seen while trying to release v1.13.0 on Windows. Refs: https://github.com/libuv/libuv/issues/1397 Refs: https://github.com/libuv/libuv/pull/1284 PR-URL: https://github.com/libuv/libuv/pull/1405 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- vcbuild.bat | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vcbuild.bat b/vcbuild.bat index a86e23698..e33573d10 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -168,7 +168,9 @@ echo Failed to create vc project files. exit /b 1 :help -echo vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [vs2017] [x86/x64] [static/shared] + +echo "vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [vs2017] [x86/x64] [static/shared]" + echo Examples: echo vcbuild.bat : builds debug build echo vcbuild.bat test : builds debug build and runs tests From 2bb4b68758f07cd8617838e68c44c125bc567ba6 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 6 Jul 2017 18:42:36 -0400 Subject: [PATCH 431/632] 2017.07.07, Version 1.13.1 (Stable) Changes since version 1.13.0: * Now working on version 1.13.1 (cjihrig) * build: workaround AppVeyor quirk (Refael Ackermann) --- ChangeLog | 9 +++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 4 ++-- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index e34a03035..59c501837 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2017.07.07, Version 1.13.1 (Stable) + +Changes since version 1.13.0: + +* Now working on version 1.13.1 (cjihrig) + +* build: workaround AppVeyor quirk (Refael Ackermann) + + 2017.07.06, Version 1.13.0 (Stable), 8342fcaab815f33b988c1910ea988f28dfe27edb Changes since version 1.12.0: diff --git a/appveyor.yml b/appveyor.yml index 1760e2110..be90ef7b4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.13.0.build{build} +version: v1.13.1.build{build} install: - cinst -y nsis diff --git a/configure.ac b/configure.ac index 1b371ede5..a52cfc622 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.13.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.13.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 30609b049..c80c40ea7 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -33,8 +33,8 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 13 #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 54ef33526759f1697ba4998833a1799ac82df8df Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 6 Jul 2017 18:42:36 -0400 Subject: [PATCH 432/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 59c501837..67c99df82 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017.07.07, Version 1.13.1 (Stable) +2017.07.07, Version 1.13.1 (Stable), 2bb4b68758f07cd8617838e68c44c125bc567ba6 Changes since version 1.13.0: From d63030b0ba3b1e5063fe04b622bb6e124065965a Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 6 Jul 2017 18:49:48 -0400 Subject: [PATCH 433/632] Now working on version 1.13.2 --- 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 c80c40ea7..31a0d2d4e 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 13 -#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 ad1c828827043fd1048582cee60103a68c8d929a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Fri, 7 Jul 2017 22:41:12 +0200 Subject: [PATCH 434/632] unix: check for NULL in uv_os_unsetenv for parameter name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes segfault of unit test on musl (AlpineLinux). Add a check for parameter like uv_os_setenv do. PR-URL: https://github.com/libuv/libuv/pull/1409 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Ben Noordhuis --- src/unix/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/unix/core.c b/src/unix/core.c index 4c744925e..a0513451a 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1292,6 +1292,9 @@ int uv_os_setenv(const char* name, const char* value) { int uv_os_unsetenv(const char* name) { + if (name == NULL) + return -EINVAL; + if (unsetenv(name) != 0) return -errno; From bdc87005a17ce843e0efca8938aa8c190aa91a38 Mon Sep 17 00:00:00 2001 From: Matthew Taylor Date: Sat, 1 Jul 2017 04:46:24 +0100 Subject: [PATCH 435/632] doc: add thread safety warning for process title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a small warning about uv_get_process_title() and uv_set_process_title() not being thread safe on platforms other than Windows. Also add a reminder for users to call uv_setup_args() first. Fixes: https://github.com/libuv/libuv/issues/1395 PR-URL: https://github.com/libuv/libuv/pull/1396 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- docs/src/misc.rst | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 9d7c3617e..3fea708a8 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -186,17 +186,24 @@ API .. c:function:: int uv_get_process_title(char* buffer, size_t size) - Gets the title of the current process. If `buffer` is `NULL` or `size` is - zero, `UV_EINVAL` is returned. If `size` cannot accommodate the process - title and terminating `NULL` character, the function returns `UV_ENOBUFS`. + Gets the title of the current process. You *must* call `uv_setup_args` + before calling this function. If `buffer` is `NULL` or `size` is zero, + `UV_EINVAL` is returned. If `size` cannot accommodate the process title and + terminating `NULL` character, the function returns `UV_ENOBUFS`. + + .. warning:: + `uv_get_process_title` is not thread safe on any platform except Windows. .. c:function:: int uv_set_process_title(const char* title) - Sets the current process title. On platforms with a fixed size buffer for the - process title the contents of `title` will be copied to the buffer and - truncated if larger than the available space. Other platforms will return - `UV_ENOMEM` if they cannot allocate enough space to duplicate the contents of - `title`. + Sets the current process title. You *must* call `uv_setup_args` before + calling this function. On platforms with a fixed size buffer for the process + title the contents of `title` will be copied to the buffer and truncated if + larger than the available space. Other platforms will return `UV_ENOMEM` if + they cannot allocate enough space to duplicate the contents of `title`. + + .. warning:: + `uv_set_process_title` is not thread safe on any platform except Windows. .. c:function:: int uv_resident_set_memory(size_t* rss) From 78c17238f48d9083359206a2215fc63dd7a0283d Mon Sep 17 00:00:00 2001 From: Matthew Taylor Date: Sat, 1 Jul 2017 04:56:11 +0100 Subject: [PATCH 436/632] unix: always copy process title into local buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensures that the user's argv is copied into a local buffer when calling uv_setup_args. Before, the argv was simply being pointed to, which meant that libuv could end up accessing invalid memory if the user decided to later edit the memory at that location. It also meant that a subsequent call to uv_set_process_title would never write more characters than the length of argv[0]. With the new changes, argv[0] is copied into a temporary buffer and any subsequent calls to uv_set_process_title will thus be able to copy as many characters as the call to uv__strdup permits. Note that on *BSD and AIX this behaviour was already in effect . Some error checking (specifically checking the result of uv__strdup) has been added, and calls to uv__free rearranged so that in case of ENOMEM uv__free can't be called erroneously. Fixes: https://github.com/libuv/libuv/issues/1395 PR-URL: https://github.com/libuv/libuv/pull/1396 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/unix/freebsd.c | 6 +++++- src/unix/netbsd.c | 8 ++++++-- src/unix/openbsd.c | 7 ++++++- src/unix/proctitle.c | 22 ++++++++++++++-------- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index c3c4902be..dba94298d 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -160,9 +160,13 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { int oid[4]; + char* new_title; + new_title = uv__strdup(title); + if (process_title == NULL) + return -ENOMEM; uv__free(process_title); - process_title = uv__strdup(title); + process_title = new_title; oid[0] = CTL_KERN; oid[1] = KERN_PROC; diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index 9b5546b7e..c54c04df2 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -124,9 +124,13 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { - if (process_title) uv__free(process_title); + char* new_title; - process_title = uv__strdup(title); + new_title = uv__strdup(title); + if (process_title == NULL) + return -ENOMEM; + uv__free(process_title); + process_title = new_title; setproctitle("%s", title); return 0; diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index 56f0af15c..d1c90289e 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -146,8 +146,13 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { + char* new_title; + + new_title = uv__strdup(title); + if (process_title == NULL) + return -ENOMEM; uv__free(process_title); - process_title = uv__strdup(title); + process_title = new_title; setproctitle("%s", title); return 0; } diff --git a/src/unix/proctitle.c b/src/unix/proctitle.c index 2ed0b21c6..70e91bfc2 100644 --- a/src/unix/proctitle.c +++ b/src/unix/proctitle.c @@ -48,12 +48,14 @@ char** uv_setup_args(int argc, char** argv) { for (i = 0; i < argc; i++) size += strlen(argv[i]) + 1; + process_title.str = uv__strdup(argv[0]); + if (process_title.str == NULL) + return argv; + #if defined(__MVS__) /* argv is not adjacent. So just use argv[0] */ - process_title.str = argv[0]; - process_title.len = strlen(argv[0]); + process_title.len = strlen(process_title.str); #else - process_title.str = argv[0]; process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0]; assert(process_title.len + 1 == size); /* argv memory should be adjacent. */ #endif @@ -81,11 +83,15 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { - if (process_title.len == 0) - return 0; - - /* No need to terminate, byte after is always '\0'. */ - strncpy(process_title.str, title, process_title.len); + char* new_title; + /* Copy the title into our own buffer. We don't want to free the pointer + * on libuv shutdown because the program might still be using it. */ + new_title = uv__strdup(title); + if (new_title == NULL) + return -ENOMEM; + uv__free(process_title.str); + process_title.str = new_title; + process_title.len = strlen(new_title); uv__set_process_title(title); return 0; From d731fd1bd9400eab4ee9bf11bda9f64951fc4d89 Mon Sep 17 00:00:00 2001 From: CurlyMoo Date: Fri, 9 Sep 2016 00:42:43 +0200 Subject: [PATCH 437/632] poll: add support for OOB TCP and GPIO interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Out-of-band TCP messages are used for TCP data transmission outside (outband) the inbound TCP data. These packets are sent with an "urgent pointer", but previously discarded. Additionally, when using (e)poll a POLLPRI is triggered when an interrupt signal is received on GPIO capable systems such as the Raspberry Pi. PR-URL: https://github.com/libuv/libuv/pull/1040 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 3 +- docs/src/poll.rst | 15 ++-- include/uv.h | 3 +- src/unix/core.c | 8 +- src/unix/internal.h | 6 ++ src/unix/kqueue.c | 35 ++++++++ src/unix/linux-core.c | 2 +- src/unix/poll.c | 24 ++++- test/test-list.h | 9 ++ test/test-poll-oob.c | 205 ++++++++++++++++++++++++++++++++++++++++++ uv.gyp | 1 + 11 files changed, 295 insertions(+), 16 deletions(-) create mode 100644 test/test-poll-oob.c diff --git a/Makefile.am b/Makefile.am index 404674baf..6bf7d2340 100644 --- a/Makefile.am +++ b/Makefile.am @@ -212,10 +212,11 @@ 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-platform-output.c \ + test/test-poll.c \ test/test-poll-close.c \ test/test-poll-close-doesnt-corrupt-stack.c \ test/test-poll-closesocket.c \ - test/test-poll.c \ + test/test-poll-oob.c \ test/test-process-title.c \ test/test-queue-foreach-delete.c \ test/test-ref.c \ diff --git a/docs/src/poll.rst b/docs/src/poll.rst index 004ff4b92..aba891588 100644 --- a/docs/src/poll.rst +++ b/docs/src/poll.rst @@ -54,7 +54,8 @@ Data types enum uv_poll_event { UV_READABLE = 1, UV_WRITABLE = 2, - UV_DISCONNECT = 4 + UV_DISCONNECT = 4, + UV_PRIORITIZED = 8 }; @@ -84,10 +85,13 @@ API .. c:function:: int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) - Starts polling the file descriptor. `events` is a bitmask consisting made up - of UV_READABLE, UV_WRITABLE and UV_DISCONNECT. As soon as an event is detected - the callback will be called with `status` set to 0, and the detected events set on the - `events` field. + Starts polling the file descriptor. `events` is a bitmask made up of + UV_READABLE, UV_WRITABLE, UV_PRIORITIZED and UV_DISCONNECT. As soon as an + event is detected the callback will be called with `status` set to 0, and the + detected events set on the `events` field. + + The UV_PRIORITIZED event is used to watch for sysfs interrupts or TCP out-of-band + messages. The UV_DISCONNECT event is optional in the sense that it may not be reported and the user is free to ignore it, but it can help optimize the shutdown @@ -108,6 +112,7 @@ API on the `events` field in the callback. .. versionchanged:: 1.9.0 Added the UV_DISCONNECT event. + .. versionchanged:: 1.14.0 Added the UV_PRIORITIZED event. .. c:function:: int uv_poll_stop(uv_poll_t* poll) diff --git a/include/uv.h b/include/uv.h index f076094cc..af500cb01 100644 --- a/include/uv.h +++ b/include/uv.h @@ -719,7 +719,8 @@ struct uv_poll_s { enum uv_poll_event { UV_READABLE = 1, UV_WRITABLE = 2, - UV_DISCONNECT = 4 + UV_DISCONNECT = 4, + UV_PRIORITIZED = 8 }; UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd); diff --git a/src/unix/core.c b/src/unix/core.c index a0513451a..bee641cb4 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -838,7 +838,7 @@ 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) { - assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); @@ -866,7 +866,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); if (w->fd == -1) @@ -898,7 +898,7 @@ 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) { - uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); QUEUE_REMOVE(&w->pending_queue); /* Remove stale events for this file descriptor */ @@ -913,7 +913,7 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { int uv__io_active(const uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); return 0 != (w->pevents & events); } diff --git a/src/unix/internal.h b/src/unix/internal.h index 2e3afa6c8..283c1dfa1 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -110,6 +110,12 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); # define UV__POLLRDHUP 0x2000 #endif +#ifdef POLLPRI +# define UV__POLLPRI POLLPRI +#else +# define UV__POLLPRI 0 +#endif + #if !defined(O_CLOEXEC) && defined(__FreeBSD__) /* * It may be that we are just missing `__POSIX_VISIBLE >= 200809`. diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 6bc60bbe4..300bac07c 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -34,6 +34,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); @@ -166,6 +177,16 @@ 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); + + if (++nevents == ARRAY_SIZE(events)) { + if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) + abort(); + nevents = 0; + } + } + w->events = w->pevents; } @@ -275,6 +296,20 @@ 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]; + 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(); + } + } + if (ev->filter == EVFILT_WRITE) { if (w->pevents & POLLOUT) { revents |= POLLOUT; diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 2866e9385..24ae9490e 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -388,7 +388,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * free when we switch over to edge-triggered I/O. */ if (pe->events == POLLERR || pe->events == POLLHUP) - pe->events |= w->pevents & (POLLIN | POLLOUT); + pe->events |= w->pevents & (POLLIN | POLLOUT | UV__POLLPRI); if (pe->events != 0) { /* Run signal watchers last. This also affects child process watchers diff --git a/src/unix/poll.c b/src/unix/poll.c index 370994bd5..2001fc8c2 100644 --- a/src/unix/poll.c +++ b/src/unix/poll.c @@ -33,8 +33,19 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { handle = container_of(w, uv_poll_t, io_watcher); - if (events & POLLERR) { - uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); + /* + * As documented in the kernel source fs/kernfs/file.c #780 + * poll will return POLLERR|POLLPRI in case of sysfs + * polling. This does not happen in case of out-of-band + * TCP messages. + * + * The above is the case on (at least) FreeBSD and Linux. + * + * So to properly determine a POLLPRI or a POLLERR we need + * to check for both. + */ + if ((events & POLLERR) && !(events & UV__POLLPRI)) { + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); uv__handle_stop(handle); handle->poll_cb(handle, -EBADF, 0); return; @@ -43,6 +54,8 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { pevents = 0; if (events & POLLIN) pevents |= UV_READABLE; + if (events & UV__POLLPRI) + pevents |= UV_PRIORITIZED; if (events & POLLOUT) pevents |= UV_WRITABLE; if (events & UV__POLLRDHUP) @@ -86,7 +99,7 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, static void uv__poll_stop(uv_poll_t* handle) { uv__io_stop(handle->loop, &handle->io_watcher, - POLLIN | POLLOUT | UV__POLLRDHUP); + POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); uv__handle_stop(handle); } @@ -101,7 +114,8 @@ int uv_poll_stop(uv_poll_t* handle) { int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { int events; - assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); + assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT | + UV_PRIORITIZED)) == 0); assert(!uv__is_closing(handle)); uv__poll_stop(handle); @@ -112,6 +126,8 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { events = 0; if (pevents & UV_READABLE) events |= POLLIN; + if (pevents & UV_PRIORITIZED) + events |= UV__POLLPRI; if (pevents & UV_WRITABLE) events |= POLLOUT; if (pevents & UV_DISCONNECT) diff --git a/test/test-list.h b/test/test-list.h index 0c32d84d2..848d0b5dd 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -328,6 +328,10 @@ TEST_DECLARE (thread_rwlock_trylock) TEST_DECLARE (thread_create) TEST_DECLARE (thread_equal) TEST_DECLARE (dlerror) +#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ + !defined(__sun) +TEST_DECLARE (poll_oob) +#endif TEST_DECLARE (poll_duplex) TEST_DECLARE (poll_unidirectional) TEST_DECLARE (poll_close) @@ -681,6 +685,11 @@ TASK_LIST_START TEST_ENTRY (poll_unidirectional) TEST_ENTRY (poll_close) TEST_ENTRY (poll_bad_fdtype) +#if (defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) && \ + !defined(__sun) + TEST_ENTRY (poll_oob) +#endif + #ifdef __linux__ TEST_ENTRY (poll_nested_epoll) #endif diff --git a/test/test-poll-oob.c b/test/test-poll-oob.c new file mode 100644 index 000000000..2a6da843c --- /dev/null +++ b/test/test-poll-oob.c @@ -0,0 +1,205 @@ +/* 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. + */ + +#if !defined(_WIN32) + +#include "uv.h" +#include "task.h" + +#include +#include +#include +#include +#include + +static uv_tcp_t server_handle; +static uv_tcp_t client_handle; +static uv_tcp_t peer_handle; +static uv_poll_t poll_req[2]; +static uv_idle_t idle; +static uv_os_fd_t client_fd; +static uv_os_fd_t server_fd; +static int ticks; +static const int kMaxTicks = 10; +static int cli_pr_check = 0; +static int cli_rd_check = 0; +static int srv_rd_check = 0; + +static int got_eagain(void) { + return errno == EAGAIN + || errno == EINPROGRESS +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK +#endif + ; +} + +static void idle_cb(uv_idle_t* idle) { + uv_sleep(100); + if (++ticks < kMaxTicks) + return; + + uv_poll_stop(&poll_req[0]); + uv_poll_stop(&poll_req[1]); + uv_close((uv_handle_t*) &server_handle, NULL); + uv_close((uv_handle_t*) &client_handle, NULL); + uv_close((uv_handle_t*) &peer_handle, NULL); + uv_close((uv_handle_t*) idle, NULL); +} + +static void poll_cb(uv_poll_t* handle, int status, int events) { + char buffer[5]; + int n; + int fd; + + ASSERT(0 == uv_fileno((uv_handle_t*)handle, &fd)); + memset(buffer, 0, 5); + + if (events & UV_PRIORITIZED) { + do + n = recv(client_fd, &buffer, 5, MSG_OOB); + 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)); + } + if (events & UV_READABLE) { + if (fd == client_fd) { + do + n = recv(client_fd, &buffer, 5, 0); + while (n == -1 && errno == EINTR); + ASSERT(n >= 0 || errno != EINVAL); + if (cli_rd_check == 1) { + ASSERT(strncmp(buffer, "world", n) == 0); + ASSERT(5 == n); + cli_rd_check = 2; + } + if (cli_rd_check == 0) { + ASSERT(n == 4); + ASSERT(strncmp(buffer, "hello", n) == 0); + 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); + cli_rd_check = 2; + } + } while (n > 0); + + ASSERT(got_eagain()); + } + } + if (fd == server_fd) { + do + 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); + srv_rd_check = 1; + uv_poll_stop(&poll_req[1]); + } + } + if (events & UV_WRITABLE) { + do { + n = send(client_fd, "foo", 3, 0); + } while (n < 0 && errno == EINTR); + ASSERT(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)); + do { + r = send(server_fd, "hello", 5, MSG_OOB); + } while (r < 0 && errno == EINTR); + ASSERT(5 == r); + + do { + r = send(server_fd, "world", 5, 0); + } while (r < 0 && errno == EINTR); + ASSERT(5 == r); + + ASSERT(0 == uv_idle_start(&idle, idle_cb)); +} + + +TEST_IMPL(poll_oob) { + struct sockaddr_in addr; + int r = 0; + uv_loop_t* loop; + + ASSERT(0 == 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)); + + /* Ensure two separate packets */ + ASSERT(0 == uv_tcp_nodelay(&client_handle, 1)); + + client_fd = socket(PF_INET, SOCK_STREAM, 0); + ASSERT(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(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(ticks == kMaxTicks); + + /* Did client receive the POLLPRI message */ + ASSERT(cli_pr_check == 1); + /* Did client receive the POLLIN message */ + ASSERT(cli_rd_check == 2); + /* Could we write with POLLOUT and did the server receive our POLLOUT message + * through POLLIN. + */ + ASSERT(srv_rd_check == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif diff --git a/uv.gyp b/uv.gyp index 6f61d725a..825edd9f1 100644 --- a/uv.gyp +++ b/uv.gyp @@ -405,6 +405,7 @@ 'test/test-poll-close.c', 'test/test-poll-close-doesnt-corrupt-stack.c', 'test/test-poll-closesocket.c', + 'test/test-poll-oob.c', 'test/test-process-title.c', 'test/test-queue-foreach-delete.c', 'test/test-ref.c', From 8807fd371db6ae81a57cf06af5c2a8c32a578019 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Wed, 12 Jul 2017 19:10:01 -0400 Subject: [PATCH 438/632] win,build: fix appveyor properly Refs: https://github.com/appveyor/ci/issues/1649 Refs: https://github.com/libuv/libuv/pull/1284 Refs: https://github.com/libuv/libuv/pull/1405 PR-URL: https://github.com/libuv/libuv/pull/1418 Reviewed-By: Colin Ihrig --- appveyor.yml | 3 +++ vcbuild.bat | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index be90ef7b4..4c1898f2c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,8 @@ version: v1.13.1.build{build} +init: + - git config --global core.autocrlf true + install: - cinst -y nsis diff --git a/vcbuild.bat b/vcbuild.bat index e33573d10..a86e23698 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -168,9 +168,7 @@ echo Failed to create vc project files. exit /b 1 :help - -echo "vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [vs2017] [x86/x64] [static/shared]" - +echo vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [vs2017] [x86/x64] [static/shared] echo Examples: echo vcbuild.bat : builds debug build echo vcbuild.bat test : builds debug build and runs tests From 1e6f1159cf4469f8e67f69d1388fba659726a49f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 31 Oct 2016 10:58:54 +0100 Subject: [PATCH 439/632] win: include filename in dlopen error message Should make the dreaded "%1 is not a valid Win32 application" error message a thing of the past. PR-URL: https://github.com/libuv/libuv/pull/1116 Reviewed-By: Colin Ihrig --- src/win/dl.c | 55 ++++++++++++++++++++++++++++----------------- test/test-dlerror.c | 2 ++ 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/win/dl.c b/src/win/dl.c index 39e400ab2..d454014d8 100644 --- a/src/win/dl.c +++ b/src/win/dl.c @@ -22,7 +22,7 @@ #include "uv.h" #include "internal.h" -static int uv__dlerror(uv_lib_t* lib, int errorno); +static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno); int uv_dlopen(const char* filename, uv_lib_t* lib) { @@ -37,12 +37,12 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) { -1, filename_w, ARRAY_SIZE(filename_w))) { - return uv__dlerror(lib, GetLastError()); + return uv__dlerror(lib, filename, GetLastError()); } lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (lib->handle == NULL) { - return uv__dlerror(lib, GetLastError()); + return uv__dlerror(lib, filename, GetLastError()); } return 0; @@ -65,7 +65,7 @@ void uv_dlclose(uv_lib_t* lib) { int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { *ptr = (void*) GetProcAddress(lib->handle, name); - return uv__dlerror(lib, *ptr ? 0 : GetLastError()); + return uv__dlerror(lib, "", *ptr ? 0 : GetLastError()); } @@ -88,31 +88,46 @@ static void uv__format_fallback_error(uv_lib_t* lib, int errorno){ -static int uv__dlerror(uv_lib_t* lib, int errorno) { +static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) { + static const char not_win32_app_msg[] = "%1 is not a valid Win32 application"; + DWORD_PTR arg; DWORD res; if (lib->errmsg) { - LocalFree((void*)lib->errmsg); + LocalFree(lib->errmsg); lib->errmsg = NULL; } - if (errorno) { + if (errorno == 0) + return 0; + + res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPSTR) &lib->errmsg, 0, NULL); + + if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) { res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, - MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), - (LPSTR) &lib->errmsg, 0, NULL); - if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) { - res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, - 0, (LPSTR) &lib->errmsg, 0, NULL); - } - - if (!res) { - uv__format_fallback_error(lib, errorno); - } + 0, (LPSTR) &lib->errmsg, 0, NULL); + } + + /* Inexpert hack to get the filename into the error message. */ + if (res && strstr(lib->errmsg, not_win32_app_msg)) { + LocalFree(lib->errmsg); + lib->errmsg = NULL; + arg = (DWORD_PTR) filename; + res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_ARGUMENT_ARRAY | + FORMAT_MESSAGE_FROM_STRING, + not_win32_app_msg, + 0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg); } - return errorno ? -1 : 0; + if (!res) + uv__format_fallback_error(lib, errorno); + + return -1; } diff --git a/test/test-dlerror.c b/test/test-dlerror.c index 091200edb..8f7697b59 100644 --- a/test/test-dlerror.c +++ b/test/test-dlerror.c @@ -42,11 +42,13 @@ TEST_IMPL(dlerror) { msg = uv_dlerror(&lib); ASSERT(msg != NULL); + ASSERT(strstr(msg, path) != NULL); ASSERT(strstr(msg, dlerror_no_error) == NULL); /* Should return the same error twice in a row. */ msg = uv_dlerror(&lib); ASSERT(msg != NULL); + ASSERT(strstr(msg, path) != NULL); ASSERT(strstr(msg, dlerror_no_error) == NULL); uv_dlclose(&lib); From 810377f4891cfc7839626150dbf2c16ec989d960 Mon Sep 17 00:00:00 2001 From: Gireesh Punathil Date: Sat, 8 Jul 2017 07:31:29 -0400 Subject: [PATCH 440/632] aix: add netmask, mac address into net interfaces uv_interface_addresses API extracts the network interface entries. In AIX, this was not fully implemented. retrieve the network mask and the mac addresses. Fixes: https://github.com/nodejs/node/issues/14119 PR-URL: https://github.com/libuv/libuv/pull/1410 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/unix/aix.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/unix/aix.c b/src/unix/aix.c index 426f7f473..56a8f4ffe 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -1108,9 +1108,10 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; - int sockfd, size = 1; + int sockfd, inet6, size = 1; struct ifconf ifc; struct ifreq *ifr, *p, flg; + struct sockaddr_dl* sa_addr; *count = 0; @@ -1174,6 +1175,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, p->ifr_addr.sa_family == AF_INET)) continue; + inet6 = (p->ifr_addr.sa_family == AF_INET6); + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { uv__close(sockfd); @@ -1187,13 +1190,23 @@ int uv_interface_addresses(uv_interface_address_t** addresses, address->name = uv__strdup(p->ifr_name); - if (p->ifr_addr.sa_family == AF_INET6) { + if (inet6) address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); - } else { + else address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); + + sa_addr = (struct sockaddr_dl*) &p->ifr_addr; + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + + if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) { + uv__close(sockfd); + return -ENOSYS; } - /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ + if (inet6) + address->netmask.netmask6 = *((struct sockaddr_in6*) &p->ifr_addr); + else + address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr); address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; From 8e76306ec2565e125816edba3fb5b900b59601a7 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 17 Jul 2017 10:36:25 +0200 Subject: [PATCH 441/632] unix, windows: map EREMOTEIO errno MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1424 Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- include/uv-errno.h | 6 ++++++ include/uv.h | 1 + 2 files changed, 7 insertions(+) diff --git a/include/uv-errno.h b/include/uv-errno.h index f1371517c..32bbc5177 100644 --- a/include/uv-errno.h +++ b/include/uv-errno.h @@ -416,4 +416,10 @@ # define UV__EHOSTDOWN (-4031) #endif +#if defined(EREMOTEIO) && !defined(_WIN32) +# define UV__EREMOTEIO (-EREMOTEIO) +#else +# define UV__EREMOTEIO (-4030) +#endif + #endif /* UV_ERRNO_H_ */ diff --git a/include/uv.h b/include/uv.h index af500cb01..6aa43a271 100644 --- a/include/uv.h +++ b/include/uv.h @@ -140,6 +140,7 @@ extern "C" { XX(ENXIO, "no such device or address") \ XX(EMLINK, "too many links") \ XX(EHOSTDOWN, "host is down") \ + XX(EREMOTEIO, "remote I/O error") \ #define UV_HANDLE_TYPE_MAP(XX) \ XX(ASYNC, async) \ From f1e0fc43d17d9f2d16b6c4f9da570a4f3f6063ed Mon Sep 17 00:00:00 2001 From: XadillaX Date: Sat, 10 Jun 2017 20:31:43 +0800 Subject: [PATCH 442/632] unix: fix wrong MAC of uv_interface_address fix a wrong `if` in `uv_interface_address` about MAC. Fixes: https://github.com/nodejs/node/issues/13581 PR-URL: https://github.com/libuv/libuv/pull/1375 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- src/unix/bsd-ifaddrs.c | 15 +++++++++++---- src/unix/internal.h | 6 ++++++ src/unix/linux-core.c | 12 ++++++------ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/unix/bsd-ifaddrs.c b/src/unix/bsd-ifaddrs.c index 414789451..ffcf15644 100644 --- a/src/unix/bsd-ifaddrs.c +++ b/src/unix/bsd-ifaddrs.c @@ -31,11 +31,18 @@ #include #endif -static int uv__ifaddr_exclude(struct ifaddrs *ent) { +static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) return 1; if (ent->ifa_addr == NULL) return 1; + /* + * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family` + * equals to `AF_LINK` or not. Otherwise, the result depends on the operation + * system with `AF_LINK` or `PF_INET`. + */ + if (exclude_type == UV__EXCLUDE_IFPHYS) + return (ent->ifa_addr->sa_family != AF_LINK); #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) /* * On BSD getifaddrs returns information related to the raw underlying @@ -63,7 +70,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; (*count)++; } @@ -78,7 +85,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; address->name = uv__strdup(ent->ifa_name); @@ -102,7 +109,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) continue; address = *addresses; diff --git a/src/unix/internal.h b/src/unix/internal.h index 283c1dfa1..c0898d982 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -151,6 +151,12 @@ enum { UV_LOOP_BLOCK_SIGPROF = 1 }; +/* flags of excluding ifaddr */ +enum { + UV__EXCLUDE_IFPHYS, + UV__EXCLUDE_IFADDR +}; + typedef enum { UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */ UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */ diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 24ae9490e..4d480ce10 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -837,7 +837,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } -static int uv__ifaddr_exclude(struct ifaddrs *ent) { +static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) return 1; if (ent->ifa_addr == NULL) @@ -847,8 +847,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) { * devices. We're not interested in this information yet. */ if (ent->ifa_addr->sa_family == PF_PACKET) - return 1; - return 0; + return exclude_type; + return !exclude_type; } int uv_interface_addresses(uv_interface_address_t** addresses, @@ -869,7 +869,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; (*count)++; @@ -887,7 +887,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; address->name = uv__strdup(ent->ifa_name); @@ -911,7 +911,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) continue; address = *addresses; From 01b23314ccb2e7e70f05fc3676db262b7a687b6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 10 Jul 2017 20:50:29 +0200 Subject: [PATCH 443/632] win,build: fix building from Windows SDK or VS console Introduced in https://github.com/libuv/libuv/commit/2f6d4b4b58ea290961dc983117d31b19e198403a and accidentally undone in https://github.com/libuv/libuv/commit/19c896dd086abb351361eab54b7e88ed5ce8af08. PR-URL: https://github.com/libuv/libuv/pull/1415 Reviewed-By: Ben Noordhuis Reviewed-By: Refael Ackermann --- vcbuild.bat | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vcbuild.bat b/vcbuild.bat index a86e23698..698044df4 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -43,6 +43,9 @@ shift goto next-arg :args-done +if defined WindowsSDKDir goto select-target +if defined VCINSTALLDIR goto select-target + @rem Look for Visual Studio 2017 only if explicitly requested. if "%target_env%" NEQ "vs2017" goto vs-set-2015 echo Looking for Visual Studio 2017 From fabe3d2c3375fd42977519b8724c017fff169b81 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 22 Jul 2017 20:28:45 +0200 Subject: [PATCH 444/632] github: fix link to help repo in issue template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1431 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- .github/ISSUE_TEMPLATE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index c060a606a..543dc9fd4 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,7 +1,8 @@ From e25b5a5b2ce927ad7afb87bbc59962918a2477a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 23 Jul 2017 18:46:05 +0200 Subject: [PATCH 445/632] zos: remove nonexistent include from autotools build PR-URL: https://github.com/libuv/libuv/pull/1432 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 6bf7d2340..e92529f41 100644 --- a/Makefile.am +++ b/Makefile.am @@ -437,7 +437,7 @@ libuv_la_SOURCES += src/unix/no-proctitle.c \ endif if OS390 -include_HEADERS += include/pthread-fixes.h include/pthread-barrier.h +include_HEADERS += include/pthread-barrier.h libuv_la_CFLAGS += -D_UNIX03_THREADS \ -D_UNIX03_SOURCE \ -D_OPEN_SYS_IF_EXT=1 \ From 9e6feb69acef6a5422b2c7bf4e60aefadc28c618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 23 Jul 2017 18:46:51 +0200 Subject: [PATCH 446/632] misc: remove reference to pthread-fixes.h from LICENSE PR-URL: https://github.com/libuv/libuv/pull/1432 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 41ba44c28..28f17339e 100644 --- a/LICENSE +++ b/LICENSE @@ -62,8 +62,8 @@ The externally maintained libraries used by libuv are: - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three clause BSD license. - - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile - Communications AB. Three clause BSD license. + - 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 From cf38297b6081bcfcd4959f88c8e105881aad8bd6 Mon Sep 17 00:00:00 2001 From: Anticrisis Date: Fri, 21 Jul 2017 13:10:54 -1000 Subject: [PATCH 447/632] docs: fix guide source code example paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Source code examples in the User guide were not appearing in the built documentation because the relative paths were incorrect. PR-URL: https://github.com/libuv/libuv/pull/1428 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- docs/src/guide/basics.rst | 6 +++--- docs/src/guide/eventloops.rst | 4 ++-- docs/src/guide/filesystem.rst | 22 +++++++++++----------- docs/src/guide/networking.rst | 16 ++++++++-------- docs/src/guide/processes.rst | 32 ++++++++++++++++---------------- docs/src/guide/threads.rst | 30 +++++++++++++++--------------- docs/src/guide/utilities.rst | 28 ++++++++++++++-------------- 7 files changed, 69 insertions(+), 69 deletions(-) diff --git a/docs/src/guide/basics.rst b/docs/src/guide/basics.rst index 55798bff2..91fa6a6d2 100644 --- a/docs/src/guide/basics.rst +++ b/docs/src/guide/basics.rst @@ -86,7 +86,7 @@ With the basics out of the way, lets write our first libuv program. It does nothing, except start a loop which will exit immediately. .. rubric:: helloworld/main.c -.. literalinclude:: ../code/helloworld/main.c +.. literalinclude:: ../../code/helloworld/main.c :linenos: This program quits immediately because it has no events to process. A libuv @@ -136,7 +136,7 @@ Handles are opaque structs named as ``uv_TYPE_t`` where type signifies what the handle is used for. .. rubric:: libuv watchers -.. literalinclude:: ../libuv/include/uv.h +.. literalinclude:: ../../../include/uv.h :lines: 197-230 Handles represent long-lived objects. Async operations on such handles are @@ -170,7 +170,7 @@ watcher is stopped when the count is reached and ``uv_run()`` exits since no event watchers are active. .. rubric:: idle-basic/main.c -.. literalinclude:: ../code/idle-basic/main.c +.. literalinclude:: ../../code/idle-basic/main.c :emphasize-lines: 6,10,14-17 Storing context diff --git a/docs/src/guide/eventloops.rst b/docs/src/guide/eventloops.rst index 2413163a9..fd9df5fbd 100644 --- a/docs/src/guide/eventloops.rst +++ b/docs/src/guide/eventloops.rst @@ -19,7 +19,7 @@ these things can be a bit difficult to understand, so let's look at ``uv_run()`` where all the control flow occurs. .. rubric:: src/unix/core.c - uv_run -.. literalinclude:: ../libuv/src/unix/core.c +.. literalinclude:: ../../../src/unix/core.c :linenos: :lines: 304-324 :emphasize-lines: 10,19,21 @@ -42,7 +42,7 @@ Here is a simple example that stops the loop and demonstrates how the current iteration of the loop still takes places. .. rubric:: uvstop/main.c -.. literalinclude:: ../code/uvstop/main.c +.. literalinclude:: ../../code/uvstop/main.c :linenos: :emphasize-lines: 11 diff --git a/docs/src/guide/filesystem.rst b/docs/src/guide/filesystem.rst index f4004c460..6129303e7 100644 --- a/docs/src/guide/filesystem.rst +++ b/docs/src/guide/filesystem.rst @@ -53,7 +53,7 @@ Let's see a simple implementation of ``cat``. We start with registering a callback for when the file is opened: .. rubric:: uvcat/main.c - opening a file -.. literalinclude:: ../code/uvcat/main.c +.. literalinclude:: ../../code/uvcat/main.c :linenos: :lines: 41-53 :emphasize-lines: 4, 6-7 @@ -62,7 +62,7 @@ The ``result`` field of a ``uv_fs_t`` is the file descriptor in case of the ``uv_fs_open`` callback. If the file is successfully opened, we start reading it. .. rubric:: uvcat/main.c - read callback -.. literalinclude:: ../code/uvcat/main.c +.. literalinclude:: ../../code/uvcat/main.c :linenos: :lines: 26-40 :emphasize-lines: 2,8,12 @@ -86,7 +86,7 @@ simply drives the next read. Thus read and write proceed in lockstep via callbacks. .. rubric:: uvcat/main.c - write callback -.. literalinclude:: ../code/uvcat/main.c +.. literalinclude:: ../../code/uvcat/main.c :linenos: :lines: 16-24 :emphasize-lines: 6 @@ -99,7 +99,7 @@ callbacks. We set the dominos rolling in ``main()``: .. rubric:: uvcat/main.c -.. literalinclude:: ../code/uvcat/main.c +.. literalinclude:: ../../code/uvcat/main.c :linenos: :lines: 55- :emphasize-lines: 2 @@ -118,7 +118,7 @@ same patterns as the read/write/open calls, returning the result in the ``uv_fs_t.result`` field. The full list: .. rubric:: Filesystem operations -.. literalinclude:: ../libuv/include/uv.h +.. literalinclude:: ../../../include/uv.h :lines: 1084-1195 .. _buffers-and-streams: @@ -167,7 +167,7 @@ We start off opening pipes on the files we require. libuv pipes to a file are opened as bidirectional by default. .. rubric:: uvtee/main.c - read on pipes -.. literalinclude:: ../code/uvtee/main.c +.. literalinclude:: ../../code/uvtee/main.c :linenos: :lines: 61-80 :emphasize-lines: 4,5,15 @@ -182,7 +182,7 @@ buffers are required to hold incoming data. ``read_stdin`` will be called with these buffers. .. rubric:: uvtee/main.c - reading buffers -.. literalinclude:: ../code/uvtee/main.c +.. literalinclude:: ../../code/uvtee/main.c :linenos: :lines: 19-22,44-60 @@ -206,7 +206,7 @@ The read callback may be called with ``nread = 0``, indicating that at this point there is nothing to be read. Most applications will just ignore this. .. rubric:: uvtee/main.c - Write to pipe -.. literalinclude:: ../code/uvtee/main.c +.. literalinclude:: ../../code/uvtee/main.c :linenos: :lines: 9-13,23-42 @@ -246,7 +246,7 @@ a command whenever any of the watched files change:: The file change notification is started using ``uv_fs_event_init()``: .. rubric:: onchange/main.c - The setup -.. literalinclude:: ../code/onchange/main.c +.. literalinclude:: ../../code/onchange/main.c :linenos: :lines: 26- :emphasize-lines: 15 @@ -254,7 +254,7 @@ The file change notification is started using ``uv_fs_event_init()``: The third argument is the actual file or directory to monitor. The last argument, ``flags``, can be: -.. literalinclude:: ../libuv/include/uv.h +.. literalinclude:: ../../../include/uv.h :lines: 1299, 1308, 1315 ``UV_FS_EVENT_WATCH_ENTRY`` and ``UV_FS_EVENT_STAT`` don't do anything (yet). @@ -276,7 +276,7 @@ In our example we simply print the arguments and run the command using ``system()``. .. rubric:: onchange/main.c - file change notification callback -.. literalinclude:: ../code/onchange/main.c +.. literalinclude:: ../../code/onchange/main.c :linenos: :lines: 9-24 diff --git a/docs/src/guide/networking.rst b/docs/src/guide/networking.rst index f3463dfea..8d3c87bfb 100644 --- a/docs/src/guide/networking.rst +++ b/docs/src/guide/networking.rst @@ -37,7 +37,7 @@ Server sockets proceed by: Here is a simple echo server .. rubric:: tcp-echo-server/main.c - The listen socket -.. literalinclude:: ../code/tcp-echo-server/main.c +.. literalinclude:: ../../code/tcp-echo-server/main.c :linenos: :lines: 68- :emphasize-lines: 4-5,7-10 @@ -59,7 +59,7 @@ a handle for the client socket and associate the handle using ``uv_accept``. In this case we also establish interest in reading from this stream. .. rubric:: tcp-echo-server/main.c - Accepting the client -.. literalinclude:: ../code/tcp-echo-server/main.c +.. literalinclude:: ../../code/tcp-echo-server/main.c :linenos: :lines: 51-66 :emphasize-lines: 9-10 @@ -107,7 +107,7 @@ address from a `DHCP`_ server -- DHCP Discover. numbers below 1024. .. rubric:: udp-dhcp/main.c - Setup and send UDP packets -.. literalinclude:: ../code/udp-dhcp/main.c +.. literalinclude:: ../../code/udp-dhcp/main.c :linenos: :lines: 7-11,104- :emphasize-lines: 8,10-11,17-18,21 @@ -142,7 +142,7 @@ provided by your allocator was not large enough to hold the data. *In this case the OS will discard the data that could not fit* (That's UDP for you!). .. rubric:: udp-dhcp/main.c - Reading packets -.. literalinclude:: ../code/udp-dhcp/main.c +.. literalinclude:: ../../code/udp-dhcp/main.c :linenos: :lines: 17-40 :emphasize-lines: 1,23 @@ -167,7 +167,7 @@ Multicast A socket can (un)subscribe to a multicast group using: -.. literalinclude:: ../libuv/include/uv.h +.. literalinclude:: ../../../include/uv.h :lines: 594-597 where ``membership`` is ``UV_JOIN_GROUP`` or ``UV_LEAVE_GROUP``. @@ -191,7 +191,7 @@ perform normal socket operations on the retrieved addresses. Let's connect to Freenode to see an example of DNS resolution. .. rubric:: dns/main.c -.. literalinclude:: ../code/dns/main.c +.. literalinclude:: ../../code/dns/main.c :linenos: :lines: 61- :emphasize-lines: 12 @@ -207,7 +207,7 @@ addrinfo(s)``. This also demonstrates ``uv_tcp_connect``. It is necessary to call ``uv_freeaddrinfo`` in the callback. .. rubric:: dns/main.c -.. literalinclude:: ../code/dns/main.c +.. literalinclude:: ../../code/dns/main.c :linenos: :lines: 42-60 :emphasize-lines: 8,16 @@ -225,7 +225,7 @@ interface details so you get an idea of the fields that are available. This is useful to allow your service to bind to IP addresses when it starts. .. rubric:: interfaces/main.c -.. literalinclude:: ../code/interfaces/main.c +.. literalinclude:: ../../code/interfaces/main.c :linenos: :emphasize-lines: 9,17 diff --git a/docs/src/guide/processes.rst b/docs/src/guide/processes.rst index bbe13bc0c..49df4e93e 100644 --- a/docs/src/guide/processes.rst +++ b/docs/src/guide/processes.rst @@ -26,7 +26,7 @@ The simplest case is when you simply want to launch a process and know when it exits. This is achieved using ``uv_spawn``. .. rubric:: spawn/main.c -.. literalinclude:: ../code/spawn/main.c +.. literalinclude:: ../../code/spawn/main.c :linenos: :lines: 6-8,15- :emphasize-lines: 11,13-17 @@ -55,7 +55,7 @@ The exit callback will be invoked with the *exit status* and the type of *signal which caused the exit. .. rubric:: spawn/main.c -.. literalinclude:: ../code/spawn/main.c +.. literalinclude:: ../../code/spawn/main.c :linenos: :lines: 9-12 :emphasize-lines: 3 @@ -105,7 +105,7 @@ child processes which are independent of the parent so that the parent exiting does not affect it. .. rubric:: detach/main.c -.. literalinclude:: ../code/detach/main.c +.. literalinclude:: ../../code/detach/main.c :linenos: :lines: 9-30 :emphasize-lines: 12,19 @@ -141,7 +141,7 @@ can only be associated with one signal number, with subsequent calls to stop watching. Here is a small example demonstrating the various possibilities: .. rubric:: signal/main.c -.. literalinclude:: ../code/signal/main.c +.. literalinclude:: ../../code/signal/main.c :linenos: :emphasize-lines: 17-18,27-28 @@ -173,7 +173,7 @@ child be the same as the stderr of the parent. In this case, libuv supports which is: .. rubric:: proc-streams/test.c -.. literalinclude:: ../code/proc-streams/test.c +.. literalinclude:: ../../code/proc-streams/test.c The actual program ``proc-streams`` runs this while sharing only ``stderr``. The file descriptors of the child process are set using the ``stdio`` field in @@ -181,7 +181,7 @@ The file descriptors of the child process are set using the ``stdio`` field in file descriptors being set. ``uv_process_options_t.stdio`` is an array of ``uv_stdio_container_t``, which is: -.. literalinclude:: ../libuv/include/uv.h +.. literalinclude:: ../../../include/uv.h :lines: 826-834 where flags can have several values. Use ``UV_IGNORE`` if it isn't going to be @@ -192,7 +192,7 @@ Since we want to pass on an existing descriptor, we'll use ``UV_INHERIT_FD``. Then we set the ``fd`` to ``stderr``. .. rubric:: proc-streams/main.c -.. literalinclude:: ../code/proc-streams/main.c +.. literalinclude:: ../../code/proc-streams/main.c :linenos: :lines: 15-17,27- :emphasize-lines: 6,10,11,12 @@ -210,13 +210,13 @@ can be used to implement something like CGI_. A sample CGI script/executable is: .. rubric:: cgi/tick.c -.. literalinclude:: ../code/cgi/tick.c +.. literalinclude:: ../../code/cgi/tick.c The CGI server combines the concepts from this chapter and :doc:`networking` so that every client is sent ten ticks after which that connection is closed. .. rubric:: cgi/main.c -.. literalinclude:: ../code/cgi/main.c +.. literalinclude:: ../../code/cgi/main.c :linenos: :lines: 49-63 :emphasize-lines: 10 @@ -225,7 +225,7 @@ Here we simply accept the TCP connection and pass on the socket (*stream*) to ``invoke_cgi_script``. .. rubric:: cgi/main.c -.. literalinclude:: ../code/cgi/main.c +.. literalinclude:: ../../code/cgi/main.c :linenos: :lines: 16, 25-45 :emphasize-lines: 8-9,18,20 @@ -275,7 +275,7 @@ creator/owner of the socket acting as the server. After the initial setup, messaging is no different from TCP, so we'll re-use the echo server example. .. rubric:: pipe-echo-server/main.c -.. literalinclude:: ../code/pipe-echo-server/main.c +.. literalinclude:: ../../code/pipe-echo-server/main.c :linenos: :lines: 70- :emphasize-lines: 5,10,14 @@ -312,7 +312,7 @@ The worker process is quite simple, since the file-descriptor is handed over to it by the master. .. rubric:: multi-echo-server/worker.c -.. literalinclude:: ../code/multi-echo-server/worker.c +.. literalinclude:: ../../code/multi-echo-server/worker.c :linenos: :lines: 7-9,81- :emphasize-lines: 6-8 @@ -325,7 +325,7 @@ standard input of the worker, we connect the pipe to ``stdin`` using ``uv_pipe_open``. .. rubric:: multi-echo-server/worker.c -.. literalinclude:: ../code/multi-echo-server/worker.c +.. literalinclude:: ../../code/multi-echo-server/worker.c :linenos: :lines: 51-79 :emphasize-lines: 10,15,20 @@ -343,7 +343,7 @@ Turning now to the master, let's take a look at how the workers are launched to allow load balancing. .. rubric:: multi-echo-server/main.c -.. literalinclude:: ../code/multi-echo-server/main.c +.. literalinclude:: ../../code/multi-echo-server/main.c :linenos: :lines: 9-13 @@ -351,7 +351,7 @@ The ``child_worker`` structure wraps the process, and the pipe between the master and the individual process. .. rubric:: multi-echo-server/main.c -.. literalinclude:: ../code/multi-echo-server/main.c +.. literalinclude:: ../../code/multi-echo-server/main.c :linenos: :lines: 51,61-95 :emphasize-lines: 17,20-21 @@ -369,7 +369,7 @@ It is in ``on_new_connection`` (the TCP infrastructure is initialized in worker in the round-robin. .. rubric:: multi-echo-server/main.c -.. literalinclude:: ../code/multi-echo-server/main.c +.. literalinclude:: ../../code/multi-echo-server/main.c :linenos: :lines: 31-49 :emphasize-lines: 9,12-13 diff --git a/docs/src/guide/threads.rst b/docs/src/guide/threads.rst index 4117cc7ef..3b0a07e14 100644 --- a/docs/src/guide/threads.rst +++ b/docs/src/guide/threads.rst @@ -38,9 +38,9 @@ wait for it to close using ``uv_thread_join()``. .. _thread-create-example: .. rubric:: thread-create/main.c -.. literalinclude:: ../code/thread-create/main.c +.. literalinclude:: ../../code/thread-create/main.c :linenos: - :lines: 26-37 + :lines: 26-36 :emphasize-lines: 3-7 .. tip:: @@ -54,7 +54,7 @@ custom parameters to the thread. The function ``hare`` will now run in a separat thread, scheduled pre-emptively by the operating system: .. rubric:: thread-create/main.c -.. literalinclude:: ../code/thread-create/main.c +.. literalinclude:: ../../code/thread-create/main.c :linenos: :lines: 6-14 :emphasize-lines: 2 @@ -76,7 +76,7 @@ Mutexes The mutex functions are a **direct** map to the pthread equivalents. .. rubric:: libuv mutex functions -.. literalinclude:: ../libuv/include/uv.h +.. literalinclude:: ../../../include/uv.h :lines: 1355-1360 The ``uv_mutex_init()`` and ``uv_mutex_trylock()`` functions will return 0 on @@ -115,7 +115,7 @@ holding it. Read-write locks are frequently used in databases. Here is a toy example. .. rubric:: locks/main.c - simple rwlocks -.. literalinclude:: ../code/locks/main.c +.. literalinclude:: ../../code/locks/main.c :linenos: :emphasize-lines: 13,16,27,31,42,55 @@ -199,7 +199,7 @@ a separate thread so that the blocking and CPU bound task does not prevent the event loop from performing other activities. .. rubric:: queue-work/main.c - lazy fibonacci -.. literalinclude:: ../code/queue-work/main.c +.. literalinclude:: ../../code/queue-work/main.c :linenos: :lines: 17-29 @@ -212,10 +212,10 @@ you are changing things while both threads may be running. The trigger is ``uv_queue_work``: .. rubric:: queue-work/main.c -.. literalinclude:: ../code/queue-work/main.c +.. literalinclude:: ../../code/queue-work/main.c :linenos: :lines: 31-44 - :emphasize-lines: 40 + :emphasize-lines: 10 The thread function will be launched in a separate thread, passed the ``uv_work_t`` structure and once the function returns, the *after* function @@ -239,7 +239,7 @@ Let's modify the fibonacci example to demonstrate ``uv_cancel()``. We first set up a signal handler for termination. .. rubric:: queue-cancel/main.c -.. literalinclude:: ../code/queue-cancel/main.c +.. literalinclude:: ../../code/queue-cancel/main.c :linenos: :lines: 43- @@ -247,7 +247,7 @@ When the user triggers the signal by pressing ``Ctrl+C`` we send ``uv_cancel()`` to all the workers. ``uv_cancel()`` will return ``0`` for those that are already executing or finished. .. rubric:: queue-cancel/main.c -.. literalinclude:: ../code/queue-cancel/main.c +.. literalinclude:: ../../code/queue-cancel/main.c :linenos: :lines: 33-41 :emphasize-lines: 6 @@ -256,7 +256,7 @@ For tasks that do get cancelled successfully, the *after* function is called with ``status`` set to ``UV_ECANCELED``. .. rubric:: queue-cancel/main.c -.. literalinclude:: ../code/queue-cancel/main.c +.. literalinclude:: ../../code/queue-cancel/main.c :linenos: :lines: 28-31 :emphasize-lines: 2 @@ -283,7 +283,7 @@ to the main thread. This is a simple example of having a download manager informing the user of the status of running downloads. .. rubric:: progress/main.c -.. literalinclude:: ../code/progress/main.c +.. literalinclude:: ../../code/progress/main.c :linenos: :lines: 7-8,34- :emphasize-lines: 2,11 @@ -308,7 +308,7 @@ with the async watcher whenever it receives a message. event. .. rubric:: progress/main.c -.. literalinclude:: ../code/progress/main.c +.. literalinclude:: ../../code/progress/main.c :linenos: :lines: 10-23 :emphasize-lines: 7-8 @@ -318,7 +318,7 @@ for delivery with ``uv_async_send``. Remember: ``uv_async_send`` is also non-blocking and will return immediately. .. rubric:: progress/main.c -.. literalinclude:: ../code/progress/main.c +.. literalinclude:: ../../code/progress/main.c :linenos: :lines: 30-33 @@ -327,7 +327,7 @@ The callback is a standard libuv pattern, extracting the data from the watcher. Finally it is important to remember to clean up the watcher. .. rubric:: progress/main.c -.. literalinclude:: ../code/progress/main.c +.. literalinclude:: ../../code/progress/main.c :linenos: :lines: 25-28 :emphasize-lines: 3 diff --git a/docs/src/guide/utilities.rst b/docs/src/guide/utilities.rst index fe3c0da6b..abe6fa8d5 100644 --- a/docs/src/guide/utilities.rst +++ b/docs/src/guide/utilities.rst @@ -86,7 +86,7 @@ the JS API. A ``uv_handle_t`` (the superclass of all watchers) is created per JS object and can be ref/unrefed. .. rubric:: ref-timer/main.c -.. literalinclude:: ../code/ref-timer/main.c +.. literalinclude:: ../../code/ref-timer/main.c :linenos: :lines: 5-8, 17- :emphasize-lines: 9 @@ -110,7 +110,7 @@ and the user will face an unresponsive application. In such a case queue up and idle watcher to keep the UI operational. .. rubric:: idle-compute/main.c -.. literalinclude:: ../code/idle-compute/main.c +.. literalinclude:: ../../code/idle-compute/main.c :linenos: :lines: 5-9, 34- :emphasize-lines: 13 @@ -122,7 +122,7 @@ for a brief amount as the loop deals with the input data, after which it will keep calling the idle callback again. .. rubric:: idle-compute/main.c -.. literalinclude:: ../code/idle-compute/main.c +.. literalinclude:: ../../code/idle-compute/main.c :linenos: :lines: 10-19 @@ -214,7 +214,7 @@ progress with the download whenever libuv notifies of I/O readiness. .. _multi: http://curl.haxx.se/libcurl/c/libcurl-multi.html .. rubric:: uvwget/main.c - The setup -.. literalinclude:: ../code/uvwget/main.c +.. literalinclude:: ../../code/uvwget/main.c :linenos: :lines: 1-9,140- :emphasize-lines: 7,21,24-25 @@ -234,7 +234,7 @@ Our downloader is to be invoked as:: So we add each argument as an URL .. rubric:: uvwget/main.c - Adding urls -.. literalinclude:: ../code/uvwget/main.c +.. literalinclude:: ../../code/uvwget/main.c :linenos: :lines: 39-56 :emphasize-lines: 13-14 @@ -250,7 +250,7 @@ call whenever sockets change state. But before we go into that, we need to poll on sockets whenever ``handle_socket`` is called. .. rubric:: uvwget/main.c - Setting up polling -.. literalinclude:: ../code/uvwget/main.c +.. literalinclude:: ../../code/uvwget/main.c :linenos: :lines: 102-140 :emphasize-lines: 9,11,15,21,24 @@ -270,10 +270,10 @@ multiple times on the same handle is acceptable, it will just update the events mask with the new value. ``curl_perform`` is the crux of this program. .. rubric:: uvwget/main.c - Driving libcurl. -.. literalinclude:: ../code/uvwget/main.c +.. literalinclude:: ../../code/uvwget/main.c :linenos: :lines: 81-95 - :emphasize-lines: 2,6-7,12,18,20 + :emphasize-lines: 2,6-7,12 The first thing we do is to stop the timer, since there has been some progress in the interval. Then depending on what event triggered the callback, we set @@ -287,7 +287,7 @@ are completed. So we extract these messages, and clean up handles whose transfers are done. .. rubric:: uvwget/main.c - Reading transfer status. -.. literalinclude:: ../code/uvwget/main.c +.. literalinclude:: ../../code/uvwget/main.c :linenos: :lines: 58-79 :emphasize-lines: 6,9-10,13-14 @@ -311,14 +311,14 @@ plugin system which does nothing except print the name of the plugin. Let us first look at the interface provided to plugin authors. .. rubric:: plugin/plugin.h -.. literalinclude:: ../code/plugin/plugin.h +.. literalinclude:: ../../code/plugin/plugin.h :linenos: You can similarly add more functions that plugin authors can use to do useful things in your application [#]_. A sample plugin using this API is: .. rubric:: plugin/hello.c -.. literalinclude:: ../code/plugin/hello.c +.. literalinclude:: ../../code/plugin/hello.c :linenos: Our interface defines that all plugins should have an ``initialize`` function @@ -339,7 +339,7 @@ This is done by using ``uv_dlopen`` to first load the shared library ``uv_dlsym`` and invoke it. .. rubric:: plugin/main.c -.. literalinclude:: ../code/plugin/main.c +.. literalinclude:: ../../code/plugin/main.c :linenos: :lines: 7- :emphasize-lines: 15, 18, 24 @@ -391,7 +391,7 @@ a file, control sequences should not be written as they impede readability and Here is a simple example which prints white text on a red background: .. rubric:: tty/main.c -.. literalinclude:: ../code/tty/main.c +.. literalinclude:: ../../code/tty/main.c :linenos: :emphasize-lines: 11-12,14,17,27 @@ -401,7 +401,7 @@ program which does some animation using the function and character position escape codes. .. rubric:: tty-gravity/main.c -.. literalinclude:: ../code/tty-gravity/main.c +.. literalinclude:: ../../code/tty-gravity/main.c :linenos: :emphasize-lines: 19,25,38 From 7dabd57af40ea02d11ae36d5ed6c4834df352337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Sun, 23 Jul 2017 19:10:12 +0200 Subject: [PATCH 448/632] android: fix compilation with new NDK versions Fixes compiling with Android NDK when using Unified Headers (default since r15). Fixes: https://github.com/libuv/libuv/issues/1417 PR-URL: https://github.com/libuv/libuv/pull/1433 Reviewed-By: Ben Noordhuis --- Makefile.am | 7 +-- android-configure | 5 +- include/pthread-barrier.h | 1 + src/unix/pthread-barrier.c | 121 ------------------------------------- src/unix/thread.c | 104 +++++++++++++++++++++++++++++++ uv.gyp | 5 +- 6 files changed, 112 insertions(+), 131 deletions(-) delete mode 100644 src/unix/pthread-barrier.c diff --git a/Makefile.am b/Makefile.am index e92529f41..96a0249ef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -334,8 +334,7 @@ if ANDROID include_HEADERS += include/android-ifaddrs.h \ include/pthread-barrier.h libuv_la_SOURCES += src/unix/android-ifaddrs.c \ - src/unix/pthread-fixes.c \ - src/unix/pthread-barrier.c + src/unix/pthread-fixes.c endif if CYGWIN @@ -361,8 +360,7 @@ libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \ src/unix/darwin-proctitle.c \ src/unix/fsevents.c \ src/unix/kqueue.c \ - src/unix/proctitle.c \ - src/unix/pthread-barrier.c + src/unix/proctitle.c test_run_tests_LDFLAGS += -lutil endif @@ -454,7 +452,6 @@ libuv_la_CFLAGS += -D_UNIX03_THREADS \ -qFLOAT=IEEE libuv_la_LDFLAGS += -qXPLINK libuv_la_SOURCES += src/unix/pthread-fixes.c \ - src/unix/pthread-barrier.c \ src/unix/no-fsevents.c \ src/unix/os390.c \ src/unix/os390-syscalls.c \ diff --git a/android-configure b/android-configure index 7ffc035c1..b5c11cd40 100755 --- a/android-configure +++ b/android-configure @@ -2,17 +2,20 @@ export TOOLCHAIN=$PWD/android-toolchain mkdir -p $TOOLCHAIN +API=${3:-24} $1/build/tools/make-standalone-toolchain.sh \ --toolchain=arm-linux-androideabi-4.9 \ --arch=arm \ --install-dir=$TOOLCHAIN \ - --platform=android-21 + --platform=android-$API \ + --force export PATH=$TOOLCHAIN/bin:$PATH export AR=arm-linux-androideabi-ar export CC=arm-linux-androideabi-gcc export CXX=arm-linux-androideabi-g++ export LINK=arm-linux-androideabi-g++ export PLATFORM=android +export CFLAGS="-D__ANDROID_API__=$API" if [[ $2 == 'gyp' ]] then diff --git a/include/pthread-barrier.h b/include/pthread-barrier.h index 900ebedd3..07db9b8a6 100644 --- a/include/pthread-barrier.h +++ b/include/pthread-barrier.h @@ -23,6 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #endif #define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 +#define UV__PTHREAD_BARRIER_FALLBACK 1 /* * To maintain ABI compatibility with diff --git a/src/unix/pthread-barrier.c b/src/unix/pthread-barrier.c deleted file mode 100644 index b6e604d46..000000000 --- a/src/unix/pthread-barrier.c +++ /dev/null @@ -1,121 +0,0 @@ -/* -Copyright (c) 2016, Kari Tristan Helgason - -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. -*/ -#include "uv-common.h" -#include "pthread-barrier.h" - -#include -#include - -/* TODO: support barrier_attr */ -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* barrier_attr, - unsigned count) { - int rc; - _uv_barrier* b; - - if (barrier == NULL || count == 0) - return EINVAL; - - if (barrier_attr != NULL) - return ENOTSUP; - - b = uv__malloc(sizeof(*b)); - if (b == NULL) - return ENOMEM; - - b->in = 0; - b->out = 0; - b->threshold = count; - - if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) - goto error2; - if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) - goto error; - - barrier->b = b; - return 0; - -error: - pthread_mutex_destroy(&b->mutex); -error2: - uv__free(b); - return rc; -} - -int pthread_barrier_wait(pthread_barrier_t* barrier) { - int rc; - _uv_barrier* b; - - if (barrier == NULL || barrier->b == NULL) - return EINVAL; - - b = barrier->b; - /* Lock the mutex*/ - if ((rc = pthread_mutex_lock(&b->mutex)) != 0) - return rc; - - /* Increment the count. If this is the first thread to reach the threshold, - wake up waiters, unlock the mutex, then return - PTHREAD_BARRIER_SERIAL_THREAD. */ - if (++b->in == b->threshold) { - b->in = 0; - b->out = b->threshold - 1; - rc = pthread_cond_signal(&b->cond); - assert(rc == 0); - - pthread_mutex_unlock(&b->mutex); - return PTHREAD_BARRIER_SERIAL_THREAD; - } - /* Otherwise, wait for other threads until in is set to 0, - then return 0 to indicate this is not the first thread. */ - do { - if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) - break; - } while (b->in != 0); - - /* mark thread exit */ - b->out--; - pthread_cond_signal(&b->cond); - pthread_mutex_unlock(&b->mutex); - return rc; -} - -int pthread_barrier_destroy(pthread_barrier_t* barrier) { - int rc; - _uv_barrier* b; - - if (barrier == NULL || barrier->b == NULL) - return EINVAL; - - b = barrier->b; - - if ((rc = pthread_mutex_lock(&b->mutex)) != 0) - return rc; - - if (b->in > 0 || b->out > 0) - rc = EBUSY; - - pthread_mutex_unlock(&b->mutex); - - if (rc) - return rc; - - pthread_cond_destroy(&b->cond); - pthread_mutex_destroy(&b->mutex); - uv__free(barrier->b); - barrier->b = NULL; - return 0; -} diff --git a/src/unix/thread.c b/src/unix/thread.c index a9b5e4c02..8244f7d71 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -41,6 +41,110 @@ #define NANOSEC ((uint64_t) 1e9) +#if defined(UV__PTHREAD_BARRIER_FALLBACK) +/* TODO: support barrier_attr */ +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || count == 0) + return EINVAL; + + if (barrier_attr != NULL) + return ENOTSUP; + + b = uv__malloc(sizeof(*b)); + if (b == NULL) + return ENOMEM; + + b->in = 0; + b->out = 0; + b->threshold = count; + + if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) + goto error2; + if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) + goto error; + + barrier->b = b; + return 0; + +error: + pthread_mutex_destroy(&b->mutex); +error2: + uv__free(b); + return rc; +} + +int pthread_barrier_wait(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + /* Lock the mutex*/ + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + /* Increment the count. If this is the first thread to reach the threshold, + wake up waiters, unlock the mutex, then return + PTHREAD_BARRIER_SERIAL_THREAD. */ + if (++b->in == b->threshold) { + b->in = 0; + b->out = b->threshold - 1; + rc = pthread_cond_signal(&b->cond); + assert(rc == 0); + + pthread_mutex_unlock(&b->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + /* Otherwise, wait for other threads until in is set to 0, + then return 0 to indicate this is not the first thread. */ + do { + if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) + break; + } while (b->in != 0); + + /* mark thread exit */ + b->out--; + pthread_cond_signal(&b->cond); + pthread_mutex_unlock(&b->mutex); + return rc; +} + +int pthread_barrier_destroy(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + if (b->in > 0 || b->out > 0) + rc = EBUSY; + + pthread_mutex_unlock(&b->mutex); + + if (rc) + return rc; + + pthread_cond_destroy(&b->cond); + pthread_mutex_destroy(&b->mutex); + uv__free(barrier->b); + barrier->b = NULL; + return 0; +} +#endif + + int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { int err; pthread_attr_t* attr; diff --git a/uv.gyp b/uv.gyp index 825edd9f1..b09889c73 100644 --- a/uv.gyp +++ b/uv.gyp @@ -217,8 +217,7 @@ 'sources': [ 'src/unix/darwin.c', 'src/unix/fsevents.c', - 'src/unix/darwin-proctitle.c', - 'src/unix/pthread-barrier.c' + 'src/unix/darwin-proctitle.c' ], 'defines': [ '_DARWIN_USE_64_BIT_INODE=1', @@ -253,7 +252,6 @@ 'src/unix/linux-syscalls.h', 'src/unix/pthread-fixes.c', 'src/unix/android-ifaddrs.c', - 'src/unix/pthread-barrier.c', 'src/unix/procfs-exepath.c', 'src/unix/sysinfo-loadavg.c', 'src/unix/sysinfo-memory.c', @@ -322,7 +320,6 @@ ['OS=="os390"', { 'sources': [ 'src/unix/pthread-fixes.c', - 'src/unix/pthread-barrier.c', 'src/unix/no-fsevents.c', 'src/unix/os390.c', 'src/unix/os390-syscalls.c' From 33e6f79088afb4a043c232d461da42f760795322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Mon, 24 Jul 2017 23:39:59 +0200 Subject: [PATCH 449/632] misc: add android-toolchain to .gitignore PR-URL: https://github.com/libuv/libuv/pull/1433 Reviewed-By: Ben Noordhuis --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index eb54f9248..7536abd54 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ Makefile.in # Generated by gyp for android *.target.mk +/android-toolchain /out/ /build/gyp From e5024c54a1d015607698849d69882174203f8205 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Wed, 26 Jul 2017 13:24:41 +0200 Subject: [PATCH 450/632] win, fs: support unusual reparse points MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow for running uv_fs_stat and uv_fs_lstat on all reparse points Ref: https://github.com/nodejs/node/issues/12737 PR-URL: https://github.com/libuv/libuv/pull/1419 Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 8223d6f65..d77238106 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1118,8 +1118,6 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { */ if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) { statbuf->st_mode |= S_IFLNK; - } else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) { - return -1; } } From b6e6207c75baaecf4c104d40a3b782a77d12499b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 26 Jul 2017 21:56:50 +0200 Subject: [PATCH 451/632] android: fix detection of pthread_condattr_setclock It's only available on API level >= 21. PR-URL: https://github.com/libuv/libuv/pull/1441 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/unix/thread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/thread.c b/src/unix/thread.c index 8244f7d71..ce035df7f 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -528,7 +528,7 @@ int uv_cond_init(uv_cond_t* cond) { if (err) return -err; -#if !(defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)) +#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21) err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); if (err) goto error2; From 27dcbd6ff41f64dd8ecae67b0587523c94c14388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 26 Jul 2017 22:01:03 +0200 Subject: [PATCH 452/632] android: remove no longer needed check The latest NDK (r15 at the time of this writing) no longer needs this. `pthread_cond_timedwait` is available at any (reasonable) API level. PR-URL: https://github.com/libuv/libuv/pull/1441 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/unix/thread.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/unix/thread.c b/src/unix/thread.c index ce035df7f..f5d2c28c1 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -615,15 +615,7 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { timeout += uv__hrtime(UV_CLOCK_PRECISE); ts.tv_sec = timeout / NANOSEC; ts.tv_nsec = timeout % NANOSEC; -#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) - /* - * The bionic pthread implementation doesn't support CLOCK_MONOTONIC, - * but has this alternative function instead. - */ - r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts); -#else r = pthread_cond_timedwait(cond, mutex, &ts); -#endif /* __ANDROID__ */ #endif From cf6d047e8455e354689a5ebad7d677168eee02fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Wed, 26 Jul 2017 22:04:44 +0200 Subject: [PATCH 453/632] doc: update instructions for building on Android PR-URL: https://github.com/libuv/libuv/pull/1441 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 372d514e0..733171be0 100644 --- a/README.md +++ b/README.md @@ -267,7 +267,14 @@ Make sure that you specify the architecture you wish to build for in the Run: ```bash -$ source ./android-configure NDK_PATH gyp +$ source ./android-configure NDK_PATH gyp [API_LEVEL] +$ make -C out +``` + +The default API level is 24, but a different one can be selected as follows: + +```bash +$ source ./android-configure ~/android-ndk-r15b gyp 21 $ make -C out ``` From cbcf13af6ac6973ffdce798936bc0e2e46d4d58e Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Thu, 27 Jul 2017 12:34:31 +0200 Subject: [PATCH 454/632] win, process: support semicolons in PATH variable Fixes a bug that would cause libuv to crash when PATH environment variable contained paths with semicolon in it Refs: https://github.com/nodejs/help/issues/728 Fixes: https://github.com/libuv/libuv/issues/1422 PR-URL: https://github.com/libuv/libuv/pull/1438 Reviewed-By: Ben Noordhuis --- src/win/process.c | 9 ++++++++- test/test-list.h | 2 ++ test/test-spawn.c | 26 ++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/win/process.c b/src/win/process.c index d14160160..97b67ca52 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -405,8 +405,15 @@ static WCHAR* search_path(const WCHAR *file, /* Next slice starts just after where the previous one ended */ dir_start = dir_end; + /* If path is quoted, find quote end */ + if (*dir_start == L'"' || *dir_start == L'\'') { + dir_end = wcschr(dir_start + 1, *dir_start); + if (dir_end == NULL) { + dir_end = wcschr(dir_start, L'\0'); + } + } /* Slice until the next ; or \0 is found */ - dir_end = wcschr(dir_start, L';'); + dir_end = wcschr(dir_end, L';'); if (dir_end == NULL) { dir_end = wcschr(dir_start, L'\0'); } diff --git a/test/test-list.h b/test/test-list.h index 848d0b5dd..c2bb5616f 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -256,6 +256,7 @@ TEST_DECLARE (spawn_auto_unref) TEST_DECLARE (spawn_closed_process_io) TEST_DECLARE (spawn_reads_child_path) TEST_DECLARE (spawn_inherit_streams) +TEST_DECLARE (spawn_quoted_path) TEST_DECLARE (fs_poll) TEST_DECLARE (fs_poll_getpath) TEST_DECLARE (kill) @@ -723,6 +724,7 @@ TASK_LIST_START TEST_ENTRY (spawn_closed_process_io) TEST_ENTRY (spawn_reads_child_path) TEST_ENTRY (spawn_inherit_streams) + TEST_ENTRY (spawn_quoted_path) TEST_ENTRY (fs_poll) TEST_ENTRY (fs_poll_getpath) TEST_ENTRY (kill) diff --git a/test/test-spawn.c b/test/test-spawn.c index bb35e32b2..12e06b73d 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1,3 +1,4 @@ + /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -1711,6 +1712,31 @@ TEST_IMPL(spawn_inherit_streams) { return 0; } +TEST_IMPL(spawn_quoted_path) { +#ifndef _WIN32 + RETURN_SKIP("Test for Windows") +#else + char* quoted_path_env[2]; + options.file = "not_existing"; + args[0] = options.file; + args[1] = NULL; + options.args = args; + options.exit_cb = exit_cb; + options.flags = 0; + /* We test if search_path works correctly with semicolons in quoted path. */ + /* We will use invalid drive, so we are sure no executable is spawned */ + quoted_path_env[0] = "PATH=\"xyz:\\test;\";xyz:\\other"; + quoted_path_env[1] = NULL; + options.env = quoted_path_env; + + /* We test if libuv will not segfault. */ + uv_spawn(uv_default_loop(), &process, &options); + + MAKE_VALGRIND_HAPPY(); + return 0; +#endif +} + /* Helper for child process of spawn_inherit_streams */ #ifndef _WIN32 int spawn_stdin_stdout(void) { From 19e51ae51fc8844b0eb47fb81ea67a562128713c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 24 Jul 2017 10:58:25 +0200 Subject: [PATCH 455/632] doc: document uv_async_(init|send) return values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/576 PR-URL: https://github.com/libuv/libuv/pull/1435 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- docs/src/async.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/src/async.rst b/docs/src/async.rst index 5c4004582..02e6a58e7 100644 --- a/docs/src/async.rst +++ b/docs/src/async.rst @@ -35,12 +35,16 @@ API Initialize the handle. A NULL callback is allowed. + :returns: 0 on success, or an error code < 0 on failure. + .. note:: Unlike other handle initialization functions, it immediately starts the handle. .. c:function:: int uv_async_send(uv_async_t* async) - Wakeup the event loop and call the async handle's callback. + Wake up the event loop and call the async handle's callback. + + :returns: 0 on success, or an error code < 0 on failure. .. note:: It's safe to call this function from any thread. The callback will be called on the From 3b1e836abd8122b8caff7345f1cf891a8dfe9323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Thu, 27 Jul 2017 00:49:53 +0200 Subject: [PATCH 456/632] doc: add Android as a tier 3 supported platform PR-URL: https://github.com/libuv/libuv/pull/1442 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- SUPPORTED_PLATFORMS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 3a000c5dd..79c04bfbc 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -10,6 +10,7 @@ | z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | | Linux with musl | Tier 2 | musl >= 1.0 | | | SunOS | Tier 2 | Solaris 121 and later | Maintainers: @libuv/sunos | +| Android | Tier 3 | NDK >= r15b | | | MinGW | Tier 3 | MinGW32 and MinGW-w64 | | | Other | Tier 3 | N/A | | From 3c6f9e54ef18f185ef367a15f457cbd54e1dc1cf Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 26 Jul 2017 02:50:00 -0400 Subject: [PATCH 457/632] unix: add missing semicolon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1444 Reviewed-By: Bartosz Sosnowski Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- 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 12e06b73d..d714e045b 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1714,7 +1714,7 @@ TEST_IMPL(spawn_inherit_streams) { TEST_IMPL(spawn_quoted_path) { #ifndef _WIN32 - RETURN_SKIP("Test for Windows") + RETURN_SKIP("Test for Windows"); #else char* quoted_path_env[2]; options.file = "not_existing"; From bded0fa4f0243ea86366c4f6d974915277d7ca7f Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Mon, 7 Aug 2017 14:56:20 +0200 Subject: [PATCH 458/632] win, test: fix double close in test runner Fixes: https://github.com/libuv/libuv/issues/1426 Credit: Tom Seddon Reviewed-By: Colin Ihrig --- test/runner-win.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/runner-win.c b/test/runner-win.c index 0f1b56e77..49c9a90cf 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -212,8 +212,18 @@ int process_copy_output(process_info_t* p, FILE* stream) { char buf[1024]; int fd, r; FILE* f; + HANDLE stdio_out_copy; + + if (!DuplicateHandle(GetCurrentProcess(), + p->stdio_out, + GetCurrentProcess(), + &stdio_out_copy, + 0, + FALSE, + 0)) + return -1; - fd = _open_osfhandle((intptr_t)p->stdio_out, _O_RDONLY | _O_TEXT); + fd = _open_osfhandle((intptr_t)stdio_out_copy, _O_RDONLY | _O_TEXT); if (fd == -1) return -1; f = _fdopen(fd, "rt"); From 4646428def02c2cd2641c6323045824fd5a80e6a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 24 Jul 2017 11:06:43 +0200 Subject: [PATCH 459/632] doc: update supported windows version baseline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the baseline from Windows XP SP1 to Windows 8.1 PR-URL: https://github.com/libuv/libuv/pull/1436 Reviewed-By: Colin Ihrig --- SUPPORTED_PLATFORMS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 79c04bfbc..191b9571e 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -4,7 +4,7 @@ |---|---|---|---| | GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | | | macOS | Tier 1 | macOS >= 10.7 | | -| Windows | Tier 1 | Windows >= XP SP1 | MSVC 2008 and later are supported | +| Windows | Tier 1 | Windows >= 8.1 | MSVC 2008 and later are supported | | FreeBSD | Tier 1 | >= 9 (see note) | | | AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | | z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | From 5e2fbe59940902c8a89366cb46a087f506200543 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 2 Aug 2017 22:27:54 -0400 Subject: [PATCH 460/632] test,zos: skip chown root test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit z/OS allows non root users to chown a file to root via the CHOWN.UNRESTRICTED profile. So avoid that test on z/OS. PR-URL: https://github.com/libuv/libuv/pull/1454 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- test/test-fs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test-fs.c b/test/test-fs.c index 404d0426f..cf05a6c60 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1492,12 +1492,14 @@ TEST_IMPL(fs_chown) { uv_run(loop, UV_RUN_DEFAULT); ASSERT(chown_cb_count == 1); +#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); uv_run(loop, UV_RUN_DEFAULT); ASSERT(chown_cb_count == 1); +#endif /* async fchown */ r = uv_fs_fchown(loop, &req, file, -1, -1, fchown_cb); From f9823e5c12945fbff0c678d9517c403a23478bd9 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 2 Aug 2017 22:58:45 -0400 Subject: [PATCH 461/632] test,zos: use gid=-1 to test spawn_setgid_fails This is because on some platforms like z/OS, setgid(0) is allowed for non-superusers. So instead, use setgid(-1) to get UV_EINVAL to test that spawn failure returns the right return code. PR-URL: https://github.com/libuv/libuv/pull/1456 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- test/test-spawn.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/test-spawn.c b/test/test-spawn.c index d714e045b..91d831e19 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1351,10 +1351,14 @@ TEST_IMPL(spawn_setgid_fails) { init_process_options("spawn_helper1", fail_cb); options.flags |= UV_PROCESS_SETGID; +#if defined(__MVS__) + options.gid = -1; +#else options.gid = 0; +#endif r = uv_spawn(uv_default_loop(), &process, &options); -#if defined(__CYGWIN__) +#if defined(__CYGWIN__) || defined(__MVS__) ASSERT(r == UV_EINVAL); #else ASSERT(r == UV_EPERM); From 04adefafdf060ab85604d6481afc364f60855974 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 2 Aug 2017 19:41:13 -0400 Subject: [PATCH 462/632] zos: fix hr timer resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One tick on the high resolution clock (TOD clock) on z/OS is equivalent to (1/4.096) nanoseconds. PR-URL: https://github.com/libuv/libuv/pull/1453 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- src/unix/os390.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index de7df9116..e0a70024f 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -77,6 +77,9 @@ #pragma linkage(BPX4GTH, OS) #pragma linkage(BPX1GTH, OS) +/* TOD Clock resolution in nanoseconds */ +#define TOD_RES 4.096 + typedef unsigned data_area_ptr_assign_type; typedef union { @@ -122,7 +125,7 @@ uint64_t uv__hrtime(uv_clocktype_t type) { unsigned long long timestamp; __stckf(×tamp); /* Convert to nanoseconds */ - return timestamp / 10; + return timestamp / TOD_RES; } From 095e07cd79e6810fc35983e5c7532300b3bb4d4e Mon Sep 17 00:00:00 2001 From: Jacob Segal Date: Wed, 2 Aug 2017 11:13:28 -0700 Subject: [PATCH 463/632] android: fix blocking recvmsg due to netlink bug Code was assuming that the nl_pid was always equal to the process id. As the netlink documentation says, "nl_pid is usually the PID of the process owning the destination socket. However, nl_pid identifies a netlink socket, not a process". There are two cases in which this assumption breaks down. The first is that some other part of the application has already bound a netlink socket with a nl_pid equal to the PID of the process. The second is Android version 5.0 where it appears that nl_pid is not always defaulted to the PID of the process. The result of this bad assumption is that netlink message responses to our request are ignored due to having a bad nl_pid. We eventually run out of messages on the netlink socket and block forever awaiting our response. PR-URL: https://github.com/libuv/libuv/pull/1451 Reviewed-By: Ben Noordhuis --- src/unix/android-ifaddrs.c | 41 ++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/unix/android-ifaddrs.c b/src/unix/android-ifaddrs.c index 30f681b7d..1a842ced4 100644 --- a/src/unix/android-ifaddrs.c +++ b/src/unix/android-ifaddrs.c @@ -43,9 +43,10 @@ typedef struct NetlinkList unsigned int m_size; } NetlinkList; -static int netlink_socket(void) +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) @@ -61,6 +62,14 @@ static int netlink_socket(void) 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; } @@ -128,7 +137,7 @@ static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) } } -static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) +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; @@ -153,11 +162,10 @@ static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_don } if(l_read >= 0) { - pid_t l_pid = getpid(); 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 != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket) { continue; } @@ -207,7 +215,7 @@ static void freeResultList(NetlinkList *p_list) } } -static NetlinkList *getResultList(int p_socket, int p_request) +static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid) { int l_size; int l_done; @@ -227,7 +235,7 @@ static NetlinkList *getResultList(int p_socket, int p_request) { NetlinkList *l_item; - struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); + struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done); /* Error */ if(!l_hdr) { @@ -578,18 +586,17 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, return 0; } -static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) +static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) { int l_numLinks = 0; - pid_t l_pid = getpid(); 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 != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket) { continue; } @@ -612,16 +619,15 @@ static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifadd return l_numLinks; } -static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) +static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) { - pid_t l_pid = getpid(); 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 != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket) { continue; } @@ -648,6 +654,7 @@ int getifaddrs(struct ifaddrs **ifap) int l_socket; int l_result; int l_numLinks; + pid_t l_pid; NetlinkList *l_linkResults; NetlinkList *l_addrResults; @@ -657,20 +664,20 @@ int getifaddrs(struct ifaddrs **ifap) } *ifap = NULL; - l_socket = netlink_socket(); + l_socket = netlink_socket(&l_pid); if(l_socket < 0) { return -1; } - l_linkResults = getResultList(l_socket, RTM_GETLINK); + 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_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid); if(!l_addrResults) { close(l_socket); @@ -679,8 +686,8 @@ int getifaddrs(struct ifaddrs **ifap) } l_result = 0; - l_numLinks = interpretLinks(l_socket, l_linkResults, ifap); - if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1) + 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; } From 371ca6d4b2f9dbb0a0b012a7a8e2bad26cfd402b Mon Sep 17 00:00:00 2001 From: John Barboza Date: Thu, 9 Mar 2017 19:57:28 -0500 Subject: [PATCH 464/632] zos: read more accurate rss info from RSM More accurate Resident Set Size (Central Storage size on Z) is stored in the MVS Data Areas managed by the RSM (Real Storage Manager). PR-URL: https://github.com/libuv/libuv/pull/1244 Reviewed-By: Ben Noordhuis --- src/unix/os390.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index e0a70024f..80e01f3c9 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -33,6 +33,7 @@ #endif #define CVT_PTR 0x10 +#define PSA_PTR 0x00 #define CSD_OFFSET 0x294 /* @@ -70,6 +71,18 @@ /* CPC model length from the CSRSI Service. */ #define CPCMODEL_LENGTH 16 +/* Pointer to the home (current) ASCB. */ +#define PSAAOLD 0x224 + +/* Pointer to rsm address space block extension. */ +#define ASCBRSME 0x16C + +/* + NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE. + It does not include 2G frames. +*/ +#define RAXFMCT 0x2C + /* Thread Entry constants */ #define PGTH_CURRENT 1 #define PGTH_LEN 26 @@ -342,13 +355,17 @@ uint64_t uv_get_total_memory(void) { int uv_resident_set_memory(size_t* rss) { - W_PSPROC buf; + char* psa; + char* ascb; + char* rax; + size_t nframes; - memset(&buf, 0, sizeof(buf)); - if (w_getpsent(0, &buf, sizeof(W_PSPROC)) == -1) - return -EINVAL; + psa = PSA_PTR; + ascb = *(char* __ptr32 *)(psa + PSAAOLD); + rax = *(char* __ptr32 *)(ascb + ASCBRSME); + nframes = *(unsigned int*)(rax + RAXFMCT); - *rss = buf.ps_size; + *rss = nframes * sysconf(_SC_PAGESIZE); return 0; } From 6827fa34513b35ae3bb4fe5c0c229b17a484f959 Mon Sep 17 00:00:00 2001 From: "Maciej Szeptuch (Neverous)" Date: Mon, 31 Jul 2017 01:29:12 +0200 Subject: [PATCH 465/632] win: allow bound/connected socket in uv_tcp_open() On Unix you can pass bound and even connected socket to uv_tcp_open and it will work as expected: you can run uv_listen or other io functions (uv_read, uv_write) on it without problems. On windows on the other hand the function always assumes to have clean socket and for example uv_listen will try to bind it again, and uv_read/write will return with errors about unreadable streams (basically invalid internal flags). To check if socket is already bound uv_tcp_getsockname is called which on windows returns error when socket is unbound. To further differentiate connected one from just bound, uv_tcp_getpeername also returns error but when target socket is not connected. PR-URL: https://github.com/libuv/libuv/pull/1447 Reviewed-By: Bartosz Sosnowski Reviewed-By: Ben Noordhuis --- src/win/tcp.c | 15 ++++++++++++ test/test-list.h | 5 ++++ test/test-tcp-open.c | 57 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/src/win/tcp.c b/src/win/tcp.c index 972539f4d..e63a63e77 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -1446,6 +1446,8 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { WSAPROTOCOL_INFOW protocol_info; int opt_len; int err; + struct sockaddr_storage saddr; + int saddr_len; /* Detect the address family of the socket. */ opt_len = (int) sizeof protocol_info; @@ -1466,6 +1468,19 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { return uv_translate_sys_error(err); } + /* Support already active socket. */ + saddr_len = sizeof(saddr); + if (!uv_tcp_getsockname(handle, (struct sockaddr*) &saddr, &saddr_len)) { + /* Socket is already bound. */ + handle->flags |= UV_HANDLE_BOUND; + 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); + handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; + } + } + return 0; } diff --git a/test/test-list.h b/test/test-list.h index c2bb5616f..a0ff96a75 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -81,6 +81,8 @@ TEST_DECLARE (tcp_try_write) TEST_DECLARE (tcp_write_queue_order) TEST_DECLARE (tcp_open) TEST_DECLARE (tcp_open_twice) +TEST_DECLARE (tcp_open_bound) +TEST_DECLARE (tcp_open_connected) TEST_DECLARE (tcp_connect_error_after_write) TEST_DECLARE (tcp_shutdown_after_write) TEST_DECLARE (tcp_bind_error_addrinuse) @@ -491,6 +493,9 @@ TASK_LIST_START TEST_ENTRY (tcp_open) TEST_HELPER (tcp_open, tcp4_echo_server) TEST_ENTRY (tcp_open_twice) + TEST_ENTRY (tcp_open_bound) + TEST_ENTRY (tcp_open_connected) + TEST_HELPER (tcp_open_connected, tcp4_echo_server) TEST_ENTRY (tcp_shutdown_after_write) TEST_HELPER (tcp_shutdown_after_write, tcp4_echo_server) diff --git a/test/test-tcp-open.c b/test/test-tcp-open.c index 6c8d43d00..cb74c50e2 100644 --- a/test/test-tcp-open.c +++ b/test/test-tcp-open.c @@ -218,3 +218,60 @@ TEST_IMPL(tcp_open_twice) { MAKE_VALGRIND_HAPPY(); return 0; } + + +TEST_IMPL(tcp_open_bound) { + struct sockaddr_in addr; + uv_tcp_t server; + uv_os_sock_t sock; + + startup(); + sock = create_tcp_socket(); + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); + + ASSERT(0 == bind(sock, (struct sockaddr*) &addr, sizeof(addr))); + + ASSERT(0 == uv_tcp_open(&server, sock)); + + ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, NULL)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +TEST_IMPL(tcp_open_connected) { + struct sockaddr_in addr; + uv_tcp_t client; + 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)); + + startup(); + sock = create_tcp_socket(); + + ASSERT(0 == connect(sock, (struct sockaddr*) &addr, sizeof(addr))); + + ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); + + ASSERT(0 == uv_tcp_open(&client, sock)); + + ASSERT(0 == 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(0 == 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); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From 3af5512950bd6f3a0d386b0825cdd3e78a3e7f48 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 7 Aug 2017 13:09:34 -0400 Subject: [PATCH 466/632] doc: differentiate SmartOS and SunOS support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs: https://github.com/libuv/libuv/pull/991 Refs: https://github.com/libuv/libuv/issues/1458 PR-URL: https://github.com/libuv/libuv/pull/1469 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno --- SUPPORTED_PLATFORMS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 191b9571e..08fd5f4a9 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -9,9 +9,10 @@ | AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | | z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | | Linux with musl | Tier 2 | musl >= 1.0 | | -| SunOS | Tier 2 | Solaris 121 and later | Maintainers: @libuv/sunos | +| SmartOS | Tier 2 | >= 14.4 | Maintainers: @libuv/smartos | | Android | Tier 3 | NDK >= r15b | | | MinGW | Tier 3 | MinGW32 and MinGW-w64 | | +| SunOS | Tier 3 | Solaris 121 and later | | | Other | Tier 3 | N/A | | #### Note on FreeBSD 9 From ce56a85b19e13287d2613f8de33f479a9c1104b5 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 8 Aug 2017 15:30:42 +0200 Subject: [PATCH 467/632] unix: make uv_poll_stop() remove fd from pollset Avoid repeated wake-ups in `uv__io_poll()` when the previously watched file descriptor has been duplicated (with `dup(2)`) and then closed. Because epoll reports events for _file descriptions_ rather than _file descriptors_, events on the duplicated file descriptor cause the event loop to wake up. Libuv then tries to unregister the event listener for the original file descriptor but that fails with EBADF because the file descriptor is closed. Since libuv uses epoll in level-triggered mode, it effectively results in a busy loop because the event is re-reported as soon as libuv calls epoll_wait() again. I tried hard to write a test case for this but there is no directly observable behavior, only increased CPU usuage. Fixes: https://github.com/libuv/libuv/issues/1148 PR-URL: https://github.com/libuv/libuv/pull/1468 Reviewed-By: Colin Ihrig --- src/unix/poll.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/unix/poll.c b/src/unix/poll.c index 2001fc8c2..816c7dc2e 100644 --- a/src/unix/poll.c +++ b/src/unix/poll.c @@ -101,6 +101,7 @@ static void uv__poll_stop(uv_poll_t* handle) { &handle->io_watcher, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); uv__handle_stop(handle); + uv__platform_invalidate_fd(handle->loop, handle->io_watcher.fd); } From 766d7e9c0b8eca53b864764b735682d814c56350 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 14 Jul 2017 21:47:36 -0400 Subject: [PATCH 468/632] unix, windows: add basic uv_fs_copyfile() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/925 PR-URL: https://github.com/libuv/libuv/pull/1465 Reviewed-By: Bartosz Sosnowski Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Ben Noordhuis --- Makefile.am | 1 + checksparse.sh | 1 + docs/src/fs.rst | 19 +++++- include/uv.h | 15 ++++- src/unix/fs.c | 114 +++++++++++++++++++++++++++++++ src/win/fs.c | 42 ++++++++++++ test/test-fs-copyfile.c | 145 ++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 + uv.gyp | 1 + 9 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 test/test-fs-copyfile.c diff --git a/Makefile.am b/Makefile.am index 96a0249ef..16cb47cca 100644 --- a/Makefile.am +++ b/Makefile.am @@ -169,6 +169,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-env-vars.c \ test/test-error.c \ test/test-fail-always.c \ + test/test-fs-copyfile.c \ test/test-fs-event.c \ test/test-fs-poll.c \ test/test-fs.c \ diff --git a/checksparse.sh b/checksparse.sh index 9782718a2..ae0e5374f 100755 --- a/checksparse.sh +++ b/checksparse.sh @@ -96,6 +96,7 @@ test/test-embed.c test/test-env-vars.c test/test-error.c test/test-fail-always.c +test/test-fs-copyfile.c test/test-fs-event.c test/test-fs-poll.c test/test-fs.c diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 3f766e393..2db915bc9 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -92,7 +92,8 @@ Data types UV_FS_READLINK, UV_FS_CHOWN, UV_FS_FCHOWN, - UV_FS_REALPATH + UV_FS_REALPATH, + UV_FS_COPYFILE } uv_fs_type; .. c:type:: uv_dirent_t @@ -241,6 +242,22 @@ API Equivalent to :man:`ftruncate(2)`. +.. c:function:: 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) + + Copies a file from `path` to `new_path`. Supported `flags` are described below. + + - `UV_FS_COPYFILE_EXCL`: If present, `uv_fs_copyfile()` will fail with + `UV_EEXIST` if the destination path already exists. The default behavior + is to overwrite the destination if it exists. + + .. warning:: + If the destination path is created, but an error occurs while copying + the data, then the destination path is removed. There is a brief window + of time between closing and removing the file where another process + could access the file. + + .. versionadded:: 1.14.0 + .. c:function:: int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb) Limited equivalent to :man:`sendfile(2)`. diff --git a/include/uv.h b/include/uv.h index 6aa43a271..eac63dde4 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1114,7 +1114,8 @@ typedef enum { UV_FS_READLINK, UV_FS_CHOWN, UV_FS_FCHOWN, - UV_FS_REALPATH + UV_FS_REALPATH, + UV_FS_COPYFILE } uv_fs_type; /* uv_fs_t is a subclass of uv_req_t. */ @@ -1159,6 +1160,18 @@ UV_EXTERN int uv_fs_write(uv_loop_t* loop, unsigned int nbufs, int64_t offset, uv_fs_cb cb); +/* + * This flag can be used with uv_fs_copyfile() to return an error if the + * destination already exists. + */ +#define UV_FS_COPYFILE_EXCL 0x0001 + +UV_EXTERN 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); UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, diff --git a/src/unix/fs.c b/src/unix/fs.c index f9513ea55..626d6c058 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -60,6 +60,10 @@ # include #endif +#if defined(__APPLE__) +# include +#endif + #define INIT(subtype) \ do { \ req->type = UV_FS; \ @@ -766,6 +770,102 @@ 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). */ + copyfile_flags_t flags; + + flags = COPYFILE_ALL; + + if (req->flags & UV_FS_COPYFILE_EXCL) + flags |= COPYFILE_EXCL; + + return copyfile(req->path, req->new_path, NULL, flags); +#else + uv_fs_t fs_req; + uv_file srcfd; + uv_file dstfd; + struct stat statsbuf; + int dst_flags; + int result; + int err; + + dstfd = -1; + + /* Open the source file. */ + srcfd = uv_fs_open(req->loop, &fs_req, req->path, O_RDONLY, 0, NULL); + uv_fs_req_cleanup(&fs_req); + + if (srcfd < 0) + return srcfd; + + /* Get the source file's mode. */ + if (fstat(srcfd, &statsbuf)) { + err = -errno; + goto out; + } + + dst_flags = O_WRONLY | O_CREAT; + + if (req->flags & UV_FS_COPYFILE_EXCL) + dst_flags |= O_EXCL; + + /* Open the destination file. */ + dstfd = uv_fs_open(req->loop, + &fs_req, + req->new_path, + dst_flags, + statsbuf.st_mode, + NULL); + uv_fs_req_cleanup(&fs_req); + + if (dstfd < 0) { + err = dstfd; + goto out; + } + + err = uv_fs_sendfile(req->loop, + &fs_req, + dstfd, + srcfd, + 0, + statsbuf.st_size, + NULL); + uv_fs_req_cleanup(&fs_req); + +out: + if (err < 0) + result = err; + else + result = 0; + + /* Close the source file. */ + err = uv__close_nocheckstdio(srcfd); + + /* Don't overwrite any existing errors. */ + if (err != 0 && result == 0) + result = err; + + /* Close the destination file if it is open. */ + if (dstfd >= 0) { + err = uv__close_nocheckstdio(dstfd); + + /* Don't overwrite any existing errors. */ + if (err != 0 && result == 0) + result = err; + + /* Remove the destination file if something went wrong. */ + if (result != 0) { + uv_fs_unlink(NULL, &fs_req, req->new_path, NULL); + /* Ignore the unlink return value, as an error already happened. */ + uv_fs_req_cleanup(&fs_req); + } + } + + return result; +#endif +} + static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_dev = src->st_dev; dst->st_mode = src->st_mode; @@ -946,6 +1046,7 @@ static void uv__fs_work(struct uv__work* w) { X(CHMOD, chmod(req->path, req->mode)); X(CHOWN, chown(req->path, req->uid, req->gid)); X(CLOSE, close(req->file)); + X(COPYFILE, uv__fs_copyfile(req)); X(FCHMOD, fchmod(req->file, req->mode)); X(FCHOWN, fchown(req->file, req->uid, req->gid)); X(FDATASYNC, uv__fs_fdatasync(req)); @@ -1367,3 +1468,16 @@ void uv_fs_req_cleanup(uv_fs_t* req) { uv__free(req->ptr); req->ptr = NULL; } + + +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) { + INIT(COPYFILE); + PATH2; + req->flags = flags; + POST; +} diff --git a/src/win/fs.c b/src/win/fs.c index d77238106..970a7a437 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1331,6 +1331,22 @@ static void fs__ftruncate(uv_fs_t* req) { } +static void fs__copyfile(uv_fs_t* req) { + int flags; + int overwrite; + + flags = req->fs.info.file_flags; + overwrite = flags & UV_FS_COPYFILE_EXCL; + + if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) == 0) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + SET_REQ_RESULT(req, 0); +} + + static void fs__sendfile(uv_fs_t* req) { int fd_in = req->file.fd, fd_out = req->fs.info.fd_out; size_t length = req->fs.info.bufsml[0].len; @@ -1853,6 +1869,7 @@ static void uv__fs_work(struct uv__work* w) { XX(CLOSE, close) XX(READ, read) XX(WRITE, write) + XX(COPYFILE, copyfile) XX(SENDFILE, sendfile) XX(STAT, stat) XX(LSTAT, lstat) @@ -2387,6 +2404,31 @@ int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd, } +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 err; + + uv_fs_req_init(loop, req, UV_FS_COPYFILE, cb); + err = fs__capture_path(req, path, new_path, cb != NULL); + + if (err) + return uv_translate_sys_error(err); + + req->fs.info.file_flags = flags; + + if (cb != NULL) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } + + fs__copyfile(req); + return req->result; +} + int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out, uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) { diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c new file mode 100644 index 000000000..746cd94b7 --- /dev/null +++ b/test/test-fs-copyfile.c @@ -0,0 +1,145 @@ +/* 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" + +#if defined(__unix__) || defined(__POSIX__) || \ + defined(__APPLE__) || defined(_AIX) || defined(__MVS__) +#include /* unlink, etc. */ +#else +# include +# include +# define unlink _unlink +#endif + +static const char fixture[] = "test/fixtures/load_error.node"; +static const char dst[] = "test_file_dst"; +static int result_check_count; + + +static void handle_result(uv_fs_t* req) { + uv_fs_t stat_req; + uint64_t size; + uint64_t mode; + int r; + + ASSERT(req->fs_type == UV_FS_COPYFILE); + ASSERT(req->result == 0); + + /* Verify that the file size and mode are the same. */ + r = uv_fs_stat(NULL, &stat_req, req->path, NULL); + ASSERT(r == 0); + 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); + uv_fs_req_cleanup(&stat_req); + uv_fs_req_cleanup(req); + result_check_count++; +} + + +static void touch_file(const char* name, unsigned int size) { + uv_file file; + uv_fs_t req; + uv_buf_t buf; + int r; + unsigned int i; + + r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); + uv_fs_req_cleanup(&req); + ASSERT(r >= 0); + file = r; + + buf = uv_buf_init("a", 1); + + /* Inefficient but simple. */ + 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); + } + + r = uv_fs_close(NULL, &req, file, NULL); + uv_fs_req_cleanup(&req); + ASSERT(r == 0); +} + + +TEST_IMPL(fs_copyfile) { + const char src[] = "test_file_src"; + uv_loop_t* loop; + uv_fs_t req; + int r; + + loop = uv_default_loop(); + + /* 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); + uv_fs_req_cleanup(&req); + /* The destination should not exist. */ + r = uv_fs_stat(NULL, &req, dst, NULL); + ASSERT(r != 0); + uv_fs_req_cleanup(&req); + + /* Copies file synchronously. Creates new file. */ + unlink(dst); + r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + + /* Copies file synchronously. Overwrites existing file. */ + r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + + /* Fails to overwrites existing file. */ + r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_EXCL, NULL); + ASSERT(r == UV_EEXIST); + uv_fs_req_cleanup(&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); + 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 == 3); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(result_check_count == 4); + unlink(dst); /* Cleanup */ + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index a0ff96a75..011cb7843 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -274,6 +274,7 @@ TEST_DECLARE (fs_mkdtemp) TEST_DECLARE (fs_fstat) TEST_DECLARE (fs_access) TEST_DECLARE (fs_chmod) +TEST_DECLARE (fs_copyfile) TEST_DECLARE (fs_unlink_readonly) TEST_DECLARE (fs_chown) TEST_DECLARE (fs_link) @@ -778,6 +779,7 @@ TASK_LIST_START TEST_ENTRY (fs_fstat) TEST_ENTRY (fs_access) TEST_ENTRY (fs_chmod) + TEST_ENTRY (fs_copyfile) TEST_ENTRY (fs_unlink_readonly) TEST_ENTRY (fs_chown) TEST_ENTRY (fs_utime) diff --git a/uv.gyp b/uv.gyp index b09889c73..cac6da819 100644 --- a/uv.gyp +++ b/uv.gyp @@ -359,6 +359,7 @@ 'test/test-fail-always.c', 'test/test-fork.c', 'test/test-fs.c', + 'test/test-fs-copyfile.c', 'test/test-fs-event.c', 'test/test-get-currentexe.c', 'test/test-get-memory.c', From e0d31e9e21870f88277746b6d59cf07b977cdfea Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 16 Aug 2017 10:11:33 -0400 Subject: [PATCH 469/632] 2017.08.17, Version 1.14.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.13.1: * unix: check for NULL in uv_os_unsetenv for parameter name (André Klitzing) * doc: add thread safety warning for process title (Matthew Taylor) * unix: always copy process title into local buffer (Matthew Taylor) * poll: add support for OOB TCP and GPIO interrupts (CurlyMoo) * win,build: fix appveyor properly (Refael Ackermann) * win: include filename in dlopen error message (Ben Noordhuis) * aix: add netmask, mac address into net interfaces (Gireesh Punathil) * unix, windows: map EREMOTEIO errno (Ben Noordhuis) * unix: fix wrong MAC of uv_interface_address (XadillaX) * win,build: fix building from Windows SDK or VS console (Saúl Ibarra Corretgé) * github: fix link to help repo in issue template (Ben Noordhuis) * zos: remove nonexistent include from autotools build (Saúl Ibarra Corretgé) * misc: remove reference to pthread-fixes.h from LICENSE (Saúl Ibarra Corretgé) * docs: fix guide source code example paths (Anticrisis) * android: fix compilation with new NDK versions (Saúl Ibarra Corretgé) * misc: add android-toolchain to .gitignore (Saúl Ibarra Corretgé) * win, fs: support unusual reparse points (Bartosz Sosnowski) * android: fix detection of pthread_condattr_setclock (Saúl Ibarra Corretgé) * android: remove no longer needed check (Saúl Ibarra Corretgé) * doc: update instructions for building on Android (Saúl Ibarra Corretgé) * win, process: support semicolons in PATH variable (Bartosz Sosnowski) * doc: document uv_async_(init|send) return values (Ben Noordhuis) * doc: add Android as a tier 3 supported platform (Saúl Ibarra Corretgé) * unix: add missing semicolon (jBarz) * win, test: fix double close in test runner (Bartosz Sosnowski) * doc: update supported windows version baseline (Ben Noordhuis) * test,zos: skip chown root test (jBarz) * test,zos: use gid=-1 to test spawn_setgid_fails (jBarz) * zos: fix hr timer resolution (jBarz) * android: fix blocking recvmsg due to netlink bug (Jacob Segal) * zos: read more accurate rss info from RSM (jBarz) * win: allow bound/connected socket in uv_tcp_open() (Maciej Szeptuch (Neverous)) * doc: differentiate SmartOS and SunOS support (cjihrig) * unix: make uv_poll_stop() remove fd from pollset (Ben Noordhuis) * unix, windows: add basic uv_fs_copyfile() (cjihrig) --- AUTHORS | 7 ++++ ChangeLog | 76 ++++++++++++++++++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 8 ++--- 5 files changed, 89 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4ef241092..b87ec3a53 100644 --- a/AUTHORS +++ b/AUTHORS @@ -299,3 +299,10 @@ Barnabas Gema Romain Caire Robert Ayrapetyan Refael Ackermann +André Klitzing +Matthew Taylor +CurlyMoo +XadillaX +Anticrisis +Jacob Segal +Maciej Szeptuch (Neverous) diff --git a/ChangeLog b/ChangeLog index 67c99df82..4ad73fc17 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,79 @@ +2017.08.17, Version 1.14.0 (Stable) + +Changes since version 1.13.1: + +* unix: check for NULL in uv_os_unsetenv for parameter name (André Klitzing) + +* doc: add thread safety warning for process title (Matthew Taylor) + +* unix: always copy process title into local buffer (Matthew Taylor) + +* poll: add support for OOB TCP and GPIO interrupts (CurlyMoo) + +* win,build: fix appveyor properly (Refael Ackermann) + +* win: include filename in dlopen error message (Ben Noordhuis) + +* aix: add netmask, mac address into net interfaces (Gireesh Punathil) + +* unix, windows: map EREMOTEIO errno (Ben Noordhuis) + +* unix: fix wrong MAC of uv_interface_address (XadillaX) + +* win,build: fix building from Windows SDK or VS console (Saúl Ibarra Corretgé) + +* github: fix link to help repo in issue template (Ben Noordhuis) + +* zos: remove nonexistent include from autotools build (Saúl Ibarra Corretgé) + +* misc: remove reference to pthread-fixes.h from LICENSE (Saúl Ibarra Corretgé) + +* docs: fix guide source code example paths (Anticrisis) + +* android: fix compilation with new NDK versions (Saúl Ibarra Corretgé) + +* misc: add android-toolchain to .gitignore (Saúl Ibarra Corretgé) + +* win, fs: support unusual reparse points (Bartosz Sosnowski) + +* android: fix detection of pthread_condattr_setclock (Saúl Ibarra Corretgé) + +* android: remove no longer needed check (Saúl Ibarra Corretgé) + +* doc: update instructions for building on Android (Saúl Ibarra Corretgé) + +* win, process: support semicolons in PATH variable (Bartosz Sosnowski) + +* doc: document uv_async_(init|send) return values (Ben Noordhuis) + +* doc: add Android as a tier 3 supported platform (Saúl Ibarra Corretgé) + +* unix: add missing semicolon (jBarz) + +* win, test: fix double close in test runner (Bartosz Sosnowski) + +* doc: update supported windows version baseline (Ben Noordhuis) + +* test,zos: skip chown root test (jBarz) + +* test,zos: use gid=-1 to test spawn_setgid_fails (jBarz) + +* zos: fix hr timer resolution (jBarz) + +* android: fix blocking recvmsg due to netlink bug (Jacob Segal) + +* zos: read more accurate rss info from RSM (jBarz) + +* win: allow bound/connected socket in uv_tcp_open() (Maciej Szeptuch + (Neverous)) + +* doc: differentiate SmartOS and SunOS support (cjihrig) + +* unix: make uv_poll_stop() remove fd from pollset (Ben Noordhuis) + +* unix, windows: add basic uv_fs_copyfile() (cjihrig) + + 2017.07.07, Version 1.13.1 (Stable), 2bb4b68758f07cd8617838e68c44c125bc567ba6 Changes since version 1.13.0: diff --git a/appveyor.yml b/appveyor.yml index 4c1898f2c..2c82662c8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.13.1.build{build} +version: v1.14.0.build{build} init: - git config --global core.autocrlf true diff --git a/configure.ac b/configure.ac index a52cfc622..3c74a7cfc 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.13.1], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.14.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 31a0d2d4e..d3b6ec1f0 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 13 -#define UV_VERSION_PATCH 2 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 14 +#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 1f4ec0271550ff3761cfea85ce5eb5d52055373c Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 16 Aug 2017 10:11:34 -0400 Subject: [PATCH 470/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 4ad73fc17..961ac9590 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017.08.17, Version 1.14.0 (Stable) +2017.08.17, Version 1.14.0 (Stable), e0d31e9e21870f88277746b6d59cf07b977cdfea Changes since version 1.13.1: From c8ee8bef9bfa30e9370c592f4f6511190a3ec5b6 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 16 Aug 2017 10:21:47 -0400 Subject: [PATCH 471/632] Now working on version 1.14.1 --- 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 d3b6ec1f0..8fd047345 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 14 -#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 89d31932a595fdec18dd19b70142816312ea2338 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Fri, 18 Aug 2017 14:21:58 +0200 Subject: [PATCH 472/632] fs, win: add support for user symlinks Add SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE to CreateSymbolicLink which allows unelevated users to create symbolic links on supported platforms. Fixes: https://github.com/libuv/libuv/issues/1157 PR-URL: https://github.com/libuv/libuv/pull/1466 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/win/fs.c | 52 ++++++++++++++++++++++++++++++++++-------------- src/win/winapi.h | 4 ++++ 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 970a7a437..9ef29fea6 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -113,6 +113,7 @@ const WCHAR LONG_PATH_PREFIX_LEN = 4; const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\"; const WCHAR UNC_PATH_PREFIX_LEN = 8; +static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; void uv_fs_init(void) { _fmode = _O_BINARY; @@ -1713,25 +1714,46 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path, static void fs__symlink(uv_fs_t* req) { - WCHAR* pathw = req->file.pathw; - WCHAR* new_pathw = req->fs.info.new_pathw; - int flags = req->fs.info.file_flags; - int result; + WCHAR* pathw; + WCHAR* new_pathw; + int flags; + int err; + pathw = req->file.pathw; + new_pathw = req->fs.info.new_pathw; - if (flags & UV_FS_SYMLINK_JUNCTION) { + if (req->fs.info.file_flags & UV_FS_SYMLINK_JUNCTION) { fs__create_junction(req, pathw, new_pathw); - } else if (pCreateSymbolicLinkW) { - result = pCreateSymbolicLinkW(new_pathw, - pathw, - flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1; - if (result == -1) { - SET_REQ_WIN32_ERROR(req, GetLastError()); - } else { - SET_REQ_RESULT(req, result); - } - } else { + return; + } + if (!pCreateSymbolicLinkW) { SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); + return; + } + + if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR) + flags = SYMBOLIC_LINK_FLAG_DIRECTORY; + else + flags = uv__file_symlink_usermode_flag; + + if (pCreateSymbolicLinkW(new_pathw, pathw, flags)) { + SET_REQ_RESULT(req, 0); + return; + } + + /* Something went wrong. We will test if it is because of user-mode + * symlinks. + */ + err = GetLastError(); + if (err == ERROR_INVALID_PARAMETER && + flags & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) { + /* This system does not support user-mode symlinks. We will clear the + * unsupported flag and retry. + */ + uv__file_symlink_usermode_flag = 0; + fs__symlink(req); + } else { + SET_REQ_WIN32_ERROR(req, err); } } diff --git a/src/win/winapi.h b/src/win/winapi.h index 9401676fb..6c699bfe1 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4104,6 +4104,10 @@ # define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 #endif +#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x00000002 +#endif + /* from winternl.h */ typedef struct _UNICODE_STRING { USHORT Length; From ce41af28c82b16e223852123d8d49553a958c116 Mon Sep 17 00:00:00 2001 From: Joel Winarske Date: Wed, 16 Aug 2017 12:10:24 -0700 Subject: [PATCH 473/632] cygwin: include uv-posix.h header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/1480 PR-URL: https://github.com/libuv/libuv/pull/1482 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index 16cb47cca..b94fdd63b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -339,6 +339,7 @@ libuv_la_SOURCES += src/unix/android-ifaddrs.c \ endif if CYGWIN +include_HEADERS += include/uv-posix.h libuv_la_CFLAGS += -D_GNU_SOURCE libuv_la_SOURCES += src/unix/cygwin.c \ src/unix/bsd-ifaddrs.c \ From e80921c1ae6b978fa3a3eaad3c7ec4321c1bad6a Mon Sep 17 00:00:00 2001 From: John Barboza Date: Fri, 11 Aug 2017 07:28:47 -0400 Subject: [PATCH 474/632] zos: fix semaphore initialization To set an initial value to a semaphore, the semop call won't do it. We need to use the semctl call with the SETVAL flag PR-URL: https://github.com/libuv/libuv/pull/1473 Reviewed-By: Ben Noordhuis --- src/unix/thread.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/unix/thread.c b/src/unix/thread.c index f5d2c28c1..c7ff3fa49 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -387,16 +387,19 @@ int uv_sem_init(uv_sem_t* sem, unsigned int value) { uv_sem_t semid; struct sembuf buf; int err; + union { + int val; + struct semid_ds* buf; + unsigned short* array; + } arg; - buf.sem_num = 0; - buf.sem_op = value; - buf.sem_flg = 0; semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); if (semid == -1) return -errno; - if (-1 == semop(semid, &buf, 1)) { + arg.val = value; + if (-1 == semctl(semid, 0, SETVAL, arg)) { err = errno; if (-1 == semctl(*sem, 0, IPC_RMID)) abort(); From cbac5f1693c6c7e88cc00d20731bb9a170005e52 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 31 May 2017 06:08:44 -0400 Subject: [PATCH 475/632] zos: improve loop_count benchmark performance After the poll call, the code updates all the event objects in the array. Instead, use the integer value returned by poll to limit the number of epoll_event objects that are updated. e.g. If poll returns 5, we know that we only need to update 5 event objects. PR-URL: https://github.com/libuv/libuv/pull/1391 Reviewed-By: Ben Noordhuis --- src/unix/os390-syscalls.c | 23 ++++++----------------- src/unix/os390.c | 6 ++++-- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c index 7edf2358d..08623f4ea 100644 --- a/src/unix/os390-syscalls.c +++ b/src/unix/os390-syscalls.c @@ -183,33 +183,22 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, int pollret; int reventcount; - uv_mutex_lock(&global_epoll_lock); - uv_mutex_unlock(&global_epoll_lock); size = lst->size; pfds = lst->items; pollret = poll(pfds, size, timeout); - if(pollret == -1) + if (pollret <= 0) return pollret; reventcount = 0; - for (int i = 0; i < lst->size && i < maxevents; ++i) { + for (int i = 0; + i < lst->size && i < maxevents && reventcount < pollret; ++i) { struct epoll_event ev; - ev.events = 0; - ev.fd = pfds[i].fd; - if(!pfds[i].revents) + if (pfds[i].fd == -1 || pfds[i].revents == 0) continue; - if(pfds[i].revents & POLLRDNORM) - ev.events = ev.events | POLLIN; - - if(pfds[i].revents & POLLWRNORM) - ev.events = ev.events | POLLOUT; - - if(pfds[i].revents & POLLHUP) - ev.events = ev.events | POLLHUP; - - pfds[i].revents = 0; + ev.fd = pfds[i].fd; + ev.events = pfds[i].revents; events[reventcount++] = ev; } diff --git a/src/unix/os390.c b/src/unix/os390.c index 80e01f3c9..559970de2 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -767,9 +767,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { assert(timeout != -1); - timeout = real_timeout - timeout; - if (timeout > 0) + + if (timeout > 0) { + timeout = real_timeout - timeout; continue; + } return; } From 607dc073eb293f9d193b3491071b00e815d1df76 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 16 Aug 2017 20:36:34 -0400 Subject: [PATCH 476/632] zos, test: flush out the oob data in callback Need to flush out the OOB data. Otherwise, this callback will get triggered on every poll with nread = 0. PR-URL: https://github.com/libuv/libuv/pull/1484 Reviewed-By: Santiago Gimeno Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis --- test/test-tcp-oob.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/test-tcp-oob.c b/test/test-tcp-oob.c index fc011ee49..4f1397a82 100644 --- a/test/test-tcp-oob.c +++ b/test/test-tcp-oob.c @@ -56,8 +56,21 @@ static void idle_cb(uv_idle_t* idle) { static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { +#ifdef __MVS__ + char lbuf[12]; +#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)); + +#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)); +#endif } From 8a95c6b5c10392c3cfd38ececbee0343d57bc4f5 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 19 Aug 2017 14:40:46 -0400 Subject: [PATCH 477/632] unix,win: check for bad flags in uv_fs_copyfile() Refs: https://github.com/libuv/libuv/pull/1465 PR-URL: https://github.com/libuv/libuv/pull/1493 Reviewed-By: Santiago Gimeno Reviewed-By: Ben Noordhuis --- src/unix/fs.c | 3 +++ src/win/fs.c | 3 +++ test/test-fs-copyfile.c | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index 626d6c058..2f4ab871c 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1476,6 +1476,9 @@ int uv_fs_copyfile(uv_loop_t* loop, const char* new_path, int flags, uv_fs_cb cb) { + if (flags & ~UV_FS_COPYFILE_EXCL) + return -EINVAL; + INIT(COPYFILE); PATH2; req->flags = flags; diff --git a/src/win/fs.c b/src/win/fs.c index 9ef29fea6..5edfee88b 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -2434,6 +2434,9 @@ int uv_fs_copyfile(uv_loop_t* loop, uv_fs_cb cb) { int err; + if (flags & ~UV_FS_COPYFILE_EXCL) + return UV_EINVAL; + uv_fs_req_init(loop, req, UV_FS_COPYFILE, cb); err = fs__capture_path(req, path, new_path, cb != NULL); diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index 746cd94b7..a973e86af 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -96,6 +96,10 @@ TEST_IMPL(fs_copyfile) { loop = uv_default_loop(); + /* Fails with EINVAL if bad flags are passed. */ + r = uv_fs_copyfile(NULL, &req, src, dst, -1, NULL); + ASSERT(r == UV_EINVAL); + /* Fails with ENOENT if source does not exist. */ unlink(src); unlink(dst); From afc05a3ab0ad2ab79385f3e3f029eb34849eda0e Mon Sep 17 00:00:00 2001 From: Matthew Taylor Date: Thu, 17 Aug 2017 18:25:29 +0100 Subject: [PATCH 478/632] unix: modify argv[0] when process title is set Ensure that argv[0] is changed when uv_set_process_title() is called. Previously, on some unix systems uv__set_process_title() was being called, but argv[0] was not modified. Partial revert of 78c17238f48d9083359206a2215fc63dd7a0283d. Refs: https://github.com/libuv/libuv/pull/1396 PR-URL: https://github.com/libuv/libuv/pull/1487 Reviewed-By: Colin Ihrig --- src/unix/proctitle.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/unix/proctitle.c b/src/unix/proctitle.c index 70e91bfc2..2ed0b21c6 100644 --- a/src/unix/proctitle.c +++ b/src/unix/proctitle.c @@ -48,14 +48,12 @@ char** uv_setup_args(int argc, char** argv) { for (i = 0; i < argc; i++) size += strlen(argv[i]) + 1; - process_title.str = uv__strdup(argv[0]); - if (process_title.str == NULL) - return argv; - #if defined(__MVS__) /* argv is not adjacent. So just use argv[0] */ - process_title.len = strlen(process_title.str); + process_title.str = argv[0]; + process_title.len = strlen(argv[0]); #else + process_title.str = argv[0]; process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0]; assert(process_title.len + 1 == size); /* argv memory should be adjacent. */ #endif @@ -83,15 +81,11 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { - char* new_title; - /* Copy the title into our own buffer. We don't want to free the pointer - * on libuv shutdown because the program might still be using it. */ - new_title = uv__strdup(title); - if (new_title == NULL) - return -ENOMEM; - uv__free(process_title.str); - process_title.str = new_title; - process_title.len = strlen(new_title); + if (process_title.len == 0) + return 0; + + /* No need to terminate, byte after is always '\0'. */ + strncpy(process_title.str, title, process_title.len); uv__set_process_title(title); return 0; From 564677d325db6122cba2091100d07ea6d366161b Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 21 Aug 2017 22:15:39 -0400 Subject: [PATCH 479/632] unix: don't use req->loop in uv__fs_copyfile() Pass NULL instead of req->loop to the various libuv functions called from uv__fs_copyfile(). Refs: https://github.com/libuv/libuv/pull/1494 PR-URL: https://github.com/libuv/libuv/pull/1504 Reviewed-By: Ben Noordhuis --- 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 2f4ab871c..296e9b151 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -793,7 +793,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { dstfd = -1; /* Open the source file. */ - srcfd = uv_fs_open(req->loop, &fs_req, req->path, O_RDONLY, 0, NULL); + srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL); uv_fs_req_cleanup(&fs_req); if (srcfd < 0) @@ -811,7 +811,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { dst_flags |= O_EXCL; /* Open the destination file. */ - dstfd = uv_fs_open(req->loop, + dstfd = uv_fs_open(NULL, &fs_req, req->new_path, dst_flags, @@ -824,7 +824,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { goto out; } - err = uv_fs_sendfile(req->loop, + err = uv_fs_sendfile(NULL, &fs_req, dstfd, srcfd, From 737b482baa69dee0397d5d631a81f7288deaee34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20=C4=8Cun=C3=A1t?= Date: Fri, 1 Sep 2017 10:23:28 +0200 Subject: [PATCH 480/632] doc: fix a trivial typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1516 Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- docs/src/stream.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/stream.rst b/docs/src/stream.rst index de492b357..1f4e87e63 100644 --- a/docs/src/stream.rst +++ b/docs/src/stream.rst @@ -6,7 +6,7 @@ Stream handles provide an abstraction of a duplex communication channel. :c:type:`uv_stream_t` is an abstract type, libuv provides 3 stream implementations -in the for of :c:type:`uv_tcp_t`, :c:type:`uv_pipe_t` and :c:type:`uv_tty_t`. +in the form of :c:type:`uv_tcp_t`, :c:type:`uv_pipe_t` and :c:type:`uv_tty_t`. Data types From 36ea2cb2954934d91f0636504cf0c7df2593903c Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Mon, 28 Aug 2017 17:18:57 +0200 Subject: [PATCH 481/632] android: fix uv_cond_timedwait on API level < 21 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit partly reverses libuv#1441. It is true that pthread_cond_timedwait is available on older API levels, but if we do not call pthread_condattr_setclock then we cannot use timestamps from CLOCK_MONOTONIC with pthread_cond_timedwait. PR-URL: https://github.com/libuv/libuv/pull/1511 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/thread.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/unix/thread.c b/src/unix/thread.c index c7ff3fa49..f88462259 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -618,7 +618,16 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { timeout += uv__hrtime(UV_CLOCK_PRECISE); ts.tv_sec = timeout / NANOSEC; ts.tv_nsec = timeout % NANOSEC; +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + + /* + * The bionic pthread implementation doesn't support CLOCK_MONOTONIC, + * but has this alternative function instead. + */ + r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts); +#else r = pthread_cond_timedwait(cond, mutex, &ts); +#endif /* __ANDROID_API__ */ #endif From 165c63b96c08ce68040d6494607f7ddec351bf2a Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Wed, 30 Aug 2017 14:25:50 +0200 Subject: [PATCH 482/632] win: add uv__once_init() calls Some functions, such as uv_fs_scandir() can be called with a NULL loop argument. In this case, it's possible that the Windows API hasn't been initialized, leading to a crash. This commit adds additional uv__once_init() calls to mitigate this situation. Fixes: https://github.com/libuv/libuv/issues/1488 PR-URL: https://github.com/libuv/libuv/pull/1512 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/win/fs.c | 1 + src/win/pipe.c | 2 ++ src/win/tty.c | 1 + 3 files changed, 4 insertions(+) diff --git a/src/win/fs.c b/src/win/fs.c index 5edfee88b..dee34cd3a 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -221,6 +221,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, 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; diff --git a/src/win/pipe.c b/src/win/pipe.c index 9b10cc9fe..5c666788f 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1913,6 +1913,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { if (os_handle == INVALID_HANDLE_VALUE) return UV_EBADF; + 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. * We could also opt to use the original OS handle and just never close it, @@ -1986,6 +1987,7 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) unsigned int name_len; int err; + uv__once_init(); name_info = NULL; if (handle->handle == INVALID_HANDLE_VALUE) { diff --git a/src/win/tty.c b/src/win/tty.c index a6f583956..c4f99bdc7 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -148,6 +148,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { HANDLE handle; CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; + uv__once_init(); handle = (HANDLE) uv__get_osfhandle(fd); if (handle == INVALID_HANDLE_VALUE) return UV_EBADF; From 7a0e64d2e0e6a01673365a4062067a79ff690712 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 25 Aug 2017 09:58:32 -0400 Subject: [PATCH 483/632] unix,windows: init all requests in fs calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to this change, several of the fs functions checked for invalid arguments before initializing the fs request. If a consumer received a UV_EINVAL from one of these functions, and then called uv_fs_req_cleanup(), the application would crash, as the pointer being freed was not allocated. This commit makes sure that all fs functions initialize the request before returning. Fixes: https://github.com/libuv/libuv/issues/1508 PR-URL: https://github.com/libuv/libuv/pull/1509 Reviewed-By: Bartosz Sosnowski Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fs.c | 9 ++++++--- src/win/fs.c | 17 +++++++++-------- test/test-fs-copyfile.c | 1 + test/test-fs.c | 12 ++++++++---- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 296e9b151..5400d0c70 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -1287,10 +1287,11 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, unsigned int nbufs, int64_t off, uv_fs_cb cb) { + INIT(READ); + if (bufs == NULL || nbufs == 0) return -EINVAL; - INIT(READ); req->file = file; req->nbufs = nbufs; @@ -1425,10 +1426,11 @@ int uv_fs_write(uv_loop_t* loop, unsigned int nbufs, int64_t off, uv_fs_cb cb) { + INIT(WRITE); + if (bufs == NULL || nbufs == 0) return -EINVAL; - INIT(WRITE); req->file = file; req->nbufs = nbufs; @@ -1476,10 +1478,11 @@ int uv_fs_copyfile(uv_loop_t* loop, const char* new_path, int flags, uv_fs_cb cb) { + INIT(COPYFILE); + if (flags & ~UV_FS_COPYFILE_EXCL) return -EINVAL; - INIT(COPYFILE); PATH2; req->flags = flags; POST; diff --git a/src/win/fs.c b/src/win/fs.c index dee34cd3a..567069962 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -2010,11 +2010,11 @@ int uv_fs_read(uv_loop_t* loop, unsigned int nbufs, int64_t offset, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_READ, cb); + if (bufs == NULL || nbufs == 0) return UV_EINVAL; - uv_fs_req_init(loop, req, UV_FS_READ, cb); - req->file.fd = fd; req->fs.info.nbufs = nbufs; @@ -2046,11 +2046,11 @@ int uv_fs_write(uv_loop_t* loop, unsigned int nbufs, int64_t offset, uv_fs_cb cb) { + uv_fs_req_init(loop, req, UV_FS_WRITE, cb); + if (bufs == NULL || nbufs == 0) return UV_EINVAL; - uv_fs_req_init(loop, req, UV_FS_WRITE, cb); - req->file.fd = fd; req->fs.info.nbufs = nbufs; @@ -2251,12 +2251,12 @@ int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - if (!req || !path) { + uv_fs_req_init(loop, req, UV_FS_REALPATH, cb); + + if (!path) { return UV_EINVAL; } - uv_fs_req_init(loop, req, UV_FS_REALPATH, cb); - err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2435,10 +2435,11 @@ int uv_fs_copyfile(uv_loop_t* loop, uv_fs_cb cb) { int err; + uv_fs_req_init(loop, req, UV_FS_COPYFILE, cb); + if (flags & ~UV_FS_COPYFILE_EXCL) return UV_EINVAL; - uv_fs_req_init(loop, req, UV_FS_COPYFILE, cb); err = fs__capture_path(req, path, new_path, cb != NULL); if (err) diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index a973e86af..2d1f9079a 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -99,6 +99,7 @@ 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); + uv_fs_req_cleanup(&req); /* Fails with ENOENT if source does not exist. */ unlink(src); diff --git a/test/test-fs.c b/test/test-fs.c index cf05a6c60..660d22ccf 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2751,19 +2751,23 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) { TEST_IMPL(fs_read_write_null_arguments) { int r; - r = uv_fs_read(NULL, NULL, 0, NULL, 0, -1, NULL); + r = uv_fs_read(NULL, &read_req, 0, NULL, 0, -1, NULL); ASSERT(r == UV_EINVAL); + uv_fs_req_cleanup(&read_req); - r = uv_fs_write(NULL, NULL, 0, NULL, 0, -1, NULL); + r = uv_fs_write(NULL, &write_req, 0, NULL, 0, -1, NULL); ASSERT(r == UV_EINVAL); + uv_fs_req_cleanup(&write_req); iov = uv_buf_init(NULL, 0); - r = uv_fs_read(NULL, NULL, 0, &iov, 0, -1, NULL); + r = uv_fs_read(NULL, &read_req, 0, &iov, 0, -1, NULL); ASSERT(r == UV_EINVAL); + uv_fs_req_cleanup(&read_req); iov = uv_buf_init(NULL, 0); - r = uv_fs_write(NULL, NULL, 0, &iov, 0, -1, NULL); + r = uv_fs_write(NULL, &write_req, 0, &iov, 0, -1, NULL); ASSERT(r == UV_EINVAL); + uv_fs_req_cleanup(&write_req); return 0; } From e539fc412f87ec215bd7291c3fdf36aed7557667 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 26 Aug 2017 15:31:02 -0400 Subject: [PATCH 484/632] unix,windows: return UV_EINVAL on NULL fs reqs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces an INIT macro to file system functions on Windows, similar to the one used on Unix platforms. The macro checks for NULL requests, and returns UV_EINVAL in such scenarios. This commit also adds support for passing NULL to uv_fs_req_cleanup(). In this scenario, the function is a no-op. Fixes: https://github.com/libuv/libuv/issues/1508 PR-URL: https://github.com/libuv/libuv/pull/1509 Reviewed-By: Bartosz Sosnowski Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fs.c | 5 +++ src/win/fs.c | 89 ++++++++++++++++++++------------------------ test/test-fs.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 + 4 files changed, 144 insertions(+), 49 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 5400d0c70..3b816ecad 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -66,6 +66,8 @@ #define INIT(subtype) \ do { \ + if (req == NULL) \ + return -EINVAL; \ req->type = UV_FS; \ if (cb != NULL) \ uv__req_init(loop, req, UV_FS); \ @@ -1452,6 +1454,9 @@ int uv_fs_write(uv_loop_t* loop, void uv_fs_req_cleanup(uv_fs_t* req) { + if (req == NULL) + return; + /* Only necessary for asychronous 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 is the diff --git a/src/win/fs.c b/src/win/fs.c index 567069962..5ff7d0b09 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -43,6 +43,14 @@ #define UV_FS_CLEANEDUP 0x0010 +#define INIT(subtype) \ + do { \ + if (req == NULL) \ + return UV_EINVAL; \ + uv_fs_req_init(loop, req, subtype, cb); \ + } \ + while (0) + #define QUEUE_FS_TP_JOB(loop, req) \ do { \ uv__req_register(loop, req); \ @@ -1939,6 +1947,9 @@ static void uv__fs_done(struct uv__work* w, int status) { void uv_fs_req_cleanup(uv_fs_t* req) { + if (req == NULL) + return; + if (req->flags & UV_FS_CLEANEDUP) return; @@ -1969,8 +1980,7 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_OPEN, cb); - + INIT(UV_FS_OPEN); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -1990,7 +2000,7 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_CLOSE, cb); + INIT(UV_FS_CLOSE); req->file.fd = fd; if (cb) { @@ -2010,7 +2020,7 @@ int uv_fs_read(uv_loop_t* loop, unsigned int nbufs, int64_t offset, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_READ, cb); + INIT(UV_FS_READ); if (bufs == NULL || nbufs == 0) return UV_EINVAL; @@ -2046,7 +2056,7 @@ int uv_fs_write(uv_loop_t* loop, unsigned int nbufs, int64_t offset, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_WRITE, cb); + INIT(UV_FS_WRITE); if (bufs == NULL || nbufs == 0) return UV_EINVAL; @@ -2079,8 +2089,7 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_UNLINK, cb); - + INIT(UV_FS_UNLINK); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2100,8 +2109,7 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_MKDIR, cb); - + INIT(UV_FS_MKDIR); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2123,8 +2131,7 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb); - + INIT(UV_FS_MKDTEMP); err = fs__capture_path(req, tpl, NULL, TRUE); if (err) return uv_translate_sys_error(err); @@ -2142,8 +2149,7 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_RMDIR, cb); - + INIT(UV_FS_RMDIR); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2163,8 +2169,7 @@ int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_SCANDIR, cb); - + INIT(UV_FS_SCANDIR); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2186,8 +2191,7 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_LINK, cb); - + INIT(UV_FS_LINK); err = fs__capture_path(req, path, new_path, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2207,8 +2211,7 @@ 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) { int err; - uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb); - + INIT(UV_FS_SYMLINK); err = fs__capture_path(req, path, new_path, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2230,8 +2233,7 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_READLINK, cb); - + INIT(UV_FS_READLINK); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2251,7 +2253,7 @@ int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_REALPATH, cb); + INIT(UV_FS_REALPATH); if (!path) { return UV_EINVAL; @@ -2276,8 +2278,7 @@ 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 err; - uv_fs_req_init(loop, req, UV_FS_CHOWN, cb); - + INIT(UV_FS_CHOWN); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2295,7 +2296,7 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb); + INIT(UV_FS_FCHOWN); if (cb) { QUEUE_FS_TP_JOB(loop, req); @@ -2310,8 +2311,7 @@ int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid, int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_STAT, cb); - + INIT(UV_FS_STAT); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2330,8 +2330,7 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_LSTAT, cb); - + INIT(UV_FS_LSTAT); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2348,7 +2347,7 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FSTAT, cb); + INIT(UV_FS_FSTAT); req->file.fd = fd; if (cb) { @@ -2365,8 +2364,7 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_RENAME, cb); - + INIT(UV_FS_RENAME); err = fs__capture_path(req, path, new_path, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2383,7 +2381,7 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FSYNC, cb); + INIT(UV_FS_FSYNC); req->file.fd = fd; if (cb) { @@ -2397,7 +2395,7 @@ int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb); + INIT(UV_FS_FDATASYNC); req->file.fd = fd; if (cb) { @@ -2412,8 +2410,7 @@ int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int64_t offset, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb); - + INIT(UV_FS_FTRUNCATE); req->file.fd = fd; req->fs.info.offset = offset; @@ -2435,7 +2432,7 @@ int uv_fs_copyfile(uv_loop_t* loop, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_COPYFILE, cb); + INIT(UV_FS_COPYFILE); if (flags & ~UV_FS_COPYFILE_EXCL) return UV_EINVAL; @@ -2459,8 +2456,7 @@ int uv_fs_copyfile(uv_loop_t* loop, int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out, uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb); - + INIT(UV_FS_SENDFILE); req->file.fd = fd_in; req->fs.info.fd_out = fd_out; req->fs.info.offset = in_offset; @@ -2483,8 +2479,7 @@ int uv_fs_access(uv_loop_t* loop, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_ACCESS, cb); - + INIT(UV_FS_ACCESS); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) return uv_translate_sys_error(err); @@ -2505,8 +2500,7 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_CHMOD, cb); - + INIT(UV_FS_CHMOD); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2526,8 +2520,7 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb); - + INIT(UV_FS_FCHMOD); req->file.fd = fd; req->fs.info.mode = mode; @@ -2545,8 +2538,7 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb) { int err; - uv_fs_req_init(loop, req, UV_FS_UTIME, cb); - + INIT(UV_FS_UTIME); err = fs__capture_path(req, path, NULL, cb != NULL); if (err) { return uv_translate_sys_error(err); @@ -2567,8 +2559,7 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime, double mtime, uv_fs_cb cb) { - uv_fs_req_init(loop, req, UV_FS_FUTIME, cb); - + INIT(UV_FS_FUTIME); req->file.fd = fd; req->fs.time.atime = atime; req->fs.time.mtime = mtime; diff --git a/test/test-fs.c b/test/test-fs.c index 660d22ccf..0000e563a 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2850,3 +2850,100 @@ TEST_IMPL(fs_file_pos_after_op_with_offset) { MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(fs_null_req) { + /* Verify that all fs functions return UV_EINVAL when the request is NULL. */ + int r; + + r = uv_fs_open(NULL, NULL, NULL, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_close(NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_read(NULL, NULL, 0, NULL, 0, -1, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_write(NULL, NULL, 0, NULL, 0, -1, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_unlink(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_mkdir(NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_mkdtemp(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_rmdir(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_scandir(NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_link(NULL, NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_symlink(NULL, NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_readlink(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_realpath(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_chown(NULL, NULL, NULL, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fchown(NULL, NULL, 0, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_stat(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_lstat(NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fstat(NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_rename(NULL, NULL, NULL, NULL, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fsync(NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fdatasync(NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_ftruncate(NULL, NULL, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_copyfile(NULL, NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_sendfile(NULL, NULL, 0, 0, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_access(NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_chmod(NULL, NULL, NULL, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_fchmod(NULL, NULL, 0, 0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_utime(NULL, NULL, NULL, 0.0, 0.0, NULL); + ASSERT(r == UV_EINVAL); + + r = uv_fs_futime(NULL, NULL, 0, 0.0, 0.0, NULL); + ASSERT(r == UV_EINVAL); + + /* This should be a no-op. */ + uv_fs_req_cleanup(NULL); + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 011cb7843..6e84653e8 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -316,6 +316,7 @@ TEST_DECLARE (get_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) +TEST_DECLARE (fs_null_req) TEST_DECLARE (threadpool_queue_work_simple) TEST_DECLARE (threadpool_queue_work_einval) TEST_DECLARE (threadpool_multiple_event_loops) @@ -819,6 +820,7 @@ TASK_LIST_START TEST_ENTRY (fs_write_alotof_bufs_with_offset) TEST_ENTRY (fs_read_write_null_arguments) TEST_ENTRY (fs_file_pos_after_op_with_offset) + TEST_ENTRY (fs_null_req) TEST_ENTRY (get_osfhandle_valid_handle) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) From 9a4468f47aead2c9fad1735ebcdcf51d160c860e Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 2 Sep 2017 15:12:46 -0400 Subject: [PATCH 485/632] windows: add POST macro to fs functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a POST macro to the Windows fs functions, similar to the one used on Unix platforms. PR-URL: https://github.com/libuv/libuv/pull/1509 Reviewed-By: Saúl Ibarra Corretgé --- src/win/fs.c | 268 ++++++++------------------------------------------- 1 file changed, 41 insertions(+), 227 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 5ff7d0b09..c374a82ca 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -51,11 +51,18 @@ } \ while (0) -#define QUEUE_FS_TP_JOB(loop, req) \ - do { \ - uv__req_register(loop, req); \ - uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \ - } while (0) +#define POST \ + do { \ + if (cb != NULL) { \ + uv__req_register(loop, req); \ + uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \ + return 0; \ + } else { \ + uv__fs_work(&req->work_req); \ + return req->result; \ + } \ + } \ + while (0) #define SET_REQ_RESULT(req, result_value) \ do { \ @@ -1988,28 +1995,14 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, req->fs.info.file_flags = flags; req->fs.info.mode = mode; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__open(req); - return req->result; - } + POST; } int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { INIT(UV_FS_CLOSE); req->file.fd = fd; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__close(req); - return req->result; - } + POST; } @@ -2038,14 +2031,7 @@ int uv_fs_read(uv_loop_t* loop, memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs)); req->fs.info.offset = offset; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__read(req); - return req->result; - } + POST; } @@ -2074,14 +2060,7 @@ int uv_fs_write(uv_loop_t* loop, memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs)); req->fs.info.offset = offset; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__write(req); - return req->result; - } + POST; } @@ -2095,13 +2074,7 @@ int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__unlink(req); - return req->result; - } + POST; } @@ -2116,14 +2089,7 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, } req->fs.info.mode = mode; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__mkdir(req); - return req->result; - } + POST; } @@ -2136,13 +2102,7 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, if (err) return uv_translate_sys_error(err); - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__mkdtemp(req); - return req->result; - } + POST; } @@ -2155,13 +2115,7 @@ int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__rmdir(req); - return req->result; - } + POST; } @@ -2176,14 +2130,7 @@ int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, } req->fs.info.file_flags = flags; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__scandir(req); - return req->result; - } + POST; } @@ -2197,13 +2144,7 @@ int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__link(req); - return req->result; - } + POST; } @@ -2218,14 +2159,7 @@ int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, } req->fs.info.file_flags = flags; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__symlink(req); - return req->result; - } + POST; } @@ -2239,13 +2173,7 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__readlink(req); - return req->result; - } + POST; } @@ -2264,13 +2192,7 @@ int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__realpath(req); - return req->result; - } + POST; } @@ -2284,27 +2206,14 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__chown(req); - return req->result; - } + POST; } int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) { INIT(UV_FS_FCHOWN); - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__fchown(req); - return req->result; - } + POST; } @@ -2317,13 +2226,7 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__stat(req); - return req->result; - } + POST; } @@ -2336,27 +2239,14 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__lstat(req); - return req->result; - } + POST; } int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { INIT(UV_FS_FSTAT); req->file.fd = fd; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__fstat(req); - return req->result; - } + POST; } @@ -2370,41 +2260,21 @@ int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, return uv_translate_sys_error(err); } - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__rename(req); - return req->result; - } + POST; } int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { INIT(UV_FS_FSYNC); req->file.fd = fd; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__fsync(req); - return req->result; - } + POST; } int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { INIT(UV_FS_FDATASYNC); req->file.fd = fd; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__fdatasync(req); - return req->result; - } + POST; } @@ -2413,14 +2283,7 @@ int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd, INIT(UV_FS_FTRUNCATE); req->file.fd = fd; req->fs.info.offset = offset; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__ftruncate(req); - return req->result; - } + POST; } @@ -2443,14 +2306,7 @@ int uv_fs_copyfile(uv_loop_t* loop, return uv_translate_sys_error(err); req->fs.info.file_flags = flags; - - if (cb != NULL) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } - - fs__copyfile(req); - return req->result; + POST; } @@ -2461,14 +2317,7 @@ int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out, req->fs.info.fd_out = fd_out; req->fs.info.offset = in_offset; req->fs.info.bufsml[0].len = length; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__sendfile(req); - return req->result; - } + POST; } @@ -2485,14 +2334,7 @@ int uv_fs_access(uv_loop_t* loop, return uv_translate_sys_error(err); req->fs.info.mode = flags; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } - - fs__access(req); - return req->result; + POST; } @@ -2507,14 +2349,7 @@ int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, } req->fs.info.mode = mode; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__chmod(req); - return req->result; - } + POST; } @@ -2523,14 +2358,7 @@ int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode, INIT(UV_FS_FCHMOD); req->file.fd = fd; req->fs.info.mode = mode; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__fchmod(req); - return req->result; - } + POST; } @@ -2546,14 +2374,7 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, req->fs.time.atime = atime; req->fs.time.mtime = mtime; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__utime(req); - return req->result; - } + POST; } @@ -2563,12 +2384,5 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime, req->file.fd = fd; req->fs.time.atime = atime; req->fs.time.mtime = mtime; - - if (cb) { - QUEUE_FS_TP_JOB(loop, req); - return 0; - } else { - fs__futime(req); - return req->result; - } + POST; } From dff7ebe4f0bac1fdbcd6dec9eec72882597c78ca Mon Sep 17 00:00:00 2001 From: Andreas Hauptmann Date: Sun, 20 Aug 2017 14:42:22 +0200 Subject: [PATCH 486/632] unix: handle partial sends in uv_fs_copyfile() uv_fs_sendfile() is used as the fallback for uv_fs_copyfile(). However, sendfile() does not necessarily send all of the bytes in one call. This commit adds a loop to ensure all data is sent. Fixes: https://github.com/libuv/libuv/issues/1517 PR-URL: https://github.com/libuv/libuv/pull/1494 Reviewed-By: Santiago Gimeno Reviewed-By: Colin Ihrig --- src/unix/fs.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 3b816ecad..5a172cc78 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -791,6 +791,8 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { int dst_flags; int result; int err; + size_t bytes_to_send; + int64_t in_offset; dstfd = -1; @@ -826,14 +828,22 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { goto out; } - err = uv_fs_sendfile(NULL, - &fs_req, - dstfd, - srcfd, - 0, - statsbuf.st_size, - NULL); - uv_fs_req_cleanup(&fs_req); + bytes_to_send = statsbuf.st_size; + in_offset = 0; + while (bytes_to_send != 0) { + err = uv_fs_sendfile(NULL, + &fs_req, + dstfd, + srcfd, + in_offset, + bytes_to_send, + NULL); + uv_fs_req_cleanup(&fs_req); + if (err < 0) + break; + bytes_to_send -= fs_req.result; + in_offset += fs_req.result; + } out: if (err < 0) From eb4a37c8f640bdc6a0c09a3bd9c11f3669ff316f Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Wed, 6 Sep 2017 15:01:41 +0200 Subject: [PATCH 487/632] Revert "win, test: fix double close in test runner" Causes test output to be lost. This reverts commit bded0fa4f0243ea86366c4f6d974915277d7ca7f. Refs: https://github.com/libuv/libuv/issues/1426 Refs: https://github.com/libuv/libuv/pull/1450 PR-URL: https://github.com/libuv/libuv/pull/1523 Reviewed-By: Colin Ihrig --- test/runner-win.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/test/runner-win.c b/test/runner-win.c index 49c9a90cf..0f1b56e77 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -212,18 +212,8 @@ int process_copy_output(process_info_t* p, FILE* stream) { char buf[1024]; int fd, r; FILE* f; - HANDLE stdio_out_copy; - - if (!DuplicateHandle(GetCurrentProcess(), - p->stdio_out, - GetCurrentProcess(), - &stdio_out_copy, - 0, - FALSE, - 0)) - return -1; - fd = _open_osfhandle((intptr_t)stdio_out_copy, _O_RDONLY | _O_TEXT); + fd = _open_osfhandle((intptr_t)p->stdio_out, _O_RDONLY | _O_TEXT); if (fd == -1) return -1; f = _fdopen(fd, "rt"); From e79589d550e9a9aafcdefc066af4fec18b2adaad Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Wed, 6 Sep 2017 15:04:24 +0200 Subject: [PATCH 488/632] win, test: remove surplus CloseHandle Fixes: https://github.com/libuv/libuv/issues/1426 PR-URL: https://github.com/libuv/libuv/pull/1523 Reviewed-By: Colin Ihrig --- test/runner-win.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/runner-win.c b/test/runner-win.c index 0f1b56e77..d86fda3c5 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -300,7 +300,6 @@ int process_reap(process_info_t *p) { void process_cleanup(process_info_t *p) { CloseHandle(p->process); CloseHandle(p->stdio_in); - CloseHandle(p->stdio_out); } From b0f9fb2a07a5e638b1580fe9a42a356c3ab35f37 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 6 Sep 2017 09:41:30 -0400 Subject: [PATCH 489/632] 2017.09.07, Version 1.14.1 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.14.0: * fs, win: add support for user symlinks (Bartosz Sosnowski) * cygwin: include uv-posix.h header (Joel Winarske) * zos: fix semaphore initialization (jBarz) * zos: improve loop_count benchmark performance (jBarz) * zos, test: flush out the oob data in callback (jBarz) * unix,win: check for bad flags in uv_fs_copyfile() (cjihrig) * unix: modify argv[0] when process title is set (Matthew Taylor) * unix: don't use req->loop in uv__fs_copyfile() (cjihrig) * doc: fix a trivial typo (Vladimír Čunát) * android: fix uv_cond_timedwait on API level < 21 (Gergely Nagy) * win: add uv__once_init() calls (Bartosz Sosnowski) * unix,windows: init all requests in fs calls (cjihrig) * unix,windows: return UV_EINVAL on NULL fs reqs (cjihrig) * windows: add POST macro to fs functions (cjihrig) * unix: handle partial sends in uv_fs_copyfile() (A. Hauptmann) * Revert "win, test: fix double close in test runner" (Bartosz Sosnowski) * win, test: remove surplus CloseHandle (Bartosz Sosnowski) --- AUTHORS | 2 ++ ChangeLog | 39 +++++++++++++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 4 ++-- 5 files changed, 45 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index b87ec3a53..3562bb816 100644 --- a/AUTHORS +++ b/AUTHORS @@ -306,3 +306,5 @@ XadillaX Anticrisis Jacob Segal Maciej Szeptuch (Neverous) +Joel Winarske +Gergely Nagy diff --git a/ChangeLog b/ChangeLog index 961ac9590..7d1844e88 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +2017.09.07, Version 1.14.1 (Stable) + +Changes since version 1.14.0: + +* fs, win: add support for user symlinks (Bartosz Sosnowski) + +* cygwin: include uv-posix.h header (Joel Winarske) + +* zos: fix semaphore initialization (jBarz) + +* zos: improve loop_count benchmark performance (jBarz) + +* zos, test: flush out the oob data in callback (jBarz) + +* unix,win: check for bad flags in uv_fs_copyfile() (cjihrig) + +* unix: modify argv[0] when process title is set (Matthew Taylor) + +* unix: don't use req->loop in uv__fs_copyfile() (cjihrig) + +* doc: fix a trivial typo (Vladimír Čunát) + +* android: fix uv_cond_timedwait on API level < 21 (Gergely Nagy) + +* win: add uv__once_init() calls (Bartosz Sosnowski) + +* unix,windows: init all requests in fs calls (cjihrig) + +* unix,windows: return UV_EINVAL on NULL fs reqs (cjihrig) + +* windows: add POST macro to fs functions (cjihrig) + +* unix: handle partial sends in uv_fs_copyfile() (A. Hauptmann) + +* Revert "win, test: fix double close in test runner" (Bartosz Sosnowski) + +* win, test: remove surplus CloseHandle (Bartosz Sosnowski) + + 2017.08.17, Version 1.14.0 (Stable), e0d31e9e21870f88277746b6d59cf07b977cdfea Changes since version 1.13.1: diff --git a/appveyor.yml b/appveyor.yml index 2c82662c8..986c0d440 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.14.0.build{build} +version: v1.14.1.build{build} init: - git config --global core.autocrlf true diff --git a/configure.ac b/configure.ac index 3c74a7cfc..41349a092 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.14.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.14.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 8fd047345..9b891499e 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -33,8 +33,8 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 14 #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 ff0e8a4571b9c66163b97abda46d9139dca23434 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 6 Sep 2017 09:41:30 -0400 Subject: [PATCH 490/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 7d1844e88..d0b557501 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017.09.07, Version 1.14.1 (Stable) +2017.09.07, Version 1.14.1 (Stable), b0f9fb2a07a5e638b1580fe9a42a356c3ab35f37 Changes since version 1.14.0: From 1a682cb7c0be43cdc0bd7cce4f4514e723c69bb8 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 6 Sep 2017 09:50:12 -0400 Subject: [PATCH 491/632] Now working on version 1.14.2 --- 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 9b891499e..19099010e 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 14 -#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 0b41b0ad396870365f0af491d196070cba9e3b68 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Wed, 6 Sep 2017 23:10:15 +0200 Subject: [PATCH 492/632] unix: limit uv__has_forked_with_cfrunloop to macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The uv__has_forked_with_cfrunloop local variable is unused on BSDs and causes compilation warnings. Observed on NetBSD/amd64 8.99.2 with GCC 5.4.0. PR-URL: https://github.com/libuv/libuv/pull/1529 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno Reviewed-By: Colin Ihrig --- src/unix/kqueue.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 300bac07c..c9adddbdb 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -59,7 +59,9 @@ int uv__kqueue_init(uv_loop_t* loop) { } +#if defined(__APPLE__) static int uv__has_forked_with_cfrunloop; +#endif int uv__io_fork(uv_loop_t* loop) { int err; From 832ab902cf63dd42d6c75b60196dfb83d553e126 Mon Sep 17 00:00:00 2001 From: "tux.uudiin" <77389867@qq.com> Date: Tue, 8 Aug 2017 11:20:47 +0800 Subject: [PATCH 493/632] win: fix buffer size in uv__getpwuid_r() PR-URL: https://github.com/libuv/libuv/pull/1467 Reviewed-By: Colin Ihrig Reviewed-By: Bartosz Sosnowski --- src/win/util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/win/util.c b/src/win/util.c index d2e7f772c..a2acda115 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1388,7 +1388,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0) return uv_translate_sys_error(GetLastError()); - bufsize = sizeof(path); + bufsize = ARRAY_SIZE(path); if (!GetUserProfileDirectoryW(token, path, &bufsize)) { r = GetLastError(); CloseHandle(token); @@ -1403,7 +1403,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { CloseHandle(token); /* Get the username using GetUserNameW() */ - bufsize = sizeof(username); + bufsize = ARRAY_SIZE(username); if (!GetUserNameW(username, &bufsize)) { r = GetLastError(); From 6ad1e81547c83f9fe7c5a806b6b282642e8d3bca Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Thu, 22 Jun 2017 12:07:30 +0200 Subject: [PATCH 494/632] win,tty: improve SIGWINCH support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add SetWinEventHook for EVENT_CONSOLE_LAYOUT for better detection of console resize events. Ref: https://github.com/nodejs/node/issues/13197 PR-URL: https://github.com/libuv/libuv/pull/1408 Reviewed-By: Saúl Ibarra Corretgé --- src/win/tty.c | 114 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 34 deletions(-) diff --git a/src/win/tty.c b/src/win/tty.c index c4f99bdc7..c7b4df9bf 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -112,14 +112,30 @@ static int uv_tty_virtual_offset = -1; static int uv_tty_virtual_height = -1; static int uv_tty_virtual_width = -1; +/* The console window size + * We keep this separate from uv_tty_virtual_*. We use those values to only + * handle signalling SIGWINCH + */ + +static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE; +static int uv__tty_console_height = -1; +static int uv__tty_console_width = -1; + +static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param); +static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, + DWORD event, + HWND hwnd, + LONG idObject, + LONG idChild, + DWORD dwEventThread, + DWORD dwmsEventTime); + /* We use a semaphore rather than a mutex or critical section because in some cases (uv__cancel_read_console) we need take the lock in the main thread and release it in another thread. Using a semaphore ensures that in such scenario the main thread will still block when trying to acquire the lock. */ static uv_sem_t uv_tty_output_lock; -static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE; - static WORD uv_tty_default_text_attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; @@ -141,6 +157,18 @@ static void uv__determine_vterm_state(HANDLE handle); void uv_console_init(void) { 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 != NULL) { + QueueUserWorkItem(uv__tty_console_resize_message_loop_thread, + NULL, + WT_EXECUTELONGFUNCTION); + } } @@ -184,11 +212,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { if (uv__vterm_state == UV_UNCHECKED) uv__determine_vterm_state(handle); - /* Store the global tty output handle. This handle is used by TTY read */ - /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */ - /* is received. */ - uv_tty_output_handle = handle; - /* Remember the original console text attributes. */ uv_tty_capture_initial_style(&screen_buffer_info); @@ -705,25 +728,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, } records_left--; - /* If the window was resized, recompute the virtual window size. This */ - /* will trigger a SIGWINCH signal if the window size changed in an */ - /* way that matters to libuv. */ - if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) { - CONSOLE_SCREEN_BUFFER_INFO info; - - uv_sem_wait(&uv_tty_output_lock); - - if (uv_tty_output_handle != INVALID_HANDLE_VALUE && - GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) { - uv_tty_update_virtual_window(&info); - } - - uv_sem_post(&uv_tty_output_lock); - - continue; - } - - /* Ignore other events that are not key or resize events. */ + /* Ignore other events that are not key events. */ if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) { continue; } @@ -1125,14 +1130,6 @@ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { if (uv_tty_virtual_offset < 0) { uv_tty_virtual_offset = 0; } - - /* If the virtual window size changed, emit a SIGWINCH signal. Don't emit */ - /* if this was the first time the virtual window size was computed. */ - if (old_virtual_width != -1 && old_virtual_height != -1 && - (uv_tty_virtual_width != old_virtual_width || - uv_tty_virtual_height != old_virtual_height)) { - uv__signal_dispatch(SIGWINCH); - } } @@ -2280,3 +2277,52 @@ static void uv__determine_vterm_state(HANDLE handle) { uv__vterm_state = UV_SUPPORTED; } + +static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) { + CONSOLE_SCREEN_BUFFER_INFO sb_info; + MSG msg; + + if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) + return 0; + + uv__tty_console_width = sb_info.dwSize.X; + uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; + + if (!SetWinEventHook(EVENT_CONSOLE_LAYOUT, + EVENT_CONSOLE_LAYOUT, + NULL, + uv__tty_console_resize_event, + 0, + 0, + WINEVENT_OUTOFCONTEXT)) + return 0; + + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return 0; +} + +static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, + DWORD event, + HWND hwnd, + LONG idObject, + LONG idChild, + DWORD dwEventThread, + DWORD dwmsEventTime) { + CONSOLE_SCREEN_BUFFER_INFO sb_info; + int width, height; + + if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) + return; + + width = sb_info.dwSize.X; + height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; + + if (width != uv__tty_console_width || height != uv__tty_console_height) { + uv__tty_console_width = width; + uv__tty_console_height = height; + uv__signal_dispatch(SIGWINCH); + } +} From eaf25ae3eb8fe567b8be15614996b112dbf5c11b Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 13 Sep 2017 14:14:25 -0400 Subject: [PATCH 495/632] unix: use fchmod() in uv_fs_copyfile() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduces fchmod() in uv_fs_copyfile() to set the mode of the destination file. Refs: https://github.com/nodejs/node/issues/15394 PR-URL: https://github.com/libuv/libuv/pull/1547 Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- src/unix/fs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index 5a172cc78..a63662558 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -828,6 +828,11 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { goto out; } + if (fchmod(dstfd, statsbuf.st_mode) == -1) { + err = -errno; + goto out; + } + bytes_to_send = statsbuf.st_size; in_offset = 0; while (bytes_to_send != 0) { From a41f8b52e1e22b39a2d06a600e47dad96fae35c1 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 19 Sep 2017 18:02:51 -0400 Subject: [PATCH 496/632] unix: support copying empty files Initialize the error variable in uv_fs_copyfile() to zero. If the source file being copied has no data in it, then it's possible to make it to the exit without ever setting error. In this situation, the function's behavior is unpredictable. Refs: https://github.com/libuv/libuv/pull/1551 PR-URL: https://github.com/libuv/libuv/pull/1552 Reviewed-By: Santiago Gimeno Reviewed-By: Ben Noordhuis --- src/unix/fs.c | 1 + test/test-fs-copyfile.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index a63662558..00af4675e 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -795,6 +795,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { int64_t in_offset; dstfd = -1; + err = 0; /* Open the source file. */ srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL); diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index 2d1f9079a..e91044e0e 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -119,6 +119,13 @@ TEST_IMPL(fs_copyfile) { ASSERT(r == 0); 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); + handle_result(&req); + /* Copies file synchronously. Overwrites existing file. */ r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL); ASSERT(r == 0); @@ -141,9 +148,9 @@ TEST_IMPL(fs_copyfile) { unlink(dst); r = uv_fs_copyfile(loop, &req, fixture, dst, 0, handle_result); ASSERT(r == 0); - ASSERT(result_check_count == 3); - uv_run(loop, UV_RUN_DEFAULT); ASSERT(result_check_count == 4); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(result_check_count == 5); unlink(dst); /* Cleanup */ return 0; From b0653625e26cef175156403823e0758f550cce3e Mon Sep 17 00:00:00 2001 From: Nick Logan Date: Mon, 18 Sep 2017 18:47:45 -0400 Subject: [PATCH 497/632] unix: truncate destination in uv_fs_copyfile() This commit adds the O_TRUNC flag to the destination file in the sendfile() fallback. This allows smaller source files to be properly copied into larger existing destination files. Refs: https://github.com/libuv/libuv/pull/1551 PR-URL: https://github.com/libuv/libuv/pull/1552 Reviewed-By: Santiago Gimeno Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/unix/fs.c | 2 +- test/test-fs-copyfile.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 00af4675e..52b3123fb 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -810,7 +810,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { goto out; } - dst_flags = O_WRONLY | O_CREAT; + dst_flags = O_WRONLY | O_CREAT | O_TRUNC; if (req->flags & UV_FS_COPYFILE_EXCL) dst_flags |= O_EXCL; diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index e91044e0e..460c1dc6a 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -68,7 +68,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, S_IWUSR | S_IRUSR, NULL); + 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); file = r; @@ -136,6 +137,12 @@ TEST_IMPL(fs_copyfile) { ASSERT(r == UV_EEXIST); uv_fs_req_cleanup(&req); + /* Truncates when an existing destination is larger than the source file. */ + touch_file(src, 1); + r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL); + ASSERT(r == 0); + handle_result(&req); + /* Copies a larger file. */ unlink(dst); touch_file(src, 4096 * 2); @@ -148,9 +155,9 @@ TEST_IMPL(fs_copyfile) { unlink(dst); r = uv_fs_copyfile(loop, &req, fixture, dst, 0, handle_result); ASSERT(r == 0); - ASSERT(result_check_count == 4); - uv_run(loop, UV_RUN_DEFAULT); ASSERT(result_check_count == 5); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(result_check_count == 6); unlink(dst); /* Cleanup */ return 0; From c78caf0b34c18f62a945659eacf63cfb5a3c8396 Mon Sep 17 00:00:00 2001 From: darobs Date: Wed, 13 Sep 2017 10:42:05 -0700 Subject: [PATCH 498/632] win,build: keep cwd when setting build environment Fixes: https://github.com/libuv/libuv/issues/1545 PR-URL: https://github.com/libuv/libuv/pull/1546 Reviewed-By: Bartosz Sosnowski --- vcbuild.bat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vcbuild.bat b/vcbuild.bat index 698044df4..46b347610 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -55,6 +55,8 @@ set "VSINSTALLDIR=" call tools\vswhere_usability_wrapper.cmd if "_%VCINSTALLDIR%_" == "__" goto vs-set-2015 @rem Need to clear VSINSTALLDIR for vcvarsall to work as expected. +@rem Keep current working directory after call to vcvarsall +set "VSCMD_START_DIR=%CD%" set vcvars_call="%VCINSTALLDIR%\Auxiliary\Build\vcvarsall.bat" %vs_toolset% echo calling: %vcvars_call% call %vcvars_call% From fbb8132d90a4009cd8d71704d179b1efff022075 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sun, 10 Sep 2017 00:27:25 +0200 Subject: [PATCH 499/632] test: add NetBSD support to test-udp-ipv6.c NetBSD and FreeBSD can share the can_ipv6_ipv4_dual() function as is. This commit also corrects the function definition to be compliant with C standards. This fixes a warning on NetBSD 8.99.2 with GCC 5.4.0. PR-URL: https://github.com/libuv/libuv/pull/1535 Reviewed-By: Santiago Gimeno Reviewed-By: Colin Ihrig --- test/test-udp-ipv6.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test-udp-ipv6.c b/test/test-udp-ipv6.c index 54b364da9..000079185 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__) +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) #include #endif @@ -47,8 +47,8 @@ static int send_cb_called; static int recv_cb_called; static int close_cb_called; -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -static int can_ipv6_ipv4_dual() { +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) +static int can_ipv6_ipv4_dual(void) { int v6only; size_t size = sizeof(int); @@ -171,7 +171,7 @@ TEST_IMPL(udp_dual_stack) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) if (!can_ipv6_ipv4_dual()) RETURN_SKIP("IPv6-IPv4 dual stack not supported"); #endif From c0504885ea4a7f763a5c33b5dda8dfd9d42c5be6 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sun, 10 Sep 2017 00:16:36 +0200 Subject: [PATCH 500/632] unix: add NetBSD support in core.c NetBSD supports: - O_CLOEXEC - accept4(2) like API with paccept(2) NetBSD 8.0 will get compat accept4(2) - SOCK_NONBLOCK - SOCK_CLOEXEC - dup3(2) PR-URL: https://github.com/libuv/libuv/pull/1534 Reviewed-By: Santiago Gimeno Reviewed-By: Colin Ihrig --- src/unix/core.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index bee641cb4..ef82ee27b 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -58,13 +58,19 @@ #if defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) # include # include # include # define UV__O_CLOEXEC O_CLOEXEC # if defined(__FreeBSD__) && __FreeBSD__ >= 10 # define uv__accept4 accept4 +# endif +# if defined(__NetBSD__) +# define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d)) +# endif +# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__) # define UV__SOCK_NONBLOCK SOCK_NONBLOCK # define UV__SOCK_CLOEXEC SOCK_CLOEXEC # endif @@ -462,7 +468,9 @@ int uv__accept(int sockfd) { assert(sockfd >= 0); while (1) { -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) +#if defined(__linux__) || \ + (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \ + defined(__NetBSD__) static int no_accept4; if (no_accept4) @@ -988,7 +996,7 @@ int uv__open_cloexec(const char* path, int flags) { int uv__dup2_cloexec(int oldfd, int newfd) { int r; -#if defined(__FreeBSD__) && __FreeBSD__ >= 10 +#if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__) r = dup3(oldfd, newfd, O_CLOEXEC); if (r == -1) return -errno; From 0afccdb0a48e776b93da4fb3962fa3a5c42f9bae Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 6 Sep 2017 17:41:13 +0200 Subject: [PATCH 501/632] linux: increase thread stack size with musl libc musl has tiny default thread stack sizes compared to glibc (80 kB vs. 2048 kB or more) so set an explicit stack size to harmonize between different libcs. Fixes: https://github.com/libuv/libuv/issues/1507 PR-URL: https://github.com/libuv/libuv/pull/1526 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/unix/thread.c | 55 +++++++++++++++++++++++++++++++--------------- test/test-thread.c | 22 ++++++++++++------- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/unix/thread.c b/src/unix/thread.c index f88462259..35d3e77b0 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -145,36 +145,55 @@ int pthread_barrier_destroy(pthread_barrier_t* barrier) { #endif -int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { - int err; - pthread_attr_t* attr; -#if defined(__APPLE__) - pthread_attr_t attr_storage; +/* 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. + * + * 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 thread_stack_size(void) { +#if defined(__APPLE__) || defined(__linux__) struct rlimit lim; -#endif - /* On OSX threads other than the main thread are created with a reduced stack - * size by default, adjust it to RLIMIT_STACK. - */ -#if defined(__APPLE__) if (getrlimit(RLIMIT_STACK, &lim)) abort(); - attr = &attr_storage; - if (pthread_attr_init(attr)) - abort(); - if (lim.rlim_cur != RLIM_INFINITY) { /* pthread_attr_setstacksize() expects page-aligned values. */ lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); - if (lim.rlim_cur >= PTHREAD_STACK_MIN) - if (pthread_attr_setstacksize(attr, lim.rlim_cur)) - abort(); + return lim.rlim_cur; } +#endif + +#if !defined(__linux__) + return 0; +#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__) + return 4 << 20; /* glibc default. */ #else - attr = NULL; + return 2 << 20; /* glibc default. */ #endif +} + + +int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { + int err; + size_t stack_size; + pthread_attr_t* attr; + pthread_attr_t attr_storage; + + attr = NULL; + stack_size = thread_stack_size(); + + if (stack_size > 0) { + attr = &attr_storage; + + if (pthread_attr_init(attr)) + abort(); + + if (pthread_attr_setstacksize(attr, stack_size)) + abort(); + } err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg); diff --git a/test/test-thread.c b/test/test-thread.c index 10bec3fe6..b0e87e208 100644 --- a/test/test-thread.c +++ b/test/test-thread.c @@ -211,22 +211,28 @@ TEST_IMPL(thread_local_storage) { } -#if defined(__APPLE__) static void thread_check_stack(void* arg) { - /* 512KB is the default stack size of threads other than the main thread - * on OSX. */ +#if defined(__APPLE__) + /* 512 kB is the default stack size of threads other than the main thread + * on MacOS. */ ASSERT(pthread_get_stacksize_np(pthread_self()) > 512*1024); -} +#elif defined(__linux__) && defined(__GLIBC__) + struct rlimit lim; + size_t stack_size; + pthread_attr_t attr; + ASSERT(0 == 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(stack_size >= lim.rlim_cur); #endif +} TEST_IMPL(thread_stack_size) { -#if defined(__APPLE__) uv_thread_t thread; ASSERT(0 == uv_thread_create(&thread, thread_check_stack, NULL)); ASSERT(0 == uv_thread_join(&thread)); return 0; -#else - RETURN_SKIP("OSX only test"); -#endif } From 5fa0f0b6e1a2f922ce7d365cb1a1d3cb2a322f60 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sat, 9 Sep 2017 13:41:34 +0200 Subject: [PATCH 502/632] netbsd: correct uv_exepath() on NetBSD Setup proper sysctl(2) arguments in order to retrieve the executable name. Use an intermediate buffer beacause if it is too short, the sysctl(2) call will return error. With this intermediate buffer populate the outer one. Note issue with too long file names on NetBSD-8(beta), this is caused by the current implementation of vnode to path translator in the kernel. It does not cache longer file names than 31 character ones. PR-URL: https://github.com/libuv/libuv/pull/1532 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- src/unix/netbsd.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index c54c04df2..d9066349c 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -66,22 +66,32 @@ void uv_loadavg(double avg[3]) { int uv_exepath(char* buffer, size_t* size) { + /* Intermediate buffer, retrieving partial path name does not work + * As of NetBSD-8(beta), vnode->path translator does not handle files + * with longer names than 31 characters. + */ + char int_buf[PATH_MAX]; + size_t int_size; int mib[4]; - size_t cb; - pid_t mypid; if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; - mypid = getpid(); mib[0] = CTL_KERN; mib[1] = KERN_PROC_ARGS; - mib[2] = mypid; - mib[3] = KERN_PROC_ARGV; + mib[2] = -1; + mib[3] = KERN_PROC_PATHNAME; + int_size = ARRAY_SIZE(int_buf); - cb = *size; - if (sysctl(mib, 4, buffer, &cb, NULL, 0)) + if (sysctl(mib, 4, int_buf, &int_size, NULL, 0)) return -errno; + + /* Copy string from the intermediate buffer to outer one with appropriate + * length. + */ + strlcpy(buffer, int_buf, *size); + + /* Set new size. */ *size = strlen(buffer); return 0; From bf144cee422b44d7aaa348904fccfc48def43dae Mon Sep 17 00:00:00 2001 From: John Barboza Date: Sat, 23 Sep 2017 13:48:36 -0400 Subject: [PATCH 503/632] test: clean up semaphore after use On systems that use System V semaphores, it is necessary to destroy semaphores to free up system resources when the process finishes execution. PR-URL: https://github.com/libuv/libuv/pull/1559 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- test/test-signal-multiple-loops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test-signal-multiple-loops.c b/test/test-signal-multiple-loops.c index 11193dcf5..1272d4576 100644 --- a/test/test-signal-multiple-loops.c +++ b/test/test-signal-multiple-loops.c @@ -275,6 +275,7 @@ TEST_IMPL(signal_multiple_loops) { ASSERT(r == 0); } + uv_sem_destroy(&sem); printf("signal1_cb calls: %d\n", signal1_cb_counter); printf("signal2_cb calls: %d\n", signal2_cb_counter); printf("loops created and destroyed: %d\n", loop_creation_counter); From 66b8b2f76d457ac50778a3d363183fe6d2fd063b Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Sun, 13 Aug 2017 14:20:37 -0400 Subject: [PATCH 504/632] win,build: bump vswhere_usability_wrapper to 2.0.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1479 Fixes: https://github.com/nodejs/libuv/issues/1476 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Bartosz Sosnowski --- tools/vswhere_usability_wrapper.cmd | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/vswhere_usability_wrapper.cmd b/tools/vswhere_usability_wrapper.cmd index e4acf03e1..ee0549c80 100644 --- a/tools/vswhere_usability_wrapper.cmd +++ b/tools/vswhere_usability_wrapper.cmd @@ -2,23 +2,23 @@ :: Distributed under MIT style license or the libuv license :: See accompanying file LICENSE at https://github.com/node4good/windows-autoconf :: or libuv LICENSE file at https://github.com/libuv/libuv -:: version: 1.15.3 +:: version: 2.0.0 @if not defined DEBUG_HELPER @ECHO OFF setlocal +if "%~1"=="prerelease" set VSWHERE_WITH_PRERELEASE=1 set "InstallerPath=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer" if not exist "%InstallerPath%" set "InstallerPath=%ProgramFiles%\Microsoft Visual Studio\Installer" -if not exist "%InstallerPath%" exit goto :no-vswhere +if not exist "%InstallerPath%" goto :no-vswhere :: Manipulate %Path% for easier " handeling -set Path=%Path%;%InstallerPath% +set "Path=%Path%;%InstallerPath%" where vswhere 2> nul > nul if errorlevel 1 goto :no-vswhere set VSWHERE_REQ=-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 set VSWHERE_PRP=-property installationPath set VSWHERE_LMT=-version "[15.0,16.0)" vswhere -prerelease > nul -if "%~1"=="prerelase" set VSWHERE_WITH_PRERELASE=1 -if not errorlevel 1 if "%VSWHERE_WITH_PRERELASE%"=="1" set "VSWHERE_LMT=%VSWHERE_LMT% -prerelease" +if not errorlevel 1 if "%VSWHERE_WITH_PRERELEASE%"=="1" set "VSWHERE_LMT=%VSWHERE_LMT% -prerelease" SET VSWHERE_ARGS=-latest -products * %VSWHERE_REQ% %VSWHERE_PRP% %VSWHERE_LMT% for /f "usebackq tokens=*" %%i in (`vswhere %VSWHERE_ARGS%`) do ( endlocal From b21c1f900c55572917d64c5e208c3eb8850ffd18 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 23 Sep 2017 21:20:49 -0400 Subject: [PATCH 505/632] win: let UV_PROCESS_WINDOWS_HIDE hide consoles The existing UV_PROCESS_WINDOWS_HIDE flag only applies to executables linked to the WINDOWS subsystem. This allows CONSOLE subsystem applications to pop up a console window. This commit sets the CREATE_NO_WINDOW process flag when UV_PROCESS_WINDOWS_HIDE to prevent this behavior. Refs: https://github.com/nodejs/node/pull/15380 Refs: https://github.com/joyent/libuv/pull/627 Refs: https://github.com/libuv/libuv/issues/965 PR-URL: https://github.com/libuv/libuv/pull/1558 Reviewed-By: Ben Noordhuis Reviewed-By: Bartosz Sosnowski --- src/win/process.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index 97b67ca52..764250e13 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -1058,15 +1058,18 @@ int uv_spawn(uv_loop_t* loop, startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1); startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2); + process_flags = CREATE_UNICODE_ENVIRONMENT; + if (options->flags & UV_PROCESS_WINDOWS_HIDE) { /* Use SW_HIDE to avoid any potential process window. */ startup.wShowWindow = SW_HIDE; + + /* Hide console windows. */ + process_flags |= CREATE_NO_WINDOW; } else { startup.wShowWindow = SW_SHOWDEFAULT; } - process_flags = CREATE_UNICODE_ENVIRONMENT; - if (options->flags & UV_PROCESS_DETACHED) { /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That * means that libuv might not let you create a fully daemonized process From 24334e0739d72e3f485f0cc573091673e8e045f5 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Sat, 23 Sep 2017 11:57:45 -0400 Subject: [PATCH 506/632] zos: lock protect global epoll list in epoll_ctl This will eliminate a race condition that occurs between epoll_close_fd, epoll_ctl and epoll_create in the signal_multiple_loops test. PR-URL: https://github.com/libuv/libuv/pull/1560 Reviewed-By: Ben Noordhuis --- src/unix/os390-syscalls.c | 24 +++++++++++++++--------- src/unix/os390.c | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c index 08623f4ea..ea4e11ac1 100644 --- a/src/unix/os390-syscalls.c +++ b/src/unix/os390-syscalls.c @@ -130,17 +130,17 @@ static void epoll_init(void) { uv__os390_epoll* epoll_create1(int flags) { uv__os390_epoll* lst; - uv_once(&once, epoll_init); - uv_mutex_lock(&global_epoll_lock); lst = uv__malloc(sizeof(*lst)); - if (lst == -1) - return NULL; - QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); - uv_mutex_unlock(&global_epoll_lock); + if (lst != NULL) { + /* initialize list */ + lst->size = 0; + lst->items = NULL; + uv_once(&once, epoll_init); + uv_mutex_lock(&global_epoll_lock); + QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); + uv_mutex_unlock(&global_epoll_lock); + } - /* initialize list */ - lst->size = 0; - lst->items = NULL; return lst; } @@ -149,8 +149,11 @@ int epoll_ctl(uv__os390_epoll* lst, int op, int fd, struct epoll_event *event) { + uv_mutex_lock(&global_epoll_lock); + if(op == EPOLL_CTL_DEL) { if (fd >= lst->size || lst->items[fd].fd == -1) { + uv_mutex_unlock(&global_epoll_lock); errno = ENOENT; return -1; } @@ -158,6 +161,7 @@ int epoll_ctl(uv__os390_epoll* lst, } else if(op == EPOLL_CTL_ADD) { maybe_resize(lst, fd + 1); if (lst->items[fd].fd != -1) { + uv_mutex_unlock(&global_epoll_lock); errno = EEXIST; return -1; } @@ -165,6 +169,7 @@ int epoll_ctl(uv__os390_epoll* lst, lst->items[fd].events = event->events; } else if(op == EPOLL_CTL_MOD) { if (fd >= lst->size || lst->items[fd].fd == -1) { + uv_mutex_unlock(&global_epoll_lock); errno = ENOENT; return -1; } @@ -172,6 +177,7 @@ int epoll_ctl(uv__os390_epoll* lst, } else abort(); + uv_mutex_unlock(&global_epoll_lock); return 0; } diff --git a/src/unix/os390.c b/src/unix/os390.c index 559970de2..eaeb43e6c 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -117,7 +117,7 @@ void uv_loadavg(double avg[3]) { int uv__platform_loop_init(uv_loop_t* loop) { uv__os390_epoll* ep; - ep = epoll_create1(UV__EPOLL_CLOEXEC); + ep = epoll_create1(0); loop->ep = ep; if (ep == NULL) return -errno; From eb1fe77f664bd05f0f4a5f0c397696d4e3af4ac4 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Fri, 22 Sep 2017 15:19:01 -0400 Subject: [PATCH 507/632] zos: change platform name to match python The latest python on z/OS (2.7.13) was changed to update sys.platform to return "zos" instead of "os390". So a change has been submitted to the official gyp repository here. PR-URL: https://github.com/libuv/libuv/pull/1557 Refs: https://chromium-review.googlesource.com/c/external/gyp/+/679077 Reviewed-By: Ben Noordhuis Reviewed-By: Gibson Fahnestock Reviewed-By: Refael Ackermann --- common.gypi | 6 +++--- uv.gyp | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/common.gypi b/common.gypi index ec482340c..821fb79c5 100644 --- a/common.gypi +++ b/common.gypi @@ -35,7 +35,7 @@ 'OTHER_CFLAGS': [ '-Wno-strict-aliasing' ], }, 'conditions': [ - ['OS != "os390"', { + ['OS != "zos"', { 'cflags': [ '-O0', '-fwrapv' ] }], ['OS == "android"', { @@ -80,7 +80,7 @@ }, }, 'conditions': [ - ['OS != "os390"', { + ['OS != "zos"', { 'cflags': [ '-fomit-frame-pointer', '-fdata-sections', @@ -160,7 +160,7 @@ 'cflags': [ '-pthreads' ], 'ldflags': [ '-pthreads' ], }], - [ 'OS not in "solaris android os390"', { + [ 'OS not in "solaris android zos"', { 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], diff --git a/uv.gyp b/uv.gyp index cac6da819..07458995b 100644 --- a/uv.gyp +++ b/uv.gyp @@ -10,10 +10,10 @@ ['OS=="solaris"', { 'cflags': [ '-pthreads' ], }], - ['OS not in "solaris android os390"', { + ['OS not in "solaris android zos"', { 'cflags': [ '-pthread' ], }], - ['OS in "os390"', { + ['OS in "zos"', { 'defines': [ '_UNIX03_THREADS', '_UNIX03_SOURCE', @@ -172,10 +172,10 @@ ['OS=="solaris"', { 'ldflags': [ '-pthreads' ], }], - [ 'OS=="os390" and uv_library=="shared_library"', { + [ 'OS=="zos" and uv_library=="shared_library"', { 'ldflags': [ '-Wl,DLL' ], }], - ['OS != "solaris" and OS != "android" and OS != "os390"', { + ['OS != "solaris" and OS != "android" and OS != "zos"', { 'ldflags': [ '-pthread' ], }], ], @@ -183,14 +183,14 @@ 'conditions': [ ['uv_library=="shared_library"', { 'conditions': [ - ['OS=="os390"', { + ['OS=="zos"', { 'cflags': [ '-qexportall' ], }, { 'cflags': [ '-fPIC' ], }], ], }], - ['uv_library=="shared_library" and OS!="mac" and OS!="os390"', { + ['uv_library=="shared_library" and OS!="mac" and OS!="zos"', { # This will cause gyp to set soname # Must correspond with UV_VERSION_MAJOR # in include/uv-version.h @@ -198,10 +198,10 @@ }], ], }], - [ 'OS in "linux mac ios android os390"', { + [ 'OS in "linux mac ios android zos"', { 'sources': [ 'src/unix/proctitle.c' ], }], - [ 'OS != "os390"', { + [ 'OS != "zos"', { 'cflags': [ '-fvisibility=hidden', '-g', @@ -224,7 +224,7 @@ '_DARWIN_UNLIMITED_SELECT=1', ] }], - [ 'OS!="mac" and OS!="os390"', { + [ 'OS!="mac" and OS!="zos"', { # Enable on all platforms except OS X. The antique gcc/clang that # ships with Xcode emits waaaay too many false positives. 'cflags': [ '-Wstrict-aliasing' ], @@ -317,7 +317,7 @@ ['uv_library=="shared_library"', { 'defines': [ 'BUILDING_UV_SHARED=1' ] }], - ['OS=="os390"', { + ['OS=="zos"', { 'sources': [ 'src/unix/pthread-fixes.c', 'src/unix/no-fsevents.c', @@ -489,7 +489,7 @@ 'test/runner-unix.h', ], 'conditions': [ - [ 'OS != "os390"', { + [ 'OS != "zos"', { 'defines': [ '_GNU_SOURCE' ], 'cflags': [ '-Wno-long-long' ], 'xcode_settings': { @@ -518,7 +518,7 @@ ['uv_library=="shared_library"', { 'defines': [ 'USING_UV_SHARED=1' ], 'conditions': [ - [ 'OS == "os390"', { + [ 'OS == "zos"', { 'cflags': [ '-Wc,DLL' ], }], ], @@ -579,7 +579,7 @@ ['uv_library=="shared_library"', { 'defines': [ 'USING_UV_SHARED=1' ], 'conditions': [ - [ 'OS == "os390"', { + [ 'OS == "zos"', { 'cflags': [ '-Wc,DLL' ], }], ], From 11a7aa4a09e2bd2ff3def0ac0c8ff5787b12d7f2 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Tue, 26 Sep 2017 03:12:13 +0800 Subject: [PATCH 508/632] android: fix getifaddrs() The most critical bug is using IFLA_RTA instead of IFA_RTA on address message. This causes android to not return any ipv6 address. PR-URL: https://github.com/libuv/libuv/pull/1561 Reviewed-By: Ben Noordhuis --- src/unix/android-ifaddrs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/unix/android-ifaddrs.c b/src/unix/android-ifaddrs.c index 1a842ced4..bf30b1417 100644 --- a/src/unix/android-ifaddrs.c +++ b/src/unix/android-ifaddrs.c @@ -457,7 +457,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, char *l_name; char *l_addr; - for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + 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) @@ -479,7 +479,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); break; case IFA_LABEL: - l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); + l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1); break; default: break; @@ -504,7 +504,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, } l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); - for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + 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); @@ -567,7 +567,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, { 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); - char l_mask[16] = {0}; + unsigned char l_mask[16] = {0}; unsigned i; for(i=0; i<(l_prefix/8); ++i) { From 3877a90e69b9fa3bc11ee3e2c1b29a1dc3841ea3 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sat, 9 Sep 2017 20:21:31 +0200 Subject: [PATCH 509/632] netbsd: implement uv__tty_is_slave() NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave device name for both descriptors, the master one and slave one. Workaround this problem and verify the device major and compare it with the pts driver. Major numbers for the master and the slave TTY are machine-dependent. On amd64 they are respectively 6 (ptc) and 5 (pts). PR-URL: https://github.com/libuv/libuv/pull/1533 Reviewed-By: Ben Noordhuis --- src/unix/tty.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/unix/tty.c b/src/unix/tty.c index b2d37f4c2..357f9748f 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -48,6 +48,42 @@ static int uv__tty_is_slave(const int fd) { char dummy[256]; result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0; +#elif defined(__NetBSD__) + /* + * NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave + * device name for both descriptors, the master one and slave one. + * + * Implement function to compare major device number with pts devices. + * + * The major numbers are machine-dependent, on NetBSD/amd64 they are + * respectively: + * - master tty: ptc - major 6 + * - slave tty: pts - major 5 + */ + + struct stat sb; + /* Lookup device's major for the pts driver and cache it. */ + static devmajor_t pts = NODEVMAJOR; + + if (pts == NODEVMAJOR) { + pts = getdevmajor("pts", S_IFCHR); + if (pts == NODEVMAJOR) + abort(); + } + + /* Lookup stat structure behind the file descriptor. */ + if (fstat(fd, &sb) != 0) + abort(); + + /* Assert character device. */ + if (!S_ISCHR(sb.st_mode)) + abort(); + + /* Assert valid major. */ + if (major(sb.st_rdev) == NODEVMAJOR) + abort(); + + result = (pts == major(sb.st_rdev)); #else /* Fallback to ptsname */ From 8d3645a19bccfd656bfae8f05b9b9744e1caa862 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Fri, 11 Aug 2017 06:54:58 -0400 Subject: [PATCH 510/632] zos: fix readlink for mounts with system variables On z/OS, fs mounts can have variables starting with '$'. The problem is that following symlinks that contain these variables can lead to a loop because readlink($SYSVAR) will return $SYSVAR. To work around this, we must resolve the $SYSVAR to an actual path using realpath. More information about z/OS symlink resolution is available here: https://www.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/ com.ibm.zos.v2r1.bpxb100/sym.htm PR-URL: https://github.com/libuv/libuv/pull/1472 Reviewed-By: Ben Noordhuis --- src/unix/fs.c | 5 +++ src/unix/os390-syscalls.c | 69 +++++++++++++++++++++++++++++++++++++++ src/unix/os390-syscalls.h | 1 + 3 files changed, 75 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index 52b3123fb..2684c814a 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -438,7 +438,12 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) { return -1; } +#if defined(__MVS__) + len = os390_readlink(req->path, buf, len); +#else len = readlink(req->path, buf, len); +#endif + if (len == -1) { uv__free(buf); diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c index ea4e11ac1..ca539c26f 100644 --- a/src/unix/os390-syscalls.c +++ b/src/unix/os390-syscalls.c @@ -327,3 +327,72 @@ char* mkdtemp(char* path) { return path; } + + +ssize_t os390_readlink(const char* path, char* buf, size_t len) { + ssize_t rlen; + ssize_t vlen; + ssize_t plen; + char* delimiter; + char old_delim; + char* tmpbuf; + char realpathstr[PATH_MAX + 1]; + + tmpbuf = uv__malloc(len + 1); + if (tmpbuf == NULL) { + errno = ENOMEM; + return -1; + } + + rlen = readlink(path, tmpbuf, len); + if (rlen < 0) { + uv__free(tmpbuf); + return rlen; + } + + if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) { + /* Straightforward readlink. */ + memcpy(buf, tmpbuf, rlen); + uv__free(tmpbuf); + return rlen; + } + + /* + * There is a parmlib variable at the beginning + * which needs interpretation. + */ + tmpbuf[rlen] = '\0'; + delimiter = strchr(tmpbuf + 2, '/'); + if (delimiter == NULL) + /* No slash at the end */ + delimiter = strchr(tmpbuf + 2, '\0'); + + /* Read real path of the variable. */ + old_delim = *delimiter; + *delimiter = '\0'; + if (realpath(tmpbuf, realpathstr) == NULL) { + uv__free(tmpbuf); + return -1; + } + + /* realpathstr is not guaranteed to end with null byte.*/ + realpathstr[PATH_MAX] = '\0'; + + /* Reset the delimiter and fill up the buffer. */ + *delimiter = old_delim; + plen = strlen(delimiter); + vlen = strlen(realpathstr); + rlen = plen + vlen; + if (rlen > len) { + uv__free(tmpbuf); + errno = ENAMETOOLONG; + return -1; + } + memcpy(buf, realpathstr, vlen); + memcpy(buf + vlen, delimiter, plen); + + /* Done using temporary buffer. */ + uv__free(tmpbuf); + + return rlen; +} diff --git a/src/unix/os390-syscalls.h b/src/unix/os390-syscalls.h index 61a7cee83..7aba3d27d 100644 --- a/src/unix/os390-syscalls.h +++ b/src/unix/os390-syscalls.h @@ -65,5 +65,6 @@ int scandir(const char* maindir, struct dirent*** namelist, int (*compar)(const struct dirent **, const struct dirent **)); char *mkdtemp(char* path); +ssize_t os390_readlink(const char* path, char* buf, size_t len); #endif /* UV_OS390_SYSCALL_H_ */ From c1ca7f078d0fcc408b849bde369932427255b79c Mon Sep 17 00:00:00 2001 From: Sakthipriyan Vairamani Date: Tue, 12 Sep 2017 02:33:12 -0700 Subject: [PATCH 511/632] test: sort the tests alphabetically As it is, when the tests run, there is no indicator as to how long the tests will run, how many more tests are pending. PR-URL: https://github.com/libuv/libuv/pull/1543 Reviewed-By: Ben Noordhuis --- test/runner.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/test/runner.c b/test/runner.c index 4f54f85e2..5e4411877 100644 --- a/test/runner.c +++ b/test/runner.c @@ -29,6 +29,13 @@ char executable_path[sizeof(executable_path)]; +static int compare_task(const void* va, const void* vb) { + const task_entry_t* a = va; + const task_entry_t* b = vb; + return strcmp(a->task_name, b->task_name); +} + + const char* fmt(double d) { static char buf[1024]; static char* p; @@ -67,6 +74,7 @@ const char* fmt(double d) { int run_tests(int benchmark_output) { + int actual; int total; int passed; int failed; @@ -76,13 +84,16 @@ int run_tests(int benchmark_output) { task_entry_t* task; /* Count the number of tests. */ + actual = 0; total = 0; - for (task = TASKS; task->main; task++) { + for (task = TASKS; task->main; task++, actual++) { if (!task->is_helper) { total++; } } + qsort(TASKS, actual, sizeof(TASKS[0]), compare_task); + fprintf(stderr, "1..%d\n", total); fflush(stderr); @@ -352,12 +363,6 @@ int run_test_part(const char* test, const char* part) { } -static int compare_task(const void* va, const void* vb) { - const task_entry_t* a = va; - const task_entry_t* b = vb; - return strcmp(a->task_name, b->task_name); -} - static int find_helpers(const task_entry_t* task, const task_entry_t** helpers) { From 939a8f1a5b8a7b419cf4c44295e0de57a5c37500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlo=20Marcelo=20Arenas=20Bel=C3=B3n?= Date: Wed, 6 Sep 2017 17:09:41 -0700 Subject: [PATCH 512/632] windows: fix compilation warnings Refs: https://github.com/libuv/libuv/pull/1530 PR-URL: https://github.com/libuv/libuv/pull/1542 Reviewed-By: Ben Noordhuis Reviewed-By: Refael Ackermann Reviewed-By: Colin Ihrig --- src/win/error.c | 2 +- src/win/signal.c | 2 +- src/win/timer.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/win/error.c b/src/win/error.c index 642d1112e..9b03bfef6 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -58,7 +58,7 @@ void uv_fatal_error(const int errorno, const char* syscall) { LocalFree(buf); } - *((char*)NULL) = 0xff; /* Force debug break */ + DebugBreak(); abort(); } diff --git a/src/win/signal.c b/src/win/signal.c index 7b42dd992..a174da1f7 100644 --- a/src/win/signal.c +++ b/src/win/signal.c @@ -64,7 +64,7 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { } -RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare); +RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare) /* diff --git a/src/win/timer.c b/src/win/timer.c index 27ca7716a..7e006fedf 100644 --- a/src/win/timer.c +++ b/src/win/timer.c @@ -56,7 +56,7 @@ static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) { } -RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare); +RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare) int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { From 9991bb7c62462e3a42aa981883f0e6e404e616d9 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Thu, 3 Aug 2017 03:48:24 -0400 Subject: [PATCH 513/632] build: avoid -fstrict-aliasing compile option Libuv is not aliasing-safe if you consider aliasing to be nominal rather than structural and it's not as if it makes much of a difference in the quality of the generated code, at least for libuv. PR-URL: https://github.com/libuv/libuv/pull/1457 Reviewed-By: Ben Noordhuis --- common.gypi | 5 ----- uv.gyp | 5 ----- 2 files changed, 10 deletions(-) diff --git a/common.gypi b/common.gypi index 821fb79c5..816847bfc 100644 --- a/common.gypi +++ b/common.gypi @@ -32,7 +32,6 @@ }, 'xcode_settings': { 'GCC_OPTIMIZATION_LEVEL': '0', - 'OTHER_CFLAGS': [ '-Wno-strict-aliasing' ], }, 'conditions': [ ['OS != "zos"', { @@ -48,7 +47,6 @@ 'defines': [ 'NDEBUG' ], 'cflags': [ '-O3', - '-fstrict-aliasing', ], 'msvs_settings': { 'VCCLCompilerTool': { @@ -178,9 +176,6 @@ 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics 'PREBINDING': 'NO', # No -Wl,-prebind 'USE_HEADERMAP': 'NO', - 'OTHER_CFLAGS': [ - '-fstrict-aliasing', - ], 'WARNING_CFLAGS': [ '-Wall', '-Wendif-labels', diff --git a/uv.gyp b/uv.gyp index 07458995b..38765eefd 100644 --- a/uv.gyp +++ b/uv.gyp @@ -224,11 +224,6 @@ '_DARWIN_UNLIMITED_SELECT=1', ] }], - [ 'OS!="mac" and OS!="zos"', { - # Enable on all platforms except OS X. The antique gcc/clang that - # ships with Xcode emits waaaay too many false positives. - 'cflags': [ '-Wstrict-aliasing' ], - }], [ 'OS=="linux"', { 'defines': [ '_GNU_SOURCE' ], 'sources': [ From e9d2b5824fb76e1d7bc5fb23cd5242bea7b90a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlo=20Marcelo=20Arenas=20Bel=C3=B3n?= Date: Fri, 29 Sep 2017 10:50:50 -0700 Subject: [PATCH 514/632] win: remove unused variables This commit removes unused variables left over from 6ad1e81547c83f9fe7c5a806b6b282642e8d3bca. Refs: https://github.com/libuv/libuv/pull/1408 PR-URL: https://github.com/libuv/libuv/pull/1571 Reviewed-By: Santiago Gimeno Reviewed-By: Bartosz Sosnowski Reviewed-By: Colin Ihrig --- src/win/tty.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/win/tty.c b/src/win/tty.c index c7b4df9bf..4cd1c7212 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -1108,9 +1108,6 @@ static int uv__cancel_read_console(uv_tty_t* handle) { static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { - int old_virtual_width = uv_tty_virtual_width; - int old_virtual_height = uv_tty_virtual_height; - uv_tty_virtual_width = info->dwSize.X; uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1; From 8ea2ee4e26436137be26ec20d75e7995c2898f45 Mon Sep 17 00:00:00 2001 From: "Sakthipriyan Vairamani (thefourtheye)" Date: Mon, 2 Oct 2017 12:25:16 +0530 Subject: [PATCH 515/632] unix: remove unused variables PR-URL: https://github.com/libuv/libuv/pull/1578 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno Reviewed-By: Colin Ihrig --- src/unix/os390.c | 1 - src/unix/sunos.c | 1 - src/unix/thread.c | 1 - 3 files changed, 3 deletions(-) diff --git a/src/unix/os390.c b/src/unix/os390.c index eaeb43e6c..127656db8 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -386,7 +386,6 @@ int uv_uptime(double* uptime) { int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { uv_cpu_info_t* cpu_info; - int result; int idx; siv1v2 info; data_area_ptr cvt = {0}; diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 49de5a7fc..a72c26a01 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -757,7 +757,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; struct ifaddrs* addrs; struct ifaddrs* ent; - int i; if (getifaddrs(&addrs)) return -errno; diff --git a/src/unix/thread.c b/src/unix/thread.c index 35d3e77b0..e61b51ed8 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -404,7 +404,6 @@ int uv_sem_trywait(uv_sem_t* sem) { int uv_sem_init(uv_sem_t* sem, unsigned int value) { uv_sem_t semid; - struct sembuf buf; int err; union { int val; From 7824370ff80bf9e52aac90fee3e222a9524f87b0 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sat, 30 Sep 2017 19:28:01 +0200 Subject: [PATCH 516/632] netbsd: disable poll_bad_fdtype on NetBSD Follow other BSDs and disable the failing poll_bad_fdtype test on NetBSD. PR-URL: https://github.com/libuv/libuv/pull/1574 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- test/test-poll.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test-poll.c b/test/test-poll.c index 7cfc159a2..e828addbb 100644 --- a/test/test-poll.c +++ b/test/test-poll.c @@ -601,7 +601,8 @@ TEST_IMPL(poll_unidirectional) { TEST_IMPL(poll_bad_fdtype) { #if !defined(__DragonFly__) && !defined(__FreeBSD__) && !defined(__sun) && \ !defined(_AIX) && !defined(__MVS__) && !defined(__FreeBSD_kernel__) && \ - !defined(__OpenBSD__) && !defined(__CYGWIN__) && !defined(__MSYS__) + !defined(__OpenBSD__) && !defined(__CYGWIN__) && !defined(__MSYS__) && \ + !defined(__NetBSD__) uv_poll_t poll_handle; int fd; From 60bf1dfb511afa69c8d5f2e91f8d3684e36ff3d2 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sat, 30 Sep 2017 19:57:51 +0200 Subject: [PATCH 517/632] netbsd: use uv__cloexec and uv__nonblock This commit causes NetBSD, like other BSDs, to reuse uv__cloexec_ioctl and uv__nonblock_ioctl. This fixes poll_nested_kqueue. PR-URL: https://github.com/libuv/libuv/pull/1575 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/unix/internal.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/unix/internal.h b/src/unix/internal.h index c0898d982..3df5c4c3e 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -175,7 +175,8 @@ struct uv__stream_queued_fds_s { defined(__FreeBSD__) || \ defined(__FreeBSD_kernel__) || \ defined(__linux__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || \ + defined(__NetBSD__) #define uv__cloexec uv__cloexec_ioctl #define uv__nonblock uv__nonblock_ioctl #else From 5b6eead0649bd3dae8e9636ba7cc04e024bba54c Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sat, 30 Sep 2017 20:35:01 +0200 Subject: [PATCH 518/632] test: fix udp_multicast_join6 on NetBSD NetBSD must use the uv_udp_set_membership call with "::1%lo0", similar to FreeBSD. PR-URL: https://github.com/libuv/libuv/pull/1577 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- test/test-udp-multicast-join6.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test-udp-multicast-join6.c b/test/test-udp-multicast-join6.c index 2eb9e920e..8814b5ad1 100644 --- a/test/test-udp-multicast-join6.c +++ b/test/test-udp-multicast-join6.c @@ -122,7 +122,8 @@ TEST_IMPL(udp_multicast_join6) { #if defined(__APPLE__) || \ defined(_AIX) || \ defined(__MVS__) || \ - defined(__FreeBSD_kernel__) + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP); #else r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP); From ec96b5543823c6ab5b6654a07c318b659e841563 Mon Sep 17 00:00:00 2001 From: Scott Parker Date: Thu, 21 Sep 2017 10:36:20 -0700 Subject: [PATCH 519/632] unix,win: add uv_mutex_init_recursive() Support the creation of recursive mutexes on Unix. A matching API is added on Windows, however mutexes on Windows are always recursive. Refs: https://github.com/libuv/libuv/issues/1022 PR-URL: https://github.com/libuv/libuv/pull/1555 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- docs/src/guide/threads.rst | 14 ++++++++------ docs/src/threading.rst | 1 + include/uv.h | 1 + src/unix/thread.c | 19 +++++++++++++++++++ src/win/thread.c | 5 +++++ test/test-list.h | 2 ++ test/test-mutexes.c | 20 ++++++++++++++++++++ 7 files changed, 56 insertions(+), 6 deletions(-) diff --git a/docs/src/guide/threads.rst b/docs/src/guide/threads.rst index 3b0a07e14..b6a4fd856 100644 --- a/docs/src/guide/threads.rst +++ b/docs/src/guide/threads.rst @@ -79,18 +79,21 @@ The mutex functions are a **direct** map to the pthread equivalents. .. literalinclude:: ../../../include/uv.h :lines: 1355-1360 -The ``uv_mutex_init()`` and ``uv_mutex_trylock()`` functions will return 0 on -success, and an error code otherwise. +The ``uv_mutex_init()``, ``uv_mutex_init_recursive()`` and ``uv_mutex_trylock()`` +functions will return 0 on success, and an error code otherwise. If `libuv` has been compiled with debugging enabled, ``uv_mutex_destroy()``, ``uv_mutex_lock()`` and ``uv_mutex_unlock()`` will ``abort()`` on error. Similarly ``uv_mutex_trylock()`` will abort if the error is anything *other than* ``EAGAIN`` or ``EBUSY``. -Recursive mutexes are supported by some platforms, but you should not rely on -them. The BSD mutex implementation will raise an error if a thread which has +Recursive mutexes are supported, but you should not rely on them. Also, they +should not be used with ``uv_cond_t`` variables. + +The default BSD mutex implementation will raise an error if a thread which has locked a mutex attempts to lock it again. For example, a construct like:: + uv_mutex_init(a_mutex); uv_mutex_lock(a_mutex); uv_thread_create(thread_id, entry, (void *)a_mutex); uv_mutex_lock(a_mutex); @@ -102,8 +105,7 @@ return an error in the second call to ``uv_mutex_lock()``. .. note:: - Mutexes on linux support attributes for a recursive mutex, but the API is - not exposed via libuv. + Mutexes on Windows are always recursive. Locks ~~~~~ diff --git a/docs/src/threading.rst b/docs/src/threading.rst index e876dde12..bca8ba1d0 100644 --- a/docs/src/threading.rst +++ b/docs/src/threading.rst @@ -91,6 +91,7 @@ Functions return 0 on success or an error code < 0 (unless the return type is void, of course). .. c:function:: int uv_mutex_init(uv_mutex_t* handle) +.. c:function:: int uv_mutex_init_recursive(uv_mutex_t* handle) .. c:function:: void uv_mutex_destroy(uv_mutex_t* handle) .. c:function:: void uv_mutex_lock(uv_mutex_t* handle) .. c:function:: int uv_mutex_trylock(uv_mutex_t* handle) diff --git a/include/uv.h b/include/uv.h index eac63dde4..0e4151d13 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1424,6 +1424,7 @@ UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr); UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib); UV_EXTERN int uv_mutex_init(uv_mutex_t* handle); +UV_EXTERN int uv_mutex_init_recursive(uv_mutex_t* handle); UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle); UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle); UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle); diff --git a/src/unix/thread.c b/src/unix/thread.c index e61b51ed8..abaca295d 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -241,6 +241,25 @@ int uv_mutex_init(uv_mutex_t* mutex) { } +int uv_mutex_init_recursive(uv_mutex_t* mutex) { + pthread_mutexattr_t attr; + int err; + + if (pthread_mutexattr_init(&attr)) + abort(); + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) + abort(); + + err = pthread_mutex_init(mutex, &attr); + + if (pthread_mutexattr_destroy(&attr)) + abort(); + + return -err; +} + + void uv_mutex_destroy(uv_mutex_t* mutex) { if (pthread_mutex_destroy(mutex)) abort(); diff --git a/src/win/thread.c b/src/win/thread.c index 91684e938..30b2d7793 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -198,6 +198,11 @@ int uv_mutex_init(uv_mutex_t* mutex) { } +int uv_mutex_init_recursive(uv_mutex_t* mutex) { + return uv_mutex_init(mutex); +} + + void uv_mutex_destroy(uv_mutex_t* mutex) { DeleteCriticalSection(mutex); } diff --git a/test/test-list.h b/test/test-list.h index 6e84653e8..0dde57c2e 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -328,6 +328,7 @@ TEST_DECLARE (threadpool_cancel_single) TEST_DECLARE (thread_local_storage) TEST_DECLARE (thread_stack_size) TEST_DECLARE (thread_mutex) +TEST_DECLARE (thread_mutex_recursive) TEST_DECLARE (thread_rwlock) TEST_DECLARE (thread_rwlock_trylock) TEST_DECLARE (thread_create) @@ -840,6 +841,7 @@ TASK_LIST_START TEST_ENTRY (thread_local_storage) TEST_ENTRY (thread_stack_size) TEST_ENTRY (thread_mutex) + TEST_ENTRY (thread_mutex_recursive) TEST_ENTRY (thread_rwlock) TEST_ENTRY (thread_rwlock_trylock) TEST_ENTRY (thread_create) diff --git a/test/test-mutexes.c b/test/test-mutexes.c index af5e4e88a..975222ca1 100644 --- a/test/test-mutexes.c +++ b/test/test-mutexes.c @@ -50,6 +50,26 @@ TEST_IMPL(thread_mutex) { } +TEST_IMPL(thread_mutex_recursive) { + uv_mutex_t mutex; + int r; + + r = uv_mutex_init_recursive(&mutex); + ASSERT(r == 0); + + uv_mutex_lock(&mutex); + uv_mutex_lock(&mutex); + ASSERT(0 == uv_mutex_trylock(&mutex)); + + uv_mutex_unlock(&mutex); + uv_mutex_unlock(&mutex); + uv_mutex_unlock(&mutex); + uv_mutex_destroy(&mutex); + + return 0; +} + + TEST_IMPL(thread_rwlock) { uv_rwlock_t rwlock; int r; From 001a4a11f624153a3f27a7efef9746eb03d519d7 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sat, 30 Sep 2017 20:25:55 +0200 Subject: [PATCH 520/632] netbsd: do not exclude IPv6 functionality On NetBSD, do not exclude PF_INET6 in uv__ifaddr_exclude(). PR-URL: https://github.com/libuv/libuv/pull/1576 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/unix/bsd-ifaddrs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/unix/bsd-ifaddrs.c b/src/unix/bsd-ifaddrs.c index ffcf15644..2593b9ff3 100644 --- a/src/unix/bsd-ifaddrs.c +++ b/src/unix/bsd-ifaddrs.c @@ -50,7 +50,11 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { */ if (ent->ifa_addr->sa_family == AF_LINK) return 1; -#elif defined(__NetBSD__) || defined(__OpenBSD__) +#elif defined(__NetBSD__) + if (ent->ifa_addr->sa_family != PF_INET && + ent->ifa_addr->sa_family != PF_INET6) + return 1; +#elif defined(__OpenBSD__) if (ent->ifa_addr->sa_family != PF_INET) return 1; #endif From 0fcf2d14416ef308923e1b641d24dc0308c00980 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 30 Sep 2017 14:47:29 +0200 Subject: [PATCH 521/632] fsevents: watch files with fsevents on macos 10.7+ Adopted from an earlier pull request by Evan Lucas. Avoids opening a file descriptor per watched file. Fixes: https://github.com/libuv/libuv/issues/387 PR-URL: https://github.com/libuv/libuv/pull/1572 Refs: https://github.com/libuv/libuv/pull/641 Reviewed-By: Colin Ihrig --- src/unix/fsevents.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c index 643e233cf..38837406a 100644 --- a/src/unix/fsevents.c +++ b/src/unix/fsevents.c @@ -230,6 +230,7 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, uv_loop_t* loop; uv__cf_loop_state_t* state; uv__fsevents_event_t* event; + FSEventStreamEventFlags flags; QUEUE head; loop = info; @@ -245,8 +246,10 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, /* Process and filter out events */ for (i = 0; i < numEvents; i++) { + flags = eventFlags[i]; + /* Ignore system events */ - if (eventFlags[i] & kFSEventsSystem) + if (flags & kFSEventsSystem) continue; path = paths[i]; @@ -271,6 +274,9 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, /* Ignore events with path equal to directory itself */ if (len == 0) continue; +#else + if (len == 0 && (flags & kFSEventStreamEventFlagItemIsDir)) + continue; #endif /* MAC_OS_X_VERSION_10_7 */ /* Do not emit events from subdirectories (without option set) */ @@ -291,12 +297,24 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, memset(event, 0, sizeof(*event)); memcpy(event->path, path, len + 1); + event->events = UV_RENAME; - if ((eventFlags[i] & kFSEventsModified) != 0 && - (eventFlags[i] & kFSEventsRenamed) == 0) +#ifdef MAC_OS_X_VERSION_10_7 + if (0 != (flags & kFSEventsModified) && + 0 == (flags & kFSEventsRenamed)) { + event->events = UV_CHANGE; + } +#else + if (0 != (flags & kFSEventsModified) && + 0 != (flags & kFSEventStreamEventFlagItemIsDir) && + 0 == (flags & kFSEventStreamEventFlagItemRenamed)) { event->events = UV_CHANGE; - else - event->events = UV_RENAME; + } + if (0 == (flags & kFSEventStreamEventFlagItemIsDir) && + 0 == (flags & kFSEventStreamEventFlagItemRenamed)) { + event->events = UV_CHANGE; + } +#endif /* MAC_OS_X_VERSION_10_7 */ QUEUE_INSERT_TAIL(&head, &event->member); } From 8a9585232e9df227bcaf1263748d8997ec5d1077 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Sat, 30 Sep 2017 18:33:32 +0200 Subject: [PATCH 522/632] unix: retry on ENOBUFS in sendmsg(2) libuv retries when sendmsg(2) fails with EAGAIN or EWOULDBLOCK. This commit adds similar functionality for ENOBUFS. PR-URL: https://github.com/libuv/libuv/pull/1573 Reviewed-By: Santiago Gimeno Reviewed-By: Ben Noordhuis --- src/unix/stream.c | 2 +- src/unix/udp.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index c502098dc..672a7e2d6 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -859,7 +859,7 @@ static void uv__write(uv_stream_t* stream) { } if (n < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { + if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENOBUFS) { err = -errno; goto error; } else if (stream->flags & UV_STREAM_BLOCKING) { diff --git a/src/unix/udp.c b/src/unix/udp.c index c556325de..a475bf574 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -237,8 +237,10 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { size = sendmsg(handle->io_watcher.fd, &h, 0); } while (size == -1 && errno == EINTR); - if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) - break; + if (size == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) + break; + } req->status = (size == -1 ? -errno : size); @@ -472,7 +474,7 @@ int uv__udp_try_send(uv_udp_t* handle, } while (size == -1 && errno == EINTR); if (size == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) return -EAGAIN; else return -errno; From 8b69ce1419d2958011d415a636810705c36c2cc2 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 2 Oct 2017 19:30:27 -0400 Subject: [PATCH 523/632] 2017.10.03, Version 1.15.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.14.1: * unix: limit uv__has_forked_with_cfrunloop to macOS (Kamil Rytarowski) * win: fix buffer size in uv__getpwuid_r() (tux.uudiin) * win,tty: improve SIGWINCH support (Bartosz Sosnowski) * unix: use fchmod() in uv_fs_copyfile() (cjihrig) * unix: support copying empty files (cjihrig) * unix: truncate destination in uv_fs_copyfile() (Nick Logan) * win,build: keep cwd when setting build environment (darobs) * test: add NetBSD support to test-udp-ipv6.c (Kamil Rytarowski) * unix: add NetBSD support in core.c (Kamil Rytarowski) * linux: increase thread stack size with musl libc (Ben Noordhuis) * netbsd: correct uv_exepath() on NetBSD (Kamil Rytarowski) * test: clean up semaphore after use (jBarz) * win,build: bump vswhere_usability_wrapper to 2.0.0 (Refael Ackermann) * win: let UV_PROCESS_WINDOWS_HIDE hide consoles (cjihrig) * zos: lock protect global epoll list in epoll_ctl (jBarz) * zos: change platform name to match python (jBarz) * android: fix getifaddrs() (Zheng, Lei) * netbsd: implement uv__tty_is_slave() (Kamil Rytarowski) * zos: fix readlink for mounts with system variables (jBarz) * test: sort the tests alphabetically (Sakthipriyan Vairamani) * windows: fix compilation warnings (Carlo Marcelo Arenas Belón) * build: avoid -fstrict-aliasing compile option (jBarz) * win: remove unused variables (Carlo Marcelo Arenas Belón) * unix: remove unused variables (Sakthipriyan Vairamani) * netbsd: disable poll_bad_fdtype on NetBSD (Kamil Rytarowski) * netbsd: use uv__cloexec and uv__nonblock (Kamil Rytarowski) * test: fix udp_multicast_join6 on NetBSD (Kamil Rytarowski) * unix,win: add uv_mutex_init_recursive() (Scott Parker) * netbsd: do not exclude IPv6 functionality (Kamil Rytarowski) * fsevents: watch files with fsevents on macos 10.7+ (Ben Noordhuis) * unix: retry on ENOBUFS in sendmsg(2) (Kamil Rytarowski) --- .mailmap | 1 + AUTHORS | 7 +++++ ChangeLog | 67 ++++++++++++++++++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 8 +++--- 6 files changed, 81 insertions(+), 6 deletions(-) diff --git a/.mailmap b/.mailmap index 896d4065b..500c2b518 100644 --- a/.mailmap +++ b/.mailmap @@ -31,6 +31,7 @@ Rasmus Christian Pedersen Robert Mustacchi Ryan Dahl Ryan Emery +Sakthipriyan Vairamani Sam Roberts San-Tai Hsu Santiago Gimeno diff --git a/AUTHORS b/AUTHORS index 3562bb816..4747c06b3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -308,3 +308,10 @@ Jacob Segal Maciej Szeptuch (Neverous) Joel Winarske Gergely Nagy +Kamil Rytarowski +tux.uudiin <77389867@qq.com> +Nick Logan +darobs +Zheng, Lei +Carlo Marcelo Arenas Belón +Scott Parker diff --git a/ChangeLog b/ChangeLog index d0b557501..ee8efc575 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,70 @@ +2017.10.03, Version 1.15.0 (Stable) + +Changes since version 1.14.1: + +* unix: limit uv__has_forked_with_cfrunloop to macOS (Kamil Rytarowski) + +* win: fix buffer size in uv__getpwuid_r() (tux.uudiin) + +* win,tty: improve SIGWINCH support (Bartosz Sosnowski) + +* unix: use fchmod() in uv_fs_copyfile() (cjihrig) + +* unix: support copying empty files (cjihrig) + +* unix: truncate destination in uv_fs_copyfile() (Nick Logan) + +* win,build: keep cwd when setting build environment (darobs) + +* test: add NetBSD support to test-udp-ipv6.c (Kamil Rytarowski) + +* unix: add NetBSD support in core.c (Kamil Rytarowski) + +* linux: increase thread stack size with musl libc (Ben Noordhuis) + +* netbsd: correct uv_exepath() on NetBSD (Kamil Rytarowski) + +* test: clean up semaphore after use (jBarz) + +* win,build: bump vswhere_usability_wrapper to 2.0.0 (Refael Ackermann) + +* win: let UV_PROCESS_WINDOWS_HIDE hide consoles (cjihrig) + +* zos: lock protect global epoll list in epoll_ctl (jBarz) + +* zos: change platform name to match python (jBarz) + +* android: fix getifaddrs() (Zheng, Lei) + +* netbsd: implement uv__tty_is_slave() (Kamil Rytarowski) + +* zos: fix readlink for mounts with system variables (jBarz) + +* test: sort the tests alphabetically (Sakthipriyan Vairamani) + +* windows: fix compilation warnings (Carlo Marcelo Arenas Belón) + +* build: avoid -fstrict-aliasing compile option (jBarz) + +* win: remove unused variables (Carlo Marcelo Arenas Belón) + +* unix: remove unused variables (Sakthipriyan Vairamani) + +* netbsd: disable poll_bad_fdtype on NetBSD (Kamil Rytarowski) + +* netbsd: use uv__cloexec and uv__nonblock (Kamil Rytarowski) + +* test: fix udp_multicast_join6 on NetBSD (Kamil Rytarowski) + +* unix,win: add uv_mutex_init_recursive() (Scott Parker) + +* netbsd: do not exclude IPv6 functionality (Kamil Rytarowski) + +* fsevents: watch files with fsevents on macos 10.7+ (Ben Noordhuis) + +* unix: retry on ENOBUFS in sendmsg(2) (Kamil Rytarowski) + + 2017.09.07, Version 1.14.1 (Stable), b0f9fb2a07a5e638b1580fe9a42a356c3ab35f37 Changes since version 1.14.0: diff --git a/appveyor.yml b/appveyor.yml index 986c0d440..f519bc099 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.14.1.build{build} +version: v1.15.0.build{build} init: - git config --global core.autocrlf true diff --git a/configure.ac b/configure.ac index 41349a092..ebf5bc3d8 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.14.1], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.15.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 19099010e..55d7c9105 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 14 -#define UV_VERSION_PATCH 2 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 15 +#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 d15dda997195f4157c6b908fe0be55ee9527a962 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 2 Oct 2017 19:30:28 -0400 Subject: [PATCH 524/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ee8efc575..64b18695e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017.10.03, Version 1.15.0 (Stable) +2017.10.03, Version 1.15.0 (Stable), 8b69ce1419d2958011d415a636810705c36c2cc2 Changes since version 1.14.1: From 94f507535cd7bf0d8ba426291f0498ab212d4fe5 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 2 Oct 2017 19:41:06 -0400 Subject: [PATCH 525/632] Now working on version 1.15.1 --- 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 55d7c9105..4667db65e 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 15 -#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 5a2b5e84d06e0704928d111249e75615173cdcfb Mon Sep 17 00:00:00 2001 From: Joran Dirk Greef Date: Wed, 27 Sep 2017 11:09:28 +0200 Subject: [PATCH 526/632] win: change st_blksize from `2048` to `4096` `fs__stat_handle()` used to set st_blksize to `2048` regardless of the underlying physical sector size of the disk. `4096` is a better constant to avoid read-modify-write behavior on advanced format drives. Fixes: https://github.com/libuv/libuv/issues/1563 PR-URL: https://github.com/libuv/libuv/pull/1566 Reviewed-By: Bartosz Sosnowski --- src/win/fs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/win/fs.c b/src/win/fs.c index c374a82ca..51afac289 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1178,8 +1178,12 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { * * Therefore we'll just report a sensible value that's quite commonly okay * on modern hardware. + * + * 4096 is the minimum required to be compatible with newer Advanced Format + * drives (which have 4096 bytes per physical sector), and to be backwards + * compatible with older drives (which have 512 bytes per physical sector). */ - statbuf->st_blksize = 2048; + statbuf->st_blksize = 4096; /* Todo: set st_flags to something meaningful. Also provide a wrapper for * chattr(2). From 4b666bd2d82a51f1c809b2703a91679789c1ec01 Mon Sep 17 00:00:00 2001 From: Joran Dirk Greef Date: Wed, 27 Sep 2017 15:03:00 +0200 Subject: [PATCH 527/632] unix,win: add fs open flags, map O_DIRECT|O_DSYNC Define stable cross-platform file open constants so that users can pass `UV_FS_O_RDWR` rather than `_O_RDWR` (win) or `O_RDWR` (unix). Map `UV_FS_O_DIRECT`, `UV_FS_O_DSYNC` and `UV_FS_O_SYNC` to `FILE_FLAG_NO_BUFFERING` and `FILE_FLAG_WRITE_THROUGH` (win). Fixes: https://github.com/libuv/libuv/issues/1550 PR-URL: https://github.com/libuv/libuv/pull/1567 Reviewed-By: Bartosz Sosnowski --- docs/src/fs.rst | 151 ++++++++++++++++++++++++++++++++++++++++++++++ include/uv-unix.h | 93 ++++++++++++++++++++++++++++ include/uv-win.h | 25 ++++++++ src/win/fs.c | 59 +++++++++++------- 4 files changed, 306 insertions(+), 22 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 2db915bc9..f46c4e761 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -353,3 +353,154 @@ Helper functions any attempts to close it or to use it after closing the fd may lead to malfunction. .. versionadded:: 1.12.0 + +File open constants +------------------- + +.. c:macro:: UV_FS_O_APPEND + + The file is opened in append mode. Before each write, the file offset is + positioned at the end of the file. + +.. c:macro:: UV_FS_O_CREAT + + The file is created if it does not already exist. + +.. c:macro:: UV_FS_O_DIRECT + + File I/O is done directly to and from user-space buffers, which must be + aligned. Buffer size and address should be a multiple of the physical sector + size of the block device. + + .. note:: + `UV_FS_O_DIRECT` is supported on Linux, and on Windows via + `FILE_FLAG_NO_BUFFERING `_. + `UV_FS_O_DIRECT` is not supported on macOS. + +.. c:macro:: UV_FS_O_DIRECTORY + + If the path is not a directory, fail the open. + + .. note:: + `UV_FS_O_DIRECTORY` is not supported on Windows. + +.. c:macro:: UV_FS_O_DSYNC + + The file is opened for synchronous I/O. Write operations will complete once + all data and a minimum of metadata are flushed to disk. + + .. note:: + `UV_FS_O_DSYNC` is supported on Windows via + `FILE_FLAG_WRITE_THROUGH `_. + +.. c:macro:: UV_FS_O_EXCL + + If the `O_CREAT` flag is set and the file already exists, fail the open. + + .. note:: + In general, the behavior of `O_EXCL` is undefined if it is used without + `O_CREAT`. There is one exception: on Linux 2.6 and later, `O_EXCL` can + be used without `O_CREAT` if pathname refers to a block device. If the + block device is in use by the system (e.g., mounted), the open will fail + with the error `EBUSY`. + +.. c:macro:: UV_FS_O_EXLOCK + + Atomically obtain an exclusive lock. + + .. note:: + `UV_FS_O_EXLOCK` is only supported on macOS. + +.. c:macro:: UV_FS_O_NOATIME + + Do not update the file access time when the file is read. + + .. note:: + `UV_FS_O_NOATIME` is not supported on Windows. + +.. c:macro:: UV_FS_O_NOCTTY + + If the path identifies a terminal device, opening the path will not cause + that terminal to become the controlling terminal for the process (if the + process does not already have one). + + .. note:: + `UV_FS_O_NOCTTY` is not supported on Windows. + +.. c:macro:: UV_FS_O_NOFOLLOW + + If the path is a symbolic link, fail the open. + + .. note:: + `UV_FS_O_NOFOLLOW` is not supported on Windows. + +.. c:macro:: UV_FS_O_NONBLOCK + + Open the file in nonblocking mode if possible. + + .. note:: + `UV_FS_O_NONBLOCK` is not supported on Windows. + +.. c:macro:: UV_FS_O_RANDOM + + Access is intended to be random. The system can use this as a hint to + optimize file caching. + + .. note:: + `UV_FS_O_RANDOM` is only supported on Windows via + `FILE_FLAG_RANDOM_ACCESS `_. + +.. c:macro:: UV_FS_O_RDONLY + + Open the file for read-only access. + +.. c:macro:: UV_FS_O_RDWR + + Open the file for read-write access. + +.. c:macro:: UV_FS_O_SEQUENTIAL + + Access is intended to be sequential from beginning to end. The system can + use this as a hint to optimize file caching. + + .. note:: + `UV_FS_O_SEQUENTIAL` is only supported on Windows via + `FILE_FLAG_SEQUENTIAL_SCAN `_. + +.. c:macro:: UV_FS_O_SHORT_LIVED + + The file is temporary and should not be flushed to disk if possible. + + .. note:: + `UV_FS_O_SHORT_LIVED` is only supported on Windows via + `FILE_ATTRIBUTE_TEMPORARY `_. + +.. c:macro:: UV_FS_O_SYMLINK + + Open the symbolic link itself rather than the resource it points to. + +.. c:macro:: UV_FS_O_SYNC + + The file is opened for synchronous I/O. Write operations will complete once + all data and all metadata are flushed to disk. + + .. note:: + `UV_FS_O_SYNC` is supported on Windows via + `FILE_FLAG_WRITE_THROUGH `_. + +.. c:macro:: UV_FS_O_TEMPORARY + + The file is temporary and should not be flushed to disk if possible. + + .. note:: + `UV_FS_O_TEMPORARY` is only supported on Windows via + `FILE_ATTRIBUTE_TEMPORARY `_. + +.. c:macro:: UV_FS_O_TRUNC + + If the file exists and is a regular file, and the file is opened + successfully for write access, its length shall be truncated to zero. + +.. c:macro:: UV_FS_O_WRONLY + + Open the file for write-only access. diff --git a/include/uv-unix.h b/include/uv-unix.h index d7754509b..e0494f0ca 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -365,4 +365,97 @@ typedef struct { uv_fs_event_cb cb; \ UV_PLATFORM_FS_EVENT_FIELDS \ +/* fs open() flags supported on this platform: */ +#if defined(O_APPEND) +# define UV_FS_O_APPEND O_APPEND +#else +# define UV_FS_O_APPEND 0 +#endif +#if defined(O_CREAT) +# define UV_FS_O_CREAT O_CREAT +#else +# define UV_FS_O_CREAT 0 +#endif +#if defined(O_DIRECT) +# define UV_FS_O_DIRECT O_DIRECT +#else +# define UV_FS_O_DIRECT 0 +#endif +#if defined(O_DIRECTORY) +# define UV_FS_O_DIRECTORY O_DIRECTORY +#else +# define UV_FS_O_DIRECTORY 0 +#endif +#if defined(O_DSYNC) +# define UV_FS_O_DSYNC O_DSYNC +#else +# define UV_FS_O_DSYNC 0 +#endif +#if defined(O_EXCL) +# define UV_FS_O_EXCL O_EXCL +#else +# define UV_FS_O_EXCL 0 +#endif +#if defined(O_EXLOCK) +# define UV_FS_O_EXLOCK O_EXLOCK +#else +# define UV_FS_O_EXLOCK 0 +#endif +#if defined(O_NOATIME) +# define UV_FS_O_NOATIME O_NOATIME +#else +# define UV_FS_O_NOATIME 0 +#endif +#if defined(O_NOCTTY) +# define UV_FS_O_NOCTTY O_NOCTTY +#else +# define UV_FS_O_NOCTTY 0 +#endif +#if defined(O_NOFOLLOW) +# define UV_FS_O_NOFOLLOW O_NOFOLLOW +#else +# define UV_FS_O_NOFOLLOW 0 +#endif +#if defined(O_NONBLOCK) +# define UV_FS_O_NONBLOCK O_NONBLOCK +#else +# define UV_FS_O_NONBLOCK 0 +#endif +#if defined(O_RDONLY) +# define UV_FS_O_RDONLY O_RDONLY +#else +# define UV_FS_O_RDONLY 0 +#endif +#if defined(O_RDWR) +# define UV_FS_O_RDWR O_RDWR +#else +# define UV_FS_O_RDWR 0 +#endif +#if defined(O_SYMLINK) +# define UV_FS_O_SYMLINK O_SYMLINK +#else +# define UV_FS_O_SYMLINK 0 +#endif +#if defined(O_SYNC) +# define UV_FS_O_SYNC O_SYNC +#else +# define UV_FS_O_SYNC 0 +#endif +#if defined(O_TRUNC) +# define UV_FS_O_TRUNC O_TRUNC +#else +# define UV_FS_O_TRUNC 0 +#endif +#if defined(O_WRONLY) +# define UV_FS_O_WRONLY O_WRONLY +#else +# define UV_FS_O_WRONLY 0 +#endif + +/* fs open() flags supported on other platforms: */ +#define UV_FS_O_RANDOM 0 +#define UV_FS_O_SHORT_LIVED 0 +#define UV_FS_O_SEQUENTIAL 0 +#define UV_FS_O_TEMPORARY 0 + #endif /* UV_UNIX_H */ diff --git a/include/uv-win.h b/include/uv-win.h index 9677ff164..e9605cd30 100644 --- a/include/uv-win.h +++ b/include/uv-win.h @@ -648,3 +648,28 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #ifndef X_OK #define X_OK 1 #endif + +/* fs open() flags supported on this platform: */ +#define UV_FS_O_APPEND _O_APPEND +#define UV_FS_O_CREAT _O_CREAT +#define UV_FS_O_EXCL _O_EXCL +#define UV_FS_O_RANDOM _O_RANDOM +#define UV_FS_O_RDONLY _O_RDONLY +#define UV_FS_O_RDWR _O_RDWR +#define UV_FS_O_SEQUENTIAL _O_SEQUENTIAL +#define UV_FS_O_SHORT_LIVED _O_SHORT_LIVED +#define UV_FS_O_TEMPORARY _O_TEMPORARY +#define UV_FS_O_TRUNC _O_TRUNC +#define UV_FS_O_WRONLY _O_WRONLY + +/* fs open() flags supported on other platforms (or mapped on this platform): */ +#define UV_FS_O_DIRECT 0x2000000 /* FILE_FLAG_NO_BUFFERING */ +#define UV_FS_O_DIRECTORY 0 +#define UV_FS_O_DSYNC 0x4000000 /* FILE_FLAG_WRITE_THROUGH */ +#define UV_FS_O_EXLOCK 0 +#define UV_FS_O_NOATIME 0 +#define UV_FS_O_NOCTTY 0 +#define UV_FS_O_NOFOLLOW 0 +#define UV_FS_O_NONBLOCK 0 +#define UV_FS_O_SYMLINK 0 +#define UV_FS_O_SYNC 0x8000000 /* FILE_FLAG_WRITE_THROUGH */ diff --git a/src/win/fs.c b/src/win/fs.c index 51afac289..e732cd246 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -415,21 +415,21 @@ void fs__open(uv_fs_t* req) { umask(current_umask); /* convert flags and mode to CreateFile parameters */ - switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) { - case _O_RDONLY: + switch (flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) { + case UV_FS_O_RDONLY: access = FILE_GENERIC_READ; break; - case _O_WRONLY: + case UV_FS_O_WRONLY: access = FILE_GENERIC_WRITE; break; - case _O_RDWR: + case UV_FS_O_RDWR: access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; break; default: goto einval; } - if (flags & _O_APPEND) { + if (flags & UV_FS_O_APPEND) { access &= ~FILE_WRITE_DATA; access |= FILE_APPEND_DATA; } @@ -442,23 +442,23 @@ void fs__open(uv_fs_t* req) { */ share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) { + switch (flags & (UV_FS_O_CREAT | UV_FS_O_EXCL | UV_FS_O_TRUNC)) { case 0: - case _O_EXCL: + case UV_FS_O_EXCL: disposition = OPEN_EXISTING; break; - case _O_CREAT: + case UV_FS_O_CREAT: disposition = OPEN_ALWAYS; break; - case _O_CREAT | _O_EXCL: - case _O_CREAT | _O_TRUNC | _O_EXCL: + case UV_FS_O_CREAT | UV_FS_O_EXCL: + case UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL: disposition = CREATE_NEW; break; - case _O_TRUNC: - case _O_TRUNC | _O_EXCL: + case UV_FS_O_TRUNC: + case UV_FS_O_TRUNC | UV_FS_O_EXCL: disposition = TRUNCATE_EXISTING; break; - case _O_CREAT | _O_TRUNC: + case UV_FS_O_CREAT | UV_FS_O_TRUNC: disposition = CREATE_ALWAYS; break; default: @@ -466,34 +466,49 @@ void fs__open(uv_fs_t* req) { } attributes |= FILE_ATTRIBUTE_NORMAL; - if (flags & _O_CREAT) { + if (flags & UV_FS_O_CREAT) { if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) { attributes |= FILE_ATTRIBUTE_READONLY; } } - if (flags & _O_TEMPORARY ) { + if (flags & UV_FS_O_TEMPORARY ) { attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY; access |= DELETE; } - if (flags & _O_SHORT_LIVED) { + if (flags & UV_FS_O_SHORT_LIVED) { attributes |= FILE_ATTRIBUTE_TEMPORARY; } - switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) { + switch (flags & (UV_FS_O_SEQUENTIAL | UV_FS_O_RANDOM)) { case 0: break; - case _O_SEQUENTIAL: + case UV_FS_O_SEQUENTIAL: attributes |= FILE_FLAG_SEQUENTIAL_SCAN; break; - case _O_RANDOM: + case UV_FS_O_RANDOM: attributes |= FILE_FLAG_RANDOM_ACCESS; break; default: goto einval; } + if (flags & UV_FS_O_DIRECT) { + attributes |= FILE_FLAG_NO_BUFFERING; + } + + switch (flags & (UV_FS_O_DSYNC | UV_FS_O_SYNC)) { + case 0: + break; + case UV_FS_O_DSYNC: + case UV_FS_O_SYNC: + attributes |= FILE_FLAG_WRITE_THROUGH; + break; + default: + goto einval; + } + /* Setting this flag makes it possible to open a directory. */ attributes |= FILE_FLAG_BACKUP_SEMANTICS; @@ -506,9 +521,9 @@ void fs__open(uv_fs_t* req) { NULL); if (file == INVALID_HANDLE_VALUE) { DWORD error = GetLastError(); - if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) && - !(flags & _O_EXCL)) { - /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */ + if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) && + !(flags & UV_FS_O_EXCL)) { + /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was */ /* specified, it means the path referred to a directory. */ SET_REQ_UV_ERROR(req, UV_EISDIR, error); } else { From 1d9c13f1f7d6e769833346daf0f8811ba111d100 Mon Sep 17 00:00:00 2001 From: Wade Brainerd Date: Tue, 5 Sep 2017 16:13:43 -0400 Subject: [PATCH 528/632] win, fs: fix non-symlink reparse points Fixes uv_fs_stat and uv_fs_lstat returning EINVAL when invoked on a non-symlink reparse point. 1. Only tries to read symlinks when invoked via lstat (do_lstat == 1). Rationale is that only lstat can set S_IFLNK because when a file is tested by stat, symlinks are resolved by the OS and the returned file must be real. Note that broken symlinks fail at CreateFile. FILE_ATTRIBUTE_REPARSE_POINT is used by filesystem drivers for purposes besides symlinks, and uv_fs_stat fails when invoked on these files because fs__readlink_handle returns ERROR_SYMLINK_NOT_SUPPORTED. By ignoring the attribute in uv_fs_stat, these files are now handled correctly. 2. Modifies the logic added to fs__stat_handle to fix #995 as follows: A failed fs__readlink_handle on a file with a reparse point indicates that the file is not a symlink. The fix for #995 added code to fall through and behave as with a normal file in this case. However, this is not correct because lstat had opened the file with FILE_FLAG_OPEN_REPARSE_POINT, preventing the filesystem from acting based on the reparse point contents. The fix makes fs__stat_handle fail back to the higher level fs__stat_impl, which sets do_lstat to 0 and re-opens the file without FILE_FLAG_OPEN_REPARSE_POINT, allowing normal filesystem processing to take place. This is also a slightly cleaner solution as symlink fallback is only handled in one place (fs__stat_impl) instead of two (fs__stat_impl and fs__stat_handle). Note that the error tested in the fix for #995, ERROR_NOT_A_REPARSE_POINT, is not actually returned by Windows in the case of a non-symlink reparse point. I attempted to reproduce the error by repeating the test steps in the issue but failed. However, the the fix logic is preserved out of caution. 3. Adds tests to fs-test.c for the above two changes. Thorough testing requires some non-trivial setup - like an OSX computer on the LAN or a custom filesystem driver - so these tests are left commented out for manual invocation. PR-URL: https://github.com/libuv/libuv/pull/1522 Reviewed-By: Bartosz Sosnowski --- src/win/fs.c | 37 +++++++++------ test/test-fs.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 6 +++ 3 files changed, 144 insertions(+), 13 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index e732cd246..b90eaa754 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1085,7 +1085,8 @@ void fs__scandir(uv_fs_t* req) { } -INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { +INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, + int do_lstat) { FILE_ALL_INFORMATION file_info; FILE_FS_VOLUME_INFORMATION volume_info; NTSTATUS nt_status; @@ -1140,17 +1141,25 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) { */ statbuf->st_mode = 0; - if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + /* + * On Windows, FILE_ATTRIBUTE_REPARSE_POINT is a general purpose mechanism + * by which filesystem drivers can intercept and alter file system requests. + * + * The only reparse points we care about are symlinks and mount points, both + * of which are treated as POSIX symlinks. Further, we only care when + * invoked via lstat, which seeks information about the link instead of its + * target. Otherwise, reparse points must be treated as regular files. + */ + if (do_lstat && + (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { /* - * It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have - * any link data. In that case DeviceIoControl() in fs__readlink_handle() sets - * the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode - * calculated below will indicate a normal directory or file, as if - * FILE_ATTRIBUTE_REPARSE_POINT was not present. + * 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, &statbuf->st_size) == 0) { - statbuf->st_mode |= S_IFLNK; - } + if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0) + return -1; + statbuf->st_mode |= S_IFLNK; } if (statbuf->st_mode == 0) { @@ -1249,9 +1258,11 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) { return; } - if (fs__stat_handle(handle, &req->statbuf) != 0) { + if (fs__stat_handle(handle, &req->statbuf, do_lstat) != 0) { DWORD error = GetLastError(); - if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) { + if (do_lstat && + (error == ERROR_SYMLINK_NOT_SUPPORTED || + error == ERROR_NOT_A_REPARSE_POINT)) { /* We opened a reparse point but it was not a symlink. Try again. */ fs__stat_impl(req, 0); @@ -1295,7 +1306,7 @@ static void fs__fstat(uv_fs_t* req) { return; } - if (fs__stat_handle(handle, &req->statbuf) != 0) { + if (fs__stat_handle(handle, &req->statbuf, 0) != 0) { SET_REQ_WIN32_ERROR(req, GetLastError()); return; } diff --git a/test/test-fs.c b/test/test-fs.c index 0000e563a..6afa65079 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -115,6 +115,17 @@ static char test_buf[] = "test-buffer\n"; static char test_buf2[] = "second-buffer\n"; static uv_buf_t iov; +#ifdef _WIN32 +/* + * This tag and guid have no special meaning, and don't conflict with + * reserved ids. +*/ +static unsigned REPARSE_TAG = 0x9913; +static GUID REPARSE_GUID = { + 0x1bf6205f, 0x46ae, 0x4527, + 0xb1, 0x0c, 0xc5, 0x09, 0xb7, 0x55, 0x22, 0x80 }; +#endif + static void check_permission(const char* filename, unsigned int mode) { int r; uv_fs_t req; @@ -1991,6 +2002,109 @@ TEST_IMPL(fs_symlink_dir) { } +#ifdef _WIN32 +TEST_IMPL(fs_non_symlink_reparse_point) { + uv_fs_t req; + int r; + HANDLE file_handle; + REPARSE_GUID_DATA_BUFFER reparse_buffer; + DWORD bytes_returned; + uv_dirent_t dent; + + /* set-up */ + unlink("test_dir/test_file"); + rmdir("test_dir"); + + loop = uv_default_loop(); + + uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL); + uv_fs_req_cleanup(&req); + + file_handle = CreateFile("test_dir/test_file", + 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); + + memset(&reparse_buffer, 0, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE); + reparse_buffer.ReparseTag = REPARSE_TAG; + reparse_buffer.ReparseDataLength = 0; + reparse_buffer.ReparseGuid = REPARSE_GUID; + + r = DeviceIoControl(file_handle, + FSCTL_SET_REPARSE_POINT, + &reparse_buffer, + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, + NULL, + 0, + &bytes_returned, + NULL); + ASSERT(r != 0); + + CloseHandle(file_handle); + + r = uv_fs_readlink(NULL, &req, "test_dir/test_file", NULL); + ASSERT(r == UV_EINVAL && GetLastError() == ERROR_SYMLINK_NOT_SUPPORTED); + uv_fs_req_cleanup(&req); + +/* + Placeholder tests for exercising the behavior fixed in issue #995. + To run, update the path with the IP address of a Mac with the hard drive + shared via SMB as "Macintosh HD". + + r = uv_fs_stat(NULL, &req, "\\\\\\Macintosh HD\\.DS_Store", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_lstat(NULL, &req, "\\\\\\Macintosh HD\\.DS_Store", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); +*/ + +/* + uv_fs_stat and uv_fs_lstat can only work on non-symlink reparse + points when a minifilter driver is registered which intercepts + associated filesystem requests. Installing a driver is beyond + the scope of this test. + + r = uv_fs_stat(NULL, &req, "test_dir/test_file", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_lstat(NULL, &req, "test_dir/test_file", NULL); + ASSERT(r == 0); + 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(scandir_req.ptr); + while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) { + ASSERT(strcmp(dent.name, "test_file") == 0); + /* 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); + } + uv_fs_req_cleanup(&scandir_req); + ASSERT(!scandir_req.ptr); + + /* clean-up */ + unlink("test_dir/test_file"); + rmdir("test_dir"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + TEST_IMPL(fs_utime) { utime_check_t checkme; const char* path = "test_file"; diff --git a/test/test-list.h b/test/test-list.h index 0dde57c2e..59d45568d 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -282,6 +282,9 @@ TEST_DECLARE (fs_readlink) TEST_DECLARE (fs_realpath) TEST_DECLARE (fs_symlink) TEST_DECLARE (fs_symlink_dir) +#ifdef _WIN32 +TEST_DECLARE (fs_non_symlink_reparse_point) +#endif TEST_DECLARE (fs_utime) TEST_DECLARE (fs_futime) TEST_DECLARE (fs_file_open_append) @@ -790,6 +793,9 @@ TASK_LIST_START TEST_ENTRY (fs_realpath) TEST_ENTRY (fs_symlink) TEST_ENTRY (fs_symlink_dir) +#ifdef _WIN32 + TEST_ENTRY (fs_non_symlink_reparse_point) +#endif TEST_ENTRY (fs_stat_missing_path) TEST_ENTRY (fs_read_file_eof) TEST_ENTRY (fs_file_open_append) From 763f34cc1f94c4f2238a5772300f5714764f7678 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 2 Oct 2017 21:05:47 +0200 Subject: [PATCH 529/632] test: fix -Wstrict-prototypes warnings These have been around for some time apparently (commit 391f0098de from May 2011) but went unnoticed so far. No longer. PR-URL: https://github.com/libuv/libuv/pull/1581 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- test/benchmark-pump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/benchmark-pump.c b/test/benchmark-pump.c index 88f2dc5c6..8685258e0 100644 --- a/test/benchmark-pump.c +++ b/test/benchmark-pump.c @@ -36,9 +36,9 @@ static int TARGET_CONNECTIONS; static void do_write(uv_stream_t*); -static void maybe_connect_some(); +static void maybe_connect_some(void); -static uv_req_t* req_alloc(); +static uv_req_t* req_alloc(void); static void req_free(uv_req_t* uv_req); static void buf_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf); From e9cda2cfe71dce809a6ecba4ff913e24e36c233e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 2 Oct 2017 21:03:39 +0200 Subject: [PATCH 530/632] unix, windows: map ENOTTY errno PR-URL: https://github.com/libuv/libuv/pull/1582 Refs: https://github.com/libuv/libuv/issues/1579 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- include/uv-errno.h | 6 ++++++ include/uv.h | 1 + 2 files changed, 7 insertions(+) diff --git a/include/uv-errno.h b/include/uv-errno.h index 32bbc5177..8a4153314 100644 --- a/include/uv-errno.h +++ b/include/uv-errno.h @@ -422,4 +422,10 @@ # define UV__EREMOTEIO (-4030) #endif +#if defined(ENOTTY) && !defined(_WIN32) +# define UV__ENOTTY (-ENOTTY) +#else +# define UV__ENOTTY (-4029) +#endif + #endif /* UV_ERRNO_H_ */ diff --git a/include/uv.h b/include/uv.h index 0e4151d13..d6f8a216b 100644 --- a/include/uv.h +++ b/include/uv.h @@ -141,6 +141,7 @@ extern "C" { XX(EMLINK, "too many links") \ XX(EHOSTDOWN, "host is down") \ XX(EREMOTEIO, "remote I/O error") \ + XX(ENOTTY, "inappropriate ioctl for device") \ #define UV_HANDLE_TYPE_MAP(XX) \ XX(ASYNC, async) \ From 5b0e1d75a207bb1c662f4495c0d8ba1e81a5bb7d Mon Sep 17 00:00:00 2001 From: Joran Dirk Greef Date: Mon, 2 Oct 2017 17:16:10 +0200 Subject: [PATCH 531/632] unix: fall back to fsync() if F_FULLFSYNC fails F_FULLFSYNC may fail on non-Apple block devices. Fixes: https://github.com/libuv/libuv/issues/1579 PR-URL: https://github.com/libuv/libuv/pull/1580 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/unix/fs.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 2684c814a..e0969a4c2 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -132,26 +132,33 @@ while (0) -static ssize_t uv__fs_fdatasync(uv_fs_t* req) { -#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) - return fdatasync(req->file); -#elif defined(__APPLE__) +static ssize_t uv__fs_fsync(uv_fs_t* req) { +#if defined(__APPLE__) /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache * to the drive platters. This is in contrast to Linux's fdatasync and fsync * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent - * for flushing buffered data to permanent storage. + * for flushing buffered data to permanent storage. If F_FULLFSYNC is not + * supported by the file system we should fall back to fsync(). This is the + * same approach taken by sqlite. */ - return fcntl(req->file, F_FULLFSYNC); + int r; + + r = fcntl(req->file, F_FULLFSYNC); + if (r != 0 && errno == ENOTTY) + r = fsync(req->file); + return r; #else return fsync(req->file); #endif } -static ssize_t uv__fs_fsync(uv_fs_t* req) { -#if defined(__APPLE__) - /* See the comment in uv__fs_fdatasync. */ - return fcntl(req->file, F_FULLFSYNC); +static ssize_t uv__fs_fdatasync(uv_fs_t* req) { +#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) + return fdatasync(req->file); +#elif defined(__APPLE__) + /* See the comment in uv__fs_fsync. */ + return uv__fs_fsync(req); #else return fsync(req->file); #endif From 6a101e78e860101ac6b3b9f17bb7a74b181ae736 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Tue, 3 Oct 2017 00:04:48 -0400 Subject: [PATCH 532/632] unix: do not close invalid kqueue fd after fork The kqueue documentation states that the file descriptor is not inherited by the child process. Hence, do not close it in uv_loop_fork to avoid tampering with a possibly valid file descriptor already opened by the child process. PR-URL: https://github.com/libuv/libuv/pull/1583 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/unix/kqueue.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index c9adddbdb..5e89bdced 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -65,7 +65,6 @@ static int uv__has_forked_with_cfrunloop; int uv__io_fork(uv_loop_t* loop) { int err; - uv__close(loop->backend_fd); loop->backend_fd = -1; err = uv__kqueue_init(loop); if (err) From 44b7c71035a4270510f642923604cc5fed93d20e Mon Sep 17 00:00:00 2001 From: John Barboza Date: Mon, 21 Aug 2017 00:45:19 -0400 Subject: [PATCH 533/632] zos: reset epoll data after fork Remove all the epoll file descriptors after a fork since they are no longer valid. The uv__signal_global_once_init function needs to be run after uv__platform_loop_init so that the epoll pthread_atfork handlers get run first. PR-URL: https://github.com/libuv/libuv/pull/1496 Reviewed-By: Ben Noordhuis --- src/unix/loop.c | 2 +- src/unix/os390-syscalls.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/unix/loop.c b/src/unix/loop.c index bcd49242c..5b5b0e095 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -31,7 +31,6 @@ int uv_loop_init(uv_loop_t* loop) { void* saved_data; int err; - uv__signal_global_once_init(); saved_data = loop->data; memset(loop, 0, sizeof(*loop)); @@ -68,6 +67,7 @@ int uv_loop_init(uv_loop_t* loop) { if (err) return err; + uv__signal_global_once_init(); err = uv_signal_init(loop, &loop->child_watcher); if (err) goto fail_signal_init; diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c index ca539c26f..86c6852b4 100644 --- a/src/unix/os390-syscalls.c +++ b/src/unix/os390-syscalls.c @@ -120,10 +120,41 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) { } +static void before_fork(void) { + uv_mutex_lock(&global_epoll_lock); +} + + +static void after_fork(void) { + uv_mutex_unlock(&global_epoll_lock); +} + + +static void child_fork(void) { + 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)) { + q = QUEUE_HEAD(&global_epoll_queue); + QUEUE_REMOVE(q); + } + + uv_mutex_unlock(&global_epoll_lock); + uv_mutex_destroy(&global_epoll_lock); +} + + static void epoll_init(void) { QUEUE_INIT(&global_epoll_queue); if (uv_mutex_init(&global_epoll_lock)) abort(); + + if (pthread_atfork(&before_fork, &after_fork, &child_fork)) + abort(); } From f2214561f30c26f6c9a69b8b87eb121e59536424 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Thu, 12 Oct 2017 20:58:22 -0400 Subject: [PATCH 534/632] zos: skip fork_threadpool_queue_work_simple z/OS does not allow a child process to create threads if it was forked from a multi-threaded parent. PR-URL: https://github.com/libuv/libuv/pull/1596 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- test/test-fork.c | 2 ++ test/test-list.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/test/test-fork.c b/test/test-fork.c index 3716a3ad9..ba85b5310 100644 --- a/test/test-fork.c +++ b/test/test-fork.c @@ -636,6 +636,7 @@ static void assert_run_work(uv_loop_t* const loop) { } +#ifndef __MVS__ TEST_IMPL(fork_threadpool_queue_work_simple) { /* The threadpool works in a child process. */ @@ -672,6 +673,7 @@ TEST_IMPL(fork_threadpool_queue_work_simple) { MAKE_VALGRIND_HAPPY(); return 0; } +#endif /* !__MVS__ */ #endif /* !_WIN32 */ diff --git a/test/test-list.h b/test/test-list.h index 59d45568d..80f01ea84 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -401,8 +401,10 @@ TEST_DECLARE (fork_signal_to_child_closed) TEST_DECLARE (fork_fs_events_child) TEST_DECLARE (fork_fs_events_child_dir) TEST_DECLARE (fork_fs_events_file_parent_child) +#ifndef __MVS__ TEST_DECLARE (fork_threadpool_queue_work_simple) #endif +#endif TASK_LIST_START TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000) @@ -867,8 +869,10 @@ TASK_LIST_START TEST_ENTRY (fork_fs_events_child) TEST_ENTRY (fork_fs_events_child_dir) TEST_ENTRY (fork_fs_events_file_parent_child) +#ifndef __MVS__ TEST_ENTRY (fork_threadpool_queue_work_simple) #endif +#endif #if 0 /* These are for testing the test runner. */ From bdbae7d46b1ce67f6cfb387b9532c1834f977b8c Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Wed, 4 Oct 2017 09:29:19 +0200 Subject: [PATCH 535/632] test: keep platform_output as first test When sorting tests, keeps platform_output as the first test. PR-URL: https://github.com/libuv/libuv/pull/1584 Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- test/runner.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/runner.c b/test/runner.c index 5e4411877..b766097ce 100644 --- a/test/runner.c +++ b/test/runner.c @@ -81,6 +81,7 @@ int run_tests(int benchmark_output) { int skipped; int current; int test_result; + int skip; task_entry_t* task; /* Count the number of tests. */ @@ -92,7 +93,9 @@ int run_tests(int benchmark_output) { } } - qsort(TASKS, actual, sizeof(TASKS[0]), compare_task); + /* Keep platform_output first. */ + 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); From 719dfecf95b0c74af6494f05049e56d5771ebfae Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Wed, 4 Oct 2017 10:20:45 +0200 Subject: [PATCH 536/632] win: fix non-English dlopen error message Extend https://github.com/libuv/libuv/pull/1116 to work on other Windows languages. PR-URL: https://github.com/libuv/libuv/pull/1585 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/win/dl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/win/dl.c b/src/win/dl.c index d454014d8..97ac1c1ad 100644 --- a/src/win/dl.c +++ b/src/win/dl.c @@ -89,9 +89,9 @@ static void uv__format_fallback_error(uv_lib_t* lib, int errorno){ static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) { - static const char not_win32_app_msg[] = "%1 is not a valid Win32 application"; DWORD_PTR arg; DWORD res; + char* msg; if (lib->errmsg) { LocalFree(lib->errmsg); @@ -114,16 +114,16 @@ static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) { 0, (LPSTR) &lib->errmsg, 0, NULL); } - /* Inexpert hack to get the filename into the error message. */ - if (res && strstr(lib->errmsg, not_win32_app_msg)) { - LocalFree(lib->errmsg); + if (res && errorno == ERROR_BAD_EXE_FORMAT && strstr(lib->errmsg, "%1")) { + msg = lib->errmsg; lib->errmsg = NULL; arg = (DWORD_PTR) filename; res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING, - not_win32_app_msg, + msg, 0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg); + LocalFree(msg); } if (!res) From e8e6a8a500267f4ed33f0ba6459ec22f8b7a597f Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 30 Oct 2017 19:21:34 -0400 Subject: [PATCH 537/632] unix,win: add uv_os_getppid() Refs: https://github.com/nodejs/node/issues/14957 PR-URL: https://github.com/libuv/libuv/pull/1610 Reviewed-By: Santiago Gimeno Reviewed-By: Ben Noordhuis Reviewed-By: Gireesh Punathil --- docs/src/misc.rst | 12 ++++++++++++ include/uv-unix.h | 1 + include/uv-win.h | 1 + include/uv.h | 1 + src/unix/core.c | 5 +++++ src/win/internal.h | 1 - src/win/pipe.c | 2 +- src/win/util.c | 2 +- test/test-platform-output.c | 5 +++++ 9 files changed, 27 insertions(+), 3 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 3fea708a8..299cf0343 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -59,6 +59,12 @@ Data types Abstract representation of a file descriptor. On Unix systems this is a `typedef` of `int` and on Windows a `HANDLE`. +.. c:type:: uv_pid_t + + Cross platform representation of a `pid_t`. + + .. versionadded:: 1.16.0 + .. c:type:: uv_rusage_t Data type for resource usage results. @@ -221,6 +227,12 @@ 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:: uv_pid_t uv_os_getppid(void) + + Returns the parent process ID. + + .. versionadded:: 1.16.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 diff --git a/include/uv-unix.h b/include/uv-unix.h index e0494f0ca..6565ff441 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -123,6 +123,7 @@ typedef struct uv_buf_t { typedef int uv_file; typedef int uv_os_sock_t; typedef int uv_os_fd_t; +typedef pid_t uv_pid_t; #define UV_ONCE_INIT PTHREAD_ONCE_INIT diff --git a/include/uv-win.h b/include/uv-win.h index e9605cd30..be150fc48 100644 --- a/include/uv-win.h +++ b/include/uv-win.h @@ -222,6 +222,7 @@ typedef struct uv_buf_t { typedef int uv_file; typedef SOCKET uv_os_sock_t; typedef HANDLE uv_os_fd_t; +typedef int uv_pid_t; typedef HANDLE uv_thread_t; diff --git a/include/uv.h b/include/uv.h index d6f8a216b..76673e08f 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1069,6 +1069,7 @@ 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 uv_pid_t uv_os_getppid(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 ef82ee27b..d64593a31 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1343,3 +1343,8 @@ int uv_os_gethostname(char* buffer, size_t* size) { uv_os_fd_t uv_get_osfhandle(int fd) { return fd; } + + +uv_pid_t uv_os_getppid(void) { + return getppid(); +} diff --git a/src/win/internal.h b/src/win/internal.h index 444327d64..217fcdb5d 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -326,7 +326,6 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle); void uv__util_init(void); uint64_t uv__hrtime(double scale); -int uv_parent_pid(void); int uv_current_pid(void); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); int uv__getpwuid_r(uv_passwd_t* pwd); diff --git a/src/win/pipe.c b/src/win/pipe.c index 5c666788f..d102f5871 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -1969,7 +1969,7 @@ 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_pid = uv_parent_pid(); + pipe->pipe.conn.ipc_pid = uv_os_getppid(); assert(pipe->pipe.conn.ipc_pid != -1); } return 0; diff --git a/src/win/util.c b/src/win/util.c index a2acda115..2aec9f8df 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -331,7 +331,7 @@ uint64_t uv_get_total_memory(void) { } -int uv_parent_pid(void) { +uv_pid_t uv_os_getppid(void) { int parent_pid = -1; HANDLE handle; PROCESSENTRY32 pe; diff --git a/test/test-platform-output.c b/test/test-platform-output.c index 72c176edc..50ed59a6d 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -29,6 +29,7 @@ TEST_IMPL(platform_output) { size_t rss; size_t size; double uptime; + uv_pid_t ppid; uv_rusage_t rusage; uv_cpu_info_t* cpus; uv_interface_address_t* interfaces; @@ -144,5 +145,9 @@ TEST_IMPL(platform_output) { printf(" shell: %s\n", pwd.shell); printf(" home directory: %s\n", pwd.homedir); + ppid = uv_os_getppid(); + ASSERT(ppid > 0); + printf("uv_os_getppid: %d\n", (int) ppid); + return 0; } From d2101b0b9f00d8d8276a8ce04a7f65c13ffaacfa Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 5 Oct 2017 22:44:25 +0200 Subject: [PATCH 538/632] test: fix const qualification compiler warning `options.file` is of type `const char*`, don't assign it to a variable that is a non-const `char*`. The other way around is perfectly legal, though. PR-URL: https://github.com/libuv/libuv/pull/1588 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Refael Ackermann Reviewed-By: Gireesh Punathil --- 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 91d831e19..d3958fe21 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1721,9 +1721,9 @@ TEST_IMPL(spawn_quoted_path) { RETURN_SKIP("Test for Windows"); #else char* quoted_path_env[2]; - options.file = "not_existing"; - args[0] = options.file; + args[0] = "not_existing"; args[1] = NULL; + options.file = args[0]; options.args = args; options.exit_cb = exit_cb; options.flags = 0; From 7a93b12f1d87dc7e451ab0845a3b236cd1509185 Mon Sep 17 00:00:00 2001 From: rayrase Date: Fri, 6 Oct 2017 22:02:33 -0400 Subject: [PATCH 539/632] doc: mark uv_default_loop() as not thread safe Fixes: https://github.com/libuv/libuv/issues/1461 PR-URL: https://github.com/libuv/libuv/pull/1590 Reviewed-By: Colin Ihrig --- docs/src/loop.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/loop.rst b/docs/src/loop.rst index 02543171d..c63f81399 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -86,6 +86,9 @@ API should) be closed with :c:func:`uv_loop_close` so the resources associated with it are freed. + .. warning:: + This function is not thread safe. + .. c:function:: int uv_run(uv_loop_t* loop, uv_run_mode mode) This function runs the event loop. It will act differently depending on the From 6445cc63080f35370d38434666fa4ae9f7b3f41c Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 17 Jul 2015 22:21:54 -0400 Subject: [PATCH 540/632] win, pipe: null-initialize stream->shutdown_req When initializing a stream on Windows, this also inits the shutdown_req field, instead of waiting for a successful connection. A NULL value is used as a sentinel to check for whether this handle is currently in the shutdown state, and it may not get set if a stream was not connected immediately. PR-URL: https://github.com/libuv/libuv/pull/1500 Reviewed-By: Colin Ihrig Reviewed-By: Bartosz Sosnowski --- src/win/stream-inl.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/win/stream-inl.h b/src/win/stream-inl.h index bf12148af..dba037470 100644 --- a/src/win/stream-inl.h +++ b/src/win/stream-inl.h @@ -36,6 +36,7 @@ INLINE static void uv_stream_init(uv_loop_t* loop, uv__handle_init(loop, (uv_handle_t*) handle, type); handle->write_queue_size = 0; handle->activecnt = 0; + handle->stream.conn.shutdown_req = NULL; } @@ -47,8 +48,6 @@ INLINE static void uv_connection_init(uv_stream_t* handle) { handle->read_req.event_handle = NULL; handle->read_req.wait_handle = INVALID_HANDLE_VALUE; handle->read_req.data = handle; - - handle->stream.conn.shutdown_req = NULL; } From e7f4e9eccaf739da95a56887a80564838d75fdae Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Fri, 3 Nov 2017 12:18:52 +0100 Subject: [PATCH 541/632] tty, win: get SetWinEventHook pointer at startup SetWinEventHook is not available on some Windows versions. Fixes: https://github.com/nodejs/node/issues/16603 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/win/tty.c | 17 ++++++++++------- src/win/winapi.c | 10 ++++++++++ src/win/winapi.h | 22 ++++++++++++++++++++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/win/tty.c b/src/win/tty.c index 4cd1c7212..05a11e883 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -2285,13 +2285,16 @@ static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) { uv__tty_console_width = sb_info.dwSize.X; uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; - if (!SetWinEventHook(EVENT_CONSOLE_LAYOUT, - EVENT_CONSOLE_LAYOUT, - NULL, - uv__tty_console_resize_event, - 0, - 0, - WINEVENT_OUTOFCONTEXT)) + if (pSetWinEventHook == NULL) + return 0; + + if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT, + EVENT_CONSOLE_LAYOUT, + NULL, + uv__tty_console_resize_event, + 0, + 0, + WINEVENT_OUTOFCONTEXT)) return 0; while (GetMessage(&msg, NULL, 0, 0)) { diff --git a/src/win/winapi.c b/src/win/winapi.c index aa5d719fb..4ccdf0a5f 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -52,11 +52,15 @@ sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; /* Powrprof.dll function pointer */ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; +/* User32.dll function pointer */ +sSetWinEventHook pSetWinEventHook; + void uv_winapi_init(void) { HMODULE ntdll_module; HMODULE kernel32_module; HMODULE powrprof_module; + HMODULE user32_module; ntdll_module = GetModuleHandleA("ntdll.dll"); if (ntdll_module == NULL) { @@ -156,4 +160,10 @@ void uv_winapi_init(void) { GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification"); } + user32_module = LoadLibraryA("user32.dll"); + if (user32_module != NULL) { + pSetWinEventHook = (sSetWinEventHook) + GetProcAddress(user32_module, "SetWinEventHook"); + } + } diff --git a/src/win/winapi.h b/src/win/winapi.h index 6c699bfe1..cc54b79b0 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4725,6 +4725,25 @@ typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification) HANDLE Recipient, _PHPOWERNOTIFY RegistrationHandle); +/* from Winuser.h */ +typedef VOID (CALLBACK* WINEVENTPROC) + (HWINEVENTHOOK hWinEventHook, + DWORD event, + HWND hwnd, + LONG idObject, + LONG idChild, + DWORD idEventThread, + DWORD dwmsEventTime); + +typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook) + (UINT eventMin, + UINT eventMax, + HMODULE hmodWinEventProc, + WINEVENTPROC lpfnWinEventProc, + DWORD idProcess, + DWORD idThread, + UINT dwflags); + /* Ntdll function pointers */ extern sRtlNtStatusToDosError pRtlNtStatusToDosError; @@ -4753,4 +4772,7 @@ extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; /* Powrprof.dll function pointer */ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; +/* User32.dll function pointer */ +extern sSetWinEventHook pSetWinEventHook; + #endif /* UV_WIN_WINAPI_H_ */ From 96ea5ac96d71300d2d7b89bb319102eb2c7a0a28 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Fri, 3 Nov 2017 12:43:59 +0100 Subject: [PATCH 542/632] test: no extra new line in skipped test output Removes extra empty line when a test was skipped. PR-URL: https://github.com/libuv/libuv/pull/1616 Reviewed-By: Colin Ihrig --- test/runner.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/runner.c b/test/runner.c index b766097ce..f017902a0 100644 --- a/test/runner.c +++ b/test/runner.c @@ -130,6 +130,7 @@ void log_tap_result(int test_count, const char* result; const char* directive; char reason[1024]; + int reason_length; switch (status) { case TEST_OK: @@ -147,6 +148,9 @@ void log_tap_result(int test_count, if (status == TEST_SKIP && process_output_size(process) > 0) { process_read_last_line(process, reason, sizeof reason); + reason_length = strlen(reason); + if (reason_length > 0 && reason[reason_length - 1] == '\n') + reason[reason_length - 1] = '\0'; } else { reason[0] = '\0'; } From fd02ab681b6b4403e6a357413dc52df7ef7c5cde Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Thu, 22 Jun 2017 18:59:34 +0200 Subject: [PATCH 543/632] pipe: allow access from other users Adds new uv_pipe_chmod function which can be used to make the pipe writable or readable by all users. PR-URL: https://github.com/libuv/libuv/pull/1386 Reviewed-By: Santiago Gimeno Reviewed-By: Colin Ihrig --- Makefile.am | 1 + docs/src/pipe.rst | 9 ++++ include/uv.h | 1 + src/unix/pipe.c | 53 +++++++++++++++++++++++ src/win/pipe.c | 86 +++++++++++++++++++++++++++++++++++-- test/test-list.h | 2 + test/test-pipe-set-fchmod.c | 66 ++++++++++++++++++++++++++++ uv.gyp | 1 + 8 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 test/test-pipe-set-fchmod.c diff --git a/Makefile.am b/Makefile.am index b94fdd63b..6e548a69c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -212,6 +212,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-pipe-server-close.c \ test/test-pipe-close-stdout-read-stdin.c \ test/test-pipe-set-non-blocking.c \ + test/test-pipe-set-fchmod.c \ test/test-platform-output.c \ test/test-poll.c \ test/test-poll-close.c \ diff --git a/docs/src/pipe.rst b/docs/src/pipe.rst index d33b0f2b9..bdaeeba9d 100644 --- a/docs/src/pipe.rst +++ b/docs/src/pipe.rst @@ -102,3 +102,12 @@ API and call ``uv_accept(pipe, handle)``. .. seealso:: The :c:type:`uv_stream_t` API functions also apply. + +.. c:function:: int uv_pipe_chmod(uv_pipe_t* handle, int flags) + + Alters pipe permissions, allowing it to be accessed from processes run by + different users. Makes the pipe writable or readable by all users. Mode can + be ``UV_WRITABLE``, ``UV_READABLE`` or ``UV_WRITABLE | UV_READABLE``. This + function is blocking. + + .. versionadded:: 1.16.0 diff --git a/include/uv.h b/include/uv.h index 76673e08f..b8adbc9a2 100644 --- a/include/uv.h +++ b/include/uv.h @@ -710,6 +710,7 @@ UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle, UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count); UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle); UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle); +UV_EXTERN int uv_pipe_chmod(uv_pipe_t* handle, int flags); struct uv_poll_s { diff --git a/src/unix/pipe.c b/src/unix/pipe.c index 4a812955b..ac7cfb46a 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -302,3 +302,56 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { else return uv__handle_type(handle->accepted_fd); } + + +int uv_pipe_chmod(uv_pipe_t* handle, int mode) { + unsigned desired_mode; + struct stat pipe_stat; + char* name_buffer; + size_t name_len; + int r; + + if (handle == NULL || uv__stream_fd(handle) == -1) + return -EBADF; + + if (mode != UV_READABLE && + mode != UV_WRITABLE && + mode != (UV_WRITABLE | UV_READABLE)) + return -EINVAL; + + if (fstat(uv__stream_fd(handle), &pipe_stat) == -1) + return -errno; + + desired_mode = 0; + if (mode & UV_READABLE) + desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; + if (mode & UV_WRITABLE) + desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; + + /* Exit early if pipe already has desired mode. */ + if ((pipe_stat.st_mode & desired_mode) == desired_mode) + return 0; + + pipe_stat.st_mode |= desired_mode; + + /* Unfortunately fchmod does not work on all platforms, we will use chmod. */ + name_len = 0; + r = uv_pipe_getsockname(handle, NULL, &name_len); + if (r != UV_ENOBUFS) + return r; + + name_buffer = uv__malloc(name_len); + if (name_buffer == NULL) + return UV_ENOMEM; + + r = uv_pipe_getsockname(handle, name_buffer, &name_len); + if (r != 0) { + uv__free(name_buffer); + return r; + } + + r = chmod(name_buffer, pipe_stat.st_mode); + uv__free(name_buffer); + + return r != -1 ? 0 : -errno; +} diff --git a/src/win/pipe.c b/src/win/pipe.c index d102f5871..642213bc8 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -31,6 +31,9 @@ #include "stream-inl.h" #include "req-inl.h" +#include +#include + typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t; struct uv__ipc_queue_item_s { @@ -202,7 +205,7 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, uv_unique_pipe_name(ptr, name, nameSize); pipeHandle = CreateNamedPipeA(name, - access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, + access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0, NULL); @@ -534,7 +537,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { */ handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | - FILE_FLAG_FIRST_PIPE_INSTANCE, + FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); @@ -803,7 +806,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, assert(req->pipeHandle == INVALID_HANDLE_VALUE); req->pipeHandle = CreateNamedPipeW(handle->name, - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL); @@ -2132,3 +2135,80 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { else return UV_TCP; } + +int uv_pipe_chmod(uv_pipe_t* handle, int mode) { + SID_IDENTIFIER_AUTHORITY sid_world = SECURITY_WORLD_SID_AUTHORITY; + PACL old_dacl, new_dacl; + PSECURITY_DESCRIPTOR sd; + EXPLICIT_ACCESS ea; + PSID everyone; + int error; + + if (handle == NULL || handle->handle == INVALID_HANDLE_VALUE) + return UV_EBADF; + + if (mode != UV_READABLE && + mode != UV_WRITABLE && + mode != (UV_WRITABLE | UV_READABLE)) + return UV_EINVAL; + + if (!AllocateAndInitializeSid(&sid_world, + 1, + SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, + &everyone)) { + error = GetLastError(); + goto done; + } + + if (GetSecurityInfo(handle->handle, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + &old_dacl, + NULL, + &sd)) { + error = GetLastError(); + goto clean_sid; + } + + memset(&ea, 0, sizeof(EXPLICIT_ACCESS)); + if (mode & UV_READABLE) + ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; + if (mode & UV_WRITABLE) + ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES; + ea.grfAccessPermissions |= SYNCHRONIZE; + ea.grfAccessMode = SET_ACCESS; + ea.grfInheritance = NO_INHERITANCE; + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + ea.Trustee.ptstrName = (LPTSTR)everyone; + + if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl)) { + error = GetLastError(); + goto clean_sd; + } + + if (SetSecurityInfo(handle->handle, + SE_KERNEL_OBJECT, + DACL_SECURITY_INFORMATION, + NULL, + NULL, + new_dacl, + NULL)) { + error = GetLastError(); + goto clean_dacl; + } + + error = 0; + +clean_dacl: + LocalFree((HLOCAL) new_dacl); +clean_sd: + LocalFree((HLOCAL) sd); +clean_sid: + FreeSid(everyone); +done: + return uv_translate_sys_error(error); +} diff --git a/test/test-list.h b/test/test-list.h index 80f01ea84..3e88e6c92 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -204,6 +204,7 @@ TEST_DECLARE (pipe_ref4) TEST_DECLARE (pipe_close_stdout_read_stdin) #endif TEST_DECLARE (pipe_set_non_blocking) +TEST_DECLARE (pipe_set_chmod) TEST_DECLARE (process_ref) TEST_DECLARE (has_ref) TEST_DECLARE (active) @@ -443,6 +444,7 @@ TASK_LIST_START TEST_ENTRY (pipe_close_stdout_read_stdin) #endif TEST_ENTRY (pipe_set_non_blocking) + TEST_ENTRY (pipe_set_chmod) TEST_ENTRY (tty) #ifdef _WIN32 TEST_ENTRY (tty_raw) diff --git a/test/test-pipe-set-fchmod.c b/test/test-pipe-set-fchmod.c new file mode 100644 index 000000000..59f0e6f54 --- /dev/null +++ b/test/test-pipe-set-fchmod.c @@ -0,0 +1,66 @@ +/* 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" + +TEST_IMPL(pipe_set_chmod) { + uv_pipe_t pipe_handle; + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + r = uv_pipe_init(loop, &pipe_handle, 0); + ASSERT(r == 0); + + r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME); + ASSERT(r == 0); + + /* No easy way to test if this works, we will only make sure that */ + /* the call is successful. */ + r = uv_pipe_chmod(&pipe_handle, UV_READABLE); + if (r == UV_EPERM) { + MAKE_VALGRIND_HAPPY(); + RETURN_SKIP("Insufficient privileges to alter pipe fmode"); + } + ASSERT(r == 0); + + r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE); + ASSERT(r == 0); + + r = uv_pipe_chmod(&pipe_handle, UV_WRITABLE | UV_READABLE); + ASSERT(r == 0); + + r = uv_pipe_chmod(NULL, UV_WRITABLE | UV_READABLE); + ASSERT(r == UV_EBADF); + + r = uv_pipe_chmod(&pipe_handle, 12345678); + ASSERT(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); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/uv.gyp b/uv.gyp index 38765eefd..9d9bb4b73 100644 --- a/uv.gyp +++ b/uv.gyp @@ -393,6 +393,7 @@ 'test/test-pipe-server-close.c', 'test/test-pipe-close-stdout-read-stdin.c', 'test/test-pipe-set-non-blocking.c', + 'test/test-pipe-set-fchmod.c', 'test/test-platform-output.c', 'test/test-poll.c', 'test/test-poll-close.c', From 695afe8322e4e9d8fbd8fe3f30069bca31b74f11 Mon Sep 17 00:00:00 2001 From: Pekka Nikander Date: Thu, 27 Jul 2017 10:24:01 +0200 Subject: [PATCH 544/632] unix,win: add uv_if_{indextoname,indextoiid} uv_if_indextoname() is used to convert an IPv6 scope_id to an interface identifier string such as %eth0 or %lo. uv_if_indextoiid() returns an IPv6 interface identifier. On Unix it calls uv_if_indextoname(). On Windows it uses snprintf() to return the numeric interface identifier as a string. Refs: https://github.com/nodejs/node/pull/14500 PR-URL: https://github.com/libuv/libuv/pull/1445 Reviewed-By: Santiago Gimeno Reviewed-By: Colin Ihrig --- docs/src/misc.rst | 54 +++++++++++++++++++++++++++++++++ include/uv-unix.h | 1 + include/uv.h | 15 ++++++++++ src/unix/getaddrinfo.c | 29 ++++++++++++++++++ src/win/getaddrinfo.c | 68 ++++++++++++++++++++++++++++++++++++++++++ test/test-ip6-addr.c | 31 ++++++++++++++----- 6 files changed, 191 insertions(+), 7 deletions(-) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 299cf0343..2968d1cea 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -283,6 +283,60 @@ API and :man:`inet_pton(3)`. On success they return 0. In case of error the target `dst` pointer is unmodified. +.. c:macro:: UV_IF_NAMESIZE + + Maximum IPv6 interface identifier name length. Defined as + `IFNAMSIZ` on Unix and `IF_NAMESIZE` on Linux and Windows. + + .. versionadded:: 1.16.0 + +.. c:function:: int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) + + IPv6-capable implementation of :man:`if_indextoname(3)`. When called, + `*size` indicates the length of the `buffer`, which is used to store the + result. + On success, zero is returned, `buffer` contains the interface name, and + `*size` represents the string length of the `buffer`, excluding the NUL + terminator byte from `*size`. On error, a negative result is + returned. If `buffer` is not large enough to hold the result, + `UV_ENOBUFS` is returned, and `*size` represents the necessary size in + bytes, including the NUL terminator byte into the `*size`. + + On Unix, the returned interface name can be used directly as an + interface identifier in scoped IPv6 addresses, e.g. + `fe80::abc:def1:2345%en0`. + + On Windows, the returned interface cannot be used as an interface + identifier, as Windows uses numerical interface identifiers, e.g. + `fe80::abc:def1:2345%5`. + + To get an interface identifier in a cross-platform compatible way, + use `uv_if_indextoiid()`. + + Example: + + :: + + char ifname[UV_IF_NAMESIZE]; + size_t size = sizeof(ifname); + uv_if_indextoname(sin6->sin6_scope_id, ifname, &size); + + .. versionadded:: 1.16.0 + +.. c:function:: int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) + + Retrieves a network interface identifier suitable for use in an IPv6 scoped + address. On Windows, returns the numeric `ifindex` as a string. On all other + platforms, `uv_if_indextoname()` is called. The result is written to + `buffer`, with `*size` indicating the length of `buffer`. If `buffer` is not + large enough to hold the result, then `UV_ENOBUFS` is returned, and `*size` + represents the size, including the NUL byte, required to hold the + result. + + See `uv_if_indextoname` for further details. + + .. versionadded:: 1.16.0 + .. c:function:: int uv_exepath(char* buffer, size_t* size) Gets the executable path. diff --git a/include/uv-unix.h b/include/uv-unix.h index 6565ff441..99aab2b8a 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/include/uv.h b/include/uv.h index b8adbc9a2..3f6181208 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1408,6 +1408,21 @@ UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* 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); +#if defined(IF_NAMESIZE) +# define UV_IF_NAMESIZE (IF_NAMESIZE + 1) +#elif defined(IFNAMSIZ) +# define UV_IF_NAMESIZE (IFNAMSIZ + 1) +#else +# define UV_IF_NAMESIZE (16 + 1) +#endif + +UV_EXTERN int uv_if_indextoname(unsigned int ifindex, + char* buffer, + size_t* size); +UV_EXTERN int uv_if_indextoiid(unsigned int ifindex, + char* buffer, + size_t* size); + UV_EXTERN int uv_exepath(char* buffer, size_t* size); UV_EXTERN int uv_cwd(char* buffer, size_t* size); diff --git a/src/unix/getaddrinfo.c b/src/unix/getaddrinfo.c index 2049aea2f..99a6ef33b 100644 --- a/src/unix/getaddrinfo.c +++ b/src/unix/getaddrinfo.c @@ -200,3 +200,32 @@ void uv_freeaddrinfo(struct addrinfo* ai) { if (ai) freeaddrinfo(ai); } + + +int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { + char ifname_buf[UV_IF_NAMESIZE]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + if (if_indextoname(ifindex, ifname_buf) == NULL) + return -errno; + + len = strnlen(ifname_buf, sizeof(ifname_buf)); + + if (*size <= len) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, ifname_buf, len); + buffer[len] = '\0'; + *size = len; + + return 0; +} + +int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { + return uv_if_indextoname(ifindex, buffer, size); +} diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index baab83889..ab1599d46 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -28,6 +28,8 @@ /* EAI_* constants. */ #include +/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */ +#include int uv__getaddrinfo_translate_error(int sys_err) { switch (sys_err) { @@ -380,3 +382,69 @@ int uv_getaddrinfo(uv_loop_t* loop, } 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) + return UV_EINVAL; + + r = ConvertInterfaceIndexToLuid(ifindex, &luid); + + if (r != 0) + return uv_translate_sys_error(r); + + r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname)); + + 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; +} + +int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { + int r; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + r = snprintf(buffer, *size, "%d", ifindex); + + if (r < 0) + return uv_translate_sys_error(r); + + if (r >= (int) *size) { + *size = r + 1; + return UV_ENOBUFS; + } + + *size = r; + return 0; +} diff --git a/test/test-ip6-addr.c b/test/test-ip6-addr.c index 156fccde3..25570dcac 100644 --- a/test/test-ip6-addr.c +++ b/test/test-ip6-addr.c @@ -44,8 +44,12 @@ TEST_IMPL(ip6_addr_link_local) { const char* device_name; /* 40 bytes address, 16 bytes device name, plus reserve. */ char scoped_addr[128]; + size_t scoped_addr_len; + char interface_id[UV_IF_NAMESIZE]; + size_t interface_id_len; int count; int ix; + int r; ASSERT(0 == uv_interface_addresses(&addresses, &count)); @@ -67,19 +71,29 @@ TEST_IMPL(ip6_addr_link_local) { iface_index = address->address.address6.sin6_scope_id; device_name = address->name; + scoped_addr_len = sizeof(scoped_addr); + ASSERT(0 == 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)); +#endif + + interface_id_len = sizeof(interface_id); + r = uv_if_indextoiid(iface_index, interface_id, &interface_id_len); + ASSERT(0 == r); #ifdef _WIN32 - snprintf(scoped_addr, - sizeof(scoped_addr), - "%s%%%d", - string_address, - iface_index); + /* On Windows, the interface identifier is the numeric string of the index. */ + ASSERT(strtol(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)); +#endif + snprintf(scoped_addr, sizeof(scoped_addr), "%s%%%s", string_address, - device_name); -#endif + interface_id); fprintf(stderr, "Testing link-local address %s " "(iface_index: 0x%02x, device_name: %s)\n", @@ -96,6 +110,9 @@ TEST_IMPL(ip6_addr_link_local) { 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)); + MAKE_VALGRIND_HAPPY(); return 0; } From d68779f0ea742918f653b9c20237460271c39aeb Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 6 Nov 2017 11:20:52 -0500 Subject: [PATCH 545/632] 2017.11.07, Version 1.16.0 (Stable) Changes since version 1.15.0: * win: change st_blksize from `2048` to `4096` (Joran Dirk Greef) * unix,win: add fs open flags, map O_DIRECT|O_DSYNC (Joran Dirk Greef) * win, fs: fix non-symlink reparse points (Wade Brainerd) * test: fix -Wstrict-prototypes warnings (Ben Noordhuis) * unix, windows: map ENOTTY errno (Ben Noordhuis) * unix: fall back to fsync() if F_FULLFSYNC fails (Joran Dirk Greef) * unix: do not close invalid kqueue fd after fork (jBarz) * zos: reset epoll data after fork (jBarz) * zos: skip fork_threadpool_queue_work_simple (jBarz) * test: keep platform_output as first test (Bartosz Sosnowski) * win: fix non-English dlopen error message (Bartosz Sosnowski) * unix,win: add uv_os_getppid() (cjihrig) * test: fix const qualification compiler warning (Ben Noordhuis) * doc: mark uv_default_loop() as not thread safe (rayrase) * win, pipe: null-initialize stream->shutdown_req (Jameson Nash) * tty, win: get SetWinEventHook pointer at startup (Bartosz Sosnowski) * test: no extra new line in skipped test output (Bartosz Sosnowski) * pipe: allow access from other users (Bartosz Sosnowski) * unix,win: add uv_if_{indextoname,indextoiid} (Pekka Nikander) --- AUTHORS | 3 +++ ChangeLog | 43 +++++++++++++++++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 8 ++++---- 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4747c06b3..03255534f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -315,3 +315,6 @@ darobs Zheng, Lei Carlo Marcelo Arenas Belón Scott Parker +Wade Brainerd +rayrase +Pekka Nikander diff --git a/ChangeLog b/ChangeLog index 64b18695e..d763704c2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,46 @@ +2017.11.07, Version 1.16.0 (Stable) + +Changes since version 1.15.0: + +* win: change st_blksize from `2048` to `4096` (Joran Dirk Greef) + +* unix,win: add fs open flags, map O_DIRECT|O_DSYNC (Joran Dirk Greef) + +* win, fs: fix non-symlink reparse points (Wade Brainerd) + +* test: fix -Wstrict-prototypes warnings (Ben Noordhuis) + +* unix, windows: map ENOTTY errno (Ben Noordhuis) + +* unix: fall back to fsync() if F_FULLFSYNC fails (Joran Dirk Greef) + +* unix: do not close invalid kqueue fd after fork (jBarz) + +* zos: reset epoll data after fork (jBarz) + +* zos: skip fork_threadpool_queue_work_simple (jBarz) + +* test: keep platform_output as first test (Bartosz Sosnowski) + +* win: fix non-English dlopen error message (Bartosz Sosnowski) + +* unix,win: add uv_os_getppid() (cjihrig) + +* test: fix const qualification compiler warning (Ben Noordhuis) + +* doc: mark uv_default_loop() as not thread safe (rayrase) + +* win, pipe: null-initialize stream->shutdown_req (Jameson Nash) + +* tty, win: get SetWinEventHook pointer at startup (Bartosz Sosnowski) + +* test: no extra new line in skipped test output (Bartosz Sosnowski) + +* pipe: allow access from other users (Bartosz Sosnowski) + +* unix,win: add uv_if_{indextoname,indextoiid} (Pekka Nikander) + + 2017.10.03, Version 1.15.0 (Stable), 8b69ce1419d2958011d415a636810705c36c2cc2 Changes since version 1.14.1: diff --git a/appveyor.yml b/appveyor.yml index f519bc099..965b02e63 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.15.0.build{build} +version: v1.16.0.build{build} init: - git config --global core.autocrlf true diff --git a/configure.ac b/configure.ac index ebf5bc3d8..1251fbc00 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.15.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.16.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 4667db65e..7af91864f 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 15 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 16 +#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 7b397c801aa66858b4a9fd9755cc1cb97d0ca35d Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 6 Nov 2017 11:20:53 -0500 Subject: [PATCH 546/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index d763704c2..826bc04fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017.11.07, Version 1.16.0 (Stable) +2017.11.07, Version 1.16.0 (Stable), d68779f0ea742918f653b9c20237460271c39aeb Changes since version 1.15.0: From 921b030a5986353fea0dab737b1109108ca67ef5 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 6 Nov 2017 11:31:12 -0500 Subject: [PATCH 547/632] Now working on 1.16.1 --- 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 7af91864f..6d063389f 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 16 -#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 c83f8b91af225050568a37dcdc46af7c49af0930 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 8 Nov 2017 12:22:34 -0500 Subject: [PATCH 548/632] unix: move net/if.h include This commit moves the net/if.h include into src/getaddrinfo.c to prevent AIX compilation errors. With these symbols exposed publicly, Node.js compilation failed on AIX by exposing Free(), which conflicts with another API. Refs: https://github.com/nodejs/node/pull/16835 Refs: https://github.com/libuv/libuv/pull/1445 PR-URL: https://github.com/libuv/libuv/pull/1622 Reviewed-By: Ben Noordhuis --- include/uv-unix.h | 1 - src/unix/getaddrinfo.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uv-unix.h b/include/uv-unix.h index 99aab2b8a..6565ff441 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -32,7 +32,6 @@ #include #include #include -#include #include #include diff --git a/src/unix/getaddrinfo.c b/src/unix/getaddrinfo.c index 99a6ef33b..018597169 100644 --- a/src/unix/getaddrinfo.c +++ b/src/unix/getaddrinfo.c @@ -32,6 +32,7 @@ #include /* NULL */ #include #include +#include /* if_indextoname() */ /* EAI_* constants. */ #include From 84fa7fc7425e1d468a1812e7ab21286024ddd837 Mon Sep 17 00:00:00 2001 From: Nick Logan Date: Wed, 8 Nov 2017 22:35:46 -0500 Subject: [PATCH 549/632] win: fix undeclared NDIS_IF_MAX_STRING_SIZE NDIS_IF_MAX_STRING_SIZE does not appear to be available on some Windows systems. This commit defines it using the same logic used by Wireshark. See: https://github.com/boundary/wireshark/blob/07eade8124fd1d5386161591b52e177ee6ea849f/capture_win_ifnames.c#L42-L44 Refs: https://github.com/nodejs/node/pull/16835 Refs: https://github.com/libuv/libuv/pull/1445 PR-URL: https://github.com/libuv/libuv/pull/1623 Reviewed-By: Colin Ihrig Reviewed-By: Bartosz Sosnowski --- src/win/getaddrinfo.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index ab1599d46..282d919cf 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -75,6 +75,9 @@ int uv__getaddrinfo_translate_error(int sys_err) { /* Do we need different versions of this for different architectures? */ #define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2) +#ifndef NDIS_IF_MAX_STRING_SIZE +#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE +#endif static void uv__getaddrinfo_work(struct uv__work* w) { uv_getaddrinfo_t* req; From 4056fbe46493ef87237e307e0025e551db875e13 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 10 Nov 2017 11:49:42 -0500 Subject: [PATCH 550/632] 2017.11.11, Version 1.16.1 (Stable) Changes since version 1.16.0: * unix: move net/if.h include (cjihrig) * win: fix undeclared NDIS_IF_MAX_STRING_SIZE (Nick Logan) --- .mailmap | 1 + ChangeLog | 9 +++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 4 ++-- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.mailmap b/.mailmap index 500c2b518..da4214365 100644 --- a/.mailmap +++ b/.mailmap @@ -26,6 +26,7 @@ Marc Schlaich Michael Michael Neumann Nicholas Vavilov +Nick Logan Rasmus Christian Pedersen Rasmus Christian Pedersen Robert Mustacchi diff --git a/ChangeLog b/ChangeLog index 826bc04fe..5c406cae5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2017.11.11, Version 1.16.1 (Stable) + +Changes since version 1.16.0: + +* unix: move net/if.h include (cjihrig) + +* win: fix undeclared NDIS_IF_MAX_STRING_SIZE (Nick Logan) + + 2017.11.07, Version 1.16.0 (Stable), d68779f0ea742918f653b9c20237460271c39aeb Changes since version 1.15.0: diff --git a/appveyor.yml b/appveyor.yml index 965b02e63..8ad69718b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.16.0.build{build} +version: v1.16.1.build{build} init: - git config --global core.autocrlf true diff --git a/configure.ac b/configure.ac index 1251fbc00..5fc0f7243 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.16.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.16.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 6d063389f..1c9113cdc 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -33,8 +33,8 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 16 #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 31f80515127868812569605fc6cbd8c32e3d17dc Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 10 Nov 2017 11:49:43 -0500 Subject: [PATCH 551/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 5c406cae5..595b38712 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017.11.11, Version 1.16.1 (Stable) +2017.11.11, Version 1.16.1 (Stable), 4056fbe46493ef87237e307e0025e551db875e13 Changes since version 1.16.0: From 6973886ac8acbaa4f7aff164f2757ac2238d57cc Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 10 Nov 2017 12:03:09 -0500 Subject: [PATCH 552/632] Now working on version 1.16.2 --- 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 1c9113cdc..a6ffb5d3a 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 16 -#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 c1ff7cc6aab22a395c93bb23d75a95e73c134929 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 11 Nov 2017 12:02:09 +0100 Subject: [PATCH 553/632] unix: avoid malloc() call in uv_spawn() The stdio count for the new process is almost always a low number that we can allocate on the stack instead of the heap. PR-URL: https://github.com/libuv/libuv/pull/1626 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/unix/process.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/unix/process.c b/src/unix/process.c index 80b9686ec..9842710d0 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -419,6 +419,7 @@ int uv_spawn(uv_loop_t* loop, return -ENOSYS; #else int signal_pipe[2] = { -1, -1 }; + int pipes_storage[8][2]; int (*pipes)[2]; int stdio_count; ssize_t r; @@ -443,7 +444,10 @@ int uv_spawn(uv_loop_t* loop, stdio_count = 3; err = -ENOMEM; - pipes = uv__malloc(stdio_count * sizeof(*pipes)); + pipes = pipes_storage; + if (stdio_count > (int) ARRAY_SIZE(pipes_storage)) + pipes = uv__malloc(stdio_count * sizeof(*pipes)); + if (pipes == NULL) goto error; @@ -548,7 +552,9 @@ int uv_spawn(uv_loop_t* loop, process->pid = pid; process->exit_cb = options->exit_cb; - uv__free(pipes); + if (pipes != pipes_storage) + uv__free(pipes); + return exec_errorno; error: @@ -562,7 +568,9 @@ int uv_spawn(uv_loop_t* loop, if (pipes[i][1] != -1) uv__close_nocheckstdio(pipes[i][1]); } - uv__free(pipes); + + if (pipes != pipes_storage) + uv__free(pipes); } return err; From 7ef23d9e85b42abd83594575ba95c8499e993980 Mon Sep 17 00:00:00 2001 From: Ed Schouten Date: Wed, 11 Oct 2017 10:28:52 +0200 Subject: [PATCH 554/632] doc: clarify the description of uv_loop_alive() This function not only returns true if there are active handles or requests. First of all, it also takes into account whether handles are referenced. Second, handles that are being closed also contribute to whether a loop is alive. Fixes: https://github.com/libuv/libuv/issues/1592 PR-URL: https://github.com/libuv/libuv/pull/1594 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- docs/src/loop.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/loop.rst b/docs/src/loop.rst index c63f81399..18dd135cd 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -109,7 +109,8 @@ API .. c:function:: int uv_loop_alive(const uv_loop_t* loop) - Returns non-zero if there are active handles or request in the loop. + Returns non-zero if there are referenced active handles, active + requests or closing handles in the loop. .. c:function:: void uv_stop(uv_loop_t* loop) From 1c4de1916e36f8462c48a36ce7c88b247465f3cf Mon Sep 17 00:00:00 2001 From: Joran Dirk Greef Date: Wed, 1 Nov 2017 13:18:39 +0200 Subject: [PATCH 555/632] win: map UV_FS_O_EXLOCK to a share mode of 0 This is necessary to enable writing past the MBR of a raw block device. Fixes: https://github.com/libuv/libuv/issues/1605 PR-URL: https://github.com/libuv/libuv/pull/1613 Reviewed-By: Bartosz Sosnowski --- docs/src/fs.rst | 4 +++- include/uv-win.h | 8 +++---- src/win/fs.c | 9 +++++++- test/test-fs.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 6 +++++ 5 files changed, 78 insertions(+), 6 deletions(-) diff --git a/docs/src/fs.rst b/docs/src/fs.rst index f46c4e761..16d5e05c7 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -409,7 +409,9 @@ File open constants Atomically obtain an exclusive lock. .. note:: - `UV_FS_O_EXLOCK` is only supported on macOS. + `UV_FS_O_EXLOCK` is only supported on macOS and Windows. + + .. versionchanged:: 1.17.0 support is added for Windows. .. c:macro:: UV_FS_O_NOATIME diff --git a/include/uv-win.h b/include/uv-win.h index be150fc48..b96bed22a 100644 --- a/include/uv-win.h +++ b/include/uv-win.h @@ -664,13 +664,13 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #define UV_FS_O_WRONLY _O_WRONLY /* fs open() flags supported on other platforms (or mapped on this platform): */ -#define UV_FS_O_DIRECT 0x2000000 /* FILE_FLAG_NO_BUFFERING */ +#define UV_FS_O_DIRECT 0x02000000 /* FILE_FLAG_NO_BUFFERING */ #define UV_FS_O_DIRECTORY 0 -#define UV_FS_O_DSYNC 0x4000000 /* FILE_FLAG_WRITE_THROUGH */ -#define UV_FS_O_EXLOCK 0 +#define UV_FS_O_DSYNC 0x04000000 /* FILE_FLAG_WRITE_THROUGH */ +#define UV_FS_O_EXLOCK 0x10000000 /* EXCLUSIVE SHARING MODE */ #define UV_FS_O_NOATIME 0 #define UV_FS_O_NOCTTY 0 #define UV_FS_O_NOFOLLOW 0 #define UV_FS_O_NONBLOCK 0 #define UV_FS_O_SYMLINK 0 -#define UV_FS_O_SYNC 0x8000000 /* FILE_FLAG_WRITE_THROUGH */ +#define UV_FS_O_SYNC 0x08000000 /* FILE_FLAG_WRITE_THROUGH */ diff --git a/src/win/fs.c b/src/win/fs.c index b90eaa754..11c7c13ed 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -439,8 +439,15 @@ void fs__open(uv_fs_t* req) { * does. We indiscriminately use all the sharing modes, to match * UNIX semantics. In particular, this ensures that the file can * be deleted even whilst it's open, fixing issue #1449. + * We still support exclusive sharing mode, since it is necessary + * for opening raw block devices, otherwise Windows will prevent + * any attempt to write past the master boot record. */ - share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + if (flags & UV_FS_O_EXLOCK) { + share = 0; + } else { + share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + } switch (flags & (UV_FS_O_CREAT | UV_FS_O_EXCL | UV_FS_O_TRUNC)) { case 0: diff --git a/test/test-fs.c b/test/test-fs.c index 6afa65079..d22384ca6 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -3061,3 +3061,60 @@ TEST_IMPL(fs_null_req) { return 0; } + +#ifdef _WIN32 +TEST_IMPL(fs_exclusive_sharing_mode) { + int r; + + /* Setup. */ + unlink("test_file"); + + ASSERT(UV_FS_O_EXLOCK > 0); + + r = uv_fs_open(NULL, + &open_req1, + "test_file", + O_RDWR | O_CREAT | UV_FS_O_EXLOCK, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(open_req1.result >= 0); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_open(NULL, + &open_req2, + "test_file", + O_RDONLY | UV_FS_O_EXLOCK, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r < 0); + ASSERT(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); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(NULL, + &open_req2, + "test_file", + O_RDONLY | UV_FS_O_EXLOCK, + S_IWUSR | S_IRUSR, + NULL); + ASSERT(r >= 0); + ASSERT(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); + uv_fs_req_cleanup(&close_req); + + /* Cleanup */ + unlink("test_file"); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif diff --git a/test/test-list.h b/test/test-list.h index 3e88e6c92..23e363813 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -321,6 +321,9 @@ TEST_DECLARE (fs_write_alotof_bufs) TEST_DECLARE (fs_write_alotof_bufs_with_offset) TEST_DECLARE (fs_file_pos_after_op_with_offset) TEST_DECLARE (fs_null_req) +#ifdef _WIN32 +TEST_DECLARE (fs_exclusive_sharing_mode) +#endif TEST_DECLARE (threadpool_queue_work_simple) TEST_DECLARE (threadpool_queue_work_einval) TEST_DECLARE (threadpool_multiple_event_loops) @@ -832,6 +835,9 @@ TASK_LIST_START TEST_ENTRY (fs_read_write_null_arguments) TEST_ENTRY (fs_file_pos_after_op_with_offset) TEST_ENTRY (fs_null_req) +#ifdef _WIN32 + TEST_ENTRY (fs_exclusive_sharing_mode) +#endif TEST_ENTRY (get_osfhandle_valid_handle) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) From facac203481ab893912aa7edeae291b9999baf5d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 15 Nov 2017 16:20:45 +0100 Subject: [PATCH 556/632] win: fix build on case-sensitive file systems Cross-compiling with mingw64 was broken because the header files are called `accctrl.h` and `aclapi.h` whereas libuv was trying to include `AccCtrl.h` and `AclAPI.h`. PR-URL: https://github.com/libuv/libuv/pull/1629 Reviewed-By: Colin Ihrig --- src/win/pipe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/win/pipe.c b/src/win/pipe.c index 642213bc8..1a7c4dc15 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -31,8 +31,8 @@ #include "stream-inl.h" #include "req-inl.h" -#include -#include +#include +#include typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t; From fe3e635425a1f10399d49c610a66d5e27b217b33 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 17 Nov 2017 13:17:30 +0100 Subject: [PATCH 557/632] win: fix test runner build with mingw64 Include `` for the definition of `FSCTL_SET_REPARSE_POINT` and define `ERROR_SYMLINK_NOT_SUPPORTED` if not already defined. PR-URL: https://github.com/libuv/libuv/pull/1632 Reviewed-By: Colin Ihrig Reviewed-By: Refael Ackermann Reviewed-By: Santiago Gimeno --- test/test-fs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test-fs.c b/test/test-fs.c index d22384ca6..9df467a5b 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -32,8 +32,12 @@ defined(__APPLE__) || defined(_AIX) || defined(__MVS__) #include /* unlink, rmdir, etc. */ #else +# include # include # include +# ifndef ERROR_SYMLINK_NOT_SUPPORTED +# define ERROR_SYMLINK_NOT_SUPPORTED 1464 +# endif # define unlink _unlink # define rmdir _rmdir # define open _open From 0b18f57be525ac47bf39c62ed7d3d2d3be7d8dd0 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 17 Nov 2017 13:17:30 +0100 Subject: [PATCH 558/632] win: remove unused variable in test/test-fs.c PR-URL: https://github.com/libuv/libuv/pull/1632 Reviewed-By: Colin Ihrig Reviewed-By: Refael Ackermann Reviewed-By: Santiago Gimeno --- test/test-fs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test-fs.c b/test/test-fs.c index 9df467a5b..cae02dd1f 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2171,7 +2171,6 @@ TEST_IMPL(fs_utime) { #ifdef _WIN32 TEST_IMPL(fs_stat_root) { int r; - uv_loop_t* loop = uv_default_loop(); r = uv_fs_stat(NULL, &stat_req, "\\", NULL); ASSERT(r == 0); From 88d716e126b98d776bcb262d0dea87e6c139e40f Mon Sep 17 00:00:00 2001 From: John Barboza Date: Thu, 16 Nov 2017 20:20:39 -0500 Subject: [PATCH 559/632] zos: add strnlen() implementation Add an implementation of strnlen() which is not provided by default. PR-URL: https://github.com/libuv/libuv/pull/1631 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- src/unix/os390-syscalls.c | 9 +++++++++ src/unix/os390-syscalls.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c index 86c6852b4..5bc489387 100644 --- a/src/unix/os390-syscalls.c +++ b/src/unix/os390-syscalls.c @@ -427,3 +427,12 @@ ssize_t os390_readlink(const char* path, char* buf, size_t len) { return rlen; } + + +size_t strnlen(const char* str, size_t maxlen) { + void* p = memchr(str, 0, maxlen); + if (p == NULL) + return maxlen; + else + return p - str; +} diff --git a/src/unix/os390-syscalls.h b/src/unix/os390-syscalls.h index 7aba3d27d..5ce6a681b 100644 --- a/src/unix/os390-syscalls.h +++ b/src/unix/os390-syscalls.h @@ -66,5 +66,6 @@ int scandir(const char* maindir, struct dirent*** namelist, const struct dirent **)); char *mkdtemp(char* path); ssize_t os390_readlink(const char* path, char* buf, size_t len); +size_t strnlen(const char* str, size_t maxlen); #endif /* UV_OS390_SYSCALL_H_ */ From c5dd2d4218a79f2da0b365794139ad0f6e8cb60d Mon Sep 17 00:00:00 2001 From: John Barboza Date: Mon, 15 May 2017 11:32:33 -0400 Subject: [PATCH 560/632] unix: keep track of bound sockets sent via spawn We use the UV_HANDLE_BOUND flag to mark a socket as bound to a port. We need to do this for sockets that are sent from another process as well as sockets that created by the process itself. First check if the port number is non-zero. If yes then mark it as bound. PR-URL: https://github.com/libuv/libuv/pull/1348 Reviewed-By: Santiago Gimeno --- src/unix/tcp.c | 101 ++++++++++++++++++++++++++++++++++------------ test/run-tests.c | 5 +++ test/test-list.h | 2 + test/test-spawn.c | 76 ++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 26 deletions(-) diff --git a/src/unix/tcp.c b/src/unix/tcp.c index c423dcb15..c7c8d21c6 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -28,15 +28,12 @@ #include -static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) { +static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { + struct sockaddr_storage saddr; + socklen_t slen; int sockfd; int err; - if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) { - handle->flags |= flags; - return 0; - } - err = uv__socket(domain, SOCK_STREAM, 0); if (err < 0) return err; @@ -48,10 +45,74 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) { return err; } + if (flags & UV_HANDLE_BOUND) { + /* Bind this new socket to an arbitrary port */ + slen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen); + if (err) { + uv__close(sockfd); + return err; + } + + err = bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen); + if (err) { + uv__close(sockfd); + return err; + } + } + return 0; } +static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { + struct sockaddr_storage saddr; + socklen_t slen; + + if (domain == AF_UNSPEC) { + handle->flags |= flags; + return 0; + } + + if (uv__stream_fd(handle) != -1) { + + 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 -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 -errno; + } + + handle->flags |= flags; + return 0; + } + + return new_socket(handle, domain, flags); +} + + int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) { int domain; @@ -260,6 +321,7 @@ int uv_tcp_getpeername(const uv_tcp_t* handle, int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { static int single_accept = -1; + unsigned long flags; int err; if (tcp->delayed_error) @@ -273,30 +335,17 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { if (single_accept) tcp->flags |= UV_TCP_SINGLE_ACCEPT; - err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE); - if (err) - return err; - -#ifdef __MVS__ + flags = UV_STREAM_READABLE; +#if defined(__MVS__) /* on zOS the listen call does not bind automatically if the socket is unbound. Hence the manual binding to an arbitrary port is required to be done manually */ - - if (!(tcp->flags & UV_HANDLE_BOUND)) { - struct sockaddr_storage saddr; - socklen_t slen = sizeof(saddr); - memset(&saddr, 0, sizeof(saddr)); - - if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen)) - return -errno; - - if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen)) - return -errno; - - tcp->flags |= UV_HANDLE_BOUND; - } -#endif + flags |= UV_HANDLE_BOUND; +#endif + err = maybe_new_socket(tcp, AF_INET, flags); + if (err) + return err; if (listen(tcp->io_watcher.fd, backlog)) return -errno; diff --git a/test/run-tests.c b/test/run-tests.c index 4e10b68f3..da4ac82e4 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -43,6 +43,7 @@ int ipc_send_recv_helper(void); int ipc_helper_bind_twice(void); int stdio_over_pipes_helper(void); int spawn_stdin_stdout(void); +int spawn_tcp_server_helper(void); static int maybe_run_test(int argc, char **argv); @@ -111,6 +112,10 @@ static int maybe_run_test(int argc, char **argv) { return 1; } + if (strcmp(argv[1], "spawn_tcp_server_helper") == 0) { + return spawn_tcp_server_helper(); + } + if (strcmp(argv[1], "spawn_helper3") == 0) { char buffer[256]; ASSERT(buffer == fgets(buffer, sizeof(buffer) - 1, stdin)); diff --git a/test/test-list.h b/test/test-list.h index 23e363813..2adbe6a01 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -260,6 +260,7 @@ TEST_DECLARE (spawn_closed_process_io) TEST_DECLARE (spawn_reads_child_path) TEST_DECLARE (spawn_inherit_streams) TEST_DECLARE (spawn_quoted_path) +TEST_DECLARE (spawn_tcp_server) TEST_DECLARE (fs_poll) TEST_DECLARE (fs_poll_getpath) TEST_DECLARE (kill) @@ -743,6 +744,7 @@ TASK_LIST_START TEST_ENTRY (spawn_reads_child_path) TEST_ENTRY (spawn_inherit_streams) TEST_ENTRY (spawn_quoted_path) + TEST_ENTRY (spawn_tcp_server) TEST_ENTRY (fs_poll) TEST_ENTRY (fs_poll_getpath) TEST_ENTRY (kill) diff --git a/test/test-spawn.c b/test/test-spawn.c index d3958fe21..57d9e094a 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -50,6 +50,7 @@ static size_t exepath_size = 1024; static char* args[5]; static int no_term_signal; static int timer_counter; +static uv_tcp_t tcp_server; #define OUTPUT_SIZE 1024 static char output[OUTPUT_SIZE]; @@ -622,6 +623,81 @@ TEST_IMPL(spawn_stdio_greater_than_3) { } +int spawn_tcp_server_helper(void) { + uv_tcp_t tcp; + uv_os_sock_t handle; + int r; + + r = uv_tcp_init(uv_default_loop(), &tcp); + ASSERT(r == 0); + +#ifdef _WIN32 + handle = _get_osfhandle(3); +#else + handle = 3; +#endif + r = uv_tcp_open(&tcp, handle); + ASSERT(r == 0); + + /* 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); + + return 1; +} + + +TEST_IMPL(spawn_tcp_server) { + uv_stdio_container_t stdio[4]; + struct sockaddr_in addr; + int fd; + int r; + + init_process_options("spawn_tcp_server_helper", exit_cb); + + ASSERT(0 == 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); + r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); +#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); + + options.stdio = stdio; + options.stdio[0].flags = UV_INHERIT_FD; + options.stdio[0].data.fd = 0; + options.stdio[1].flags = UV_INHERIT_FD; + options.stdio[1].data.fd = 1; + options.stdio[2].flags = UV_INHERIT_FD; + options.stdio[2].data.fd = 2; + options.stdio[3].flags = UV_INHERIT_FD; + options.stdio[3].data.fd = fd; + options.stdio_count = 4; + + r = uv_spawn(uv_default_loop(), &process, &options); + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + TEST_IMPL(spawn_ignored_stdio) { int r; From 5486f6bd517382284109ff2f5355b61de417c4e8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 20 Nov 2017 20:35:02 +0100 Subject: [PATCH 561/632] unix,win: wait for threads to start It appears that, at least on Windows, the process terminates abnormally when the program exits before the worker threads complete initializing. Wait for the threads to spin up in `init_threads()` to avoid that. Refs: https://github.com/libuv/libuv/pull/1613#issuecomment-344958863 PR-URL: https://github.com/libuv/libuv/pull/1639 Reviewed-By: Bartosz Sosnowski Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/threadpool.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/threadpool.c b/src/threadpool.c index 108934112..ff64a3aee 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -38,7 +38,6 @@ static uv_thread_t* threads; static uv_thread_t default_threads[4]; static QUEUE exit_message; static QUEUE wq; -static volatile int initialized; static void uv__cancelled(struct uv__work* w) { @@ -105,7 +104,7 @@ static void post(QUEUE* q) { UV_DESTRUCTOR(static void cleanup(void)) { unsigned int i; - if (initialized == 0) + if (nthreads == 0) return; post(&exit_message); @@ -122,7 +121,6 @@ UV_DESTRUCTOR(static void cleanup(void)) { threads = NULL; nthreads = 0; - initialized = 0; } #endif @@ -130,6 +128,7 @@ UV_DESTRUCTOR(static void cleanup(void)) { static void init_threads(void) { unsigned int i; const char* val; + int spin; nthreads = ARRAY_SIZE(default_threads); val = getenv("UV_THREADPOOL_SIZE"); @@ -161,7 +160,11 @@ static void init_threads(void) { if (uv_thread_create(threads + i, worker, NULL)) abort(); - initialized = 1; + do { + uv_mutex_lock(&mutex); + spin = (idle_threads < nthreads); + uv_mutex_unlock(&mutex); + } while (spin); } From e99ac4c1f4eb3b049a9e147cb53a666506858121 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Mon, 20 Nov 2017 20:35:02 +0100 Subject: [PATCH 562/632] test: add threadpool init/teardown test Verify that quick setup and teardown of the threadpool doesn't cause crashes or hangs. PR-URL: https://github.com/libuv/libuv/pull/1639 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- test/test-list.h | 2 ++ test/test-loop-close.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/test/test-list.h b/test/test-list.h index 2adbe6a01..8b530d44b 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -28,6 +28,7 @@ TEST_DECLARE (run_once) TEST_DECLARE (run_nowait) TEST_DECLARE (loop_alive) TEST_DECLARE (loop_close) +TEST_DECLARE (loop_instant_close) TEST_DECLARE (loop_stop) TEST_DECLARE (loop_update_time) TEST_DECLARE (loop_backend_timeout) @@ -422,6 +423,7 @@ TASK_LIST_START TEST_ENTRY (run_nowait) TEST_ENTRY (loop_alive) TEST_ENTRY (loop_close) + TEST_ENTRY (loop_instant_close) TEST_ENTRY (loop_stop) TEST_ENTRY (loop_update_time) TEST_ENTRY (loop_backend_timeout) diff --git a/test/test-loop-close.c b/test/test-loop-close.c index 971c9d725..f0f3e627f 100644 --- a/test/test-loop-close.c +++ b/test/test-loop-close.c @@ -55,3 +55,21 @@ TEST_IMPL(loop_close) { return 0; } + +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) { +} + +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)); + MAKE_VALGRIND_HAPPY(); + return 0; +} From 9594719e737f3f99aafeb48645d67da0684341c2 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 19 Nov 2017 13:23:08 +0100 Subject: [PATCH 563/632] test: avoid malloc() in threadpool test Stack-allocate the `uv_loop_t` instance, no reason to heap-allocate it. PR-URL: https://github.com/libuv/libuv/pull/1634 Reviewed-By: Colin Ihrig --- test/test-thread.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/test/test-thread.c b/test/test-thread.c index b0e87e208..dac6d6851 100644 --- a/test/test-thread.c +++ b/test/test-thread.c @@ -107,34 +107,28 @@ static void fs_cb(uv_fs_t* handle) { static void do_work(void* arg) { struct getaddrinfo_req getaddrinfo_reqs[16]; struct fs_req fs_reqs[16]; - uv_loop_t* loop; + uv_loop_t loop; size_t i; - int r; struct test_thread* thread = arg; - loop = malloc(sizeof *loop); - ASSERT(loop != NULL); - ASSERT(0 == uv_loop_init(loop)); + ASSERT(0 == uv_loop_init(&loop)); for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) { struct getaddrinfo_req* req = getaddrinfo_reqs + i; req->counter = 16; - req->loop = loop; + req->loop = &loop; getaddrinfo_do(req); } for (i = 0; i < ARRAY_SIZE(fs_reqs); i++) { struct fs_req* req = fs_reqs + i; req->counter = 16; - req->loop = loop; + req->loop = &loop; fs_do(req); } - r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT(r == 0); - - ASSERT(0 == uv_loop_close(loop)); - free(loop); + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + ASSERT(0 == uv_loop_close(&loop)); thread->thread_called = 1; } From aeaff5f03799da7a39fc450a7cd343d91f6aa5c4 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 19 Nov 2017 13:23:08 +0100 Subject: [PATCH 564/632] test: lower number of tasks in threadpool test Reduce the task count from 2*16*16 to 2*4*4 (512 vs. 32) because several people have reported that the test frequently times out on their system. Fixes: https://github.com/libuv/libuv/issues/1471 PR-URL: https://github.com/libuv/libuv/pull/1634 Reviewed-By: Colin Ihrig --- test/test-thread.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test-thread.c b/test/test-thread.c index dac6d6851..c06ae9e2b 100644 --- a/test/test-thread.c +++ b/test/test-thread.c @@ -105,8 +105,8 @@ static void fs_cb(uv_fs_t* handle) { static void do_work(void* arg) { - struct getaddrinfo_req getaddrinfo_reqs[16]; - struct fs_req fs_reqs[16]; + struct getaddrinfo_req getaddrinfo_reqs[4]; + struct fs_req fs_reqs[4]; uv_loop_t loop; size_t i; struct test_thread* thread = arg; @@ -115,14 +115,14 @@ static void do_work(void* arg) { for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) { struct getaddrinfo_req* req = getaddrinfo_reqs + i; - req->counter = 16; + req->counter = 4; req->loop = &loop; getaddrinfo_do(req); } for (i = 0; i < ARRAY_SIZE(fs_reqs); i++) { struct fs_req* req = fs_reqs + i; - req->counter = 16; + req->counter = 4; req->loop = &loop; fs_do(req); } From 5070620777338b0873c4253bdb3718a46cffa84e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 19 Nov 2017 13:23:08 +0100 Subject: [PATCH 565/632] win: issue memory barrier in uv_thread_join() I'm 99% sure `WaitForSingleObject()` already issues a memory barrier for thread objects but since I could find no mention of that on MSDN, let's play it safe and do it ourselves, too. PR-URL: https://github.com/libuv/libuv/pull/1634 Reviewed-By: Colin Ihrig --- src/win/thread.c | 1 + test/test-thread.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/win/thread.c b/src/win/thread.c index 30b2d7793..9eaad77cd 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -182,6 +182,7 @@ int uv_thread_join(uv_thread_t *tid) { else { CloseHandle(*tid); *tid = 0; + MemoryBarrier(); /* For feature parity with pthread_join(). */ return 0; } } diff --git a/test/test-thread.c b/test/test-thread.c index c06ae9e2b..955c9f2f1 100644 --- a/test/test-thread.c +++ b/test/test-thread.c @@ -44,7 +44,7 @@ struct fs_req { struct test_thread { uv_thread_t thread_id; - volatile int thread_called; + int thread_called; }; static void getaddrinfo_do(struct getaddrinfo_req* req); @@ -54,7 +54,7 @@ static void getaddrinfo_cb(uv_getaddrinfo_t* handle, static void fs_do(struct fs_req* req); static void fs_cb(uv_fs_t* handle); -static volatile int thread_called; +static int thread_called; static uv_key_t tls_key; @@ -173,7 +173,7 @@ TEST_IMPL(threadpool_multiple_event_loops) { for (i = 0; i < ARRAY_SIZE(threads); i++) { r = uv_thread_join(&threads[i].thread_id); ASSERT(r == 0); - ASSERT(threads[i].thread_called); + ASSERT(threads[i].thread_called == 1); } return 0; From bb3d093bbb9eb6f1e23b88f9c13f1c9ddda808b0 Mon Sep 17 00:00:00 2001 From: Xu Meng Date: Mon, 9 Oct 2017 09:36:03 +0800 Subject: [PATCH 566/632] ibmi: add support for new platform Support the IBM i platform. - add a new file src/unix/ibmi.c - extract the common functions from /src/unix/aix.c into aix-common.c - update uv.gyp and include/uv-unix.h to enable the new file ibmi.c PR-URL: https://github.com/libuv/libuv/pull/1601 Reviewed-By: Ben Noordhuis Reviewed-By: Gireesh Punathil Reviewed-By: Michael Dawson --- Makefile.am | 2 +- checksparse.sh | 10 ++ include/uv-unix.h | 2 + src/unix/aix-common.c | 292 ++++++++++++++++++++++++++++++++++++++++++ src/unix/aix.c | 236 +--------------------------------- src/unix/ibmi.c | 112 ++++++++++++++++ uv.gyp | 38 +++++- 7 files changed, 449 insertions(+), 243 deletions(-) create mode 100644 src/unix/aix-common.c create mode 100644 src/unix/ibmi.c diff --git a/Makefile.am b/Makefile.am index 6e548a69c..e01cf4166 100644 --- a/Makefile.am +++ b/Makefile.am @@ -329,7 +329,7 @@ libuv_la_CFLAGS += -D_ALL_SOURCE \ -D_THREAD_SAFE \ -DHAVE_SYS_AHAFS_EVPRODS_H include_HEADERS += include/uv-aix.h -libuv_la_SOURCES += src/unix/aix.c +libuv_la_SOURCES += src/unix/aix.c src/unix/aix-common.c endif if ANDROID diff --git a/checksparse.sh b/checksparse.sh index ae0e5374f..d4a983d02 100755 --- a/checksparse.sh +++ b/checksparse.sh @@ -177,8 +177,18 @@ case `uname -s` in AIX) SPARSE_FLAGS="$SPARSE_FLAGS -D_AIX=1" SOURCES="$SOURCES + src/unix/aix-common.c src/unix/aix.c" ;; +OS400) + SPARSE_FLAGS="$SPARSE_FLAGS -D_PASE=1" + SOURCES="$SOURCES + src/unix/aix-common.c + src/unix/ibmi.c + src/unix/posix-poll.c + src/unix/no-fsevents.c + src/unix/no-proctitle.c" + ;; Darwin) SPARSE_FLAGS="$SPARSE_FLAGS -D__APPLE__=1" SOURCES="$SOURCES diff --git a/include/uv-unix.h b/include/uv-unix.h index 6565ff441..da32f86e8 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -48,6 +48,8 @@ # include "uv-linux.h" #elif defined (__MVS__) # include "uv-os390.h" +#elif defined(_PASE) +# include "uv-posix.h" #elif defined(_AIX) # include "uv-aix.h" #elif defined(__sun) diff --git a/src/unix/aix-common.c b/src/unix/aix-common.c new file mode 100644 index 000000000..2cfe8be6f --- /dev/null +++ b/src/unix/aix-common.c @@ -0,0 +1,292 @@ +/* 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 "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +uint64_t uv__hrtime(uv_clocktype_t type) { + uint64_t G = 1000000000; + timebasestruct_t t; + read_wall_time(&t, TIMEBASE_SZ); + time_base_to_time(&t, TIMEBASE_SZ); + return (uint64_t) t.tb_high * G + t.tb_low; +} + + +/* + * We could use a static buffer for the path manipulations that we need outside + * of the function, but this function could be called by multiple consumers and + * we don't want to potentially create a race condition in the use of snprintf. + * There is no direct way of getting the exe path in AIX - either through /procfs + * or through some libc APIs. The below approach is to parse the argv[0]'s pattern + * and use it in conjunction with PATH environment variable to craft one. + */ +int uv_exepath(char* buffer, size_t* size) { + int res; + char args[PATH_MAX]; + char abspath[PATH_MAX]; + size_t abspath_size; + struct procsinfo pi; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + + pi.pi_pid = getpid(); + res = getargs(&pi, sizeof(pi), args, sizeof(args)); + if (res < 0) + return -EINVAL; + + /* + * Possibilities for args: + * i) an absolute path such as: /home/user/myprojects/nodejs/node + * ii) a relative path such as: ./node or ../myprojects/nodejs/node + * iii) a bare filename such as "node", after exporting PATH variable + * to its location. + */ + + /* Case i) and ii) absolute or relative paths */ + if (strchr(args, '/') != NULL) { + if (realpath(args, abspath) != abspath) + return -errno; + + abspath_size = strlen(abspath); + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; + } else { + /* Case iii). Search PATH environment variable */ + char trypath[PATH_MAX]; + char *clonedpath = NULL; + char *token = NULL; + char *path = getenv("PATH"); + + if (path == NULL) + return -EINVAL; + + clonedpath = uv__strdup(path); + if (clonedpath == NULL) + return -ENOMEM; + + token = strtok(clonedpath, ":"); + while (token != NULL) { + snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); + if (realpath(trypath, abspath) == abspath) { + /* Check the match is executable */ + if (access(abspath, X_OK) == 0) { + abspath_size = strlen(abspath); + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + uv__free(clonedpath); + return 0; + } + } + token = strtok(NULL, ":"); + } + uv__free(clonedpath); + + /* Out of tokens (path entries), and no match found */ + return -EINVAL; + } +} + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; ++i) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, + int* count) { + uv_interface_address_t* address; + int sockfd, inet6, size = 1; + struct ifconf ifc; + struct ifreq *ifr, *p, flg; + struct sockaddr_dl* sa_addr; + + *count = 0; + + if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { + return -errno; + } + + if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { + uv__close(sockfd); + return -errno; + } + + ifc.ifc_req = (struct ifreq*)uv__malloc(size); + ifc.ifc_len = size; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { + uv__close(sockfd); + return -errno; + } + +#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) + + /* Count all up and running ipv4/ipv6 addresses */ + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return -errno; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + (*count)++; + } + + /* Alloc the return interface structs */ + *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); + if (!(*addresses)) { + uv__close(sockfd); + return -ENOMEM; + } + address = *addresses; + + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + inet6 = (p->ifr_addr.sa_family == AF_INET6); + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return -ENOSYS; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + /* All conditions above must match count loop */ + + address->name = uv__strdup(p->ifr_name); + + if (inet6) + address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); + else + address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); + + sa_addr = (struct sockaddr_dl*) &p->ifr_addr; + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + + if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) { + uv__close(sockfd); + return -ENOSYS; + } + + if (inet6) + address->netmask.netmask6 = *((struct sockaddr_in6*) &p->ifr_addr); + else + address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr); + + address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; + + address++; + } + +#undef ADDR_SIZE + + uv__close(sockfd); + return 0; +} + + +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); +} \ No newline at end of file diff --git a/src/unix/aix.c b/src/unix/aix.c index 56a8f4ffe..07f81fcf0 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -1,4 +1,5 @@ /* 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 @@ -316,104 +317,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } -uint64_t uv__hrtime(uv_clocktype_t type) { - uint64_t G = 1000000000; - timebasestruct_t t; - read_wall_time(&t, TIMEBASE_SZ); - time_base_to_time(&t, TIMEBASE_SZ); - return (uint64_t) t.tb_high * G + t.tb_low; -} - - -/* - * We could use a static buffer for the path manipulations that we need outside - * of the function, but this function could be called by multiple consumers and - * we don't want to potentially create a race condition in the use of snprintf. - * There is no direct way of getting the exe path in AIX - either through /procfs - * or through some libc APIs. The below approach is to parse the argv[0]'s pattern - * and use it in conjunction with PATH environment variable to craft one. - */ -int uv_exepath(char* buffer, size_t* size) { - int res; - char args[PATH_MAX]; - char abspath[PATH_MAX]; - size_t abspath_size; - struct procsinfo pi; - - if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; - - pi.pi_pid = getpid(); - res = getargs(&pi, sizeof(pi), args, sizeof(args)); - if (res < 0) - return -EINVAL; - - /* - * Possibilities for args: - * i) an absolute path such as: /home/user/myprojects/nodejs/node - * ii) a relative path such as: ./node or ../myprojects/nodejs/node - * iii) a bare filename such as "node", after exporting PATH variable - * to its location. - */ - - /* Case i) and ii) absolute or relative paths */ - if (strchr(args, '/') != NULL) { - if (realpath(args, abspath) != abspath) - return -errno; - - abspath_size = strlen(abspath); - - *size -= 1; - if (*size > abspath_size) - *size = abspath_size; - - memcpy(buffer, abspath, *size); - buffer[*size] = '\0'; - - return 0; - } else { - /* Case iii). Search PATH environment variable */ - char trypath[PATH_MAX]; - char *clonedpath = NULL; - char *token = NULL; - char *path = getenv("PATH"); - - if (path == NULL) - return -EINVAL; - - clonedpath = uv__strdup(path); - if (clonedpath == NULL) - return -ENOMEM; - - token = strtok(clonedpath, ":"); - while (token != NULL) { - snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); - if (realpath(trypath, abspath) == abspath) { - /* Check the match is executable */ - if (access(abspath, X_OK) == 0) { - abspath_size = strlen(abspath); - - *size -= 1; - if (*size > abspath_size) - *size = abspath_size; - - memcpy(buffer, abspath, *size); - buffer[*size] = '\0'; - - uv__free(clonedpath); - return 0; - } - } - token = strtok(NULL, ":"); - } - uv__free(clonedpath); - - /* Out of tokens (path entries), and no match found */ - return -EINVAL; - } -} - - uint64_t uv_get_free_memory(void) { perfstat_memory_total_t mem_total; int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1); @@ -1094,143 +997,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { } -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - int i; - - for (i = 0; i < count; ++i) { - uv__free(cpu_infos[i].model); - } - - uv__free(cpu_infos); -} - - -int uv_interface_addresses(uv_interface_address_t** addresses, - int* count) { - uv_interface_address_t* address; - int sockfd, inet6, size = 1; - struct ifconf ifc; - struct ifreq *ifr, *p, flg; - struct sockaddr_dl* sa_addr; - - *count = 0; - - if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { - return -errno; - } - - if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { - uv__close(sockfd); - return -errno; - } - - ifc.ifc_req = (struct ifreq*)uv__malloc(size); - ifc.ifc_len = size; - if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { - uv__close(sockfd); - return -errno; - } - -#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) - - /* Count all up and running ipv4/ipv6 addresses */ - ifr = ifc.ifc_req; - while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { - p = ifr; - ifr = (struct ifreq*) - ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); - - if (!(p->ifr_addr.sa_family == AF_INET6 || - p->ifr_addr.sa_family == AF_INET)) - continue; - - memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); - if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { - uv__close(sockfd); - return -errno; - } - - if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) - continue; - - (*count)++; - } - - /* Alloc the return interface structs */ - *addresses = (uv_interface_address_t*) - uv__malloc(*count * sizeof(uv_interface_address_t)); - if (!(*addresses)) { - uv__close(sockfd); - return -ENOMEM; - } - address = *addresses; - - ifr = ifc.ifc_req; - while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { - p = ifr; - ifr = (struct ifreq*) - ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); - - if (!(p->ifr_addr.sa_family == AF_INET6 || - p->ifr_addr.sa_family == AF_INET)) - continue; - - inet6 = (p->ifr_addr.sa_family == AF_INET6); - - memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); - if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { - uv__close(sockfd); - return -ENOSYS; - } - - if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) - continue; - - /* All conditions above must match count loop */ - - address->name = uv__strdup(p->ifr_name); - - if (inet6) - address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); - else - address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); - - sa_addr = (struct sockaddr_dl*) &p->ifr_addr; - memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); - - if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) { - uv__close(sockfd); - return -ENOSYS; - } - - if (inet6) - address->netmask.netmask6 = *((struct sockaddr_in6*) &p->ifr_addr); - else - address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr); - - address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; - - address++; - } - -#undef ADDR_SIZE - - uv__close(sockfd); - return 0; -} - - -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); -} - void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { struct pollfd* events; uintptr_t i; diff --git a/src/unix/ibmi.c b/src/unix/ibmi.c new file mode 100644 index 000000000..8380d02db --- /dev/null +++ b/src/unix/ibmi.c @@ -0,0 +1,112 @@ +/* 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 "internal.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +uint64_t uv_get_free_memory(void) { + return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES); +} + + +uint64_t uv_get_total_memory(void) { + return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES); +} + + +void uv_loadavg(double avg[3]) { + avg[0] = avg[1] = avg[2] = 0; + return; +} + + +int uv_resident_set_memory(size_t* rss) { + return UV_ENOSYS; +} + + +int uv_uptime(double* uptime) { + return UV_ENOSYS; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int numcpus, idx = 0; + uv_cpu_info_t* cpu_info; + + *cpu_infos = NULL; + *count = 0; + + numcpus = sysconf(_SC_NPROCESSORS_ONLN); + + *cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) { + return -ENOMEM; + } + + cpu_info = *cpu_infos; + for (idx = 0; idx < numcpus; idx++) { + cpu_info->speed = 0; + cpu_info->model = uv__strdup("unknown"); + cpu_info->cpu_times.user = 0; + cpu_info->cpu_times.sys = 0; + cpu_info->cpu_times.idle = 0; + cpu_info->cpu_times.irq = 0; + cpu_info->cpu_times.nice = 0; + cpu_info++; + } + *count = numcpus; + + return 0; +} \ No newline at end of file diff --git a/uv.gyp b/uv.gyp index 9d9bb4b73..96fb801a7 100644 --- a/uv.gyp +++ b/uv.gyp @@ -274,19 +274,43 @@ }, }], [ 'OS=="aix"', { - 'sources': [ 'src/unix/aix.c' ], + 'variables': { + 'os_name': ' Date: Tue, 21 Nov 2017 14:39:09 +0100 Subject: [PATCH 567/632] test: fix test-spawn compilation Unbreaks libuv compilation on Windows. PR-URL: https://github.com/libuv/libuv/pull/1641 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- test/test-spawn.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test-spawn.c b/test/test-spawn.c index 57d9e094a..4b138265a 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -654,6 +654,9 @@ TEST_IMPL(spawn_tcp_server) { struct sockaddr_in addr; int fd; int r; +#ifdef _WIN32 + uv_os_fd_t handle; +#endif init_process_options("spawn_tcp_server_helper", exit_cb); From 1344d2bb82e195d0eafc0b40ba103f18dfd04cc5 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 23 Nov 2017 20:29:12 -0500 Subject: [PATCH 568/632] 2017.11.25, Version 1.17.0 (Stable) Changes since version 1.16.1: * unix: avoid malloc() call in uv_spawn() (Ben Noordhuis) * doc: clarify the description of uv_loop_alive() (Ed Schouten) * win: map UV_FS_O_EXLOCK to a share mode of 0 (Joran Dirk Greef) * win: fix build on case-sensitive file systems (Ben Noordhuis) * win: fix test runner build with mingw64 (Ben Noordhuis) * win: remove unused variable in test/test-fs.c (Ben Noordhuis) * zos: add strnlen() implementation (jBarz) * unix: keep track of bound sockets sent via spawn (jBarz) * unix,win: wait for threads to start (Ben Noordhuis) * test: add threadpool init/teardown test (Bartosz Sosnowski) * test: avoid malloc() in threadpool test (Ben Noordhuis) * test: lower number of tasks in threadpool test (Ben Noordhuis) * win: issue memory barrier in uv_thread_join() (Ben Noordhuis) * ibmi: add support for new platform (Xu Meng) * test: fix test-spawn compilation (Bartosz Sosnowski) --- AUTHORS | 2 ++ ChangeLog | 35 +++++++++++++++++++++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 8 ++++---- 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index 03255534f..4e15bc478 100644 --- a/AUTHORS +++ b/AUTHORS @@ -318,3 +318,5 @@ Scott Parker Wade Brainerd rayrase Pekka Nikander +Ed Schouten +Xu Meng diff --git a/ChangeLog b/ChangeLog index 595b38712..fc274d251 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,38 @@ +2017.11.25, Version 1.17.0 (Stable) + +Changes since version 1.16.1: + +* unix: avoid malloc() call in uv_spawn() (Ben Noordhuis) + +* doc: clarify the description of uv_loop_alive() (Ed Schouten) + +* win: map UV_FS_O_EXLOCK to a share mode of 0 (Joran Dirk Greef) + +* win: fix build on case-sensitive file systems (Ben Noordhuis) + +* win: fix test runner build with mingw64 (Ben Noordhuis) + +* win: remove unused variable in test/test-fs.c (Ben Noordhuis) + +* zos: add strnlen() implementation (jBarz) + +* unix: keep track of bound sockets sent via spawn (jBarz) + +* unix,win: wait for threads to start (Ben Noordhuis) + +* test: add threadpool init/teardown test (Bartosz Sosnowski) + +* test: avoid malloc() in threadpool test (Ben Noordhuis) + +* test: lower number of tasks in threadpool test (Ben Noordhuis) + +* win: issue memory barrier in uv_thread_join() (Ben Noordhuis) + +* ibmi: add support for new platform (Xu Meng) + +* test: fix test-spawn compilation (Bartosz Sosnowski) + + 2017.11.11, Version 1.16.1 (Stable), 4056fbe46493ef87237e307e0025e551db875e13 Changes since version 1.16.0: diff --git a/appveyor.yml b/appveyor.yml index 8ad69718b..5cb1edbb1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.16.1.build{build} +version: v1.17.0.build{build} init: - git config --global core.autocrlf true diff --git a/configure.ac b/configure.ac index 5fc0f7243..30e4a9b91 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.16.1], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.17.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 a6ffb5d3a..fcdc20a46 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 16 -#define UV_VERSION_PATCH 2 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 17 +#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 c2c5b856e8a2ff304b0020e6bee3f72faab843f7 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 23 Nov 2017 20:29:13 -0500 Subject: [PATCH 569/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index fc274d251..c9863550f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017.11.25, Version 1.17.0 (Stable) +2017.11.25, Version 1.17.0 (Stable), 1344d2bb82e195d0eafc0b40ba103f18dfd04cc5 Changes since version 1.16.1: From 40a003b4e1d24df879952ee87bacebf02851a638 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 23 Nov 2017 20:36:59 -0500 Subject: [PATCH 570/632] Now working on version 1.17.1 --- 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 fcdc20a46..97c88d360 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 17 -#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 9f70d39b5aaaf25fb8a7e8ce1f0c9033c45abe85 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 23 Nov 2017 22:00:05 -0500 Subject: [PATCH 571/632] aix: fix -Wmaybe-uninitialized warning PR-URL: https://github.com/libuv/libuv/pull/1650 Reviewed-By: Ben Noordhuis Reviewed-By: Gireesh Punathil --- src/unix/aix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/unix/aix.c b/src/unix/aix.c index 07f81fcf0..06f19a4fc 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -921,6 +921,7 @@ int uv_uptime(double* uptime) { size_t entries = 0; time_t boot_time; + boot_time = 0; utmpname(UTMP_FILE); setutent(); From c845245e43d23fbf65490dea94bcab2b51d37e31 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Tue, 28 Nov 2017 14:48:09 +0100 Subject: [PATCH 572/632] doc: remove note about SIGWINCH on Windows SIGWINCH support was improved by https://github.com/libuv/libuv/commit/6ad1e81547c83f9fe7c5a806b6b282642e8d3bca PR-URL: https://github.com/libuv/libuv/pull/1638 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- docs/src/signal.rst | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/src/signal.rst b/docs/src/signal.rst index 5b3b352bd..24354e4f7 100644 --- a/docs/src/signal.rst +++ b/docs/src/signal.rst @@ -17,13 +17,6 @@ Reception of some signals is emulated on Windows: program is given approximately 10 seconds to perform cleanup. After that Windows will unconditionally terminate it. -* SIGWINCH is raised whenever libuv detects that the console has been - resized. SIGWINCH is emulated by libuv when the program uses a :c:type:`uv_tty_t` - handle to write to the console. SIGWINCH may not always be delivered in a - timely manner; libuv will only detect size changes when the cursor is - being moved. When a readable :c:type:`uv_tty_t` handle is used in raw mode, - resizing the console buffer will also trigger a SIGWINCH signal. - Watchers for other signals can be successfully created, but these signals are never received. These signals are: `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`, `SIGTERM` and `SIGKILL.` @@ -36,6 +29,7 @@ not detected by libuv; these will not trigger a signal watcher. manage threads. Installing watchers for those signals will lead to unpredictable behavior and is strongly discouraged. Future versions of libuv may simply reject them. +.. versionchanged:: 1.15.0 SIGWINCH support on Windows was improved. Data types ---------- From 49616e4e17bf3e9417992cf177e5bccc1a8cc891 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 30 Nov 2017 00:09:42 +0100 Subject: [PATCH 573/632] Revert "unix,win: wait for threads to start" Reverted for suspected regressions in the Node.js test suite on Windows. Also revert e99ac4c1f4 ("test: add threadpool init/teardown test") since it depends on 5486f6bd51. This reverts commit 5486f6bd517382284109ff2f5355b61de417c4e8. This reverts commit e99ac4c1f4eb3b049a9e147cb53a666506858121. PR-URL: https://github.com/libuv/libuv/pull/1656 Refs: https://github.com/libuv/libuv/pull/1639 Reviewed-By: Colin Ihrig --- src/threadpool.c | 11 ++++------- test/test-list.h | 2 -- test/test-loop-close.c | 18 ------------------ 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/src/threadpool.c b/src/threadpool.c index ff64a3aee..108934112 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -38,6 +38,7 @@ static uv_thread_t* threads; static uv_thread_t default_threads[4]; static QUEUE exit_message; static QUEUE wq; +static volatile int initialized; static void uv__cancelled(struct uv__work* w) { @@ -104,7 +105,7 @@ static void post(QUEUE* q) { UV_DESTRUCTOR(static void cleanup(void)) { unsigned int i; - if (nthreads == 0) + if (initialized == 0) return; post(&exit_message); @@ -121,6 +122,7 @@ UV_DESTRUCTOR(static void cleanup(void)) { threads = NULL; nthreads = 0; + initialized = 0; } #endif @@ -128,7 +130,6 @@ UV_DESTRUCTOR(static void cleanup(void)) { static void init_threads(void) { unsigned int i; const char* val; - int spin; nthreads = ARRAY_SIZE(default_threads); val = getenv("UV_THREADPOOL_SIZE"); @@ -160,11 +161,7 @@ static void init_threads(void) { if (uv_thread_create(threads + i, worker, NULL)) abort(); - do { - uv_mutex_lock(&mutex); - spin = (idle_threads < nthreads); - uv_mutex_unlock(&mutex); - } while (spin); + initialized = 1; } diff --git a/test/test-list.h b/test/test-list.h index 8b530d44b..2adbe6a01 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -28,7 +28,6 @@ TEST_DECLARE (run_once) TEST_DECLARE (run_nowait) TEST_DECLARE (loop_alive) TEST_DECLARE (loop_close) -TEST_DECLARE (loop_instant_close) TEST_DECLARE (loop_stop) TEST_DECLARE (loop_update_time) TEST_DECLARE (loop_backend_timeout) @@ -423,7 +422,6 @@ TASK_LIST_START TEST_ENTRY (run_nowait) TEST_ENTRY (loop_alive) TEST_ENTRY (loop_close) - TEST_ENTRY (loop_instant_close) TEST_ENTRY (loop_stop) TEST_ENTRY (loop_update_time) TEST_ENTRY (loop_backend_timeout) diff --git a/test/test-loop-close.c b/test/test-loop-close.c index f0f3e627f..971c9d725 100644 --- a/test/test-loop-close.c +++ b/test/test-loop-close.c @@ -55,21 +55,3 @@ TEST_IMPL(loop_close) { return 0; } - -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) { -} - -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)); - MAKE_VALGRIND_HAPPY(); - return 0; -} From d708df110a03332224bd9be1bbd23093d9cf9022 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Thu, 30 Nov 2017 12:41:09 +0100 Subject: [PATCH 574/632] unix,win: add uv_os_getpid() Adds a multi platform way to get current process id. PR-URL: https://github.com/libuv/libuv/pull/1661 Reviewed-By: Colin Ihrig --- docs/src/misc.rst | 6 ++++++ include/uv.h | 1 + src/unix/core.c | 5 +++++ src/win/util.c | 5 +++++ test/test-platform-output.c | 4 ++++ 5 files changed, 21 insertions(+) diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 2968d1cea..a653413e0 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -227,6 +227,12 @@ 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:: uv_pid_t uv_os_getpid(void) + + Returns the current process ID. + + .. versionadded:: 1.18.0 + .. c:function:: uv_pid_t uv_os_getppid(void) Returns the parent process ID. diff --git a/include/uv.h b/include/uv.h index 3f6181208..b11666e2e 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1070,6 +1070,7 @@ 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 uv_pid_t uv_os_getpid(void); UV_EXTERN uv_pid_t uv_os_getppid(void); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); diff --git a/src/unix/core.c b/src/unix/core.c index d64593a31..c7e431e52 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1345,6 +1345,11 @@ uv_os_fd_t uv_get_osfhandle(int fd) { } +uv_pid_t uv_os_getpid(void) { + return getpid(); +} + + uv_pid_t uv_os_getppid(void) { return getppid(); } diff --git a/src/win/util.c b/src/win/util.c index 2aec9f8df..3100bc23a 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -331,6 +331,11 @@ uint64_t uv_get_total_memory(void) { } +uv_pid_t uv_os_getpid(void) { + return GetCurrentProcessId(); +} + + uv_pid_t uv_os_getppid(void) { int parent_pid = -1; HANDLE handle; diff --git a/test/test-platform-output.c b/test/test-platform-output.c index 50ed59a6d..4025fba54 100644 --- a/test/test-platform-output.c +++ b/test/test-platform-output.c @@ -29,6 +29,7 @@ TEST_IMPL(platform_output) { size_t rss; size_t size; double uptime; + uv_pid_t pid; uv_pid_t ppid; uv_rusage_t rusage; uv_cpu_info_t* cpus; @@ -145,6 +146,9 @@ TEST_IMPL(platform_output) { printf(" shell: %s\n", pwd.shell); printf(" home directory: %s\n", pwd.homedir); + pid = uv_os_getpid(); + ASSERT(pid > 0); + printf("uv_os_getpid: %d\n", (int) pid); ppid = uv_os_getppid(); ASSERT(ppid > 0); printf("uv_os_getppid: %d\n", (int) ppid); From 0e2814179c9903423d058b095e84f48fcfb8f3d1 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 2 Nov 2017 16:46:50 -0400 Subject: [PATCH 575/632] unix: remove incorrect assertion in uv_shutdown() It isn't necessary, and doesn't agree with the printed message. PR-URL: https://github.com/libuv/libuv/pull/1620 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/unix/stream.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 672a7e2d6..6fc0a01f5 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1261,8 +1261,9 @@ static void uv__read(uv_stream_t* stream) { int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { - assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) && - "uv_shutdown (unix) only supports uv_handle_t right now"); + assert(stream->type == UV_TCP || + stream->type == UV_TTY || + stream->type == UV_NAMED_PIPE); if (!(stream->flags & UV_STREAM_WRITABLE) || stream->flags & UV_STREAM_SHUT || From dadad46d70ab0f5c8aebce33c7c313b03d12f197 Mon Sep 17 00:00:00 2001 From: Matt Harrison Date: Thu, 23 Nov 2017 10:15:04 +0700 Subject: [PATCH 576/632] doc: fix IRC URL in CONTRIBUTING.md PR-URL: https://github.com/libuv/libuv/pull/1647 Reviewed-By: Colin Ihrig Reviewed-By: Refael Ackermann --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aa97506db..d9bf0472f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -164,6 +164,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.freelibuv.net/?channels=libuv +[IRC]: http://webchat.freenode.net/?channels=libuv [Google C/C++ style guide]: https://google.github.io/styleguide/cppguide.html [project maintainers]: https://github.com/libuv/libuv/blob/master/MAINTAINERS.md From 1489c98b7fc17f1702821a269eb0c5e730c5c813 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 30 Nov 2017 21:07:38 -0500 Subject: [PATCH 577/632] 2017.12.02, Version 1.18.0 (Stable) Changes since version 1.17.0: * aix: fix -Wmaybe-uninitialized warning (cjihrig) * doc: remove note about SIGWINCH on Windows (Bartosz Sosnowski) * Revert "unix,win: wait for threads to start" (Ben Noordhuis) * unix,win: add uv_os_getpid() (Bartosz Sosnowski) * unix: remove incorrect assertion in uv_shutdown() (Jameson Nash) * doc: fix IRC URL in CONTRIBUTING.md (Matt Harrison) --- AUTHORS | 1 + ChangeLog | 17 +++++++++++++++++ appveyor.yml | 2 +- configure.ac | 2 +- include/uv-version.h | 8 ++++---- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4e15bc478..b227123e4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -320,3 +320,4 @@ rayrase Pekka Nikander Ed Schouten Xu Meng +Matt Harrison diff --git a/ChangeLog b/ChangeLog index c9863550f..9e73bb3a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2017.12.02, Version 1.18.0 (Stable) + +Changes since version 1.17.0: + +* aix: fix -Wmaybe-uninitialized warning (cjihrig) + +* doc: remove note about SIGWINCH on Windows (Bartosz Sosnowski) + +* Revert "unix,win: wait for threads to start" (Ben Noordhuis) + +* unix,win: add uv_os_getpid() (Bartosz Sosnowski) + +* unix: remove incorrect assertion in uv_shutdown() (Jameson Nash) + +* doc: fix IRC URL in CONTRIBUTING.md (Matt Harrison) + + 2017.11.25, Version 1.17.0 (Stable), 1344d2bb82e195d0eafc0b40ba103f18dfd04cc5 Changes since version 1.16.1: diff --git a/appveyor.yml b/appveyor.yml index 5cb1edbb1..f77e640eb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.17.0.build{build} +version: v1.18.0.build{build} init: - git config --global core.autocrlf true diff --git a/configure.ac b/configure.ac index 30e4a9b91..7eb1674db 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.17.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.18.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 97c88d360..831ee54de 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 17 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 18 +#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 a78847f1b266f1a345d7658cb65fb81582f8b42f Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 30 Nov 2017 21:07:39 -0500 Subject: [PATCH 578/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 9e73bb3a8..113c28aed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2017.12.02, Version 1.18.0 (Stable) +2017.12.02, Version 1.18.0 (Stable), 1489c98b7fc17f1702821a269eb0c5e730c5c813 Changes since version 1.17.0: From c6b7e19f81ec10dfe56f8cb20d5793f428a20711 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 30 Nov 2017 21:15:46 -0500 Subject: [PATCH 579/632] Now working on version 1.18.1 --- 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 831ee54de..6a90f87e4 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 18 -#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 0d6525acae3b9cf8e52bda01a2662b82ca63f6dc Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Thu, 30 Nov 2017 00:29:47 +0100 Subject: [PATCH 580/632] core: add getter/setter functions for easier ABI compat Add getter/setter functions for the fields of public structs that might be relevant to e.g. Node.js addons. Through these methods, ABI compatibility for a subset of the ABI is easier to achieve, since using them makes code independent of the exact offsets of these fields. The intended use case that prompted this are N-API addons for Node.js, which look for more long-term ABI compatibility guarantees than typical Node code. With these helper functions, using libuv directly should no longer be an obstacle for such addons. PR-URL: https://github.com/libuv/libuv/pull/1657 Refs: https://github.com/nodejs/node/issues/13512 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Refael Ackermann Reviewed-By: Santiago Gimeno --- Makefile.am | 2 + checksparse.sh | 2 + docs/src/fs.rst | 30 +++++++++++ docs/src/handle.rst | 32 ++++++++++++ docs/src/loop.rst | 12 +++++ docs/src/process.rst | 6 +++ docs/src/request.rst | 27 ++++++++++ docs/src/stream.rst | 6 +++ docs/src/udp.rst | 12 +++++ include/uv.h | 23 +++++++++ src/uv-data-getter-setters.c | 96 ++++++++++++++++++++++++++++++++++++ test/test-getters-setters.c | 88 +++++++++++++++++++++++++++++++++ test/test-list.h | 8 +++ test/test-spawn.c | 2 + uv.gyp | 2 + 15 files changed, 348 insertions(+) create mode 100644 src/uv-data-getter-setters.c create mode 100644 test/test-getters-setters.c diff --git a/Makefile.am b/Makefile.am index e01cf4166..b104edecd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,6 +29,7 @@ libuv_la_SOURCES = src/fs-poll.c \ src/inet.c \ src/queue.h \ src/threadpool.c \ + src/uv-data-getter-setters.c \ src/uv-common.c \ src/uv-common.h \ src/version.c @@ -174,6 +175,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-fs-poll.c \ test/test-fs.c \ test/test-fork.c \ + test/test-getters-setters.c \ test/test-get-currentexe.c \ test/test-get-loadavg.c \ test/test-get-memory.c \ diff --git a/checksparse.sh b/checksparse.sh index d4a983d02..02a5d7f2d 100755 --- a/checksparse.sh +++ b/checksparse.sh @@ -53,6 +53,7 @@ src/unix/tty.c src/unix/udp.c src/uv-common.c src/uv-common.h +src/uv-data-getter-setters.c " TESTS=" @@ -100,6 +101,7 @@ test/test-fs-copyfile.c test/test-fs-event.c test/test-fs-poll.c test/test-fs.c +test/test-getters-setters.c test/test-get-currentexe.c test/test-get-loadavg.c test/test-get-memory.c diff --git a/docs/src/fs.rst b/docs/src/fs.rst index 16d5e05c7..87af828a2 100644 --- a/docs/src/fs.rst +++ b/docs/src/fs.rst @@ -340,6 +340,36 @@ API .. note:: These functions are not implemented on Windows. +.. c:function:: uv_fs_type uv_fs_get_type(const uv_fs_t* req) + + Returns `req->fs_type`. + + .. versionadded:: 1.19.0 + +.. c:function:: ssize_t uv_fs_get_result(const uv_fs_t* req) + + Returns `req->result`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_fs_get_ptr(const uv_fs_t* req) + + Returns `req->ptr`. + + .. versionadded:: 1.19.0 + +.. c:function:: const char* uv_fs_get_path(const uv_fs_t* req) + + Returns `req->path`. + + .. versionadded:: 1.19.0 + +.. c:function:: uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) + + Returns `&req->statbuf`. + + .. versionadded:: 1.19.0 + .. seealso:: The :c:type:`uv_req_t` API functions also apply. Helper functions diff --git a/docs/src/handle.rst b/docs/src/handle.rst index a0f3d05fd..e4cb90b5f 100644 --- a/docs/src/handle.rst +++ b/docs/src/handle.rst @@ -211,6 +211,38 @@ just for some handle types. Be very careful when using this function. libuv assumes it's in control of the file descriptor so any change to it may lead to malfunction. +.. c:function:: uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) + + Returns `handle->loop`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_handle_get_data(const uv_handle_t* handle) + + Returns `handle->data`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_handle_set_data(uv_handle_t* handle, void* data) + + Sets `handle->data` to `data`. + + .. versionadded:: 1.19.0 + +.. c:function:: uv_handle_type uv_handle_get_type(const uv_handle_t* handle) + + Returns `handle->type`. + + .. versionadded:: 1.19.0 + +.. c:function:: const char* uv_handle_type_name(uv_handle_type type) + + Returns the name for the equivalent struct for a given handle type, + e.g. `"pipe"` (as in :c:type:`uv_pipe_t`) for `UV_NAMED_PIPE`. + + If no such handle type exists, this returns `NULL`. + + .. versionadded:: 1.19.0 .. _refcount: diff --git a/docs/src/loop.rst b/docs/src/loop.rst index 18dd135cd..dcde5049a 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -222,3 +222,15 @@ API Any previous value returned from :c:func`uv_backend_fd` is now invalid. That function must be called again to determine the correct backend file descriptor. + +.. c:function:: void* uv_loop_get_data(const uv_loop_t* loop) + + Returns `loop->data`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_loop_set_data(uv_loop_t* loop, void* data) + + Sets `loop->data` to `data`. + + .. versionadded:: 1.19.0 diff --git a/docs/src/process.rst b/docs/src/process.rst index b0380ddfb..ecc3cbf34 100644 --- a/docs/src/process.rst +++ b/docs/src/process.rst @@ -222,4 +222,10 @@ API Sends the specified signal to the given PID. Check the documentation on :c:ref:`signal` for signal support, specially on Windows. +.. c:function:: uv_pid_t uv_process_get_pid(const uv_process_t* handle) + + Returns `handle->pid`. + + .. versionadded:: 1.19.0 + .. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/docs/src/request.rst b/docs/src/request.rst index 660b80ae9..54d9a2f30 100644 --- a/docs/src/request.rst +++ b/docs/src/request.rst @@ -80,3 +80,30 @@ API Returns the size of the given request type. Useful for FFI binding writers who don't want to know the structure layout. + +.. c:function:: void* uv_req_get_data(const uv_req_t* req) + + Returns `req->data`. + + .. versionadded:: 1.19.0 + +.. c:function:: void* uv_req_set_data(uv_req_t* req, void* data) + + Sets `req->data` to `data`. + + .. versionadded:: 1.19.0 + +.. c:function:: uv_req_type uv_req_get_type(const uv_req_t* req) + + Returns `req->type`. + + .. versionadded:: 1.19.0 + +.. c:function:: const char* uv_req_type_name(uv_req_type type) + + Returns the name for the equivalent struct for a given request type, + e.g. `"connect"` (as in :c:type:`uv_connect_t`) for `UV_CONNECT`. + + If no such request type exists, this returns `NULL`. + + .. versionadded:: 1.19.0 diff --git a/docs/src/stream.rst b/docs/src/stream.rst index 1f4e87e63..9ec236225 100644 --- a/docs/src/stream.rst +++ b/docs/src/stream.rst @@ -228,4 +228,10 @@ API .. versionchanged:: 1.4.0 UNIX implementation added. +.. c:function:: size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) + + Returns `stream->write_queue_size`. + + .. versionadded:: 1.19.0 + .. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/docs/src/udp.rst b/docs/src/udp.rst index dd4660339..8704a099a 100644 --- a/docs/src/udp.rst +++ b/docs/src/udp.rst @@ -292,4 +292,16 @@ API :returns: 0 on success, or an error code < 0 on failure. +.. c:function:: size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) + + Returns `handle->send_queue_size`. + + .. versionadded:: 1.19.0 + +.. c:function:: size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) + + Returns `handle->send_queue_count`. + + .. versionadded:: 1.19.0 + .. seealso:: The :c:type:`uv_handle_t` API functions also apply. diff --git a/include/uv.h b/include/uv.h index b11666e2e..3a061132c 100644 --- a/include/uv.h +++ b/include/uv.h @@ -425,7 +425,17 @@ struct uv_handle_s { }; UV_EXTERN size_t uv_handle_size(uv_handle_type type); +UV_EXTERN uv_handle_type uv_handle_get_type(const uv_handle_t* handle); +UV_EXTERN const char* uv_handle_type_name(uv_handle_type type); +UV_EXTERN void* uv_handle_get_data(const uv_handle_t* handle); +UV_EXTERN uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle); +UV_EXTERN void uv_handle_set_data(uv_handle_t* handle, void* data); + UV_EXTERN size_t uv_req_size(uv_req_type type); +UV_EXTERN void* uv_req_get_data(const uv_req_t* req); +UV_EXTERN void uv_req_set_data(uv_req_t* req, void* data); +UV_EXTERN uv_req_type uv_req_get_type(const uv_req_t* req); +UV_EXTERN const char* uv_req_type_name(uv_req_type type); UV_EXTERN int uv_is_active(const uv_handle_t* handle); @@ -465,6 +475,8 @@ struct uv_stream_s { UV_STREAM_FIELDS }; +UV_EXTERN size_t uv_stream_get_write_queue_size(const uv_stream_t* stream); + UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb); UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client); @@ -642,6 +654,8 @@ UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb); UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle); +UV_EXTERN size_t uv_udp_get_send_queue_size(const uv_udp_t* handle); +UV_EXTERN size_t uv_udp_get_send_queue_count(const uv_udp_t* handle); /* @@ -962,6 +976,7 @@ UV_EXTERN int uv_spawn(uv_loop_t* loop, const uv_process_options_t* options); UV_EXTERN int uv_process_kill(uv_process_t*, int signum); UV_EXTERN int uv_kill(int pid, int signum); +UV_EXTERN uv_pid_t uv_process_get_pid(const uv_process_t*); /* @@ -1135,6 +1150,12 @@ struct uv_fs_s { UV_FS_PRIVATE_FIELDS }; +UV_EXTERN uv_fs_type uv_fs_get_type(const uv_fs_t*); +UV_EXTERN ssize_t uv_fs_get_result(const uv_fs_t*); +UV_EXTERN void* uv_fs_get_ptr(const uv_fs_t*); +UV_EXTERN const char* uv_fs_get_path(const uv_fs_t*); +UV_EXTERN uv_stat_t* uv_fs_get_statbuf(uv_fs_t*); + UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req); UV_EXTERN int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, @@ -1516,6 +1537,8 @@ struct uv_loop_s { UV_LOOP_PRIVATE_FIELDS }; +UV_EXTERN void* uv_loop_get_data(const uv_loop_t*); +UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data); /* Don't export the private CPP symbols. */ #undef UV_HANDLE_TYPE_PRIVATE diff --git a/src/uv-data-getter-setters.c b/src/uv-data-getter-setters.c new file mode 100644 index 000000000..533e4a2fe --- /dev/null +++ b/src/uv-data-getter-setters.c @@ -0,0 +1,96 @@ +#include "uv.h" + +const char* uv_handle_type_name(uv_handle_type type) { + switch (type) { +#define XX(uc,lc) case UV_##uc: return #lc; + UV_HANDLE_TYPE_MAP(XX) +#undef XX + case UV_FILE: return "file"; + case UV_HANDLE_TYPE_MAX: + case UV_UNKNOWN_HANDLE: return NULL; + } + return NULL; +} + +uv_handle_type uv_handle_get_type(const uv_handle_t* handle) { + return handle->type; +} + +void* uv_handle_get_data(const uv_handle_t* handle) { + return handle->data; +} + +uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) { + return handle->loop; +} + +void uv_handle_set_data(uv_handle_t* handle, void* data) { + handle->data = data; +} + +const char* uv_req_type_name(uv_req_type type) { + switch (type) { +#define XX(uc,lc) case UV_##uc: return #lc; + UV_REQ_TYPE_MAP(XX) +#undef XX + case UV_REQ_TYPE_MAX: + case UV_UNKNOWN_REQ: return NULL; + } + return NULL; +} + +uv_req_type uv_req_get_type(const uv_req_t* req) { + return req->type; +} + +void* uv_req_get_data(const uv_req_t* req) { + return req->data; +} + +void uv_req_set_data(uv_req_t* req, void* data) { + req->data = data; +} + +size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) { + return stream->write_queue_size; +} + +size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) { + return handle->send_queue_size; +} + +size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) { + return handle->send_queue_count; +} + +uv_pid_t uv_process_get_pid(const uv_process_t* proc) { + return proc->pid; +} + +uv_fs_type uv_fs_get_type(const uv_fs_t* req) { + return req->fs_type; +} + +ssize_t uv_fs_get_result(const uv_fs_t* req) { + return req->result; +} + +void* uv_fs_get_ptr(const uv_fs_t* req) { + return req->ptr; +} + +const char* uv_fs_get_path(const uv_fs_t* req) { + return req->path; +} + +uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) { + return &req->statbuf; +} + +void* uv_loop_get_data(const uv_loop_t* loop) { + return loop->data; +} + +void uv_loop_set_data(uv_loop_t* loop, void* data) { + loop->data = data; +} diff --git a/test/test-getters-setters.c b/test/test-getters-setters.c new file mode 100644 index 000000000..60a1b9264 --- /dev/null +++ b/test/test-getters-setters.c @@ -0,0 +1,88 @@ +#include "uv.h" +#include "task.h" +#include +#include + +int cookie1; +int cookie2; +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(uv_handle_type_name(UV_HANDLE_TYPE_MAX) == NULL); + ASSERT(uv_handle_type_name(UV_HANDLE_TYPE_MAX + 1) == NULL); + ASSERT(uv_handle_type_name(UV_UNKNOWN_HANDLE) == NULL); + return 0; +} + + +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(uv_req_type_name(UV_REQ_TYPE_MAX) == NULL); + ASSERT(uv_req_type_name(UV_REQ_TYPE_MAX + 1) == NULL); + ASSERT(uv_req_type_name(UV_UNKNOWN_REQ) == NULL); + return 0; +} + + +TEST_IMPL(getters_setters) { + uv_loop_t* loop; + uv_pipe_t* pipe; + uv_fs_t* fs; + int r; + + loop = malloc(uv_loop_size()); + ASSERT(loop != NULL); + r = uv_loop_init(loop); + ASSERT(r == 0); + + uv_loop_set_data(loop, &cookie1); + ASSERT(loop->data == &cookie1); + ASSERT(uv_loop_get_data(loop) == &cookie1); + + pipe = malloc(uv_handle_size(UV_NAMED_PIPE)); + r = uv_pipe_init(loop, pipe, 0); + ASSERT(uv_handle_get_type((uv_handle_t*)pipe) == UV_NAMED_PIPE); + + ASSERT(uv_handle_get_loop((uv_handle_t*)pipe) == loop); + pipe->data = &cookie2; + ASSERT(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(uv_stream_get_write_queue_size((uv_stream_t*)pipe) == 0); + pipe->write_queue_size++; + ASSERT(uv_stream_get_write_queue_size((uv_stream_t*)pipe) == 1); + pipe->write_queue_size--; + uv_close((uv_handle_t*)pipe, NULL); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + fs = malloc(uv_req_size(UV_FS)); + uv_fs_stat(loop, fs, ".", NULL); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + 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(uv_fs_get_statbuf(fs)->st_mode & S_IFDIR); + ASSERT(strcmp(uv_fs_get_path(fs), ".") == 0); + uv_fs_req_cleanup(fs); + + r = uv_loop_close(loop); + ASSERT(r == 0); + + free(pipe); + free(fs); + free(loop); + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 2adbe6a01..662fe78b3 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -397,6 +397,10 @@ HELPER_DECLARE (pipe_echo_server) TEST_DECLARE (queue_foreach_delete) +TEST_DECLARE (handle_type_name) +TEST_DECLARE (req_type_name) +TEST_DECLARE (getters_setters) + #ifndef _WIN32 TEST_DECLARE (fork_timer) TEST_DECLARE (fork_socketpair) @@ -870,6 +874,10 @@ TASK_LIST_START TEST_ENTRY (queue_foreach_delete) + TEST_ENTRY (handle_type_name) + TEST_ENTRY (req_type_name) + TEST_ENTRY (getters_setters) + #ifndef _WIN32 TEST_ENTRY (fork_timer) TEST_ENTRY (fork_socketpair) diff --git a/test/test-spawn.c b/test/test-spawn.c index 4b138265a..9a30f6cb5 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -805,6 +805,8 @@ TEST_IMPL(spawn_detached) { ASSERT(exit_cb_called == 0); + ASSERT(process.pid == uv_process_get_pid(&process)); + r = uv_kill(process.pid, 0); ASSERT(r == 0); diff --git a/uv.gyp b/uv.gyp index 96fb801a7..10f322792 100644 --- a/uv.gyp +++ b/uv.gyp @@ -78,6 +78,7 @@ 'src/inet.c', 'src/queue.h', 'src/threadpool.c', + 'src/uv-data-getter-setters.c', 'src/uv-common.c', 'src/uv-common.h', 'src/version.c' @@ -380,6 +381,7 @@ 'test/test-fs.c', 'test/test-fs-copyfile.c', 'test/test-fs-event.c', + 'test/test-getters-setters.c', 'test/test-get-currentexe.c', 'test/test-get-memory.c', 'test/test-get-passwd.c', From 8a6d1b32c5e3701051f89b4b61559c1cabb5e914 Mon Sep 17 00:00:00 2001 From: Matt Harrison Date: Wed, 15 Nov 2017 15:31:01 +0700 Subject: [PATCH 581/632] unix: make get(set)_process_title MT-safe Used a shared uv_mutex_t in unix implementations of these functions to prevent simultaneous execution. Fixes: https://github.com/libuv/libuv/issues/271 PR-URL: https://github.com/libuv/libuv/pull/1640 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- Makefile.am | 1 + checksparse.sh | 1 + docs/src/misc.rst | 6 +- src/unix/aix.c | 17 ++++++ src/unix/freebsd.c | 27 ++++++++- src/unix/netbsd.c | 27 ++++++++- src/unix/openbsd.c | 28 ++++++++- src/unix/proctitle.c | 31 ++++++++-- test/test-list.h | 2 + test/test-process-title-threadsafe.c | 90 ++++++++++++++++++++++++++++ uv.gyp | 1 + 11 files changed, 215 insertions(+), 16 deletions(-) create mode 100644 test/test-process-title-threadsafe.c diff --git a/Makefile.am b/Makefile.am index b104edecd..128ac5661 100644 --- a/Makefile.am +++ b/Makefile.am @@ -222,6 +222,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-poll-closesocket.c \ test/test-poll-oob.c \ test/test-process-title.c \ + test/test-process-title-threadsafe.c \ test/test-queue-foreach-delete.c \ test/test-ref.c \ test/test-run-nowait.c \ diff --git a/checksparse.sh b/checksparse.sh index 02a5d7f2d..27eb529bc 100755 --- a/checksparse.sh +++ b/checksparse.sh @@ -128,6 +128,7 @@ test/test-platform-output.c test/test-poll-close.c test/test-poll.c test/test-process-title.c +test/test-process-title-threadsafe.c test/test-ref.c test/test-run-nowait.c test/test-run-once.c diff --git a/docs/src/misc.rst b/docs/src/misc.rst index a653413e0..07908c98f 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -197,8 +197,7 @@ API `UV_EINVAL` is returned. If `size` cannot accommodate the process title and terminating `NULL` character, the function returns `UV_ENOBUFS`. - .. warning:: - `uv_get_process_title` is not thread safe on any platform except Windows. + .. versionchanged:: 1.18.1 now thread-safe on all supported platforms. .. c:function:: int uv_set_process_title(const char* title) @@ -208,8 +207,7 @@ API larger than the available space. Other platforms will return `UV_ENOMEM` if they cannot allocate enough space to duplicate the contents of `title`. - .. warning:: - `uv_set_process_title` is not thread safe on any platform except Windows. + .. versionchanged:: 1.18.1 now thread-safe on all supported platforms. .. c:function:: int uv_resident_set_memory(size_t* rss) diff --git a/src/unix/aix.c b/src/unix/aix.c index 06f19a4fc..fd413090f 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -65,11 +65,18 @@ #define RDWR_BUF_SIZE 4096 #define EQ(a,b) (strcmp(a,b) == 0) +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; static void* args_mem = NULL; static char** process_argv = NULL; static int process_argc = 0; static char* process_title_ptr = NULL; +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + int uv__platform_loop_init(uv_loop_t* loop) { loop->fs_fd = -1; @@ -856,6 +863,9 @@ int uv_set_process_title(const char* title) { if (new_title == NULL) return -ENOMEM; + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + /* If this is the first time this is set, * don't free and set argv[1] to NULL. */ @@ -868,6 +878,8 @@ int uv_set_process_title(const char* title) { if (process_argc > 1) process_argv[1] = NULL; + uv_mutex_unlock(&process_title_mutex); + return 0; } @@ -880,8 +892,13 @@ int uv_get_process_title(char* buffer, size_t size) { else if (size <= len) return -ENOBUFS; + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + memcpy(buffer, process_argv[0], len + 1); + uv_mutex_unlock(&process_title_mutex); + return 0; } diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index dba94298d..39db148a2 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -47,9 +47,16 @@ # define CP_INTR 4 #endif +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; static char *process_title; +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + int uv__platform_loop_init(uv_loop_t* loop) { return uv__kqueue_init(loop); } @@ -163,8 +170,15 @@ int uv_set_process_title(const char* title) { char* new_title; new_title = uv__strdup(title); - if (process_title == NULL) + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title == NULL) { + uv_mutex_unlock(&process_title_mutex); return -ENOMEM; + } + uv__free(process_title); process_title = new_title; @@ -180,6 +194,8 @@ int uv_set_process_title(const char* title) { process_title, strlen(process_title) + 1); + uv_mutex_unlock(&process_title_mutex); + return 0; } @@ -190,17 +206,24 @@ int uv_get_process_title(char* buffer, size_t size) { if (buffer == NULL || size == 0) return -EINVAL; + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + if (process_title) { len = strlen(process_title) + 1; - if (size < len) + if (size < len) { + uv_mutex_unlock(&process_title_mutex); return -ENOBUFS; + } memcpy(buffer, process_title, len); } else { len = 0; } + uv_mutex_unlock(&process_title_mutex); + buffer[len] = '\0'; return 0; diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index d9066349c..742507233 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -40,9 +40,16 @@ #include #include +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; static char *process_title; +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + int uv__platform_loop_init(uv_loop_t* loop) { return uv__kqueue_init(loop); } @@ -137,12 +144,21 @@ int uv_set_process_title(const char* title) { char* new_title; new_title = uv__strdup(title); - if (process_title == NULL) + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title == NULL) { + uv_mutex_unlock(&process_title_mutex); return -ENOMEM; + } + uv__free(process_title); process_title = new_title; setproctitle("%s", title); + uv_mutex_unlock(&process_title_mutex); + return 0; } @@ -153,17 +169,24 @@ int uv_get_process_title(char* buffer, size_t size) { if (buffer == NULL || size == 0) return -EINVAL; + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + if (process_title) { len = strlen(process_title) + 1; - if (size < len) + if (size < len) { + uv_mutex_unlock(&process_title_mutex); return -ENOBUFS; + } memcpy(buffer, process_title, len); } else { len = 0; } + uv_mutex_unlock(&process_title_mutex); + buffer[len] = '\0'; return 0; diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index d1c90289e..c0ffa564b 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -36,9 +36,16 @@ #include +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; static char *process_title; +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + int uv__platform_loop_init(uv_loop_t* loop) { return uv__kqueue_init(loop); } @@ -149,11 +156,21 @@ int uv_set_process_title(const char* title) { char* new_title; new_title = uv__strdup(title); - if (process_title == NULL) + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title == NULL) { + uv_mutex_unlock(&process_title_mutex); return -ENOMEM; + } + uv__free(process_title); process_title = new_title; setproctitle("%s", title); + + uv_mutex_unlock(&process_title_mutex); + return 0; } @@ -164,17 +181,24 @@ int uv_get_process_title(char* buffer, size_t size) { if (buffer == NULL || size == 0) return -EINVAL; + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + if (process_title) { len = strlen(process_title) + 1; - if (size < len) + if (size < len) { + uv_mutex_unlock(&process_title_mutex); return -ENOBUFS; + } memcpy(buffer, process_title, len); } else { len = 0; } + uv_mutex_unlock(&process_title_mutex); + buffer[len] = '\0'; return 0; diff --git a/src/unix/proctitle.c b/src/unix/proctitle.c index 2ed0b21c6..1b3a79882 100644 --- a/src/unix/proctitle.c +++ b/src/unix/proctitle.c @@ -26,6 +26,8 @@ extern void uv__set_process_title(const char* title); +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; static void* args_mem; static struct { @@ -34,6 +36,11 @@ static struct { } process_title; +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + char** uv_setup_args(int argc, char** argv) { char** new_argv; size_t size; @@ -81,12 +88,16 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { - if (process_title.len == 0) - return 0; + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title.len != 0) { + /* No need to terminate, byte after is always '\0'. */ + strncpy(process_title.str, title, process_title.len); + uv__set_process_title(title); + } - /* No need to terminate, byte after is always '\0'. */ - strncpy(process_title.str, title, process_title.len); - uv__set_process_title(title); + uv_mutex_unlock(&process_title_mutex); return 0; } @@ -95,14 +106,22 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { if (buffer == NULL || size == 0) return -EINVAL; - else if (size <= process_title.len) + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (size <= process_title.len) { + uv_mutex_unlock(&process_title_mutex); return -ENOBUFS; + } if (process_title.len != 0) memcpy(buffer, process_title.str, process_title.len + 1); buffer[process_title.len] = '\0'; + uv_mutex_unlock(&process_title_mutex); + return 0; } diff --git a/test/test-list.h b/test/test-list.h index 662fe78b3..08a599910 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -214,6 +214,7 @@ TEST_DECLARE (async_null_cb) TEST_DECLARE (eintr_handling) TEST_DECLARE (get_currentexe) TEST_DECLARE (process_title) +TEST_DECLARE (process_title_threadsafe) TEST_DECLARE (cwd_and_chdir) TEST_DECLARE (get_memory) TEST_DECLARE (get_passwd) @@ -672,6 +673,7 @@ TASK_LIST_START TEST_ENTRY (get_currentexe) TEST_ENTRY (process_title) + TEST_ENTRY (process_title_threadsafe) TEST_ENTRY (cwd_and_chdir) diff --git a/test/test-process-title-threadsafe.c b/test/test-process-title-threadsafe.c new file mode 100644 index 000000000..d986576ed --- /dev/null +++ b/test/test-process-title-threadsafe.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 + +#ifdef __APPLE__ +# define NUM_ITERATIONS 20 +#else +# define NUM_ITERATIONS 50 +#endif + +static const char* titles[] = { + "8L2NY0Kdj0XyNFZnmUZigIOfcWjyNr0SkMmUhKw99VLUsZFrvCQQC3XIRfNR8pjyMjXObllled", + "jUAcscJN49oLSN8GdmXj2Wo34XX2T2vp2j5khfajNQarlOulp57cE130yiY53ipJFnPyTn5i82", + "9niCI5icXGFS72XudhXqo5alftmZ1tpE7B3cwUmrq0CCDjC84FzBNB8XAHqvpNQfI2QAQG6ztT", + "n8qXVXuG6IEHDpabJgTEiwtpY6LHMZ8MgznnMpdHARu5EywufA6hcBaQfetb0YhEsK0ykDd7JU" +}; + +static void getter_thread_body(void* arg) { + char buffer[512]; + + for (;;) { + ASSERT(0 == uv_get_process_title(buffer, sizeof(buffer))); + ASSERT( + 0 == strcmp(buffer, titles[0]) || + 0 == strcmp(buffer, titles[1]) || + 0 == strcmp(buffer, titles[2]) || + 0 == strcmp(buffer, titles[3])); + + uv_sleep(0); + } +} + + +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])); + } +} + + +TEST_IMPL(process_title_threadsafe) { + uv_thread_t setter_threads[4]; + uv_thread_t getter_thread; + int i; + +#if defined(__sun) || defined(__CYGWIN__) || defined(__MSYS__) || \ + defined(__MVS__) + RETURN_SKIP("uv_(get|set)_process_title is not implemented."); +#else + + ASSERT(0 == uv_set_process_title(titles[0])); + ASSERT(0 == uv_thread_create(&getter_thread, getter_thread_body, NULL)); + + for (i = 0; i < (int) ARRAY_SIZE(setter_threads); i++) + ASSERT(0 == 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])); + + return 0; +#endif +} diff --git a/uv.gyp b/uv.gyp index 10f322792..dade2125c 100644 --- a/uv.gyp +++ b/uv.gyp @@ -427,6 +427,7 @@ 'test/test-poll-closesocket.c', 'test/test-poll-oob.c', 'test/test-process-title.c', + 'test/test-process-title-threadsafe.c', 'test/test-queue-foreach-delete.c', 'test/test-ref.c', 'test/test-run-nowait.c', From 647fbc026e367cbf0ca2df2b0f72f668e41dccdf Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 6 Dec 2017 23:47:38 +0100 Subject: [PATCH 582/632] unix,win: wait for threads to start It appears that, at least on Windows, the process terminates abnormally when the program exits before the worker threads complete initializing. Wait for the threads to spin up in `init_threads()` to avoid that. PR-URL: https://github.com/libuv/libuv/pull/1662 Reviewed-By: Bartosz Sosnowski Reviewed-By: Colin Ihrig Reviewed-By: Jamie Davis --- src/threadpool.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/threadpool.c b/src/threadpool.c index 108934112..413d1c204 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -38,7 +38,6 @@ static uv_thread_t* threads; static uv_thread_t default_threads[4]; static QUEUE exit_message; static QUEUE wq; -static volatile int initialized; static void uv__cancelled(struct uv__work* w) { @@ -53,7 +52,8 @@ static void worker(void* arg) { struct uv__work* w; QUEUE* q; - (void) arg; + uv_sem_post((uv_sem_t*) arg); + arg = NULL; for (;;) { uv_mutex_lock(&mutex); @@ -105,7 +105,7 @@ static void post(QUEUE* q) { UV_DESTRUCTOR(static void cleanup(void)) { unsigned int i; - if (initialized == 0) + if (nthreads == 0) return; post(&exit_message); @@ -122,7 +122,6 @@ UV_DESTRUCTOR(static void cleanup(void)) { threads = NULL; nthreads = 0; - initialized = 0; } #endif @@ -130,6 +129,7 @@ UV_DESTRUCTOR(static void cleanup(void)) { static void init_threads(void) { unsigned int i; const char* val; + uv_sem_t sem; nthreads = ARRAY_SIZE(default_threads); val = getenv("UV_THREADPOOL_SIZE"); @@ -157,11 +157,17 @@ static void init_threads(void) { QUEUE_INIT(&wq); + if (uv_sem_init(&sem, 0)) + abort(); + for (i = 0; i < nthreads; i++) - if (uv_thread_create(threads + i, worker, NULL)) + if (uv_thread_create(threads + i, worker, &sem)) abort(); - initialized = 1; + for (i = 0; i < nthreads; i++) + uv_sem_wait(&sem); + + uv_sem_destroy(&sem); } From c73e73c8743cc664460a8ae173f034481d94323f Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Wed, 6 Dec 2017 23:47:38 +0100 Subject: [PATCH 583/632] test: add threadpool init/teardown test Verify that quick setup and teardown of the threadpool doesn't cause crashes or hangs. PR-URL: https://github.com/libuv/libuv/pull/1639 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- test/test-list.h | 2 ++ test/test-loop-close.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/test/test-list.h b/test/test-list.h index 08a599910..bc75858fb 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -28,6 +28,7 @@ TEST_DECLARE (run_once) TEST_DECLARE (run_nowait) TEST_DECLARE (loop_alive) TEST_DECLARE (loop_close) +TEST_DECLARE (loop_instant_close) TEST_DECLARE (loop_stop) TEST_DECLARE (loop_update_time) TEST_DECLARE (loop_backend_timeout) @@ -427,6 +428,7 @@ TASK_LIST_START TEST_ENTRY (run_nowait) TEST_ENTRY (loop_alive) TEST_ENTRY (loop_close) + TEST_ENTRY (loop_instant_close) TEST_ENTRY (loop_stop) TEST_ENTRY (loop_update_time) TEST_ENTRY (loop_backend_timeout) diff --git a/test/test-loop-close.c b/test/test-loop-close.c index 971c9d725..f0f3e627f 100644 --- a/test/test-loop-close.c +++ b/test/test-loop-close.c @@ -55,3 +55,21 @@ TEST_IMPL(loop_close) { return 0; } + +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) { +} + +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)); + MAKE_VALGRIND_HAPPY(); + return 0; +} From 890eedaf59cea75faaa6a14b4248a472dcadb831 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Tue, 21 Nov 2017 14:35:36 +0100 Subject: [PATCH 584/632] win, process: uv_kill improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Maps pid 0 to the current process, simulating Linux kill sending signal to the process group. Adds detection of invalid signals. If the signum is invalid - below 0 or NSIG or above – UV_EINVAL will be returned instead of UV_ENOSYS. PR-URL: https://github.com/libuv/libuv/pull/1642 Reviewed-By: Ben Noordhuis Reviewed-By: Refael Ackermann Reviewed-By: Colin Ihrig --- src/win/process.c | 15 +++++++++++++-- test/test-list.h | 2 ++ test/test-signal.c | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index 764250e13..cc06d9e22 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -1173,6 +1173,10 @@ int uv_spawn(uv_loop_t* loop, static int uv__kill(HANDLE process_handle, int signum) { + if (signum < 0 || signum >= NSIG) { + return UV_EINVAL; + } + switch (signum) { case SIGTERM: case SIGKILL: @@ -1237,8 +1241,15 @@ int uv_process_kill(uv_process_t* process, int signum) { int uv_kill(int pid, int signum) { int err; - HANDLE process_handle = OpenProcess(PROCESS_TERMINATE | - PROCESS_QUERY_INFORMATION, FALSE, pid); + HANDLE process_handle; + + if (pid == 0) { + process_handle = GetCurrentProcess(); + } else { + process_handle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, + FALSE, + pid); + } if (process_handle == NULL) { err = GetLastError(); diff --git a/test/test-list.h b/test/test-list.h index bc75858fb..892a00196 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -266,6 +266,7 @@ TEST_DECLARE (spawn_tcp_server) TEST_DECLARE (fs_poll) TEST_DECLARE (fs_poll_getpath) TEST_DECLARE (kill) +TEST_DECLARE (kill_invalid_signum) TEST_DECLARE (fs_file_noent) TEST_DECLARE (fs_file_nametoolong) TEST_DECLARE (fs_file_loop) @@ -756,6 +757,7 @@ TASK_LIST_START TEST_ENTRY (fs_poll) TEST_ENTRY (fs_poll_getpath) TEST_ENTRY (kill) + TEST_ENTRY (kill_invalid_signum) TEST_ENTRY (poll_close_doesnt_corrupt_stack) TEST_ENTRY (poll_closesocket) diff --git a/test/test-signal.c b/test/test-signal.c index 9a881510c..c2ce5ec0e 100644 --- a/test/test-signal.c +++ b/test/test-signal.c @@ -22,6 +22,26 @@ #include "uv.h" #include "task.h" +#ifndef _WIN32 +#include +#endif + +TEST_IMPL(kill_invalid_signum) { + uv_pid_t pid; + + pid = uv_os_getpid(); + + ASSERT(uv_kill(pid, -1) == UV_EINVAL); +#ifdef _WIN32 + /* NSIG is not available on all platforms. */ + ASSERT(uv_kill(pid, NSIG) == UV_EINVAL); +#endif + ASSERT(uv_kill(pid, 4096) == UV_EINVAL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + /* For Windows we test only signum handling */ #ifdef _WIN32 static void signum_test_cb(uv_signal_t* handle, int signum) { From e771ede0699f0b4a05d9ab2d824a32a4df73964e Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 8 Dec 2017 10:14:25 -0500 Subject: [PATCH 585/632] win: set _WIN32_WINNT to 0x0600 This updates the value to Windows Vista. Fixes: https://github.com/libuv/libuv/issues/1671 PR-URL: https://github.com/libuv/libuv/pull/1675 Reviewed-By: Ben Noordhuis Reviewed-By: Refael Ackermann --- include/uv-win.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uv-win.h b/include/uv-win.h index b96bed22a..4c6c50a29 100644 --- a/include/uv-win.h +++ b/include/uv-win.h @@ -20,7 +20,7 @@ */ #ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x0502 +# define _WIN32_WINNT 0x0600 #endif #if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) From b01de7341f40e1f30d78178442b0b87a46b3b7a7 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Mon, 10 Apr 2017 08:55:37 -0400 Subject: [PATCH 586/632] zos: implement uv_fs_event* functions This commit uses the Register File Interest feature on z/OS to enable users to monitor file system events. The poll call is used to check for file descriptors as well as a message queue that z/OS will report file system events on. The last item on the list used by poll will contain the message queue id instead of a file descriptor. Limitation: Writes to a directory (that is, file creation and deletion) do not generate a change message for a registered directory. PR-URL: https://github.com/libuv/libuv/pull/1311 Reviewed-By: Ben Noordhuis --- Makefile.am | 1 - docs/src/fs_event.rst | 6 ++ include/uv-os390.h | 3 + src/unix/os390-syscalls.c | 73 ++++++++++++++++++++-- src/unix/os390-syscalls.h | 1 + src/unix/os390.c | 128 +++++++++++++++++++++++++++++++++++++- test/task.h | 2 +- test/test-fork.c | 4 +- test/test-fs-event.c | 4 ++ test/test-spawn.c | 3 - uv.gyp | 1 - 11 files changed, 212 insertions(+), 14 deletions(-) diff --git a/Makefile.am b/Makefile.am index 128ac5661..2093ac23d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -458,7 +458,6 @@ libuv_la_CFLAGS += -D_UNIX03_THREADS \ -qFLOAT=IEEE libuv_la_LDFLAGS += -qXPLINK libuv_la_SOURCES += src/unix/pthread-fixes.c \ - src/unix/no-fsevents.c \ src/unix/os390.c \ src/unix/os390-syscalls.c \ src/unix/proctitle.c diff --git a/docs/src/fs_event.rst b/docs/src/fs_event.rst index 2af3e9802..bd076aaeb 100644 --- a/docs/src/fs_event.rst +++ b/docs/src/fs_event.rst @@ -19,7 +19,13 @@ the best backend for the job on each platform. See documentation_ for more details. + The z/OS file system events monitoring infrastructure does not notify of file + creation/deletion within a directory that is being monitored. + See the `IBM Knowledge centre`_ for more details. + .. _documentation: http://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/ + .. _`IBM Knowledge centre`: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.2.0/com.ibm.zos.v2r1.bpxb100/ioc.htm + diff --git a/include/uv-os390.h b/include/uv-os390.h index 58f926111..39e7384db 100644 --- a/include/uv-os390.h +++ b/include/uv-os390.h @@ -27,4 +27,7 @@ #define UV_PLATFORM_LOOP_FIELDS \ void* ep; \ +#define UV_PLATFORM_FS_EVENT_FIELDS \ + char rfis_rftok[8]; \ + #endif /* UV_MVS_H */ diff --git a/src/unix/os390-syscalls.c b/src/unix/os390-syscalls.c index 5bc489387..21558ea86 100644 --- a/src/unix/os390-syscalls.c +++ b/src/unix/os390-syscalls.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #define CW_CONDVAR 32 @@ -103,10 +105,19 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) { unsigned int newsize; unsigned int i; struct pollfd* newlst; + struct pollfd event; if (len <= lst->size) return; + if (lst->size == 0) + event.fd = -1; + else { + /* Extract the message queue at the end. */ + event = lst->items[lst->size - 1]; + lst->items[lst->size - 1].fd = -1; + } + newsize = next_power_of_two(len); newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0])); @@ -115,11 +126,40 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) { for (i = lst->size; i < newsize; ++i) newlst[i].fd = -1; + /* Restore the message queue at the end */ + newlst[newsize - 1] = event; + lst->items = newlst; lst->size = newsize; } +static void init_message_queue(uv__os390_epoll* lst) { + struct { + long int header; + char body; + } msg; + + /* initialize message queue */ + lst->msg_queue = msgget(IPC_PRIVATE, 0622 | IPC_CREAT); + if (lst->msg_queue == -1) + abort(); + + /* + On z/OS, the message queue will be affiliated with the process only + when a send is performed on it. Once this is done, the system + can be queried for all message queues belonging to our process id. + */ + msg.header = 1; + if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0) + abort(); + + /* Clean up the dummy message sent above */ + if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body)) + abort(); +} + + static void before_fork(void) { uv_mutex_lock(&global_epoll_lock); } @@ -139,8 +179,13 @@ static void child_fork(void) { /* reset epoll list */ while (!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); + uv__free(lst->items); + lst->items = NULL; + lst->size = 0; } uv_mutex_unlock(&global_epoll_lock); @@ -166,6 +211,10 @@ uv__os390_epoll* epoll_create1(int flags) { /* initialize list */ lst->size = 0; lst->items = NULL; + init_message_queue(lst); + maybe_resize(lst, 1); + lst->items[lst->size - 1].fd = lst->msg_queue; + lst->items[lst->size - 1].events = POLLIN; uv_once(&once, epoll_init); uv_mutex_lock(&global_epoll_lock); QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); @@ -182,15 +231,20 @@ int epoll_ctl(uv__os390_epoll* lst, struct epoll_event *event) { uv_mutex_lock(&global_epoll_lock); - if(op == EPOLL_CTL_DEL) { + if (op == EPOLL_CTL_DEL) { if (fd >= lst->size || lst->items[fd].fd == -1) { uv_mutex_unlock(&global_epoll_lock); errno = ENOENT; return -1; } lst->items[fd].fd = -1; - } else if(op == EPOLL_CTL_ADD) { - maybe_resize(lst, fd + 1); + } else if (op == EPOLL_CTL_ADD) { + + /* Resizing to 'fd + 1' would expand the list to contain at least + * 'fd'. But we need to guarantee that the last index on the list + * is reserved for the message queue. So specify 'fd + 2' instead. + */ + maybe_resize(lst, fd + 2); if (lst->items[fd].fd != -1) { uv_mutex_unlock(&global_epoll_lock); errno = EEXIST; @@ -198,7 +252,7 @@ int epoll_ctl(uv__os390_epoll* lst, } lst->items[fd].fd = fd; lst->items[fd].events = event->events; - } else if(op == EPOLL_CTL_MOD) { + } else if (op == EPOLL_CTL_MOD) { if (fd >= lst->size || lst->items[fd].fd == -1) { uv_mutex_unlock(&global_epoll_lock); errno = ENOENT; @@ -215,17 +269,19 @@ int epoll_ctl(uv__os390_epoll* lst, int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, int maxevents, int timeout) { - size_t size; + nmsgsfds_t size; struct pollfd* pfds; int pollret; int reventcount; - size = lst->size; + size = _SET_FDS_MSGS(size, 1, lst->size - 1); pfds = lst->items; pollret = poll(pfds, size, timeout); if (pollret <= 0) return pollret; + pollret = _NFDS(pollret) + _NMSGS(pollret); + reventcount = 0; for (int i = 0; i < lst->size && i < maxevents && reventcount < pollret; ++i) { @@ -261,9 +317,14 @@ 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_mutex_unlock(&global_epoll_lock); + + /* Free resources */ + msgctl(lst->msg_queue, IPC_RMID, NULL); + lst->msg_queue = -1; uv__free(lst->items); lst->items = NULL; } diff --git a/src/unix/os390-syscalls.h b/src/unix/os390-syscalls.h index 5ce6a681b..6e34a88cb 100644 --- a/src/unix/os390-syscalls.h +++ b/src/unix/os390-syscalls.h @@ -50,6 +50,7 @@ typedef struct { QUEUE member; struct pollfd* items; unsigned long size; + int msg_queue; } uv__os390_epoll; /* epoll api */ diff --git a/src/unix/os390.c b/src/unix/os390.c index 127656db8..081438e8e 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #if defined(__clang__) #include "csrsic.h" #else @@ -684,11 +686,124 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { return 0; } + +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; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, + const char* filename, unsigned int flags) { + uv__os390_epoll* ep; + _RFIS reg_struct; + char* path; + int rc; + + if (uv__is_active(handle)) + return -EINVAL; + + ep = handle->loop->ep; + assert(ep->msg_queue != -1); + + reg_struct.__rfis_cmd = _RFIS_REG; + reg_struct.__rfis_qid = ep->msg_queue; + reg_struct.__rfis_type = 1; + memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle)); + + path = uv__strdup(filename); + if (path == NULL) + return -ENOMEM; + + rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); + if (rc != 0) + return -errno; + + uv__handle_start(handle); + handle->path = path; + handle->cb = cb; + memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok, + sizeof(handle->rfis_rftok)); + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + uv__os390_epoll* ep; + _RFIS reg_struct; + int rc; + + if (!uv__is_active(handle)) + return 0; + + ep = handle->loop->ep; + assert(ep->msg_queue != -1); + + reg_struct.__rfis_cmd = _RFIS_UNREG; + reg_struct.__rfis_qid = ep->msg_queue; + reg_struct.__rfis_type = 1; + memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok, + sizeof(handle->rfis_rftok)); + + /* + * This call will take "/" as the path argument in case we + * don't care to supply the correct path. The system will simply + * ignore it. + */ + rc = __w_pioctl("/", _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); + if (rc != 0 && errno != EALREADY && errno != ENOENT) + abort(); + + uv__handle_stop(handle); + + return 0; +} + + +static int os390_message_queue_handler(uv__os390_epoll* ep) { + uv_fs_event_t* handle; + int msglen; + int events; + _RFIM msg; + + if (ep->msg_queue == -1) + return 0; + + msglen = msgrcv(ep->msg_queue, &msg, sizeof(msg), 0, IPC_NOWAIT); + + if (msglen == -1 && errno == ENOMSG) + return 0; + + if (msglen == -1) + abort(); + + events = 0; + if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE) + events = UV_CHANGE; + else if (msg.__rfim_event == _RFIM_RENAME) + events = UV_RENAME; + else + /* Some event that we are not interested in. */ + return 0; + + handle = *(uv_fs_event_t**)(msg.__rfim_utok); + handle->cb(handle, uv__basename_r(handle->path), events, 0); + return 1; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { static const int max_safe_timeout = 1789569; struct epoll_event events[1024]; struct epoll_event* pe; struct epoll_event e; + uv__os390_epoll* ep; int real_timeout; QUEUE* q; uv__io_t* w; @@ -802,6 +917,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (fd == -1) continue; + ep = loop->ep; + if (fd == ep->msg_queue) { + os390_message_queue_handler(ep); + continue; + } + assert(fd >= 0); assert((unsigned) fd < loop->nwatchers); @@ -866,7 +987,12 @@ void uv__set_process_title(const char* title) { } int uv__io_fork(uv_loop_t* loop) { - uv__platform_loop_delete(loop); + /* + Nullify the msg queue but don't close it because + it is still being used by the parent. + */ + loop->ep = NULL; + uv__platform_loop_delete(loop); return uv__platform_loop_init(loop); } diff --git a/test/task.h b/test/task.h index 67eb98049..af99d92fb 100644 --- a/test/task.h +++ b/test/task.h @@ -209,7 +209,7 @@ UNUSED static int can_ipv6(void) { return supported; } -#if defined(__MVS__) || defined(__CYGWIN__) || defined(__MSYS__) +#if defined(__CYGWIN__) || defined(__MSYS__) # define NO_FS_EVENTS "Filesystem watching not supported on this platform." #endif diff --git a/test/test-fork.c b/test/test-fork.c index ba85b5310..924c65b21 100644 --- a/test/test-fork.c +++ b/test/test-fork.c @@ -533,10 +533,12 @@ TEST_IMPL(fork_fs_events_file_parent_child) { #if defined(NO_FS_EVENTS) RETURN_SKIP(NO_FS_EVENTS); #endif -#if defined(__sun) || defined(_AIX) +#if defined(__sun) || defined(_AIX) || defined(__MVS__) /* It's not possible to implement this without additional * bookkeeping on SunOS. For AIX it is possible, but has to be * written. See https://github.com/libuv/libuv/pull/846#issuecomment-287170420 + * TODO: On z/OS, we need to open another message queue and subscribe to the + * same events as the parent. */ return 0; #else diff --git a/test/test-fs-event.c b/test/test-fs-event.c index fba6b5440..dc47b3a62 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -396,6 +396,8 @@ static void timer_cb_watch_twice(uv_timer_t* handle) { TEST_IMPL(fs_event_watch_dir) { #if defined(NO_FS_EVENTS) RETURN_SKIP(NO_FS_EVENTS); +#elif defined(__MVS__) + RETURN_SKIP("Directory watching not supported on this platform."); #endif uv_loop_t* loop = uv_default_loop(); @@ -820,6 +822,8 @@ static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, TEST_IMPL(fs_event_close_in_callback) { #if defined(NO_FS_EVENTS) RETURN_SKIP(NO_FS_EVENTS); +#elif defined(__MVS__) + RETURN_SKIP("Directory watching not supported on this platform."); #endif uv_loop_t* loop; int r; diff --git a/test/test-spawn.c b/test/test-spawn.c index 9a30f6cb5..4086ab15d 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -1562,9 +1562,6 @@ TEST_IMPL(spawn_fs_open) { #ifndef _WIN32 TEST_IMPL(closed_fd_events) { -#if defined(__MVS__) - RETURN_SKIP("Filesystem watching not supported on this platform."); -#endif uv_stdio_container_t stdio[3]; uv_pipe_t pipe_handle; int fd[2]; diff --git a/uv.gyp b/uv.gyp index dade2125c..fbb384a42 100644 --- a/uv.gyp +++ b/uv.gyp @@ -340,7 +340,6 @@ ['OS=="zos"', { 'sources': [ 'src/unix/pthread-fixes.c', - 'src/unix/no-fsevents.c', 'src/unix/os390.c', 'src/unix/os390-syscalls.c' ] From fd049399aa4ed8495928e375466970d98cb42e17 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 12 Feb 2013 16:53:37 -0500 Subject: [PATCH 587/632] unix,tcp: avoid marking server sockets connected It shouldn't be setting READABLE and WRITABLE on the socket server, since they aren't, and this could confuse the client. PR-URL: https://github.com/libuv/libuv/pull/1655 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- src/unix/stream.c | 6 ++++++ src/unix/tcp.c | 8 +++----- test/test-list.h | 2 ++ test/test-tcp-bind-error.c | 42 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 6fc0a01f5..bccfd20f8 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1411,6 +1411,9 @@ int uv_write2(uv_write_t* req, if (uv__stream_fd(stream) < 0) return -EBADF; + if (!(stream->flags & UV_STREAM_WRITABLE)) + return -EPIPE; + if (send_handle) { if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) return -EINVAL; @@ -1562,6 +1565,9 @@ int uv_read_start(uv_stream_t* stream, if (stream->flags & UV_CLOSING) return -EINVAL; + if (!(stream->flags & UV_STREAM_READABLE)) + return -ENOTCONN; + /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just * expresses the desired state of the user. */ diff --git a/src/unix/tcp.c b/src/unix/tcp.c index c7c8d21c6..a40378518 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -158,9 +158,7 @@ int uv__tcp_bind(uv_tcp_t* tcp, if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6) return -EINVAL; - err = maybe_new_socket(tcp, - addr->sa_family, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + err = maybe_new_socket(tcp, addr->sa_family, 0); if (err) return err; @@ -335,14 +333,14 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { if (single_accept) tcp->flags |= UV_TCP_SINGLE_ACCEPT; - flags = UV_STREAM_READABLE; + flags = 0; #if defined(__MVS__) /* on zOS the listen call does not bind automatically if the socket is unbound. Hence the manual binding to an arbitrary port is required to be done manually */ flags |= UV_HANDLE_BOUND; -#endif +#endif err = maybe_new_socket(tcp, AF_INET, flags); if (err) return err; diff --git a/test/test-list.h b/test/test-list.h index 892a00196..c1a17803e 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -93,6 +93,7 @@ TEST_DECLARE (tcp_bind_error_fault) 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_listen_without_bind) TEST_DECLARE (tcp_connect_error_fault) TEST_DECLARE (tcp_connect_timeout) @@ -530,6 +531,7 @@ TASK_LIST_START TEST_ENTRY (tcp_bind_error_inval) TEST_ENTRY (tcp_bind_localhost_ok) TEST_ENTRY (tcp_bind_invalid_flags) + TEST_ENTRY (tcp_bind_writable_flags) TEST_ENTRY (tcp_listen_without_bind) TEST_ENTRY (tcp_connect_error_fault) TEST_ENTRY (tcp_connect_timeout) diff --git a/test/test-tcp-bind-error.c b/test/test-tcp-bind-error.c index 10ed68e10..1456d081a 100644 --- a/test/test-tcp-bind-error.c +++ b/test/test-tcp-bind-error.c @@ -214,3 +214,45 @@ TEST_IMPL(tcp_listen_without_bind) { MAKE_VALGRIND_HAPPY(); return 0; } + + +TEST_IMPL(tcp_bind_writable_flags) { + struct sockaddr_in addr; + uv_tcp_t server; + uv_buf_t buf; + uv_write_t write_req; + uv_shutdown_t shutdown_req; + int r; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + r = uv_listen((uv_stream_t*)&server, 128, NULL); + ASSERT(r == 0); + + ASSERT(0 == uv_is_writable((uv_stream_t*) &server)); + ASSERT(0 == 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); + r = uv_shutdown(&shutdown_req, (uv_stream_t*) &server, NULL); +#ifdef _WIN32 + ASSERT(r == UV_EPIPE); +#else + ASSERT(r == UV_ENOTCONN); +#endif + r = uv_read_start((uv_stream_t*) &server, NULL, NULL); + ASSERT(r == UV_ENOTCONN); + + uv_close((uv_handle_t*)&server, close_cb); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} From cde132631b5da7368e7fb0d62d7b9e3b30e81a83 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Thu, 28 Dec 2017 10:22:04 +0100 Subject: [PATCH 588/632] doc: mark Windows 7 as Tier 1 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1682 Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- SUPPORTED_PLATFORMS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index 08fd5f4a9..c56913bbc 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -4,7 +4,7 @@ |---|---|---|---| | GNU/Linux | Tier 1 | Linux >= 2.6.32 with glibc >= 2.12 | | | macOS | Tier 1 | macOS >= 10.7 | | -| Windows | Tier 1 | Windows >= 8.1 | MSVC 2008 and later are supported | +| Windows | Tier 1 | >= Windows 7 | MSVC 2008 and later are supported | | FreeBSD | Tier 1 | >= 9 (see note) | | | AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix | | z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos | From 2b32e77bb6f41e2786168ec0f32d1f0fcc78071b Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Thu, 28 Dec 2017 10:42:11 +0100 Subject: [PATCH 589/632] win: map 0.0.0.0 and :: addresses to localhost On Linux when connecting IP addresses 0.0.0.0 and :: are automatically converted to localhost. This adds same functionality to Windows. PR-URL: https://github.com/libuv/libuv/pull/1515 Reviewed-By: Ben Noordhuis --- Makefile.am | 1 + docs/src/tcp.rst | 7 ++++ docs/src/udp.rst | 7 ++++ src/win/tcp.c | 17 +++++---- src/win/udp.c | 7 +++- src/win/winsock.c | 28 +++++++++++++++ src/win/winsock.h | 3 ++ test/test-connect-unspecified.c | 61 +++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ uv.gyp | 1 + 10 files changed, 127 insertions(+), 7 deletions(-) create mode 100644 test/test-connect-unspecified.c diff --git a/Makefile.am b/Makefile.am index 2093ac23d..68dd8ae39 100644 --- a/Makefile.am +++ b/Makefile.am @@ -159,6 +159,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-close-fd.c \ test/test-close-order.c \ test/test-condvar.c \ + test/test-connect-unspecified.c \ test/test-connection-fail.c \ test/test-cwd-and-chdir.c \ test/test-default-loop-close.c \ diff --git a/docs/src/tcp.rst b/docs/src/tcp.rst index a1a582456..e761b460d 100644 --- a/docs/src/tcp.rst +++ b/docs/src/tcp.rst @@ -102,7 +102,14 @@ API and an uninitialized :c:type:`uv_connect_t`. `addr` should point to an initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``. + On Windows if the `addr` is initialized to point to an unspecified address + (``0.0.0.0`` or ``::``) it will be changed to point to ``localhost``. + This is done to match the behavior of Linux systems. + The callback is made when the connection has been established or when a connection error happened. + .. versionchanged:: 1.19.0 added ``0.0.0.0`` and ``::`` to ``localhost`` + mapping + .. seealso:: The :c:type:`uv_stream_t` API functions also apply. diff --git a/docs/src/udp.rst b/docs/src/udp.rst index 8704a099a..814882852 100644 --- a/docs/src/udp.rst +++ b/docs/src/udp.rst @@ -243,6 +243,10 @@ API with :c:func:`uv_udp_bind` it will be bound to 0.0.0.0 (the "all interfaces" IPv4 address) and a random port number. + On Windows if the `addr` is initialized to point to an unspecified address + (``0.0.0.0`` or ``::``) it will be changed to point to ``localhost``. + This is done to match the behavior of Linux systems. + :param req: UDP request handle. Need not be initialized. :param handle: UDP handle. Should have been initialized with @@ -259,6 +263,9 @@ API :returns: 0 on success, or an error code < 0 on failure. + .. versionchanged:: 1.19.0 added ``0.0.0.0`` and ``::`` to ``localhost`` + mapping + .. c:function:: int uv_udp_try_send(uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr) Same as :c:func:`uv_udp_send`, but won't queue a send request if it can't diff --git a/src/win/tcp.c b/src/win/tcp.c index e63a63e77..fd6efbaf8 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -747,10 +747,15 @@ static int uv_tcp_try_connect(uv_connect_t* req, uv_connect_cb cb) { uv_loop_t* loop = handle->loop; const struct sockaddr* bind_addr; + struct sockaddr_storage converted; BOOL success; DWORD bytes; int err; + err = uv__convert_to_localhost_if_unspecified(addr, &converted); + if (err) + return err; + if (handle->delayed_error) { return handle->delayed_error; } @@ -782,12 +787,12 @@ static int uv_tcp_try_connect(uv_connect_t* req, memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); success = handle->tcp.conn.func_connectex(handle->socket, - addr, - addrlen, - NULL, - 0, - &bytes, - &req->u.io.overlapped); + (const struct sockaddr*) &converted, + addrlen, + NULL, + 0, + &bytes, + &req->u.io.overlapped); if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { /* Process the req without IOCP. */ diff --git a/src/win/udp.c b/src/win/udp.c index 21348f379..cd1d0e07b 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -923,10 +923,15 @@ int uv__udp_try_send(uv_udp_t* handle, unsigned int addrlen) { DWORD bytes; const struct sockaddr* bind_addr; + struct sockaddr_storage converted; int err; assert(nbufs > 0); + err = uv__convert_to_localhost_if_unspecified(addr, &converted); + if (err) + return err; + /* Already sending a message.*/ if (handle->send_queue_count != 0) return UV_EAGAIN; @@ -948,7 +953,7 @@ int uv__udp_try_send(uv_udp_t* handle, nbufs, &bytes, 0, - addr, + (const struct sockaddr*) &converted, addrlen, NULL, NULL); diff --git a/src/win/winsock.c b/src/win/winsock.c index e86d76b13..7cfa90f8a 100644 --- a/src/win/winsock.c +++ b/src/win/winsock.c @@ -559,3 +559,31 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, return SOCKET_ERROR; } } + +int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr, + struct sockaddr_storage* storage) { + struct sockaddr_in* dest4; + struct sockaddr_in6* dest6; + + if (addr == NULL) + return UV_EINVAL; + + switch (addr->sa_family) { + case AF_INET: + dest4 = (struct sockaddr_in*) storage; + memcpy(dest4, addr, sizeof(*dest4)); + if (dest4->sin_addr.s_addr == 0) + dest4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + return 0; + case AF_INET6: + dest6 = (struct sockaddr_in6*) storage; + memcpy(dest6, addr, sizeof(*dest6)); + if (memcmp(&dest6->sin6_addr, + &uv_addr_ip6_any_.sin6_addr, + sizeof(uv_addr_ip6_any_.sin6_addr)) == 0) + dest6->sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT; + return 0; + default: + return UV_EINVAL; + } +} diff --git a/src/win/winsock.h b/src/win/winsock.h index 7c007ab49..7ecb755bf 100644 --- a/src/win/winsock.h +++ b/src/win/winsock.h @@ -187,4 +187,7 @@ typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH { #endif +int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr, + struct sockaddr_storage* storage); + #endif /* UV_WIN_WINSOCK_H_ */ diff --git a/test/test-connect-unspecified.c b/test/test-connect-unspecified.c new file mode 100644 index 000000000..04e1c8a5f --- /dev/null +++ b/test/test-connect-unspecified.c @@ -0,0 +1,61 @@ +/* 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" + +static void connect_4(uv_connect_t* req, int status) { + ASSERT(status != UV_EADDRNOTAVAIL); +} + +static void connect_6(uv_connect_t* req, int status) { + ASSERT(status != UV_EADDRNOTAVAIL); +} + +TEST_IMPL(connect_unspecified) { + uv_loop_t* loop; + uv_tcp_t socket4; + struct sockaddr_in addr4; + uv_connect_t connect4; + uv_tcp_t socket6; + struct sockaddr_in6 addr6; + uv_connect_t connect6; + + 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(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(uv_run(loop, UV_RUN_DEFAULT) == 0); + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index c1a17803e..6af1b64fe 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -55,6 +55,7 @@ TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) TEST_DECLARE (stdio_over_pipes) TEST_DECLARE (ip6_pton) +TEST_DECLARE (connect_unspecified) TEST_DECLARE (ipc_listen_before_write) TEST_DECLARE (ipc_listen_after_write) #ifndef _WIN32 @@ -468,6 +469,7 @@ TASK_LIST_START TEST_ENTRY (tty_pty) TEST_ENTRY (stdio_over_pipes) TEST_ENTRY (ip6_pton) + TEST_ENTRY (connect_unspecified) TEST_ENTRY (ipc_listen_before_write) TEST_ENTRY (ipc_listen_after_write) #ifndef _WIN32 diff --git a/uv.gyp b/uv.gyp index fbb384a42..46606c5bd 100644 --- a/uv.gyp +++ b/uv.gyp @@ -366,6 +366,7 @@ 'test/test-callback-order.c', 'test/test-close-fd.c', 'test/test-close-order.c', + 'test/test-connect-unspecified.c', 'test/test-connection-fail.c', 'test/test-cwd-and-chdir.c', 'test/test-default-loop-close.c', From 8156f15e8282e9efe7e3595a5380e5eca3253a65 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 18 Dec 2017 22:57:33 +0100 Subject: [PATCH 590/632] build: install libuv.pc unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was requested and I can't see a reason not to. Fixes: https://github.com/libuv/libuv/issues/1684 PR-URL: https://github.com/libuv/libuv/pull/1685 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 2 -- configure.ac | 7 +------ 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/Makefile.am b/Makefile.am index 68dd8ae39..ae9d96bcf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -464,7 +464,5 @@ libuv_la_SOURCES += src/unix/pthread-fixes.c \ src/unix/proctitle.c endif -if HAVE_PKG_CONFIG pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = @PACKAGE_NAME@.pc -endif diff --git a/configure.ac b/configure.ac index 7eb1674db..ecc45881d 100644 --- a/configure.ac +++ b/configure.ac @@ -68,10 +68,5 @@ AS_CASE([$host_os],[mingw*], [ ]) AS_CASE([$host_os], [netbsd*], [AC_CHECK_LIB([kvm], [kvm_open])]) AC_CHECK_HEADERS([sys/ahafs_evProds.h]) -AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes) -AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" != "x"]) -AS_IF([test "x$PKG_CONFIG" != "x"], [ - AC_CONFIG_FILES([libuv.pc]) -]) -AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([Makefile libuv.pc]) AC_OUTPUT From 6ecd79eb6e113869169cad5211406e8c57df1fd7 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 18 Dec 2017 00:53:31 +0100 Subject: [PATCH 591/632] test: remove custom timeout for thread test on ppc The two minute timeout should not be necessary anymore after commit aeaff5f0 ("test: lower number of tasks in threadpool test".) PR-URL: https://github.com/libuv/libuv/pull/1681 Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil --- test/test-list.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/test-list.h b/test/test-list.h index 6af1b64fe..a008b0390 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -857,14 +857,7 @@ TASK_LIST_START TEST_ENTRY (get_osfhandle_valid_handle) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (threadpool_queue_work_einval) -#if defined(__PPC__) || defined(__PPC64__) /* For linux PPC and AIX */ - /* pthread_join takes a while, especially on AIX. - * Therefore being gratuitous with timeout. - */ - TEST_ENTRY_CUSTOM (threadpool_multiple_event_loops, 0, 0, 120000) -#else TEST_ENTRY (threadpool_multiple_event_loops) -#endif TEST_ENTRY (threadpool_cancel_getaddrinfo) TEST_ENTRY (threadpool_cancel_getnameinfo) TEST_ENTRY (threadpool_cancel_work) From 3ad4dfad0cb47703b91fcea0b61b734d1dedee7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Fri, 29 Dec 2017 12:26:33 +0100 Subject: [PATCH 592/632] test: allow multicast not permitted status PR-URL: https://github.com/libuv/libuv/pull/1689 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- test/test-udp-multicast-interface.c | 2 +- test/test-udp-multicast-ttl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-udp-multicast-interface.c b/test/test-udp-multicast-interface.c index 71001a77e..0b3c0e62d 100644 --- a/test/test-udp-multicast-interface.c +++ b/test/test-udp-multicast-interface.c @@ -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(req != NULL); - ASSERT(status == 0 || status == UV_ENETUNREACH); + ASSERT(status == 0 || status == UV_ENETUNREACH || status == UV_EPERM); CHECK_HANDLE(req->handle); sv_send_cb_called++; diff --git a/test/test-udp-multicast-ttl.c b/test/test-udp-multicast-ttl.c index 7f1af9b9d..e92608be4 100644 --- a/test/test-udp-multicast-ttl.c +++ b/test/test-udp-multicast-ttl.c @@ -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(req != NULL); - ASSERT(status == 0 || status == UV_ENETUNREACH); + ASSERT(status == 0 || status == UV_ENETUNREACH || status == UV_EPERM); CHECK_HANDLE(req->handle); sv_send_cb_called++; From a468257e5dd38953988d6ff6c7ab043585aad155 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 9 Jan 2018 14:37:42 +0100 Subject: [PATCH 593/632] test: allow net unreachable status in udp test Since the destination address may not be routable, UV_ENETUNREACH is an error that can happen and should be handled. Fixes: https://github.com/libuv/libuv/issues/1680 PR-URL: https://github.com/libuv/libuv/pull/1695 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- 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 6253ff7a4..bf4dfebfb 100644 --- a/test/test-udp-send-hang-loop.c +++ b/test/test-udp-send-hang-loop.c @@ -67,7 +67,7 @@ static void idle_cb(uv_idle_t* handle) { static void send_cb(uv_udp_send_t* req, int status) { ASSERT(req != NULL); - ASSERT(status == 0); + ASSERT(status == 0 || status == UV_ENETUNREACH); CHECK_OBJECT(req->handle, uv_udp_t, client); CHECK_OBJECT(req, uv_udp_send_t, send_req); req->handle = NULL; From 52b8b9a8b92c88c06669b58dbe016efb94f192de Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 9 Jan 2018 10:36:51 -0500 Subject: [PATCH 594/632] unix: use SA_RESTART when setting our sighandler BSD `signal(2)` semantics make some system calls (e.g. for `write`) restartable when interrupted by a signal handler. Use `SA_RESTART` to enable these semantics everywhere that supports them. This was done by libev back when we used it. In addition to being common practice, this is required by C++ stream libraries that interpret `EINTR` as any other error, set `badbit`, and stop writing. I've observed this with `libstdc++` during a `std::cout.flush()` call interrupted by `SIGCHLD`. PR-URL: https://github.com/libuv/libuv/pull/1696 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- src/unix/signal.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/unix/signal.c b/src/unix/signal.c index cb09ead50..375977801 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -28,6 +28,9 @@ #include #include +#ifndef SA_RESTART +# define SA_RESTART 0 +#endif typedef struct { uv_signal_t* handle; @@ -216,7 +219,9 @@ static int uv__signal_register_handler(int signum, int oneshot) { if (sigfillset(&sa.sa_mask)) abort(); sa.sa_handler = uv__signal_handler; - sa.sa_flags = oneshot ? SA_RESETHAND : 0; + sa.sa_flags = SA_RESTART; + if (oneshot) + sa.sa_flags |= SA_RESETHAND; /* XXX save old action so we can restore it later on? */ if (sigaction(signum, &sa, NULL)) From 14bfc27e641aff178c431083c0c0eada4d6f02dd Mon Sep 17 00:00:00 2001 From: Ben Wijen Date: Fri, 22 Jan 2016 19:35:46 +0100 Subject: [PATCH 595/632] unix,fs: fix for potential partial reads/writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a check in uv__fs_buf_iter to detect partial reads and writes. Partial reads and writes are looped until all data has been processed. PR-URL: https://github.com/libuv/libuv/pull/640 Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 1 - src/unix/fs.c | 62 ++++++------------ test/test-eintr-handling.c | 94 --------------------------- test/test-fs.c | 127 ++++++++++++++++++++++++++++++++++++- test/test-list.h | 6 +- uv.gyp | 1 - 6 files changed, 150 insertions(+), 141 deletions(-) delete mode 100644 test/test-eintr-handling.c diff --git a/Makefile.am b/Makefile.am index ae9d96bcf..c49802f7f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -165,7 +165,6 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-default-loop-close.c \ test/test-delayed-accept.c \ test/test-dlerror.c \ - test/test-eintr-handling.c \ test/test-embed.c \ test/test-emfile.c \ test/test-env-vars.c \ diff --git a/src/unix/fs.c b/src/unix/fs.c index e0969a4c2..798646380 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -334,25 +334,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) { if (no_preadv) retry: # endif { - off_t nread; - size_t index; - - nread = 0; - index = 0; - result = 1; - do { - if (req->bufs[index].len > 0) { - result = pread(req->file, - req->bufs[index].base, - req->bufs[index].len, - req->off + nread); - if (result > 0) - nread += result; - } - index++; - } while (index < req->nbufs && result > 0); - if (nread > 0) - result = nread; + result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off); } # if defined(__linux__) else { @@ -740,25 +722,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) { if (no_pwritev) retry: # endif { - off_t written; - size_t index; - - written = 0; - index = 0; - r = 0; - do { - if (req->bufs[index].len > 0) { - r = pwrite(req->file, - req->bufs[index].base, - req->bufs[index].len, - req->off + written); - if (r > 0) - written += r; - } - index++; - } while (index < req->nbufs && r >= 0); - if (written > 0) - r = written; + r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off); } # if defined(__linux__) else { @@ -1008,6 +972,19 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) { return ret; } +static size_t uv__fs_buf_offset(uv_buf_t* bufs, size_t size) { + size_t offset; + /* Figure out which bufs are done */ + for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset) + size -= bufs[offset].len; + + /* Fix a partial read/write */ + if (size > 0) { + bufs[offset].base += size; + bufs[offset].len -= size; + } + return offset; +} typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req); static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) { @@ -1027,7 +1004,10 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) if (req->nbufs > iovmax) req->nbufs = iovmax; - result = process(req); + do + result = process(req); + while (result < 0 && errno == EINTR); + if (result <= 0) { if (total == 0) total = result; @@ -1037,14 +1017,12 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) if (req->off >= 0) req->off += result; + req->nbufs = uv__fs_buf_offset(req->bufs, result); req->bufs += req->nbufs; nbufs -= req->nbufs; total += result; } - if (errno == EINTR && total == -1) - return total; - if (bufs != req->bufsml) uv__free(bufs); diff --git a/test/test-eintr-handling.c b/test/test-eintr-handling.c deleted file mode 100644 index 1aaf623b7..000000000 --- a/test/test-eintr-handling.c +++ /dev/null @@ -1,94 +0,0 @@ -/* 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(eintr_handling) { - RETURN_SKIP("Test not implemented on Windows."); -} - -#else /* !_WIN32 */ - -#include -#include - -static uv_loop_t* loop; -static uv_fs_t read_req; -static uv_buf_t iov; - -static char buf[32]; -static char test_buf[] = "test-buffer\n"; -int pipe_fds[2]; - -struct thread_ctx { - uv_barrier_t barrier; - int fd; -}; - -static void thread_main(void* arg) { - int nwritten; - ASSERT(0 == kill(getpid(), SIGUSR1)); - - do - nwritten = write(pipe_fds[1], test_buf, sizeof(test_buf)); - while (nwritten == -1 && errno == EINTR); - - ASSERT(nwritten == sizeof(test_buf)); -} - -static void sig_func(uv_signal_t* handle, int signum) { - uv_signal_stop(handle); -} - -TEST_IMPL(eintr_handling) { - struct thread_ctx ctx; - uv_thread_t thread; - uv_signal_t signal; - int nread; - - 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(0 == pipe(pipe_fds)); - ASSERT(0 == 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(0 == uv_run(loop, UV_RUN_DEFAULT)); - - ASSERT(0 == close(pipe_fds[0])); - ASSERT(0 == close(pipe_fds[1])); - uv_close((uv_handle_t*) &signal, NULL); - - MAKE_VALGRIND_HAPPY(); - return 0; -} - -#endif /* !_WIN32 */ diff --git a/test/test-fs.c b/test/test-fs.c index cae02dd1f..fc568dc22 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2865,6 +2865,131 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) { } +#ifdef _WIN32 + +TEST_IMPL(fs_partial_read) { + RETURN_SKIP("Test not implemented on Windows."); +} + +TEST_IMPL(fs_partial_write) { + RETURN_SKIP("Test not implemented on Windows."); +} + +#else /* !_WIN32 */ + +static void thread_exec(int fd, char* data, int size, int interval, int doread) { + pid_t pid; + ssize_t result; + + pid = getpid(); + result = 1; + + while (size > 0 && result > 0) { + do { + if (doread) + result = write(fd, data, size < interval ? size : interval); + else + result = read(fd, data, size < interval ? size : interval); + } while (result == -1 && errno == EINTR); + + kill(pid, SIGUSR1); + size -= result; + data += result; + } + + ASSERT(size == 0); + ASSERT(result > 0); +} + +struct thread_ctx { + int fd; + char *data; + int size; + int interval; + int doread; +}; + +static void thread_main(void* arg) { + struct thread_ctx *ctx; + ctx = (struct thread_ctx*)arg; + thread_exec(ctx->fd, ctx->data, ctx->size, ctx->interval, ctx->doread); +} + +static void sig_func(uv_signal_t* handle, int signum) { + uv_signal_stop(handle); +} + +static void test_fs_partial(int doread) { + struct thread_ctx ctx; + uv_thread_t thread; + uv_signal_t signal; + int pipe_fds[2]; + size_t iovcount; + uv_buf_t* iovs; + char* buffer; + size_t index; + int result; + + iovcount = 54321; + + iovs = malloc(sizeof(*iovs) * iovcount); + ASSERT(iovs != NULL); + + ctx.doread = doread; + ctx.interval = 1000; + ctx.size = sizeof(test_buf) * iovcount; + ctx.data = malloc(ctx.size); + ASSERT(ctx.data != NULL); + buffer = malloc(ctx.size); + ASSERT(buffer != NULL); + + for (index = 0; index < iovcount; ++index) + iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf), sizeof(test_buf)); + + loop = uv_default_loop(); + + ASSERT(0 == uv_signal_init(loop, &signal)); + ASSERT(0 == uv_signal_start(&signal, sig_func, SIGUSR1)); + + ASSERT(0 == pipe(pipe_fds)); + + ctx.fd = pipe_fds[doread]; + ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); + + if (doread) + result = uv_fs_read(loop, &read_req, pipe_fds[0], iovs, iovcount, -1, NULL); + else + result = uv_fs_write(loop, &write_req, pipe_fds[1], iovs, iovcount, -1, NULL); + + ASSERT(result == ctx.size); + ASSERT(0 == memcmp(buffer, ctx.data, result)); + + ASSERT(0 == uv_thread_join(&thread)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(0 == close(pipe_fds[0])); + ASSERT(0 == close(pipe_fds[1])); + uv_close((uv_handle_t*) &signal, NULL); + + free(iovs); + free(buffer); + free(ctx.data); + + MAKE_VALGRIND_HAPPY(); +} + +TEST_IMPL(fs_partial_read) { + test_fs_partial(1); + return 0; +} + +TEST_IMPL(fs_partial_write) { + test_fs_partial(0); + return 0; +} + +#endif/* _WIN32 */ + TEST_IMPL(fs_read_write_null_arguments) { int r; @@ -3073,7 +3198,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) { unlink("test_file"); ASSERT(UV_FS_O_EXLOCK > 0); - + r = uv_fs_open(NULL, &open_req1, "test_file", diff --git a/test/test-list.h b/test/test-list.h index a008b0390..ea3692c77 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -214,7 +214,6 @@ TEST_DECLARE (active) TEST_DECLARE (embed) TEST_DECLARE (async) TEST_DECLARE (async_null_cb) -TEST_DECLARE (eintr_handling) TEST_DECLARE (get_currentexe) TEST_DECLARE (process_title) TEST_DECLARE (process_title_threadsafe) @@ -325,6 +324,8 @@ TEST_DECLARE (fs_read_write_null_arguments) TEST_DECLARE (get_osfhandle_valid_handle) TEST_DECLARE (fs_write_alotof_bufs) TEST_DECLARE (fs_write_alotof_bufs_with_offset) +TEST_DECLARE (fs_partial_read) +TEST_DECLARE (fs_partial_write) TEST_DECLARE (fs_file_pos_after_op_with_offset) TEST_DECLARE (fs_null_req) #ifdef _WIN32 @@ -675,7 +676,6 @@ TASK_LIST_START TEST_ENTRY (async) TEST_ENTRY (async_null_cb) - TEST_ENTRY (eintr_handling) TEST_ENTRY (get_currentexe) @@ -848,6 +848,8 @@ TASK_LIST_START TEST_ENTRY (fs_write_multiple_bufs) TEST_ENTRY (fs_write_alotof_bufs) TEST_ENTRY (fs_write_alotof_bufs_with_offset) + TEST_ENTRY (fs_partial_read) + TEST_ENTRY (fs_partial_write) TEST_ENTRY (fs_read_write_null_arguments) TEST_ENTRY (fs_file_pos_after_op_with_offset) TEST_ENTRY (fs_null_req) diff --git a/uv.gyp b/uv.gyp index 46606c5bd..19008dfa8 100644 --- a/uv.gyp +++ b/uv.gyp @@ -371,7 +371,6 @@ 'test/test-cwd-and-chdir.c', 'test/test-default-loop-close.c', 'test/test-delayed-accept.c', - 'test/test-eintr-handling.c', 'test/test-error.c', 'test/test-embed.c', 'test/test-emfile.c', From 685059bf795543d8726346b761e6ad3273ac1fc7 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Mon, 15 Jan 2018 23:05:09 -0800 Subject: [PATCH 596/632] win,build: do not build executable installer for dll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/1707 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé --- appveyor.yml | 7 ----- libuv.nsi | 86 ---------------------------------------------------- 2 files changed, 93 deletions(-) delete mode 100644 libuv.nsi diff --git a/appveyor.yml b/appveyor.yml index f77e640eb..1b018a59c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,12 +28,5 @@ build_script: - cmd: set ARCH=%platform% - cmd: vcbuild.bat release %ARCH% shared -after_build: - - '"%PROGRAMFILES(x86)%\NSIS\makensis" /DVERSION=%APPVEYOR_BUILD_VERSION% /DARCH=%ARCH% libuv.nsi' - -artifacts: - - name: Installer - path: 'libuv-*.exe' - cache: - C:\projects\libuv\build\gyp diff --git a/libuv.nsi b/libuv.nsi deleted file mode 100644 index 159756e19..000000000 --- a/libuv.nsi +++ /dev/null @@ -1,86 +0,0 @@ -; NSIS installer script for libuv - -!include "MUI2.nsh" - -Name "libuv" -OutFile "libuv-${ARCH}-${VERSION}.exe" - -!include "x64.nsh" -# Default install location, for 32-bit files -InstallDir "$PROGRAMFILES\libuv" - -# Override install and registry locations if this is a 64-bit install. -function .onInit - ${If} ${ARCH} == "x64" - SetRegView 64 - StrCpy $INSTDIR "$PROGRAMFILES64\libuv" - ${EndIf} -functionEnd - -;-------------------------------- -; Installer pages -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES -!insertmacro MUI_PAGE_FINISH - - -;-------------------------------- -; Uninstaller pages -!insertmacro MUI_UNPAGE_WELCOME -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES -!insertmacro MUI_UNPAGE_FINISH - -;-------------------------------- -; Languages -!insertmacro MUI_LANGUAGE "English" - -;-------------------------------- -; Installer sections - -Section "Files" SecInstall - SectionIn RO - SetOutPath "$INSTDIR" - File "Release\*.dll" - File "Release\*.lib" - File "LICENSE" - File "README.md" - - SetOutPath "$INSTDIR\include" - File "include\uv.h" - File "include\uv-errno.h" - File "include\uv-threadpool.h" - File "include\uv-version.h" - File "include\uv-win.h" - File "include\tree.h" - - WriteUninstaller "$INSTDIR\Uninstall.exe" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "DisplayName" "libuv-${ARCH}-${VERSION}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "HelpLink" "http://libuv.org/" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "URLInfoAbout" "http://libuv.org/" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "DisplayVersion" "${VERSION}" - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "NoModify" "1" - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "NoRepair" "1" -SectionEnd - -Section "Uninstall" - Delete "$INSTDIR\libuv.dll" - Delete "$INSTDIR\libuv.lib" - Delete "$INSTDIR\LICENSE" - Delete "$INSTDIR\README.md" - - Delete "$INSTDIR\include\uv.h" - Delete "$INSTDIR\include\uv-errno.h" - Delete "$INSTDIR\include\uv-threadpool.h" - Delete "$INSTDIR\include\uv-version.h" - Delete "$INSTDIR\include\uv-win.h" - Delete "$INSTDIR\include\tree.h" - - Delete "$INSTDIR\Uninstall.exe" - RMDir "$INSTDIR" - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" -SectionEnd - From dcd9b3cb27c543ae7166d973d51b09c02d69d67b Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Mon, 15 Jan 2018 19:22:56 -0800 Subject: [PATCH 597/632] win: allow directory symlinks to be created in a non-elevated context PR-URL: https://github.com/libuv/libuv/pull/1706 Reviewed-By: Colin Ihrig --- src/win/fs.c | 2 +- test/test-fs.c | 17 ++++++++++++++--- test/test-list.h | 2 ++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 11c7c13ed..097b00e08 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -1785,7 +1785,7 @@ static void fs__symlink(uv_fs_t* req) { } if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR) - flags = SYMBOLIC_LINK_FLAG_DIRECTORY; + flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag; else flags = uv__file_symlink_usermode_flag; diff --git a/test/test-fs.c b/test/test-fs.c index fc568dc22..11268c156 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1861,7 +1861,7 @@ TEST_IMPL(fs_symlink) { } -TEST_IMPL(fs_symlink_dir) { +int test_symlink_dir_impl(int type) { uv_fs_t req; int r; char* test_dir; @@ -1895,8 +1895,12 @@ TEST_IMPL(fs_symlink_dir) { test_dir = "test_dir"; #endif - r = uv_fs_symlink(NULL, &req, test_dir, "test_dir_symlink", - UV_FS_SYMLINK_JUNCTION, NULL); + r = uv_fs_symlink(NULL, &req, test_dir, "test_dir_symlink", type, NULL); + if (type == UV_FS_SYMLINK_DIR && (r == UV_ENOTSUP || r == UV_EPERM)) { + uv_fs_req_cleanup(&req); + RETURN_SKIP("this version of Windows doesn't support unprivileged " + "creation of directory symlinks"); + } fprintf(stderr, "r == %i\n", r); ASSERT(r == 0); ASSERT(req.result == 0); @@ -2005,6 +2009,13 @@ TEST_IMPL(fs_symlink_dir) { return 0; } +TEST_IMPL(fs_symlink_dir) { + return test_symlink_dir_impl(UV_FS_SYMLINK_DIR); +} + +TEST_IMPL(fs_symlink_junction) { + return test_symlink_dir_impl(UV_FS_SYMLINK_JUNCTION); +} #ifdef _WIN32 TEST_IMPL(fs_non_symlink_reparse_point) { diff --git a/test/test-list.h b/test/test-list.h index ea3692c77..d23cf8660 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -289,6 +289,7 @@ TEST_DECLARE (fs_realpath) TEST_DECLARE (fs_symlink) TEST_DECLARE (fs_symlink_dir) #ifdef _WIN32 +TEST_DECLARE (fs_symlink_junction) TEST_DECLARE (fs_non_symlink_reparse_point) #endif TEST_DECLARE (fs_utime) @@ -817,6 +818,7 @@ TASK_LIST_START TEST_ENTRY (fs_symlink) TEST_ENTRY (fs_symlink_dir) #ifdef _WIN32 + TEST_ENTRY (fs_symlink_junction) TEST_ENTRY (fs_non_symlink_reparse_point) #endif TEST_ENTRY (fs_stat_missing_path) From 634bcc316451629066fa36bacb97154cb342fb0e Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 17 Jan 2018 00:34:52 -0500 Subject: [PATCH 598/632] zos,test: accept SIGKILL for flaky test Sending a SIGTERM to a process that is still starting up kills it with SIGKILL instead of SIGTERM. PR-URL: https://github.com/libuv/libuv/pull/1709 Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Santiago Gimeno Reviewed-By: Ben Noordhuis --- 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 4086ab15d..4a2869a18 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -92,7 +92,7 @@ static void kill_cb(uv_process_t* process, #else ASSERT(exit_status == 0); #endif -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__MVS__) /* * At least starting with Darwin Kernel Version 16.4.0, sending a SIGTERM to a * process that is still starting up kills it with SIGKILL instead of SIGTERM. From 15f29dc08fe72cd189002f1b8ae22fd82264deef Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 12 Jan 2018 12:42:44 +0100 Subject: [PATCH 599/632] win: use RemoveDirectoryW() instead of _wmrmdir() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use RemoveDirectoryW() and remap ERROR_DIRECTORY from UV_ENOENT to UV_ENOTDIR so that attempted removal of a non-directory produces the right (and legible) error message. Fixes: https://github.com/nodejs/node/issues/18014 PR-URL: https://github.com/libuv/libuv/pull/1698 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/win/error.c | 2 +- src/win/fs.c | 7 +++++-- test/test-fs.c | 22 ++++++++++++++++++---- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/win/error.c b/src/win/error.c index 9b03bfef6..1ec3d6e27 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -131,7 +131,7 @@ int uv_translate_sys_error(int sys_errno) { case WSAENETUNREACH: return UV_ENETUNREACH; case WSAENOBUFS: return UV_ENOBUFS; case ERROR_BAD_PATHNAME: return UV_ENOENT; - case ERROR_DIRECTORY: return UV_ENOENT; + case ERROR_DIRECTORY: return UV_ENOTDIR; case ERROR_FILE_NOT_FOUND: return UV_ENOENT; case ERROR_INVALID_NAME: return UV_ENOENT; case ERROR_INVALID_DRIVE: return UV_ENOENT; diff --git a/src/win/fs.c b/src/win/fs.c index 097b00e08..0905a24e5 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -723,8 +723,11 @@ void fs__write(uv_fs_t* req) { void fs__rmdir(uv_fs_t* req) { - int result = _wrmdir(req->file.pathw); - SET_REQ_RESULT(req, result); + if (RemoveDirectoryW(req->file.pathw)) { + SET_REQ_SUCCESS(req); + } else { + SET_REQ_WIN32_ERROR(req, GetLastError()); + } } diff --git a/test/test-fs.c b/test/test-fs.c index 11268c156..d43d6e61a 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -469,10 +469,19 @@ static void mkdtemp_cb(uv_fs_t* req) { static void rmdir_cb(uv_fs_t* req) { ASSERT(req == &rmdir_req); ASSERT(req->fs_type == UV_FS_RMDIR); - ASSERT(req->result == 0); - rmdir_cb_count++; ASSERT(req->path); - ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); + switch (rmdir_cb_count++) { + default: + ASSERT(0); + case 0: + ASSERT(req->result == UV_ENOTDIR); + ASSERT(memcmp(req->path, "test_dir/file1\0", 15) == 0); + break; + case 1: + ASSERT(req->result == 0); + ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); + break; + } uv_fs_req_cleanup(req); } @@ -986,6 +995,11 @@ TEST_IMPL(fs_async_dir) { ASSERT(stat_cb_count == 4); + r = uv_fs_rmdir(loop, &rmdir_req, "test_dir/file1", rmdir_cb); + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(rmdir_cb_count == 1); + r = uv_fs_unlink(loop, &unlink_req, "test_dir/file1", unlink_cb); ASSERT(r == 0); uv_run(loop, UV_RUN_DEFAULT); @@ -999,7 +1013,7 @@ TEST_IMPL(fs_async_dir) { r = uv_fs_rmdir(loop, &rmdir_req, "test_dir", rmdir_cb); ASSERT(r == 0); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(rmdir_cb_count == 1); + ASSERT(rmdir_cb_count == 2); /* Cleanup */ unlink("test_dir/file1"); From 9241cc297767eb36820133532eb4d9d8fa7bcda2 Mon Sep 17 00:00:00 2001 From: elephantp Date: Sat, 13 Jan 2018 05:41:57 +0800 Subject: [PATCH 600/632] unix: fix uv_cpu_info() error on FreeBSD This commit updates the key used in uv_cpu_info() for ARM FreeBSD. Fixes: https://github.com/nodejs/node/issues/17995 Fixes: https://github.com/libuv/libuv/issues/1694 PR-URL: https://github.com/libuv/libuv/pull/1700 Reviewed-By: Colin Ihrig Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno --- src/unix/freebsd.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index 39db148a2..f2b3f247a 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -276,6 +276,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { uv_cpu_info_t* cpu_info; const char* maxcpus_key; const char* cptimes_key; + const char* model_key; char model[512]; long* cp_times; int numcpus; @@ -294,8 +295,20 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { cptimes_key = "kern.cp_times"; #endif +#if defined(__arm__) || defined(__aarch64__) + /* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */ + model_key = "hw.machine"; + cpuspeed = 0; +#else + model_key = "hw.model"; + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) + return -errno; +#endif + size = sizeof(model); - if (sysctlbyname("hw.model", &model, &size, NULL, 0)) + if (sysctlbyname(model_key, &model, &size, NULL, 0)) return -errno; size = sizeof(numcpus); @@ -308,12 +321,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { *count = numcpus; - size = sizeof(cpuspeed); - if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) { - uv__free(*cpu_infos); - return -errno; - } - /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of * ncpu. */ From 9c503a278cd4f3adc48c9ca2c3fd16b63bb71e37 Mon Sep 17 00:00:00 2001 From: John Barboza Date: Sun, 14 Jan 2018 16:04:59 -0500 Subject: [PATCH 601/632] zos,test: decrease pings to avoid timeout Fixes: https://github.com/libuv/libuv/issues/1691 PR-URL: https://github.com/libuv/libuv/pull/1704 Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Santiago Gimeno --- test/test-ping-pong.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-ping-pong.c b/test/test-ping-pong.c index bdc967151..508f0db67 100644 --- a/test/test-ping-pong.c +++ b/test/test-ping-pong.c @@ -27,7 +27,7 @@ static int completed_pingers = 0; -#if defined(__CYGWIN__) || defined(__MSYS__) +#if defined(__CYGWIN__) || defined(__MSYS__) || defined(__MVS__) #define NUM_PINGS 100 /* fewer pings to avoid timeout */ #else #define NUM_PINGS 1000 From effbb7c9d29090b2e085a40867f8cdfa916a66df Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 17 Jan 2018 10:46:26 -0500 Subject: [PATCH 602/632] 2018.01.18, Version 1.19.0 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.18.0: * core: add getter/setter functions for easier ABI compat (Anna Henningsen) * unix: make get(set)_process_title MT-safe (Matt Harrison) * unix,win: wait for threads to start (Ben Noordhuis) * test: add threadpool init/teardown test (Bartosz Sosnowski) * win, process: uv_kill improvements (Bartosz Sosnowski) * win: set _WIN32_WINNT to 0x0600 (cjihrig) * zos: implement uv_fs_event* functions (jBarz) * unix,tcp: avoid marking server sockets connected (Jameson Nash) * doc: mark Windows 7 as Tier 1 support (Bartosz Sosnowski) * win: map 0.0.0.0 and :: addresses to localhost (Bartosz Sosnowski) * build: install libuv.pc unconditionally (Ben Noordhuis) * test: remove custom timeout for thread test on ppc (Ben Noordhuis) * test: allow multicast not permitted status (Jérémy Lal) * test: allow net unreachable status in udp test (Ben Noordhuis) * unix: use SA_RESTART when setting our sighandler (Brad King) * unix,fs: fix for potential partial reads/writes (Ben Wijen) * win,build: do not build executable installer for dll (Bert Belder) * win: allow directory symlinks to be created in a non-elevated context (Bert Belder) * zos,test: accept SIGKILL for flaky test (jBarz) * win: use RemoveDirectoryW() instead of _wmrmdir() (Ben Noordhuis) * unix: fix uv_cpu_info() error on FreeBSD (elephantp) * zos,test: decrease pings to avoid timeout (jBarz) --- AUTHORS | 4 ++++ ChangeLog | 50 ++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv-version.h | 8 +++---- 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index b227123e4..c826c8e13 100644 --- a/AUTHORS +++ b/AUTHORS @@ -321,3 +321,7 @@ Pekka Nikander Ed Schouten Xu Meng Matt Harrison +Anna Henningsen +Jérémy Lal +Ben Wijen +elephantp diff --git a/ChangeLog b/ChangeLog index 113c28aed..4ea9aa4a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,53 @@ +2018.01.18, Version 1.19.0 (Stable) + +Changes since version 1.18.0: + +* core: add getter/setter functions for easier ABI compat (Anna Henningsen) + +* unix: make get(set)_process_title MT-safe (Matt Harrison) + +* unix,win: wait for threads to start (Ben Noordhuis) + +* test: add threadpool init/teardown test (Bartosz Sosnowski) + +* win, process: uv_kill improvements (Bartosz Sosnowski) + +* win: set _WIN32_WINNT to 0x0600 (cjihrig) + +* zos: implement uv_fs_event* functions (jBarz) + +* unix,tcp: avoid marking server sockets connected (Jameson Nash) + +* doc: mark Windows 7 as Tier 1 support (Bartosz Sosnowski) + +* win: map 0.0.0.0 and :: addresses to localhost (Bartosz Sosnowski) + +* build: install libuv.pc unconditionally (Ben Noordhuis) + +* test: remove custom timeout for thread test on ppc (Ben Noordhuis) + +* test: allow multicast not permitted status (Jérémy Lal) + +* test: allow net unreachable status in udp test (Ben Noordhuis) + +* unix: use SA_RESTART when setting our sighandler (Brad King) + +* unix,fs: fix for potential partial reads/writes (Ben Wijen) + +* win,build: do not build executable installer for dll (Bert Belder) + +* win: allow directory symlinks to be created in a non-elevated context (Bert + Belder) + +* zos,test: accept SIGKILL for flaky test (jBarz) + +* win: use RemoveDirectoryW() instead of _wmrmdir() (Ben Noordhuis) + +* unix: fix uv_cpu_info() error on FreeBSD (elephantp) + +* zos,test: decrease pings to avoid timeout (jBarz) + + 2017.12.02, Version 1.18.0 (Stable), 1489c98b7fc17f1702821a269eb0c5e730c5c813 Changes since version 1.17.0: diff --git a/configure.ac b/configure.ac index ecc45881d..150a03a7f 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.18.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.19.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 6a90f87e4..2d4d9256a 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -31,10 +31,10 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 18 -#define UV_VERSION_PATCH 1 -#define UV_VERSION_IS_RELEASE 0 -#define UV_VERSION_SUFFIX "dev" +#define UV_VERSION_MINOR 19 +#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 da51b57a36dd84936f22cb7673e82f054c3cfdfb Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 17 Jan 2018 10:46:26 -0500 Subject: [PATCH 603/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 4ea9aa4a6..27971efe9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2018.01.18, Version 1.19.0 (Stable) +2018.01.18, Version 1.19.0 (Stable), effbb7c9d29090b2e085a40867f8cdfa916a66df Changes since version 1.18.0: From 1366e7412058be0f1510301454dabbe3004693cc Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 17 Jan 2018 10:50:30 -0500 Subject: [PATCH 604/632] Now working on version 1.19.1 Fixes: https://github.com/libuv/libuv/issues/1697 --- 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 2d4d9256a..1dc63e57c 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 19 -#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 20987732434cdd0a11c4b86437a706509907d39c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 19 Jan 2018 01:24:43 +0100 Subject: [PATCH 605/632] Revert "unix,tcp: avoid marking server sockets connected" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverted for breaking Node.js in rather spectacular fashion. The bug is arguably on the Node.js side. It looks like Node.js starts reading before the socket is actually connected to something. Until that is fixed downstream, let's revert the change. This reverts commit fd049399aa4ed8495928e375466970d98cb42e17. Fixes: https://github.com/libuv/libuv/issues/1716 Fixes: https://github.com/nodejs/node/issues/18225 PR-URL: https://github.com/libuv/libuv/pull/1717 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/unix/stream.c | 6 ------ src/unix/tcp.c | 8 +++++--- test/test-list.h | 2 -- test/test-tcp-bind-error.c | 42 -------------------------------------- 4 files changed, 5 insertions(+), 53 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index bccfd20f8..6fc0a01f5 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1411,9 +1411,6 @@ int uv_write2(uv_write_t* req, if (uv__stream_fd(stream) < 0) return -EBADF; - if (!(stream->flags & UV_STREAM_WRITABLE)) - return -EPIPE; - if (send_handle) { if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) return -EINVAL; @@ -1565,9 +1562,6 @@ int uv_read_start(uv_stream_t* stream, if (stream->flags & UV_CLOSING) return -EINVAL; - if (!(stream->flags & UV_STREAM_READABLE)) - return -ENOTCONN; - /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just * expresses the desired state of the user. */ diff --git a/src/unix/tcp.c b/src/unix/tcp.c index a40378518..c7c8d21c6 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -158,7 +158,9 @@ int uv__tcp_bind(uv_tcp_t* tcp, if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6) return -EINVAL; - err = maybe_new_socket(tcp, addr->sa_family, 0); + err = maybe_new_socket(tcp, + addr->sa_family, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); if (err) return err; @@ -333,14 +335,14 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { if (single_accept) tcp->flags |= UV_TCP_SINGLE_ACCEPT; - flags = 0; + flags = UV_STREAM_READABLE; #if defined(__MVS__) /* on zOS the listen call does not bind automatically if the socket is unbound. Hence the manual binding to an arbitrary port is required to be done manually */ flags |= UV_HANDLE_BOUND; -#endif +#endif err = maybe_new_socket(tcp, AF_INET, flags); if (err) return err; diff --git a/test/test-list.h b/test/test-list.h index d23cf8660..8e4f2025c 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -94,7 +94,6 @@ TEST_DECLARE (tcp_bind_error_fault) 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_listen_without_bind) TEST_DECLARE (tcp_connect_error_fault) TEST_DECLARE (tcp_connect_timeout) @@ -535,7 +534,6 @@ TASK_LIST_START TEST_ENTRY (tcp_bind_error_inval) TEST_ENTRY (tcp_bind_localhost_ok) TEST_ENTRY (tcp_bind_invalid_flags) - TEST_ENTRY (tcp_bind_writable_flags) TEST_ENTRY (tcp_listen_without_bind) TEST_ENTRY (tcp_connect_error_fault) TEST_ENTRY (tcp_connect_timeout) diff --git a/test/test-tcp-bind-error.c b/test/test-tcp-bind-error.c index 1456d081a..10ed68e10 100644 --- a/test/test-tcp-bind-error.c +++ b/test/test-tcp-bind-error.c @@ -214,45 +214,3 @@ TEST_IMPL(tcp_listen_without_bind) { MAKE_VALGRIND_HAPPY(); return 0; } - - -TEST_IMPL(tcp_bind_writable_flags) { - struct sockaddr_in addr; - uv_tcp_t server; - uv_buf_t buf; - uv_write_t write_req; - uv_shutdown_t shutdown_req; - int r; - - ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); - r = uv_tcp_init(uv_default_loop(), &server); - ASSERT(r == 0); - r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0); - ASSERT(r == 0); - r = uv_listen((uv_stream_t*)&server, 128, NULL); - ASSERT(r == 0); - - ASSERT(0 == uv_is_writable((uv_stream_t*) &server)); - ASSERT(0 == 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); - r = uv_shutdown(&shutdown_req, (uv_stream_t*) &server, NULL); -#ifdef _WIN32 - ASSERT(r == UV_EPIPE); -#else - ASSERT(r == UV_ENOTCONN); -#endif - r = uv_read_start((uv_stream_t*) &server, NULL, NULL); - ASSERT(r == UV_ENOTCONN); - - uv_close((uv_handle_t*)&server, close_cb); - - uv_run(uv_default_loop(), UV_RUN_DEFAULT); - - ASSERT(close_cb_called == 1); - - MAKE_VALGRIND_HAPPY(); - return 0; -} From b0f3310bb184b9ae8654698dea6c34f916fd442d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 19 Jan 2018 01:24:43 +0100 Subject: [PATCH 606/632] Revert "unix,fs: fix for potential partial reads/writes" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit has been reported as introducing a backwards-incompatible change in reading from stdin and is independently suspected of breaking the Node.js test suite on MacOS and maybe other platforms, possibly in combination with commit fd049399 ("unix,tcp: avoid marking server sockets connected".) This reverts commit 14bfc27e641aff178c431083c0c0eada4d6f02dd. Fixes: https://github.com/libuv/libuv/issues/1716 Fixes: https://github.com/libuv/libuv/issues/1720 Fixes: https://github.com/nodejs/node/issues/18225 PR-URL: https://github.com/libuv/libuv/pull/1717 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 1 + src/unix/fs.c | 62 ++++++++++++------ test/test-eintr-handling.c | 94 +++++++++++++++++++++++++++ test/test-fs.c | 127 +------------------------------------ test/test-list.h | 6 +- uv.gyp | 1 + 6 files changed, 141 insertions(+), 150 deletions(-) create mode 100644 test/test-eintr-handling.c diff --git a/Makefile.am b/Makefile.am index c49802f7f..ae9d96bcf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -165,6 +165,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-default-loop-close.c \ test/test-delayed-accept.c \ test/test-dlerror.c \ + test/test-eintr-handling.c \ test/test-embed.c \ test/test-emfile.c \ test/test-env-vars.c \ diff --git a/src/unix/fs.c b/src/unix/fs.c index 798646380..e0969a4c2 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -334,7 +334,25 @@ static ssize_t uv__fs_read(uv_fs_t* req) { if (no_preadv) retry: # endif { - result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off); + off_t nread; + size_t index; + + nread = 0; + index = 0; + result = 1; + do { + if (req->bufs[index].len > 0) { + result = pread(req->file, + req->bufs[index].base, + req->bufs[index].len, + req->off + nread); + if (result > 0) + nread += result; + } + index++; + } while (index < req->nbufs && result > 0); + if (nread > 0) + result = nread; } # if defined(__linux__) else { @@ -722,7 +740,25 @@ static ssize_t uv__fs_write(uv_fs_t* req) { if (no_pwritev) retry: # endif { - r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off); + off_t written; + size_t index; + + written = 0; + index = 0; + r = 0; + do { + if (req->bufs[index].len > 0) { + r = pwrite(req->file, + req->bufs[index].base, + req->bufs[index].len, + req->off + written); + if (r > 0) + written += r; + } + index++; + } while (index < req->nbufs && r >= 0); + if (written > 0) + r = written; } # if defined(__linux__) else { @@ -972,19 +1008,6 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) { return ret; } -static size_t uv__fs_buf_offset(uv_buf_t* bufs, size_t size) { - size_t offset; - /* Figure out which bufs are done */ - for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset) - size -= bufs[offset].len; - - /* Fix a partial read/write */ - if (size > 0) { - bufs[offset].base += size; - bufs[offset].len -= size; - } - return offset; -} typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req); static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) { @@ -1004,10 +1027,7 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) if (req->nbufs > iovmax) req->nbufs = iovmax; - do - result = process(req); - while (result < 0 && errno == EINTR); - + result = process(req); if (result <= 0) { if (total == 0) total = result; @@ -1017,12 +1037,14 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) if (req->off >= 0) req->off += result; - req->nbufs = uv__fs_buf_offset(req->bufs, result); req->bufs += req->nbufs; nbufs -= req->nbufs; total += result; } + if (errno == EINTR && total == -1) + return total; + if (bufs != req->bufsml) uv__free(bufs); diff --git a/test/test-eintr-handling.c b/test/test-eintr-handling.c new file mode 100644 index 000000000..1aaf623b7 --- /dev/null +++ b/test/test-eintr-handling.c @@ -0,0 +1,94 @@ +/* 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(eintr_handling) { + RETURN_SKIP("Test not implemented on Windows."); +} + +#else /* !_WIN32 */ + +#include +#include + +static uv_loop_t* loop; +static uv_fs_t read_req; +static uv_buf_t iov; + +static char buf[32]; +static char test_buf[] = "test-buffer\n"; +int pipe_fds[2]; + +struct thread_ctx { + uv_barrier_t barrier; + int fd; +}; + +static void thread_main(void* arg) { + int nwritten; + ASSERT(0 == kill(getpid(), SIGUSR1)); + + do + nwritten = write(pipe_fds[1], test_buf, sizeof(test_buf)); + while (nwritten == -1 && errno == EINTR); + + ASSERT(nwritten == sizeof(test_buf)); +} + +static void sig_func(uv_signal_t* handle, int signum) { + uv_signal_stop(handle); +} + +TEST_IMPL(eintr_handling) { + struct thread_ctx ctx; + uv_thread_t thread; + uv_signal_t signal; + int nread; + + 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(0 == pipe(pipe_fds)); + ASSERT(0 == 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(0 == uv_run(loop, UV_RUN_DEFAULT)); + + ASSERT(0 == close(pipe_fds[0])); + ASSERT(0 == close(pipe_fds[1])); + uv_close((uv_handle_t*) &signal, NULL); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* !_WIN32 */ diff --git a/test/test-fs.c b/test/test-fs.c index d43d6e61a..241416bcf 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2890,131 +2890,6 @@ TEST_IMPL(fs_write_alotof_bufs_with_offset) { } -#ifdef _WIN32 - -TEST_IMPL(fs_partial_read) { - RETURN_SKIP("Test not implemented on Windows."); -} - -TEST_IMPL(fs_partial_write) { - RETURN_SKIP("Test not implemented on Windows."); -} - -#else /* !_WIN32 */ - -static void thread_exec(int fd, char* data, int size, int interval, int doread) { - pid_t pid; - ssize_t result; - - pid = getpid(); - result = 1; - - while (size > 0 && result > 0) { - do { - if (doread) - result = write(fd, data, size < interval ? size : interval); - else - result = read(fd, data, size < interval ? size : interval); - } while (result == -1 && errno == EINTR); - - kill(pid, SIGUSR1); - size -= result; - data += result; - } - - ASSERT(size == 0); - ASSERT(result > 0); -} - -struct thread_ctx { - int fd; - char *data; - int size; - int interval; - int doread; -}; - -static void thread_main(void* arg) { - struct thread_ctx *ctx; - ctx = (struct thread_ctx*)arg; - thread_exec(ctx->fd, ctx->data, ctx->size, ctx->interval, ctx->doread); -} - -static void sig_func(uv_signal_t* handle, int signum) { - uv_signal_stop(handle); -} - -static void test_fs_partial(int doread) { - struct thread_ctx ctx; - uv_thread_t thread; - uv_signal_t signal; - int pipe_fds[2]; - size_t iovcount; - uv_buf_t* iovs; - char* buffer; - size_t index; - int result; - - iovcount = 54321; - - iovs = malloc(sizeof(*iovs) * iovcount); - ASSERT(iovs != NULL); - - ctx.doread = doread; - ctx.interval = 1000; - ctx.size = sizeof(test_buf) * iovcount; - ctx.data = malloc(ctx.size); - ASSERT(ctx.data != NULL); - buffer = malloc(ctx.size); - ASSERT(buffer != NULL); - - for (index = 0; index < iovcount; ++index) - iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf), sizeof(test_buf)); - - loop = uv_default_loop(); - - ASSERT(0 == uv_signal_init(loop, &signal)); - ASSERT(0 == uv_signal_start(&signal, sig_func, SIGUSR1)); - - ASSERT(0 == pipe(pipe_fds)); - - ctx.fd = pipe_fds[doread]; - ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx)); - - if (doread) - result = uv_fs_read(loop, &read_req, pipe_fds[0], iovs, iovcount, -1, NULL); - else - result = uv_fs_write(loop, &write_req, pipe_fds[1], iovs, iovcount, -1, NULL); - - ASSERT(result == ctx.size); - ASSERT(0 == memcmp(buffer, ctx.data, result)); - - ASSERT(0 == uv_thread_join(&thread)); - ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); - - ASSERT(0 == close(pipe_fds[0])); - ASSERT(0 == close(pipe_fds[1])); - uv_close((uv_handle_t*) &signal, NULL); - - free(iovs); - free(buffer); - free(ctx.data); - - MAKE_VALGRIND_HAPPY(); -} - -TEST_IMPL(fs_partial_read) { - test_fs_partial(1); - return 0; -} - -TEST_IMPL(fs_partial_write) { - test_fs_partial(0); - return 0; -} - -#endif/* _WIN32 */ - TEST_IMPL(fs_read_write_null_arguments) { int r; @@ -3223,7 +3098,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) { unlink("test_file"); ASSERT(UV_FS_O_EXLOCK > 0); - + r = uv_fs_open(NULL, &open_req1, "test_file", diff --git a/test/test-list.h b/test/test-list.h index 8e4f2025c..5a50ec671 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -213,6 +213,7 @@ TEST_DECLARE (active) TEST_DECLARE (embed) TEST_DECLARE (async) TEST_DECLARE (async_null_cb) +TEST_DECLARE (eintr_handling) TEST_DECLARE (get_currentexe) TEST_DECLARE (process_title) TEST_DECLARE (process_title_threadsafe) @@ -324,8 +325,6 @@ TEST_DECLARE (fs_read_write_null_arguments) TEST_DECLARE (get_osfhandle_valid_handle) TEST_DECLARE (fs_write_alotof_bufs) TEST_DECLARE (fs_write_alotof_bufs_with_offset) -TEST_DECLARE (fs_partial_read) -TEST_DECLARE (fs_partial_write) TEST_DECLARE (fs_file_pos_after_op_with_offset) TEST_DECLARE (fs_null_req) #ifdef _WIN32 @@ -675,6 +674,7 @@ TASK_LIST_START TEST_ENTRY (async) TEST_ENTRY (async_null_cb) + TEST_ENTRY (eintr_handling) TEST_ENTRY (get_currentexe) @@ -848,8 +848,6 @@ TASK_LIST_START TEST_ENTRY (fs_write_multiple_bufs) TEST_ENTRY (fs_write_alotof_bufs) TEST_ENTRY (fs_write_alotof_bufs_with_offset) - TEST_ENTRY (fs_partial_read) - TEST_ENTRY (fs_partial_write) TEST_ENTRY (fs_read_write_null_arguments) TEST_ENTRY (fs_file_pos_after_op_with_offset) TEST_ENTRY (fs_null_req) diff --git a/uv.gyp b/uv.gyp index 19008dfa8..46606c5bd 100644 --- a/uv.gyp +++ b/uv.gyp @@ -371,6 +371,7 @@ 'test/test-cwd-and-chdir.c', 'test/test-default-loop-close.c', 'test/test-delayed-accept.c', + 'test/test-eintr-handling.c', 'test/test-error.c', 'test/test-embed.c', 'test/test-emfile.c', From 9f07a3673b301da99bd31f2d793983caad6e3428 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 19 Jan 2018 01:24:43 +0100 Subject: [PATCH 607/632] Revert "win: use RemoveDirectoryW() instead of _wmrmdir()" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverted for breaking `test/parallel/test-child-process-cwd.js` from the Node.js test suite. Instead of ENOENT when trying to remove a directory that does not exist, it started failing with ENOTDIR. This reverts commit 15f29dc08fe72cd189002f1b8ae22fd82264deef. PR-URL: https://github.com/libuv/libuv/pull/1717 Refs: https://github.com/nodejs/node/issues/18014 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- src/win/error.c | 2 +- src/win/fs.c | 7 ++----- test/test-fs.c | 22 ++++------------------ 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/src/win/error.c b/src/win/error.c index 1ec3d6e27..9b03bfef6 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -131,7 +131,7 @@ int uv_translate_sys_error(int sys_errno) { case WSAENETUNREACH: return UV_ENETUNREACH; case WSAENOBUFS: return UV_ENOBUFS; case ERROR_BAD_PATHNAME: return UV_ENOENT; - case ERROR_DIRECTORY: return UV_ENOTDIR; + case ERROR_DIRECTORY: return UV_ENOENT; case ERROR_FILE_NOT_FOUND: return UV_ENOENT; case ERROR_INVALID_NAME: return UV_ENOENT; case ERROR_INVALID_DRIVE: return UV_ENOENT; diff --git a/src/win/fs.c b/src/win/fs.c index 0905a24e5..097b00e08 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -723,11 +723,8 @@ void fs__write(uv_fs_t* req) { void fs__rmdir(uv_fs_t* req) { - if (RemoveDirectoryW(req->file.pathw)) { - SET_REQ_SUCCESS(req); - } else { - SET_REQ_WIN32_ERROR(req, GetLastError()); - } + int result = _wrmdir(req->file.pathw); + SET_REQ_RESULT(req, result); } diff --git a/test/test-fs.c b/test/test-fs.c index 241416bcf..7c481f071 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -469,19 +469,10 @@ static void mkdtemp_cb(uv_fs_t* req) { static void rmdir_cb(uv_fs_t* req) { ASSERT(req == &rmdir_req); ASSERT(req->fs_type == UV_FS_RMDIR); + ASSERT(req->result == 0); + rmdir_cb_count++; ASSERT(req->path); - switch (rmdir_cb_count++) { - default: - ASSERT(0); - case 0: - ASSERT(req->result == UV_ENOTDIR); - ASSERT(memcmp(req->path, "test_dir/file1\0", 15) == 0); - break; - case 1: - ASSERT(req->result == 0); - ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); - break; - } + ASSERT(memcmp(req->path, "test_dir\0", 9) == 0); uv_fs_req_cleanup(req); } @@ -995,11 +986,6 @@ TEST_IMPL(fs_async_dir) { ASSERT(stat_cb_count == 4); - r = uv_fs_rmdir(loop, &rmdir_req, "test_dir/file1", rmdir_cb); - ASSERT(r == 0); - uv_run(loop, UV_RUN_DEFAULT); - ASSERT(rmdir_cb_count == 1); - r = uv_fs_unlink(loop, &unlink_req, "test_dir/file1", unlink_cb); ASSERT(r == 0); uv_run(loop, UV_RUN_DEFAULT); @@ -1013,7 +999,7 @@ TEST_IMPL(fs_async_dir) { r = uv_fs_rmdir(loop, &rmdir_req, "test_dir", rmdir_cb); ASSERT(r == 0); uv_run(loop, UV_RUN_DEFAULT); - ASSERT(rmdir_cb_count == 2); + ASSERT(rmdir_cb_count == 1); /* Cleanup */ unlink("test_dir/file1"); From 63de1ecad3252d3e9ed2fe960c21d9387615fa45 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 18 Jan 2018 14:42:09 -0500 Subject: [PATCH 608/632] cygwin: fix compilation of ifaddrs impl On cygwin there is no `AF_LINK`. Skip the check for it since we just zero the physical addresses on this platform anyway. Fixes: https://github.com/libuv/libuv/issues/1448 PR-URL: https://github.com/libuv/libuv/pull/1719 Reviewed-By: Ben Noordhuis --- src/unix/bsd-ifaddrs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/unix/bsd-ifaddrs.c b/src/unix/bsd-ifaddrs.c index 2593b9ff3..ea3166c5e 100644 --- a/src/unix/bsd-ifaddrs.c +++ b/src/unix/bsd-ifaddrs.c @@ -36,6 +36,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 `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family` * equals to `AF_LINK` or not. Otherwise, the result depends on the operation @@ -43,6 +44,7 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { */ if (exclude_type == UV__EXCLUDE_IFPHYS) return (ent->ifa_addr->sa_family != AF_LINK); +#endif #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) /* * On BSD getifaddrs returns information related to the raw underlying From 8202d1751196c2374ad370f7f3779daef89befae Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 19 Jan 2018 15:17:23 -0500 Subject: [PATCH 609/632] 2018.01.20, Version 1.19.1 (Stable) Changes since version 1.19.0: * Revert "unix,tcp: avoid marking server sockets connected" (Ben Noordhuis) * Revert "unix,fs: fix for potential partial reads/writes" (Ben Noordhuis) * Revert "win: use RemoveDirectoryW() instead of _wmrmdir()" (Ben Noordhuis) * cygwin: fix compilation of ifaddrs impl (Brad King) --- ChangeLog | 13 +++++++++++++ configure.ac | 2 +- include/uv-version.h | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 27971efe9..49420528a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2018.01.20, Version 1.19.1 (Stable) + +Changes since version 1.19.0: + +* Revert "unix,tcp: avoid marking server sockets connected" (Ben Noordhuis) + +* Revert "unix,fs: fix for potential partial reads/writes" (Ben Noordhuis) + +* Revert "win: use RemoveDirectoryW() instead of _wmrmdir()" (Ben Noordhuis) + +* cygwin: fix compilation of ifaddrs impl (Brad King) + + 2018.01.18, Version 1.19.0 (Stable), effbb7c9d29090b2e085a40867f8cdfa916a66df Changes since version 1.18.0: diff --git a/configure.ac b/configure.ac index 150a03a7f..75fb13c8c 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.19.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.19.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 1dc63e57c..581d761df 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -33,8 +33,8 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 19 #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 f03cc21a751b1722f37d1b7e97c876981b5e6303 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 19 Jan 2018 15:17:24 -0500 Subject: [PATCH 610/632] Add SHA to ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 49420528a..163500245 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -2018.01.20, Version 1.19.1 (Stable) +2018.01.20, Version 1.19.1 (Stable), 8202d1751196c2374ad370f7f3779daef89befae Changes since version 1.19.0: From faa52872b98a9757ac3f6d1fb712bb4fcb0517a5 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 19 Jan 2018 15:22:56 -0500 Subject: [PATCH 611/632] Now working on version 1.19.2 --- 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 581d761df..f5703e699 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -32,9 +32,9 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 19 -#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 974a5bf30ecec76cae440560967d7a9c78c51816 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 19 Jan 2018 13:52:21 -0500 Subject: [PATCH 612/632] test: fix incorrect asserts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes two assertions of the form (events == UV_CHANGE || UV_RENAME) which always passed because UV_RENAME is 1. Refs: https://github.com/libuv/help/issues/41 PR-URL: https://github.com/libuv/libuv/pull/1722 Reviewed-By: Santiago Gimeno Reviewed-By: Saúl Ibarra Corretgé --- test/test-fs-event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-fs-event.c b/test/test-fs-event.c index dc47b3a62..39d73300d 100644 --- a/test/test-fs-event.c +++ b/test/test-fs-event.c @@ -199,7 +199,7 @@ static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle, fs_event_cb_called++; ASSERT(handle == &fs_event); ASSERT(status == 0); - ASSERT(events == UV_CHANGE || UV_RENAME); + ASSERT(events == UV_CHANGE || events == UV_RENAME); #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) ASSERT(strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0); #else @@ -283,7 +283,7 @@ static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle, fs_event_cb_called++; ASSERT(handle == &fs_event); ASSERT(status == 0); - ASSERT(events == UV_CHANGE || UV_RENAME); + ASSERT(events == UV_CHANGE || events == UV_RENAME); #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) ASSERT(strncmp(filename, file_prefix_in_subdir, From 83e187178021531780a873a89b4a8c70e2f70e56 Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Fri, 19 Jan 2018 12:52:50 +0800 Subject: [PATCH 613/632] test: fix a typo in test-fork.c PR-URL: https://github.com/libuv/libuv/pull/1721 Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Santiago Gimeno --- test/test-fork.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-fork.c b/test/test-fork.c index 924c65b21..39b59c8f2 100644 --- a/test/test-fork.c +++ b/test/test-fork.c @@ -335,7 +335,7 @@ TEST_IMPL(fork_signal_to_child_closed) { /* Note that we're deliberately not running the loop * in the child, and also not closing the loop's handles, * so the child default loop can't be cleanly closed. - * We need te explicitly exit to avoid an automatic failure + * We need to explicitly exit to avoid an automatic failure * in that case. */ exit(0); From 760556d3e7fba56734c34ee9c0c39e3026596df8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 23 Jan 2018 20:39:04 +0100 Subject: [PATCH 614/632] build: remove long-obsolete gyp workarounds Drop obsolete workarounds from the `gyp_uv.py` wrapper script. The bugs they work around were fixed about five years ago. PR-URL: https://github.com/libuv/libuv/pull/1725 Reviewed-By: Colin Ihrig --- gyp_uv.py | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/gyp_uv.py b/gyp_uv.py index bd37d95c4..e5759cdd3 100755 --- a/gyp_uv.py +++ b/gyp_uv.py @@ -43,28 +43,7 @@ def run_gyp(args): if __name__ == '__main__': args = sys.argv[1:] - - # GYP bug. - # On msvs it will crash if it gets an absolute path. - # On Mac/make it will crash if it doesn't get an absolute path. - if sys.platform == 'win32': - args.append(os.path.join(uv_root, 'uv.gyp')) - common_fn = os.path.join(uv_root, 'common.gypi') - options_fn = os.path.join(uv_root, 'options.gypi') - # we force vs 2010 over 2008 which would otherwise be the default for gyp - if not os.environ.get('GYP_MSVS_VERSION'): - os.environ['GYP_MSVS_VERSION'] = '2010' - else: - args.append(os.path.join(os.path.abspath(uv_root), 'uv.gyp')) - common_fn = os.path.join(os.path.abspath(uv_root), 'common.gypi') - options_fn = os.path.join(os.path.abspath(uv_root), 'options.gypi') - - if os.path.exists(common_fn): - args.extend(['-I', common_fn]) - - if os.path.exists(options_fn): - args.extend(['-I', options_fn]) - + args.extend('-I common.gypi uv.gyp'.split(' ')) args.append('--depth=' + uv_root) # There's a bug with windows which doesn't allow this feature. From fdf7c2ad1ddcd915cc9d8786b412f82427a6b12e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 23 Jan 2018 20:39:04 +0100 Subject: [PATCH 615/632] build: split off tests into separate gyp file Make it easier for Node.js to ship libuv in its tarballs without also including the test suite. Node.js already does so but recent changes to its build system complicate that. Kills two birds with one stone: it helps out Node.js and it makes it harder for us to introduce hidden dependencies between the library and the test suite. PR-URL: https://github.com/libuv/libuv/pull/1725 Refs: https://github.com/nodejs/node/pull/18287 Reviewed-By: Colin Ihrig --- gyp_uv.py | 2 +- test/test.gyp | 279 +++++++++++++++++++++++++++++++++++++++ uv.gyp | 357 +++++++------------------------------------------- vcbuild.bat | 7 +- 4 files changed, 331 insertions(+), 314 deletions(-) create mode 100644 test/test.gyp diff --git a/gyp_uv.py b/gyp_uv.py index e5759cdd3..c2add5cae 100755 --- a/gyp_uv.py +++ b/gyp_uv.py @@ -43,7 +43,7 @@ def run_gyp(args): if __name__ == '__main__': args = sys.argv[1:] - args.extend('-I common.gypi uv.gyp'.split(' ')) + args.extend('-I common.gypi test/test.gyp'.split(' ')) args.append('--depth=' + uv_root) # There's a bug with windows which doesn't allow this feature. diff --git a/test/test.gyp b/test/test.gyp new file mode 100644 index 000000000..480e5a26c --- /dev/null +++ b/test/test.gyp @@ -0,0 +1,279 @@ +{ + 'targets': [ + { + 'target_name': 'run-tests', + 'type': 'executable', + 'dependencies': [ '../uv.gyp:libuv' ], + 'sources': [ + 'blackhole-server.c', + 'echo-server.c', + 'run-tests.c', + 'runner.c', + 'runner.h', + 'test-get-loadavg.c', + 'task.h', + 'test-active.c', + 'test-async.c', + 'test-async-null-cb.c', + 'test-callback-stack.c', + 'test-callback-order.c', + 'test-close-fd.c', + 'test-close-order.c', + 'test-connect-unspecified.c', + 'test-connection-fail.c', + 'test-cwd-and-chdir.c', + 'test-default-loop-close.c', + 'test-delayed-accept.c', + 'test-eintr-handling.c', + 'test-error.c', + 'test-embed.c', + 'test-emfile.c', + 'test-env-vars.c', + 'test-fail-always.c', + 'test-fork.c', + 'test-fs.c', + 'test-fs-copyfile.c', + 'test-fs-event.c', + 'test-getters-setters.c', + 'test-get-currentexe.c', + 'test-get-memory.c', + 'test-get-passwd.c', + 'test-getaddrinfo.c', + 'test-gethostname.c', + 'test-getnameinfo.c', + 'test-getsockname.c', + 'test-handle-fileno.c', + 'test-homedir.c', + 'test-hrtime.c', + 'test-idle.c', + 'test-ip6-addr.c', + 'test-ipc.c', + 'test-ipc-send-recv.c', + 'test-list.h', + 'test-loop-handles.c', + 'test-loop-alive.c', + 'test-loop-close.c', + 'test-loop-stop.c', + 'test-loop-time.c', + 'test-loop-configure.c', + 'test-walk-handles.c', + 'test-watcher-cross-stop.c', + 'test-multiple-listen.c', + 'test-osx-select.c', + 'test-pass-always.c', + 'test-ping-pong.c', + 'test-pipe-bind-error.c', + 'test-pipe-connect-error.c', + 'test-pipe-connect-multiple.c', + 'test-pipe-connect-prepare.c', + 'test-pipe-getsockname.c', + 'test-pipe-pending-instances.c', + 'test-pipe-sendmsg.c', + 'test-pipe-server-close.c', + 'test-pipe-close-stdout-read-stdin.c', + 'test-pipe-set-non-blocking.c', + 'test-pipe-set-fchmod.c', + 'test-platform-output.c', + 'test-poll.c', + 'test-poll-close.c', + 'test-poll-close-doesnt-corrupt-stack.c', + 'test-poll-closesocket.c', + 'test-poll-oob.c', + 'test-process-title.c', + 'test-process-title-threadsafe.c', + 'test-queue-foreach-delete.c', + 'test-ref.c', + 'test-run-nowait.c', + 'test-run-once.c', + 'test-semaphore.c', + 'test-shutdown-close.c', + 'test-shutdown-eof.c', + 'test-shutdown-twice.c', + 'test-signal.c', + 'test-signal-multiple-loops.c', + 'test-socket-buffer-size.c', + 'test-spawn.c', + 'test-fs-poll.c', + 'test-stdio-over-pipes.c', + 'test-tcp-alloc-cb-fail.c', + 'test-tcp-bind-error.c', + 'test-tcp-bind6-error.c', + 'test-tcp-close.c', + 'test-tcp-close-accept.c', + 'test-tcp-close-while-connecting.c', + 'test-tcp-create-socket-early.c', + 'test-tcp-connect-error-after-write.c', + 'test-tcp-shutdown-after-write.c', + 'test-tcp-flags.c', + 'test-tcp-connect-error.c', + 'test-tcp-connect-timeout.c', + 'test-tcp-connect6-error.c', + 'test-tcp-open.c', + 'test-tcp-write-to-half-open-connection.c', + 'test-tcp-write-after-connect.c', + 'test-tcp-writealot.c', + 'test-tcp-write-fail.c', + 'test-tcp-try-write.c', + 'test-tcp-unexpected-read.c', + 'test-tcp-oob.c', + 'test-tcp-read-stop.c', + 'test-tcp-write-queue-order.c', + 'test-threadpool.c', + 'test-threadpool-cancel.c', + 'test-thread-equal.c', + 'test-tmpdir.c', + 'test-mutexes.c', + 'test-thread.c', + 'test-barrier.c', + 'test-condvar.c', + 'test-timer-again.c', + 'test-timer-from-check.c', + 'test-timer.c', + 'test-tty.c', + 'test-udp-alloc-cb-fail.c', + 'test-udp-bind.c', + 'test-udp-create-socket-early.c', + 'test-udp-dgram-too-big.c', + 'test-udp-ipv6.c', + 'test-udp-open.c', + 'test-udp-options.c', + 'test-udp-send-and-recv.c', + 'test-udp-send-hang-loop.c', + 'test-udp-send-immediate.c', + 'test-udp-send-unreachable.c', + 'test-udp-multicast-join.c', + 'test-udp-multicast-join6.c', + 'test-dlerror.c', + 'test-udp-multicast-ttl.c', + 'test-ip4-addr.c', + 'test-ip6-addr.c', + 'test-udp-multicast-interface.c', + 'test-udp-multicast-interface6.c', + 'test-udp-try-send.c', + ], + 'conditions': [ + [ 'OS=="win"', { + 'sources': [ + 'runner-win.c', + 'runner-win.h', + '../src/win/snprintf.c', + ], + 'libraries': [ '-lws2_32' ] + }, { # POSIX + 'sources': [ + 'runner-unix.c', + 'runner-unix.h', + ], + 'conditions': [ + [ 'OS != "zos"', { + 'defines': [ '_GNU_SOURCE' ], + 'cflags': [ '-Wno-long-long' ], + 'xcode_settings': { + 'WARNING_CFLAGS': [ '-Wno-long-long' ] + } + }], + ]}, + ], + [ 'OS in "mac dragonflybsd freebsd linux netbsd openbsd".split()', { + 'link_settings': { + 'libraries': [ '-lutil' ], + }, + }], + [ 'OS=="solaris"', { # make test-fs.c compile, needs _POSIX_C_SOURCE + 'defines': [ + '__EXTENSIONS__', + '_XOPEN_SOURCE=500', + ], + }], + [ 'OS=="aix"', { # make test-fs.c compile, needs _POSIX_C_SOURCE + 'defines': [ + '_ALL_SOURCE', + '_XOPEN_SOURCE=500', + ], + }], + [ 'OS == "zos"', { + 'cflags': [ '-qxplink' ], + 'ldflags': [ '-qxplink' ], + }], + ['uv_library=="shared_library"', { + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "zos"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], + }], + ], + 'msvs-settings': { + 'VCLinkerTool': { + 'SubSystem': 1, # /subsystem:console + }, + }, + }, + + { + 'target_name': 'run-benchmarks', + 'type': 'executable', + 'dependencies': [ '../uv.gyp:libuv' ], + 'sources': [ + 'benchmark-async.c', + 'benchmark-async-pummel.c', + 'benchmark-fs-stat.c', + 'benchmark-getaddrinfo.c', + 'benchmark-list.h', + 'benchmark-loop-count.c', + 'benchmark-million-async.c', + 'benchmark-million-timers.c', + 'benchmark-multi-accept.c', + 'benchmark-ping-pongs.c', + 'benchmark-pound.c', + 'benchmark-pump.c', + 'benchmark-sizes.c', + 'benchmark-spawn.c', + 'benchmark-thread.c', + 'benchmark-tcp-write-batch.c', + 'benchmark-udp-pummel.c', + 'dns-server.c', + 'echo-server.c', + 'blackhole-server.c', + 'run-benchmarks.c', + 'runner.c', + 'runner.h', + 'task.h', + ], + 'conditions': [ + [ 'OS=="win"', { + 'sources': [ + 'runner-win.c', + 'runner-win.h', + '../src/win/snprintf.c', + ], + 'libraries': [ '-lws2_32' ] + }, { # POSIX + 'defines': [ '_GNU_SOURCE' ], + 'sources': [ + 'runner-unix.c', + 'runner-unix.h', + ] + }], + [ 'OS == "zos"', { + 'cflags': [ '-qxplink' ], + 'ldflags': [ '-qxplink' ], + }], + ['uv_library=="shared_library"', { + 'defines': [ 'USING_UV_SHARED=1' ], + 'conditions': [ + [ 'OS == "zos"', { + 'cflags': [ '-Wc,DLL' ], + }], + ], + }], + ], + 'msvs-settings': { + 'VCLinkerTool': { + 'SubSystem': 1, # /subsystem:console + }, + }, + }, + ], +} diff --git a/uv.gyp b/uv.gyp index 46606c5bd..a5046b87e 100644 --- a/uv.gyp +++ b/uv.gyp @@ -1,44 +1,38 @@ { - 'target_defaults': { + 'variables': { 'conditions': [ - ['OS != "win"', { - 'defines': [ + ['OS=="win"', { + 'shared_unix_defines': [ '_LARGEFILE_SOURCE', '_FILE_OFFSET_BITS=64', ], - 'conditions': [ - ['OS=="solaris"', { - 'cflags': [ '-pthreads' ], - }], - ['OS not in "solaris android zos"', { - 'cflags': [ '-pthread' ], - }], - ['OS in "zos"', { - 'defines': [ - '_UNIX03_THREADS', - '_UNIX03_SOURCE', - '_UNIX03_WITHDRAWN', - '_OPEN_SYS_IF_EXT', - '_OPEN_SYS_SOCK_IPV6', - '_OPEN_MSGQ_EXT', - '_XOPEN_SOURCE_EXTENDED', - '_ALL_SOURCE', - '_LARGE_TIME_API', - '_OPEN_SYS_FILE_EXT', - '_AE_BIMODAL', - 'PATH_MAX=255' - ], - 'cflags': [ '-qxplink' ], - 'ldflags': [ '-qxplink' ], - }] + }, { + 'shared_unix_defines': [ ], + }], + ['OS in "mac ios"', { + 'shared_mac_defines': [ '_DARWIN_USE_64_BIT_INODE=1' ], + }, { + 'shared_mac_defines': [ ], + }], + ['OS=="zos"', { + 'shared_zos_defines': [ + '_UNIX03_THREADS', + '_UNIX03_SOURCE', + '_UNIX03_WITHDRAWN', + '_OPEN_SYS_IF_EXT', + '_OPEN_SYS_SOCK_IPV6', + '_OPEN_MSGQ_EXT', + '_XOPEN_SOURCE_EXTENDED', + '_ALL_SOURCE', + '_LARGE_TIME_API', + '_OPEN_SYS_FILE_EXT', + '_AE_BIMODAL', + 'PATH_MAX=255' ], + }, { + 'shared_zos_defines': [ ], }], ], - 'xcode_settings': { - 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden - 'WARNING_CFLAGS': [ '-Wall', '-Wextra', '-Wno-unused-parameter', '-Wstrict-prototypes' ], - 'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ], - } }, 'targets': [ @@ -49,18 +43,19 @@ 'include', 'src/', ], + 'defines': [ + '<@(shared_mac_defines)', + '<@(shared_unix_defines)', + '<@(shared_zos_defines)', + ], 'direct_dependent_settings': { + 'defines': [ + '<@(shared_mac_defines)', + '<@(shared_unix_defines)', + '<@(shared_zos_defines)', + ], 'include_dirs': [ 'include' ], 'conditions': [ - ['OS != "win"', { - 'defines': [ - '_LARGEFILE_SOURCE', - '_FILE_OFFSET_BITS=64', - ], - }], - ['OS in "mac ios"', { - 'defines': [ '_DARWIN_USE_64_BIT_INODE=1' ], - }], ['OS == "linux"', { 'defines': [ '_POSIX_C_SOURCE=200112' ], }], @@ -83,6 +78,16 @@ 'src/uv-common.h', 'src/version.c' ], + 'xcode_settings': { + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden + 'WARNING_CFLAGS': [ + '-Wall', + '-Wextra', + '-Wno-unused-parameter', + '-Wstrict-prototypes', + ], + 'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ], + }, 'conditions': [ [ 'OS=="win"', { 'defines': [ @@ -346,273 +351,5 @@ }], ] }, - - { - 'target_name': 'run-tests', - 'type': 'executable', - 'dependencies': [ 'libuv' ], - 'sources': [ - 'test/blackhole-server.c', - 'test/echo-server.c', - 'test/run-tests.c', - 'test/runner.c', - 'test/runner.h', - 'test/test-get-loadavg.c', - 'test/task.h', - 'test/test-active.c', - 'test/test-async.c', - 'test/test-async-null-cb.c', - 'test/test-callback-stack.c', - 'test/test-callback-order.c', - 'test/test-close-fd.c', - 'test/test-close-order.c', - 'test/test-connect-unspecified.c', - 'test/test-connection-fail.c', - 'test/test-cwd-and-chdir.c', - 'test/test-default-loop-close.c', - 'test/test-delayed-accept.c', - 'test/test-eintr-handling.c', - 'test/test-error.c', - 'test/test-embed.c', - 'test/test-emfile.c', - 'test/test-env-vars.c', - 'test/test-fail-always.c', - 'test/test-fork.c', - 'test/test-fs.c', - 'test/test-fs-copyfile.c', - 'test/test-fs-event.c', - 'test/test-getters-setters.c', - 'test/test-get-currentexe.c', - 'test/test-get-memory.c', - 'test/test-get-passwd.c', - 'test/test-getaddrinfo.c', - 'test/test-gethostname.c', - 'test/test-getnameinfo.c', - 'test/test-getsockname.c', - 'test/test-handle-fileno.c', - 'test/test-homedir.c', - 'test/test-hrtime.c', - 'test/test-idle.c', - 'test/test-ip6-addr.c', - 'test/test-ipc.c', - 'test/test-ipc-send-recv.c', - 'test/test-list.h', - 'test/test-loop-handles.c', - 'test/test-loop-alive.c', - 'test/test-loop-close.c', - 'test/test-loop-stop.c', - 'test/test-loop-time.c', - 'test/test-loop-configure.c', - 'test/test-walk-handles.c', - 'test/test-watcher-cross-stop.c', - 'test/test-multiple-listen.c', - 'test/test-osx-select.c', - 'test/test-pass-always.c', - 'test/test-ping-pong.c', - 'test/test-pipe-bind-error.c', - 'test/test-pipe-connect-error.c', - 'test/test-pipe-connect-multiple.c', - 'test/test-pipe-connect-prepare.c', - 'test/test-pipe-getsockname.c', - 'test/test-pipe-pending-instances.c', - 'test/test-pipe-sendmsg.c', - 'test/test-pipe-server-close.c', - 'test/test-pipe-close-stdout-read-stdin.c', - 'test/test-pipe-set-non-blocking.c', - 'test/test-pipe-set-fchmod.c', - 'test/test-platform-output.c', - 'test/test-poll.c', - 'test/test-poll-close.c', - 'test/test-poll-close-doesnt-corrupt-stack.c', - 'test/test-poll-closesocket.c', - 'test/test-poll-oob.c', - 'test/test-process-title.c', - 'test/test-process-title-threadsafe.c', - 'test/test-queue-foreach-delete.c', - 'test/test-ref.c', - 'test/test-run-nowait.c', - 'test/test-run-once.c', - 'test/test-semaphore.c', - 'test/test-shutdown-close.c', - 'test/test-shutdown-eof.c', - 'test/test-shutdown-twice.c', - 'test/test-signal.c', - 'test/test-signal-multiple-loops.c', - 'test/test-socket-buffer-size.c', - 'test/test-spawn.c', - 'test/test-fs-poll.c', - 'test/test-stdio-over-pipes.c', - 'test/test-tcp-alloc-cb-fail.c', - 'test/test-tcp-bind-error.c', - 'test/test-tcp-bind6-error.c', - 'test/test-tcp-close.c', - 'test/test-tcp-close-accept.c', - 'test/test-tcp-close-while-connecting.c', - 'test/test-tcp-create-socket-early.c', - 'test/test-tcp-connect-error-after-write.c', - 'test/test-tcp-shutdown-after-write.c', - 'test/test-tcp-flags.c', - 'test/test-tcp-connect-error.c', - 'test/test-tcp-connect-timeout.c', - 'test/test-tcp-connect6-error.c', - 'test/test-tcp-open.c', - 'test/test-tcp-write-to-half-open-connection.c', - 'test/test-tcp-write-after-connect.c', - 'test/test-tcp-writealot.c', - 'test/test-tcp-write-fail.c', - 'test/test-tcp-try-write.c', - 'test/test-tcp-unexpected-read.c', - 'test/test-tcp-oob.c', - 'test/test-tcp-read-stop.c', - 'test/test-tcp-write-queue-order.c', - 'test/test-threadpool.c', - 'test/test-threadpool-cancel.c', - 'test/test-thread-equal.c', - 'test/test-tmpdir.c', - 'test/test-mutexes.c', - 'test/test-thread.c', - 'test/test-barrier.c', - 'test/test-condvar.c', - 'test/test-timer-again.c', - 'test/test-timer-from-check.c', - 'test/test-timer.c', - 'test/test-tty.c', - 'test/test-udp-alloc-cb-fail.c', - 'test/test-udp-bind.c', - 'test/test-udp-create-socket-early.c', - 'test/test-udp-dgram-too-big.c', - 'test/test-udp-ipv6.c', - 'test/test-udp-open.c', - 'test/test-udp-options.c', - 'test/test-udp-send-and-recv.c', - 'test/test-udp-send-hang-loop.c', - 'test/test-udp-send-immediate.c', - 'test/test-udp-send-unreachable.c', - 'test/test-udp-multicast-join.c', - 'test/test-udp-multicast-join6.c', - 'test/test-dlerror.c', - 'test/test-udp-multicast-ttl.c', - 'test/test-ip4-addr.c', - 'test/test-ip6-addr.c', - 'test/test-udp-multicast-interface.c', - 'test/test-udp-multicast-interface6.c', - 'test/test-udp-try-send.c', - ], - 'conditions': [ - [ 'OS=="win"', { - 'sources': [ - 'test/runner-win.c', - 'test/runner-win.h', - 'src/win/snprintf.c', - ], - 'libraries': [ '-lws2_32' ] - }, { # POSIX - 'sources': [ - 'test/runner-unix.c', - 'test/runner-unix.h', - ], - 'conditions': [ - [ 'OS != "zos"', { - 'defines': [ '_GNU_SOURCE' ], - 'cflags': [ '-Wno-long-long' ], - 'xcode_settings': { - 'WARNING_CFLAGS': [ '-Wno-long-long' ] - } - }], - ]}, - ], - [ 'OS in "mac dragonflybsd freebsd linux netbsd openbsd".split()', { - 'link_settings': { - 'libraries': [ '-lutil' ], - }, - }], - [ 'OS=="solaris"', { # make test-fs.c compile, needs _POSIX_C_SOURCE - 'defines': [ - '__EXTENSIONS__', - '_XOPEN_SOURCE=500', - ], - }], - [ 'OS=="aix"', { # make test-fs.c compile, needs _POSIX_C_SOURCE - 'defines': [ - '_ALL_SOURCE', - '_XOPEN_SOURCE=500', - ], - }], - ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ], - 'conditions': [ - [ 'OS == "zos"', { - 'cflags': [ '-Wc,DLL' ], - }], - ], - }], - ], - 'msvs-settings': { - 'VCLinkerTool': { - 'SubSystem': 1, # /subsystem:console - }, - }, - }, - - { - 'target_name': 'run-benchmarks', - 'type': 'executable', - 'dependencies': [ 'libuv' ], - 'sources': [ - 'test/benchmark-async.c', - 'test/benchmark-async-pummel.c', - 'test/benchmark-fs-stat.c', - 'test/benchmark-getaddrinfo.c', - 'test/benchmark-list.h', - 'test/benchmark-loop-count.c', - 'test/benchmark-million-async.c', - 'test/benchmark-million-timers.c', - 'test/benchmark-multi-accept.c', - 'test/benchmark-ping-pongs.c', - 'test/benchmark-pound.c', - 'test/benchmark-pump.c', - 'test/benchmark-sizes.c', - 'test/benchmark-spawn.c', - 'test/benchmark-thread.c', - 'test/benchmark-tcp-write-batch.c', - 'test/benchmark-udp-pummel.c', - 'test/dns-server.c', - 'test/echo-server.c', - 'test/blackhole-server.c', - 'test/run-benchmarks.c', - 'test/runner.c', - 'test/runner.h', - 'test/task.h', - ], - 'conditions': [ - [ 'OS=="win"', { - 'sources': [ - 'test/runner-win.c', - 'test/runner-win.h', - 'src/win/snprintf.c', - ], - 'libraries': [ '-lws2_32' ] - }, { # POSIX - 'defines': [ '_GNU_SOURCE' ], - 'sources': [ - 'test/runner-unix.c', - 'test/runner-unix.h', - ] - }], - ['uv_library=="shared_library"', { - 'defines': [ 'USING_UV_SHARED=1' ], - 'conditions': [ - [ 'OS == "zos"', { - 'cflags': [ '-Wc,DLL' ], - }], - ], - }], - ], - 'msvs-settings': { - 'VCLinkerTool': { - 'SubSystem': 1, # /subsystem:console - }, - }, - }, ] } diff --git a/vcbuild.bat b/vcbuild.bat index 46b347610..c195394f3 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -159,13 +159,14 @@ goto run :msbuild-found msbuild uv.sln /t:%target% /p:Configuration=%config% /p:Platform="%msbuild_platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo if errorlevel 1 exit /b 1 +msbuild test\test.sln /t:%target% /p:Configuration=%config% /p:Platform="%msbuild_platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo +if errorlevel 1 exit /b 1 :run @rem Run tests if requested. if "%run%"=="" goto exit -if not exist %config%\%run% goto exit -echo running '%config%\%run%' -%config%\%run% +echo running 'test\%config%\%run%' +test\%config%\%run% goto exit :create-msvs-files-failed From 693c217f803e7eab81c01fb1a9c307835fe4003d Mon Sep 17 00:00:00 2001 From: Jamie Davis Date: Wed, 17 Jan 2018 21:47:18 -0500 Subject: [PATCH 616/632] test: check uv_cond_timedwait more carefully Problem: The "timeout" functionality of uv_cond_timedwait was not being tested. The test (condvar_3) would use a worker that signaled the condition. Solution: Introduce a new condvar test case to ensure that the timeout also works. PR-URL: https://github.com/libuv/libuv/pull/1713 Reviewed-By: Ben Noordhuis Reviewed-By: John Barboza --- test/test-condvar.c | 54 ++++++++++++++++++++++++++++++++++++++------- test/test-list.h | 2 ++ 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/test/test-condvar.c b/test/test-condvar.c index 83b28494a..d956efef3 100644 --- a/test/test-condvar.c +++ b/test/test-condvar.c @@ -34,7 +34,7 @@ typedef struct worker_config { volatile int posted_1; volatile int posted_2; void (*signal_cond)(struct worker_config* c, volatile int* flag); - void (*wait_cond)(struct worker_config* c, const volatile int* flag); + int (*wait_cond)(struct worker_config* c, const volatile int* flag); } worker_config; @@ -44,6 +44,9 @@ static void worker(void* arg) { c->wait_cond(c, &c->posted_2); } +static void noop_worker(void* arg) { + return; +} static void condvar_signal(worker_config* c, volatile int* flag) { if (c->signal_delay) @@ -60,7 +63,7 @@ static void condvar_signal(worker_config* c, volatile int* flag) { } -static void condvar_wait(worker_config* c, const volatile int* flag) { +static int condvar_wait(worker_config* c, const volatile int* flag) { uv_mutex_lock(&c->mutex); if (c->wait_delay) uv_sleep(c->wait_delay); @@ -69,6 +72,8 @@ static void condvar_wait(worker_config* c, const volatile int* flag) { } ASSERT(*flag == 1); uv_mutex_unlock(&c->mutex); + + return 0; } @@ -85,7 +90,7 @@ TEST_IMPL(condvar_1) { ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - wc.wait_cond(&wc, &wc.posted_1); + ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); @@ -109,7 +114,7 @@ TEST_IMPL(condvar_2) { ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - wc.wait_cond(&wc, &wc.posted_1); + ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); @@ -120,20 +125,26 @@ TEST_IMPL(condvar_2) { } -static void condvar_timedwait(worker_config* c, const volatile int* flag) { +static int condvar_timedwait(worker_config* c, const volatile int* flag) { int r; + r = 0; + uv_mutex_lock(&c->mutex); if (c->wait_delay) uv_sleep(c->wait_delay); while (*flag == 0) { r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(150 * 1e6)); - ASSERT(r == 0); + ASSERT(r == 0 || r == UV_ETIMEDOUT); + if (r == UV_ETIMEDOUT) + break; } uv_mutex_unlock(&c->mutex); -} + return r; +} +/* Test that uv_cond_timedwait will return early when cond is signaled. */ TEST_IMPL(condvar_3) { uv_thread_t thread; worker_config wc; @@ -147,7 +158,7 @@ TEST_IMPL(condvar_3) { ASSERT(0 == uv_mutex_init(&wc.mutex)); ASSERT(0 == uv_thread_create(&thread, worker, &wc)); - wc.wait_cond(&wc, &wc.posted_1); + ASSERT(0 == wc.wait_cond(&wc, &wc.posted_1)); wc.signal_cond(&wc, &wc.posted_2); ASSERT(0 == uv_thread_join(&thread)); @@ -205,3 +216,30 @@ TEST_IMPL(condvar_5) { return 0; } + +/* Test that uv_cond_timedwait will time out when cond is not signaled. */ +TEST_IMPL(condvar_6) { + uv_thread_t thread; + worker_config wc; + int r; + + memset(&wc, 0, sizeof(wc)); + wc.signal_delay = 100; + wc.signal_cond = condvar_signal; + wc.wait_cond = condvar_timedwait; + + ASSERT(0 == uv_cond_init(&wc.cond)); + ASSERT(0 == uv_mutex_init(&wc.mutex)); + ASSERT(0 == uv_thread_create(&thread, noop_worker, &wc)); + + /* This can only return having timed out, because otherwise we + * loop forever in condvar_timedwait. */ + r = wc.wait_cond(&wc, &wc.posted_1); + ASSERT(r == UV_ETIMEDOUT); + + ASSERT(0 == uv_thread_join(&thread)); + uv_mutex_destroy(&wc.mutex); + uv_cond_destroy(&wc.cond); + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 5a50ec671..ff0a31d16 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -42,6 +42,7 @@ TEST_DECLARE (condvar_2) TEST_DECLARE (condvar_3) TEST_DECLARE (condvar_4) TEST_DECLARE (condvar_5) +TEST_DECLARE (condvar_6) TEST_DECLARE (semaphore_1) TEST_DECLARE (semaphore_2) TEST_DECLARE (semaphore_3) @@ -445,6 +446,7 @@ TASK_LIST_START TEST_ENTRY (condvar_3) TEST_ENTRY (condvar_4) TEST_ENTRY (condvar_5) + TEST_ENTRY (condvar_6) TEST_ENTRY (semaphore_1) TEST_ENTRY (semaphore_2) TEST_ENTRY (semaphore_3) From 89cbbc895bb459c6ab5319fa86a32a9fecbf8744 Mon Sep 17 00:00:00 2001 From: Mason X Date: Thu, 18 Jan 2018 21:04:51 -0500 Subject: [PATCH 617/632] include,src: introduce UV__ERR() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using -errno, -E**, and -pthread_function() can be error prone, and breaks compatibility with some operating systems that already negate errno's (e.g. Haiku). This commit adds a UV__ERR() macro that ensures libuv errors are negative. Fixes: https://github.com/libuv/help/issues/39 PR-URL: https://github.com/libuv/libuv/pull/1687 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno Reviewed-By: Fedor Indutny Reviewed-By: Ben Noordhuis Reviewed-By: Saúl Ibarra Corretgé --- include/uv-errno.h | 132 +++++++++++++++++++----------------- include/uv.h | 1 + src/unix/aix-common.c | 26 +++---- src/unix/aix.c | 46 ++++++------- src/unix/async.c | 8 +-- src/unix/bsd-ifaddrs.c | 4 +- src/unix/core.c | 102 ++++++++++++++-------------- src/unix/cygwin.c | 2 +- src/unix/darwin-proctitle.c | 13 ++-- src/unix/darwin.c | 24 +++---- src/unix/freebsd.c | 34 +++++----- src/unix/fs.c | 28 ++++---- src/unix/fsevents.c | 26 +++---- src/unix/getaddrinfo.c | 10 +-- src/unix/getnameinfo.c | 2 +- src/unix/ibmi.c | 2 +- src/unix/internal.h | 1 + src/unix/kqueue.c | 8 +-- src/unix/linux-core.c | 34 +++++----- src/unix/linux-inotify.c | 10 +-- src/unix/loop-watcher.c | 2 +- src/unix/netbsd.c | 28 ++++---- src/unix/no-fsevents.c | 6 +- src/unix/no-proctitle.c | 2 +- src/unix/openbsd.c | 32 ++++----- src/unix/os390.c | 38 +++++------ src/unix/pipe.c | 30 ++++---- src/unix/poll.c | 4 +- src/unix/posix-poll.c | 4 +- src/unix/process.c | 40 +++++------ src/unix/procfs-exepath.c | 4 +- src/unix/proctitle.c | 4 +- src/unix/signal.c | 4 +- src/unix/stream.c | 76 ++++++++++----------- src/unix/sunos.c | 42 ++++++------ src/unix/tcp.c | 46 ++++++------- src/unix/thread.c | 52 +++++++------- src/unix/timer.c | 4 +- src/unix/tty.c | 16 ++--- src/unix/udp.c | 76 ++++++++++----------- src/uv-common.h | 6 ++ test/test-ipc-send-recv.c | 2 +- 42 files changed, 524 insertions(+), 507 deletions(-) diff --git a/include/uv-errno.h b/include/uv-errno.h index 8a4153314..aa4d4509f 100644 --- a/include/uv-errno.h +++ b/include/uv-errno.h @@ -23,6 +23,11 @@ #define UV_ERRNO_H_ #include +#if EDOM > 0 +# define UV__ERR(x) (-(x)) +#else +# define UV__ERR(x) (x) +#endif #define UV__EOF (-4095) #define UV__UNKNOWN (-4094) @@ -46,355 +51,355 @@ * a fairly common practice for Windows programmers to redefine errno codes. */ #if defined(E2BIG) && !defined(_WIN32) -# define UV__E2BIG (-E2BIG) +# define UV__E2BIG UV__ERR(E2BIG) #else # define UV__E2BIG (-4093) #endif #if defined(EACCES) && !defined(_WIN32) -# define UV__EACCES (-EACCES) +# define UV__EACCES UV__ERR(EACCES) #else # define UV__EACCES (-4092) #endif #if defined(EADDRINUSE) && !defined(_WIN32) -# define UV__EADDRINUSE (-EADDRINUSE) +# define UV__EADDRINUSE UV__ERR(EADDRINUSE) #else # define UV__EADDRINUSE (-4091) #endif #if defined(EADDRNOTAVAIL) && !defined(_WIN32) -# define UV__EADDRNOTAVAIL (-EADDRNOTAVAIL) +# define UV__EADDRNOTAVAIL UV__ERR(EADDRNOTAVAIL) #else # define UV__EADDRNOTAVAIL (-4090) #endif #if defined(EAFNOSUPPORT) && !defined(_WIN32) -# define UV__EAFNOSUPPORT (-EAFNOSUPPORT) +# define UV__EAFNOSUPPORT UV__ERR(EAFNOSUPPORT) #else # define UV__EAFNOSUPPORT (-4089) #endif #if defined(EAGAIN) && !defined(_WIN32) -# define UV__EAGAIN (-EAGAIN) +# define UV__EAGAIN UV__ERR(EAGAIN) #else # define UV__EAGAIN (-4088) #endif #if defined(EALREADY) && !defined(_WIN32) -# define UV__EALREADY (-EALREADY) +# define UV__EALREADY UV__ERR(EALREADY) #else # define UV__EALREADY (-4084) #endif #if defined(EBADF) && !defined(_WIN32) -# define UV__EBADF (-EBADF) +# define UV__EBADF UV__ERR(EBADF) #else # define UV__EBADF (-4083) #endif #if defined(EBUSY) && !defined(_WIN32) -# define UV__EBUSY (-EBUSY) +# define UV__EBUSY UV__ERR(EBUSY) #else # define UV__EBUSY (-4082) #endif #if defined(ECANCELED) && !defined(_WIN32) -# define UV__ECANCELED (-ECANCELED) +# define UV__ECANCELED UV__ERR(ECANCELED) #else # define UV__ECANCELED (-4081) #endif #if defined(ECHARSET) && !defined(_WIN32) -# define UV__ECHARSET (-ECHARSET) +# define UV__ECHARSET UV__ERR(ECHARSET) #else # define UV__ECHARSET (-4080) #endif #if defined(ECONNABORTED) && !defined(_WIN32) -# define UV__ECONNABORTED (-ECONNABORTED) +# define UV__ECONNABORTED UV__ERR(ECONNABORTED) #else # define UV__ECONNABORTED (-4079) #endif #if defined(ECONNREFUSED) && !defined(_WIN32) -# define UV__ECONNREFUSED (-ECONNREFUSED) +# define UV__ECONNREFUSED UV__ERR(ECONNREFUSED) #else # define UV__ECONNREFUSED (-4078) #endif #if defined(ECONNRESET) && !defined(_WIN32) -# define UV__ECONNRESET (-ECONNRESET) +# define UV__ECONNRESET UV__ERR(ECONNRESET) #else # define UV__ECONNRESET (-4077) #endif #if defined(EDESTADDRREQ) && !defined(_WIN32) -# define UV__EDESTADDRREQ (-EDESTADDRREQ) +# define UV__EDESTADDRREQ UV__ERR(EDESTADDRREQ) #else # define UV__EDESTADDRREQ (-4076) #endif #if defined(EEXIST) && !defined(_WIN32) -# define UV__EEXIST (-EEXIST) +# define UV__EEXIST UV__ERR(EEXIST) #else # define UV__EEXIST (-4075) #endif #if defined(EFAULT) && !defined(_WIN32) -# define UV__EFAULT (-EFAULT) +# define UV__EFAULT UV__ERR(EFAULT) #else # define UV__EFAULT (-4074) #endif #if defined(EHOSTUNREACH) && !defined(_WIN32) -# define UV__EHOSTUNREACH (-EHOSTUNREACH) +# define UV__EHOSTUNREACH UV__ERR(EHOSTUNREACH) #else # define UV__EHOSTUNREACH (-4073) #endif #if defined(EINTR) && !defined(_WIN32) -# define UV__EINTR (-EINTR) +# define UV__EINTR UV__ERR(EINTR) #else # define UV__EINTR (-4072) #endif #if defined(EINVAL) && !defined(_WIN32) -# define UV__EINVAL (-EINVAL) +# define UV__EINVAL UV__ERR(EINVAL) #else # define UV__EINVAL (-4071) #endif #if defined(EIO) && !defined(_WIN32) -# define UV__EIO (-EIO) +# define UV__EIO UV__ERR(EIO) #else # define UV__EIO (-4070) #endif #if defined(EISCONN) && !defined(_WIN32) -# define UV__EISCONN (-EISCONN) +# define UV__EISCONN UV__ERR(EISCONN) #else # define UV__EISCONN (-4069) #endif #if defined(EISDIR) && !defined(_WIN32) -# define UV__EISDIR (-EISDIR) +# define UV__EISDIR UV__ERR(EISDIR) #else # define UV__EISDIR (-4068) #endif #if defined(ELOOP) && !defined(_WIN32) -# define UV__ELOOP (-ELOOP) +# define UV__ELOOP UV__ERR(ELOOP) #else # define UV__ELOOP (-4067) #endif #if defined(EMFILE) && !defined(_WIN32) -# define UV__EMFILE (-EMFILE) +# define UV__EMFILE UV__ERR(EMFILE) #else # define UV__EMFILE (-4066) #endif #if defined(EMSGSIZE) && !defined(_WIN32) -# define UV__EMSGSIZE (-EMSGSIZE) +# define UV__EMSGSIZE UV__ERR(EMSGSIZE) #else # define UV__EMSGSIZE (-4065) #endif #if defined(ENAMETOOLONG) && !defined(_WIN32) -# define UV__ENAMETOOLONG (-ENAMETOOLONG) +# define UV__ENAMETOOLONG UV__ERR(ENAMETOOLONG) #else # define UV__ENAMETOOLONG (-4064) #endif #if defined(ENETDOWN) && !defined(_WIN32) -# define UV__ENETDOWN (-ENETDOWN) +# define UV__ENETDOWN UV__ERR(ENETDOWN) #else # define UV__ENETDOWN (-4063) #endif #if defined(ENETUNREACH) && !defined(_WIN32) -# define UV__ENETUNREACH (-ENETUNREACH) +# define UV__ENETUNREACH UV__ERR(ENETUNREACH) #else # define UV__ENETUNREACH (-4062) #endif #if defined(ENFILE) && !defined(_WIN32) -# define UV__ENFILE (-ENFILE) +# define UV__ENFILE UV__ERR(ENFILE) #else # define UV__ENFILE (-4061) #endif #if defined(ENOBUFS) && !defined(_WIN32) -# define UV__ENOBUFS (-ENOBUFS) +# define UV__ENOBUFS UV__ERR(ENOBUFS) #else # define UV__ENOBUFS (-4060) #endif #if defined(ENODEV) && !defined(_WIN32) -# define UV__ENODEV (-ENODEV) +# define UV__ENODEV UV__ERR(ENODEV) #else # define UV__ENODEV (-4059) #endif #if defined(ENOENT) && !defined(_WIN32) -# define UV__ENOENT (-ENOENT) +# define UV__ENOENT UV__ERR(ENOENT) #else # define UV__ENOENT (-4058) #endif #if defined(ENOMEM) && !defined(_WIN32) -# define UV__ENOMEM (-ENOMEM) +# define UV__ENOMEM UV__ERR(ENOMEM) #else # define UV__ENOMEM (-4057) #endif #if defined(ENONET) && !defined(_WIN32) -# define UV__ENONET (-ENONET) +# define UV__ENONET UV__ERR(ENONET) #else # define UV__ENONET (-4056) #endif #if defined(ENOSPC) && !defined(_WIN32) -# define UV__ENOSPC (-ENOSPC) +# define UV__ENOSPC UV__ERR(ENOSPC) #else # define UV__ENOSPC (-4055) #endif #if defined(ENOSYS) && !defined(_WIN32) -# define UV__ENOSYS (-ENOSYS) +# define UV__ENOSYS UV__ERR(ENOSYS) #else # define UV__ENOSYS (-4054) #endif #if defined(ENOTCONN) && !defined(_WIN32) -# define UV__ENOTCONN (-ENOTCONN) +# define UV__ENOTCONN UV__ERR(ENOTCONN) #else # define UV__ENOTCONN (-4053) #endif #if defined(ENOTDIR) && !defined(_WIN32) -# define UV__ENOTDIR (-ENOTDIR) +# define UV__ENOTDIR UV__ERR(ENOTDIR) #else # define UV__ENOTDIR (-4052) #endif #if defined(ENOTEMPTY) && !defined(_WIN32) -# define UV__ENOTEMPTY (-ENOTEMPTY) +# define UV__ENOTEMPTY UV__ERR(ENOTEMPTY) #else # define UV__ENOTEMPTY (-4051) #endif #if defined(ENOTSOCK) && !defined(_WIN32) -# define UV__ENOTSOCK (-ENOTSOCK) +# define UV__ENOTSOCK UV__ERR(ENOTSOCK) #else # define UV__ENOTSOCK (-4050) #endif #if defined(ENOTSUP) && !defined(_WIN32) -# define UV__ENOTSUP (-ENOTSUP) +# define UV__ENOTSUP UV__ERR(ENOTSUP) #else # define UV__ENOTSUP (-4049) #endif #if defined(EPERM) && !defined(_WIN32) -# define UV__EPERM (-EPERM) +# define UV__EPERM UV__ERR(EPERM) #else # define UV__EPERM (-4048) #endif #if defined(EPIPE) && !defined(_WIN32) -# define UV__EPIPE (-EPIPE) +# define UV__EPIPE UV__ERR(EPIPE) #else # define UV__EPIPE (-4047) #endif #if defined(EPROTO) && !defined(_WIN32) -# define UV__EPROTO (-EPROTO) +# define UV__EPROTO UV__ERR(EPROTO) #else -# define UV__EPROTO (-4046) +# define UV__EPROTO UV__ERR(4046) #endif #if defined(EPROTONOSUPPORT) && !defined(_WIN32) -# define UV__EPROTONOSUPPORT (-EPROTONOSUPPORT) +# define UV__EPROTONOSUPPORT UV__ERR(EPROTONOSUPPORT) #else # define UV__EPROTONOSUPPORT (-4045) #endif #if defined(EPROTOTYPE) && !defined(_WIN32) -# define UV__EPROTOTYPE (-EPROTOTYPE) +# define UV__EPROTOTYPE UV__ERR(EPROTOTYPE) #else # define UV__EPROTOTYPE (-4044) #endif #if defined(EROFS) && !defined(_WIN32) -# define UV__EROFS (-EROFS) +# define UV__EROFS UV__ERR(EROFS) #else # define UV__EROFS (-4043) #endif #if defined(ESHUTDOWN) && !defined(_WIN32) -# define UV__ESHUTDOWN (-ESHUTDOWN) +# define UV__ESHUTDOWN UV__ERR(ESHUTDOWN) #else # define UV__ESHUTDOWN (-4042) #endif #if defined(ESPIPE) && !defined(_WIN32) -# define UV__ESPIPE (-ESPIPE) +# define UV__ESPIPE UV__ERR(ESPIPE) #else # define UV__ESPIPE (-4041) #endif #if defined(ESRCH) && !defined(_WIN32) -# define UV__ESRCH (-ESRCH) +# define UV__ESRCH UV__ERR(ESRCH) #else # define UV__ESRCH (-4040) #endif #if defined(ETIMEDOUT) && !defined(_WIN32) -# define UV__ETIMEDOUT (-ETIMEDOUT) +# define UV__ETIMEDOUT UV__ERR(ETIMEDOUT) #else # define UV__ETIMEDOUT (-4039) #endif #if defined(ETXTBSY) && !defined(_WIN32) -# define UV__ETXTBSY (-ETXTBSY) +# define UV__ETXTBSY UV__ERR(ETXTBSY) #else # define UV__ETXTBSY (-4038) #endif #if defined(EXDEV) && !defined(_WIN32) -# define UV__EXDEV (-EXDEV) +# define UV__EXDEV UV__ERR(EXDEV) #else # define UV__EXDEV (-4037) #endif #if defined(EFBIG) && !defined(_WIN32) -# define UV__EFBIG (-EFBIG) +# define UV__EFBIG UV__ERR(EFBIG) #else # define UV__EFBIG (-4036) #endif #if defined(ENOPROTOOPT) && !defined(_WIN32) -# define UV__ENOPROTOOPT (-ENOPROTOOPT) +# define UV__ENOPROTOOPT UV__ERR(ENOPROTOOPT) #else # define UV__ENOPROTOOPT (-4035) #endif #if defined(ERANGE) && !defined(_WIN32) -# define UV__ERANGE (-ERANGE) +# define UV__ERANGE UV__ERR(ERANGE) #else # define UV__ERANGE (-4034) #endif #if defined(ENXIO) && !defined(_WIN32) -# define UV__ENXIO (-ENXIO) +# define UV__ENXIO UV__ERR(ENXIO) #else # define UV__ENXIO (-4033) #endif #if defined(EMLINK) && !defined(_WIN32) -# define UV__EMLINK (-EMLINK) +# define UV__EMLINK UV__ERR(EMLINK) #else # define UV__EMLINK (-4032) #endif @@ -404,7 +409,7 @@ * icky to hard-code it. */ #if defined(EHOSTDOWN) && !defined(_WIN32) -# define UV__EHOSTDOWN (-EHOSTDOWN) +# define UV__EHOSTDOWN UV__ERR(EHOSTDOWN) #elif defined(__APPLE__) || \ defined(__DragonFly__) || \ defined(__FreeBSD__) || \ @@ -417,15 +422,16 @@ #endif #if defined(EREMOTEIO) && !defined(_WIN32) -# define UV__EREMOTEIO (-EREMOTEIO) +# define UV__EREMOTEIO UV__ERR(EREMOTEIO) #else # define UV__EREMOTEIO (-4030) #endif #if defined(ENOTTY) && !defined(_WIN32) -# define UV__ENOTTY (-ENOTTY) +# define UV__ENOTTY UV__ERR(ENOTTY) #else # define UV__ENOTTY (-4029) #endif + #endif /* UV_ERRNO_H_ */ diff --git a/include/uv.h b/include/uv.h index 3a061132c..9794d9969 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1559,6 +1559,7 @@ UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data); #undef UV_SIGNAL_PRIVATE_FIELDS #undef UV_LOOP_PRIVATE_FIELDS #undef UV_LOOP_PRIVATE_PLATFORM_FIELDS +#undef UV__ERR #ifdef __cplusplus } diff --git a/src/unix/aix-common.c b/src/unix/aix-common.c index 2cfe8be6f..e17e44948 100644 --- a/src/unix/aix-common.c +++ b/src/unix/aix-common.c @@ -83,12 +83,12 @@ int uv_exepath(char* buffer, size_t* size) { struct procsinfo pi; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; pi.pi_pid = getpid(); res = getargs(&pi, sizeof(pi), args, sizeof(args)); if (res < 0) - return -EINVAL; + return UV_EINVAL; /* * Possibilities for args: @@ -101,7 +101,7 @@ int uv_exepath(char* buffer, size_t* size) { /* Case i) and ii) absolute or relative paths */ if (strchr(args, '/') != NULL) { if (realpath(args, abspath) != abspath) - return -errno; + return UV__ERR(errno); abspath_size = strlen(abspath); @@ -121,11 +121,11 @@ int uv_exepath(char* buffer, size_t* size) { char *path = getenv("PATH"); if (path == NULL) - return -EINVAL; + return UV_EINVAL; clonedpath = uv__strdup(path); if (clonedpath == NULL) - return -ENOMEM; + return UV_ENOMEM; token = strtok(clonedpath, ":"); while (token != NULL) { @@ -151,7 +151,7 @@ int uv_exepath(char* buffer, size_t* size) { uv__free(clonedpath); /* Out of tokens (path entries), and no match found */ - return -EINVAL; + return UV_EINVAL; } } @@ -177,19 +177,19 @@ int uv_interface_addresses(uv_interface_address_t** addresses, *count = 0; if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { - return -errno; + return UV__ERR(errno); } if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { uv__close(sockfd); - return -errno; + return UV__ERR(errno); } ifc.ifc_req = (struct ifreq*)uv__malloc(size); ifc.ifc_len = size; if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { uv__close(sockfd); - return -errno; + return UV__ERR(errno); } #define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) @@ -208,7 +208,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { uv__close(sockfd); - return -errno; + return UV__ERR(errno); } if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) @@ -221,7 +221,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); if (!(*addresses)) { uv__close(sockfd); - return -ENOMEM; + return UV_ENOMEM; } address = *addresses; @@ -240,7 +240,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { uv__close(sockfd); - return -ENOSYS; + return UV_ENOSYS; } if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) @@ -260,7 +260,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) { uv__close(sockfd); - return -ENOSYS; + return UV_ENOSYS; } if (inet6) diff --git a/src/unix/aix.c b/src/unix/aix.c index fd413090f..92de81483 100644 --- a/src/unix/aix.c +++ b/src/unix/aix.c @@ -119,7 +119,7 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { pc.fd = fd; if (pollset_ctl(loop->backend_fd, &pc, 1)) - return -errno; + return UV__ERR(errno); pc.cmd = PS_DELETE; if (pollset_ctl(loop->backend_fd, &pc, 1)) @@ -409,22 +409,22 @@ static int uv__is_ahafs_mounted(void){ p = uv__malloc(siz); if (p == NULL) - return -errno; + return UV__ERR(errno); /* Retrieve all mounted filesystems */ rv = mntctl(MCTL_QUERY, siz, (char*)p); if (rv < 0) - return -errno; + return UV__ERR(errno); if (rv == 0) { /* buffer was not large enough, reallocate to correct size */ siz = *(int*)p; uv__free(p); p = uv__malloc(siz); if (p == NULL) - return -errno; + return UV__ERR(errno); rv = mntctl(MCTL_QUERY, siz, (char*)p); if (rv < 0) - return -errno; + return UV__ERR(errno); } /* Look for dev in filesystems mount info */ @@ -495,7 +495,7 @@ static int uv__make_subdirs_p(const char *filename) { rc = uv__makedir_p(cmd); if (rc == -1 && errno != EEXIST){ - return -errno; + return UV__ERR(errno); } return rc; @@ -522,7 +522,7 @@ static int uv__setup_ahafs(const char* filename, int *fd) { sprintf(mon_file, "/aha/fs/modFile.monFactory"); if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX) - return -ENAMETOOLONG; + return UV_ENAMETOOLONG; /* Make the necessary subdirectories for the monitor file */ rc = uv__make_subdirs_p(filename); @@ -537,7 +537,7 @@ static int uv__setup_ahafs(const char* filename, int *fd) { /* Open the monitor file, creating it if necessary */ *fd = open(mon_file, O_CREAT|O_RDWR); if (*fd < 0) - return -errno; + return UV__ERR(errno); /* Write out the monitoring specifications. * In this case, we are monitoring for a state change event type @@ -558,7 +558,7 @@ static int uv__setup_ahafs(const char* filename, int *fd) { rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1); if (rc < 0) - return -errno; + return UV__ERR(errno); return 0; } @@ -716,7 +716,7 @@ 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; #else - return -ENOSYS; + return UV_ENOSYS; #endif } @@ -771,7 +771,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, return 0; #else - return -ENOSYS; + return UV_ENOSYS; #endif } @@ -796,7 +796,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { return 0; #else - return -ENOSYS; + return UV_ENOSYS; #endif } @@ -861,7 +861,7 @@ int uv_set_process_title(const char* title) { */ new_title = uv__strdup(title); if (new_title == NULL) - return -ENOMEM; + return UV_ENOMEM; uv_once(&process_title_mutex_once, init_process_title_mutex_once); uv_mutex_lock(&process_title_mutex); @@ -888,9 +888,9 @@ int uv_get_process_title(char* buffer, size_t size) { size_t len; len = strlen(process_argv[0]); if (buffer == NULL || size == 0) - return -EINVAL; + return UV_EINVAL; else if (size <= len) - return -ENOBUFS; + return UV_ENOBUFS; uv_once(&process_title_mutex_once, init_process_title_mutex_once); uv_mutex_lock(&process_title_mutex); @@ -919,10 +919,10 @@ int uv_resident_set_memory(size_t* rss) { fd = open(pp, O_RDONLY); if (fd == -1) - return -errno; + return UV__ERR(errno); /* FIXME(bnoordhuis) Handle EINTR. */ - err = -EINVAL; + err = UV_EINVAL; if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) { *rss = (size_t)psinfo.pr_rssize * 1024; err = 0; @@ -953,7 +953,7 @@ int uv_uptime(double* uptime) { endutent(); if (boot_time == 0) - return -ENOSYS; + return UV_ENOSYS; *uptime = time(NULL) - boot_time; return 0; @@ -969,30 +969,30 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1); if (result == -1) { - return -ENOSYS; + return UV_ENOSYS; } ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0); if (result == -1) { - return -ENOSYS; + return UV_ENOSYS; } ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t)); if (!ps_cpus) { - return -ENOMEM; + return UV_ENOMEM; } strcpy(cpu_id.name, FIRST_CPU); result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus); if (result == -1) { uv__free(ps_cpus); - return -ENOSYS; + return UV_ENOSYS; } *cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t)); if (!*cpu_infos) { uv__free(ps_cpus); - return -ENOMEM; + return UV_ENOMEM; } *count = ncpus; diff --git a/src/unix/async.c b/src/unix/async.c index 45c088ea1..0b450ae0d 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -166,7 +166,7 @@ static int uv__async_start(uv_loop_t* loop) { pipefd[0] = err; pipefd[1] = -1; } - else if (err == -ENOSYS) { + else if (err == UV_ENOSYS) { err = uv__make_pipe(pipefd, UV__F_NONBLOCK); #if defined(__linux__) /* Save a file descriptor by opening one of the pipe descriptors as @@ -240,7 +240,7 @@ static int uv__async_eventfd(void) { return fd; if (errno != ENOSYS) - return -errno; + return UV__ERR(errno); no_eventfd2 = 1; @@ -257,7 +257,7 @@ static int uv__async_eventfd(void) { } if (errno != ENOSYS) - return -errno; + return UV__ERR(errno); no_eventfd = 1; @@ -265,5 +265,5 @@ static int uv__async_eventfd(void) { #endif - return -ENOSYS; + return UV_ENOSYS; } diff --git a/src/unix/bsd-ifaddrs.c b/src/unix/bsd-ifaddrs.c index ea3166c5e..0d0215448 100644 --- a/src/unix/bsd-ifaddrs.c +++ b/src/unix/bsd-ifaddrs.c @@ -70,7 +70,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { int i; if (getifaddrs(&addrs) != 0) - return -errno; + return UV__ERR(errno); *count = 0; @@ -85,7 +85,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (*addresses == NULL) { freeifaddrs(addrs); - return -ENOMEM; + return UV_ENOMEM; } address = *addresses; diff --git a/src/unix/core.c b/src/unix/core.c index c7e431e52..3741c1d06 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -191,14 +191,14 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { socklen_t len; if (handle == NULL || value == NULL) - return -EINVAL; + return UV_EINVAL; if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE) fd = uv__stream_fd((uv_stream_t*) handle); else if (handle->type == UV_UDP) fd = ((uv_udp_t *) handle)->io_watcher.fd; else - return -ENOTSUP; + return UV_ENOTSUP; len = sizeof(*value); @@ -208,7 +208,7 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len); if (r < 0) - return -errno; + return UV__ERR(errno); return 0; } @@ -418,12 +418,12 @@ int uv__socket(int domain, int type, int protocol) { return sockfd; if (errno != EINVAL) - return -errno; + return UV__ERR(errno); #endif sockfd = socket(domain, type, protocol); if (sockfd == -1) - return -errno; + return UV__ERR(errno); err = uv__nonblock(sockfd, 1); if (err == 0) @@ -487,7 +487,7 @@ int uv__accept(int sockfd) { continue; if (errno != ENOSYS) - return -errno; + return UV__ERR(errno); no_accept4 = 1; skip: @@ -497,7 +497,7 @@ int uv__accept(int sockfd) { if (peerfd == -1) { if (errno == EINTR) continue; - return -errno; + return UV__ERR(errno); } err = uv__cloexec(peerfd, 1); @@ -523,8 +523,8 @@ int uv__close_nocheckstdio(int fd) { saved_errno = errno; rc = close(fd); if (rc == -1) { - rc = -errno; - if (rc == -EINTR || rc == -EINPROGRESS) + rc = UV__ERR(errno); + if (rc == UV_EINTR || rc == UV__ERR(EINPROGRESS)) rc = 0; /* The close is in progress, not an error. */ errno = saved_errno; } @@ -550,7 +550,7 @@ int uv__nonblock_ioctl(int fd, int set) { while (r == -1 && errno == EINTR); if (r) - return -errno; + return UV__ERR(errno); return 0; } @@ -565,7 +565,7 @@ int uv__cloexec_ioctl(int fd, int set) { while (r == -1 && errno == EINTR); if (r) - return -errno; + return UV__ERR(errno); return 0; } @@ -581,7 +581,7 @@ int uv__nonblock_fcntl(int fd, int set) { while (r == -1 && errno == EINTR); if (r == -1) - return -errno; + return UV__ERR(errno); /* Bail out now if already set/clear. */ if (!!(r & O_NONBLOCK) == !!set) @@ -597,7 +597,7 @@ int uv__nonblock_fcntl(int fd, int set) { while (r == -1 && errno == EINTR); if (r) - return -errno; + return UV__ERR(errno); return 0; } @@ -612,7 +612,7 @@ int uv__cloexec_fcntl(int fd, int set) { while (r == -1 && errno == EINTR); if (r == -1) - return -errno; + return UV__ERR(errno); /* Bail out now if already set/clear. */ if (!!(r & FD_CLOEXEC) == !!set) @@ -628,7 +628,7 @@ int uv__cloexec_fcntl(int fd, int set) { while (r == -1 && errno == EINTR); if (r) - return -errno; + return UV__ERR(errno); return 0; } @@ -643,7 +643,7 @@ int uv__dup(int fd) { fd = dup(fd); if (fd == -1) - return -errno; + return UV__ERR(errno); err = uv__cloexec(fd, 1); if (err) { @@ -667,10 +667,10 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { if (rc != -1) return rc; if (errno != EINVAL) - return -errno; + return UV__ERR(errno); rc = recvmsg(fd, msg, flags); if (rc == -1) - return -errno; + return UV__ERR(errno); no_msg_cmsg_cloexec = 1; } else { rc = recvmsg(fd, msg, flags); @@ -679,7 +679,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { rc = recvmsg(fd, msg, flags); #endif if (rc == -1) - return -errno; + return UV__ERR(errno); if (msg->msg_controllen == 0) return rc; for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) @@ -695,10 +695,10 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { int uv_cwd(char* buffer, size_t* size) { if (buffer == NULL || size == NULL) - return -EINVAL; + return UV_EINVAL; if (getcwd(buffer, *size) == NULL) - return -errno; + return UV__ERR(errno); *size = strlen(buffer); if (*size > 1 && buffer[*size - 1] == '/') { @@ -712,7 +712,7 @@ int uv_cwd(char* buffer, size_t* size) { int uv_chdir(const char* dir) { if (chdir(dir)) - return -errno; + return UV__ERR(errno); return 0; } @@ -749,11 +749,11 @@ int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) { break; default: - return -EINVAL; + return UV_EINVAL; } if (uv__is_closing(handle) || fd_out == -1) - return -EBADF; + return UV_EBADF; *fd = fd_out; return 0; @@ -931,7 +931,7 @@ int uv_getrusage(uv_rusage_t* rusage) { struct rusage usage; if (getrusage(RUSAGE_SELF, &usage)) - return -errno; + return UV__ERR(errno); rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec; rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec; @@ -973,7 +973,7 @@ int uv__open_cloexec(const char* path, int flags) { return fd; if (errno != EINVAL) - return -errno; + return UV__ERR(errno); /* O_CLOEXEC not supported. */ no_cloexec = 1; @@ -982,7 +982,7 @@ int uv__open_cloexec(const char* path, int flags) { fd = open(path, flags); if (fd == -1) - return -errno; + return UV__ERR(errno); err = uv__cloexec(fd, 1); if (err) { @@ -999,14 +999,14 @@ int uv__dup2_cloexec(int oldfd, int newfd) { #if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__) r = dup3(oldfd, newfd, O_CLOEXEC); if (r == -1) - return -errno; + return UV__ERR(errno); return r; #elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC) r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); if (r != -1) return r; if (errno != EINVAL) - return -errno; + return UV__ERR(errno); /* Fall through. */ #elif defined(__linux__) static int no_dup3; @@ -1017,7 +1017,7 @@ int uv__dup2_cloexec(int oldfd, int newfd) { if (r != -1) return r; if (errno != ENOSYS) - return -errno; + return UV__ERR(errno); /* Fall through. */ no_dup3 = 1; } @@ -1033,7 +1033,7 @@ int uv__dup2_cloexec(int oldfd, int newfd) { #endif if (r == -1) - return -errno; + return UV__ERR(errno); err = uv__cloexec(newfd, 1); if (err) { @@ -1053,7 +1053,7 @@ int uv_os_homedir(char* buffer, size_t* size) { int r; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; /* Check if the HOME environment variable is set first */ buf = getenv("HOME"); @@ -1063,7 +1063,7 @@ int uv_os_homedir(char* buffer, size_t* size) { if (len >= *size) { *size = len + 1; - return -ENOBUFS; + return UV_ENOBUFS; } memcpy(buffer, buf, len + 1); @@ -1084,7 +1084,7 @@ int uv_os_homedir(char* buffer, size_t* size) { if (len >= *size) { *size = len + 1; uv_os_free_passwd(&pwd); - return -ENOBUFS; + return UV_ENOBUFS; } memcpy(buffer, pwd.homedir, len + 1); @@ -1100,7 +1100,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) { size_t len; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; #define CHECK_ENV_VAR(name) \ do { \ @@ -1130,7 +1130,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) { if (len >= *size) { *size = len + 1; - return -ENOBUFS; + return UV_ENOBUFS; } /* The returned directory should not have a trailing slash. */ @@ -1162,11 +1162,11 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); if (getpwuid_r == NULL) - return -ENOSYS; + return UV_ENOSYS; #endif if (pwd == NULL) - return -EINVAL; + return UV_EINVAL; initsize = sysconf(_SC_GETPW_R_SIZE_MAX); @@ -1183,7 +1183,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { buf = uv__malloc(bufsize); if (buf == NULL) - return -ENOMEM; + return UV_ENOMEM; r = getpwuid_r(uid, &pw, buf, bufsize, &result); @@ -1200,7 +1200,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { if (result == NULL) { uv__free(buf); - return -ENOENT; + return UV_ENOENT; } /* Allocate memory for the username, shell, and home directory */ @@ -1211,7 +1211,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { if (pwd->username == NULL) { uv__free(buf); - return -ENOMEM; + return UV_ENOMEM; } /* Copy the username */ @@ -1267,18 +1267,18 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { size_t len; if (name == NULL || buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; var = getenv(name); if (var == NULL) - return -ENOENT; + return UV_ENOENT; len = strlen(var); if (len >= *size) { *size = len + 1; - return -ENOBUFS; + return UV_ENOBUFS; } memcpy(buffer, var, len + 1); @@ -1290,10 +1290,10 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { int uv_os_setenv(const char* name, const char* value) { if (name == NULL || value == NULL) - return -EINVAL; + return UV_EINVAL; if (setenv(name, value, 1) != 0) - return -errno; + return UV__ERR(errno); return 0; } @@ -1301,10 +1301,10 @@ int uv_os_setenv(const char* name, const char* value) { int uv_os_unsetenv(const char* name) { if (name == NULL) - return -EINVAL; + return UV_EINVAL; if (unsetenv(name) != 0) - return -errno; + return UV__ERR(errno); return 0; } @@ -1321,17 +1321,17 @@ int uv_os_gethostname(char* buffer, size_t* size) { size_t len; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; if (gethostname(buf, sizeof(buf)) != 0) - return -errno; + return UV__ERR(errno); buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ len = strlen(buf); if (len >= *size) { *size = len + 1; - return -ENOBUFS; + return UV_ENOBUFS; } memcpy(buffer, buf, len + 1); diff --git a/src/unix/cygwin.c b/src/unix/cygwin.c index 5a887dd4c..9fe4093ef 100644 --- a/src/unix/cygwin.c +++ b/src/unix/cygwin.c @@ -29,7 +29,7 @@ int uv_uptime(double* uptime) { struct sysinfo info; if (sysinfo(&info) < 0) - return -errno; + return UV__ERR(errno); *uptime = info.uptime; return 0; diff --git a/src/unix/darwin-proctitle.c b/src/unix/darwin-proctitle.c index 114231160..dabde2239 100644 --- a/src/unix/darwin-proctitle.c +++ b/src/unix/darwin-proctitle.c @@ -18,6 +18,9 @@ * IN THE SOFTWARE. */ +#include "uv.h" +#include "internal.h" + #include #include #include @@ -41,14 +44,14 @@ static int uv__pthread_setname_np(const char* name) { dlsym(RTLD_DEFAULT, "pthread_setname_np"); if (dynamic_pthread_setname_np == NULL) - return -ENOSYS; + return UV_ENOSYS; strncpy(namebuf, name, sizeof(namebuf) - 1); namebuf[sizeof(namebuf) - 1] = '\0'; err = dynamic_pthread_setname_np(namebuf); if (err) - return -err; + return UV__ERR(err); return 0; } @@ -84,7 +87,7 @@ int uv__set_process_title(const char* title) { CFTypeRef asn; int err; - err = -ENOENT; + err = UV_ENOENT; application_services_handle = dlopen("/System/Library/Frameworks/" "ApplicationServices.framework/" "Versions/A/ApplicationServices", @@ -151,7 +154,7 @@ int uv__set_process_title(const char* title) { /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */ hi_services_bundle = pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices")); - err = -ENOENT; + err = UV_ENOENT; if (hi_services_bundle == NULL) goto out; @@ -182,7 +185,7 @@ int uv__set_process_title(const char* title) { asn = pLSGetCurrentApplicationASN(); - err = -EINVAL; + err = UV_EINVAL; if (pLSSetApplicationInformationItem(-2, /* Magic value. */ asn, *display_name_key, diff --git a/src/unix/darwin.c b/src/unix/darwin.c index df6dd1c61..31ad8a9e4 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -37,7 +37,7 @@ int uv__platform_loop_init(uv_loop_t* loop) { loop->cf_state = NULL; if (uv__kqueue_init(loop)) - return -errno; + return UV__ERR(errno); return 0; } @@ -68,18 +68,18 @@ int uv_exepath(char* buffer, size_t* size) { size_t abspath_size; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; exepath_size = sizeof(exepath); if (_NSGetExecutablePath(exepath, &exepath_size)) - return -EIO; + return UV_EIO; if (realpath(exepath, abspath) != abspath) - return -errno; + return UV__ERR(errno); abspath_size = strlen(abspath); if (abspath_size == 0) - return -EIO; + return UV_EIO; *size -= 1; if (*size > abspath_size) @@ -98,7 +98,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 -EINVAL; /* FIXME(bnoordhuis) Translate error. */ + return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */ } return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE); @@ -111,7 +111,7 @@ uint64_t uv_get_total_memory(void) { size_t size = sizeof(info); if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); return (uint64_t) info; } @@ -158,7 +158,7 @@ int uv_uptime(double* uptime) { static int which[] = {CTL_KERN, KERN_BOOTTIME}; if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); now = time(NULL); *uptime = now - info.tv_sec; @@ -181,23 +181,23 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(model); if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) && sysctlbyname("hw.model", &model, &size, NULL, 0)) { - return -errno; + return UV__ERR(errno); } size = sizeof(cpuspeed); if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus, (processor_info_array_t*)&info, &msg_type) != KERN_SUCCESS) { - return -EINVAL; /* FIXME(bnoordhuis) Translate error. */ + return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */ } *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); if (!(*cpu_infos)) { vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type); - return -ENOMEM; + return UV_ENOMEM; } *count = numcpus; diff --git a/src/unix/freebsd.c b/src/unix/freebsd.c index f2b3f247a..70ccb1304 100644 --- a/src/unix/freebsd.c +++ b/src/unix/freebsd.c @@ -72,11 +72,11 @@ int uv_exepath(char* buffer, size_t* size) { ssize_t abspath_size; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath)); if (abspath_size < 0) - return -errno; + return UV__ERR(errno); assert(abspath_size > 0); *size -= 1; @@ -96,7 +96,7 @@ int uv_exepath(char* buffer, size_t* size) { size_t abspath_size; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; mib[0] = CTL_KERN; mib[1] = KERN_PROC; @@ -105,7 +105,7 @@ int uv_exepath(char* buffer, size_t* size) { abspath_size = sizeof abspath; if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0)) - return -errno; + return UV__ERR(errno); assert(abspath_size > 0); abspath_size -= 1; @@ -126,7 +126,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 -errno; + return UV__ERR(errno); return (uint64_t) freecount * sysconf(_SC_PAGESIZE); @@ -140,7 +140,7 @@ uint64_t uv_get_total_memory(void) { size_t size = sizeof(info); if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); return (uint64_t) info; } @@ -176,7 +176,7 @@ int uv_set_process_title(const char* title) { if (process_title == NULL) { uv_mutex_unlock(&process_title_mutex); - return -ENOMEM; + return UV_ENOMEM; } uv__free(process_title); @@ -204,7 +204,7 @@ int uv_get_process_title(char* buffer, size_t size) { size_t len; if (buffer == NULL || size == 0) - return -EINVAL; + return UV_EINVAL; uv_once(&process_title_mutex_once, init_process_title_mutex_once); uv_mutex_lock(&process_title_mutex); @@ -214,7 +214,7 @@ int uv_get_process_title(char* buffer, size_t size) { if (size < len) { uv_mutex_unlock(&process_title_mutex); - return -ENOBUFS; + return UV_ENOBUFS; } memcpy(buffer, process_title, len); @@ -243,7 +243,7 @@ int uv_resident_set_memory(size_t* rss) { kinfo_size = sizeof(kinfo); if (sysctl(mib, 4, &kinfo, &kinfo_size, NULL, 0)) - return -errno; + return UV__ERR(errno); page_size = getpagesize(); @@ -262,7 +262,7 @@ int uv_uptime(double* uptime) { struct timespec sp; r = clock_gettime(CLOCK_MONOTONIC, &sp); if (r) - return -errno; + return UV__ERR(errno); *uptime = sp.tv_sec; return 0; @@ -309,15 +309,15 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(model); if (sysctlbyname(model_key, &model, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); size = sizeof(numcpus); if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); if (!(*cpu_infos)) - return -ENOMEM; + return UV_ENOMEM; *count = numcpus; @@ -327,7 +327,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(maxcpus); if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) { uv__free(*cpu_infos); - return -errno; + return UV__ERR(errno); } size = maxcpus * CPUSTATES * sizeof(long); @@ -335,13 +335,13 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { cp_times = uv__malloc(size); if (cp_times == NULL) { uv__free(*cpu_infos); - return -ENOMEM; + return UV_ENOMEM; } if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { uv__free(cp_times); uv__free(*cpu_infos); - return -errno; + return UV__ERR(errno); } for (i = 0; i < numcpus; i++) { diff --git a/src/unix/fs.c b/src/unix/fs.c index e0969a4c2..46071c564 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -67,7 +67,7 @@ #define INIT(subtype) \ do { \ if (req == NULL) \ - return -EINVAL; \ + return UV_EINVAL; \ req->type = UV_FS; \ if (cb != NULL) \ uv__req_init(loop, req, UV_FS); \ @@ -90,7 +90,7 @@ req->path = uv__strdup(path); \ if (req->path == NULL) { \ uv__req_unregister(loop, req); \ - return -ENOMEM; \ + return UV_ENOMEM; \ } \ } \ } \ @@ -109,7 +109,7 @@ req->path = uv__malloc(path_len + new_path_len); \ if (req->path == NULL) { \ uv__req_unregister(loop, req); \ - return -ENOMEM; \ + return UV_ENOMEM; \ } \ req->new_path = req->path + path_len; \ memcpy((void*) req->path, path, path_len); \ @@ -818,7 +818,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { /* Get the source file's mode. */ if (fstat(srcfd, &statsbuf)) { - err = -errno; + err = UV__ERR(errno); goto out; } @@ -842,7 +842,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { } if (fchmod(dstfd, statsbuf.st_mode) == -1) { - err = -errno; + err = UV__ERR(errno); goto out; } @@ -1107,7 +1107,7 @@ static void uv__fs_work(struct uv__work* w) { } while (r == -1 && errno == EINTR && retry_on_eintr); if (r == -1) - req->result = -errno; + req->result = UV__ERR(errno); else req->result = r; @@ -1125,9 +1125,9 @@ static void uv__fs_done(struct uv__work* w, int status) { req = container_of(w, uv_fs_t, work_req); uv__req_unregister(req->loop, req); - if (status == -ECANCELED) { + if (status == UV_ECANCELED) { assert(req->result == 0); - req->result = -ECANCELED; + req->result = UV_ECANCELED; } req->cb(req); @@ -1291,7 +1291,7 @@ int uv_fs_mkdtemp(uv_loop_t* loop, if (req->path == NULL) { if (cb != NULL) uv__req_unregister(loop, req); - return -ENOMEM; + return UV_ENOMEM; } POST; } @@ -1320,7 +1320,7 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, INIT(READ); if (bufs == NULL || nbufs == 0) - return -EINVAL; + return UV_EINVAL; req->file = file; @@ -1332,7 +1332,7 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, if (req->bufs == NULL) { if (cb != NULL) uv__req_unregister(loop, req); - return -ENOMEM; + return UV_ENOMEM; } memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); @@ -1459,7 +1459,7 @@ int uv_fs_write(uv_loop_t* loop, INIT(WRITE); if (bufs == NULL || nbufs == 0) - return -EINVAL; + return UV_EINVAL; req->file = file; @@ -1471,7 +1471,7 @@ int uv_fs_write(uv_loop_t* loop, if (req->bufs == NULL) { if (cb != NULL) uv__req_unregister(loop, req); - return -ENOMEM; + return UV_ENOMEM; } memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); @@ -1514,7 +1514,7 @@ int uv_fs_copyfile(uv_loop_t* loop, INIT(COPYFILE); if (flags & ~UV_FS_COPYFILE_EXCL) - return -EINVAL; + return UV_EINVAL; PATH2; req->flags = flags; diff --git a/src/unix/fsevents.c b/src/unix/fsevents.c index 38837406a..47d8024b6 100644 --- a/src/unix/fsevents.c +++ b/src/unix/fsevents.c @@ -379,7 +379,7 @@ static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { if (!pFSEventStreamStart(ref)) { pFSEventStreamInvalidate(ref); pFSEventStreamRelease(ref); - return -EMFILE; + return UV_EMFILE; } state->fsevent_stream = ref; @@ -440,7 +440,7 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle, uv__fsevents_destroy_stream(handle->loop); /* Any failure below will be a memory failure */ - err = -ENOMEM; + err = UV_ENOMEM; /* Create list of all watched paths */ uv_mutex_lock(&state->fsevent_mutex); @@ -474,7 +474,7 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle, /* Create new FSEventStream */ cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL); if (cf_paths == NULL) { - err = -ENOMEM; + err = UV_ENOMEM; goto final; } err = uv__fsevents_create_stream(handle->loop, cf_paths); @@ -528,7 +528,7 @@ static int uv__fsevents_global_init(void) { * but if it ever becomes one, we can turn the dynamic library handles into * per-event loop properties and have the dynamic linker keep track for us. */ - err = -ENOSYS; + err = UV_ENOSYS; core_foundation_handle = dlopen("/System/Library/Frameworks/" "CoreFoundation.framework/" "Versions/A/CoreFoundation", @@ -543,7 +543,7 @@ static int uv__fsevents_global_init(void) { if (core_services_handle == NULL) goto out; - err = -ENOENT; + err = UV_ENOENT; #define V(handle, symbol) \ do { \ *(void **)(&p ## symbol) = dlsym((handle), #symbol); \ @@ -607,7 +607,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) { state = uv__calloc(1, sizeof(*state)); if (state == NULL) - return -ENOMEM; + return UV_ENOMEM; err = uv_mutex_init(&loop->cf_mutex); if (err) @@ -636,7 +636,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) { ctx.perform = uv__cf_loop_cb; state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx); if (state->signal_source == NULL) { - err = -ENOMEM; + err = UV_ENOMEM; goto fail_signal_source_create; } @@ -655,7 +655,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) { loop->cf_state = state; /* uv_thread_t is an alias for pthread_t. */ - err = -pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop); + err = UV__ERR(pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop)); if (attr != NULL) pthread_attr_destroy(attr); @@ -787,7 +787,7 @@ int uv__cf_loop_signal(uv_loop_t* loop, item = uv__malloc(sizeof(*item)); if (item == NULL) - return -ENOMEM; + return UV_ENOMEM; item->handle = handle; item->type = type; @@ -817,7 +817,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) { /* Get absolute path to file */ handle->realpath = realpath(handle->path, NULL); if (handle->realpath == NULL) - return -errno; + return UV__ERR(errno); handle->realpath_len = strlen(handle->realpath); /* Initialize event queue */ @@ -830,7 +830,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) { */ handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb)); if (handle->cf_cb == NULL) { - err = -ENOMEM; + err = UV_ENOMEM; goto fail_cf_cb_malloc; } @@ -881,7 +881,7 @@ int uv__fsevents_close(uv_fs_event_t* handle) { uv__cf_loop_state_t* state; if (handle->cf_cb == NULL) - return -EINVAL; + return UV_EINVAL; /* Remove handle from the list */ state = handle->loop->cf_state; @@ -895,7 +895,7 @@ int uv__fsevents_close(uv_fs_event_t* handle) { assert(handle != NULL); err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing); if (err) - return -err; + return UV__ERR(err); /* Wait for deinitialization */ uv_sem_wait(&state->fsevent_sem); diff --git a/src/unix/getaddrinfo.c b/src/unix/getaddrinfo.c index 018597169..10e8afd75 100644 --- a/src/unix/getaddrinfo.c +++ b/src/unix/getaddrinfo.c @@ -86,7 +86,7 @@ int uv__getaddrinfo_translate_error(int sys_err) { case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE; #endif #if defined(EAI_SYSTEM) - case EAI_SYSTEM: return -errno; + case EAI_SYSTEM: return UV__ERR(errno); #endif } assert(!"unknown EAI_* error code"); @@ -125,7 +125,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { req->service = NULL; req->hostname = NULL; - if (status == -ECANCELED) { + if (status == UV_ECANCELED) { assert(req->retcode == 0); req->retcode = UV_EAI_CANCELED; } @@ -148,7 +148,7 @@ int uv_getaddrinfo(uv_loop_t* loop, char* buf; if (req == NULL || (hostname == NULL && service == NULL)) - return -EINVAL; + return UV_EINVAL; hostname_len = hostname ? strlen(hostname) + 1 : 0; service_len = service ? strlen(service) + 1 : 0; @@ -156,7 +156,7 @@ int uv_getaddrinfo(uv_loop_t* loop, buf = uv__malloc(hostname_len + service_len + hints_len); if (buf == NULL) - return -ENOMEM; + return UV_ENOMEM; uv__req_init(loop, req, UV_GETADDRINFO); req->loop = loop; @@ -211,7 +211,7 @@ int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { return UV_EINVAL; if (if_indextoname(ifindex, ifname_buf) == NULL) - return -errno; + return UV__ERR(errno); len = strnlen(ifname_buf, sizeof(ifname_buf)); diff --git a/src/unix/getnameinfo.c b/src/unix/getnameinfo.c index daa798a45..9a4367224 100644 --- a/src/unix/getnameinfo.c +++ b/src/unix/getnameinfo.c @@ -61,7 +61,7 @@ static void uv__getnameinfo_done(struct uv__work* w, int status) { uv__req_unregister(req->loop, req); host = service = NULL; - if (status == -ECANCELED) { + if (status == UV_ECANCELED) { assert(req->retcode == 0); req->retcode = UV_EAI_CANCELED; } else if (req->retcode == 0) { diff --git a/src/unix/ibmi.c b/src/unix/ibmi.c index 8380d02db..c50a4e76f 100644 --- a/src/unix/ibmi.c +++ b/src/unix/ibmi.c @@ -92,7 +92,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { *cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t)); if (!*cpu_infos) { - return -ENOMEM; + return UV_ENOMEM; } cpu_info = *cpu_infos; diff --git a/src/unix/internal.h b/src/unix/internal.h index 3df5c4c3e..2bb3773c0 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -29,6 +29,7 @@ #include /* strrchr */ #include /* O_CLOEXEC, may be */ #include +#include #if defined(__STRICT_ANSI__) # define inline __inline diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 5e89bdced..a30fd730f 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -51,7 +51,7 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags); int uv__kqueue_init(uv_loop_t* loop) { loop->backend_fd = kqueue(); if (loop->backend_fd == -1) - return -errno; + return UV__ERR(errno); uv__cloexec(loop->backend_fd, 1); @@ -98,7 +98,7 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { rc = 0; EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) - rc = -errno; + rc = UV__ERR(errno); EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); if (rc == 0) @@ -458,12 +458,12 @@ int uv_fs_event_start(uv_fs_event_t* handle, int fd; if (uv__is_active(handle)) - return -EINVAL; + return UV_EINVAL; /* TODO open asynchronously - but how do we report back errors? */ fd = open(path, O_RDONLY); if (fd == -1) - return -errno; + return UV__ERR(errno); uv__handle_start(handle); uv__io_init(&handle->event_watcher, uv__fs_event, fd); diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 4d480ce10..b63c25f3c 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -101,7 +101,7 @@ int uv__platform_loop_init(uv_loop_t* loop) { loop->inotify_watchers = NULL; if (fd == -1) - return -errno; + return UV__ERR(errno); return 0; } @@ -175,7 +175,7 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { rc = 0; if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e)) if (errno != EEXIST) - rc = -errno; + rc = UV__ERR(errno); if (rc == 0) if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e)) @@ -485,7 +485,7 @@ int uv_resident_set_memory(size_t* rss) { while (fd == -1 && errno == EINTR); if (fd == -1) - return -errno; + return UV__ERR(errno); do n = read(fd, buf, sizeof(buf) - 1); @@ -493,7 +493,7 @@ int uv_resident_set_memory(size_t* rss) { uv__close(fd); if (n == -1) - return -errno; + return UV__ERR(errno); buf[n] = '\0'; s = strchr(buf, ' '); @@ -525,7 +525,7 @@ int uv_resident_set_memory(size_t* rss) { return 0; err: - return -EINVAL; + return UV_EINVAL; } @@ -547,7 +547,7 @@ int uv_uptime(double* uptime) { } if (r) - return -errno; + return UV__ERR(errno); *uptime = now.tv_sec; return 0; @@ -559,7 +559,7 @@ static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { char buf[1024]; if (!fgets(buf, sizeof(buf), statfile_fp)) - return -EIO; + return UV_EIO; num = 0; while (fgets(buf, sizeof(buf), statfile_fp)) { @@ -569,7 +569,7 @@ static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { } if (num == 0) - return -EIO; + return UV_EIO; *numcpus = num; return 0; @@ -587,13 +587,13 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { statfile_fp = uv__open_file("/proc/stat"); if (statfile_fp == NULL) - return -errno; + return UV__ERR(errno); err = uv__cpu_num(statfile_fp, &numcpus); if (err < 0) goto out; - err = -ENOMEM; + err = UV_ENOMEM; ci = uv__calloc(numcpus, sizeof(*ci)); if (ci == NULL) goto out; @@ -667,7 +667,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { defined(__x86_64__) fp = uv__open_file("/proc/cpuinfo"); if (fp == NULL) - return -errno; + return UV__ERR(errno); while (fgets(buf, sizeof(buf), fp)) { if (model_idx < numcpus) { @@ -676,7 +676,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */ if (model == NULL) { fclose(fp); - return -ENOMEM; + return UV_ENOMEM; } ci[model_idx++].model = model; continue; @@ -695,7 +695,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */ if (model == NULL) { fclose(fp); - return -ENOMEM; + return UV_ENOMEM; } ci[model_idx++].model = model; continue; @@ -725,7 +725,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { while (model_idx < numcpus) { model = uv__strndup(inferred_model, strlen(inferred_model)); if (model == NULL) - return -ENOMEM; + return UV_ENOMEM; ci[model_idx++].model = model; } @@ -854,7 +854,7 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #ifndef HAVE_IFADDRS_H - return -ENOSYS; + return UV_ENOSYS; #else struct ifaddrs *addrs, *ent; uv_interface_address_t* address; @@ -862,7 +862,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, struct sockaddr_ll *sll; if (getifaddrs(&addrs)) - return -errno; + return UV__ERR(errno); *count = 0; *addresses = NULL; @@ -881,7 +881,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, *addresses = uv__malloc(*count * sizeof(**addresses)); if (!(*addresses)) { freeifaddrs(addrs); - return -ENOMEM; + return UV_ENOMEM; } address = *addresses; diff --git a/src/unix/linux-inotify.c b/src/unix/linux-inotify.c index 5934c5d8c..bcad630fa 100644 --- a/src/unix/linux-inotify.c +++ b/src/unix/linux-inotify.c @@ -73,11 +73,11 @@ static int new_inotify_fd(void) { return fd; if (errno != ENOSYS) - return -errno; + return UV__ERR(errno); fd = uv__inotify_init(); if (fd == -1) - return -errno; + return UV__ERR(errno); err = uv__cloexec(fd, 1); if (err == 0) @@ -283,7 +283,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, int wd; if (uv__is_active(handle)) - return -EINVAL; + return UV_EINVAL; err = init_inotify(handle->loop); if (err) @@ -300,7 +300,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events); if (wd == -1) - return -errno; + return UV__ERR(errno); w = find_watcher(handle->loop, wd); if (w) @@ -308,7 +308,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, w = uv__malloc(sizeof(*w) + strlen(path) + 1); if (w == NULL) - return -ENOMEM; + return UV_ENOMEM; w->wd = wd; w->path = strcpy((char*)(w + 1), path); diff --git a/src/unix/loop-watcher.c b/src/unix/loop-watcher.c index 340bb0dfa..b8c1c2a71 100644 --- a/src/unix/loop-watcher.c +++ b/src/unix/loop-watcher.c @@ -31,7 +31,7 @@ \ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ if (uv__is_active(handle)) return 0; \ - if (cb == NULL) return -EINVAL; \ + if (cb == NULL) return UV_EINVAL; \ QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \ handle->name##_cb = cb; \ uv__handle_start(handle); \ diff --git a/src/unix/netbsd.c b/src/unix/netbsd.c index 742507233..2605c114b 100644 --- a/src/unix/netbsd.c +++ b/src/unix/netbsd.c @@ -82,7 +82,7 @@ int uv_exepath(char* buffer, size_t* size) { int mib[4]; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; mib[0] = CTL_KERN; mib[1] = KERN_PROC_ARGS; @@ -91,7 +91,7 @@ int uv_exepath(char* buffer, size_t* size) { int_size = ARRAY_SIZE(int_buf); if (sysctl(mib, 4, int_buf, &int_size, NULL, 0)) - return -errno; + return UV__ERR(errno); /* Copy string from the intermediate buffer to outer one with appropriate * length. @@ -111,7 +111,7 @@ uint64_t uv_get_free_memory(void) { int which[] = {CTL_VM, VM_UVMEXP}; if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); 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, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); return (uint64_t) info; } @@ -150,7 +150,7 @@ int uv_set_process_title(const char* title) { if (process_title == NULL) { uv_mutex_unlock(&process_title_mutex); - return -ENOMEM; + return UV_ENOMEM; } uv__free(process_title); @@ -167,7 +167,7 @@ int uv_get_process_title(char* buffer, size_t size) { size_t len; if (buffer == NULL || size == 0) - return -EINVAL; + return UV_EINVAL; uv_once(&process_title_mutex_once, init_process_title_mutex_once); uv_mutex_lock(&process_title_mutex); @@ -177,7 +177,7 @@ int uv_get_process_title(char* buffer, size_t size) { if (size < len) { uv_mutex_unlock(&process_title_mutex); - return -ENOBUFS; + return UV_ENOBUFS; } memcpy(buffer, process_title, len); @@ -219,7 +219,7 @@ int uv_resident_set_memory(size_t* rss) { error: if (kd) kvm_close(kd); - return -EPERM; + return UV_EPERM; } @@ -230,7 +230,7 @@ int uv_uptime(double* uptime) { static int which[] = {CTL_KERN, KERN_BOOTTIME}; if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); now = time(NULL); @@ -254,12 +254,12 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(model); if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) && sysctlbyname("hw.model", &model, &size, NULL, 0)) { - return -errno; + return UV__ERR(errno); } size = sizeof(numcpus); if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); *count = numcpus; /* Only i386 and amd64 have machdep.tsc_freq */ @@ -270,16 +270,16 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = numcpus * CPUSTATES * sizeof(*cp_times); cp_times = uv__malloc(size); if (cp_times == NULL) - return -ENOMEM; + return UV_ENOMEM; if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); if (!(*cpu_infos)) { uv__free(cp_times); uv__free(*cpu_infos); - return -ENOMEM; + return UV_ENOMEM; } for (i = 0; i < numcpus; i++) { diff --git a/src/unix/no-fsevents.c b/src/unix/no-fsevents.c index 38fb6ab0b..158643af1 100644 --- a/src/unix/no-fsevents.c +++ b/src/unix/no-fsevents.c @@ -25,16 +25,16 @@ #include int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { - return -ENOSYS; + return UV_ENOSYS; } int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* filename, unsigned int flags) { - return -ENOSYS; + return UV_ENOSYS; } int uv_fs_event_stop(uv_fs_event_t* handle) { - return -ENOSYS; + return UV_ENOSYS; } void uv__fs_event_close(uv_fs_event_t* handle) { diff --git a/src/unix/no-proctitle.c b/src/unix/no-proctitle.c index a5c19fbff..165740ca3 100644 --- a/src/unix/no-proctitle.c +++ b/src/unix/no-proctitle.c @@ -35,7 +35,7 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { if (buffer == NULL || size == 0) - return -EINVAL; + return UV_EINVAL; buffer[0] = '\0'; return 0; diff --git a/src/unix/openbsd.c b/src/unix/openbsd.c index c0ffa564b..ce937cd3e 100644 --- a/src/unix/openbsd.c +++ b/src/unix/openbsd.c @@ -78,11 +78,11 @@ int uv_exepath(char* buffer, size_t* size) { int err; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; mypid = getpid(); for (;;) { - err = -ENOMEM; + err = UV_ENOMEM; argsbuf_tmp = uv__realloc(argsbuf, argsbuf_size); if (argsbuf_tmp == NULL) goto out; @@ -95,14 +95,14 @@ int uv_exepath(char* buffer, size_t* size) { break; } if (errno != ENOMEM) { - err = -errno; + err = UV__ERR(errno); goto out; } argsbuf_size *= 2U; } if (argsbuf[0] == NULL) { - err = -EINVAL; /* FIXME(bnoordhuis) More appropriate error. */ + err = UV_EINVAL; /* FIXME(bnoordhuis) More appropriate error. */ goto out; } @@ -128,7 +128,7 @@ uint64_t uv_get_free_memory(void) { int which[] = {CTL_VM, VM_UVMEXP}; if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); return (uint64_t) info.free * sysconf(_SC_PAGESIZE); } @@ -140,7 +140,7 @@ uint64_t uv_get_total_memory(void) { size_t size = sizeof(info); if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); return (uint64_t) info; } @@ -162,7 +162,7 @@ int uv_set_process_title(const char* title) { if (process_title == NULL) { uv_mutex_unlock(&process_title_mutex); - return -ENOMEM; + return UV_ENOMEM; } uv__free(process_title); @@ -179,7 +179,7 @@ int uv_get_process_title(char* buffer, size_t size) { size_t len; if (buffer == NULL || size == 0) - return -EINVAL; + return UV_EINVAL; uv_once(&process_title_mutex_once, init_process_title_mutex_once); uv_mutex_lock(&process_title_mutex); @@ -189,7 +189,7 @@ int uv_get_process_title(char* buffer, size_t size) { if (size < len) { uv_mutex_unlock(&process_title_mutex); - return -ENOBUFS; + return UV_ENOBUFS; } memcpy(buffer, process_title, len); @@ -219,7 +219,7 @@ int uv_resident_set_memory(size_t* rss) { mib[5] = 1; if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0) - return -errno; + return UV__ERR(errno); *rss = kinfo.p_vm_rssize * page_size; return 0; @@ -233,7 +233,7 @@ int uv_uptime(double* uptime) { static int which[] = {CTL_KERN, KERN_BOOTTIME}; if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); now = time(NULL); @@ -255,16 +255,16 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(model); if (sysctl(which, 2, &model, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); which[1] = HW_NCPU; size = sizeof(numcpus); if (sysctl(which, 2, &numcpus, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); if (!(*cpu_infos)) - return -ENOMEM; + return UV_ENOMEM; *count = numcpus; @@ -272,7 +272,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(cpuspeed); if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { uv__free(*cpu_infos); - return -errno; + return UV__ERR(errno); } size = sizeof(info); @@ -283,7 +283,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(info); if (sysctl(which, 3, &info, &size, NULL, 0)) { uv__free(*cpu_infos); - return -errno; + return UV__ERR(errno); } cpu_info = &(*cpu_infos)[i]; diff --git a/src/unix/os390.c b/src/unix/os390.c index 081438e8e..f766b3933 100644 --- a/src/unix/os390.c +++ b/src/unix/os390.c @@ -122,7 +122,7 @@ int uv__platform_loop_init(uv_loop_t* loop) { ep = epoll_create1(0); loop->ep = ep; if (ep == NULL) - return -errno; + return UV__ERR(errno); return 0; } @@ -259,12 +259,12 @@ int uv_exepath(char* buffer, size_t* size) { int pid; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; pid = getpid(); res = getexe(pid, args, sizeof(args)); if (res < 0) - return -EINVAL; + return UV_EINVAL; /* * Possibilities for args: @@ -277,7 +277,7 @@ int uv_exepath(char* buffer, size_t* size) { /* Case i) and ii) absolute or relative paths */ if (strchr(args, '/') != NULL) { if (realpath(args, abspath) != abspath) - return -errno; + return UV__ERR(errno); abspath_size = strlen(abspath); @@ -297,11 +297,11 @@ int uv_exepath(char* buffer, size_t* size) { char* path = getenv("PATH"); if (path == NULL) - return -EINVAL; + return UV_EINVAL; clonedpath = uv__strdup(path); if (clonedpath == NULL) - return -ENOMEM; + return UV_ENOMEM; token = strtok(clonedpath, ":"); while (token != NULL) { @@ -327,7 +327,7 @@ int uv_exepath(char* buffer, size_t* size) { uv__free(clonedpath); /* Out of tokens (path entries), and no match found */ - return -EINVAL; + return UV_EINVAL; } } @@ -407,7 +407,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { *cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t)); if (!*cpu_infos) - return -ENOMEM; + return UV_ENOMEM; cpu_info = *cpu_infos; idx = 0; @@ -452,7 +452,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, maxsize = 16384; if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) - return -errno; + return UV__ERR(errno); ifc.__nif6h_version = 1; ifc.__nif6h_buflen = maxsize; @@ -460,7 +460,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) { uv__close(sockfd); - return -errno; + return UV__ERR(errno); } @@ -484,7 +484,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); if (!(*addresses)) { uv__close(sockfd); - return -ENOMEM; + return UV_ENOMEM; } address = *addresses; @@ -543,13 +543,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (0 > sockfd) - return -errno; + return UV__ERR(errno); ifc.ifc_req = uv__calloc(1, maxsize); ifc.ifc_len = maxsize; if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { uv__close(sockfd); - return -errno; + return UV__ERR(errno); } #define MAX(a,b) (((a)>(b))?(a):(b)) @@ -569,7 +569,7 @@ 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__close(sockfd); - return -errno; + return UV__ERR(errno); } if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) @@ -584,7 +584,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { if (!(*addresses)) { uv__close(sockfd); - return -ENOMEM; + return UV_ENOMEM; } address = *addresses; @@ -607,7 +607,7 @@ 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__close(sockfd); - return -ENOSYS; + return UV_ENOSYS; } if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) @@ -706,7 +706,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, int rc; if (uv__is_active(handle)) - return -EINVAL; + return UV_EINVAL; ep = handle->loop->ep; assert(ep->msg_queue != -1); @@ -718,11 +718,11 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, path = uv__strdup(filename); if (path == NULL) - return -ENOMEM; + return UV_ENOMEM; rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); if (rc != 0) - return -errno; + return UV__ERR(errno); uv__handle_start(handle); handle->path = path; diff --git a/src/unix/pipe.c b/src/unix/pipe.c index ac7cfb46a..e640bf29f 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -50,12 +50,12 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { /* Already bound? */ if (uv__stream_fd(handle) >= 0) - return -EINVAL; + 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 -ENOMEM; + return UV_ENOMEM; /* We've got a copy, don't touch the original any more. */ name = NULL; @@ -71,10 +71,10 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { saddr.sun_family = AF_UNIX; if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { - err = -errno; + err = UV__ERR(errno); /* Convert ENOENT to EACCES for compatibility with Windows. */ - if (err == -ENOENT) - err = -EACCES; + if (err == UV_ENOENT) + err = UV_EACCES; uv__close(sockfd); goto err_socket; @@ -94,7 +94,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) { if (uv__stream_fd(handle) == -1) - return -EINVAL; + return UV_EINVAL; #if defined(__MVS__) /* On zOS, backlog=0 has undefined behaviour */ @@ -105,7 +105,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { #endif if (listen(uv__stream_fd(handle), backlog)) - return -errno; + return UV__ERR(errno); handle->connection_cb = cb; handle->io_watcher.cb = uv__server_io; @@ -180,14 +180,14 @@ void uv_pipe_connect(uv_connect_t* req, while (r == -1 && errno == EINTR); if (r == -1 && errno != EINPROGRESS) { - err = -errno; + err = UV__ERR(errno); #if defined(__CYGWIN__) || defined(__MSYS__) /* EBADF is supposed to mean that the socket fd is bad, but Cygwin reports EBADF instead of ENOTSOCK when the file is not a socket. We do not expect to see a bad fd here (e.g. due to new_sock), so translate the error. */ - if (err == -EBADF) - err = -ENOTSOCK; + if (err == UV_EBADF) + err = UV_ENOTSOCK; #endif goto out; } @@ -234,7 +234,7 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, err = func(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen); if (err < 0) { *size = 0; - return -errno; + return UV__ERR(errno); } #if defined(__linux__) @@ -312,15 +312,15 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { int r; if (handle == NULL || uv__stream_fd(handle) == -1) - return -EBADF; + return UV_EBADF; if (mode != UV_READABLE && mode != UV_WRITABLE && mode != (UV_WRITABLE | UV_READABLE)) - return -EINVAL; + return UV_EINVAL; if (fstat(uv__stream_fd(handle), &pipe_stat) == -1) - return -errno; + return UV__ERR(errno); desired_mode = 0; if (mode & UV_READABLE) @@ -353,5 +353,5 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { r = chmod(name_buffer, pipe_stat.st_mode); uv__free(name_buffer); - return r != -1 ? 0 : -errno; + return r != -1 ? 0 : UV__ERR(errno); } diff --git a/src/unix/poll.c b/src/unix/poll.c index 816c7dc2e..f3b0bf4e4 100644 --- a/src/unix/poll.c +++ b/src/unix/poll.c @@ -47,7 +47,7 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { if ((events & POLLERR) && !(events & UV__POLLPRI)) { uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); uv__handle_stop(handle); - handle->poll_cb(handle, -EBADF, 0); + handle->poll_cb(handle, UV_EBADF, 0); return; } @@ -76,7 +76,7 @@ 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 (err == -ENOTTY) + if (err == UV_ENOTTY) if (uv__nonblock == uv__nonblock_ioctl) err = uv__nonblock_fcntl(fd, 1); diff --git a/src/unix/posix-poll.c b/src/unix/posix-poll.c index 3fba96e1b..f356e76c7 100644 --- a/src/unix/posix-poll.c +++ b/src/unix/posix-poll.c @@ -315,10 +315,10 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { while (rv == -1 && (errno == EINTR || errno == EAGAIN)); if (rv == -1) - return -errno; + return UV__ERR(errno); if (p[0].revents & POLLNVAL) - return -EINVAL; + return UV_EINVAL; return 0; } diff --git a/src/unix/process.c b/src/unix/process.c index 9842710d0..74113e3a6 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -126,7 +126,7 @@ int uv__make_socketpair(int fds[2], int flags) { * Anything else is a genuine error. */ if (errno != EINVAL) - return -errno; + return UV__ERR(errno); no_cloexec = 1; @@ -134,7 +134,7 @@ int uv__make_socketpair(int fds[2], int flags) { #endif if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) - return -errno; + return UV__ERR(errno); uv__cloexec(fds[0], 1); uv__cloexec(fds[1], 1); @@ -159,7 +159,7 @@ int uv__make_pipe(int fds[2], int flags) { return 0; if (errno != ENOSYS) - return -errno; + return UV__ERR(errno); no_pipe2 = 1; @@ -167,7 +167,7 @@ int uv__make_pipe(int fds[2], int flags) { #endif if (pipe(fds)) - return -errno; + return UV__ERR(errno); uv__cloexec(fds[0], 1); uv__cloexec(fds[1], 1); @@ -198,7 +198,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { case UV_CREATE_PIPE: assert(container->data.stream != NULL); if (container->data.stream->type != UV_NAMED_PIPE) - return -EINVAL; + return UV_EINVAL; else return uv__make_socketpair(fds, 0); @@ -210,14 +210,14 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { fd = uv__stream_fd(container->data.stream); if (fd == -1) - return -EINVAL; + return UV_EINVAL; fds[1] = fd; return 0; default: assert(0 && "Unexpected flags"); - return -EINVAL; + return UV_EINVAL; } } @@ -299,7 +299,7 @@ static void uv__process_child_init(const uv_process_options_t* options, continue; pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); if (pipes[fd][1] == -1) { - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } } @@ -319,7 +319,7 @@ static void uv__process_child_init(const uv_process_options_t* options, close_fd = use_fd; if (use_fd == -1) { - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } } @@ -331,7 +331,7 @@ static void uv__process_child_init(const uv_process_options_t* options, fd = dup2(use_fd, fd); if (fd == -1) { - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } @@ -350,7 +350,7 @@ static void uv__process_child_init(const uv_process_options_t* options, } if (options->cwd != NULL && chdir(options->cwd)) { - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } @@ -366,12 +366,12 @@ static void uv__process_child_init(const uv_process_options_t* options, } if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) { - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } @@ -391,7 +391,7 @@ 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, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } @@ -400,12 +400,12 @@ static void uv__process_child_init(const uv_process_options_t* options, err = pthread_sigmask(SIG_SETMASK, &set, NULL); if (err != 0) { - uv__write_int(error_fd, -err); + uv__write_int(error_fd, UV__ERR(err)); _exit(127); } execvp(options->file, options->args); - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } #endif @@ -416,7 +416,7 @@ int uv_spawn(uv_loop_t* loop, const uv_process_options_t* options) { #if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ - return -ENOSYS; + return UV_ENOSYS; #else int signal_pipe[2] = { -1, -1 }; int pipes_storage[8][2]; @@ -443,7 +443,7 @@ int uv_spawn(uv_loop_t* loop, if (stdio_count < 3) stdio_count = 3; - err = -ENOMEM; + err = UV_ENOMEM; pipes = pipes_storage; if (stdio_count > (int) ARRAY_SIZE(pipes_storage)) pipes = uv__malloc(stdio_count * sizeof(*pipes)); @@ -493,7 +493,7 @@ int uv_spawn(uv_loop_t* loop, pid = fork(); if (pid == -1) { - err = -errno; + err = UV__ERR(errno); uv_rwlock_wrunlock(&loop->cloexec_lock); uv__close(signal_pipe[0]); uv__close(signal_pipe[1]); @@ -585,7 +585,7 @@ int uv_process_kill(uv_process_t* process, int signum) { int uv_kill(int pid, int signum) { if (kill(pid, signum)) - return -errno; + return UV__ERR(errno); else return 0; } diff --git a/src/unix/procfs-exepath.c b/src/unix/procfs-exepath.c index 5fdb61155..00dc021f2 100644 --- a/src/unix/procfs-exepath.c +++ b/src/unix/procfs-exepath.c @@ -29,14 +29,14 @@ int uv_exepath(char* buffer, size_t* size) { ssize_t n; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; n = *size - 1; if (n > 0) n = readlink("/proc/self/exe", buffer, n); if (n == -1) - return -errno; + return UV__ERR(errno); buffer[n] = '\0'; *size = n; diff --git a/src/unix/proctitle.c b/src/unix/proctitle.c index 1b3a79882..1a8c7a709 100644 --- a/src/unix/proctitle.c +++ b/src/unix/proctitle.c @@ -105,14 +105,14 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { if (buffer == NULL || size == 0) - return -EINVAL; + return UV_EINVAL; uv_once(&process_title_mutex_once, init_process_title_mutex_once); uv_mutex_lock(&process_title_mutex); if (size <= process_title.len) { uv_mutex_unlock(&process_title_mutex); - return -ENOBUFS; + return UV_ENOBUFS; } if (process_title.len != 0) diff --git a/src/unix/signal.c b/src/unix/signal.c index 375977801..b9d0a5608 100644 --- a/src/unix/signal.c +++ b/src/unix/signal.c @@ -225,7 +225,7 @@ static int uv__signal_register_handler(int signum, int oneshot) { /* XXX save old action so we can restore it later on? */ if (sigaction(signum, &sa, NULL)) - return -errno; + return UV__ERR(errno); return 0; } @@ -362,7 +362,7 @@ static int uv__signal_start(uv_signal_t* handle, * eventually. */ if (signum == 0) - return -EINVAL; + return UV_EINVAL; /* Short circuit: if the signal watcher is already watching {signum} don't * go through the process of deregistering and registering the handler. diff --git a/src/unix/stream.c b/src/unix/stream.c index 6fc0a01f5..5aa60431e 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -282,7 +282,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { kq = kqueue(); if (kq == -1) { perror("(libuv) kqueue()"); - return -errno; + return UV__ERR(errno); } EV_SET(&filter[0], *fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); @@ -298,7 +298,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { uv__close(kq); if (ret == -1) - return -errno; + return UV__ERR(errno); if (ret == 0 || (events[0].flags & EV_ERROR) == 0 || events[0].data != EINVAL) return 0; @@ -310,7 +310,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { * NOTE: do it ahead of malloc below to allocate enough space for fd_sets */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) - return -errno; + return UV__ERR(errno); max_fd = *fd; if (fds[1] > max_fd) @@ -321,7 +321,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { s = uv__malloc(sizeof(*s) + sread_sz + swrite_sz); if (s == NULL) { - err = -ENOMEM; + err = UV_ENOMEM; goto failed_malloc; } @@ -395,18 +395,18 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { #endif if (!(stream->io_watcher.fd == -1 || stream->io_watcher.fd == fd)) - return -EBUSY; + return UV_EBUSY; assert(fd >= 0); stream->flags |= flags; if (stream->type == UV_TCP) { if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) - return -errno; + return UV__ERR(errno); /* TODO Use delay the user passed in. */ if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60)) - return -errno; + return UV__ERR(errno); } #if defined(__APPLE__) @@ -414,7 +414,7 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) && errno != ENOTSOCK && errno != EINVAL) { - return -errno; + return UV__ERR(errno); } #endif @@ -445,11 +445,11 @@ void uv__stream_destroy(uv_stream_t* stream) { if (stream->connect_req) { uv__req_unregister(stream->loop, stream->connect_req); - stream->connect_req->cb(stream->connect_req, -ECANCELED); + stream->connect_req->cb(stream->connect_req, UV_ECANCELED); stream->connect_req = NULL; } - uv__stream_flush_write_queue(stream, -ECANCELED); + uv__stream_flush_write_queue(stream, UV_ECANCELED); uv__write_callbacks(stream); if (stream->shutdown_req) { @@ -459,7 +459,7 @@ void uv__stream_destroy(uv_stream_t* stream) { * callee that the handle has been destroyed. */ uv__req_unregister(stream->loop, stream->shutdown_req); - stream->shutdown_req->cb(stream->shutdown_req, -ECANCELED); + stream->shutdown_req->cb(stream->shutdown_req, UV_ECANCELED); stream->shutdown_req = NULL; } @@ -483,7 +483,7 @@ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) { int emfile_fd; if (loop->emfile_fd == -1) - return -EMFILE; + return UV_EMFILE; uv__close(loop->emfile_fd); loop->emfile_fd = -1; @@ -492,7 +492,7 @@ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) { err = uv__accept(accept_fd); if (err >= 0) uv__close(err); - } while (err >= 0 || err == -EINTR); + } while (err >= 0 || err == UV_EINTR); emfile_fd = uv__open_cloexec("/", O_RDONLY); if (emfile_fd >= 0) @@ -533,15 +533,15 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { err = uv__accept(uv__stream_fd(stream)); if (err < 0) { - if (err == -EAGAIN || err == -EWOULDBLOCK) + if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK)) return; /* Not an error. */ - if (err == -ECONNABORTED) + if (err == UV_ECONNABORTED) continue; /* Ignore. Nothing we can do about that. */ - if (err == -EMFILE || err == -ENFILE) { + if (err == UV_EMFILE || err == UV_ENFILE) { err = uv__emfile_trick(loop, uv__stream_fd(stream)); - if (err == -EAGAIN || err == -EWOULDBLOCK) + if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK)) break; } @@ -577,7 +577,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { assert(server->loop == client->loop); if (server->accepted_fd == -1) - return -EAGAIN; + return UV_EAGAIN; switch (client->type) { case UV_NAMED_PIPE: @@ -601,7 +601,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { break; default: - return -EINVAL; + return UV_EINVAL; } client->flags |= UV_HANDLE_BOUND; @@ -649,7 +649,7 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { break; default: - err = -EINVAL; + err = UV_EINVAL; } if (err == 0) @@ -680,7 +680,7 @@ static void uv__drain(uv_stream_t* stream) { err = 0; if (shutdown(uv__stream_fd(stream), SHUT_WR)) - err = -errno; + err = UV__ERR(errno); if (err == 0) stream->flags |= UV_STREAM_SHUT; @@ -792,7 +792,7 @@ static void uv__write(uv_stream_t* stream) { } scratch; if (uv__is_closing(req->send_handle)) { - err = -EBADF; + err = UV_EBADF; goto error; } @@ -860,7 +860,7 @@ static void uv__write(uv_stream_t* stream) { if (n < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENOBUFS) { - err = -errno; + err = UV__ERR(errno); goto error; } else if (stream->flags & UV_STREAM_BLOCKING) { /* If this is a blocking stream, try again. */ @@ -1029,7 +1029,7 @@ static int uv__stream_queue_fd(uv_stream_t* stream, int fd) { queued_fds = uv__malloc((queue_size - 1) * sizeof(*queued_fds->fds) + sizeof(*queued_fds)); if (queued_fds == NULL) - return -ENOMEM; + return UV_ENOMEM; queued_fds->size = queue_size; queued_fds->offset = 0; stream->queued_fds = queued_fds; @@ -1046,7 +1046,7 @@ static int uv__stream_queue_fd(uv_stream_t* stream, int fd) { * NOTE: if it is fatal - sockets will be closed in uv__stream_close */ if (queued_fds == NULL) - return -ENOMEM; + return UV_ENOMEM; queued_fds->size = queue_size; stream->queued_fds = queued_fds; } @@ -1192,7 +1192,7 @@ static void uv__read(uv_stream_t* stream) { #endif } else { /* Error. User should call uv_close(). */ - stream->read_cb(stream, -errno, &buf); + stream->read_cb(stream, UV__ERR(errno), &buf); if (stream->flags & UV_STREAM_READING) { stream->flags &= ~UV_STREAM_READING; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); @@ -1269,7 +1269,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { stream->flags & UV_STREAM_SHUT || stream->flags & UV_STREAM_SHUTTING || uv__is_closing(stream)) { - return -ENOTCONN; + return UV_ENOTCONN; } assert(uv__stream_fd(stream) >= 0); @@ -1368,10 +1368,10 @@ static void uv__stream_connect(uv_stream_t* stream) { SO_ERROR, &error, &errorsize); - error = -error; + error = UV__ERR(error); } - if (error == -EINPROGRESS) + if (error == UV__ERR(EINPROGRESS)) return; stream->connect_req = NULL; @@ -1388,7 +1388,7 @@ static void uv__stream_connect(uv_stream_t* stream) { return; if (error < 0) { - uv__stream_flush_write_queue(stream, -ECANCELED); + uv__stream_flush_write_queue(stream, UV_ECANCELED); uv__write_callbacks(stream); } } @@ -1409,11 +1409,11 @@ int uv_write2(uv_write_t* req, "uv_write (unix) does not yet support other types of streams"); if (uv__stream_fd(stream) < 0) - return -EBADF; + return UV_EBADF; if (send_handle) { if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) - return -EINVAL; + return UV_EINVAL; /* XXX We abuse uv_write2() to send over UDP handles to child processes. * Don't call uv__stream_fd() on those handles, it's a macro that on OS X @@ -1422,12 +1422,12 @@ int uv_write2(uv_write_t* req, * which works but only by accident. */ if (uv__handle_fd((uv_handle_t*) send_handle) < 0) - return -EBADF; + return UV_EBADF; #if defined(__CYGWIN__) || defined(__MSYS__) /* Cygwin recvmsg always sets msg_controllen to zero, so we cannot send it. See https://github.com/mirror/newlib-cygwin/blob/86fc4bf0/winsup/cygwin/fhandler_socket.cc#L1736-L1743 */ - return -ENOSYS; + return UV_ENOSYS; #endif } @@ -1452,7 +1452,7 @@ int uv_write2(uv_write_t* req, req->bufs = uv__malloc(nbufs * sizeof(bufs[0])); if (req->bufs == NULL) - return -ENOMEM; + return UV_ENOMEM; memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); req->nbufs = nbufs; @@ -1516,7 +1516,7 @@ int uv_try_write(uv_stream_t* stream, /* Connecting or already writing some data */ if (stream->connect_req != NULL || stream->write_queue_size != 0) - return -EAGAIN; + return UV_EAGAIN; has_pollout = uv__io_active(&stream->io_watcher, POLLOUT); @@ -1547,7 +1547,7 @@ int uv_try_write(uv_stream_t* stream, } if (written == 0 && req_size != 0) - return -EAGAIN; + return UV_EAGAIN; else return written; } @@ -1560,7 +1560,7 @@ int uv_read_start(uv_stream_t* stream, stream->type == UV_TTY); if (stream->flags & UV_CLOSING) - return -EINVAL; + return UV_EINVAL; /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just * expresses the desired state of the user. diff --git a/src/unix/sunos.c b/src/unix/sunos.c index a72c26a01..b6b3dfea7 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -73,7 +73,7 @@ int uv__platform_loop_init(uv_loop_t* loop) { fd = port_create(); if (fd == -1) - return -errno; + return UV__ERR(errno); err = uv__cloexec(fd, 1); if (err) { @@ -132,7 +132,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { int uv__io_check_fd(uv_loop_t* loop, int fd) { if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) - return -errno; + return UV__ERR(errno); if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) abort(); @@ -342,7 +342,7 @@ int uv_exepath(char* buffer, size_t* size) { char buf[128]; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid()); @@ -351,7 +351,7 @@ int uv_exepath(char* buffer, size_t* size) { res = readlink(buf, buffer, res); if (res == -1) - return -errno; + return UV__ERR(errno); buffer[res] = '\0'; *size = res; @@ -378,14 +378,14 @@ void uv_loadavg(double avg[3]) { static int uv__fs_event_rearm(uv_fs_event_t *handle) { if (handle->fd == -1) - return -EBADF; + return UV_EBADF; if (port_associate(handle->loop->fs_fd, PORT_SOURCE_FILE, (uintptr_t) &handle->fo, FILE_ATTRIB | FILE_MODIFIED, handle) == -1) { - return -errno; + return UV__ERR(errno); } handle->fd = PORT_LOADED; @@ -462,13 +462,13 @@ int uv_fs_event_start(uv_fs_event_t* handle, int err; if (uv__is_active(handle)) - return -EINVAL; + return UV_EINVAL; first_run = 0; if (handle->loop->fs_fd == -1) { portfd = port_create(); if (portfd == -1) - return -errno; + return UV__ERR(errno); handle->loop->fs_fd = portfd; first_run = 1; } @@ -521,7 +521,7 @@ void uv__fs_event_close(uv_fs_event_t* handle) { #else /* !defined(PORT_SOURCE_FILE) */ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { - return -ENOSYS; + return UV_ENOSYS; } @@ -529,12 +529,12 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* filename, unsigned int flags) { - return -ENOSYS; + return UV_ENOSYS; } int uv_fs_event_stop(uv_fs_event_t* handle) { - return -ENOSYS; + return UV_ENOSYS; } @@ -552,10 +552,10 @@ int uv_resident_set_memory(size_t* rss) { fd = open("/proc/self/psinfo", O_RDONLY); if (fd == -1) - return -errno; + return UV__ERR(errno); /* FIXME(bnoordhuis) Handle EINTR. */ - err = -EINVAL; + err = UV_EINVAL; if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) { *rss = (size_t)psinfo.pr_rssize * 1024; err = 0; @@ -575,7 +575,7 @@ int uv_uptime(double* uptime) { kc = kstat_open(); if (kc == NULL) - return -EPERM; + return UV_EPERM; ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc"); if (kstat_read(kc, ksp, NULL) == -1) { @@ -599,7 +599,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { kc = kstat_open(); if (kc == NULL) - return -EPERM; + return UV_EPERM; /* Get count of cpus */ lookup_instance = 0; @@ -610,7 +610,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { *cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos)); if (!(*cpu_infos)) { kstat_close(kc); - return -ENOMEM; + return UV_ENOMEM; } *count = lookup_instance; @@ -692,7 +692,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { #ifdef SUNOS_NO_IFADDRS int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - return -ENOSYS; + return UV_ENOSYS; } #else /* SUNOS_NO_IFADDRS */ /* @@ -730,11 +730,11 @@ static int uv__set_phys_addr(uv_interface_address_t* address, sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) - return -errno; + return UV__ERR(errno); if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) { uv__close(sockfd); - return -errno; + return UV__ERR(errno); } memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr)); uv__close(sockfd); @@ -759,7 +759,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifaddrs* ent; if (getifaddrs(&addrs)) - return -errno; + return UV__ERR(errno); *count = 0; @@ -773,7 +773,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { *addresses = uv__malloc(*count * sizeof(**addresses)); if (!(*addresses)) { freeifaddrs(addrs); - return -ENOMEM; + return UV_ENOMEM; } address = *addresses; diff --git a/src/unix/tcp.c b/src/unix/tcp.c index c7c8d21c6..96f89312d 100644 --- a/src/unix/tcp.c +++ b/src/unix/tcp.c @@ -89,7 +89,7 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { slen = sizeof(saddr); memset(&saddr, 0, sizeof(saddr)); if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) - return -errno; + return UV__ERR(errno); if ((saddr.ss_family == AF_INET6 && ((struct sockaddr_in6*) &saddr)->sin6_port != 0) || @@ -102,7 +102,7 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { /* Bind to arbitrary port */ if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) - return -errno; + return UV__ERR(errno); } handle->flags |= flags; @@ -119,10 +119,10 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) { /* Use the lower 8 bits for the domain */ domain = flags & 0xFF; if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) - return -EINVAL; + return UV_EINVAL; if (flags & ~0xFF) - return -EINVAL; + return UV_EINVAL; uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP); @@ -156,7 +156,7 @@ int uv__tcp_bind(uv_tcp_t* tcp, /* Cannot set IPv6-only mode on non-IPv6 socket. */ if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6) - return -EINVAL; + return UV_EINVAL; err = maybe_new_socket(tcp, addr->sa_family, @@ -166,7 +166,7 @@ int uv__tcp_bind(uv_tcp_t* tcp, on = 1; if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) - return -errno; + return UV__ERR(errno); #ifdef IPV6_V6ONLY if (addr->sa_family == AF_INET6) { @@ -178,9 +178,9 @@ int uv__tcp_bind(uv_tcp_t* tcp, sizeof on) == -1) { #if defined(__MVS__) if (errno == EOPNOTSUPP) - return -EINVAL; + return UV_EINVAL; #endif - return -errno; + return UV__ERR(errno); } } #endif @@ -190,10 +190,10 @@ int uv__tcp_bind(uv_tcp_t* tcp, 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 -EINVAL; - return -errno; + return UV_EINVAL; + return UV__ERR(errno); } - tcp->delayed_error = -errno; + tcp->delayed_error = UV__ERR(errno); tcp->flags |= UV_HANDLE_BOUND; if (addr->sa_family == AF_INET6) @@ -214,7 +214,7 @@ int uv__tcp_connect(uv_connect_t* req, assert(handle->type == UV_TCP); if (handle->connect_req != NULL) - return -EALREADY; /* FIXME(bnoordhuis) -EINVAL or maybe -EBUSY. */ + return UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */ err = maybe_new_socket(handle, addr->sa_family, @@ -242,9 +242,9 @@ int uv__tcp_connect(uv_connect_t* req, * error. Solaris wants to report immediately--other unixes want to * wait. */ - handle->delayed_error = -errno; + handle->delayed_error = UV__ERR(errno); else - return -errno; + return UV__ERR(errno); } uv__req_init(handle->loop, req, UV_CONNECT); @@ -284,13 +284,13 @@ int uv_tcp_getsockname(const uv_tcp_t* handle, return handle->delayed_error; if (uv__stream_fd(handle) < 0) - return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ + return UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ /* sizeof(socklen_t) != sizeof(int) on some systems. */ socklen = (socklen_t) *namelen; if (getsockname(uv__stream_fd(handle), name, &socklen)) - return -errno; + return UV__ERR(errno); *namelen = (int) socklen; return 0; @@ -306,13 +306,13 @@ int uv_tcp_getpeername(const uv_tcp_t* handle, return handle->delayed_error; if (uv__stream_fd(handle) < 0) - return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ + return UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ /* sizeof(socklen_t) != sizeof(int) on some systems. */ socklen = (socklen_t) *namelen; if (getpeername(uv__stream_fd(handle), name, &socklen)) - return -errno; + return UV__ERR(errno); *namelen = (int) socklen; return 0; @@ -348,7 +348,7 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { return err; if (listen(tcp->io_watcher.fd, backlog)) - return -errno; + return UV__ERR(errno); tcp->connection_cb = cb; tcp->flags |= UV_HANDLE_BOUND; @@ -363,18 +363,18 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { int uv__tcp_nodelay(int fd, int on) { if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on))) - return -errno; + return UV__ERR(errno); return 0; } int uv__tcp_keepalive(int fd, int on, unsigned int delay) { if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) - return -errno; + return UV__ERR(errno); #ifdef TCP_KEEPIDLE if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) - return -errno; + return UV__ERR(errno); #endif /* Solaris/SmartOS, if you don't support keep-alive, @@ -383,7 +383,7 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { /* 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))) - return -errno; + return UV__ERR(errno); #endif return 0; diff --git a/src/unix/thread.c b/src/unix/thread.c index abaca295d..8229c2759 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -200,7 +200,7 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { if (attr != NULL) pthread_attr_destroy(attr); - return -err; + return UV__ERR(err); } @@ -209,7 +209,7 @@ uv_thread_t uv_thread_self(void) { } int uv_thread_join(uv_thread_t *tid) { - return -pthread_join(*tid, NULL); + return UV__ERR(pthread_join(*tid, NULL)); } @@ -220,7 +220,7 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { int uv_mutex_init(uv_mutex_t* mutex) { #if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK) - return -pthread_mutex_init(mutex, NULL); + return UV__ERR(pthread_mutex_init(mutex, NULL)); #else pthread_mutexattr_t attr; int err; @@ -236,7 +236,7 @@ int uv_mutex_init(uv_mutex_t* mutex) { if (pthread_mutexattr_destroy(&attr)) abort(); - return -err; + return UV__ERR(err); #endif } @@ -256,7 +256,7 @@ int uv_mutex_init_recursive(uv_mutex_t* mutex) { if (pthread_mutexattr_destroy(&attr)) abort(); - return -err; + return UV__ERR(err); } @@ -279,7 +279,7 @@ int uv_mutex_trylock(uv_mutex_t* mutex) { if (err) { if (err != EBUSY && err != EAGAIN) abort(); - return -EBUSY; + return UV_EBUSY; } return 0; @@ -293,7 +293,7 @@ void uv_mutex_unlock(uv_mutex_t* mutex) { int uv_rwlock_init(uv_rwlock_t* rwlock) { - return -pthread_rwlock_init(rwlock, NULL); + return UV__ERR(pthread_rwlock_init(rwlock, NULL)); } @@ -316,7 +316,7 @@ int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { if (err) { if (err != EBUSY && err != EAGAIN) abort(); - return -EBUSY; + return UV_EBUSY; } return 0; @@ -342,7 +342,7 @@ int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { if (err) { if (err != EBUSY && err != EAGAIN) abort(); - return -EBUSY; + return UV_EBUSY; } return 0; @@ -369,12 +369,12 @@ int uv_sem_init(uv_sem_t* sem, unsigned int value) { if (err == KERN_SUCCESS) return 0; if (err == KERN_INVALID_ARGUMENT) - return -EINVAL; + return UV_EINVAL; if (err == KERN_RESOURCE_SHORTAGE) - return -ENOMEM; + return UV_ENOMEM; abort(); - return -EINVAL; /* Satisfy the compiler. */ + return UV_EINVAL; /* Satisfy the compiler. */ } @@ -413,10 +413,10 @@ int uv_sem_trywait(uv_sem_t* sem) { if (err == KERN_SUCCESS) return 0; if (err == KERN_OPERATION_TIMED_OUT) - return -EAGAIN; + return UV_EAGAIN; abort(); - return -EINVAL; /* Satisfy the compiler. */ + return UV_EINVAL; /* Satisfy the compiler. */ } #elif defined(__MVS__) @@ -433,14 +433,14 @@ int uv_sem_init(uv_sem_t* sem, unsigned int value) { semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); if (semid == -1) - return -errno; + return UV__ERR(errno); arg.val = value; if (-1 == semctl(semid, 0, SETVAL, arg)) { err = errno; if (-1 == semctl(*sem, 0, IPC_RMID)) abort(); - return -err; + return UV__ERR(err); } *sem = semid; @@ -493,7 +493,7 @@ int uv_sem_trywait(uv_sem_t* sem) { if (op_status) { if (errno == EAGAIN) - return -EAGAIN; + return UV_EAGAIN; abort(); } @@ -504,7 +504,7 @@ int uv_sem_trywait(uv_sem_t* sem) { int uv_sem_init(uv_sem_t* sem, unsigned int value) { if (sem_init(sem, 0, value)) - return -errno; + return UV__ERR(errno); return 0; } @@ -542,7 +542,7 @@ int uv_sem_trywait(uv_sem_t* sem) { if (r) { if (errno == EAGAIN) - return -EAGAIN; + return UV_EAGAIN; abort(); } @@ -555,7 +555,7 @@ int uv_sem_trywait(uv_sem_t* sem) { #if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__) int uv_cond_init(uv_cond_t* cond) { - return -pthread_cond_init(cond, NULL); + return UV__ERR(pthread_cond_init(cond, NULL)); } #else /* !(defined(__APPLE__) && defined(__MACH__)) */ @@ -566,7 +566,7 @@ int uv_cond_init(uv_cond_t* cond) { err = pthread_condattr_init(&attr); if (err) - return -err; + return UV__ERR(err); #if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21) err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); @@ -588,7 +588,7 @@ int uv_cond_init(uv_cond_t* cond) { pthread_cond_destroy(cond); error2: pthread_condattr_destroy(&attr); - return -err; + return UV__ERR(err); } #endif /* defined(__APPLE__) && defined(__MACH__) */ @@ -672,15 +672,15 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { return 0; if (r == ETIMEDOUT) - return -ETIMEDOUT; + return UV_ETIMEDOUT; abort(); - return -EINVAL; /* Satisfy the compiler. */ + return UV_EINVAL; /* Satisfy the compiler. */ } int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { - return -pthread_barrier_init(barrier, NULL, count); + return UV__ERR(pthread_barrier_init(barrier, NULL, count)); } @@ -699,7 +699,7 @@ int uv_barrier_wait(uv_barrier_t* barrier) { int uv_key_create(uv_key_t* key) { - return -pthread_key_create(key, NULL); + return UV__ERR(pthread_key_create(key, NULL)); } diff --git a/src/unix/timer.c b/src/unix/timer.c index f46bdf4bf..54dabfe7d 100644 --- a/src/unix/timer.c +++ b/src/unix/timer.c @@ -66,7 +66,7 @@ int uv_timer_start(uv_timer_t* handle, uint64_t clamped_timeout; if (cb == NULL) - return -EINVAL; + return UV_EINVAL; if (uv__is_active(handle)) uv_timer_stop(handle); @@ -105,7 +105,7 @@ int uv_timer_stop(uv_timer_t* handle) { int uv_timer_again(uv_timer_t* handle) { if (handle->timer_cb == NULL) - return -EINVAL; + return UV_EINVAL; if (handle->repeat) { uv_timer_stop(handle); diff --git a/src/unix/tty.c b/src/unix/tty.c index 357f9748f..f22b3b80d 100644 --- a/src/unix/tty.c +++ b/src/unix/tty.c @@ -106,7 +106,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { */ type = uv_guess_handle(fd); if (type == UV_FILE || type == UV_UNKNOWN_HANDLE) - return -EINVAL; + return UV_EINVAL; flags = 0; newfd = -1; @@ -142,7 +142,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { newfd = r; r = uv__dup2_cloexec(newfd, fd); - if (r < 0 && r != -EINVAL) { + if (r < 0 && r != UV_EINVAL) { /* EINVAL means newfd == fd which could conceivably happen if another * thread called close(fd) between our calls to isatty() and open(). * That's a rather unlikely event but let's handle it anyway. @@ -163,7 +163,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { if (saved_flags == -1) { if (newfd != -1) uv__close(newfd); - return -errno; + return UV__ERR(errno); } #endif @@ -234,7 +234,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { fd = uv__stream_fd(tty); if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) { if (tcgetattr(fd, &tty->orig_termios)) - return -errno; + return UV__ERR(errno); /* This is used for uv_tty_reset_mode() */ uv_spinlock_lock(&termios_spinlock); @@ -264,7 +264,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { /* Apply changes after draining */ if (tcsetattr(fd, TCSADRAIN, &tmp)) - return -errno; + return UV__ERR(errno); tty->mode = mode; return 0; @@ -280,7 +280,7 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { while (err == -1 && errno == EINTR); if (err == -1) - return -errno; + return UV__ERR(errno); *width = ws.ws_col; *height = ws.ws_row; @@ -358,12 +358,12 @@ int uv_tty_reset_mode(void) { saved_errno = errno; if (!uv_spinlock_trylock(&termios_spinlock)) - return -EBUSY; /* In uv_tty_set_mode(). */ + return UV_EBUSY; /* In uv_tty_set_mode(). */ err = 0; if (orig_termios_fd != -1) if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios)) - err = -errno; + err = UV__ERR(errno); uv_spinlock_unlock(&termios_spinlock); errno = saved_errno; diff --git a/src/unix/udp.c b/src/unix/udp.c index a475bf574..74d613b68 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -72,7 +72,7 @@ void uv__udp_finish_close(uv_udp_t* handle) { QUEUE_REMOVE(q); req = QUEUE_DATA(q, uv_udp_send_t, queue); - req->status = -ECANCELED; + req->status = UV_ECANCELED; QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); } @@ -189,7 +189,7 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { if (errno == EAGAIN || errno == EWOULDBLOCK) handle->recv_cb(handle, 0, &buf, NULL, 0); else - handle->recv_cb(handle, -errno, &buf, NULL, 0); + handle->recv_cb(handle, UV__ERR(errno), &buf, NULL, 0); } else { const struct sockaddr *addr; @@ -242,7 +242,7 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { break; } - req->status = (size == -1 ? -errno : size); + 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 @@ -270,11 +270,11 @@ static int uv__set_reuse(int fd) { #if defined(SO_REUSEPORT) && !defined(__linux__) yes = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) - return -errno; + return UV__ERR(errno); #else yes = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) - return -errno; + return UV__ERR(errno); #endif return 0; @@ -291,11 +291,11 @@ int uv__udp_bind(uv_udp_t* handle, /* Check for bad flags. */ if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR)) - return -EINVAL; + return UV_EINVAL; /* Cannot set IPv6-only mode on non-IPv6 socket. */ if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) - return -EINVAL; + return UV_EINVAL; fd = handle->io_watcher.fd; if (fd == -1) { @@ -316,21 +316,21 @@ int uv__udp_bind(uv_udp_t* handle, #ifdef IPV6_V6ONLY yes = 1; if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { - err = -errno; + err = UV__ERR(errno); return err; } #else - err = -ENOTSUP; + err = UV_ENOTSUP; return err; #endif } if (bind(fd, addr, addrlen)) { - err = -errno; + err = UV__ERR(errno); 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. */ - err = -EINVAL; + err = UV_EINVAL; return err; } @@ -418,7 +418,7 @@ int uv__udp_send(uv_udp_send_t* req, if (req->bufs == NULL) { uv__req_unregister(handle->loop, req); - return -ENOMEM; + return UV_ENOMEM; } memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); @@ -457,7 +457,7 @@ int uv__udp_try_send(uv_udp_t* handle, /* already sending a message */ if (handle->send_queue_count != 0) - return -EAGAIN; + return UV_EAGAIN; err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); if (err) @@ -475,9 +475,9 @@ int uv__udp_try_send(uv_udp_t* handle, if (size == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) - return -EAGAIN; + return UV_EAGAIN; else - return -errno; + return UV__ERR(errno); } return size; @@ -512,7 +512,7 @@ static int uv__udp_set_membership4(uv_udp_t* handle, optname = IP_DROP_MEMBERSHIP; break; default: - return -EINVAL; + return UV_EINVAL; } if (setsockopt(handle->io_watcher.fd, @@ -522,9 +522,9 @@ static int uv__udp_set_membership4(uv_udp_t* handle, sizeof(mreq))) { #if defined(__MVS__) if (errno == ENXIO) - return -ENODEV; + return UV_ENODEV; #endif - return -errno; + return UV__ERR(errno); } return 0; @@ -543,7 +543,7 @@ static int uv__udp_set_membership6(uv_udp_t* handle, if (interface_addr) { if (uv_ip6_addr(interface_addr, 0, &addr6)) - return -EINVAL; + return UV_EINVAL; mreq.ipv6mr_interface = addr6.sin6_scope_id; } else { mreq.ipv6mr_interface = 0; @@ -559,7 +559,7 @@ static int uv__udp_set_membership6(uv_udp_t* handle, optname = IPV6_DROP_MEMBERSHIP; break; default: - return -EINVAL; + return UV_EINVAL; } if (setsockopt(handle->io_watcher.fd, @@ -569,9 +569,9 @@ static int uv__udp_set_membership6(uv_udp_t* handle, sizeof(mreq))) { #if defined(__MVS__) if (errno == ENXIO) - return -ENODEV; + return UV_ENODEV; #endif - return -errno; + return UV__ERR(errno); } return 0; @@ -586,10 +586,10 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { /* Use the lower 8 bits for the domain */ domain = flags & 0xFF; if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) - return -EINVAL; + return UV_EINVAL; if (flags & ~0xFF) - return -EINVAL; + return UV_EINVAL; if (domain != AF_UNSPEC) { err = uv__socket(domain, SOCK_DGRAM, 0); @@ -622,7 +622,7 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { /* Check for already active socket. */ if (handle->io_watcher.fd != -1) - return -EBUSY; + return UV_EBUSY; err = uv__nonblock(sock, 1); if (err) @@ -656,7 +656,7 @@ int uv_udp_set_membership(uv_udp_t* handle, return err; return uv__udp_set_membership6(handle, &addr6, interface_addr, membership); } else { - return -EINVAL; + return UV_EINVAL; } } @@ -680,7 +680,7 @@ static int uv__setsockopt(uv_udp_t* handle, val, size); if (r) - return -errno; + return UV__ERR(errno); return 0; } @@ -698,7 +698,7 @@ static int uv__setsockopt_maybe_char(uv_udp_t* handle, #endif if (val < 0 || val > 255) - return -EINVAL; + return UV_EINVAL; return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg)); } @@ -710,7 +710,7 @@ int uv_udp_set_broadcast(uv_udp_t* handle, int on) { SO_BROADCAST, &on, sizeof(on))) { - return -errno; + return UV__ERR(errno); } return 0; @@ -719,11 +719,11 @@ int uv_udp_set_broadcast(uv_udp_t* handle, int on) { int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { if (ttl < 1 || ttl > 255) - return -EINVAL; + return UV_EINVAL; #if defined(__MVS__) if (!(handle->flags & UV_HANDLE_IPV6)) - return -ENOTSUP; /* zOS does not support setting ttl for IPv4 */ + return UV_ENOTSUP; /* zOS does not support setting ttl for IPv4 */ #endif /* @@ -817,7 +817,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) { /* nothing, address was parsed */ } else { - return -EINVAL; + return UV_EINVAL; } if (addr_st.ss_family == AF_INET) { @@ -826,7 +826,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) IP_MULTICAST_IF, (void*) &addr4->sin_addr, sizeof(addr4->sin_addr)) == -1) { - return -errno; + return UV__ERR(errno); } } else if (addr_st.ss_family == AF_INET6) { if (setsockopt(handle->io_watcher.fd, @@ -834,7 +834,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) IPV6_MULTICAST_IF, &addr6->sin6_scope_id, sizeof(addr6->sin6_scope_id)) == -1) { - return -errno; + return UV__ERR(errno); } } else { assert(0 && "unexpected address family"); @@ -851,13 +851,13 @@ int uv_udp_getsockname(const uv_udp_t* handle, socklen_t socklen; if (handle->io_watcher.fd == -1) - return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ + return UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ /* sizeof(socklen_t) != sizeof(int) on some systems. */ socklen = (socklen_t) *namelen; if (getsockname(handle->io_watcher.fd, name, &socklen)) - return -errno; + return UV__ERR(errno); *namelen = (int) socklen; return 0; @@ -870,10 +870,10 @@ int uv__udp_recv_start(uv_udp_t* handle, int err; if (alloc_cb == NULL || recv_cb == NULL) - return -EINVAL; + return UV_EINVAL; if (uv__io_active(&handle->io_watcher, POLLIN)) - return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */ + return UV_EALREADY; /* FIXME(bnoordhuis) Should be UV_EBUSY. */ err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0); if (err) diff --git a/src/uv-common.h b/src/uv-common.h index 781a8559d..d4fa22aae 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -41,6 +41,12 @@ #include "tree.h" #include "queue.h" +#if EDOM > 0 +# define UV__ERR(x) (-(x)) +#else +# define UV__ERR(x) (x) +#endif + #if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900 extern int snprintf(char*, size_t, const char*, ...); #endif diff --git a/test/test-ipc-send-recv.c b/test/test-ipc-send-recv.c index 160c23507..917744cba 100644 --- a/test/test-ipc-send-recv.c +++ b/test/test-ipc-send-recv.c @@ -304,7 +304,7 @@ static void read_cb(uv_stream_t* handle, union handles* recv; uv_write_t* write_req; - if (nread == UV__EOF || nread == UV__ECONNABORTED) { + if (nread == UV_EOF || nread == UV_ECONNABORTED) { return; } From c43150588d72c1981ebec132b5518955d0beedad Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 8 Feb 2018 09:54:24 +0100 Subject: [PATCH 618/632] build: add url field to libuv.pc PR-URL: https://github.com/libuv/libuv/pull/1733 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- libuv.pc.in | 1 + 1 file changed, 1 insertion(+) diff --git a/libuv.pc.in b/libuv.pc.in index 9174fe151..55c4b65d5 100644 --- a/libuv.pc.in +++ b/libuv.pc.in @@ -6,6 +6,7 @@ includedir=@includedir@ Name: @PACKAGE_NAME@ Version: @PACKAGE_VERSION@ Description: multi-platform support library with a focus on asynchronous I/O. +URL: http://libuv.org/ Libs: -L${libdir} -luv @LIBS@ Cflags: -I${includedir} From 733adae22ab50f7286105a68ccb736f30e62e9d7 Mon Sep 17 00:00:00 2001 From: Jesse Gorzinski Date: Tue, 30 Jan 2018 10:54:19 -0600 Subject: [PATCH 619/632] doc: mark IBM i as Tier 3 support PR-URL: https://github.com/libuv/libuv/pull/1732 Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig Reviewed-By: Michael Dawson Reviewed-By: Santiago Gimeno --- SUPPORTED_PLATFORMS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/SUPPORTED_PLATFORMS.md b/SUPPORTED_PLATFORMS.md index c56913bbc..077191086 100644 --- a/SUPPORTED_PLATFORMS.md +++ b/SUPPORTED_PLATFORMS.md @@ -11,6 +11,7 @@ | Linux with musl | Tier 2 | musl >= 1.0 | | | SmartOS | Tier 2 | >= 14.4 | Maintainers: @libuv/smartos | | Android | Tier 3 | NDK >= r15b | | +| IBM i | Tier 3 | >= IBM i 7.2 | Maintainers: @libuv/ibmi | | MinGW | Tier 3 | MinGW32 and MinGW-w64 | | | SunOS | Tier 3 | Solaris 121 and later | | | Other | Tier 3 | N/A | | From 95e44dd46e5e2ae146a367759a6830eb51d49fc7 Mon Sep 17 00:00:00 2001 From: Michael Fero Date: Tue, 13 Feb 2018 10:55:53 -0500 Subject: [PATCH 620/632] win,build: correct C2059 errors This commit addresses POD variable initialization issues with older Visual Studio compilers. PR-URL: https://github.com/libuv/libuv/pull/1740 Reviewed-By: Ben Noordhuis --- src/win/winsock.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/win/winsock.c b/src/win/winsock.c index 7cfa90f8a..84188954d 100644 --- a/src/win/winsock.c +++ b/src/win/winsock.c @@ -580,8 +580,10 @@ int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr, memcpy(dest6, addr, sizeof(*dest6)); if (memcmp(&dest6->sin6_addr, &uv_addr_ip6_any_.sin6_addr, - sizeof(uv_addr_ip6_any_.sin6_addr)) == 0) - dest6->sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT; + sizeof(uv_addr_ip6_any_.sin6_addr)) == 0) { + struct in6_addr init_sin6_addr = IN6ADDR_LOOPBACK_INIT; + dest6->sin6_addr = init_sin6_addr; + } return 0; default: return UV_EINVAL; From 1ded66908dba4fbd11e68471afbba17ac18361cd Mon Sep 17 00:00:00 2001 From: John Barboza Date: Wed, 17 Jan 2018 10:30:48 -0500 Subject: [PATCH 621/632] zos: fix timeout for condition variable The pthread_cond_timedwait requires a timeout relative to the Epoch. So don't use uv__hrtime to set the timeout because it is relative to an arbitrary time in the past. Use gettimeofday instead. PR-URL: https://github.com/libuv/libuv/pull/1711 Reviewed-By: Ben Noordhuis Reviewed-By: Jamie Davis --- docs/src/threading.rst | 11 +++++++++-- src/unix/thread.c | 9 +++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/src/threading.rst b/docs/src/threading.rst index bca8ba1d0..89bb4a6f3 100644 --- a/docs/src/threading.rst +++ b/docs/src/threading.rst @@ -131,8 +131,15 @@ Functions return 0 on success or an error code < 0 (unless the return type is void, of course). .. note:: - Callers should be prepared to deal with spurious wakeups on :c:func:`uv_cond_wait` and - :c:func:`uv_cond_timedwait`. + 1. Callers should be prepared to deal with spurious wakeups on :c:func:`uv_cond_wait` + and :c:func:`uv_cond_timedwait`. + 2. The timeout parameter for :c:func:`uv_cond_timedwait` is relative to the time + at which function is called. + 3. On z/OS, the timeout parameter for :c:func:`uv_cond_timedwait` is converted to an + absolute system time at which the wait expires. If the current system clock time + passes the absolute time calculated before the condition is signaled, an ETIMEDOUT + error results. After the wait begins, the wait time is not affected by changes + to the system clock. .. c:function:: int uv_cond_init(uv_cond_t* cond) .. c:function:: void uv_cond_destroy(uv_cond_t* cond) diff --git a/src/unix/thread.c b/src/unix/thread.c index 8229c2759..3def29457 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -646,13 +646,22 @@ void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { int r; struct timespec ts; +#if defined(__MVS__) + struct timeval tv; +#endif #if defined(__APPLE__) && defined(__MACH__) ts.tv_sec = timeout / NANOSEC; ts.tv_nsec = timeout % NANOSEC; r = pthread_cond_timedwait_relative_np(cond, mutex, &ts); +#else +#if defined(__MVS__) + if (gettimeofday(&tv, NULL)) + abort(); + timeout += tv.tv_sec * NANOSEC + tv.tv_usec * 1e3; #else timeout += uv__hrtime(UV_CLOCK_PRECISE); +#endif ts.tv_sec = timeout / NANOSEC; ts.tv_nsec = timeout % NANOSEC; #if defined(__ANDROID_API__) && __ANDROID_API__ < 21 From 491848a0ad20031fa26bfb4a934b82293e0f7732 Mon Sep 17 00:00:00 2001 From: Nick Logan Date: Wed, 29 Nov 2017 22:29:38 -0500 Subject: [PATCH 622/632] win: CREATE_NO_WINDOW when stdio is not inherited Fixes: https://github.com/libuv/libuv/issues/1625 PR-URL: https://github.com/libuv/libuv/pull/1659 Reviewed-By: Bartosz Sosnowski --- src/win/process.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/win/process.c b/src/win/process.c index cc06d9e22..752352221 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -1061,11 +1061,16 @@ int uv_spawn(uv_loop_t* loop, process_flags = CREATE_UNICODE_ENVIRONMENT; if (options->flags & UV_PROCESS_WINDOWS_HIDE) { + /* Avoid creating console window if stdio is not inherited. */ + for (i = 0; i < options->stdio_count; i++) { + if (options->stdio[i].flags & UV_INHERIT_FD) + break; + if (i == options->stdio_count - 1) + process_flags |= CREATE_NO_WINDOW; + } + /* Use SW_HIDE to avoid any potential process window. */ startup.wShowWindow = SW_HIDE; - - /* Hide console windows. */ - process_flags |= CREATE_NO_WINDOW; } else { startup.wShowWindow = SW_SHOWDEFAULT; } From 3f8f6dc4c74bab65fa75d226eda8dae2f2029ad1 Mon Sep 17 00:00:00 2001 From: Ryuichi KAWAMATA Date: Wed, 6 Dec 2017 11:13:41 +0900 Subject: [PATCH 623/632] build: fix commmon.gypi comment PR-URL: https://github.com/libuv/libuv/pull/1669 Reviewed-By: Bartosz Sosnowski --- common.gypi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common.gypi b/common.gypi index 816847bfc..572a1633b 100644 --- a/common.gypi +++ b/common.gypi @@ -16,9 +16,9 @@ 'VCCLCompilerTool': { 'target_conditions': [ ['uv_library=="static_library"', { - 'RuntimeLibrary': 1, # static debug + 'RuntimeLibrary': 1, # /MTd static debug }, { - 'RuntimeLibrary': 3, # DLL debug + 'RuntimeLibrary': 3, # /MDd DLL debug }], ], 'Optimization': 0, # /Od, no optimization @@ -52,9 +52,9 @@ 'VCCLCompilerTool': { 'target_conditions': [ ['uv_library=="static_library"', { - 'RuntimeLibrary': 0, # static release + 'RuntimeLibrary': 0, # /MT static release }, { - 'RuntimeLibrary': 2, # debug release + 'RuntimeLibrary': 2, # /MD DLL release }], ], 'Optimization': 3, # /Ox, full optimization From 9d74b27ad45a259e977cc2a842b51ab53f9d4991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20=C4=8Cun=C3=A1t?= Date: Mon, 11 Sep 2017 15:36:19 +0200 Subject: [PATCH 624/632] doc: document uv_timer_start() on an active timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/libuv/libuv/issues/1401 PR-URL: https://github.com/libuv/libuv/pull/1538 Reviewed-By: Colin Ihrig Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Santiago Gimeno --- docs/src/timer.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/src/timer.rst b/docs/src/timer.rst index 8e11f257f..e163e288f 100644 --- a/docs/src/timer.rst +++ b/docs/src/timer.rst @@ -45,6 +45,8 @@ API .. note:: Does not update the event loop's concept of "now". See :c:func:`uv_update_time` for more information. + If the timer is already active, it is simply updated. + .. c:function:: int uv_timer_stop(uv_timer_t* handle) Stop the timer, the callback will not be called anymore. From 10fe8c806575b4e869420dfbfb8d23a801fdb740 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Mon, 19 Feb 2018 18:04:41 +0100 Subject: [PATCH 625/632] doc: add note about handle movability Add note that explaining pointers to handles need to remain valid during the requested operations. Refs: https://github.com/libuv/libuv/issues/1731 PR-URL: https://github.com/libuv/libuv/pull/1749 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/handle.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/handle.rst b/docs/src/handle.rst index e4cb90b5f..cdfb76bf8 100644 --- a/docs/src/handle.rst +++ b/docs/src/handle.rst @@ -9,6 +9,9 @@ Structures are aligned so that any libuv handle can be cast to `uv_handle_t`. All API functions defined here work with any handle type. +Libuv handles are not movable. Pointers to handle structures passed to +functions must remain valid for the duration of the requested operation. Take +care when using stack allocated handles. Data types ---------- From a4b2e3222878aa175dd9287b3e99d6d09dc79e71 Mon Sep 17 00:00:00 2001 From: Bartosz Sosnowski Date: Mon, 19 Feb 2018 17:52:43 +0100 Subject: [PATCH 626/632] doc: fix syntax error in loop documentation PR-URL: https://github.com/libuv/libuv/pull/1748 Reviewed-By: Colin Ihrig Reviewed-By: Santiago Gimeno --- docs/src/loop.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/loop.rst b/docs/src/loop.rst index dcde5049a..86a99adf5 100644 --- a/docs/src/loop.rst +++ b/docs/src/loop.rst @@ -219,7 +219,7 @@ API .. caution:: - Any previous value returned from :c:func`uv_backend_fd` is now + Any previous value returned from :c:func:`uv_backend_fd` is now invalid. That function must be called again to determine the correct backend file descriptor. From e6168df52077e40d600807dc0096c1ed4fd99a13 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 13 Feb 2018 16:01:43 +0100 Subject: [PATCH 627/632] osx,stream: retry sending handle on EMSGSIZE error On OSX when sending handles via `sendmsg()` it can return `EMSGSIZE` if there isn't room in the socket output buffer to store the whole message. If that's the case, return control to the loop and try again in the next iteration. Fixes: https://github.com/nodejs/node/issues/14828 PR-URL: https://github.com/libuv/libuv/pull/1739 Reviewed-By: Colin Ihrig --- src/unix/stream.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index 5aa60431e..3e786abee 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -58,6 +58,12 @@ struct uv__stream_select_s { fd_set* swrite; size_t swrite_sz; }; +# define WRITE_RETRY_ON_ERROR(send_handle) \ + (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \ + (errno == EMSGSIZE && send_handle)) +#else +# define WRITE_RETRY_ON_ERROR(send_handle) \ + (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) #endif /* defined(__APPLE__) */ static void uv__stream_connect(uv_stream_t*); @@ -859,7 +865,7 @@ static void uv__write(uv_stream_t* stream) { } if (n < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENOBUFS) { + if (!WRITE_RETRY_ON_ERROR(req->send_handle)) { err = UV__ERR(errno); goto error; } else if (stream->flags & UV_STREAM_BLOCKING) { From dab311afe99861dc07cd6fc703434d188b4bbb69 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 20 Feb 2018 21:00:48 -0500 Subject: [PATCH 628/632] unix: delay fs req register until after validation On Unix, if a fs function fails validation after INIT but before sending the work to the thread pool, then is is necessary to manually unregister the request. This commit moves the registration to just before the work submission. This also makes Unix match the Windows behavior. Refs: https://github.com/libuv/libuv/pull/1747 Refs: https://github.com/nodejs/node/pull/18811 PR-URL: https://github.com/libuv/libuv/pull/1751 Reviewed-By: Ben Noordhuis --- src/unix/fs.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/unix/fs.c b/src/unix/fs.c index 46071c564..bd0d0bea6 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -68,9 +68,7 @@ do { \ if (req == NULL) \ return UV_EINVAL; \ - req->type = UV_FS; \ - if (cb != NULL) \ - uv__req_init(loop, req, UV_FS); \ + UV_REQ_INIT(req, UV_FS); \ req->fs_type = UV_FS_ ## subtype; \ req->result = 0; \ req->ptr = NULL; \ @@ -88,10 +86,8 @@ req->path = path; \ } else { \ req->path = uv__strdup(path); \ - if (req->path == NULL) { \ - uv__req_unregister(loop, req); \ + if (req->path == NULL) \ return UV_ENOMEM; \ - } \ } \ } \ while (0) @@ -107,10 +103,8 @@ path_len = strlen(path) + 1; \ new_path_len = strlen(new_path) + 1; \ req->path = uv__malloc(path_len + new_path_len); \ - if (req->path == NULL) { \ - uv__req_unregister(loop, req); \ + if (req->path == NULL) \ return UV_ENOMEM; \ - } \ req->new_path = req->path + path_len; \ memcpy((void*) req->path, path, path_len); \ memcpy((void*) req->new_path, new_path, new_path_len); \ @@ -121,6 +115,7 @@ #define POST \ do { \ if (cb != NULL) { \ + uv__req_register(loop, req); \ uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \ return 0; \ } \ @@ -1288,11 +1283,8 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_cb cb) { INIT(MKDTEMP); req->path = uv__strdup(tpl); - if (req->path == NULL) { - if (cb != NULL) - uv__req_unregister(loop, req); + if (req->path == NULL) return UV_ENOMEM; - } POST; } @@ -1329,11 +1321,8 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, if (nbufs > ARRAY_SIZE(req->bufsml)) req->bufs = uv__malloc(nbufs * sizeof(*bufs)); - if (req->bufs == NULL) { - if (cb != NULL) - uv__req_unregister(loop, req); + if (req->bufs == NULL) return UV_ENOMEM; - } memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); @@ -1468,11 +1457,8 @@ int uv_fs_write(uv_loop_t* loop, if (nbufs > ARRAY_SIZE(req->bufsml)) req->bufs = uv__malloc(nbufs * sizeof(*bufs)); - if (req->bufs == NULL) { - if (cb != NULL) - uv__req_unregister(loop, req); + if (req->bufs == NULL) return UV_ENOMEM; - } memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); From e485d2867440f7cf9bb3bb2c7b15ddaa5ffdb77c Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 21 Feb 2018 09:53:57 -0500 Subject: [PATCH 629/632] test: add tests for bad inputs This commit adds tests that pass bad options to uv_fs_copyfile(), uv_fs_read(), and uv_fs_write(). These tests verify that the asynchronous version of these functions do not hold the event loop open on bad inputs. Refs: https://github.com/nodejs/node/pull/18811 PR-URL: https://github.com/libuv/libuv/pull/1747 Reviewed-By: Colin Ihrig --- test/test-fs-copyfile.c | 11 ++++++++++- test/test-fs.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/test/test-fs-copyfile.c b/test/test-fs-copyfile.c index 460c1dc6a..4b1fdc5e7 100644 --- a/test/test-fs-copyfile.c +++ b/test/test-fs-copyfile.c @@ -36,6 +36,10 @@ static const char dst[] = "test_file_dst"; static int result_check_count; +static void fail_cb(uv_fs_t* req) { + FATAL("fail_cb should not have been called"); +} + static void handle_result(uv_fs_t* req) { uv_fs_t stat_req; uint64_t size; @@ -158,7 +162,12 @@ TEST_IMPL(fs_copyfile) { ASSERT(result_check_count == 5); uv_run(loop, UV_RUN_DEFAULT); ASSERT(result_check_count == 6); - unlink(dst); /* Cleanup */ + /* 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); + uv_run(loop, UV_RUN_DEFAULT); + unlink(dst); /* Cleanup */ return 0; } diff --git a/test/test-fs.c b/test/test-fs.c index 7c481f071..c84d8a3d9 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -319,6 +319,9 @@ static void ftruncate_cb(uv_fs_t* req) { ASSERT(r == 0); } +static void fail_cb(uv_fs_t* req) { + FATAL("fail_cb should not have been called"); +} static void read_cb(uv_fs_t* req) { int r; @@ -2897,6 +2900,31 @@ TEST_IMPL(fs_read_write_null_arguments) { ASSERT(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); + 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); + 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); + 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); + uv_run(loop, UV_RUN_DEFAULT); + uv_fs_req_cleanup(&write_req); + return 0; } From 1167ec3f476e1886606ca76bd153708aead0d397 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 21 Feb 2018 11:30:37 -0500 Subject: [PATCH 630/632] unix,win: ensure req->bufs is freed This commit ensures that req->bufs (req->fs.info.bufs on Windows) is initialized to NULL in INIT and freed, if necessary, in uv_fs_req_cleanup(). Refs: https://github.com/libuv/libuv/pull/1751#discussion_r169645330 PR-URL: https://github.com/libuv/libuv/pull/1752 Reviewed-By: Ben Noordhuis --- src/unix/fs.c | 5 +++++ src/win/fs.c | 1 + 2 files changed, 6 insertions(+) diff --git a/src/unix/fs.c b/src/unix/fs.c index bd0d0bea6..92e2d2557 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -75,6 +75,7 @@ req->loop = loop; \ req->path = NULL; \ req->new_path = NULL; \ + req->bufs = NULL; \ req->cb = cb; \ } \ while (0) @@ -1485,6 +1486,10 @@ void uv_fs_req_cleanup(uv_fs_t* req) { if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) uv__fs_scandir_cleanup(req); + if (req->bufs != req->bufsml) + uv__free(req->bufs); + req->bufs = NULL; + if (req->ptr != &req->statbuf) uv__free(req->ptr); req->ptr = NULL; diff --git a/src/win/fs.c b/src/win/fs.c index 097b00e08..6e0bdc7bb 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -245,6 +245,7 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, req->ptr = NULL; req->path = NULL; req->cb = cb; + req->fs.info.bufs = NULL; memset(&req->fs, 0, sizeof(req->fs)); } From c1ecaf7b43f70d8e864821805da1e748b75b9087 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 21 Feb 2018 11:33:48 -0500 Subject: [PATCH 631/632] test: add additional fs memory management checks This commit adds checks for fs request values when a call fails with UV_EINVAL. PR-URL: https://github.com/libuv/libuv/pull/1752 Reviewed-By: Ben Noordhuis --- test/test-fs.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/test-fs.c b/test/test-fs.c index c84d8a3d9..3318b8664 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -2887,7 +2887,19 @@ TEST_IMPL(fs_read_write_null_arguments) { 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(write_req.path == NULL); + ASSERT(write_req.ptr == NULL); +#ifdef _WIN32 + ASSERT(write_req.file.pathw == NULL); + ASSERT(write_req.fs.info.new_pathw == NULL); + ASSERT(write_req.fs.info.bufs == NULL); +#else + ASSERT(write_req.new_path == NULL); + ASSERT(write_req.bufs == NULL); +#endif uv_fs_req_cleanup(&write_req); iov = uv_buf_init(NULL, 0); @@ -3112,7 +3124,7 @@ TEST_IMPL(fs_exclusive_sharing_mode) { unlink("test_file"); ASSERT(UV_FS_O_EXLOCK > 0); - + r = uv_fs_open(NULL, &open_req1, "test_file", From c5afc37e2a8a70d8ab0da8dac10b77ba78c0488c Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 21 Feb 2018 15:25:38 -0500 Subject: [PATCH 632/632] 2018.02.22, Version 1.19.2 (Stable) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes since version 1.19.1: * test: fix incorrect asserts (cjihrig) * test: fix a typo in test-fork.c (Felix Yan) * build: remove long-obsolete gyp workarounds (Ben Noordhuis) * build: split off tests into separate gyp file (Ben Noordhuis) * test: check uv_cond_timedwait more carefully (Jamie Davis) * include,src: introduce UV__ERR() macro (Mason X) * build: add url field to libuv.pc (Ben Noordhuis) * doc: mark IBM i as Tier 3 support (Jesse Gorzinski) * win,build: correct C2059 errors (Michael Fero) * zos: fix timeout for condition variable (jBarz) * win: CREATE_NO_WINDOW when stdio is not inherited (Nick Logan) * build: fix commmon.gypi comment (Ryuichi KAWAMATA) * doc: document uv_timer_start() on an active timer (Vladimír Čunát) * doc: add note about handle movability (Bartosz Sosnowski) * doc: fix syntax error in loop documentation (Bartosz Sosnowski) * osx,stream: retry sending handle on EMSGSIZE error (Santiago Gimeno) * unix: delay fs req register until after validation (cjihrig) * test: add tests for bad inputs (Joyee Cheung) * unix,win: ensure req->bufs is freed (cjihrig) * test: add additional fs memory management checks (cjihrig) --- AUTHORS | 5 +++++ ChangeLog | 45 ++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 2 +- include/uv-version.h | 4 ++-- 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index c826c8e13..fcb0aac3e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -325,3 +325,8 @@ Anna Henningsen Jérémy Lal Ben Wijen elephantp +Felix Yan +Mason X +Jesse Gorzinski +Ryuichi KAWAMATA +Joyee Cheung diff --git a/ChangeLog b/ChangeLog index 163500245..53ebd01d5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,48 @@ +2018.02.22, Version 1.19.2 (Stable) + +Changes since version 1.19.1: + +* test: fix incorrect asserts (cjihrig) + +* test: fix a typo in test-fork.c (Felix Yan) + +* build: remove long-obsolete gyp workarounds (Ben Noordhuis) + +* build: split off tests into separate gyp file (Ben Noordhuis) + +* test: check uv_cond_timedwait more carefully (Jamie Davis) + +* include,src: introduce UV__ERR() macro (Mason X) + +* build: add url field to libuv.pc (Ben Noordhuis) + +* doc: mark IBM i as Tier 3 support (Jesse Gorzinski) + +* win,build: correct C2059 errors (Michael Fero) + +* zos: fix timeout for condition variable (jBarz) + +* win: CREATE_NO_WINDOW when stdio is not inherited (Nick Logan) + +* build: fix commmon.gypi comment (Ryuichi KAWAMATA) + +* doc: document uv_timer_start() on an active timer (Vladimír Čunát) + +* doc: add note about handle movability (Bartosz Sosnowski) + +* doc: fix syntax error in loop documentation (Bartosz Sosnowski) + +* osx,stream: retry sending handle on EMSGSIZE error (Santiago Gimeno) + +* unix: delay fs req register until after validation (cjihrig) + +* test: add tests for bad inputs (Joyee Cheung) + +* unix,win: ensure req->bufs is freed (cjihrig) + +* test: add additional fs memory management checks (cjihrig) + + 2018.01.20, Version 1.19.1 (Stable), 8202d1751196c2374ad370f7f3779daef89befae Changes since version 1.19.0: diff --git a/configure.ac b/configure.ac index 75fb13c8c..4074e7784 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.19.1], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.19.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 f5703e699..c2753d51c 100644 --- a/include/uv-version.h +++ b/include/uv-version.h @@ -33,8 +33,8 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 19 #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) | \