diff options
Diffstat (limited to 'deps/uv/src')
54 files changed, 1647 insertions, 804 deletions
diff --git a/deps/uv/src/threadpool.c b/deps/uv/src/threadpool.c index 2c5152b420..108934112c 100644 --- a/deps/uv/src/threadpool.c +++ b/deps/uv/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 <stdlib.h> @@ -139,7 +127,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 +165,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/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index 1d2cd4a80e..388c9cca97 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/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/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c index 393cdebd4e..45c088ea1b 100644 --- a/deps/uv/src/unix/async.c +++ b/deps/uv/src/unix/async.c @@ -33,16 +33,15 @@ #include <string.h> #include <unistd.h> -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); - } -} - + assert(w == &loop->async_io_watcher); -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; - - 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); + + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&loop->async_handles, q); -#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 + if (cmpxchgi(&h->pending, 1, 0) == 0) + continue; + + if (h->async_cb == NULL) + continue; - wa->cb(loop, wa, n); + 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,32 +192,41 @@ 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) +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; - 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; } -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/deps/uv/src/unix/bsd-ifaddrs.c b/deps/uv/src/unix/bsd-ifaddrs.c new file mode 100644 index 0000000000..414789451a --- /dev/null +++ b/deps/uv/src/unix/bsd-ifaddrs.c @@ -0,0 +1,139 @@ +/* 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 <errno.h> +#include <stddef.h> + +#include <ifaddrs.h> +#include <net/if.h> +#if !defined(__CYGWIN__) && !defined(__MSYS__) +#include <net/if_dl.h> +#endif + +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) { +#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++; + } + } + + 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/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 1ec549cccb..8276c60413 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -28,6 +28,7 @@ #include <errno.h> #include <assert.h> #include <unistd.h> +#include <sys/param.h> /* MAXHOSTNAMELEN on Linux and the BSDs */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -42,6 +43,7 @@ #include <pwd.h> #ifdef __sun +# include <netdb.h> /* MAXHOSTNAMELEN on Solaris */ # include <sys/filio.h> # include <sys/types.h> # include <sys/wait.h> @@ -80,6 +82,11 @@ #include <sys/ioctl.h> #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. */ @@ -538,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; @@ -550,6 +558,7 @@ int uv__cloexec_ioctl(int fd, int set) { return 0; } +#endif int uv__nonblock_fcntl(int fd, int set) { @@ -839,13 +848,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)) @@ -1245,3 +1249,83 @@ 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 (name == NULL || 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; +} + + +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; +} + + +uv_os_fd_t uv_get_osfhandle(int fd) { + return fd; +} diff --git a/deps/uv/src/unix/cygwin.c b/deps/uv/src/unix/cygwin.c new file mode 100644 index 0000000000..5a887dd4c2 --- /dev/null +++ b/deps/uv/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 <sys/sysinfo.h> +#include <unistd.h> + +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/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c index cf95da2169..df6dd1c61b 100644 --- a/deps/uv/src/unix/darwin.c +++ b/deps/uv/src/unix/darwin.c @@ -25,10 +25,6 @@ #include <stdint.h> #include <errno.h> -#include <ifaddrs.h> -#include <net/if.h> -#include <net/if_dl.h> - #include <mach/mach.h> #include <mach/mach_time.h> #include <mach-o/dyld.h> /* _NSGetExecutablePath */ @@ -233,103 +229,3 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } - - -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 (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family == AF_LINK)) { - 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 (!((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) - 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 (!((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; -} - - -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/deps/uv/src/unix/freebsd.c b/deps/uv/src/unix/freebsd.c index cba44a3e0b..e52ae99dbe 100644 --- a/deps/uv/src/unix/freebsd.c +++ b/deps/uv/src/unix/freebsd.c @@ -25,10 +25,6 @@ #include <string.h> #include <errno.h> -#include <ifaddrs.h> -#include <net/if.h> -#include <net/if_dl.h> - #include <kvm.h> #include <paths.h> #include <sys/user.h> @@ -41,9 +37,6 @@ #include <unistd.h> /* sysconf */ #include <fcntl.h> -#undef NANOSEC -#define NANOSEC ((uint64_t) 1e9) - #ifndef CPUSTATES # define CPUSTATES 5U #endif @@ -67,13 +60,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]; @@ -358,103 +344,3 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } - - -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 (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family == AF_LINK)) { - 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 (!((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) - 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 (!((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; -} - - -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/deps/uv/src/unix/fsevents.c b/deps/uv/src/unix/fsevents.c index d331a13172..643e233cfe 100644 --- a/deps/uv/src/unix/fsevents.c +++ b/deps/uv/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); diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 1188e8fe70..2e3afa6c85 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/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 @@ -191,12 +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_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); +int uv__async_fork(uv_loop_t* loop); + /* loop */ void uv__run_idle(uv_loop_t* loop); @@ -232,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); @@ -301,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. */ @@ -326,4 +319,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/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index fffd4626f1..6bc60bbe46 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/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/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index 58dd813ddf..2866e93854 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/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); @@ -454,55 +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; - - 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; -} - - -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; @@ -868,6 +837,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 +869,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 +887,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 +911,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/deps/uv/src/unix/linux-inotify.c b/deps/uv/src/unix/linux-inotify.c index 4708c051d3..5934c5d8cb 100644 --- a/deps/uv/src/unix/linux-inotify.c +++ b/deps/uv/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/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index bd63c2f9d1..bcd49242ce 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/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; @@ -108,10 +109,43 @@ fail_signal_init: } +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); - uv__async_stop(loop, &loop->async_watcher); + uv__async_stop(loop); if (loop->emfile_fd != -1) { uv__close(loop->emfile_fd); diff --git a/deps/uv/src/unix/netbsd.c b/deps/uv/src/unix/netbsd.c index 4a9e6cbc17..9b5546b7e6 100644 --- a/deps/uv/src/unix/netbsd.c +++ b/deps/uv/src/unix/netbsd.c @@ -27,14 +27,11 @@ #include <kvm.h> #include <paths.h> -#include <ifaddrs.h> #include <unistd.h> #include <time.h> #include <stdlib.h> #include <fcntl.h> -#include <net/if.h> -#include <net/if_dl.h> #include <sys/resource.h> #include <sys/types.h> #include <sys/sysctl.h> @@ -43,9 +40,6 @@ #include <unistd.h> #include <time.h> -#undef NANOSEC -#define NANOSEC ((uint64_t) 1e9) - static char *process_title; @@ -58,13 +52,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); @@ -283,98 +270,3 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } - - -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 (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != PF_INET)) { - 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 (!((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) - 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 (!((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; -} - - -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/deps/uv/src/unix/no-fsevents.c b/deps/uv/src/unix/no-fsevents.c new file mode 100644 index 0000000000..38fb6ab0bb --- /dev/null +++ b/deps/uv/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 <errno.h> + +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/deps/uv/src/unix/no-proctitle.c b/deps/uv/src/unix/no-proctitle.c new file mode 100644 index 0000000000..a5c19fbff5 --- /dev/null +++ b/deps/uv/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 <errno.h> +#include <stddef.h> + +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/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index 909288cc88..56f0af15c3 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -28,21 +28,13 @@ #include <sys/time.h> #include <sys/sysctl.h> -#include <ifaddrs.h> -#include <net/if.h> -#include <net/if_dl.h> - #include <errno.h> #include <fcntl.h> -#include <kvm.h> #include <paths.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -#undef NANOSEC -#define NANOSEC ((uint64_t) 1e9) - static char *process_title; @@ -56,13 +48,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); @@ -163,7 +148,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; } @@ -297,100 +282,3 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } - - -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 (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) || - (ent->ifa_addr == NULL) || - (ent->ifa_addr->sa_family != PF_INET)) { - 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 (!((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) - 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 (!((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; -} - - -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/deps/uv/src/unix/os390-syscalls.c b/deps/uv/src/unix/os390-syscalls.c index 2bf3b73815..7edf2358d4 100644 --- a/deps/uv/src/unix/os390-syscalls.c +++ b/deps/uv/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(); diff --git a/deps/uv/src/unix/os390.c b/deps/uv/src/unix/os390.c index be325a9230..2ba5abf354 100644 --- a/deps/uv/src/unix/os390.c +++ b/deps/uv/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]; @@ -863,3 +841,9 @@ update_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/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index b73994cb8d..4a812955b0 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/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) @@ -76,7 +75,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 +86,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; @@ -183,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; } diff --git a/deps/uv/src/unix/posix-hrtime.c b/deps/uv/src/unix/posix-hrtime.c new file mode 100644 index 0000000000..323dfc2039 --- /dev/null +++ b/deps/uv/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 <stdint.h> +#include <time.h> + +#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/deps/uv/src/unix/posix-poll.c b/deps/uv/src/unix/posix-poll.c new file mode 100644 index 0000000000..3fba96e1bf --- /dev/null +++ b/deps/uv/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 <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <errno.h> +#include <unistd.h> + +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; +} diff --git a/deps/uv/src/unix/procfs-exepath.c b/deps/uv/src/unix/procfs-exepath.c new file mode 100644 index 0000000000..5fdb611550 --- /dev/null +++ b/deps/uv/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 <stddef.h> +#include <unistd.h> + +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/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c index dbd8f86448..cb09ead50a 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/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; @@ -53,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(); @@ -63,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); } @@ -122,6 +154,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 +207,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 +216,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)) @@ -228,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; @@ -287,8 +331,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 +378,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 +392,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 +456,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 +483,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 +522,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 +540,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/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 7059df16a6..7b23d16ecf 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -390,7 +390,7 @@ failed_malloc: 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 && @@ -785,7 +785,12 @@ start: 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 @@ start: 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); @@ -1168,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); @@ -1400,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/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index a43f7f1b1c..2dc02ae457 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/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; @@ -469,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); @@ -531,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; @@ -746,6 +741,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 +765,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,10 +779,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) + if (uv__ifaddr_exclude(ent)) continue; address->name = uv__strdup(ent->ifa_name); diff --git a/deps/uv/src/unix/sysinfo-loadavg.c b/deps/uv/src/unix/sysinfo-loadavg.c new file mode 100644 index 0000000000..ebad0e89db --- /dev/null +++ b/deps/uv/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 <stdint.h> +#include <sys/sysinfo.h> + +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/deps/uv/src/unix/sysinfo-memory.c b/deps/uv/src/unix/sysinfo-memory.c new file mode 100644 index 0000000000..23b4fc6e91 --- /dev/null +++ b/deps/uv/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 <stdint.h> +#include <sys/sysinfo.h> + +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/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 1cd4925786..c556325de0 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/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,27 +329,25 @@ 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; } 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 +356,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 +365,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 +377,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); } @@ -429,6 +427,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); } diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index 27902fdf86..781a8559dc 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/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); @@ -215,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/deps/uv/src/win/async.c b/deps/uv/src/win/async.c index ad240ab897..0b636ed1e9 100644 --- a/deps/uv/src/win/async.c +++ b/deps/uv/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/deps/uv/src/win/atomicops-inl.h b/deps/uv/src/win/atomicops-inl.h index 61e006026c..6d8126f692 100644 --- a/deps/uv/src/win/atomicops-inl.h +++ b/deps/uv/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); } diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index e84186d4ec..9ed4e824c6 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -83,13 +83,8 @@ 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); - 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; @@ -156,7 +158,7 @@ loop_removed: uv_mutex_unlock(&uv__loops_lock); } -void uv__wake_all_loops() { +void uv__wake_all_loops(void) { int i; uv_loop_t* loop; @@ -332,6 +334,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/deps/uv/src/win/detect-wakeup.c b/deps/uv/src/win/detect-wakeup.c index a12179f798..72dfb7a177 100644 --- a/deps/uv/src/win/detect-wakeup.c +++ b/deps/uv/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/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 03e4adc058..95f843ad08 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/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) { @@ -131,8 +140,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; @@ -146,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; @@ -188,7 +197,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 { /* @@ -197,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) { @@ -274,6 +282,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; @@ -305,6 +315,9 @@ error: handle->buffer = NULL; } + if (uv__is_active(handle)) + uv__handle_stop(handle); + return uv_translate_sys_error(last_error); } @@ -344,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); diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 6902d4f1a6..2d72cdc70f 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/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; } @@ -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; @@ -1373,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); @@ -2400,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); diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index c13bfec350..baab838898 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/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/deps/uv/src/win/getnameinfo.c b/deps/uv/src/win/getnameinfo.c index 66b64b8832..9f10cd2a5a 100644 --- a/deps/uv/src/win/getnameinfo.c +++ b/deps/uv/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/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c index 72b49d9790..39150702dd 100644 --- a/deps/uv/src/win/handle.c +++ b/deps/uv/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/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index b8cfde90e8..444327d647 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/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,14 +323,15 @@ 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); +int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16); /* @@ -349,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); @@ -384,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/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 2442be7301..edf3002121 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/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; @@ -962,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; @@ -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; @@ -2076,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); diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c index d479e521ef..a648ba711d 100644 --- a/deps/uv/src/win/poll.c +++ b/deps/uv/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_; } @@ -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/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index bdf88d2cdd..d141601607 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/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/deps/uv/src/win/req-inl.h b/deps/uv/src/win/req-inl.h index b5e502eef5..f2513b7d3e 100644 --- a/deps/uv/src/win/req-inl.h +++ b/deps/uv/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/deps/uv/src/win/signal.c b/deps/uv/src/win/signal.c index af7974c364..7b42dd9928 100644 --- a/deps/uv/src/win/signal.c +++ b/deps/uv/src/win/signal.c @@ -34,7 +34,12 @@ static CRITICAL_SECTION uv__signal_lock; static BOOL WINAPI uv__signal_control_handler(DWORD type); -void uv_signals_init() { +int uv__signal_start(uv_signal_t* handle, + uv_signal_cb signal_cb, + int signum, + int oneshot); + +void uv_signals_init(void) { InitializeCriticalSection(&uv__signal_lock); if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) abort(); @@ -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); @@ -128,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; } @@ -166,6 +174,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 +212,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 +243,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/deps/uv/src/win/stream-inl.h b/deps/uv/src/win/stream-inl.h index b7a3c11958..bf12148afe 100644 --- a/deps/uv/src/win/stream-inl.h +++ b/deps/uv/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/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c index a2466e5e9d..13cbfdcb9e 100644 --- a/deps/uv/src/win/stream.c +++ b/deps/uv/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/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 0709696ff9..972539f4df 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/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/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 1b7adf64ff..a6f583956f 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/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(); } @@ -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/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 9bf1453e53..2fd15cfa9a 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/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)); diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 050058afaa..d2e7f772ce 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -59,6 +59,17 @@ # 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 + /* Cached copy of the process title, plus a mutex guarding it. */ static char *process_title; static CRITICAL_SECTION process_title_lock; @@ -74,7 +85,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. */ @@ -320,7 +331,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; @@ -343,7 +354,7 @@ int uv_parent_pid() { } -int uv_current_pid() { +int uv_current_pid(void) { if (current_pid == 0) { current_pid = GetCurrentProcessId(); } @@ -405,7 +416,7 @@ done: } -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))) { @@ -1322,6 +1333,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]; @@ -1387,3 +1439,138 @@ 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; + + r = uv__convert_utf8_to_utf16(name, -1, &name_w); + + if (r != 0) + return r; + + 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; + int r; + + if (name == NULL || value == NULL) + return UV_EINVAL; + + r = uv__convert_utf8_to_utf16(name, -1, &name_w); + + if (r != 0) + return r; + + r = uv__convert_utf8_to_utf16(value, -1, &value_w); + + if (r != 0) { + uv__free(name_w); + return r; + } + + r = SetEnvironmentVariableW(name_w, value_w); + uv__free(name_w); + uv__free(value_w); + + if (r == 0) + return uv_translate_sys_error(GetLastError()); + + return 0; +} + + +int uv_os_unsetenv(const char* name) { + wchar_t* name_w; + int r; + + if (name == NULL) + return UV_EINVAL; + + r = uv__convert_utf8_to_utf16(name, -1, &name_w); + + if (r != 0) + return r; + + r = SetEnvironmentVariableW(name_w, NULL); + uv__free(name_w); + + if (r == 0) + return uv_translate_sys_error(GetLastError()); + + 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/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index 1fa179b572..aa5d719fbe 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/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/deps/uv/src/win/winsock.c b/deps/uv/src/win/winsock.c index d2e667e9f7..e86d76b131 100644 --- a/deps/uv/src/win/winsock.c +++ b/deps/uv/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; |