diff options
Diffstat (limited to 'deps/uv/src/unix')
29 files changed, 1271 insertions, 683 deletions
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); } |