diff options
Diffstat (limited to 'Utilities/cmlibuv/src/unix')
51 files changed, 4603 insertions, 2352 deletions
diff --git a/Utilities/cmlibuv/src/unix/aix-common.c b/Utilities/cmlibuv/src/unix/aix-common.c new file mode 100644 index 000000000..e9697e9c2 --- /dev/null +++ b/Utilities/cmlibuv/src/unix/aix-common.c @@ -0,0 +1,298 @@ +/* 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 <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <sys/time.h> +#include <unistd.h> +#include <fcntl.h> +#include <utmp.h> +#include <libgen.h> + +#include <sys/protosw.h> +#include <procinfo.h> +#include <sys/proc.h> +#include <sys/procfs.h> + +#include <sys/poll.h> + +#include <sys/pollset.h> +#include <ctype.h> + +#include <sys/mntctl.h> +#include <sys/vmount.h> +#include <limits.h> +#include <strings.h> +#include <sys/vnode.h> + +uint64_t uv__hrtime(uv_clocktype_t type) { + uint64_t G = 1000000000; + timebasestruct_t t; + read_wall_time(&t, TIMEBASE_SZ); + time_base_to_time(&t, TIMEBASE_SZ); + return (uint64_t) t.tb_high * G + t.tb_low; +} + + +/* + * We could use a static buffer for the path manipulations that we need outside + * of the function, but this function could be called by multiple consumers and + * we don't want to potentially create a race condition in the use of snprintf. + * There is no direct way of getting the exe path in AIX - either through /procfs + * or through some libc APIs. The below approach is to parse the argv[0]'s pattern + * and use it in conjunction with PATH environment variable to craft one. + */ +int uv_exepath(char* buffer, size_t* size) { + int res; + char args[PATH_MAX]; + char abspath[PATH_MAX]; + size_t abspath_size; + struct procsinfo pi; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + pi.pi_pid = getpid(); + res = getargs(&pi, sizeof(pi), args, sizeof(args)); + if (res < 0) + return UV_EINVAL; + + /* + * Possibilities for args: + * i) an absolute path such as: /home/user/myprojects/nodejs/node + * ii) a relative path such as: ./node or ../myprojects/nodejs/node + * iii) a bare filename such as "node", after exporting PATH variable + * to its location. + */ + + /* Case i) and ii) absolute or relative paths */ + if (strchr(args, '/') != NULL) { + if (realpath(args, abspath) != abspath) + return UV__ERR(errno); + + abspath_size = strlen(abspath); + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + return 0; + } else { + /* Case iii). Search PATH environment variable */ + char trypath[PATH_MAX]; + char *clonedpath = NULL; + char *token = NULL; + char *path = getenv("PATH"); + + if (path == NULL) + return UV_EINVAL; + + clonedpath = uv__strdup(path); + if (clonedpath == NULL) + return UV_ENOMEM; + + token = strtok(clonedpath, ":"); + while (token != NULL) { + snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); + if (realpath(trypath, abspath) == abspath) { + /* Check the match is executable */ + if (access(abspath, X_OK) == 0) { + abspath_size = strlen(abspath); + + *size -= 1; + if (*size > abspath_size) + *size = abspath_size; + + memcpy(buffer, abspath, *size); + buffer[*size] = '\0'; + + uv__free(clonedpath); + return 0; + } + } + token = strtok(NULL, ":"); + } + uv__free(clonedpath); + + /* Out of tokens (path entries), and no match found */ + return UV_EINVAL; + } +} + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; ++i) { + uv__free(cpu_infos[i].model); + } + + uv__free(cpu_infos); +} + + +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + uv_interface_address_t* address; + int sockfd, inet6, size = 1; + struct ifconf ifc; + struct ifreq *ifr, *p, flg; + struct sockaddr_dl* sa_addr; + + *count = 0; + *addresses = NULL; + + if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { + return UV__ERR(errno); + } + + if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { + uv__close(sockfd); + return UV__ERR(errno); + } + + ifc.ifc_req = (struct ifreq*)uv__malloc(size); + ifc.ifc_len = size; + if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { + uv__close(sockfd); + return UV__ERR(errno); + } + +#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) + + /* Count all up and running ipv4/ipv6 addresses */ + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return UV__ERR(errno); + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + (*count)++; + } + + if (*count == 0) { + uv__close(sockfd); + return 0; + } + + /* Alloc the return interface structs */ + *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); + if (!(*addresses)) { + uv__close(sockfd); + return UV_ENOMEM; + } + address = *addresses; + + ifr = ifc.ifc_req; + while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { + p = ifr; + ifr = (struct ifreq*) + ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); + + if (!(p->ifr_addr.sa_family == AF_INET6 || + p->ifr_addr.sa_family == AF_INET)) + continue; + + inet6 = (p->ifr_addr.sa_family == AF_INET6); + + memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); + if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { + uv__close(sockfd); + return UV_ENOSYS; + } + + if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) + continue; + + /* All conditions above must match count loop */ + + address->name = uv__strdup(p->ifr_name); + + if (inet6) + address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); + else + address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); + + sa_addr = (struct sockaddr_dl*) &p->ifr_addr; + memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); + + if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) { + uv__close(sockfd); + return UV_ENOSYS; + } + + if (inet6) + address->netmask.netmask6 = *((struct sockaddr_in6*) &p->ifr_addr); + else + address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr); + + address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; + + address++; + } + +#undef ADDR_SIZE + + uv__close(sockfd); + return 0; +} + + +void uv_free_interface_addresses(uv_interface_address_t* addresses, + int count) { + int i; + + for (i = 0; i < count; ++i) { + uv__free(addresses[i].name); + } + + uv__free(addresses); +} + diff --git a/Utilities/cmlibuv/src/unix/aix.c b/Utilities/cmlibuv/src/unix/aix.c index 388c9cca9..1f36926c0 100644 --- a/Utilities/cmlibuv/src/unix/aix.c +++ b/Utilities/cmlibuv/src/unix/aix.c @@ -1,4 +1,5 @@ /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the @@ -64,11 +65,18 @@ #define RDWR_BUF_SIZE 4096 #define EQ(a,b) (strcmp(a,b) == 0) +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; static void* args_mem = NULL; static char** process_argv = NULL; static int process_argc = 0; static char* process_title_ptr = NULL; +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +} + + int uv__platform_loop_init(uv_loop_t* loop) { loop->fs_fd = -1; @@ -111,7 +119,7 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { pc.fd = fd; if (pollset_ctl(loop->backend_fd, &pc, 1)) - return -errno; + return UV__ERR(errno); pc.cmd = PS_DELETE; if (pollset_ctl(loop->backend_fd, &pc, 1)) @@ -316,104 +324,6 @@ update_timeout: } -uint64_t uv__hrtime(uv_clocktype_t type) { - uint64_t G = 1000000000; - timebasestruct_t t; - read_wall_time(&t, TIMEBASE_SZ); - time_base_to_time(&t, TIMEBASE_SZ); - return (uint64_t) t.tb_high * G + t.tb_low; -} - - -/* - * We could use a static buffer for the path manipulations that we need outside - * of the function, but this function could be called by multiple consumers and - * we don't want to potentially create a race condition in the use of snprintf. - * There is no direct way of getting the exe path in AIX - either through /procfs - * or through some libc APIs. The below approach is to parse the argv[0]'s pattern - * and use it in conjunction with PATH environment variable to craft one. - */ -int uv_exepath(char* buffer, size_t* size) { - int res; - char args[PATH_MAX]; - char abspath[PATH_MAX]; - size_t abspath_size; - struct procsinfo pi; - - if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; - - pi.pi_pid = getpid(); - res = getargs(&pi, sizeof(pi), args, sizeof(args)); - if (res < 0) - return -EINVAL; - - /* - * Possibilities for args: - * i) an absolute path such as: /home/user/myprojects/nodejs/node - * ii) a relative path such as: ./node or ../myprojects/nodejs/node - * iii) a bare filename such as "node", after exporting PATH variable - * to its location. - */ - - /* Case i) and ii) absolute or relative paths */ - if (strchr(args, '/') != NULL) { - if (realpath(args, abspath) != abspath) - return -errno; - - abspath_size = strlen(abspath); - - *size -= 1; - if (*size > abspath_size) - *size = abspath_size; - - memcpy(buffer, abspath, *size); - buffer[*size] = '\0'; - - return 0; - } else { - /* Case iii). Search PATH environment variable */ - char trypath[PATH_MAX]; - char *clonedpath = NULL; - char *token = NULL; - char *path = getenv("PATH"); - - if (path == NULL) - return -EINVAL; - - clonedpath = uv__strdup(path); - if (clonedpath == NULL) - return -ENOMEM; - - token = strtok(clonedpath, ":"); - while (token != NULL) { - snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args); - if (realpath(trypath, abspath) == abspath) { - /* Check the match is executable */ - if (access(abspath, X_OK) == 0) { - abspath_size = strlen(abspath); - - *size -= 1; - if (*size > abspath_size) - *size = abspath_size; - - memcpy(buffer, abspath, *size); - buffer[*size] = '\0'; - - uv__free(clonedpath); - return 0; - } - } - token = strtok(NULL, ":"); - } - uv__free(clonedpath); - - /* Out of tokens (path entries), and no match found */ - return -EINVAL; - } -} - - uint64_t uv_get_free_memory(void) { perfstat_memory_total_t mem_total; int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1); @@ -434,6 +344,11 @@ uint64_t uv_get_total_memory(void) { } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + void uv_loadavg(double avg[3]) { perfstat_cpu_total_t ps_total; int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1); @@ -448,19 +363,15 @@ void uv_loadavg(double avg[3]) { #ifdef HAVE_SYS_AHAFS_EVPRODS_H -static char *uv__rawname(char *cp) { - static char rawbuf[FILENAME_MAX+1]; - char *dp = rindex(cp, '/'); +static char* uv__rawname(const char* cp, char (*dst)[FILENAME_MAX+1]) { + char* dp; + dp = rindex(cp, '/'); if (dp == 0) return 0; - *dp = 0; - strcpy(rawbuf, cp); - *dp = '/'; - strcat(rawbuf, "/r"); - strcat(rawbuf, dp+1); - return rawbuf; + snprintf(*dst, sizeof(*dst), "%.*s/r%s", (int) (dp - cp), cp, dp + 1); + return *dst; } @@ -489,6 +400,7 @@ static int uv__path_is_a_directory(char* filename) { * Returns 0 if AHAFS is mounted, or an error code < 0 on failure */ static int uv__is_ahafs_mounted(void){ + char rawbuf[FILENAME_MAX+1]; int rv, i = 2; struct vmount *p; int size_multiplier = 10; @@ -499,22 +411,22 @@ static int uv__is_ahafs_mounted(void){ p = uv__malloc(siz); if (p == NULL) - return -errno; + return UV__ERR(errno); /* Retrieve all mounted filesystems */ rv = mntctl(MCTL_QUERY, siz, (char*)p); if (rv < 0) - return -errno; + return UV__ERR(errno); if (rv == 0) { /* buffer was not large enough, reallocate to correct size */ siz = *(int*)p; uv__free(p); p = uv__malloc(siz); if (p == NULL) - return -errno; + return UV__ERR(errno); rv = mntctl(MCTL_QUERY, siz, (char*)p); if (rv < 0) - return -errno; + return UV__ERR(errno); } /* Look for dev in filesystems mount info */ @@ -522,7 +434,7 @@ static int uv__is_ahafs_mounted(void){ obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */ stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */ - if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) { + if (EQ(obj, dev) || EQ(uv__rawname(obj, &rawbuf), dev) || EQ(stub, dev)) { uv__free(p); /* Found a match */ return 0; } @@ -543,7 +455,8 @@ static int uv__makedir_p(const char *dir) { size_t len; int err; - snprintf(tmp, sizeof(tmp),"%s",dir); + /* TODO(bnoordhuis) Check uv__strscpy() return value. */ + uv__strscpy(tmp, dir, sizeof(tmp)); len = strlen(tmp); if (tmp[len - 1] == '/') tmp[len - 1] = 0; @@ -585,7 +498,7 @@ static int uv__make_subdirs_p(const char *filename) { rc = uv__makedir_p(cmd); if (rc == -1 && errno != EEXIST){ - return -errno; + return UV__ERR(errno); } return rc; @@ -612,7 +525,7 @@ static int uv__setup_ahafs(const char* filename, int *fd) { sprintf(mon_file, "/aha/fs/modFile.monFactory"); if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX) - return -ENAMETOOLONG; + return UV_ENAMETOOLONG; /* Make the necessary subdirectories for the monitor file */ rc = uv__make_subdirs_p(filename); @@ -627,7 +540,7 @@ static int uv__setup_ahafs(const char* filename, int *fd) { /* Open the monitor file, creating it if necessary */ *fd = open(mon_file, O_CREAT|O_RDWR); if (*fd < 0) - return -errno; + return UV__ERR(errno); /* Write out the monitoring specifications. * In this case, we are monitoring for a state change event type @@ -647,8 +560,8 @@ static int uv__setup_ahafs(const char* filename, int *fd) { sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1"); rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1); - if (rc < 0) - return -errno; + if (rc < 0 && errno != EBUSY) + return UV__ERR(errno); return 0; } @@ -792,9 +705,9 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int else p++; } - strncpy(fname, p, sizeof(fname) - 1); - /* Just in case */ - fname[sizeof(fname) - 1] = '\0'; + + /* TODO(bnoordhuis) Check uv__strscpy() return value. */ + uv__strscpy(fname, p, sizeof(fname)); handle->cb(handle, fname, events, 0); } @@ -806,7 +719,7 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); return 0; #else - return -ENOSYS; + return UV_ENOSYS; #endif } @@ -820,12 +733,19 @@ int uv_fs_event_start(uv_fs_event_t* handle, char cwd[PATH_MAX]; char absolute_path[PATH_MAX]; char readlink_cwd[PATH_MAX]; + struct timeval zt; + fd_set pollfd; /* Figure out whether filename is absolute or not */ - if (filename[0] == '/') { + if (filename[0] == '\0') { + /* Missing a pathname */ + return UV_ENOENT; + } + else if (filename[0] == '/') { /* We have absolute pathname */ - snprintf(absolute_path, sizeof(absolute_path), "%s", filename); + /* TODO(bnoordhuis) Check uv__strscpy() return value. */ + uv__strscpy(absolute_path, filename, sizeof(absolute_path)); } else { /* We have a relative pathname, compose the absolute pathname */ snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid()); @@ -855,12 +775,22 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv__io_init(&handle->event_watcher, uv__ahafs_event, fd); handle->path = uv__strdup(filename); handle->cb = cb; + handle->dir_filename = NULL; uv__io_start(handle->loop, &handle->event_watcher, POLLIN); + /* AHAFS wants someone to poll for it to start mointoring. + * so kick-start it so that we don't miss an event in the + * eventuality of an event that occurs in the current loop. */ + do { + memset(&zt, 0, sizeof(zt)); + FD_ZERO(&pollfd); + FD_SET(fd, &pollfd); + rc = select(fd + 1, &pollfd, NULL, NULL, &zt); + } while (rc == -1 && errno == EINTR); return 0; #else - return -ENOSYS; + return UV_ENOSYS; #endif } @@ -885,7 +815,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { return 0; #else - return -ENOSYS; + return UV_ENOSYS; #endif } @@ -950,7 +880,10 @@ int uv_set_process_title(const char* title) { */ new_title = uv__strdup(title); if (new_title == NULL) - return -ENOMEM; + return UV_ENOMEM; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); /* If this is the first time this is set, * don't free and set argv[1] to NULL. @@ -964,19 +897,30 @@ int uv_set_process_title(const char* title) { if (process_argc > 1) process_argv[1] = NULL; + uv_mutex_unlock(&process_title_mutex); + return 0; } int uv_get_process_title(char* buffer, size_t size) { size_t len; - len = strlen(process_argv[0]); if (buffer == NULL || size == 0) - return -EINVAL; - else if (size <= len) - return -ENOBUFS; + return UV_EINVAL; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + len = strlen(process_argv[0]); + if (size <= len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + memcpy(buffer, process_argv[0], len); + buffer[len] = '\0'; - memcpy(buffer, process_argv[0], len + 1); + uv_mutex_unlock(&process_title_mutex); return 0; } @@ -998,10 +942,10 @@ int uv_resident_set_memory(size_t* rss) { fd = open(pp, O_RDONLY); if (fd == -1) - return -errno; + return UV__ERR(errno); /* FIXME(bnoordhuis) Handle EINTR. */ - err = -EINVAL; + err = UV_EINVAL; if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) { *rss = (size_t)psinfo.pr_rssize * 1024; err = 0; @@ -1017,6 +961,7 @@ int uv_uptime(double* uptime) { size_t entries = 0; time_t boot_time; + boot_time = 0; utmpname(UTMP_FILE); setutent(); @@ -1031,7 +976,7 @@ int uv_uptime(double* uptime) { endutent(); if (boot_time == 0) - return -ENOSYS; + return UV_ENOSYS; *uptime = time(NULL) - boot_time; return 0; @@ -1047,30 +992,31 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1); if (result == -1) { - return -ENOSYS; + return UV_ENOSYS; } ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0); if (result == -1) { - return -ENOSYS; + return UV_ENOSYS; } ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t)); if (!ps_cpus) { - return -ENOMEM; + return UV_ENOMEM; } - strcpy(cpu_id.name, FIRST_CPU); + /* TODO(bnoordhuis) Check uv__strscpy() return value. */ + uv__strscpy(cpu_id.name, FIRST_CPU, sizeof(cpu_id.name)); result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus); if (result == -1) { uv__free(ps_cpus); - return -ENOSYS; + return UV_ENOSYS; } *cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t)); if (!*cpu_infos) { uv__free(ps_cpus); - return -ENOMEM; + return UV_ENOMEM; } *count = ncpus; @@ -1093,130 +1039,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { } -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - int i; - - for (i = 0; i < count; ++i) { - uv__free(cpu_infos[i].model); - } - - uv__free(cpu_infos); -} - - -int uv_interface_addresses(uv_interface_address_t** addresses, - int* count) { - uv_interface_address_t* address; - int sockfd, size = 1; - struct ifconf ifc; - struct ifreq *ifr, *p, flg; - - *count = 0; - - if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { - return -errno; - } - - if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { - uv__close(sockfd); - return -errno; - } - - ifc.ifc_req = (struct ifreq*)uv__malloc(size); - ifc.ifc_len = size; - if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { - uv__close(sockfd); - return -errno; - } - -#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p)) - - /* Count all up and running ipv4/ipv6 addresses */ - ifr = ifc.ifc_req; - while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { - p = ifr; - ifr = (struct ifreq*) - ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); - - if (!(p->ifr_addr.sa_family == AF_INET6 || - p->ifr_addr.sa_family == AF_INET)) - continue; - - memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); - if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { - uv__close(sockfd); - return -errno; - } - - if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) - continue; - - (*count)++; - } - - /* Alloc the return interface structs */ - *addresses = (uv_interface_address_t*) - uv__malloc(*count * sizeof(uv_interface_address_t)); - if (!(*addresses)) { - uv__close(sockfd); - return -ENOMEM; - } - address = *addresses; - - ifr = ifc.ifc_req; - while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { - p = ifr; - ifr = (struct ifreq*) - ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr)); - - if (!(p->ifr_addr.sa_family == AF_INET6 || - p->ifr_addr.sa_family == AF_INET)) - continue; - - memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); - if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { - uv__close(sockfd); - return -ENOSYS; - } - - if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) - continue; - - /* All conditions above must match count loop */ - - address->name = uv__strdup(p->ifr_name); - - if (p->ifr_addr.sa_family == AF_INET6) { - address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr); - } else { - address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); - } - - /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ - - address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; - - address++; - } - -#undef ADDR_SIZE - - uv__close(sockfd); - return 0; -} - - -void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - int i; - - for (i = 0; i < count; ++i) { - uv__free(addresses[i].name); - } - - uv__free(addresses); -} - void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { struct pollfd* events; uintptr_t i; @@ -1224,6 +1046,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { struct poll_ctl pc; assert(loop->watchers != NULL); + assert(fd >= 0); events = (struct pollfd*) loop->watchers[loop->nwatchers]; nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; diff --git a/Utilities/cmlibuv/src/unix/android-ifaddrs.c b/Utilities/cmlibuv/src/unix/android-ifaddrs.c index 30f681b7d..99fb25a43 100644 --- a/Utilities/cmlibuv/src/unix/android-ifaddrs.c +++ b/Utilities/cmlibuv/src/unix/android-ifaddrs.c @@ -23,7 +23,7 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "android-ifaddrs.h" +#include "uv/android-ifaddrs.h" #include "uv-common.h" #include <string.h> @@ -43,9 +43,10 @@ typedef struct NetlinkList unsigned int m_size; } NetlinkList; -static int netlink_socket(void) +static int netlink_socket(pid_t *p_pid) { struct sockaddr_nl l_addr; + socklen_t l_len; int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if(l_socket < 0) @@ -61,6 +62,14 @@ static int netlink_socket(void) return -1; } + l_len = sizeof(l_addr); + if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0) + { + close(l_socket); + return -1; + } + *p_pid = l_addr.nl_pid; + return l_socket; } @@ -128,7 +137,7 @@ static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) } } -static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) +static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done) { size_t l_size = 4096; void *l_buffer = NULL; @@ -153,11 +162,10 @@ static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_don } if(l_read >= 0) { - pid_t l_pid = getpid(); struct nlmsghdr *l_hdr; for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) { - if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket) { continue; } @@ -207,7 +215,7 @@ static void freeResultList(NetlinkList *p_list) } } -static NetlinkList *getResultList(int p_socket, int p_request) +static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid) { int l_size; int l_done; @@ -227,7 +235,7 @@ static NetlinkList *getResultList(int p_socket, int p_request) { NetlinkList *l_item; - struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); + struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done); /* Error */ if(!l_hdr) { @@ -449,7 +457,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, char *l_name; char *l_addr; - for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); if(l_info->ifa_family == AF_PACKET) @@ -471,7 +479,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); break; case IFA_LABEL: - l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); + l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1); break; default: break; @@ -496,7 +504,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, } l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); - for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { void *l_rtaData = RTA_DATA(l_rta); size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); @@ -559,7 +567,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, { unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); - char l_mask[16] = {0}; + unsigned char l_mask[16] = {0}; unsigned i; for(i=0; i<(l_prefix/8); ++i) { @@ -578,18 +586,17 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, return 0; } -static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) +static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) { int l_numLinks = 0; - pid_t l_pid = getpid(); for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) { unsigned int l_nlsize = p_netlinkList->m_size; struct nlmsghdr *l_hdr; for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) { - if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket) { continue; } @@ -612,16 +619,15 @@ static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifadd return l_numLinks; } -static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) +static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) { - pid_t l_pid = getpid(); for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) { unsigned int l_nlsize = p_netlinkList->m_size; struct nlmsghdr *l_hdr; for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) { - if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket) { continue; } @@ -648,6 +654,7 @@ int getifaddrs(struct ifaddrs **ifap) int l_socket; int l_result; int l_numLinks; + pid_t l_pid; NetlinkList *l_linkResults; NetlinkList *l_addrResults; @@ -657,20 +664,20 @@ int getifaddrs(struct ifaddrs **ifap) } *ifap = NULL; - l_socket = netlink_socket(); + l_socket = netlink_socket(&l_pid); if(l_socket < 0) { return -1; } - l_linkResults = getResultList(l_socket, RTM_GETLINK); + l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid); if(!l_linkResults) { close(l_socket); return -1; } - l_addrResults = getResultList(l_socket, RTM_GETADDR); + l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid); if(!l_addrResults) { close(l_socket); @@ -679,8 +686,8 @@ int getifaddrs(struct ifaddrs **ifap) } l_result = 0; - l_numLinks = interpretLinks(l_socket, l_linkResults, ifap); - if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1) + l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap); + if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1) { l_result = -1; } diff --git a/Utilities/cmlibuv/src/unix/async.c b/Utilities/cmlibuv/src/unix/async.c index 45c088ea1..a5c47bca0 100644 --- a/Utilities/cmlibuv/src/unix/async.c +++ b/Utilities/cmlibuv/src/unix/async.c @@ -61,14 +61,43 @@ int uv_async_send(uv_async_t* handle) { if (ACCESS_ONCE(int, handle->pending) != 0) return 0; - if (cmpxchgi(&handle->pending, 0, 1) == 0) - uv__async_send(handle->loop); + /* Tell the other thread we're busy with the handle. */ + if (cmpxchgi(&handle->pending, 0, 1) != 0) + return 0; + + /* Wake up the other thread's event loop. */ + uv__async_send(handle->loop); + + /* Tell the other thread we're done. */ + if (cmpxchgi(&handle->pending, 1, 2) != 1) + abort(); return 0; } +/* Only call this from the event loop thread. */ +static int uv__async_spin(uv_async_t* handle) { + int rc; + + for (;;) { + /* rc=0 -- handle is not pending. + * rc=1 -- handle is pending, other thread is still working with it. + * rc=2 -- handle is pending, other thread is done. + */ + rc = cmpxchgi(&handle->pending, 2, 0); + + if (rc != 1) + return rc; + + /* Other thread is busy with this handle, spin until it's done. */ + cpu_relax(); + } +} + + void uv__async_close(uv_async_t* handle) { + uv__async_spin(handle); QUEUE_REMOVE(&handle->queue); uv__handle_stop(handle); } @@ -109,8 +138,8 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { QUEUE_REMOVE(q); QUEUE_INSERT_TAIL(&loop->async_handles, q); - if (cmpxchgi(&h->pending, 1, 0) == 0) - continue; + if (0 == uv__async_spin(h)) + continue; /* Not pending. */ if (h->async_cb == NULL) continue; @@ -166,7 +195,7 @@ static int uv__async_start(uv_loop_t* loop) { pipefd[0] = err; pipefd[1] = -1; } - else if (err == -ENOSYS) { + else if (err == UV_ENOSYS) { err = uv__make_pipe(pipefd, UV__F_NONBLOCK); #if defined(__linux__) /* Save a file descriptor by opening one of the pipe descriptors as @@ -240,7 +269,7 @@ static int uv__async_eventfd(void) { return fd; if (errno != ENOSYS) - return -errno; + return UV__ERR(errno); no_eventfd2 = 1; @@ -257,7 +286,7 @@ skip_eventfd2: } if (errno != ENOSYS) - return -errno; + return UV__ERR(errno); no_eventfd = 1; @@ -265,5 +294,5 @@ skip_eventfd: #endif - return -ENOSYS; + return UV_ENOSYS; } diff --git a/Utilities/cmlibuv/src/unix/atomic-ops.h b/Utilities/cmlibuv/src/unix/atomic-ops.h index 9dac2557f..995aca63a 100644 --- a/Utilities/cmlibuv/src/unix/atomic-ops.h +++ b/Utilities/cmlibuv/src/unix/atomic-ops.h @@ -20,11 +20,9 @@ #if defined(__SUNPRO_C) || defined(__SUNPRO_CC) #include <atomic.h> -#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n) #endif UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)); -UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)); UV_UNUSED(static void cpu_relax(void)); /* Prefer hand-rolled assembly over the gcc builtins because the latter also @@ -38,7 +36,7 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { : "r" (newval), "0" (oldval) : "memory"); return out; -#elif defined(_AIX) && defined(__xlC__) +#elif defined(_AIX) && (defined(__xlC__) || defined(__ibmxl__)) const int out = (*(volatile int*) ptr); __compare_and_swap(ptr, &oldval, newval); return out; @@ -49,40 +47,8 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { return oldval; else return op4; -#else - return __sync_val_compare_and_swap(ptr, oldval, newval); -#endif -} - -UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) { -#if defined(__i386__) || defined(__x86_64__) - long out; - __asm__ __volatile__ ("lock; cmpxchg %2, %1;" - : "=a" (out), "+m" (*(volatile long*) ptr) - : "r" (newval), "0" (oldval) - : "memory"); - return out; -#elif defined(_AIX) && defined(__xlC__) - const long out = (*(volatile int*) ptr); -# if defined(__64BIT__) - __compare_and_swaplp(ptr, &oldval, newval); -# else - __compare_and_swap(ptr, &oldval, newval); -# endif /* if defined(__64BIT__) */ - return out; -#elif defined (__MVS__) -#ifdef _LP64 - unsigned long long op4; - if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval, - (unsigned long long*) ptr, *ptr, &op4)) -#else - unsigned long op4; - if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, - (unsigned int*) ptr, *ptr, &op4)) -#endif - return oldval; - else - return op4; +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) + return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval); #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif diff --git a/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c b/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c index 414789451..0d7bbe662 100644 --- a/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c +++ b/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c @@ -31,12 +31,26 @@ #include <net/if_dl.h> #endif -static int uv__ifaddr_exclude(struct ifaddrs *ent) { +#if defined(__HAIKU__) +#define IFF_RUNNING IFF_LINK +#endif + +static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) return 1; if (ent->ifa_addr == NULL) return 1; -#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) +#if !defined(__CYGWIN__) && !defined(__MSYS__) + /* + * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family` + * equals to `AF_LINK` or not. Otherwise, the result depends on the operation + * system with `AF_LINK` or `PF_INET`. + */ + if (exclude_type == UV__EXCLUDE_IFPHYS) + return (ent->ifa_addr->sa_family != AF_LINK); +#endif +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) || \ + defined(__HAIKU__) /* * On BSD getifaddrs returns information related to the raw underlying * devices. We're not interested in this information. @@ -44,7 +58,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) { if (ent->ifa_addr->sa_family == AF_LINK) return 1; #elif defined(__NetBSD__) || defined(__OpenBSD__) - if (ent->ifa_addr->sa_family != PF_INET) + if (ent->ifa_addr->sa_family != PF_INET && + ent->ifa_addr->sa_family != PF_INET6) return 1; #endif return 0; @@ -56,29 +71,36 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; int i; - if (getifaddrs(&addrs) != 0) - return -errno; - *count = 0; + *addresses = NULL; + + if (getifaddrs(&addrs) != 0) + return UV__ERR(errno); /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; (*count)++; } - *addresses = uv__malloc(*count * sizeof(**addresses)); + if (*count == 0) { + freeifaddrs(addrs); + return 0; + } + + /* Make sure the memory is initiallized to zero using calloc() */ + *addresses = uv__calloc(*count, sizeof(**addresses)); if (*addresses == NULL) { freeifaddrs(addrs); - return -ENOMEM; + return UV_ENOMEM; } address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; address->name = uv__strdup(ent->ifa_name); @@ -100,26 +122,24 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address++; } +#if !(defined(__CYGWIN__) || defined(__MSYS__)) /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) continue; address = *addresses; 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++; } } +#endif freeifaddrs(addrs); diff --git a/Utilities/cmlibuv/src/unix/bsd-proctitle.c b/Utilities/cmlibuv/src/unix/bsd-proctitle.c new file mode 100644 index 000000000..0ce47c8f6 --- /dev/null +++ b/Utilities/cmlibuv/src/unix/bsd-proctitle.c @@ -0,0 +1,93 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include <sys/types.h> +#include <unistd.h> + + +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static char* process_title; + + +static void init_process_title_mutex_once(void) { + if (uv_mutex_init(&process_title_mutex)) + abort(); +} + + +char** uv_setup_args(int argc, char** argv) { + process_title = argc > 0 ? uv__strdup(argv[0]) : NULL; + return argv; +} + + +int uv_set_process_title(const char* title) { + char* new_title; + + new_title = uv__strdup(title); + if (new_title == NULL) + return UV_ENOMEM; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + uv__free(process_title); + process_title = new_title; + setproctitle("%s", title); + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title != NULL) { + len = strlen(process_title) + 1; + + if (size < len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + uv_mutex_unlock(&process_title_mutex); + + buffer[len] = '\0'; + + return 0; +} diff --git a/Utilities/cmlibuv/src/unix/cmake-bootstrap.c b/Utilities/cmlibuv/src/unix/cmake-bootstrap.c new file mode 100644 index 000000000..d42ff05c5 --- /dev/null +++ b/Utilities/cmlibuv/src/unix/cmake-bootstrap.c @@ -0,0 +1,149 @@ +#include "uv.h" +#include "internal.h" + +int uv__tcp_nodelay(int fd, int on) { + errno = EINVAL; + return -1; +} + +int uv__tcp_keepalive(int fd, int on, unsigned int delay) { + errno = EINVAL; + return -1; +} + +int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { + return -EINVAL; +} + +int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { + return -EINVAL; +} + +void uv__tcp_close(uv_tcp_t* handle) { +} + +void uv__udp_close(uv_udp_t* handle) { +} + +void uv__udp_finish_close(uv_udp_t* handle) { +} + +void uv__fs_poll_close(uv_fs_poll_t* handle) { +} + +int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { + return 0; +} + +void uv__async_close(uv_async_t* handle) { +} + +int uv__async_fork(uv_loop_t* loop) { + return 0; +} + +void uv__async_stop(uv_loop_t* loop) { +} + +void uv__work_submit(uv_loop_t* loop, struct uv__work* w, + enum uv__work_kind kind, + void (*work)(struct uv__work* w), + void (*done)(struct uv__work* w, int status)) { + abort(); +} + +void uv__work_done(uv_async_t* handle) { +} + +int uv__pthread_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void)) { + return 0; +} + +int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { + return 0; +} + +int uv_mutex_init(uv_mutex_t* mutex) { + return 0; +} + +void uv_mutex_destroy(uv_mutex_t* mutex) { +} + +void uv_mutex_lock(uv_mutex_t* mutex) { +} + +void uv_mutex_unlock(uv_mutex_t* mutex) { +} + +int uv_rwlock_init(uv_rwlock_t* rwlock) { + return 0; +} + +void uv_rwlock_destroy(uv_rwlock_t* rwlock) { +} + +void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { +} + +void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { +} + +void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { +} + +void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { +} + +void uv_once(uv_once_t* guard, void (*callback)(void)) { + if (*guard) { + return; + } + *guard = 1; + callback(); +} + +#if defined(__linux__) +int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { + errno = ENOSYS; + return -1; +} + +int uv__dup3(int oldfd, int newfd, int flags) { + errno = ENOSYS; + return -1; +} + +int uv__pipe2(int pipefd[2], int flags) { + errno = ENOSYS; + return -1; +} + +ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, + int64_t offset) { + errno = ENOSYS; + return -1; +} + +ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, + int64_t offset) { + errno = ENOSYS; + return -1; +} + +int uv__utimesat(int dirfd, const char* path, const struct timespec times[2], + int flags) { + errno = ENOSYS; + return -1; +} + +int uv__statx(int dirfd, + const char* path, + int flags, + unsigned int mask, + struct uv__statx* statxbuf) { + errno = ENOSYS; + return -1; +} +#endif diff --git a/Utilities/cmlibuv/src/unix/core.c b/Utilities/cmlibuv/src/unix/core.c index 30cdaef7b..cf7dea050 100644 --- a/Utilities/cmlibuv/src/unix/core.c +++ b/Utilities/cmlibuv/src/unix/core.c @@ -28,7 +28,6 @@ #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> @@ -41,9 +40,11 @@ #include <sys/uio.h> /* writev */ #include <sys/resource.h> /* getrusage */ #include <pwd.h> +#include <sched.h> +#include <sys/utsname.h> +#include <sys/time.h> #ifdef __sun -# include <netdb.h> /* MAXHOSTNAMELEN on Solaris */ # include <sys/filio.h> # include <sys/types.h> # include <sys/wait.h> @@ -59,13 +60,21 @@ #if defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) # include <sys/sysctl.h> # include <sys/filio.h> # include <sys/wait.h> +# include <sys/param.h> +# include <sys/cpuset.h> # define UV__O_CLOEXEC O_CLOEXEC # if defined(__FreeBSD__) && __FreeBSD__ >= 10 # define uv__accept4 accept4 +# endif +# if defined(__NetBSD__) +# define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d)) +# endif +# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__) # define UV__SOCK_NONBLOCK SOCK_NONBLOCK # define UV__SOCK_CLOEXEC SOCK_CLOEXEC # endif @@ -82,9 +91,8 @@ #include <sys/ioctl.h> #endif -/* Fallback for the maximum hostname length */ -#ifndef MAXHOSTNAMELEN -# define MAXHOSTNAMELEN 256 +#if defined(__linux__) +#include <sys/syscall.h> #endif static int uv__run_pending(uv_loop_t* loop); @@ -107,7 +115,7 @@ uint64_t uv_hrtime(void) { void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { assert(!uv__is_closing(handle)); - handle->flags |= UV_CLOSING; + handle->flags |= UV_HANDLE_CLOSING; handle->close_cb = close_cb; switch (handle->type) { @@ -161,12 +169,14 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { case UV_FS_POLL: uv__fs_poll_close((uv_fs_poll_t*)handle); - break; + /* Poll handles use file system requests, and one of them may still be + * running. The poll code will call uv__make_close_pending() for us. */ + return; case UV_SIGNAL: uv__signal_close((uv_signal_t*) handle); - /* Signal handles may not be closed immediately. The signal code will */ - /* itself close uv__make_close_pending whenever appropriate. */ + /* Signal handles may not be closed immediately. The signal code will + * itself close uv__make_close_pending whenever appropriate. */ return; default: @@ -182,14 +192,14 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { socklen_t len; if (handle == NULL || value == NULL) - return -EINVAL; + return UV_EINVAL; if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE) fd = uv__stream_fd((uv_stream_t*) handle); else if (handle->type == UV_UDP) fd = ((uv_udp_t *) handle)->io_watcher.fd; else - return -ENOTSUP; + return UV_ENOTSUP; len = sizeof(*value); @@ -199,14 +209,14 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len); if (r < 0) - return -errno; + return UV__ERR(errno); return 0; } void uv__make_close_pending(uv_handle_t* handle) { - assert(handle->flags & UV_CLOSING); - assert(!(handle->flags & UV_CLOSED)); + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->next_closing = handle->loop->closing_handles; handle->loop->closing_handles = handle; } @@ -232,15 +242,17 @@ int uv__getiovmax(void) { static void uv__finish_close(uv_handle_t* handle) { - /* Note: while the handle is in the UV_CLOSING state now, it's still possible - * for it to be active in the sense that uv__is_active() returns true. + /* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still + * possible for it to be active in the sense that uv__is_active() returns + * true. + * * A good example is when the user calls uv_shutdown(), immediately followed * by uv_close(). The handle is considered active at this point because the * completion of the shutdown req is still pending. */ - assert(handle->flags & UV_CLOSING); - assert(!(handle->flags & UV_CLOSED)); - handle->flags |= UV_CLOSED; + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + handle->flags |= UV_HANDLE_CLOSED; switch (handle->type) { case UV_PREPARE: @@ -409,12 +421,12 @@ int uv__socket(int domain, int type, int protocol) { return sockfd; if (errno != EINVAL) - return -errno; + return UV__ERR(errno); #endif sockfd = socket(domain, type, protocol); if (sockfd == -1) - return -errno; + return UV__ERR(errno); err = uv__nonblock(sockfd, 1); if (err == 0) @@ -459,7 +471,9 @@ int uv__accept(int sockfd) { assert(sockfd >= 0); while (1) { -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) +#if defined(__linux__) || \ + (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \ + defined(__NetBSD__) static int no_accept4; if (no_accept4) @@ -476,7 +490,7 @@ int uv__accept(int sockfd) { continue; if (errno != ENOSYS) - return -errno; + return UV__ERR(errno); no_accept4 = 1; skip: @@ -486,7 +500,7 @@ skip: if (peerfd == -1) { if (errno == EINTR) continue; - return -errno; + return UV__ERR(errno); } err = uv__cloexec(peerfd, 1); @@ -503,6 +517,34 @@ skip: } +/* close() on macos has the "interesting" quirk that it fails with EINTR + * without closing the file descriptor when a thread is in the cancel state. + * That's why libuv calls close$NOCANCEL() instead. + * + * glibc on linux has a similar issue: close() is a cancellation point and + * will unwind the thread when it's in the cancel state. Work around that + * by making the system call directly. Musl libc is unaffected. + */ +int uv__close_nocancel(int fd) { +#if defined(__APPLE__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension" +#if defined(__LP64__) + extern int close$NOCANCEL(int); + return close$NOCANCEL(fd); +#else + extern int close$NOCANCEL$UNIX2003(int); + return close$NOCANCEL$UNIX2003(fd); +#endif +#pragma GCC diagnostic pop +#elif defined(__linux__) + return syscall(SYS_close, fd); +#else + return close(fd); +#endif +} + + int uv__close_nocheckstdio(int fd) { int saved_errno; int rc; @@ -510,10 +552,10 @@ int uv__close_nocheckstdio(int fd) { assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */ saved_errno = errno; - rc = close(fd); + rc = uv__close_nocancel(fd); if (rc == -1) { - rc = -errno; - if (rc == -EINTR || rc == -EINPROGRESS) + rc = UV__ERR(errno); + if (rc == UV_EINTR || rc == UV__ERR(EINPROGRESS)) rc = 0; /* The close is in progress, not an error. */ errno = saved_errno; } @@ -525,7 +567,7 @@ int uv__close_nocheckstdio(int fd) { int uv__close(int fd) { assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */ #if defined(__MVS__) - epoll_file_close(fd); + SAVE_ERRNO(epoll_file_close(fd)); #endif return uv__close_nocheckstdio(fd); } @@ -539,13 +581,13 @@ int uv__nonblock_ioctl(int fd, int set) { while (r == -1 && errno == EINTR); if (r) - return -errno; + return UV__ERR(errno); return 0; } -#if !defined(__CYGWIN__) && !defined(__MSYS__) +#if !defined(__hpux) && !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__HAIKU__) int uv__cloexec_ioctl(int fd, int set) { int r; @@ -554,7 +596,7 @@ int uv__cloexec_ioctl(int fd, int set) { while (r == -1 && errno == EINTR); if (r) - return -errno; + return UV__ERR(errno); return 0; } @@ -570,7 +612,7 @@ int uv__nonblock_fcntl(int fd, int set) { while (r == -1 && errno == EINTR); if (r == -1) - return -errno; + return UV__ERR(errno); /* Bail out now if already set/clear. */ if (!!(r & O_NONBLOCK) == !!set) @@ -586,7 +628,7 @@ int uv__nonblock_fcntl(int fd, int set) { while (r == -1 && errno == EINTR); if (r) - return -errno; + return UV__ERR(errno); return 0; } @@ -601,7 +643,7 @@ int uv__cloexec_fcntl(int fd, int set) { while (r == -1 && errno == EINTR); if (r == -1) - return -errno; + return UV__ERR(errno); /* Bail out now if already set/clear. */ if (!!(r & FD_CLOEXEC) == !!set) @@ -617,33 +659,12 @@ int uv__cloexec_fcntl(int fd, int set) { while (r == -1 && errno == EINTR); if (r) - return -errno; + return UV__ERR(errno); return 0; } -/* This function is not execve-safe, there is a race window - * between the call to dup() and fcntl(FD_CLOEXEC). - */ -int uv__dup(int fd) { - int err; - - fd = dup(fd); - - if (fd == -1) - return -errno; - - err = uv__cloexec(fd, 1); - if (err) { - uv__close(fd); - return err; - } - - return fd; -} - - ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { struct cmsghdr* cmsg; ssize_t rc; @@ -656,10 +677,10 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { if (rc != -1) return rc; if (errno != EINVAL) - return -errno; + return UV__ERR(errno); rc = recvmsg(fd, msg, flags); if (rc == -1) - return -errno; + return UV__ERR(errno); no_msg_cmsg_cloexec = 1; } else { rc = recvmsg(fd, msg, flags); @@ -668,7 +689,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { rc = recvmsg(fd, msg, flags); #endif if (rc == -1) - return -errno; + return UV__ERR(errno); if (msg->msg_controllen == 0) return rc; for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) @@ -684,10 +705,10 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { int uv_cwd(char* buffer, size_t* size) { if (buffer == NULL || size == NULL) - return -EINVAL; + return UV_EINVAL; if (getcwd(buffer, *size) == NULL) - return -errno; + return UV__ERR(errno); *size = strlen(buffer); if (*size > 1 && buffer[*size - 1] == '/') { @@ -701,7 +722,7 @@ int uv_cwd(char* buffer, size_t* size) { int uv_chdir(const char* dir) { if (chdir(dir)) - return -errno; + return UV__ERR(errno); return 0; } @@ -738,11 +759,11 @@ int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) { break; default: - return -EINVAL; + return UV_EINVAL; } if (uv__is_closing(handle) || fd_out == -1) - return -EBADF; + return UV_EBADF; *fd = fd_out; return 0; @@ -835,7 +856,7 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); @@ -863,7 +884,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); if (w->fd == -1) @@ -895,11 +916,12 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_close(uv_loop_t* loop, uv__io_t* w) { - uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); QUEUE_REMOVE(&w->pending_queue); /* Remove stale events for this file descriptor */ - uv__platform_invalidate_fd(loop, w->fd); + if (w->fd != -1) + uv__platform_invalidate_fd(loop, w->fd); } @@ -910,17 +932,22 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { int uv__io_active(const uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI))); assert(0 != events); return 0 != (w->pevents & events); } +int uv__fd_exists(uv_loop_t* loop, int fd) { + return (unsigned) fd < loop->nwatchers && loop->watchers[fd] != NULL; +} + + int uv_getrusage(uv_rusage_t* rusage) { struct rusage usage; if (getrusage(RUSAGE_SELF, &usage)) - return -errno; + return UV__ERR(errno); rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec; rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec; @@ -928,7 +955,7 @@ int uv_getrusage(uv_rusage_t* rusage) { rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec; rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec; -#if !defined(__MVS__) +#if !defined(__MVS__) && !defined(__HAIKU__) rusage->ru_maxrss = usage.ru_maxrss; rusage->ru_ixrss = usage.ru_ixrss; rusage->ru_idrss = usage.ru_idrss; @@ -962,7 +989,7 @@ int uv__open_cloexec(const char* path, int flags) { return fd; if (errno != EINVAL) - return -errno; + return UV__ERR(errno); /* O_CLOEXEC not supported. */ no_cloexec = 1; @@ -971,7 +998,7 @@ int uv__open_cloexec(const char* path, int flags) { fd = open(path, flags); if (fd == -1) - return -errno; + return UV__ERR(errno); err = uv__cloexec(fd, 1); if (err) { @@ -985,17 +1012,17 @@ int uv__open_cloexec(const char* path, int flags) { int uv__dup2_cloexec(int oldfd, int newfd) { int r; -#if defined(__FreeBSD__) && __FreeBSD__ >= 10 +#if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__) r = dup3(oldfd, newfd, O_CLOEXEC); if (r == -1) - return -errno; + return UV__ERR(errno); return r; #elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC) r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); if (r != -1) return r; if (errno != EINVAL) - return -errno; + return UV__ERR(errno); /* Fall through. */ #elif defined(__linux__) static int no_dup3; @@ -1006,7 +1033,7 @@ int uv__dup2_cloexec(int oldfd, int newfd) { if (r != -1) return r; if (errno != ENOSYS) - return -errno; + return UV__ERR(errno); /* Fall through. */ no_dup3 = 1; } @@ -1022,7 +1049,7 @@ int uv__dup2_cloexec(int oldfd, int newfd) { #endif if (r == -1) - return -errno; + return UV__ERR(errno); err = uv__cloexec(newfd, 1); if (err) { @@ -1037,29 +1064,16 @@ int uv__dup2_cloexec(int oldfd, int newfd) { int uv_os_homedir(char* buffer, size_t* size) { uv_passwd_t pwd; - char* buf; size_t len; int r; - if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; - - /* Check if the HOME environment variable is set first */ - buf = getenv("HOME"); + /* Check if the HOME environment variable is set first. The task of + performing input validation on buffer and size is taken care of by + uv_os_getenv(). */ + r = uv_os_getenv("HOME", buffer, size); - if (buf != NULL) { - len = strlen(buf); - - if (len >= *size) { - *size = len + 1; - return -ENOBUFS; - } - - memcpy(buffer, buf, len + 1); - *size = len; - - return 0; - } + if (r != UV_ENOENT) + return r; /* HOME is not set, so call uv__getpwuid_r() */ r = uv__getpwuid_r(&pwd); @@ -1073,7 +1087,7 @@ int uv_os_homedir(char* buffer, size_t* size) { if (len >= *size) { *size = len + 1; uv_os_free_passwd(&pwd); - return -ENOBUFS; + return UV_ENOBUFS; } memcpy(buffer, pwd.homedir, len + 1); @@ -1089,7 +1103,7 @@ int uv_os_tmpdir(char* buffer, size_t* size) { size_t len; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; #define CHECK_ENV_VAR(name) \ do { \ @@ -1119,7 +1133,7 @@ return_buffer: if (len >= *size) { *size = len + 1; - return -ENOBUFS; + return UV_ENOBUFS; } /* The returned directory should not have a trailing slash. */ @@ -1151,11 +1165,11 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); if (getpwuid_r == NULL) - return -ENOSYS; + return UV_ENOSYS; #endif if (pwd == NULL) - return -EINVAL; + return UV_EINVAL; initsize = sysconf(_SC_GETPW_R_SIZE_MAX); @@ -1172,7 +1186,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { buf = uv__malloc(bufsize); if (buf == NULL) - return -ENOMEM; + return UV_ENOMEM; r = getpwuid_r(uid, &pw, buf, bufsize, &result); @@ -1189,7 +1203,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { if (result == NULL) { uv__free(buf); - return -ENOENT; + return UV_ENOENT; } /* Allocate memory for the username, shell, and home directory */ @@ -1200,7 +1214,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { if (pwd->username == NULL) { uv__free(buf); - return -ENOMEM; + return UV_ENOMEM; } /* Copy the username */ @@ -1256,18 +1270,18 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { size_t len; if (name == NULL || buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; var = getenv(name); if (var == NULL) - return -ENOENT; + return UV_ENOENT; len = strlen(var); if (len >= *size) { *size = len + 1; - return -ENOBUFS; + return UV_ENOBUFS; } memcpy(buffer, var, len + 1); @@ -1279,18 +1293,21 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { int uv_os_setenv(const char* name, const char* value) { if (name == NULL || value == NULL) - return -EINVAL; + return UV_EINVAL; if (setenv(name, value, 1) != 0) - return -errno; + return UV__ERR(errno); return 0; } int uv_os_unsetenv(const char* name) { + if (name == NULL) + return UV_EINVAL; + if (unsetenv(name) != 0) - return -errno; + return UV__ERR(errno); return 0; } @@ -1303,24 +1320,171 @@ int uv_os_gethostname(char* buffer, size_t* size) { instead by creating a large enough buffer and comparing the hostname length to the size input. */ - char buf[MAXHOSTNAMELEN + 1]; + char buf[UV_MAXHOSTNAMESIZE]; size_t len; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; if (gethostname(buf, sizeof(buf)) != 0) - return -errno; + return UV__ERR(errno); buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */ len = strlen(buf); if (len >= *size) { *size = len + 1; - return -ENOBUFS; + return UV_ENOBUFS; } memcpy(buffer, buf, len + 1); *size = len; return 0; } + + +int uv_cpumask_size(void) { +#if defined(__linux__) || defined(__FreeBSD__) + return CPU_SETSIZE; +#else + return UV_ENOTSUP; +#endif +} + + +uv_os_fd_t uv_get_osfhandle(int fd) { + return fd; +} + +int uv_open_osfhandle(uv_os_fd_t os_fd) { + return os_fd; +} + +uv_pid_t uv_os_getpid(void) { + return getpid(); +} + + +uv_pid_t uv_os_getppid(void) { + return getppid(); +} + + +int uv_os_getpriority(uv_pid_t pid, int* priority) { + int r; + + if (priority == NULL) + return UV_EINVAL; + + errno = 0; + r = getpriority(PRIO_PROCESS, (int) pid); + + if (r == -1 && errno != 0) + return UV__ERR(errno); + + *priority = r; + return 0; +} + + +int uv_os_setpriority(uv_pid_t pid, int priority) { + if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW) + return UV_EINVAL; + + if (setpriority(PRIO_PROCESS, (int) pid, priority) != 0) + return UV__ERR(errno); + + return 0; +} + + +int uv_os_uname(uv_utsname_t* buffer) { + struct utsname buf; + int r; + + if (buffer == NULL) + return UV_EINVAL; + + if (uname(&buf) == -1) { + r = UV__ERR(errno); + goto error; + } + + r = uv__strscpy(buffer->sysname, buf.sysname, sizeof(buffer->sysname)); + if (r == UV_E2BIG) + goto error; + +#ifdef _AIX + r = snprintf(buffer->release, + sizeof(buffer->release), + "%s.%s", + buf.version, + buf.release); + if (r >= sizeof(buffer->release)) { + r = UV_E2BIG; + goto error; + } +#else + r = uv__strscpy(buffer->release, buf.release, sizeof(buffer->release)); + if (r == UV_E2BIG) + goto error; +#endif + + r = uv__strscpy(buffer->version, buf.version, sizeof(buffer->version)); + if (r == UV_E2BIG) + goto error; + +#if defined(_AIX) || defined(__PASE__) + r = uv__strscpy(buffer->machine, "ppc64", sizeof(buffer->machine)); +#else + r = uv__strscpy(buffer->machine, buf.machine, sizeof(buffer->machine)); +#endif + + if (r == UV_E2BIG) + goto error; + + return 0; + +error: + buffer->sysname[0] = '\0'; + buffer->release[0] = '\0'; + buffer->version[0] = '\0'; + buffer->machine[0] = '\0'; + return r; +} + +int uv__getsockpeername(const uv_handle_t* handle, + uv__peersockfunc func, + struct sockaddr* name, + int* namelen) { + socklen_t socklen; + uv_os_fd_t fd; + int r; + + r = uv_fileno(handle, &fd); + if (r < 0) + return r; + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (func(fd, name, &socklen)) + return UV__ERR(errno); + + *namelen = (int) socklen; + return 0; +} + +int uv_gettimeofday(uv_timeval64_t* tv) { + struct timeval time; + + if (tv == NULL) + return UV_EINVAL; + + if (gettimeofday(&time, NULL) != 0) + return UV__ERR(errno); + + tv->tv_sec = (int64_t) time.tv_sec; + tv->tv_usec = (int32_t) time.tv_usec; + return 0; +} diff --git a/Utilities/cmlibuv/src/unix/cygwin.c b/Utilities/cmlibuv/src/unix/cygwin.c index 5a887dd4c..9da20e203 100644 --- a/Utilities/cmlibuv/src/unix/cygwin.c +++ b/Utilities/cmlibuv/src/unix/cygwin.c @@ -29,7 +29,7 @@ int uv_uptime(double* uptime) { struct sysinfo info; if (sysinfo(&info) < 0) - return -errno; + return UV__ERR(errno); *uptime = info.uptime; return 0; @@ -38,7 +38,7 @@ int uv_uptime(double* uptime) { int uv_resident_set_memory(size_t* rss) { /* FIXME: read /proc/meminfo? */ *rss = 0; - return UV_ENOSYS; + return 0; } int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { diff --git a/Utilities/cmlibuv/src/unix/darwin-proctitle.c b/Utilities/cmlibuv/src/unix/darwin-proctitle.c index 114231160..e505bdd23 100644 --- a/Utilities/cmlibuv/src/unix/darwin-proctitle.c +++ b/Utilities/cmlibuv/src/unix/darwin-proctitle.c @@ -18,6 +18,9 @@ * IN THE SOFTWARE. */ +#include "uv.h" +#include "internal.h" + #include <dlfcn.h> #include <errno.h> #include <stdlib.h> @@ -30,61 +33,56 @@ # include <ApplicationServices/ApplicationServices.h> #endif +#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8) -static int uv__pthread_setname_np(const char* name) { - int (*dynamic_pthread_setname_np)(const char* name); - char namebuf[64]; /* MAXTHREADNAMESIZE */ - int err; - - /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */ - *(void **)(&dynamic_pthread_setname_np) = - dlsym(RTLD_DEFAULT, "pthread_setname_np"); - - if (dynamic_pthread_setname_np == NULL) - return -ENOSYS; - - strncpy(namebuf, name, sizeof(namebuf) - 1); - namebuf[sizeof(namebuf) - 1] = '\0'; - err = dynamic_pthread_setname_np(namebuf); - if (err) - return -err; +static int (*dynamic_pthread_setname_np)(const char* name); +#if !TARGET_OS_IPHONE +static CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, + const char*, + CFStringEncoding); +static CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef); +static void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef); +static void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef); +static CFTypeRef (*pLSGetCurrentApplicationASN)(void); +static OSStatus (*pLSSetApplicationInformationItem)(int, + CFTypeRef, + CFStringRef, + CFStringRef, + CFDictionaryRef*); +static void* application_services_handle; +static void* core_foundation_handle; +static CFBundleRef launch_services_bundle; +static CFStringRef* display_name_key; +static CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef); +static CFBundleRef (*pCFBundleGetMainBundle)(void); +static CFBundleRef hi_services_bundle; +static OSStatus (*pSetApplicationIsDaemon)(int); +static CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef); +static void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t, + void*); + + +UV_DESTRUCTOR(static void uv__set_process_title_platform_fini(void)) { + if (core_foundation_handle != NULL) { + dlclose(core_foundation_handle); + core_foundation_handle = NULL; + } - return 0; + if (application_services_handle != NULL) { + dlclose(application_services_handle); + application_services_handle = NULL; + } } +#endif /* !TARGET_OS_IPHONE */ + +void uv__set_process_title_platform_init(void) { + /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */ + *(void **)(&dynamic_pthread_setname_np) = + dlsym(RTLD_DEFAULT, "pthread_setname_np"); -int uv__set_process_title(const char* title) { -#if TARGET_OS_IPHONE - return uv__pthread_setname_np(title); -#else - CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, - const char*, - CFStringEncoding); - CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef); - void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef); - void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef); - CFTypeRef (*pLSGetCurrentApplicationASN)(void); - OSStatus (*pLSSetApplicationInformationItem)(int, - CFTypeRef, - CFStringRef, - CFStringRef, - CFDictionaryRef*); - void* application_services_handle; - void* core_foundation_handle; - CFBundleRef launch_services_bundle; - CFStringRef* display_name_key; - CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef); - CFBundleRef (*pCFBundleGetMainBundle)(void); - CFBundleRef hi_services_bundle; - OSStatus (*pSetApplicationIsDaemon)(int); - CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef); - void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t, - void*); - CFTypeRef asn; - int err; - - err = -ENOENT; +#if !TARGET_OS_IPHONE application_services_handle = dlopen("/System/Library/Frameworks/" "ApplicationServices.framework/" "Versions/A/ApplicationServices", @@ -113,8 +111,6 @@ int uv__set_process_title(const char* title) { goto out; } -#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8) - launch_services_bundle = pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices")); @@ -145,13 +141,14 @@ int uv__set_process_title(const char* title) { "CFBundleGetInfoDictionary"); *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle, "CFBundleGetMainBundle"); + if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL) goto out; /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */ hi_services_bundle = pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices")); - err = -ENOENT; + if (hi_services_bundle == NULL) goto out; @@ -165,42 +162,37 @@ int uv__set_process_title(const char* title) { pCFBundleGetFunctionPointerForName( launch_services_bundle, S("_LSSetApplicationLaunchServicesServerConnectionStatus")); + if (pSetApplicationIsDaemon == NULL || pLSApplicationCheckIn == NULL || pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) { goto out; } - if (pSetApplicationIsDaemon(1) != noErr) - goto out; - - pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL); - - /* Check into process manager?! */ - pLSApplicationCheckIn(-2, - pCFBundleGetInfoDictionary(pCFBundleGetMainBundle())); - - asn = pLSGetCurrentApplicationASN(); - - err = -EINVAL; - if (pLSSetApplicationInformationItem(-2, /* Magic value. */ - asn, - *display_name_key, - S(title), - NULL) != noErr) { - goto out; - } - - uv__pthread_setname_np(title); /* Don't care if it fails. */ - err = 0; + return; out: - if (core_foundation_handle != NULL) - dlclose(core_foundation_handle); + uv__set_process_title_platform_fini(); +#endif /* !TARGET_OS_IPHONE */ +} - if (application_services_handle != NULL) - dlclose(application_services_handle); - return err; +void uv__set_process_title(const char* title) { +#if !TARGET_OS_IPHONE + if (core_foundation_handle != NULL && pSetApplicationIsDaemon(1) != noErr) { + CFTypeRef asn; + pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL); + pLSApplicationCheckIn(/* Magic value */ -2, + pCFBundleGetInfoDictionary(pCFBundleGetMainBundle())); + asn = pLSGetCurrentApplicationASN(); + pLSSetApplicationInformationItem(/* Magic value */ -2, asn, + *display_name_key, S(title), NULL); + } #endif /* !TARGET_OS_IPHONE */ + + if (dynamic_pthread_setname_np != NULL) { + char namebuf[64]; /* MAXTHREADNAMESIZE */ + uv__strscpy(namebuf, title, sizeof(namebuf)); + dynamic_pthread_setname_np(namebuf); + } } diff --git a/Utilities/cmlibuv/src/unix/darwin.c b/Utilities/cmlibuv/src/unix/darwin.c index df6dd1c61..e4cd8ff7e 100644 --- a/Utilities/cmlibuv/src/unix/darwin.c +++ b/Utilities/cmlibuv/src/unix/darwin.c @@ -37,7 +37,7 @@ int uv__platform_loop_init(uv_loop_t* loop) { loop->cf_state = NULL; if (uv__kqueue_init(loop)) - return -errno; + return UV__ERR(errno); return 0; } @@ -68,18 +68,18 @@ int uv_exepath(char* buffer, size_t* size) { size_t abspath_size; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; exepath_size = sizeof(exepath); if (_NSGetExecutablePath(exepath, &exepath_size)) - return -EIO; + return UV_EIO; if (realpath(exepath, abspath) != abspath) - return -errno; + return UV__ERR(errno); abspath_size = strlen(abspath); if (abspath_size == 0) - return -EIO; + return UV_EIO; *size -= 1; if (*size > abspath_size) @@ -98,7 +98,7 @@ uint64_t uv_get_free_memory(void) { if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&info, &count) != KERN_SUCCESS) { - return -EINVAL; /* FIXME(bnoordhuis) Translate error. */ + return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */ } return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE); @@ -111,12 +111,17 @@ uint64_t uv_get_total_memory(void) { size_t size = sizeof(info); if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); return (uint64_t) info; } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + void uv_loadavg(double avg[3]) { struct loadavg info; size_t size = sizeof(info); @@ -158,7 +163,7 @@ int uv_uptime(double* uptime) { static int which[] = {CTL_KERN, KERN_BOOTTIME}; if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); now = time(NULL); *uptime = now - info.tv_sec; @@ -181,23 +186,23 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(model); if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) && sysctlbyname("hw.model", &model, &size, NULL, 0)) { - return -errno; + return UV__ERR(errno); } size = sizeof(cpuspeed); if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus, (processor_info_array_t*)&info, &msg_type) != KERN_SUCCESS) { - return -EINVAL; /* FIXME(bnoordhuis) Translate error. */ + return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */ } *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); if (!(*cpu_infos)) { vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type); - return -ENOMEM; + return UV_ENOMEM; } *count = numcpus; diff --git a/Utilities/cmlibuv/src/unix/freebsd.c b/Utilities/cmlibuv/src/unix/freebsd.c index e52ae99db..7de88d6a5 100644 --- a/Utilities/cmlibuv/src/unix/freebsd.c +++ b/Utilities/cmlibuv/src/unix/freebsd.c @@ -25,7 +25,6 @@ #include <string.h> #include <errno.h> -#include <kvm.h> #include <paths.h> #include <sys/user.h> #include <sys/types.h> @@ -48,8 +47,6 @@ # define CP_INTR 4 #endif -static char *process_title; - int uv__platform_loop_init(uv_loop_t* loop) { return uv__kqueue_init(loop); @@ -66,11 +63,11 @@ int uv_exepath(char* buffer, size_t* size) { ssize_t abspath_size; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath)); if (abspath_size < 0) - return -errno; + return UV__ERR(errno); assert(abspath_size > 0); *size -= 1; @@ -90,7 +87,7 @@ int uv_exepath(char* buffer, size_t* size) { size_t abspath_size; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; mib[0] = CTL_KERN; mib[1] = KERN_PROC; @@ -99,7 +96,7 @@ int uv_exepath(char* buffer, size_t* size) { abspath_size = sizeof abspath; if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0)) - return -errno; + return UV__ERR(errno); assert(abspath_size > 0); abspath_size -= 1; @@ -120,7 +117,7 @@ uint64_t uv_get_free_memory(void) { size_t size = sizeof(freecount); if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); return (uint64_t) freecount * sysconf(_SC_PAGESIZE); @@ -134,12 +131,17 @@ uint64_t uv_get_total_memory(void) { size_t size = sizeof(info); if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); return (uint64_t) info; } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + void uv_loadavg(double avg[3]) { struct loadavg info; size_t size = sizeof(info); @@ -153,85 +155,31 @@ void uv_loadavg(double avg[3]) { } -char** uv_setup_args(int argc, char** argv) { - process_title = argc ? uv__strdup(argv[0]) : NULL; - return argv; -} - - -int uv_set_process_title(const char* title) { - int oid[4]; - - uv__free(process_title); - process_title = uv__strdup(title); - - oid[0] = CTL_KERN; - oid[1] = KERN_PROC; - oid[2] = KERN_PROC_ARGS; - oid[3] = getpid(); - - sysctl(oid, - ARRAY_SIZE(oid), - NULL, - NULL, - process_title, - strlen(process_title) + 1); - - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - size_t len; - - if (buffer == NULL || size == 0) - return -EINVAL; - - if (process_title) { - len = strlen(process_title) + 1; - - if (size < len) - return -ENOBUFS; - - memcpy(buffer, process_title, len); - } else { - len = 0; - } - - buffer[len] = '\0'; - - return 0; -} - - int uv_resident_set_memory(size_t* rss) { - kvm_t *kd = NULL; - struct kinfo_proc *kinfo = NULL; - pid_t pid; - int nprocs; - size_t page_size = getpagesize(); + struct kinfo_proc kinfo; + size_t page_size; + size_t kinfo_size; + int mib[4]; - pid = getpid(); + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); - kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); - if (kd == NULL) goto error; + kinfo_size = sizeof(kinfo); - kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs); - if (kinfo == NULL) goto error; + if (sysctl(mib, 4, &kinfo, &kinfo_size, NULL, 0)) + return UV__ERR(errno); + + page_size = getpagesize(); #ifdef __DragonFly__ - *rss = kinfo->kp_vm_rssize * page_size; + *rss = kinfo.kp_vm_rssize * page_size; #else - *rss = kinfo->ki_rssize * page_size; + *rss = kinfo.ki_rssize * page_size; #endif - kvm_close(kd); - return 0; - -error: - if (kd) kvm_close(kd); - return -EPERM; } @@ -240,7 +188,7 @@ int uv_uptime(double* uptime) { struct timespec sp; r = clock_gettime(CLOCK_MONOTONIC, &sp); if (r) - return -errno; + return UV__ERR(errno); *uptime = sp.tv_sec; return 0; @@ -254,6 +202,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { uv_cpu_info_t* cpu_info; const char* maxcpus_key; const char* cptimes_key; + const char* model_key; char model[512]; long* cp_times; int numcpus; @@ -272,33 +221,39 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { cptimes_key = "kern.cp_times"; #endif - size = sizeof(model); - if (sysctlbyname("hw.model", &model, &size, NULL, 0)) +#if defined(__arm__) || defined(__aarch64__) + /* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */ + model_key = "hw.machine"; + cpuspeed = 0; +#else + model_key = "hw.model"; + + size = sizeof(cpuspeed); + if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) return -errno; +#endif + + size = sizeof(model); + if (sysctlbyname(model_key, &model, &size, NULL, 0)) + return UV__ERR(errno); size = sizeof(numcpus); if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); if (!(*cpu_infos)) - return -ENOMEM; + return UV_ENOMEM; *count = numcpus; - size = sizeof(cpuspeed); - if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) { - uv__free(*cpu_infos); - return -errno; - } - /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of * ncpu. */ size = sizeof(maxcpus); if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) { uv__free(*cpu_infos); - return -errno; + return UV__ERR(errno); } size = maxcpus * CPUSTATES * sizeof(long); @@ -306,13 +261,13 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { cp_times = uv__malloc(size); if (cp_times == NULL) { uv__free(*cpu_infos); - return -ENOMEM; + return UV_ENOMEM; } if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { uv__free(cp_times); uv__free(*cpu_infos); - return -errno; + return UV__ERR(errno); } for (i = 0; i < numcpus; i++) { diff --git a/Utilities/cmlibuv/src/unix/fs.c b/Utilities/cmlibuv/src/unix/fs.c index 8a4ba7a2f..5fb34f1be 100644 --- a/Utilities/cmlibuv/src/unix/fs.c +++ b/Utilities/cmlibuv/src/unix/fs.c @@ -43,12 +43,11 @@ #include <pthread.h> #include <unistd.h> #include <fcntl.h> -#include <utime.h> #include <poll.h> #if defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel_) || \ + defined(__FreeBSD_kernel__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) # define HAVE_PREADV 1 @@ -60,17 +59,33 @@ # include <sys/sendfile.h> #endif +#if defined(__APPLE__) +# include <sys/sysctl.h> +#elif defined(__linux__) && !defined(FICLONE) +# include <sys/ioctl.h> +# define FICLONE _IOW(0x94, 9, int) +#endif + +#if defined(_AIX) && !defined(_AIX71) +# include <utime.h> +#endif + +#if defined(_AIX) && _XOPEN_SOURCE <= 600 +extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */ +#endif + #define INIT(subtype) \ do { \ - req->type = UV_FS; \ - if (cb != NULL) \ - uv__req_init(loop, req, UV_FS); \ + if (req == NULL) \ + return UV_EINVAL; \ + UV_REQ_INIT(req, UV_FS); \ req->fs_type = UV_FS_ ## subtype; \ req->result = 0; \ req->ptr = NULL; \ req->loop = loop; \ req->path = NULL; \ req->new_path = NULL; \ + req->bufs = NULL; \ req->cb = cb; \ } \ while (0) @@ -82,10 +97,8 @@ req->path = path; \ } else { \ req->path = uv__strdup(path); \ - if (req->path == NULL) { \ - uv__req_unregister(loop, req); \ - return -ENOMEM; \ - } \ + if (req->path == NULL) \ + return UV_ENOMEM; \ } \ } \ while (0) @@ -101,10 +114,8 @@ path_len = strlen(path) + 1; \ new_path_len = strlen(new_path) + 1; \ req->path = uv__malloc(path_len + new_path_len); \ - if (req->path == NULL) { \ - uv__req_unregister(loop, req); \ - return -ENOMEM; \ - } \ + if (req->path == NULL) \ + return UV_ENOMEM; \ req->new_path = req->path + path_len; \ memcpy((void*) req->path, path, path_len); \ memcpy((void*) req->new_path, new_path, new_path_len); \ @@ -115,7 +126,12 @@ #define POST \ do { \ if (cb != NULL) { \ - uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \ + uv__req_register(loop, req); \ + uv__work_submit(loop, \ + &req->work_req, \ + UV__WORK_FAST_IO, \ + uv__fs_work, \ + uv__fs_done); \ return 0; \ } \ else { \ @@ -126,26 +142,48 @@ while (0) -static ssize_t uv__fs_fdatasync(uv_fs_t* req) { -#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) - return fdatasync(req->file); -#elif defined(__APPLE__) +static int uv__fs_close(int fd) { + int rc; + + rc = uv__close_nocancel(fd); + if (rc == -1) + if (errno == EINTR || errno == EINPROGRESS) + rc = 0; /* The close is in progress, not an error. */ + + return rc; +} + + +static ssize_t uv__fs_fsync(uv_fs_t* req) { +#if defined(__APPLE__) /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache * to the drive platters. This is in contrast to Linux's fdatasync and fsync * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent - * for flushing buffered data to permanent storage. + * for flushing buffered data to permanent storage. If F_FULLFSYNC is not + * supported by the file system we fall back to F_BARRIERFSYNC or fsync(). + * This is the same approach taken by sqlite, except sqlite does not issue + * an F_BARRIERFSYNC call. */ - return fcntl(req->file, F_FULLFSYNC); + int r; + + r = fcntl(req->file, F_FULLFSYNC); + if (r != 0) + r = fcntl(req->file, 85 /* F_BARRIERFSYNC */); /* fsync + barrier */ + if (r != 0) + r = fsync(req->file); + return r; #else return fsync(req->file); #endif } -static ssize_t uv__fs_fsync(uv_fs_t* req) { -#if defined(__APPLE__) - /* See the comment in uv__fs_fdatasync. */ - return fcntl(req->file, F_FULLFSYNC); +static ssize_t uv__fs_fdatasync(uv_fs_t* req) { +#if defined(__linux__) || defined(__sun) || defined(__NetBSD__) + return fdatasync(req->file); +#elif defined(__APPLE__) + /* See the comment in uv__fs_fsync. */ + return uv__fs_fsync(req); #else return fsync(req->file); #endif @@ -153,59 +191,18 @@ static ssize_t uv__fs_fsync(uv_fs_t* req) { static ssize_t uv__fs_futime(uv_fs_t* req) { -#if defined(__linux__) +#if defined(__linux__) \ + || defined(_AIX71) \ + || defined(__HAIKU__) /* utimesat() has nanosecond resolution but we stick to microseconds * for the sake of consistency with other platforms. */ - static int no_utimesat; struct timespec ts[2]; - struct timeval tv[2]; - char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)]; - int r; - - if (no_utimesat) - goto skip; - ts[0].tv_sec = req->atime; ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; ts[1].tv_sec = req->mtime; ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; - - r = uv__utimesat(req->file, NULL, ts, 0); - if (r == 0) - return r; - - if (errno != ENOSYS) - return r; - - no_utimesat = 1; - -skip: - - tv[0].tv_sec = req->atime; - tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; - tv[1].tv_sec = req->mtime; - tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; - snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file); - - r = utimes(path, tv); - if (r == 0) - return r; - - switch (errno) { - case ENOENT: - if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF) - break; - /* Fall through. */ - - case EACCES: - case ENOTDIR: - errno = ENOSYS; - break; - } - - return r; - + return futimens(req->file, ts); #elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ @@ -223,13 +220,6 @@ skip: # else return futimes(req->file, tv); # endif -#elif defined(_AIX71) - struct timespec ts[2]; - ts[0].tv_sec = req->atime; - ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; - ts[1].tv_sec = req->mtime; - ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; - return futimens(req->file, ts); #elif defined(__MVS__) attrib_t atr; memset(&atr, 0, sizeof(atr)); @@ -244,7 +234,7 @@ skip: #endif } -#if defined(__sun) && _XOPEN_SOURCE < 600 +#if (defined(__sun) || defined(__hpux)) && (_XOPEN_SOURCE < 600 || defined(CMAKE_BOOTSTRAP)) static char* uv__mkdtemp(char *template) { if (!mktemp(template) || mkdir(template, 0700)) @@ -302,17 +292,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) { #if defined(__linux__) static int no_preadv; #endif + unsigned int iovmax; ssize_t result; -#if defined(_AIX) - struct stat buf; - if(fstat(req->file, &buf)) - return -1; - if(S_ISDIR(buf.st_mode)) { - errno = EISDIR; - return -1; - } -#endif /* defined(_AIX) */ + iovmax = uv__getiovmax(); + if (req->nbufs > iovmax) + req->nbufs = iovmax; + if (req->off < 0) { if (req->nbufs == 1) result = read(req->file, req->bufs[0].base, req->bufs[0].len); @@ -331,25 +317,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) { if (no_preadv) retry: # endif { - off_t nread; - size_t index; - - nread = 0; - index = 0; - result = 1; - do { - if (req->bufs[index].len > 0) { - result = pread(req->file, - req->bufs[index].base, - req->bufs[index].len, - req->off + nread); - if (result > 0) - nread += result; - } - index++; - } while (index < req->nbufs && result > 0); - if (nread > 0) - result = nread; + result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off); } # if defined(__linux__) else { @@ -367,6 +335,25 @@ static ssize_t uv__fs_read(uv_fs_t* req) { } done: + /* Early cleanup of bufs allocation, since we're done with it. */ + if (req->bufs != req->bufsml) + uv__free(req->bufs); + + req->bufs = NULL; + req->nbufs = 0; + +#ifdef __PASE__ + /* PASE returns EOPNOTSUPP when reading a directory, convert to EISDIR */ + if (result == -1 && errno == EOPNOTSUPP) { + struct stat buf; + ssize_t rc; + rc = fstat(req->file, &buf); + if (rc == 0 && S_ISDIR(buf.st_mode)) { + errno = EISDIR; + } + } +#endif + return result; } @@ -389,7 +376,7 @@ static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) { static ssize_t uv__fs_scandir(uv_fs_t* req) { - uv__dirent_t **dents; + uv__dirent_t** dents; int n; dents = NULL; @@ -413,42 +400,165 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) { return n; } +static int uv__fs_opendir(uv_fs_t* req) { + uv_dir_t* dir; + + dir = uv__malloc(sizeof(*dir)); + if (dir == NULL) + goto error; + + dir->dir = opendir(req->path); + if (dir->dir == NULL) + goto error; + + req->ptr = dir; + return 0; + +error: + uv__free(dir); + req->ptr = NULL; + return -1; +} + +static int uv__fs_readdir(uv_fs_t* req) { + uv_dir_t* dir; + uv_dirent_t* dirent; + struct dirent* res; + unsigned int dirent_idx; + unsigned int i; + + dir = req->ptr; + dirent_idx = 0; + + while (dirent_idx < dir->nentries) { + /* readdir() returns NULL on end of directory, as well as on error. errno + is used to differentiate between the two conditions. */ + errno = 0; + res = readdir(dir->dir); + + if (res == NULL) { + if (errno != 0) + goto error; + break; + } + + if (strcmp(res->d_name, ".") == 0 || strcmp(res->d_name, "..") == 0) + continue; + + dirent = &dir->dirents[dirent_idx]; + dirent->name = uv__strdup(res->d_name); + + if (dirent->name == NULL) + goto error; + + dirent->type = uv__fs_get_dirent_type(res); + ++dirent_idx; + } + + return dirent_idx; + +error: + for (i = 0; i < dirent_idx; ++i) { + uv__free((char*) dir->dirents[i].name); + dir->dirents[i].name = NULL; + } + + return -1; +} + +static int uv__fs_closedir(uv_fs_t* req) { + uv_dir_t* dir; + + dir = req->ptr; + + if (dir->dir != NULL) { + closedir(dir->dir); + dir->dir = NULL; + } + + uv__free(req->ptr); + req->ptr = NULL; + return 0; +} + +#if defined(_POSIX_PATH_MAX) +# define UV__FS_PATH_MAX _POSIX_PATH_MAX +#elif defined(PATH_MAX) +# define UV__FS_PATH_MAX PATH_MAX +#else +# define UV__FS_PATH_MAX_FALLBACK 8192 +# define UV__FS_PATH_MAX UV__FS_PATH_MAX_FALLBACK +#endif static ssize_t uv__fs_pathmax_size(const char* path) { ssize_t pathmax; pathmax = pathconf(path, _PC_PATH_MAX); - if (pathmax == -1) { -#if defined(PATH_MAX) - return PATH_MAX; -#else -#error "PATH_MAX undefined in the current platform" -#endif - } + if (pathmax == -1) + pathmax = UV__FS_PATH_MAX; return pathmax; } static ssize_t uv__fs_readlink(uv_fs_t* req) { + ssize_t maxlen; ssize_t len; char* buf; + char* newbuf; - len = uv__fs_pathmax_size(req->path); - buf = uv__malloc(len + 1); +#if defined(UV__FS_PATH_MAX_FALLBACK) + /* We may not have a real PATH_MAX. Read size of link. */ + struct stat st; + int ret; + ret = lstat(req->path, &st); + if (ret != 0) + return -1; + if (!S_ISLNK(st.st_mode)) { + errno = EINVAL; + return -1; + } + + maxlen = st.st_size; + + /* According to readlink(2) lstat can report st_size == 0 + for some symlinks, such as those in /proc or /sys. */ + if (maxlen == 0) + maxlen = uv__fs_pathmax_size(req->path); +#else + maxlen = uv__fs_pathmax_size(req->path); +#endif + + buf = uv__malloc(maxlen); if (buf == NULL) { errno = ENOMEM; return -1; } - len = readlink(req->path, buf, len); +#if defined(__MVS__) + len = os390_readlink(req->path, buf, maxlen); +#else + len = readlink(req->path, buf, maxlen); +#endif if (len == -1) { uv__free(buf); return -1; } + /* Uncommon case: resize to make room for the trailing nul byte. */ + if (len == maxlen) { + newbuf = uv__realloc(buf, len + 1); + + if (newbuf == NULL) { + uv__free(buf); + return -1; + } + + buf = newbuf; + } + buf[len] = '\0'; req->ptr = buf; @@ -456,9 +566,15 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) { } static ssize_t uv__fs_realpath(uv_fs_t* req) { - ssize_t len; char* buf; +#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L + buf = realpath(req->path, NULL); + if (buf == NULL) + return -1; +#else + ssize_t len; + len = uv__fs_pathmax_size(req->path); buf = uv__malloc(len + 1); @@ -471,6 +587,7 @@ static ssize_t uv__fs_realpath(uv_fs_t* req) { uv__free(buf); return -1; } +#endif req->ptr = buf; @@ -691,10 +808,49 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { static ssize_t uv__fs_utime(uv_fs_t* req) { +#if defined(__linux__) \ + || defined(_AIX71) \ + || defined(__sun) \ + || defined(__HAIKU__) + /* utimesat() has nanosecond resolution but we stick to microseconds + * for the sake of consistency with other platforms. + */ + struct timespec ts[2]; + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; + return utimensat(AT_FDCWD, req->path, ts, 0); +#elif defined(__APPLE__) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__FreeBSD_kernel__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) + struct timeval tv[2]; + tv[0].tv_sec = req->atime; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; + return utimes(req->path, tv); +#elif defined(_AIX) \ + && !defined(_AIX71) struct utimbuf buf; buf.actime = req->atime; buf.modtime = req->mtime; - return utime(req->path, &buf); /* TODO use utimes() where available */ + return utime(req->path, &buf); +#elif defined(__MVS__) + attrib_t atr; + memset(&atr, 0, sizeof(atr)); + atr.att_mtimechg = 1; + atr.att_atimechg = 1; + atr.att_mtime = req->mtime; + atr.att_atime = req->atime; + return __lchattr((char*) req->path, &atr, sizeof(atr)); +#else + errno = ENOSYS; + return -1; +#endif } @@ -732,25 +888,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) { if (no_pwritev) retry: # endif { - off_t written; - size_t index; - - written = 0; - index = 0; - r = 0; - do { - if (req->bufs[index].len > 0) { - r = pwrite(req->file, - req->bufs[index].base, - req->bufs[index].len, - req->off + written); - if (r > 0) - written += r; - } - index++; - } while (index < req->nbufs && r >= 0); - if (written > 0) - r = written; + r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off); } # if defined(__linux__) else { @@ -776,6 +914,135 @@ done: return r; } +static ssize_t uv__fs_copyfile(uv_fs_t* req) { + uv_fs_t fs_req; + uv_file srcfd; + uv_file dstfd; + struct stat statsbuf; + int dst_flags; + int result; + int err; + size_t bytes_to_send; + int64_t in_offset; + + dstfd = -1; + err = 0; + + /* Open the source file. */ + srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL); + uv_fs_req_cleanup(&fs_req); + + if (srcfd < 0) + return srcfd; + + /* Get the source file's mode. */ + if (fstat(srcfd, &statsbuf)) { + err = UV__ERR(errno); + goto out; + } + + dst_flags = O_WRONLY | O_CREAT | O_TRUNC; + + if (req->flags & UV_FS_COPYFILE_EXCL) + dst_flags |= O_EXCL; + + /* Open the destination file. */ + dstfd = uv_fs_open(NULL, + &fs_req, + req->new_path, + dst_flags, + statsbuf.st_mode, + NULL); + uv_fs_req_cleanup(&fs_req); + + if (dstfd < 0) { + err = dstfd; + goto out; + } + + if (fchmod(dstfd, statsbuf.st_mode) == -1) { + err = UV__ERR(errno); + goto out; + } + +#ifdef FICLONE + if (req->flags & UV_FS_COPYFILE_FICLONE || + req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { + if (ioctl(dstfd, FICLONE, srcfd) == -1) { + /* If an error occurred that the sendfile fallback also won't handle, or + this is a force clone then exit. Otherwise, fall through to try using + sendfile(). */ + if (errno != ENOTTY && errno != EOPNOTSUPP && errno != EXDEV) { + err = UV__ERR(errno); + goto out; + } else if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { + err = UV_ENOTSUP; + goto out; + } + } else { + goto out; + } + } +#else + if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { + err = UV_ENOSYS; + goto out; + } +#endif + + bytes_to_send = statsbuf.st_size; + in_offset = 0; + while (bytes_to_send != 0) { + err = uv_fs_sendfile(NULL, + &fs_req, + dstfd, + srcfd, + in_offset, + bytes_to_send, + NULL); + uv_fs_req_cleanup(&fs_req); + if (err < 0) + break; + bytes_to_send -= fs_req.result; + in_offset += fs_req.result; + } + +out: + if (err < 0) + result = err; + else + result = 0; + + /* Close the source file. */ + err = uv__close_nocheckstdio(srcfd); + + /* Don't overwrite any existing errors. */ + if (err != 0 && result == 0) + result = err; + + /* Close the destination file if it is open. */ + if (dstfd >= 0) { + err = uv__close_nocheckstdio(dstfd); + + /* Don't overwrite any existing errors. */ + if (err != 0 && result == 0) + result = err; + + /* Remove the destination file if something went wrong. */ + if (result != 0) { + uv_fs_unlink(NULL, &fs_req, req->new_path, NULL); + /* Ignore the unlink return value, as an error already happened. */ + uv_fs_req_cleanup(&fs_req); + } + } + + if (result == 0) + return 0; + + errno = UV__ERR(result); + return -1; +} + static void uv__to_stat(struct stat* src, uv_stat_t* dst) { dst->st_dev = src->st_dev; dst->st_mode = src->st_mode; @@ -853,10 +1120,84 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { } +static int uv__fs_statx(int fd, + const char* path, + int is_fstat, + int is_lstat, + uv_stat_t* buf) { + STATIC_ASSERT(UV_ENOSYS != -1); +#ifdef __linux__ + static int no_statx; + struct uv__statx statxbuf; + int dirfd; + int flags; + int mode; + int rc; + + if (no_statx) + return UV_ENOSYS; + + dirfd = AT_FDCWD; + flags = 0; /* AT_STATX_SYNC_AS_STAT */ + mode = 0xFFF; /* STATX_BASIC_STATS + STATX_BTIME */ + + if (is_fstat) { + dirfd = fd; + flags |= 0x1000; /* AT_EMPTY_PATH */ + } + + if (is_lstat) + flags |= AT_SYMLINK_NOFOLLOW; + + rc = uv__statx(dirfd, path, flags, mode, &statxbuf); + + if (rc == -1) { + /* EPERM happens when a seccomp filter rejects the system call. + * Has been observed with libseccomp < 2.3.3 and docker < 18.04. + */ + if (errno != EINVAL && errno != EPERM && errno != ENOSYS) + return -1; + + no_statx = 1; + return UV_ENOSYS; + } + + buf->st_dev = 256 * statxbuf.stx_dev_major + statxbuf.stx_dev_minor; + buf->st_mode = statxbuf.stx_mode; + buf->st_nlink = statxbuf.stx_nlink; + buf->st_uid = statxbuf.stx_uid; + buf->st_gid = statxbuf.stx_gid; + buf->st_rdev = statxbuf.stx_rdev_major; + buf->st_ino = statxbuf.stx_ino; + buf->st_size = statxbuf.stx_size; + buf->st_blksize = statxbuf.stx_blksize; + buf->st_blocks = statxbuf.stx_blocks; + buf->st_atim.tv_sec = statxbuf.stx_atime.tv_sec; + buf->st_atim.tv_nsec = statxbuf.stx_atime.tv_nsec; + buf->st_mtim.tv_sec = statxbuf.stx_mtime.tv_sec; + buf->st_mtim.tv_nsec = statxbuf.stx_mtime.tv_nsec; + buf->st_ctim.tv_sec = statxbuf.stx_ctime.tv_sec; + buf->st_ctim.tv_nsec = statxbuf.stx_ctime.tv_nsec; + buf->st_birthtim.tv_sec = statxbuf.stx_btime.tv_sec; + buf->st_birthtim.tv_nsec = statxbuf.stx_btime.tv_nsec; + buf->st_flags = 0; + buf->st_gen = 0; + + return 0; +#else + return UV_ENOSYS; +#endif /* __linux__ */ +} + + static int uv__fs_stat(const char *path, uv_stat_t *buf) { struct stat pbuf; int ret; + ret = uv__fs_statx(-1, path, /* is_fstat */ 0, /* is_lstat */ 0, buf); + if (ret != UV_ENOSYS) + return ret; + ret = stat(path, &pbuf); if (ret == 0) uv__to_stat(&pbuf, buf); @@ -869,6 +1210,10 @@ static int uv__fs_lstat(const char *path, uv_stat_t *buf) { struct stat pbuf; int ret; + ret = uv__fs_statx(-1, path, /* is_fstat */ 0, /* is_lstat */ 1, buf); + if (ret != UV_ENOSYS) + return ret; + ret = lstat(path, &pbuf); if (ret == 0) uv__to_stat(&pbuf, buf); @@ -881,6 +1226,10 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) { struct stat pbuf; int ret; + ret = uv__fs_statx(fd, "", /* is_fstat */ 1, /* is_lstat */ 0, buf); + if (ret != UV_ENOSYS) + return ret; + ret = fstat(fd, &pbuf); if (ret == 0) uv__to_stat(&pbuf, buf); @@ -888,9 +1237,21 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) { return ret; } +static size_t uv__fs_buf_offset(uv_buf_t* bufs, size_t size) { + size_t offset; + /* Figure out which bufs are done */ + for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset) + size -= bufs[offset].len; + + /* Fix a partial read/write */ + if (size > 0) { + bufs[offset].base += size; + bufs[offset].len -= size; + } + return offset; +} -typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req); -static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) { +static ssize_t uv__fs_write_all(uv_fs_t* req) { unsigned int iovmax; unsigned int nbufs; uv_buf_t* bufs; @@ -907,7 +1268,10 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) if (req->nbufs > iovmax) req->nbufs = iovmax; - result = process(req); + do + result = uv__fs_write(req); + while (result < 0 && errno == EINTR); + if (result <= 0) { if (total == 0) total = result; @@ -917,14 +1281,12 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) if (req->off >= 0) req->off += result; + req->nbufs = uv__fs_buf_offset(req->bufs, result); req->bufs += req->nbufs; nbufs -= req->nbufs; total += result; } - if (errno == EINTR && total == -1) - return total; - if (bufs != req->bufsml) uv__free(bufs); @@ -941,7 +1303,8 @@ static void uv__fs_work(struct uv__work* w) { ssize_t r; req = container_of(w, uv_fs_t, work_req); - retry_on_eintr = !(req->fs_type == UV_FS_CLOSE); + retry_on_eintr = !(req->fs_type == UV_FS_CLOSE || + req->fs_type == UV_FS_READ); do { errno = 0; @@ -955,9 +1318,11 @@ static void uv__fs_work(struct uv__work* w) { X(ACCESS, access(req->path, req->flags)); X(CHMOD, chmod(req->path, req->mode)); X(CHOWN, chown(req->path, req->uid, req->gid)); - X(CLOSE, close(req->file)); + X(CLOSE, uv__fs_close(req->file)); + X(COPYFILE, uv__fs_copyfile(req)); X(FCHMOD, fchmod(req->file, req->mode)); X(FCHOWN, fchown(req->file, req->uid, req->gid)); + X(LCHOWN, lchown(req->path, req->uid, req->gid)); X(FDATASYNC, uv__fs_fdatasync(req)); X(FSTAT, uv__fs_fstat(req->file, &req->statbuf)); X(FSYNC, uv__fs_fsync(req)); @@ -968,8 +1333,11 @@ static void uv__fs_work(struct uv__work* w) { X(MKDIR, mkdir(req->path, req->mode)); X(MKDTEMP, uv__fs_mkdtemp(req)); X(OPEN, uv__fs_open(req)); - X(READ, uv__fs_buf_iter(req, uv__fs_read)); + X(READ, uv__fs_read(req)); X(SCANDIR, uv__fs_scandir(req)); + X(OPENDIR, uv__fs_opendir(req)); + X(READDIR, uv__fs_readdir(req)); + X(CLOSEDIR, uv__fs_closedir(req)); X(READLINK, uv__fs_readlink(req)); X(REALPATH, uv__fs_realpath(req)); X(RENAME, rename(req->path, req->new_path)); @@ -979,14 +1347,14 @@ static void uv__fs_work(struct uv__work* w) { X(SYMLINK, symlink(req->path, req->new_path)); X(UNLINK, unlink(req->path)); X(UTIME, uv__fs_utime(req)); - X(WRITE, uv__fs_buf_iter(req, uv__fs_write)); + X(WRITE, uv__fs_write_all(req)); default: abort(); } #undef X } while (r == -1 && errno == EINTR && retry_on_eintr); if (r == -1) - req->result = -errno; + req->result = UV__ERR(errno); else req->result = r; @@ -1004,9 +1372,9 @@ static void uv__fs_done(struct uv__work* w, int status) { req = container_of(w, uv_fs_t, work_req); uv__req_unregister(req->loop, req); - if (status == -ECANCELED) { + if (status == UV_ECANCELED) { assert(req->result == 0); - req->result = -ECANCELED; + req->result = UV_ECANCELED; } req->cb(req); @@ -1084,6 +1452,20 @@ int uv_fs_fchown(uv_loop_t* loop, } +int uv_fs_lchown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb) { + INIT(LCHOWN); + PATH; + req->uid = uid; + req->gid = gid; + POST; +} + + int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { INIT(FDATASYNC); req->file = file; @@ -1167,11 +1549,8 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_cb cb) { INIT(MKDTEMP); req->path = uv__strdup(tpl); - if (req->path == NULL) { - if (cb != NULL) - uv__req_unregister(loop, req); - return -ENOMEM; - } + if (req->path == NULL) + return UV_ENOMEM; POST; } @@ -1196,10 +1575,11 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, unsigned int nbufs, int64_t off, uv_fs_cb cb) { + INIT(READ); + if (bufs == NULL || nbufs == 0) - return -EINVAL; + return UV_EINVAL; - INIT(READ); req->file = file; req->nbufs = nbufs; @@ -1207,11 +1587,8 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, if (nbufs > ARRAY_SIZE(req->bufsml)) req->bufs = uv__malloc(nbufs * sizeof(*bufs)); - if (req->bufs == NULL) { - if (cb != NULL) - uv__req_unregister(loop, req); - return -ENOMEM; - } + if (req->bufs == NULL) + return UV_ENOMEM; memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); @@ -1231,6 +1608,40 @@ int uv_fs_scandir(uv_loop_t* loop, POST; } +int uv_fs_opendir(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb) { + INIT(OPENDIR); + PATH; + POST; +} + +int uv_fs_readdir(uv_loop_t* loop, + uv_fs_t* req, + uv_dir_t* dir, + uv_fs_cb cb) { + INIT(READDIR); + + if (dir == NULL || dir->dir == NULL || dir->dirents == NULL) + return UV_EINVAL; + + req->ptr = dir; + POST; +} + +int uv_fs_closedir(uv_loop_t* loop, + uv_fs_t* req, + uv_dir_t* dir, + uv_fs_cb cb) { + INIT(CLOSEDIR); + + if (dir == NULL) + return UV_EINVAL; + + req->ptr = dir; + POST; +} int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, @@ -1334,10 +1745,11 @@ int uv_fs_write(uv_loop_t* loop, unsigned int nbufs, int64_t off, uv_fs_cb cb) { + INIT(WRITE); + if (bufs == NULL || nbufs == 0) - return -EINVAL; + return UV_EINVAL; - INIT(WRITE); req->file = file; req->nbufs = nbufs; @@ -1345,11 +1757,8 @@ int uv_fs_write(uv_loop_t* loop, if (nbufs > ARRAY_SIZE(req->bufsml)) req->bufs = uv__malloc(nbufs * sizeof(*bufs)); - if (req->bufs == NULL) { - if (cb != NULL) - uv__req_unregister(loop, req); - return -ENOMEM; - } + if (req->bufs == NULL) + return UV_ENOMEM; memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); @@ -1359,6 +1768,9 @@ int uv_fs_write(uv_loop_t* loop, void uv_fs_req_cleanup(uv_fs_t* req) { + if (req == NULL) + return; + /* Only necessary for asychronous requests, i.e., requests with a callback. * Synchronous ones don't copy their arguments and have req->path and * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the @@ -1370,10 +1782,37 @@ void uv_fs_req_cleanup(uv_fs_t* req) { req->path = NULL; req->new_path = NULL; + if (req->fs_type == UV_FS_READDIR && req->ptr != NULL) + uv__fs_readdir_cleanup(req); + if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) uv__fs_scandir_cleanup(req); - if (req->ptr != &req->statbuf) + if (req->bufs != req->bufsml) + uv__free(req->bufs); + req->bufs = NULL; + + if (req->fs_type != UV_FS_OPENDIR && req->ptr != &req->statbuf) uv__free(req->ptr); req->ptr = NULL; } + + +int uv_fs_copyfile(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + const char* new_path, + int flags, + uv_fs_cb cb) { + INIT(COPYFILE); + + if (flags & ~(UV_FS_COPYFILE_EXCL | + UV_FS_COPYFILE_FICLONE | + UV_FS_COPYFILE_FICLONE_FORCE)) { + return UV_EINVAL; + } + + PATH2; + req->flags = flags; + POST; +} diff --git a/Utilities/cmlibuv/src/unix/fsevents.c b/Utilities/cmlibuv/src/unix/fsevents.c index 643e233cf..ddacda31f 100644 --- a/Utilities/cmlibuv/src/unix/fsevents.c +++ b/Utilities/cmlibuv/src/unix/fsevents.c @@ -21,9 +21,10 @@ #include "uv.h" #include "internal.h" -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MAX_ALLOWED < 1070 /* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */ +/* macOS prior to 10.7 doesn't provide the full FSEvents API so use kqueue */ int uv__fsevents_init(uv_fs_event_t* handle) { return 0; @@ -230,6 +231,7 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, uv_loop_t* loop; uv__cf_loop_state_t* state; uv__fsevents_event_t* event; + FSEventStreamEventFlags flags; QUEUE head; loop = info; @@ -245,58 +247,77 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, /* Process and filter out events */ for (i = 0; i < numEvents; i++) { + flags = eventFlags[i]; + /* Ignore system events */ - if (eventFlags[i] & kFSEventsSystem) + if (flags & kFSEventsSystem) continue; path = paths[i]; len = strlen(path); + if (handle->realpath_len == 0) + continue; /* This should be unreachable */ + /* Filter out paths that are outside handle's request */ - if (strncmp(path, handle->realpath, handle->realpath_len) != 0) + if (len < handle->realpath_len) + continue; + + if (handle->realpath_len != len && + path[handle->realpath_len] != '/') + /* Make sure that realpath actually named a directory, + * or that we matched the whole string */ + continue; + + if (memcmp(path, handle->realpath, handle->realpath_len) != 0) continue; - if (handle->realpath_len > 1 || *handle->realpath != '/') { + if (!(handle->realpath_len == 1 && handle->realpath[0] == '/')) { + /* Remove common prefix, unless the watched folder is "/" */ path += handle->realpath_len; len -= handle->realpath_len; - /* Skip forward slash */ - if (*path != '\0') { + /* Ignore events with path equal to directory itself */ + if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir)) + continue; + + if (len == 0) { + /* Since we're using fsevents to watch the file itself, + * realpath == path, and we now need to get the basename of the file back + * (for commonality with other codepaths and platforms). */ + while (len < handle->realpath_len && path[-1] != '/') { + path--; + len++; + } + /* Created and Removed seem to be always set, but don't make sense */ + flags &= ~kFSEventsRenamed; + } else { + /* Skip forward slash */ path++; len--; } } -#ifdef MAC_OS_X_VERSION_10_7 - /* Ignore events with path equal to directory itself */ - if (len == 0) - continue; -#endif /* MAC_OS_X_VERSION_10_7 */ - /* Do not emit events from subdirectories (without option set) */ - if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) { + if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != '\0') { pos = strchr(path + 1, '/'); if (pos != NULL) continue; } -#ifndef MAC_OS_X_VERSION_10_7 - path = ""; - len = 0; -#endif /* MAC_OS_X_VERSION_10_7 */ - event = uv__malloc(sizeof(*event) + len); if (event == NULL) break; memset(event, 0, sizeof(*event)); memcpy(event->path, path, len + 1); + event->events = UV_RENAME; - if ((eventFlags[i] & kFSEventsModified) != 0 && - (eventFlags[i] & kFSEventsRenamed) == 0) - event->events = UV_CHANGE; - else - event->events = UV_RENAME; + if (0 == (flags & kFSEventsRenamed)) { + if (0 != (flags & kFSEventsModified) || + 0 == (flags & kFSEventStreamEventFlagItemIsDir)) + event->events = UV_CHANGE; + } QUEUE_INSERT_TAIL(&head, &event->member); } @@ -361,7 +382,7 @@ static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { if (!pFSEventStreamStart(ref)) { pFSEventStreamInvalidate(ref); pFSEventStreamRelease(ref); - return -EMFILE; + return UV_EMFILE; } state->fsevent_stream = ref; @@ -422,7 +443,7 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle, uv__fsevents_destroy_stream(handle->loop); /* Any failure below will be a memory failure */ - err = -ENOMEM; + err = UV_ENOMEM; /* Create list of all watched paths */ uv_mutex_lock(&state->fsevent_mutex); @@ -456,7 +477,7 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle, /* Create new FSEventStream */ cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL); if (cf_paths == NULL) { - err = -ENOMEM; + err = UV_ENOMEM; goto final; } err = uv__fsevents_create_stream(handle->loop, cf_paths); @@ -510,7 +531,7 @@ static int uv__fsevents_global_init(void) { * but if it ever becomes one, we can turn the dynamic library handles into * per-event loop properties and have the dynamic linker keep track for us. */ - err = -ENOSYS; + err = UV_ENOSYS; core_foundation_handle = dlopen("/System/Library/Frameworks/" "CoreFoundation.framework/" "Versions/A/CoreFoundation", @@ -525,7 +546,7 @@ static int uv__fsevents_global_init(void) { if (core_services_handle == NULL) goto out; - err = -ENOENT; + err = UV_ENOENT; #define V(handle, symbol) \ do { \ *(void **)(&p ## symbol) = dlsym((handle), #symbol); \ @@ -589,7 +610,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) { state = uv__calloc(1, sizeof(*state)); if (state == NULL) - return -ENOMEM; + return UV_ENOMEM; err = uv_mutex_init(&loop->cf_mutex); if (err) @@ -618,7 +639,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) { ctx.perform = uv__cf_loop_cb; state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx); if (state->signal_source == NULL) { - err = -ENOMEM; + err = UV_ENOMEM; goto fail_signal_source_create; } @@ -637,7 +658,7 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) { loop->cf_state = state; /* uv_thread_t is an alias for pthread_t. */ - err = -pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop); + err = UV__ERR(pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop)); if (attr != NULL) pthread_attr_destroy(attr); @@ -769,7 +790,7 @@ int uv__cf_loop_signal(uv_loop_t* loop, item = uv__malloc(sizeof(*item)); if (item == NULL) - return -ENOMEM; + return UV_ENOMEM; item->handle = handle; item->type = type; @@ -799,7 +820,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) { /* Get absolute path to file */ handle->realpath = realpath(handle->path, NULL); if (handle->realpath == NULL) - return -errno; + return UV__ERR(errno); handle->realpath_len = strlen(handle->realpath); /* Initialize event queue */ @@ -812,13 +833,13 @@ int uv__fsevents_init(uv_fs_event_t* handle) { */ handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb)); if (handle->cf_cb == NULL) { - err = -ENOMEM; + err = UV_ENOMEM; goto fail_cf_cb_malloc; } handle->cf_cb->data = handle; uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb); - handle->cf_cb->flags |= UV__HANDLE_INTERNAL; + handle->cf_cb->flags |= UV_HANDLE_INTERNAL; uv_unref((uv_handle_t*) handle->cf_cb); err = uv_mutex_init(&handle->cf_mutex); @@ -863,7 +884,7 @@ int uv__fsevents_close(uv_fs_event_t* handle) { uv__cf_loop_state_t* state; if (handle->cf_cb == NULL) - return -EINVAL; + return UV_EINVAL; /* Remove handle from the list */ state = handle->loop->cf_state; @@ -877,7 +898,7 @@ int uv__fsevents_close(uv_fs_event_t* handle) { assert(handle != NULL); err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing); if (err) - return -err; + return UV__ERR(err); /* Wait for deinitialization */ uv_sem_wait(&state->fsevent_sem); diff --git a/Utilities/cmlibuv/src/unix/getaddrinfo.c b/Utilities/cmlibuv/src/unix/getaddrinfo.c index 2049aea2f..d7ca7d1a4 100644 --- a/Utilities/cmlibuv/src/unix/getaddrinfo.c +++ b/Utilities/cmlibuv/src/unix/getaddrinfo.c @@ -27,11 +27,13 @@ #include "uv.h" #include "internal.h" +#include "idna.h" #include <errno.h> #include <stddef.h> /* NULL */ #include <stdlib.h> #include <string.h> +#include <net/if.h> /* if_indextoname() */ /* EAI_* constants. */ #include <netdb.h> @@ -85,12 +87,14 @@ int uv__getaddrinfo_translate_error(int sys_err) { case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE; #endif #if defined(EAI_SYSTEM) - case EAI_SYSTEM: return -errno; + case EAI_SYSTEM: return UV__ERR(errno); #endif } assert(!"unknown EAI_* error code"); abort(); +#ifndef __SUNPRO_C return 0; /* Pacify compiler. */ +#endif } @@ -124,7 +128,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { req->service = NULL; req->hostname = NULL; - if (status == -ECANCELED) { + if (status == UV_ECANCELED) { assert(req->retcode == 0); req->retcode = UV_EAI_CANCELED; } @@ -140,14 +144,33 @@ int uv_getaddrinfo(uv_loop_t* loop, const char* hostname, const char* service, const struct addrinfo* hints) { + char hostname_ascii[256]; size_t hostname_len; size_t service_len; size_t hints_len; size_t len; char* buf; + long rc; if (req == NULL || (hostname == NULL && service == NULL)) - return -EINVAL; + return UV_EINVAL; + + /* FIXME(bnoordhuis) IDNA does not seem to work z/OS, + * probably because it uses EBCDIC rather than ASCII. + */ +#ifdef __MVS__ + (void) &hostname_ascii; +#else + if (hostname != NULL) { + rc = uv__idna_toascii(hostname, + hostname + strlen(hostname), + hostname_ascii, + hostname_ascii + sizeof(hostname_ascii)); + if (rc < 0) + return rc; + hostname = hostname_ascii; + } +#endif hostname_len = hostname ? strlen(hostname) + 1 : 0; service_len = service ? strlen(service) + 1 : 0; @@ -155,7 +178,7 @@ int uv_getaddrinfo(uv_loop_t* loop, buf = uv__malloc(hostname_len + service_len + hints_len); if (buf == NULL) - return -ENOMEM; + return UV_ENOMEM; uv__req_init(loop, req, UV_GETADDRINFO); req->loop = loop; @@ -185,6 +208,7 @@ int uv_getaddrinfo(uv_loop_t* loop, if (cb) { uv__work_submit(loop, &req->work_req, + UV__WORK_SLOW_IO, uv__getaddrinfo_work, uv__getaddrinfo_done); return 0; @@ -200,3 +224,32 @@ void uv_freeaddrinfo(struct addrinfo* ai) { if (ai) freeaddrinfo(ai); } + + +int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { + char ifname_buf[UV_IF_NAMESIZE]; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + if (if_indextoname(ifindex, ifname_buf) == NULL) + return UV__ERR(errno); + + len = strnlen(ifname_buf, sizeof(ifname_buf)); + + if (*size <= len) { + *size = len + 1; + return UV_ENOBUFS; + } + + memcpy(buffer, ifname_buf, len); + buffer[len] = '\0'; + *size = len; + + return 0; +} + +int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { + return uv_if_indextoname(ifindex, buffer, size); +} diff --git a/Utilities/cmlibuv/src/unix/getnameinfo.c b/Utilities/cmlibuv/src/unix/getnameinfo.c index b2879d69b..b695081b4 100644 --- a/Utilities/cmlibuv/src/unix/getnameinfo.c +++ b/Utilities/cmlibuv/src/unix/getnameinfo.c @@ -61,7 +61,7 @@ static void uv__getnameinfo_done(struct uv__work* w, int status) { uv__req_unregister(req->loop, req); host = service = NULL; - if (status == -ECANCELED) { + if (status == UV_ECANCELED) { assert(req->retcode == 0); req->retcode = UV_EAI_CANCELED; } else if (req->retcode == 0) { @@ -109,6 +109,7 @@ int uv_getnameinfo(uv_loop_t* loop, if (getnameinfo_cb) { uv__work_submit(loop, &req->work_req, + UV__WORK_SLOW_IO, uv__getnameinfo_work, uv__getnameinfo_done); return 0; diff --git a/Utilities/cmlibuv/src/unix/haiku.c b/Utilities/cmlibuv/src/unix/haiku.c new file mode 100644 index 000000000..7708851c2 --- /dev/null +++ b/Utilities/cmlibuv/src/unix/haiku.c @@ -0,0 +1,176 @@ +/* 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 <FindDirectory.h> /* find_path() */ +#include <OS.h> + + +void uv_loadavg(double avg[3]) { + avg[0] = 0; + avg[1] = 0; + avg[2] = 0; +} + + +int uv_exepath(char* buffer, size_t* size) { + char abspath[B_PATH_NAME_LENGTH]; + status_t status; + ssize_t abspath_len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + status = find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, abspath, + sizeof(abspath)); + if (status != B_OK) + return UV__ERR(status); + + abspath_len = uv__strscpy(buffer, abspath, *size); + *size -= 1; + if (abspath_len >= 0 && *size > (size_t)abspath_len) + *size = (size_t)abspath_len; + + return 0; +} + + +uint64_t uv_get_free_memory(void) { + status_t status; + system_info sinfo; + + status = get_system_info(&sinfo); + if (status != B_OK) + return 0; + + return (sinfo.max_pages - sinfo.used_pages) * B_PAGE_SIZE; +} + + +uint64_t uv_get_total_memory(void) { + status_t status; + system_info sinfo; + + status = get_system_info(&sinfo); + if (status != B_OK) + return 0; + + return sinfo.max_pages * B_PAGE_SIZE; +} + + +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + +int uv_resident_set_memory(size_t* rss) { + area_info area; + ssize_t cookie; + status_t status; + thread_info thread; + + status = get_thread_info(find_thread(NULL), &thread); + if (status != B_OK) + return UV__ERR(status); + + cookie = 0; + *rss = 0; + while (get_next_area_info(thread.team, &cookie, &area) == B_OK) + *rss += area.ram_size; + + return 0; +} + + +int uv_uptime(double* uptime) { + /* system_time() returns time since booting in microseconds */ + *uptime = (double)system_time() / 1000000; + return 0; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + cpu_topology_node_info* topology_infos; + int i; + status_t status; + system_info system; + uint32_t topology_count; + uint64_t cpuspeed; + uv_cpu_info_t* cpu_info; + + if (cpu_infos == NULL || count == NULL) + return UV_EINVAL; + + status = get_cpu_topology_info(NULL, &topology_count); + if (status != B_OK) + return UV__ERR(status); + + topology_infos = uv__malloc(topology_count * sizeof(*topology_infos)); + if (topology_infos == NULL) + return UV_ENOMEM; + + status = get_cpu_topology_info(topology_infos, &topology_count); + if (status != B_OK) { + uv__free(topology_infos); + return UV__ERR(status); + } + + cpuspeed = 0; + for (i = 0; i < (int)topology_count; i++) { + if (topology_infos[i].type == B_TOPOLOGY_CORE) { + cpuspeed = topology_infos[i].data.core.default_frequency; + break; + } + } + + uv__free(topology_infos); + + status = get_system_info(&system); + if (status != B_OK) + return UV__ERR(status); + + *cpu_infos = uv__calloc(system.cpu_count, sizeof(**cpu_infos)); + if (*cpu_infos == NULL) + return UV_ENOMEM; + + /* CPU time and model are not exposed by Haiku. */ + cpu_info = *cpu_infos; + for (i = 0; i < (int)system.cpu_count; i++) { + cpu_info->model = uv__strdup("unknown"); + cpu_info->speed = (int)(cpuspeed / 1000000); + cpu_info++; + } + *count = system.cpu_count; + + return 0; +} + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) + uv__free(cpu_infos[i].model); + + uv__free(cpu_infos); +} diff --git a/Utilities/cmlibuv/src/unix/hpux.c b/Utilities/cmlibuv/src/unix/hpux.c new file mode 100644 index 000000000..4d3f628b7 --- /dev/null +++ b/Utilities/cmlibuv/src/unix/hpux.c @@ -0,0 +1,30 @@ +/* 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> + +uint64_t uv__hrtime(uv_clocktype_t type) { + return (uint64_t) gethrtime(); +} diff --git a/Utilities/cmlibuv/src/unix/ibmi.c b/Utilities/cmlibuv/src/unix/ibmi.c new file mode 100644 index 000000000..c7e105136 --- /dev/null +++ b/Utilities/cmlibuv/src/unix/ibmi.c @@ -0,0 +1,250 @@ +/* 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 <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <sys/time.h> +#include <unistd.h> +#include <fcntl.h> +#include <utmp.h> +#include <libgen.h> + +#include <sys/protosw.h> +#include <procinfo.h> +#include <sys/proc.h> +#include <sys/procfs.h> + +#include <ctype.h> + +#include <sys/mntctl.h> +#include <sys/vmount.h> +#include <limits.h> +#include <strings.h> +#include <sys/vnode.h> + +#include <as400_protos.h> + + +typedef struct { + int bytes_available; + int bytes_returned; + char current_date_and_time[8]; + char system_name[8]; + char elapsed_time[6]; + char restricted_state_flag; + char reserved; + int percent_processing_unit_used; + int jobs_in_system; + int percent_permanent_addresses; + int percent_temporary_addresses; + int system_asp; + int percent_system_asp_used; + int total_auxiliary_storage; + int current_unprotected_storage_used; + int maximum_unprotected_storage_used; + int percent_db_capability; + int main_storage_size; + int number_of_partitions; + int partition_identifier; + int reserved1; + int current_processing_capacity; + char processor_sharing_attribute; + char reserved2[3]; + int number_of_processors; + int active_jobs_in_system; + int active_threads_in_system; + int maximum_jobs_in_system; + int percent_temporary_256mb_segments_used; + int percent_temporary_4gb_segments_used; + int percent_permanent_256mb_segments_used; + int percent_permanent_4gb_segments_used; + int percent_current_interactive_performance; + int percent_uncapped_cpu_capacity_used; + int percent_shared_processor_pool_used; + long main_storage_size_long; +} SSTS0200; + + +static int get_ibmi_system_status(SSTS0200* rcvr) { + /* rcvrlen is input parameter 2 to QWCRSSTS */ + unsigned int rcvrlen = sizeof(*rcvr); + + /* format is input parameter 3 to QWCRSSTS ("SSTS0200" in EBCDIC) */ + unsigned char format[] = {0xE2, 0xE2, 0xE3, 0xE2, 0xF0, 0xF2, 0xF0, 0xF0}; + + /* reset_status is input parameter 4 to QWCRSSTS ("*NO " in EBCDIC) */ + unsigned char reset_status[] = { + 0x5C, 0xD5, 0xD6, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 + }; + + /* errcode is input parameter 5 to QWCRSSTS */ + struct _errcode { + int bytes_provided; + int bytes_available; + char msgid[7]; + } errcode; + + /* qwcrssts_pointer is the 16-byte tagged system pointer to QWCRSSTS */ + ILEpointer __attribute__((aligned(16))) qwcrssts_pointer; + + /* qwcrssts_argv is the array of argument pointers to QWCRSSTS */ + void* qwcrssts_argv[6]; + + /* Set the IBM i pointer to the QSYS/QWCRSSTS *PGM object */ + int rc = _RSLOBJ2(&qwcrssts_pointer, RSLOBJ_TS_PGM, "QWCRSSTS", "QSYS"); + + if (rc != 0) + return rc; + + /* initialize the QWCRSSTS returned info structure */ + memset(rcvr, 0, sizeof(*rcvr)); + + /* initialize the QWCRSSTS error code structure */ + memset(&errcode, 0, sizeof(errcode)); + errcode.bytes_provided = sizeof(errcode); + + /* initialize the array of argument pointers for the QWCRSSTS API */ + qwcrssts_argv[0] = rcvr; + qwcrssts_argv[1] = &rcvrlen; + qwcrssts_argv[2] = &format; + qwcrssts_argv[3] = &reset_status; + qwcrssts_argv[4] = &errcode; + qwcrssts_argv[5] = NULL; + + /* Call the IBM i QWCRSSTS API from PASE */ + rc = _PGMCALL(&qwcrssts_pointer, (void**)&qwcrssts_argv, 0); + + return rc; +} + + +uint64_t uv_get_free_memory(void) { + SSTS0200 rcvr; + + if (get_ibmi_system_status(&rcvr)) + return 0; + + /* The amount of main storage, in kilobytes, in the system. */ + uint64_t main_storage_size = rcvr.main_storage_size; + + /* The current amount of storage in use for temporary objects. + * in millions (M) of bytes. + */ + uint64_t current_unprotected_storage_used = + rcvr.current_unprotected_storage_used * 1024ULL; + + uint64_t free_storage_size = + (main_storage_size - current_unprotected_storage_used) * 1024ULL; + + return free_storage_size < 0 ? 0 : free_storage_size; +} + + +uint64_t uv_get_total_memory(void) { + SSTS0200 rcvr; + + if (get_ibmi_system_status(&rcvr)) + return 0; + + return (uint64_t)rcvr.main_storage_size * 1024ULL; +} + + +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + +void uv_loadavg(double avg[3]) { + SSTS0200 rcvr; + + if (get_ibmi_system_status(&rcvr)) { + avg[0] = avg[1] = avg[2] = 0; + return; + } + + /* The average (in tenths) of the elapsed time during which the processing + * units were in use. For example, a value of 411 in binary would be 41.1%. + * This percentage could be greater than 100% for an uncapped partition. + */ + double processing_unit_used_percent = + rcvr.percent_processing_unit_used / 1000.0; + + avg[0] = avg[1] = avg[2] = processing_unit_used_percent; +} + + +int uv_resident_set_memory(size_t* rss) { + *rss = 0; + return 0; +} + + +int uv_uptime(double* uptime) { + return UV_ENOSYS; +} + + +int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { + unsigned int numcpus, idx = 0; + uv_cpu_info_t* cpu_info; + + *cpu_infos = NULL; + *count = 0; + + numcpus = sysconf(_SC_NPROCESSORS_ONLN); + + *cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t)); + if (!*cpu_infos) { + return UV_ENOMEM; + } + + cpu_info = *cpu_infos; + for (idx = 0; idx < numcpus; idx++) { + cpu_info->speed = 0; + cpu_info->model = uv__strdup("unknown"); + cpu_info->cpu_times.user = 0; + cpu_info->cpu_times.sys = 0; + cpu_info->cpu_times.idle = 0; + cpu_info->cpu_times.irq = 0; + cpu_info->cpu_times.nice = 0; + cpu_info++; + } + *count = numcpus; + + return 0; +} + diff --git a/Utilities/cmlibuv/src/unix/internal.h b/Utilities/cmlibuv/src/unix/internal.h index 2e3afa6c8..b43c0b190 100644 --- a/Utilities/cmlibuv/src/unix/internal.h +++ b/Utilities/cmlibuv/src/unix/internal.h @@ -29,6 +29,7 @@ #include <string.h> /* strrchr */ #include <fcntl.h> /* O_CLOEXEC, may be */ #include <stdio.h> +#include <errno.h> #if defined(__STRICT_ANSI__) # define inline __inline @@ -59,7 +60,17 @@ # include <AvailabilityMacros.h> #endif -#if defined(__ANDROID__) +#if defined(CMAKE_BOOTSTRAP) +# undef pthread_atfork +# define pthread_atfork(prepare, parent, child) \ + uv__pthread_atfork(prepare, parent, child) +int uv__pthread_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void)); +# undef pthread_sigmask +# define pthread_sigmask(how, set, oldset) \ + uv__pthread_sigmask(how, set, oldset) +int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); +#elif defined(__ANDROID__) int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); # ifdef pthread_sigmask # undef pthread_sigmask @@ -94,8 +105,7 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); */ #if defined(__clang__) || \ defined(__GNUC__) || \ - defined(__INTEL_COMPILER) || \ - defined(__SUNPRO_C) + defined(__INTEL_COMPILER) # define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration # define UV_UNUSED(declaration) __attribute__((unused)) declaration #else @@ -110,6 +120,12 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); # define UV__POLLRDHUP 0x2000 #endif +#ifdef POLLPRI +# define UV__POLLPRI POLLPRI +#else +# define UV__POLLPRI 0 +#endif + #if !defined(O_CLOEXEC) && defined(__FreeBSD__) /* * It may be that we are just missing `__POSIX_VISIBLE >= 200809`. @@ -120,29 +136,15 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t; -/* handle flags */ +/* loop flags */ enum { - UV_CLOSING = 0x01, /* uv_close() called but not finished. */ - UV_CLOSED = 0x02, /* close(2) finished. */ - UV_STREAM_READING = 0x04, /* uv_read_start() called. */ - UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */ - UV_STREAM_SHUT = 0x10, /* Write side closed. */ - UV_STREAM_READABLE = 0x20, /* The stream is readable */ - UV_STREAM_WRITABLE = 0x40, /* The stream is writable */ - UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */ - UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */ - UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */ - UV_TCP_NODELAY = 0x400, /* Disable Nagle. */ - UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */ - UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */ - UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */ - UV_UDP_PROCESSING = 0x20000, /* Handle is running the send callback queue. */ - UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */ + UV_LOOP_BLOCK_SIGPROF = 1 }; -/* loop flags */ +/* flags of excluding ifaddr */ enum { - UV_LOOP_BLOCK_SIGPROF = 1 + UV__EXCLUDE_IFPHYS, + UV__EXCLUDE_IFADDR }; typedef enum { @@ -163,7 +165,8 @@ struct uv__stream_queued_fds_s { defined(__FreeBSD__) || \ defined(__FreeBSD_kernel__) || \ defined(__linux__) || \ - defined(__OpenBSD__) + defined(__OpenBSD__) || \ + defined(__NetBSD__) #define uv__cloexec uv__cloexec_ioctl #define uv__nonblock uv__nonblock_ioctl #else @@ -171,15 +174,27 @@ struct uv__stream_queued_fds_s { #define uv__nonblock uv__nonblock_fcntl #endif +/* On Linux, uv__nonblock_fcntl() and uv__nonblock_ioctl() do not commute + * when O_NDELAY is not equal to O_NONBLOCK. Case in point: linux/sparc32 + * and linux/sparc64, where O_NDELAY is O_NONBLOCK + another bit. + * + * Libuv uses uv__nonblock_fcntl() directly sometimes so ensure that it + * commutes with uv__nonblock(). + */ +#if defined(__linux__) && O_NDELAY != O_NONBLOCK +#undef uv__nonblock +#define uv__nonblock uv__nonblock_fcntl +#endif + /* core */ int uv__cloexec_ioctl(int fd, int set); int uv__cloexec_fcntl(int fd, int set); int uv__nonblock_ioctl(int fd, int set); int uv__nonblock_fcntl(int fd, int set); -int uv__close(int fd); +int uv__close(int fd); /* preserves errno */ int uv__close_nocheckstdio(int fd); +int uv__close_nocancel(int fd); int uv__socket(int domain, int type, int protocol); -int uv__dup(int fd); ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags); void uv__make_close_pending(uv_handle_t* handle); int uv__getiovmax(void); @@ -193,6 +208,7 @@ 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); +int uv__fd_exists(uv_loop_t* loop, int fd); /* async */ void uv__async_stop(uv_loop_t* loop); @@ -225,10 +241,6 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay); /* pipe */ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); -/* timer */ -void uv__run_timers(uv_loop_t* loop); -int uv__next_timeout(const uv_loop_t* loop); - /* signal */ void uv__signal_close(uv_signal_t* handle); void uv__signal_global_once_init(void); @@ -253,7 +265,6 @@ void uv__prepare_close(uv_prepare_t* handle); void uv__process_close(uv_process_t* handle); void uv__stream_close(uv_stream_t* handle); void uv__tcp_close(uv_tcp_t* handle); -void uv__timer_close(uv_timer_t* handle); void uv__udp_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle); uv_handle_type uv__handle_type(int fd); @@ -261,7 +272,7 @@ FILE* uv__open_file(const char* path); int uv__getpwuid_r(uv_passwd_t* pwd); -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(CMAKE_BOOTSTRAP) int uv___stream_fd(const uv_stream_t* handle); #define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle))) #else @@ -283,24 +294,6 @@ int uv__fsevents_init(uv_fs_event_t* handle); int uv__fsevents_close(uv_fs_event_t* handle); void uv__fsevents_loop_delete(uv_loop_t* loop); -/* OSX < 10.7 has no file events, polyfill them */ -#ifndef MAC_OS_X_VERSION_10_7 - -static const int kFSEventStreamCreateFlagFileEvents = 0x00000010; -static const int kFSEventStreamEventFlagItemCreated = 0x00000100; -static const int kFSEventStreamEventFlagItemRemoved = 0x00000200; -static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400; -static const int kFSEventStreamEventFlagItemRenamed = 0x00000800; -static const int kFSEventStreamEventFlagItemModified = 0x00001000; -static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000; -static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000; -static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000; -static const int kFSEventStreamEventFlagItemIsFile = 0x00010000; -static const int kFSEventStreamEventFlagItemIsDir = 0x00020000; -static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000; - -#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */ - #endif /* defined(__APPLE__) */ UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) { @@ -323,4 +316,11 @@ UV_UNUSED(static char* uv__basename_r(const char* path)) { int uv__inotify_fork(uv_loop_t* loop, void* old_watchers); #endif +typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*); + +int uv__getsockpeername(const uv_handle_t* handle, + uv__peersockfunc func, + struct sockaddr* name, + int* namelen); + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/Utilities/cmlibuv/src/unix/kqueue.c b/Utilities/cmlibuv/src/unix/kqueue.c index 6bc60bbe4..c04e7a485 100644 --- a/Utilities/cmlibuv/src/unix/kqueue.c +++ b/Utilities/cmlibuv/src/unix/kqueue.c @@ -34,13 +34,24 @@ #include <fcntl.h> #include <time.h> +/* + * Required on + * - Until at least FreeBSD 11.0 + * - Older versions of Mac OS X + * + * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp + */ +#ifndef EV_OOBAND +#define EV_OOBAND EV_FLAG1 +#endif + static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags); int uv__kqueue_init(uv_loop_t* loop) { loop->backend_fd = kqueue(); if (loop->backend_fd == -1) - return -errno; + return UV__ERR(errno); uv__cloexec(loop->backend_fd, 1); @@ -48,17 +59,18 @@ int uv__kqueue_init(uv_loop_t* loop) { } +#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 static int uv__has_forked_with_cfrunloop; +#endif 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 defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 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 @@ -74,7 +86,7 @@ int uv__io_fork(uv_loop_t* loop) { uv__free(loop->cf_state); loop->cf_state = NULL; } -#endif +#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */ return err; } @@ -86,7 +98,7 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { rc = 0; EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL)) - rc = -errno; + rc = UV__ERR(errno); EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); if (rc == 0) @@ -166,6 +178,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } } + if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) { + EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0); + + if (++nevents == ARRAY_SIZE(events)) { + if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL)) + abort(); + nevents = 0; + } + } + w->events = w->pevents; } @@ -239,8 +261,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w = loop->watchers[fd]; if (w == NULL) { - /* File descriptor that we've stopped watching, disarm it. */ - /* TODO batch up */ + /* File descriptor that we've stopped watching, disarm it. + * TODO: batch up. */ struct kevent events[1]; EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); @@ -275,6 +297,20 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } } + if (ev->filter == EV_OOBAND) { + if (w->pevents & UV__POLLPRI) { + revents |= UV__POLLPRI; + w->rcount = ev->data; + } else { + /* TODO batch up */ + struct kevent events[1]; + EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); + if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL)) + if (errno != ENOENT) + abort(); + } + } + if (ev->filter == EVFILT_WRITE) { if (w->pevents & POLLOUT) { revents |= POLLOUT; @@ -351,6 +387,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { uintptr_t nfds; assert(loop->watchers != NULL); + assert(fd >= 0); events = (struct kevent*) loop->watchers[loop->nwatchers]; nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; @@ -416,49 +453,51 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags) { -#if defined(__APPLE__) - struct stat statbuf; -#endif /* defined(__APPLE__) */ int fd; if (uv__is_active(handle)) - return -EINVAL; - - /* TODO open asynchronously - but how do we report back errors? */ - fd = open(path, O_RDONLY); - if (fd == -1) - return -errno; - - uv__handle_start(handle); - uv__io_init(&handle->event_watcher, uv__fs_event, fd); - handle->path = uv__strdup(path); - handle->cb = cb; - -#if defined(__APPLE__) - if (uv__has_forked_with_cfrunloop) - goto fallback; + return UV_EINVAL; +#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 /* Nullify field to perform checks later */ handle->cf_cb = NULL; handle->realpath = NULL; handle->realpath_len = 0; handle->cf_flags = flags; - if (fstat(fd, &statbuf)) - goto fallback; - /* FSEvents works only with directories */ - if (!(statbuf.st_mode & S_IFDIR)) - goto fallback; - - /* The fallback fd is no longer needed */ - uv__close(fd); - handle->event_watcher.fd = -1; + if (!uv__has_forked_with_cfrunloop) { + int r; + /* The fallback fd is not used */ + handle->event_watcher.fd = -1; + handle->path = uv__strdup(path); + if (handle->path == NULL) + return UV_ENOMEM; + handle->cb = cb; + r = uv__fsevents_init(handle); + if (r == 0) { + uv__handle_start(handle); + } else { + uv__free(handle->path); + handle->path = NULL; + } + return r; + } +#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */ - return uv__fsevents_init(handle); + /* TODO open asynchronously - but how do we report back errors? */ + fd = open(path, O_RDONLY); + if (fd == -1) + return UV__ERR(errno); -fallback: -#endif /* defined(__APPLE__) */ + handle->path = uv__strdup(path); + if (handle->path == NULL) { + uv__close_nocheckstdio(fd); + return UV_ENOMEM; + } + handle->cb = cb; + uv__handle_start(handle); + uv__io_init(&handle->event_watcher, uv__fs_event, fd); uv__io_start(handle->loop, &handle->event_watcher, POLLIN); return 0; @@ -466,29 +505,29 @@ fallback: int uv_fs_event_stop(uv_fs_event_t* handle) { + int r; + r = 0; + if (!uv__is_active(handle)) return 0; uv__handle_stop(handle); -#if defined(__APPLE__) - if (uv__has_forked_with_cfrunloop || uv__fsevents_close(handle)) -#endif /* defined(__APPLE__) */ - { - uv__io_close(handle->loop, &handle->event_watcher); - } - - uv__free(handle->path); - handle->path = NULL; +#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + if (!uv__has_forked_with_cfrunloop) + r = uv__fsevents_close(handle); +#endif if (handle->event_watcher.fd != -1) { - /* When FSEvents is used, we don't use the event_watcher's fd under certain - * confitions. (see uv_fs_event_start) */ + uv__io_close(handle->loop, &handle->event_watcher); uv__close(handle->event_watcher.fd); handle->event_watcher.fd = -1; } - return 0; + uv__free(handle->path); + handle->path = NULL; + + return r; } diff --git a/Utilities/cmlibuv/src/unix/linux-core.c b/Utilities/cmlibuv/src/unix/linux-core.c index 2866e9385..b539beb86 100644 --- a/Utilities/cmlibuv/src/unix/linux-core.c +++ b/Utilities/cmlibuv/src/unix/linux-core.c @@ -20,12 +20,13 @@ /* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their * EPOLL* counterparts. We use the POLL* variants in this file because that - * is what libuv uses elsewhere and it avoids a dependency on <sys/epoll.h>. + * is what libuv uses elsewhere. */ #include "uv.h" #include "internal.h" +#include <inttypes.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -34,6 +35,7 @@ #include <errno.h> #include <net/if.h> +#include <sys/epoll.h> #include <sys/param.h> #include <sys/prctl.h> #include <sys/sysinfo.h> @@ -51,7 +53,7 @@ #ifdef HAVE_IFADDRS_H # if defined(__ANDROID__) -# include "android-ifaddrs.h" +# include "uv/android-ifaddrs.h" # else # include <ifaddrs.h> # endif @@ -78,19 +80,23 @@ static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci); static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); -static unsigned long read_cpufreq(unsigned int cpunum); +static uint64_t read_cpufreq(unsigned int cpunum); int uv__platform_loop_init(uv_loop_t* loop) { int fd; - fd = uv__epoll_create1(UV__EPOLL_CLOEXEC); + /* It was reported that EPOLL_CLOEXEC is not defined on Android API < 21, + * a.k.a. Lollipop. Since EPOLL_CLOEXEC is an alias for O_CLOEXEC on all + * architectures, we just use that instead. + */ + fd = epoll_create1(O_CLOEXEC); /* epoll_create1() can fail either because it's not implemented (old kernel) - * or because it doesn't understand the EPOLL_CLOEXEC flag. + * or because it doesn't understand the O_CLOEXEC flag. */ if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) { - fd = uv__epoll_create(256); + fd = epoll_create(256); if (fd != -1) uv__cloexec(fd, 1); @@ -101,7 +107,7 @@ int uv__platform_loop_init(uv_loop_t* loop) { loop->inotify_watchers = NULL; if (fd == -1) - return -errno; + return UV__ERR(errno); return 0; } @@ -134,20 +140,21 @@ void uv__platform_loop_delete(uv_loop_t* loop) { void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { - struct uv__epoll_event* events; - struct uv__epoll_event dummy; + struct epoll_event* events; + struct epoll_event dummy; uintptr_t i; uintptr_t nfds; assert(loop->watchers != NULL); + assert(fd >= 0); - events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers]; + events = (struct epoll_event*) loop->watchers[loop->nwatchers]; nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; if (events != NULL) /* Invalidate events with same file descriptor */ for (i = 0; i < nfds; i++) - if ((int) events[i].data == fd) - events[i].data = -1; + if (events[i].data.fd == fd) + events[i].data.fd = -1; /* Remove the file descriptor from the epoll. * This avoids a problem where the same file description remains open @@ -160,25 +167,26 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. */ memset(&dummy, 0, sizeof(dummy)); - uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy); + epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy); } } int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct uv__epoll_event e; + struct epoll_event e; int rc; + memset(&e, 0, sizeof(e)); e.events = POLLIN; - e.data = -1; + e.data.fd = -1; rc = 0; - if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e)) + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e)) if (errno != EEXIST) - rc = -errno; + rc = UV__ERR(errno); if (rc == 0) - if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e)) + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e)) abort(); return rc; @@ -195,16 +203,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * that being the largest value I have seen in the wild (and only once.) */ static const int max_safe_timeout = 1789569; - static int no_epoll_pwait; - static int no_epoll_wait; - struct uv__epoll_event events[1024]; - struct uv__epoll_event* pe; - struct uv__epoll_event e; + struct epoll_event events[1024]; + struct epoll_event* pe; + struct epoll_event e; int real_timeout; QUEUE* q; uv__io_t* w; sigset_t sigset; - uint64_t sigmask; + sigset_t* psigset; uint64_t base; int have_signals; int nevents; @@ -219,6 +225,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { return; } + memset(&e, 0, sizeof(e)); + while (!QUEUE_EMPTY(&loop->watcher_queue)) { q = QUEUE_HEAD(&loop->watcher_queue); QUEUE_REMOVE(q); @@ -230,35 +238,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { assert(w->fd < (int) loop->nwatchers); e.events = w->pevents; - e.data = w->fd; + e.data.fd = w->fd; if (w->events == 0) - op = UV__EPOLL_CTL_ADD; + op = EPOLL_CTL_ADD; else - op = UV__EPOLL_CTL_MOD; + op = EPOLL_CTL_MOD; /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching * events, skip the syscall and squelch the events after epoll_wait(). */ - if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) { + if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) { if (errno != EEXIST) abort(); - assert(op == UV__EPOLL_CTL_ADD); + assert(op == EPOLL_CTL_ADD); /* We've reactivated a file descriptor that's been watched before. */ - if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e)) + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e)) abort(); } w->events = w->pevents; } - sigmask = 0; + psigset = NULL; if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { sigemptyset(&sigset); sigaddset(&sigset, SIGPROF); - sigmask |= 1 << (SIGPROF - 1); + psigset = &sigset; } assert(timeout >= -1); @@ -273,30 +281,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) timeout = max_safe_timeout; - if (sigmask != 0 && no_epoll_pwait != 0) - if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) - abort(); - - if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) { - nfds = uv__epoll_pwait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout, - sigmask); - if (nfds == -1 && errno == ENOSYS) - no_epoll_pwait = 1; - } else { - nfds = uv__epoll_wait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout); - if (nfds == -1 && errno == ENOSYS) - no_epoll_wait = 1; - } - - if (sigmask != 0 && no_epoll_pwait != 0) - if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)) - abort(); + nfds = epoll_pwait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout, + psigset); /* 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 @@ -317,12 +306,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (nfds == -1) { - if (errno == ENOSYS) { - /* epoll_wait() or epoll_pwait() failed, try the other system call. */ - assert(no_epoll_wait == 0 || no_epoll_pwait == 0); - continue; - } - if (errno != EINTR) abort(); @@ -344,7 +327,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; for (i = 0; i < nfds; i++) { pe = events + i; - fd = pe->data; + fd = pe->data.fd; /* Skip invalidated events, see uv__platform_invalidate_fd */ if (fd == -1) @@ -361,7 +344,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * Ignore all errors because we may be racing with another thread * when the file descriptor is closed. */ - uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe); + epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe); continue; } @@ -388,7 +371,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * free when we switch over to edge-triggered I/O. */ if (pe->events == POLLERR || pe->events == POLLHUP) - pe->events |= w->pevents & (POLLIN | POLLOUT); + pe->events |= + w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); if (pe->events != 0) { /* Run signal watchers last. This also affects child process watchers @@ -485,7 +469,7 @@ int uv_resident_set_memory(size_t* rss) { while (fd == -1 && errno == EINTR); if (fd == -1) - return -errno; + return UV__ERR(errno); do n = read(fd, buf, sizeof(buf) - 1); @@ -493,7 +477,7 @@ int uv_resident_set_memory(size_t* rss) { uv__close(fd); if (n == -1) - return -errno; + return UV__ERR(errno); buf[n] = '\0'; s = strchr(buf, ' '); @@ -525,7 +509,7 @@ int uv_resident_set_memory(size_t* rss) { return 0; err: - return -EINVAL; + return UV_EINVAL; } @@ -547,7 +531,7 @@ int uv_uptime(double* uptime) { } if (r) - return -errno; + return UV__ERR(errno); *uptime = now.tv_sec; return 0; @@ -559,7 +543,7 @@ static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { char buf[1024]; if (!fgets(buf, sizeof(buf), statfile_fp)) - return -EIO; + return UV_EIO; num = 0; while (fgets(buf, sizeof(buf), statfile_fp)) { @@ -569,7 +553,7 @@ static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { } if (num == 0) - return -EIO; + return UV_EIO; *numcpus = num; return 0; @@ -587,13 +571,13 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { statfile_fp = uv__open_file("/proc/stat"); if (statfile_fp == NULL) - return -errno; + return UV__ERR(errno); err = uv__cpu_num(statfile_fp, &numcpus); if (err < 0) goto out; - err = -ENOMEM; + err = UV_ENOMEM; ci = uv__calloc(numcpus, sizeof(*ci)); if (ci == NULL) goto out; @@ -667,7 +651,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { defined(__x86_64__) fp = uv__open_file("/proc/cpuinfo"); if (fp == NULL) - return -errno; + return UV__ERR(errno); while (fgets(buf, sizeof(buf), fp)) { if (model_idx < numcpus) { @@ -676,7 +660,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */ if (model == NULL) { fclose(fp); - return -ENOMEM; + return UV_ENOMEM; } ci[model_idx++].model = model; continue; @@ -695,7 +679,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */ if (model == NULL) { fclose(fp); - return -ENOMEM; + return UV_ENOMEM; } ci[model_idx++].model = model; continue; @@ -725,7 +709,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { while (model_idx < numcpus) { model = uv__strndup(inferred_model, strlen(inferred_model)); if (model == NULL) - return -ENOMEM; + return UV_ENOMEM; ci[model_idx++].model = model; } @@ -736,20 +720,20 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci) { - unsigned long clock_ticks; struct uv_cpu_times_s ts; - unsigned long user; - unsigned long nice; - unsigned long sys; - unsigned long idle; - unsigned long dummy; - unsigned long irq; - unsigned int num; - unsigned int len; + uint64_t clock_ticks; + uint64_t user; + uint64_t nice; + uint64_t sys; + uint64_t idle; + uint64_t dummy; + uint64_t irq; + uint64_t num; + uint64_t len; char buf[1024]; clock_ticks = sysconf(_SC_CLK_TCK); - assert(clock_ticks != (unsigned long) -1); + assert(clock_ticks != (uint64_t) -1); assert(clock_ticks != 0); rewind(statfile_fp); @@ -782,7 +766,8 @@ static int read_times(FILE* statfile_fp, * fields, they're not allowed in C89 mode. */ if (6 != sscanf(buf + len, - "%lu %lu %lu %lu %lu %lu", + "%" PRIu64 " %" PRIu64 " %" PRIu64 + "%" PRIu64 " %" PRIu64 " %" PRIu64, &user, &nice, &sys, @@ -804,8 +789,8 @@ static int read_times(FILE* statfile_fp, } -static unsigned long read_cpufreq(unsigned int cpunum) { - unsigned long val; +static uint64_t read_cpufreq(unsigned int cpunum) { + uint64_t val; char buf[1024]; FILE* fp; @@ -818,7 +803,7 @@ static unsigned long read_cpufreq(unsigned int cpunum) { if (fp == NULL) return 0; - if (fscanf(fp, "%lu", &val) != 1) + if (fscanf(fp, "%" PRIu64, &val) != 1) val = 0; fclose(fp); @@ -837,7 +822,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { uv__free(cpu_infos); } -static int uv__ifaddr_exclude(struct ifaddrs *ent) { +static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) return 1; if (ent->ifa_addr == NULL) @@ -847,47 +832,51 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) { * devices. We're not interested in this information yet. */ if (ent->ifa_addr->sa_family == PF_PACKET) - return 1; - return 0; + return exclude_type; + return !exclude_type; } -int uv_interface_addresses(uv_interface_address_t** addresses, - int* count) { +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { #ifndef HAVE_IFADDRS_H - return -ENOSYS; + *count = 0; + *addresses = NULL; + return UV_ENOSYS; #else struct ifaddrs *addrs, *ent; uv_interface_address_t* address; int i; struct sockaddr_ll *sll; - if (getifaddrs(&addrs)) - return -errno; - *count = 0; *addresses = NULL; + if (getifaddrs(&addrs)) + return UV__ERR(errno); + /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; (*count)++; } - if (*count == 0) + if (*count == 0) { + freeifaddrs(addrs); return 0; + } - *addresses = uv__malloc(*count * sizeof(**addresses)); + /* Make sure the memory is initiallized to zero using calloc() */ + *addresses = uv__calloc(*count, sizeof(**addresses)); if (!(*addresses)) { freeifaddrs(addrs); - return -ENOMEM; + return UV_ENOMEM; } address = *addresses; for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) continue; address->name = uv__strdup(ent->ifa_name); @@ -911,13 +900,16 @@ int uv_interface_addresses(uv_interface_address_t** addresses, /* Fill in physical addresses for each interface */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { - if (uv__ifaddr_exclude(ent)) + if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) continue; address = *addresses; for (i = 0; i < (*count); i++) { - if (strcmp(address->name, ent->ifa_name) == 0) { + size_t namelen = strlen(ent->ifa_name); + /* Alias interface share the same physical address */ + if (strncmp(address->name, ent->ifa_name, namelen) == 0 && + (address->name[namelen] == 0 || address->name[namelen] == ':')) { sll = (struct sockaddr_ll*)ent->ifa_addr; memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr)); } @@ -949,3 +941,114 @@ void uv__set_process_title(const char* title) { prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */ #endif } + + +static uint64_t uv__read_proc_meminfo(const char* what) { + uint64_t rc; + ssize_t n; + char* p; + int fd; + char buf[4096]; /* Large enough to hold all of /proc/meminfo. */ + + rc = 0; + fd = uv__open_cloexec("/proc/meminfo", O_RDONLY); + + if (fd == -1) + return 0; + + n = read(fd, buf, sizeof(buf) - 1); + + if (n <= 0) + goto out; + + buf[n] = '\0'; + p = strstr(buf, what); + + if (p == NULL) + goto out; + + p += strlen(what); + + if (1 != sscanf(p, "%" PRIu64 " kB", &rc)) + goto out; + + rc *= 1024; + +out: + + if (uv__close_nocheckstdio(fd)) + abort(); + + return rc; +} + + +uint64_t uv_get_free_memory(void) { + struct sysinfo info; + uint64_t rc; + + rc = uv__read_proc_meminfo("MemFree:"); + + if (rc != 0) + return rc; + + if (0 == sysinfo(&info)) + return (uint64_t) info.freeram * info.mem_unit; + + return 0; +} + + +uint64_t uv_get_total_memory(void) { + struct sysinfo info; + uint64_t rc; + + rc = uv__read_proc_meminfo("MemTotal:"); + + if (rc != 0) + return rc; + + if (0 == sysinfo(&info)) + return (uint64_t) info.totalram * info.mem_unit; + + return 0; +} + + +static uint64_t uv__read_cgroups_uint64(const char* cgroup, const char* param) { + char filename[256]; + uint64_t rc; + int fd; + ssize_t n; + char buf[32]; /* Large enough to hold an encoded uint64_t. */ + + snprintf(filename, 256, "/sys/fs/cgroup/%s/%s", cgroup, param); + + rc = 0; + fd = uv__open_cloexec(filename, O_RDONLY); + + if (fd < 0) + return 0; + + n = read(fd, buf, sizeof(buf) - 1); + + if (n > 0) { + buf[n] = '\0'; + sscanf(buf, "%" PRIu64, &rc); + } + + if (uv__close_nocheckstdio(fd)) + abort(); + + return rc; +} + + +uint64_t uv_get_constrained_memory(void) { + /* + * This might return 0 if there was a problem getting the memory limit from + * cgroups. This is OK because a return value of 0 signifies that the memory + * limit is unknown. + */ + return uv__read_cgroups_uint64("memory", "memory.limit_in_bytes"); +} diff --git a/Utilities/cmlibuv/src/unix/linux-inotify.c b/Utilities/cmlibuv/src/unix/linux-inotify.c index 5934c5d8c..9b26202fb 100644 --- a/Utilities/cmlibuv/src/unix/linux-inotify.c +++ b/Utilities/cmlibuv/src/unix/linux-inotify.c @@ -19,7 +19,7 @@ */ #include "uv.h" -#include "tree.h" +#include "uv/tree.h" #include "internal.h" #include <stdint.h> @@ -73,11 +73,11 @@ static int new_inotify_fd(void) { return fd; if (errno != ENOSYS) - return -errno; + return UV__ERR(errno); fd = uv__inotify_init(); if (fd == -1) - return -errno; + return UV__ERR(errno); err = uv__cloexec(fd, 1); if (err == 0) @@ -278,12 +278,13 @@ int uv_fs_event_start(uv_fs_event_t* handle, const char* path, unsigned int flags) { struct watcher_list* w; + size_t len; int events; int err; int wd; if (uv__is_active(handle)) - return -EINVAL; + return UV_EINVAL; err = init_inotify(handle->loop); if (err) @@ -300,18 +301,19 @@ int uv_fs_event_start(uv_fs_event_t* handle, wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events); if (wd == -1) - return -errno; + return UV__ERR(errno); w = find_watcher(handle->loop, wd); if (w) goto no_insert; - w = uv__malloc(sizeof(*w) + strlen(path) + 1); + len = strlen(path) + 1; + w = uv__malloc(sizeof(*w) + len); if (w == NULL) - return -ENOMEM; + return UV_ENOMEM; w->wd = wd; - w->path = strcpy((char*)(w + 1), path); + w->path = memcpy(w + 1, path, len); QUEUE_INIT(&w->watchers); w->iterating = 0; RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w); diff --git a/Utilities/cmlibuv/src/unix/linux-syscalls.c b/Utilities/cmlibuv/src/unix/linux-syscalls.c index 89998ded2..5637cf98a 100644 --- a/Utilities/cmlibuv/src/unix/linux-syscalls.c +++ b/Utilities/cmlibuv/src/unix/linux-syscalls.c @@ -77,56 +77,6 @@ # endif #endif /* __NR_eventfd2 */ -#ifndef __NR_epoll_create -# if defined(__x86_64__) -# define __NR_epoll_create 213 -# elif defined(__i386__) -# define __NR_epoll_create 254 -# elif defined(__arm__) -# define __NR_epoll_create (UV_SYSCALL_BASE + 250) -# endif -#endif /* __NR_epoll_create */ - -#ifndef __NR_epoll_create1 -# if defined(__x86_64__) -# define __NR_epoll_create1 291 -# elif defined(__i386__) -# define __NR_epoll_create1 329 -# elif defined(__arm__) -# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357) -# endif -#endif /* __NR_epoll_create1 */ - -#ifndef __NR_epoll_ctl -# if defined(__x86_64__) -# define __NR_epoll_ctl 233 /* used to be 214 */ -# elif defined(__i386__) -# define __NR_epoll_ctl 255 -# elif defined(__arm__) -# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251) -# endif -#endif /* __NR_epoll_ctl */ - -#ifndef __NR_epoll_wait -# if defined(__x86_64__) -# define __NR_epoll_wait 232 /* used to be 215 */ -# elif defined(__i386__) -# define __NR_epoll_wait 256 -# elif defined(__arm__) -# define __NR_epoll_wait (UV_SYSCALL_BASE + 252) -# endif -#endif /* __NR_epoll_wait */ - -#ifndef __NR_epoll_pwait -# if defined(__x86_64__) -# define __NR_epoll_pwait 281 -# elif defined(__i386__) -# define __NR_epoll_pwait 319 -# elif defined(__arm__) -# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346) -# endif -#endif /* __NR_epoll_pwait */ - #ifndef __NR_inotify_init # if defined(__x86_64__) # define __NR_inotify_init 253 @@ -237,6 +187,21 @@ # endif #endif /* __NR_pwritev */ +#ifndef __NR_statx +# if defined(__x86_64__) +# define __NR_statx 332 +# elif defined(__i386__) +# define __NR_statx 383 +# elif defined(__aarch64__) +# define __NR_statx 397 +# elif defined(__arm__) +# define __NR_statx (UV_SYSCALL_BASE + 397) +# elif defined(__ppc__) +# define __NR_statx 383 +# elif defined(__s390__) +# define __NR_statx 379 +# endif +#endif /* __NR_statx */ int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { #if defined(__i386__) @@ -285,76 +250,6 @@ int uv__eventfd2(unsigned int count, int flags) { } -int uv__epoll_create(int size) { -#if defined(__NR_epoll_create) - return syscall(__NR_epoll_create, size); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__epoll_create1(int flags) { -#if defined(__NR_epoll_create1) - return syscall(__NR_epoll_create1, flags); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) { -#if defined(__NR_epoll_ctl) - return syscall(__NR_epoll_ctl, epfd, op, fd, events); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__epoll_wait(int epfd, - struct uv__epoll_event* events, - int nevents, - int timeout) { -#if defined(__NR_epoll_wait) - int result; - result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout); -#if MSAN_ACTIVE - if (result > 0) - __msan_unpoison(events, sizeof(events[0]) * result); -#endif - return result; -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__epoll_pwait(int epfd, - struct uv__epoll_event* events, - int nevents, - int timeout, - uint64_t sigmask) { -#if defined(__NR_epoll_pwait) - int result; - result = syscall(__NR_epoll_pwait, - epfd, - events, - nevents, - timeout, - &sigmask, - sizeof(sigmask)); -#if MSAN_ACTIVE - if (result > 0) - __msan_unpoison(events, sizeof(events[0]) * result); -#endif - return result; -#else - return errno = ENOSYS, -1; -#endif -} - - int uv__inotify_init(void) { #if defined(__NR_inotify_init) return syscall(__NR_inotify_init); @@ -431,19 +326,6 @@ int uv__recvmmsg(int fd, } -int uv__utimesat(int dirfd, - const char* path, - const struct timespec times[2], - int flags) -{ -#if defined(__NR_utimensat) - return syscall(__NR_utimensat, dirfd, path, times, flags); -#else - return errno = ENOSYS, -1; -#endif -} - - ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { #if defined(__NR_preadv) return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); @@ -469,3 +351,19 @@ int uv__dup3(int oldfd, int newfd, int flags) { return errno = ENOSYS, -1; #endif } + + +int uv__statx(int dirfd, + const char* path, + int flags, + unsigned int mask, + struct uv__statx* statxbuf) { + /* __NR_statx make Android box killed by SIGSYS. + * That looks like a seccomp2 sandbox filter rejecting the system call. + */ +#if defined(__NR_statx) && !defined(__ANDROID__) + return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf); +#else + return errno = ENOSYS, -1; +#endif +} diff --git a/Utilities/cmlibuv/src/unix/linux-syscalls.h b/Utilities/cmlibuv/src/unix/linux-syscalls.h index 4c095e9b5..7e58bfa21 100644 --- a/Utilities/cmlibuv/src/unix/linux-syscalls.h +++ b/Utilities/cmlibuv/src/unix/linux-syscalls.h @@ -66,12 +66,6 @@ # define UV__SOCK_NONBLOCK UV__O_NONBLOCK #endif -/* epoll flags */ -#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC -#define UV__EPOLL_CTL_ADD 1 -#define UV__EPOLL_CTL_DEL 2 -#define UV__EPOLL_CTL_MOD 3 - /* inotify flags */ #define UV__IN_ACCESS 0x001 #define UV__IN_MODIFY 0x002 @@ -86,17 +80,35 @@ #define UV__IN_DELETE_SELF 0x400 #define UV__IN_MOVE_SELF 0x800 -#if defined(__x86_64__) -struct uv__epoll_event { - uint32_t events; - uint64_t data; -} __attribute__((packed)); -#else -struct uv__epoll_event { - uint32_t events; - uint64_t data; +struct uv__statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; + int32_t unused0; +}; + +struct uv__statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint16_t unused0; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct uv__statx_timestamp stx_atime; + struct uv__statx_timestamp stx_btime; + struct uv__statx_timestamp stx_ctime; + struct uv__statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t unused1[14]; }; -#endif struct uv__inotify_event { int32_t wd; @@ -113,18 +125,6 @@ struct uv__mmsghdr { int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags); int uv__eventfd(unsigned int count); -int uv__epoll_create(int size); -int uv__epoll_create1(int flags); -int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev); -int uv__epoll_wait(int epfd, - struct uv__epoll_event* events, - int nevents, - int timeout); -int uv__epoll_pwait(int epfd, - struct uv__epoll_event* events, - int nevents, - int timeout, - uint64_t sigmask); int uv__eventfd2(unsigned int count, int flags); int uv__inotify_init(void); int uv__inotify_init1(int flags); @@ -140,12 +140,13 @@ int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen, unsigned int flags); -int uv__utimesat(int dirfd, - const char* path, - const struct timespec times[2], - int flags); ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset); ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset); int uv__dup3(int oldfd, int newfd, int flags); +int uv__statx(int dirfd, + const char* path, + int flags, + unsigned int mask, + struct uv__statx* statxbuf); #endif /* UV_LINUX_SYSCALL_H_ */ diff --git a/Utilities/cmlibuv/src/unix/loop-watcher.c b/Utilities/cmlibuv/src/unix/loop-watcher.c index 340bb0dfa..b8c1c2a71 100644 --- a/Utilities/cmlibuv/src/unix/loop-watcher.c +++ b/Utilities/cmlibuv/src/unix/loop-watcher.c @@ -31,7 +31,7 @@ \ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ if (uv__is_active(handle)) return 0; \ - if (cb == NULL) return -EINVAL; \ + if (cb == NULL) return UV_EINVAL; \ QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \ handle->name##_cb = cb; \ uv__handle_start(handle); \ diff --git a/Utilities/cmlibuv/src/unix/loop.c b/Utilities/cmlibuv/src/unix/loop.c index bcd49242c..c2a03d770 100644 --- a/Utilities/cmlibuv/src/unix/loop.c +++ b/Utilities/cmlibuv/src/unix/loop.c @@ -20,7 +20,7 @@ */ #include "uv.h" -#include "tree.h" +#include "uv/tree.h" #include "internal.h" #include "heap-inl.h" #include <stdlib.h> @@ -31,7 +31,6 @@ int uv_loop_init(uv_loop_t* loop) { void* saved_data; int err; - uv__signal_global_once_init(); saved_data = loop->data; memset(loop, 0, sizeof(*loop)); @@ -39,13 +38,14 @@ int uv_loop_init(uv_loop_t* loop) { heap_init((struct heap*) &loop->timer_heap); QUEUE_INIT(&loop->wq); - QUEUE_INIT(&loop->active_reqs); QUEUE_INIT(&loop->idle_handles); QUEUE_INIT(&loop->async_handles); QUEUE_INIT(&loop->check_handles); QUEUE_INIT(&loop->prepare_handles); QUEUE_INIT(&loop->handle_queue); + loop->active_handles = 0; + loop->active_reqs.count = 0; loop->nfds = 0; loop->watchers = NULL; loop->nwatchers = 0; @@ -68,12 +68,13 @@ int uv_loop_init(uv_loop_t* loop) { if (err) return err; + uv__signal_global_once_init(); err = uv_signal_init(loop, &loop->child_watcher); if (err) goto fail_signal_init; uv__handle_unref(&loop->child_watcher); - loop->child_watcher.flags |= UV__HANDLE_INTERNAL; + loop->child_watcher.flags |= UV_HANDLE_INTERNAL; QUEUE_INIT(&loop->process_handles); err = uv_rwlock_init(&loop->cloexec_lock); @@ -89,7 +90,7 @@ int uv_loop_init(uv_loop_t* loop) { goto fail_async_init; uv__handle_unref(&loop->wq_async); - loop->wq_async.flags |= UV__HANDLE_INTERNAL; + loop->wq_async.flags |= UV_HANDLE_INTERNAL; return 0; diff --git a/Utilities/cmlibuv/src/unix/netbsd.c b/Utilities/cmlibuv/src/unix/netbsd.c index 9b5546b7e..c649bb375 100644 --- a/Utilities/cmlibuv/src/unix/netbsd.c +++ b/Utilities/cmlibuv/src/unix/netbsd.c @@ -40,8 +40,6 @@ #include <unistd.h> #include <time.h> -static char *process_title; - int uv__platform_loop_init(uv_loop_t* loop) { return uv__kqueue_init(loop); @@ -66,22 +64,33 @@ void uv_loadavg(double avg[3]) { int uv_exepath(char* buffer, size_t* size) { + /* Intermediate buffer, retrieving partial path name does not work + * As of NetBSD-8(beta), vnode->path translator does not handle files + * with longer names than 31 characters. + */ + char int_buf[PATH_MAX]; + size_t int_size; int mib[4]; - size_t cb; - pid_t mypid; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; - mypid = getpid(); mib[0] = CTL_KERN; mib[1] = KERN_PROC_ARGS; - mib[2] = mypid; - mib[3] = KERN_PROC_ARGV; + mib[2] = -1; + mib[3] = KERN_PROC_PATHNAME; + int_size = ARRAY_SIZE(int_buf); + + if (sysctl(mib, 4, int_buf, &int_size, NULL, 0)) + return UV__ERR(errno); + + /* Copy string from the intermediate buffer to outer one with appropriate + * length. + */ + /* TODO(bnoordhuis) Check uv__strscpy() return value. */ + uv__strscpy(buffer, int_buf, *size); - cb = *size; - if (sysctl(mib, 4, buffer, &cb, NULL, 0)) - return -errno; + /* Set new size. */ *size = strlen(buffer); return 0; @@ -94,7 +103,7 @@ uint64_t uv_get_free_memory(void) { int which[] = {CTL_VM, VM_UVMEXP}; if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); return (uint64_t) info.free * sysconf(_SC_PAGESIZE); } @@ -111,48 +120,14 @@ uint64_t uv_get_total_memory(void) { size_t size = sizeof(info); if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); return (uint64_t) info; } -char** uv_setup_args(int argc, char** argv) { - process_title = argc ? uv__strdup(argv[0]) : NULL; - return argv; -} - - -int uv_set_process_title(const char* title) { - if (process_title) uv__free(process_title); - - process_title = uv__strdup(title); - setproctitle("%s", title); - - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - size_t len; - - if (buffer == NULL || size == 0) - return -EINVAL; - - if (process_title) { - len = strlen(process_title) + 1; - - if (size < len) - return -ENOBUFS; - - memcpy(buffer, process_title, len); - } else { - len = 0; - } - - buffer[len] = '\0'; - - return 0; +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ } @@ -182,7 +157,7 @@ int uv_resident_set_memory(size_t* rss) { error: if (kd) kvm_close(kd); - return -EPERM; + return UV_EPERM; } @@ -193,7 +168,7 @@ int uv_uptime(double* uptime) { static int which[] = {CTL_KERN, KERN_BOOTTIME}; if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); now = time(NULL); @@ -217,12 +192,12 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(model); if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) && sysctlbyname("hw.model", &model, &size, NULL, 0)) { - return -errno; + return UV__ERR(errno); } size = sizeof(numcpus); if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); *count = numcpus; /* Only i386 and amd64 have machdep.tsc_freq */ @@ -233,16 +208,16 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = numcpus * CPUSTATES * sizeof(*cp_times); cp_times = uv__malloc(size); if (cp_times == NULL) - return -ENOMEM; + return UV_ENOMEM; if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); if (!(*cpu_infos)) { uv__free(cp_times); uv__free(*cpu_infos); - return -ENOMEM; + return UV_ENOMEM; } for (i = 0; i < numcpus; i++) { diff --git a/Utilities/cmlibuv/src/unix/no-fsevents.c b/Utilities/cmlibuv/src/unix/no-fsevents.c index 38fb6ab0b..158643af1 100644 --- a/Utilities/cmlibuv/src/unix/no-fsevents.c +++ b/Utilities/cmlibuv/src/unix/no-fsevents.c @@ -25,16 +25,16 @@ #include <errno.h> int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { - return -ENOSYS; + return UV_ENOSYS; } int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* filename, unsigned int flags) { - return -ENOSYS; + return UV_ENOSYS; } int uv_fs_event_stop(uv_fs_event_t* handle) { - return -ENOSYS; + return UV_ENOSYS; } void uv__fs_event_close(uv_fs_event_t* handle) { diff --git a/Utilities/cmlibuv/src/unix/no-proctitle.c b/Utilities/cmlibuv/src/unix/no-proctitle.c index a5c19fbff..165740ca3 100644 --- a/Utilities/cmlibuv/src/unix/no-proctitle.c +++ b/Utilities/cmlibuv/src/unix/no-proctitle.c @@ -35,7 +35,7 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { if (buffer == NULL || size == 0) - return -EINVAL; + return UV_EINVAL; buffer[0] = '\0'; return 0; diff --git a/Utilities/cmlibuv/src/unix/openbsd.c b/Utilities/cmlibuv/src/unix/openbsd.c index 56f0af15c..ffae7683d 100644 --- a/Utilities/cmlibuv/src/unix/openbsd.c +++ b/Utilities/cmlibuv/src/unix/openbsd.c @@ -36,9 +36,6 @@ #include <unistd.h> -static char *process_title; - - int uv__platform_loop_init(uv_loop_t* loop) { return uv__kqueue_init(loop); } @@ -71,11 +68,11 @@ int uv_exepath(char* buffer, size_t* size) { int err; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; mypid = getpid(); for (;;) { - err = -ENOMEM; + err = UV_ENOMEM; argsbuf_tmp = uv__realloc(argsbuf, argsbuf_size); if (argsbuf_tmp == NULL) goto out; @@ -88,14 +85,14 @@ int uv_exepath(char* buffer, size_t* size) { break; } if (errno != ENOMEM) { - err = -errno; + err = UV__ERR(errno); goto out; } argsbuf_size *= 2U; } if (argsbuf[0] == NULL) { - err = -EINVAL; /* FIXME(bnoordhuis) More appropriate error. */ + err = UV_EINVAL; /* FIXME(bnoordhuis) More appropriate error. */ goto out; } @@ -121,7 +118,7 @@ uint64_t uv_get_free_memory(void) { int which[] = {CTL_VM, VM_UVMEXP}; if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); return (uint64_t) info.free * sysconf(_SC_PAGESIZE); } @@ -133,46 +130,14 @@ uint64_t uv_get_total_memory(void) { size_t size = sizeof(info); if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); return (uint64_t) info; } -char** uv_setup_args(int argc, char** argv) { - process_title = argc ? uv__strdup(argv[0]) : NULL; - return argv; -} - - -int uv_set_process_title(const char* title) { - uv__free(process_title); - process_title = uv__strdup(title); - setproctitle("%s", title); - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - size_t len; - - if (buffer == NULL || size == 0) - return -EINVAL; - - if (process_title) { - len = strlen(process_title) + 1; - - if (size < len) - return -ENOBUFS; - - memcpy(buffer, process_title, len); - } else { - len = 0; - } - - buffer[len] = '\0'; - - return 0; +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ } @@ -190,7 +155,7 @@ int uv_resident_set_memory(size_t* rss) { mib[5] = 1; if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0) - return -errno; + return UV__ERR(errno); *rss = kinfo.p_vm_rssize * page_size; return 0; @@ -204,7 +169,7 @@ int uv_uptime(double* uptime) { static int which[] = {CTL_KERN, KERN_BOOTTIME}; if (sysctl(which, 2, &info, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); now = time(NULL); @@ -226,16 +191,16 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(model); if (sysctl(which, 2, &model, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); which[1] = HW_NCPU; size = sizeof(numcpus); if (sysctl(which, 2, &numcpus, &size, NULL, 0)) - return -errno; + return UV__ERR(errno); *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos)); if (!(*cpu_infos)) - return -ENOMEM; + return UV_ENOMEM; *count = numcpus; @@ -243,7 +208,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(cpuspeed); if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { uv__free(*cpu_infos); - return -errno; + return UV__ERR(errno); } size = sizeof(info); @@ -254,7 +219,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(info); if (sysctl(which, 3, &info, &size, NULL, 0)) { uv__free(*cpu_infos); - return -errno; + return UV__ERR(errno); } cpu_info = &(*cpu_infos)[i]; diff --git a/Utilities/cmlibuv/src/unix/os390-syscalls.c b/Utilities/cmlibuv/src/unix/os390-syscalls.c index 7edf2358d..1040d6697 100644 --- a/Utilities/cmlibuv/src/unix/os390-syscalls.c +++ b/Utilities/cmlibuv/src/unix/os390-syscalls.c @@ -25,6 +25,8 @@ #include <stdlib.h> #include <assert.h> #include <search.h> +#include <termios.h> +#include <sys/msg.h> #define CW_CONDVAR 32 @@ -103,10 +105,19 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) { unsigned int newsize; unsigned int i; struct pollfd* newlst; + struct pollfd event; if (len <= lst->size) return; + if (lst->size == 0) + event.fd = -1; + else { + /* Extract the message queue at the end. */ + event = lst->items[lst->size - 1]; + lst->items[lst->size - 1].fd = -1; + } + newsize = next_power_of_two(len); newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0])); @@ -115,32 +126,102 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) { for (i = lst->size; i < newsize; ++i) newlst[i].fd = -1; + /* Restore the message queue at the end */ + newlst[newsize - 1] = event; + lst->items = newlst; lst->size = newsize; } +static void init_message_queue(uv__os390_epoll* lst) { + struct { + long int header; + char body; + } msg; + + /* initialize message queue */ + lst->msg_queue = msgget(IPC_PRIVATE, 0600 | IPC_CREAT); + if (lst->msg_queue == -1) + abort(); + + /* + On z/OS, the message queue will be affiliated with the process only + when a send is performed on it. Once this is done, the system + can be queried for all message queues belonging to our process id. + */ + msg.header = 1; + if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0) + abort(); + + /* Clean up the dummy message sent above */ + if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body)) + abort(); +} + + +static void before_fork(void) { + uv_mutex_lock(&global_epoll_lock); +} + + +static void after_fork(void) { + uv_mutex_unlock(&global_epoll_lock); +} + + +static void child_fork(void) { + QUEUE* q; + uv_once_t child_once = UV_ONCE_INIT; + + /* reset once */ + memcpy(&once, &child_once, sizeof(child_once)); + + /* reset epoll list */ + while (!QUEUE_EMPTY(&global_epoll_queue)) { + uv__os390_epoll* lst; + q = QUEUE_HEAD(&global_epoll_queue); + QUEUE_REMOVE(q); + lst = QUEUE_DATA(q, uv__os390_epoll, member); + uv__free(lst->items); + lst->items = NULL; + lst->size = 0; + } + + uv_mutex_unlock(&global_epoll_lock); + uv_mutex_destroy(&global_epoll_lock); +} + + static void epoll_init(void) { QUEUE_INIT(&global_epoll_queue); if (uv_mutex_init(&global_epoll_lock)) abort(); + + if (pthread_atfork(&before_fork, &after_fork, &child_fork)) + abort(); } uv__os390_epoll* epoll_create1(int flags) { uv__os390_epoll* lst; - uv_once(&once, epoll_init); - uv_mutex_lock(&global_epoll_lock); lst = uv__malloc(sizeof(*lst)); - if (lst == -1) - return NULL; - QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); - uv_mutex_unlock(&global_epoll_lock); + if (lst != NULL) { + /* initialize list */ + lst->size = 0; + lst->items = NULL; + init_message_queue(lst); + maybe_resize(lst, 1); + lst->items[lst->size - 1].fd = lst->msg_queue; + lst->items[lst->size - 1].events = POLLIN; + lst->items[lst->size - 1].revents = 0; + uv_once(&once, epoll_init); + uv_mutex_lock(&global_epoll_lock); + QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); + uv_mutex_unlock(&global_epoll_lock); + } - /* initialize list */ - lst->size = 0; - lst->items = NULL; return lst; } @@ -149,71 +230,85 @@ int epoll_ctl(uv__os390_epoll* lst, int op, int fd, struct epoll_event *event) { - if(op == EPOLL_CTL_DEL) { + uv_mutex_lock(&global_epoll_lock); + + if (op == EPOLL_CTL_DEL) { if (fd >= lst->size || lst->items[fd].fd == -1) { + uv_mutex_unlock(&global_epoll_lock); errno = ENOENT; return -1; } lst->items[fd].fd = -1; - } else if(op == EPOLL_CTL_ADD) { - maybe_resize(lst, fd + 1); + } else if (op == EPOLL_CTL_ADD) { + + /* Resizing to 'fd + 1' would expand the list to contain at least + * 'fd'. But we need to guarantee that the last index on the list + * is reserved for the message queue. So specify 'fd + 2' instead. + */ + maybe_resize(lst, fd + 2); if (lst->items[fd].fd != -1) { + uv_mutex_unlock(&global_epoll_lock); errno = EEXIST; return -1; } lst->items[fd].fd = fd; lst->items[fd].events = event->events; - } else if(op == EPOLL_CTL_MOD) { - if (fd >= lst->size || lst->items[fd].fd == -1) { + lst->items[fd].revents = 0; + } else if (op == EPOLL_CTL_MOD) { + if (fd >= lst->size - 1 || lst->items[fd].fd == -1) { + uv_mutex_unlock(&global_epoll_lock); errno = ENOENT; return -1; } lst->items[fd].events = event->events; + lst->items[fd].revents = 0; } else abort(); + uv_mutex_unlock(&global_epoll_lock); return 0; } int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, int maxevents, int timeout) { - size_t size; + nmsgsfds_t size; struct pollfd* pfds; int pollret; int reventcount; + int nevents; - uv_mutex_lock(&global_epoll_lock); - uv_mutex_unlock(&global_epoll_lock); - size = lst->size; + _SET_FDS_MSGS(size, 1, lst->size - 1); pfds = lst->items; pollret = poll(pfds, size, timeout); - if(pollret == -1) + if (pollret <= 0) return pollret; + pollret = _NFDS(pollret) + _NMSGS(pollret); + reventcount = 0; - for (int i = 0; i < lst->size && i < maxevents; ++i) { + nevents = 0; + for (int i = 0; + i < lst->size && i < maxevents && reventcount < pollret; ++i) { struct epoll_event ev; + struct pollfd* pfd; - ev.events = 0; - ev.fd = pfds[i].fd; - if(!pfds[i].revents) + pfd = &pfds[i]; + if (pfd->fd == -1 || pfd->revents == 0) continue; - if(pfds[i].revents & POLLRDNORM) - ev.events = ev.events | POLLIN; - - if(pfds[i].revents & POLLWRNORM) - ev.events = ev.events | POLLOUT; + ev.fd = pfd->fd; + ev.events = pfd->revents; + if (pfd->revents & POLLIN && pfd->revents & POLLOUT) + reventcount += 2; + else if (pfd->revents & (POLLIN | POLLOUT)) + ++reventcount; - if(pfds[i].revents & POLLHUP) - ev.events = ev.events | POLLHUP; - - pfds[i].revents = 0; - events[reventcount++] = ev; + pfd->revents = 0; + events[nevents++] = ev; } - return reventcount; + return nevents; } @@ -235,9 +330,14 @@ int epoll_file_close(int fd) { } void epoll_queue_close(uv__os390_epoll* lst) { + /* Remove epoll instance from global queue */ uv_mutex_lock(&global_epoll_lock); QUEUE_REMOVE(&lst->member); uv_mutex_unlock(&global_epoll_lock); + + /* Free resources */ + msgctl(lst->msg_queue, IPC_RMID, NULL); + lst->msg_queue = -1; uv__free(lst->items); lst->items = NULL; } @@ -332,3 +432,81 @@ char* mkdtemp(char* path) { return path; } + + +ssize_t os390_readlink(const char* path, char* buf, size_t len) { + ssize_t rlen; + ssize_t vlen; + ssize_t plen; + char* delimiter; + char old_delim; + char* tmpbuf; + char realpathstr[PATH_MAX + 1]; + + tmpbuf = uv__malloc(len + 1); + if (tmpbuf == NULL) { + errno = ENOMEM; + return -1; + } + + rlen = readlink(path, tmpbuf, len); + if (rlen < 0) { + uv__free(tmpbuf); + return rlen; + } + + if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) { + /* Straightforward readlink. */ + memcpy(buf, tmpbuf, rlen); + uv__free(tmpbuf); + return rlen; + } + + /* + * There is a parmlib variable at the beginning + * which needs interpretation. + */ + tmpbuf[rlen] = '\0'; + delimiter = strchr(tmpbuf + 2, '/'); + if (delimiter == NULL) + /* No slash at the end */ + delimiter = strchr(tmpbuf + 2, '\0'); + + /* Read real path of the variable. */ + old_delim = *delimiter; + *delimiter = '\0'; + if (realpath(tmpbuf, realpathstr) == NULL) { + uv__free(tmpbuf); + return -1; + } + + /* realpathstr is not guaranteed to end with null byte.*/ + realpathstr[PATH_MAX] = '\0'; + + /* Reset the delimiter and fill up the buffer. */ + *delimiter = old_delim; + plen = strlen(delimiter); + vlen = strlen(realpathstr); + rlen = plen + vlen; + if (rlen > len) { + uv__free(tmpbuf); + errno = ENAMETOOLONG; + return -1; + } + memcpy(buf, realpathstr, vlen); + memcpy(buf + vlen, delimiter, plen); + + /* Done using temporary buffer. */ + uv__free(tmpbuf); + + return rlen; +} + + +size_t strnlen(const char* str, size_t maxlen) { + char* p = memchr(str, 0, maxlen); + if (p == NULL) + return maxlen; + else + return p - str; +} diff --git a/Utilities/cmlibuv/src/unix/os390-syscalls.h b/Utilities/cmlibuv/src/unix/os390-syscalls.h index 61a7cee83..ea599107b 100644 --- a/Utilities/cmlibuv/src/unix/os390-syscalls.h +++ b/Utilities/cmlibuv/src/unix/os390-syscalls.h @@ -36,10 +36,6 @@ #define MAX_ITEMS_PER_EPOLL 1024 #define UV__O_CLOEXEC 0x80000 -#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC -#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD -#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL -#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD struct epoll_event { int events; @@ -50,6 +46,7 @@ typedef struct { QUEUE member; struct pollfd* items; unsigned long size; + int msg_queue; } uv__os390_epoll; /* epoll api */ @@ -65,5 +62,7 @@ int scandir(const char* maindir, struct dirent*** namelist, int (*compar)(const struct dirent **, const struct dirent **)); char *mkdtemp(char* path); +ssize_t os390_readlink(const char* path, char* buf, size_t len); +size_t strnlen(const char* str, size_t maxlen); #endif /* UV_OS390_SYSCALL_H_ */ diff --git a/Utilities/cmlibuv/src/unix/os390.c b/Utilities/cmlibuv/src/unix/os390.c index 2ba5abf35..273ded7ca 100644 --- a/Utilities/cmlibuv/src/unix/os390.c +++ b/Utilities/cmlibuv/src/unix/os390.c @@ -25,6 +25,9 @@ #include <utmpx.h> #include <unistd.h> #include <sys/ps.h> +#include <builtins.h> +#include <termios.h> +#include <sys/msg.h> #if defined(__clang__) #include "csrsic.h" #else @@ -32,6 +35,7 @@ #endif #define CVT_PTR 0x10 +#define PSA_PTR 0x00 #define CSD_OFFSET 0x294 /* @@ -69,6 +73,18 @@ /* CPC model length from the CSRSI Service. */ #define CPCMODEL_LENGTH 16 +/* Pointer to the home (current) ASCB. */ +#define PSAAOLD 0x224 + +/* Pointer to rsm address space block extension. */ +#define ASCBRSME 0x16C + +/* + NUMBER OF FRAMES CURRENTLY IN USE BY THIS ADDRESS SPACE. + It does not include 2G frames. +*/ +#define RAXFMCT 0x2C + /* Thread Entry constants */ #define PGTH_CURRENT 1 #define PGTH_LEN 26 @@ -76,6 +92,9 @@ #pragma linkage(BPX4GTH, OS) #pragma linkage(BPX1GTH, OS) +/* TOD Clock resolution in nanoseconds */ +#define TOD_RES 4.096 + typedef unsigned data_area_ptr_assign_type; typedef union { @@ -100,10 +119,10 @@ void uv_loadavg(double avg[3]) { int uv__platform_loop_init(uv_loop_t* loop) { uv__os390_epoll* ep; - ep = epoll_create1(UV__EPOLL_CLOEXEC); + ep = epoll_create1(0); loop->ep = ep; if (ep == NULL) - return -errno; + return UV__ERR(errno); return 0; } @@ -118,9 +137,10 @@ void uv__platform_loop_delete(uv_loop_t* loop) { uint64_t uv__hrtime(uv_clocktype_t type) { - struct timeval time; - gettimeofday(&time, NULL); - return (uint64_t) time.tv_sec * 1e9 + time.tv_usec * 1e3; + unsigned long long timestamp; + __stckf(×tamp); + /* Convert to nanoseconds */ + return timestamp / TOD_RES; } @@ -209,15 +229,15 @@ static int getexe(const int pid, char* buf, size_t len) { assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A'); /* Get the offset from the lowest 3 bytes */ - Output_path = (char*)(&Output_buf) + - (Output_buf.Output_data.offsetPath & 0x00FFFFFF); + Output_path = (struct Output_path_type*) ((char*) (&Output_buf) + + (Output_buf.Output_data.offsetPath & 0x00FFFFFF)); if (Output_path->len >= len) { errno = ENOBUFS; return -1; } - strncpy(buf, Output_path->path, len); + uv__strscpy(buf, Output_path->path, len); return 0; } @@ -239,12 +259,12 @@ int uv_exepath(char* buffer, size_t* size) { int pid; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; pid = getpid(); res = getexe(pid, args, sizeof(args)); if (res < 0) - return -EINVAL; + return UV_EINVAL; /* * Possibilities for args: @@ -257,7 +277,7 @@ int uv_exepath(char* buffer, size_t* size) { /* Case i) and ii) absolute or relative paths */ if (strchr(args, '/') != NULL) { if (realpath(args, abspath) != abspath) - return -errno; + return UV__ERR(errno); abspath_size = strlen(abspath); @@ -277,11 +297,11 @@ int uv_exepath(char* buffer, size_t* size) { char* path = getenv("PATH"); if (path == NULL) - return -EINVAL; + return UV_EINVAL; clonedpath = uv__strdup(path); if (clonedpath == NULL) - return -ENOMEM; + return UV_ENOMEM; token = strtok(clonedpath, ":"); while (token != NULL) { @@ -307,7 +327,7 @@ int uv_exepath(char* buffer, size_t* size) { uv__free(clonedpath); /* Out of tokens (path entries), and no match found */ - return -EINVAL; + return UV_EINVAL; } } @@ -336,14 +356,21 @@ uint64_t uv_get_total_memory(void) { } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + int uv_resident_set_memory(size_t* rss) { - W_PSPROC buf; + char* ascb; + char* rax; + size_t nframes; - memset(&buf, 0, sizeof(buf)); - if (w_getpsent(0, &buf, sizeof(W_PSPROC)) == -1) - return -EINVAL; + ascb = *(char* __ptr32 *)(PSA_PTR + PSAAOLD); + rax = *(char* __ptr32 *)(ascb + ASCBRSME); + nframes = *(unsigned int*)(rax + RAXFMCT); - *rss = buf.ps_size; + *rss = nframes * sysconf(_SC_PAGESIZE); return 0; } @@ -364,7 +391,6 @@ int uv_uptime(double* uptime) { int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { uv_cpu_info_t* cpu_info; - int result; int idx; siv1v2 info; data_area_ptr cvt = {0}; @@ -384,7 +410,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { *cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t)); if (!*cpu_infos) - return -ENOMEM; + return UV_ENOMEM; cpu_info = *cpu_infos; idx = 0; @@ -429,7 +455,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, maxsize = 16384; if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) - return -errno; + return UV__ERR(errno); ifc.__nif6h_version = 1; ifc.__nif6h_buflen = maxsize; @@ -437,7 +463,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) { uv__close(sockfd); - return -errno; + return UV__ERR(errno); } @@ -461,7 +487,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); if (!(*addresses)) { uv__close(sockfd); - return -ENOMEM; + return UV_ENOMEM; } address = *addresses; @@ -489,7 +515,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0; - + memset(address->phys_addr, 0, sizeof(address->phys_addr)); address++; } @@ -508,25 +534,27 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifreq* p; int count_v6; + *count = 0; + *addresses = NULL; + /* get the ipv6 addresses first */ uv_interface_address_t* addresses_v6; uv__interface_addresses_v6(&addresses_v6, &count_v6); /* now get the ipv4 addresses */ - *count = 0; /* Assume maximum buffer size allowable */ maxsize = 16384; sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (0 > sockfd) - return -errno; + return UV__ERR(errno); ifc.ifc_req = uv__calloc(1, maxsize); ifc.ifc_len = maxsize; if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { uv__close(sockfd); - return -errno; + return UV__ERR(errno); } #define MAX(a,b) (((a)>(b))?(a):(b)) @@ -546,7 +574,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { uv__close(sockfd); - return -errno; + return UV__ERR(errno); } if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) @@ -555,13 +583,18 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { (*count)++; } + if (*count == 0) { + uv__close(sockfd); + return 0; + } + /* Alloc the return interface structs */ *addresses = uv__malloc((*count + count_v6) * sizeof(uv_interface_address_t)); if (!(*addresses)) { uv__close(sockfd); - return -ENOMEM; + return UV_ENOMEM; } address = *addresses; @@ -584,7 +617,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { uv__close(sockfd); - return -ENOSYS; + return UV_ENOSYS; } if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING)) @@ -601,6 +634,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; + memset(address->phys_addr, 0, sizeof(address->phys_addr)); address++; } @@ -628,6 +662,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { uintptr_t nfds; assert(loop->watchers != NULL); + assert(fd >= 0); events = (struct epoll_event*) loop->watchers[loop->nwatchers]; nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; @@ -639,7 +674,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { /* Remove the file descriptor from the epoll. */ if (loop->ep != NULL) - epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy); + epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, &dummy); } @@ -663,11 +698,124 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { return 0; } + +void uv__fs_event_close(uv_fs_event_t* handle) { + uv_fs_event_stop(handle); +} + + +int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { + uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + return 0; +} + + +int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, + const char* filename, unsigned int flags) { + uv__os390_epoll* ep; + _RFIS reg_struct; + char* path; + int rc; + + if (uv__is_active(handle)) + return UV_EINVAL; + + ep = handle->loop->ep; + assert(ep->msg_queue != -1); + + reg_struct.__rfis_cmd = _RFIS_REG; + reg_struct.__rfis_qid = ep->msg_queue; + reg_struct.__rfis_type = 1; + memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle)); + + path = uv__strdup(filename); + if (path == NULL) + return UV_ENOMEM; + + rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); + if (rc != 0) + return UV__ERR(errno); + + uv__handle_start(handle); + handle->path = path; + handle->cb = cb; + memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok, + sizeof(handle->rfis_rftok)); + + return 0; +} + + +int uv_fs_event_stop(uv_fs_event_t* handle) { + uv__os390_epoll* ep; + _RFIS reg_struct; + int rc; + + if (!uv__is_active(handle)) + return 0; + + ep = handle->loop->ep; + assert(ep->msg_queue != -1); + + reg_struct.__rfis_cmd = _RFIS_UNREG; + reg_struct.__rfis_qid = ep->msg_queue; + reg_struct.__rfis_type = 1; + memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok, + sizeof(handle->rfis_rftok)); + + /* + * This call will take "/" as the path argument in case we + * don't care to supply the correct path. The system will simply + * ignore it. + */ + rc = __w_pioctl("/", _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct); + if (rc != 0 && errno != EALREADY && errno != ENOENT) + abort(); + + uv__handle_stop(handle); + + return 0; +} + + +static int os390_message_queue_handler(uv__os390_epoll* ep) { + uv_fs_event_t* handle; + int msglen; + int events; + _RFIM msg; + + if (ep->msg_queue == -1) + return 0; + + msglen = msgrcv(ep->msg_queue, &msg, sizeof(msg), 0, IPC_NOWAIT); + + if (msglen == -1 && errno == ENOMSG) + return 0; + + if (msglen == -1) + abort(); + + events = 0; + if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE) + events = UV_CHANGE; + else if (msg.__rfim_event == _RFIM_RENAME) + events = UV_RENAME; + else + /* Some event that we are not interested in. */ + return 0; + + handle = *(uv_fs_event_t**)(msg.__rfim_utok); + handle->cb(handle, uv__basename_r(handle->path), events, 0); + return 1; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { static const int max_safe_timeout = 1789569; struct epoll_event events[1024]; struct epoll_event* pe; struct epoll_event e; + uv__os390_epoll* ep; int real_timeout; QUEUE* q; uv__io_t* w; @@ -702,9 +850,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { e.fd = w->fd; if (w->events == 0) - op = UV__EPOLL_CTL_ADD; + op = EPOLL_CTL_ADD; else - op = UV__EPOLL_CTL_MOD; + op = EPOLL_CTL_MOD; /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching * events, skip the syscall and squelch the events after epoll_wait(). @@ -713,10 +861,10 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (errno != EEXIST) abort(); - assert(op == UV__EPOLL_CTL_ADD); + assert(op == EPOLL_CTL_ADD); /* We've reactivated a file descriptor that's been watched before. */ - if (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e)) + if (epoll_ctl(loop->ep, EPOLL_CTL_MOD, w->fd, &e)) abort(); } @@ -745,9 +893,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { SAVE_ERRNO(uv__update_time(loop)); if (nfds == 0) { assert(timeout != -1); - timeout = real_timeout - timeout; - if (timeout > 0) + + if (timeout > 0) { + timeout = real_timeout - timeout; continue; + } return; } @@ -779,6 +929,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (fd == -1) continue; + ep = loop->ep; + if (fd == ep->msg_queue) { + os390_message_queue_handler(ep); + continue; + } + assert(fd >= 0); assert((unsigned) fd < loop->nwatchers); @@ -790,7 +946,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * Ignore all errors because we may be racing with another thread * when the file descriptor is closed. */ - epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, pe); + epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, pe); continue; } @@ -843,7 +999,12 @@ void uv__set_process_title(const char* title) { } int uv__io_fork(uv_loop_t* loop) { - uv__platform_loop_delete(loop); + /* + Nullify the msg queue but don't close it because + it is still being used by the parent. + */ + loop->ep = NULL; + uv__platform_loop_delete(loop); return uv__platform_loop_init(loop); } diff --git a/Utilities/cmlibuv/src/unix/pipe.c b/Utilities/cmlibuv/src/unix/pipe.c index 7ba1bf879..7d97550ae 100644 --- a/Utilities/cmlibuv/src/unix/pipe.c +++ b/Utilities/cmlibuv/src/unix/pipe.c @@ -48,12 +48,12 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { /* Already bound? */ if (uv__stream_fd(handle) >= 0) - return -EINVAL; + return UV_EINVAL; /* Make a copy of the file name, it outlives this function's scope. */ pipe_fname = uv__strdup(name); if (pipe_fname == NULL) - return -ENOMEM; + return UV_ENOMEM; /* We've got a copy, don't touch the original any more. */ name = NULL; @@ -64,15 +64,14 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { sockfd = err; memset(&saddr, 0, sizeof saddr); - strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1); - saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0'; + uv__strscpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path)); saddr.sun_family = AF_UNIX; if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { - err = -errno; + err = UV__ERR(errno); /* Convert ENOENT to EACCES for compatibility with Windows. */ - if (err == -ENOENT) - err = -EACCES; + if (err == UV_ENOENT) + err = UV_EACCES; uv__close(sockfd); goto err_socket; @@ -92,7 +91,7 @@ err_socket: int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { if (uv__stream_fd(handle) == -1) - return -EINVAL; + return UV_EINVAL; #if defined(__MVS__) /* On zOS, backlog=0 has undefined behaviour */ @@ -103,7 +102,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { #endif if (listen(uv__stream_fd(handle), backlog)) - return -errno; + return UV__ERR(errno); handle->connection_cb = cb; handle->io_watcher.cb = uv__server_io; @@ -130,21 +129,38 @@ void uv__pipe_close(uv_pipe_t* handle) { int uv_pipe_open(uv_pipe_t* handle, uv_file fd) { + int flags; + int mode; int err; + flags = 0; + + if (uv__fd_exists(handle->loop, fd)) + return UV_EEXIST; + + do + mode = fcntl(fd, F_GETFL); + while (mode == -1 && errno == EINTR); + + if (mode == -1) + return UV__ERR(errno); /* according to docs, must be EBADF */ err = uv__nonblock(fd, 1); if (err) return err; -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(CMAKE_BOOTSTRAP) err = uv__stream_try_select((uv_stream_t*) handle, &fd); if (err) return err; #endif /* defined(__APPLE__) */ - return uv__stream_open((uv_stream_t*)handle, - fd, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + mode &= O_ACCMODE; + if (mode != O_WRONLY) + flags |= UV_HANDLE_READABLE; + if (mode != O_RDONLY) + flags |= UV_HANDLE_WRITABLE; + + return uv__stream_open((uv_stream_t*)handle, fd, flags); } @@ -167,8 +183,7 @@ void uv_pipe_connect(uv_connect_t* req, } memset(&saddr, 0, sizeof saddr); - strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1); - saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0'; + uv__strscpy(saddr.sun_path, name, sizeof(saddr.sun_path)); saddr.sun_family = AF_UNIX; do { @@ -178,14 +193,14 @@ void uv_pipe_connect(uv_connect_t* req, while (r == -1 && errno == EINTR); if (r == -1 && errno != EINPROGRESS) { - err = -errno; + err = UV__ERR(errno); #if defined(__CYGWIN__) || defined(__MSYS__) /* EBADF is supposed to mean that the socket fd is bad, but Cygwin reports EBADF instead of ENOTSOCK when the file is not a socket. We do not expect to see a bad fd here (e.g. due to new_sock), so translate the error. */ - if (err == -EBADF) - err = -ENOTSOCK; + if (err == UV_EBADF) + err = UV_ENOTSOCK; #endif goto out; } @@ -194,11 +209,11 @@ void uv_pipe_connect(uv_connect_t* req, if (new_sock) { err = uv__stream_open((uv_stream_t*)handle, uv__stream_fd(handle), - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); } if (err == 0) - uv__io_start(handle->loop, &handle->io_watcher, POLLIN | POLLOUT); + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); out: handle->delayed_error = err; @@ -216,9 +231,6 @@ out: } -typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*); - - static int uv__pipe_getsockpeername(const uv_pipe_t* handle, uv__peersockfunc func, char* buffer, @@ -229,10 +241,13 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, addrlen = sizeof(sa); memset(&sa, 0, addrlen); - err = func(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen); + err = uv__getsockpeername((const uv_handle_t*) handle, + func, + (struct sockaddr*) &sa, + (int*) &addrlen); if (err < 0) { *size = 0; - return -errno; + return err; } #if defined(__linux__) @@ -300,3 +315,61 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { else return uv__handle_type(handle->accepted_fd); } + + +int uv_pipe_chmod(uv_pipe_t* handle, int mode) { + unsigned desired_mode; + struct stat pipe_stat; + char* name_buffer; + size_t name_len; + int r; + + if (handle == NULL || uv__stream_fd(handle) == -1) + return UV_EBADF; + + if (mode != UV_READABLE && + mode != UV_WRITABLE && + mode != (UV_WRITABLE | UV_READABLE)) + return UV_EINVAL; + + /* Unfortunately fchmod does not work on all platforms, we will use chmod. */ + name_len = 0; + r = uv_pipe_getsockname(handle, NULL, &name_len); + if (r != UV_ENOBUFS) + return r; + + name_buffer = uv__malloc(name_len); + if (name_buffer == NULL) + return UV_ENOMEM; + + r = uv_pipe_getsockname(handle, name_buffer, &name_len); + if (r != 0) { + uv__free(name_buffer); + return r; + } + + /* stat must be used as fstat has a bug on Darwin */ + if (stat(name_buffer, &pipe_stat) == -1) { + uv__free(name_buffer); + return -errno; + } + + desired_mode = 0; + if (mode & UV_READABLE) + desired_mode |= S_IRUSR | S_IRGRP | S_IROTH; + if (mode & UV_WRITABLE) + desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH; + + /* Exit early if pipe already has desired mode. */ + if ((pipe_stat.st_mode & desired_mode) == desired_mode) { + uv__free(name_buffer); + return 0; + } + + pipe_stat.st_mode |= desired_mode; + + r = chmod(name_buffer, pipe_stat.st_mode); + uv__free(name_buffer); + + return r != -1 ? 0 : UV__ERR(errno); +} diff --git a/Utilities/cmlibuv/src/unix/poll.c b/Utilities/cmlibuv/src/unix/poll.c index 370994bd5..3d5022b22 100644 --- a/Utilities/cmlibuv/src/unix/poll.c +++ b/Utilities/cmlibuv/src/unix/poll.c @@ -33,16 +33,29 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { handle = container_of(w, uv_poll_t, io_watcher); - if (events & POLLERR) { - uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); + /* + * As documented in the kernel source fs/kernfs/file.c #780 + * poll will return POLLERR|POLLPRI in case of sysfs + * polling. This does not happen in case of out-of-band + * TCP messages. + * + * The above is the case on (at least) FreeBSD and Linux. + * + * So to properly determine a POLLPRI or a POLLERR we need + * to check for both. + */ + if ((events & POLLERR) && !(events & UV__POLLPRI)) { + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); uv__handle_stop(handle); - handle->poll_cb(handle, -EBADF, 0); + handle->poll_cb(handle, UV_EBADF, 0); return; } pevents = 0; if (events & POLLIN) pevents |= UV_READABLE; + if (events & UV__POLLPRI) + pevents |= UV_PRIORITIZED; if (events & POLLOUT) pevents |= UV_WRITABLE; if (events & UV__POLLRDHUP) @@ -55,6 +68,9 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { int err; + if (uv__fd_exists(loop, fd)) + return UV_EEXIST; + err = uv__io_check_fd(loop, fd); if (err) return err; @@ -63,7 +79,7 @@ int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { * Workaround for e.g. kqueue fds not supporting ioctls. */ err = uv__nonblock(fd, 1); - if (err == -ENOTTY) + if (err == UV_ENOTTY) if (uv__nonblock == uv__nonblock_ioctl) err = uv__nonblock_fcntl(fd, 1); @@ -86,8 +102,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, static void uv__poll_stop(uv_poll_t* handle) { uv__io_stop(handle->loop, &handle->io_watcher, - POLLIN | POLLOUT | UV__POLLRDHUP); + POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); uv__handle_stop(handle); + uv__platform_invalidate_fd(handle->loop, handle->io_watcher.fd); } @@ -101,7 +118,8 @@ int uv_poll_stop(uv_poll_t* handle) { int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { int events; - assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); + assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT | + UV_PRIORITIZED)) == 0); assert(!uv__is_closing(handle)); uv__poll_stop(handle); @@ -112,6 +130,8 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { events = 0; if (pevents & UV_READABLE) events |= POLLIN; + if (pevents & UV_PRIORITIZED) + events |= UV__POLLPRI; if (pevents & UV_WRITABLE) events |= POLLOUT; if (pevents & UV_DISCONNECT) diff --git a/Utilities/cmlibuv/src/unix/posix-hrtime.c b/Utilities/cmlibuv/src/unix/posix-hrtime.c index 323dfc203..870b45c76 100644 --- a/Utilities/cmlibuv/src/unix/posix-hrtime.c +++ b/Utilities/cmlibuv/src/unix/posix-hrtime.c @@ -22,6 +22,43 @@ #include "uv.h" #include "internal.h" +#if defined(__APPLE__) +/* Special case for CMake bootstrap: no clock_gettime on macOS < 10.12 */ + +#ifndef CMAKE_BOOTSTRAP +#error "This code path meant only for use during CMake bootstrap." +#endif + +#include <mach/mach.h> +#include <mach/mach_time.h> + +uint64_t uv__hrtime(uv_clocktype_t type) { + static mach_timebase_info_data_t info; + + if ((ACCESS_ONCE(uint32_t, info.numer) == 0 || + ACCESS_ONCE(uint32_t, info.denom) == 0) && + mach_timebase_info(&info) != KERN_SUCCESS) + abort(); + + return mach_absolute_time() * info.numer / info.denom; +} + +#elif defined(__hpux) +/* Special case for CMake bootstrap: no CLOCK_MONOTONIC on HP-UX */ + +#ifndef CMAKE_BOOTSTRAP +#error "This code path meant only for use during CMake bootstrap." +#endif + +#include <stdint.h> +#include <time.h> + +uint64_t uv__hrtime(uv_clocktype_t type) { + return (uint64_t) gethrtime(); +} + +#else + #include <stdint.h> #include <time.h> @@ -33,3 +70,5 @@ uint64_t uv__hrtime(uv_clocktype_t type) { clock_gettime(CLOCK_MONOTONIC, &ts); return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); } + +#endif diff --git a/Utilities/cmlibuv/src/unix/posix-poll.c b/Utilities/cmlibuv/src/unix/posix-poll.c index 3fba96e1b..a3b9f2196 100644 --- a/Utilities/cmlibuv/src/unix/posix-poll.c +++ b/Utilities/cmlibuv/src/unix/posix-poll.c @@ -107,7 +107,7 @@ static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) { 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) { + for (i = 0; i < loop->poll_fds_used;) { if (loop->poll_fds[i].fd == fd) { /* swap to last position and remove */ --loop->poll_fds_used; @@ -115,7 +115,17 @@ static void uv__pollfds_del(uv_loop_t* loop, int fd) { 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; + /* This method is called with an fd of -1 to purge the invalidated fds, + * so we may possibly have multiples to remove. + */ + if (-1 != fd) + return; + } else { + /* We must only increment the loop counter when the fds do not match. + * Otherwise, when we are purging an invalidated fd, the value just + * swapped here from the previous end of the array will be skipped. + */ + ++i; } } } @@ -288,6 +298,8 @@ update_timeout: void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { size_t i; + assert(fd >= 0); + if (loop->poll_fds_iterating) { /* uv__io_poll is currently iterating. Just invalidate fd. */ for (i = 0; i < loop->poll_fds_used; i++) @@ -315,10 +327,10 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { while (rv == -1 && (errno == EINTR || errno == EAGAIN)); if (rv == -1) - return -errno; + return UV__ERR(errno); if (p[0].revents & POLLNVAL) - return -EINVAL; + return UV_EINVAL; return 0; } diff --git a/Utilities/cmlibuv/src/unix/process.c b/Utilities/cmlibuv/src/unix/process.c index f2fe30521..f4826bf62 100644 --- a/Utilities/cmlibuv/src/unix/process.c +++ b/Utilities/cmlibuv/src/unix/process.c @@ -32,6 +32,7 @@ #include <unistd.h> #include <fcntl.h> #include <poll.h> +#include <sched.h> #if defined(__APPLE__) && !TARGET_OS_IPHONE # include <crt_externs.h> @@ -44,6 +45,16 @@ extern char **environ; # include <grp.h> #endif +#ifndef CMAKE_BOOTSTRAP +#if defined(__linux__) +# define uv__cpu_set_t cpu_set_t +#elif defined(__FreeBSD__) +# include <sys/param.h> +# include <sys/cpuset.h> +# include <pthread_np.h> +# define uv__cpu_set_t cpuset_t +#endif +#endif static void uv__chld(uv_signal_t* handle, int signum) { uv_process_t* process; @@ -126,7 +137,7 @@ int uv__make_socketpair(int fds[2], int flags) { * Anything else is a genuine error. */ if (errno != EINVAL) - return -errno; + return UV__ERR(errno); no_cloexec = 1; @@ -134,7 +145,7 @@ skip: #endif if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) - return -errno; + return UV__ERR(errno); uv__cloexec(fds[0], 1); uv__cloexec(fds[1], 1); @@ -159,7 +170,7 @@ int uv__make_pipe(int fds[2], int flags) { return 0; if (errno != ENOSYS) - return -errno; + return UV__ERR(errno); no_pipe2 = 1; @@ -167,7 +178,7 @@ skip: #endif if (pipe(fds)) - return -errno; + return UV__ERR(errno); uv__cloexec(fds[0], 1); uv__cloexec(fds[1], 1); @@ -198,7 +209,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { case UV_CREATE_PIPE: assert(container->data.stream != NULL); if (container->data.stream->type != UV_NAMED_PIPE) - return -EINVAL; + return UV_EINVAL; else return uv__make_socketpair(fds, 0); @@ -210,21 +221,20 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { fd = uv__stream_fd(container->data.stream); if (fd == -1) - return -EINVAL; + return UV_EINVAL; fds[1] = fd; return 0; default: assert(0 && "Unexpected flags"); - return -EINVAL; + return UV_EINVAL; } } static int uv__process_open_stream(uv_stdio_container_t* container, - int pipefds[2], - int writable) { + int pipefds[2]) { int flags; int err; @@ -238,13 +248,11 @@ static int uv__process_open_stream(uv_stdio_container_t* container, pipefds[1] = -1; uv__nonblock(pipefds[0], 1); - if (container->data.stream->type == UV_NAMED_PIPE && - ((uv_pipe_t*)container->data.stream)->ipc) - flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE; - else if (writable) - flags = UV_STREAM_WRITABLE; - else - flags = UV_STREAM_READABLE; + flags = 0; + if (container->flags & UV_WRITABLE_PIPE) + flags |= UV_HANDLE_READABLE; + if (container->flags & UV_READABLE_PIPE) + flags |= UV_HANDLE_WRITABLE; return uv__stream_open(container->data.stream, pipefds[0], flags); } @@ -279,9 +287,20 @@ static void uv__process_child_init(const uv_process_options_t* options, int stdio_count, int (*pipes)[2], int error_fd) { + sigset_t set; int close_fd; int use_fd; + int err; int fd; + int n; +#ifndef CMAKE_BOOTSTRAP +#if defined(__linux__) || defined(__FreeBSD__) + int r; + int i; + int cpumask_size; + uv__cpu_set_t cpuset; +#endif +#endif if (options->flags & UV_PROCESS_DETACHED) setsid(); @@ -296,7 +315,7 @@ static void uv__process_child_init(const uv_process_options_t* options, continue; pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); if (pipes[fd][1] == -1) { - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } } @@ -315,8 +334,8 @@ static void uv__process_child_init(const uv_process_options_t* options, use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); close_fd = use_fd; - if (use_fd == -1) { - uv__write_int(error_fd, -errno); + if (use_fd < 0) { + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } } @@ -328,7 +347,7 @@ static void uv__process_child_init(const uv_process_options_t* options, fd = dup2(use_fd, fd); if (fd == -1) { - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } @@ -347,7 +366,7 @@ static void uv__process_child_init(const uv_process_options_t* options, } if (options->cwd != NULL && chdir(options->cwd)) { - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } @@ -363,21 +382,73 @@ static void uv__process_child_init(const uv_process_options_t* options, } if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) { - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } +#ifndef CMAKE_BOOTSTRAP +#if defined(__linux__) || defined(__FreeBSD__) + if (options->cpumask != NULL) { + cpumask_size = uv_cpumask_size(); + assert(options->cpumask_size >= (size_t)cpumask_size); + + CPU_ZERO(&cpuset); + for (i = 0; i < cpumask_size; ++i) { + if (options->cpumask[i]) { + CPU_SET(i, &cpuset); + } + } + + r = -pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset); + if (r != 0) { + uv__write_int(error_fd, r); + _exit(127); + } + } +#endif +#endif + if (options->env != NULL) { environ = options->env; } + /* Reset signal disposition. Use a hard-coded limit because NSIG + * is not fixed on Linux: it's either 32, 34 or 64, depending on + * whether RT signals are enabled. We are not allowed to touch + * RT signal handlers, glibc uses them internally. + */ + for (n = 1; n < 32; n += 1) { + if (n == SIGKILL || n == SIGSTOP) + continue; /* Can't be changed. */ + +#if defined(__HAIKU__) + if (n == SIGKILLTHR) + continue; /* Can't be changed. */ +#endif + + if (SIG_ERR != signal(n, SIG_DFL)) + continue; + + uv__write_int(error_fd, UV__ERR(errno)); + _exit(127); + } + + /* Reset signal mask. */ + sigemptyset(&set); + err = pthread_sigmask(SIG_SETMASK, &set, NULL); + + if (err != 0) { + uv__write_int(error_fd, UV__ERR(err)); + _exit(127); + } + execvp(options->file, options->args); - uv__write_int(error_fd, -errno); + uv__write_int(error_fd, UV__ERR(errno)); _exit(127); } #endif @@ -388,9 +459,10 @@ int uv_spawn(uv_loop_t* loop, const uv_process_options_t* options) { #if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ - return -ENOSYS; + return UV_ENOSYS; #else int signal_pipe[2] = { -1, -1 }; + int pipes_storage[8][2]; int (*pipes)[2]; int stdio_count; ssize_t r; @@ -400,11 +472,27 @@ int uv_spawn(uv_loop_t* loop, int i; int status; + if (options->cpumask != NULL) { +#ifndef CMAKE_BOOTSTRAP +#if defined(__linux__) || defined(__FreeBSD__) + if (options->cpumask_size < (size_t)uv_cpumask_size()) { + return UV_EINVAL; + } +#else + return UV_ENOTSUP; +#endif +#else + return UV_ENOTSUP; +#endif + } + assert(options->file != NULL); assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID | UV_PROCESS_WINDOWS_HIDE | + UV_PROCESS_WINDOWS_HIDE_CONSOLE | + UV_PROCESS_WINDOWS_HIDE_GUI | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); @@ -414,8 +502,11 @@ int uv_spawn(uv_loop_t* loop, if (stdio_count < 3) stdio_count = 3; - err = -ENOMEM; - pipes = uv__malloc(stdio_count * sizeof(*pipes)); + err = UV_ENOMEM; + pipes = pipes_storage; + if (stdio_count > (int) ARRAY_SIZE(pipes_storage)) + pipes = uv__malloc(stdio_count * sizeof(*pipes)); + if (pipes == NULL) goto error; @@ -461,7 +552,7 @@ int uv_spawn(uv_loop_t* loop, pid = fork(); if (pid == -1) { - err = -errno; + err = UV__ERR(errno); uv_rwlock_wrunlock(&loop->cloexec_lock); uv__close(signal_pipe[0]); uv__close(signal_pipe[1]); @@ -501,7 +592,7 @@ int uv_spawn(uv_loop_t* loop, uv__close_nocheckstdio(signal_pipe[0]); for (i = 0; i < options->stdio_count; i++) { - err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0); + err = uv__process_open_stream(options->stdio + i, pipes[i]); if (err == 0) continue; @@ -520,7 +611,9 @@ int uv_spawn(uv_loop_t* loop, process->pid = pid; process->exit_cb = options->exit_cb; - uv__free(pipes); + if (pipes != pipes_storage) + uv__free(pipes); + return exec_errorno; error: @@ -534,7 +627,9 @@ error: if (pipes[i][1] != -1) uv__close_nocheckstdio(pipes[i][1]); } - uv__free(pipes); + + if (pipes != pipes_storage) + uv__free(pipes); } return err; @@ -549,7 +644,7 @@ int uv_process_kill(uv_process_t* process, int signum) { int uv_kill(int pid, int signum) { if (kill(pid, signum)) - return -errno; + return UV__ERR(errno); else return 0; } diff --git a/Utilities/cmlibuv/src/unix/procfs-exepath.c b/Utilities/cmlibuv/src/unix/procfs-exepath.c index 5fdb61155..00dc021f2 100644 --- a/Utilities/cmlibuv/src/unix/procfs-exepath.c +++ b/Utilities/cmlibuv/src/unix/procfs-exepath.c @@ -29,14 +29,14 @@ int uv_exepath(char* buffer, size_t* size) { ssize_t n; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; n = *size - 1; if (n > 0) n = readlink("/proc/self/exe", buffer, n); if (n == -1) - return -errno; + return UV__ERR(errno); buffer[n] = '\0'; *size = n; diff --git a/Utilities/cmlibuv/src/unix/proctitle.c b/Utilities/cmlibuv/src/unix/proctitle.c index 9160f7eaf..a5ce2030c 100644 --- a/Utilities/cmlibuv/src/unix/proctitle.c +++ b/Utilities/cmlibuv/src/unix/proctitle.c @@ -24,8 +24,11 @@ #include <stdlib.h> #include <string.h> +extern void uv__set_process_title_platform_init(void); extern void uv__set_process_title(const char* title); +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; static void* args_mem; static struct { @@ -34,6 +37,14 @@ static struct { } process_title; +static void init_process_title_mutex_once(void) { + uv_mutex_init(&process_title_mutex); +#ifdef __APPLE__ + uv__set_process_title_platform_init(); +#endif +} + + char** uv_setup_args(int argc, char** argv) { char** new_argv; size_t size; @@ -81,12 +92,16 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { - if (process_title.len == 0) - return 0; + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title.len != 0) { + /* No need to terminate, byte after is always '\0'. */ + strncpy(process_title.str, title, process_title.len); + uv__set_process_title(title); + } - /* No need to terminate, byte after is always '\0'. */ - strncpy(process_title.str, title, process_title.len); - uv__set_process_title(title); + uv_mutex_unlock(&process_title_mutex); return 0; } @@ -94,13 +109,23 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { if (buffer == NULL || size == 0) - return -EINVAL; - else if (size <= process_title.len) - return -ENOBUFS; + return UV_EINVAL; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (size <= process_title.len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + if (process_title.len != 0) + memcpy(buffer, process_title.str, process_title.len + 1); - memcpy(buffer, process_title.str, process_title.len + 1); buffer[process_title.len] = '\0'; + uv_mutex_unlock(&process_title_mutex); + return 0; } diff --git a/Utilities/cmlibuv/src/unix/pthread-barrier.c b/Utilities/cmlibuv/src/unix/pthread-barrier.c deleted file mode 100644 index b6e604d46..000000000 --- a/Utilities/cmlibuv/src/unix/pthread-barrier.c +++ /dev/null @@ -1,121 +0,0 @@ -/* -Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com> - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -#include "uv-common.h" -#include "pthread-barrier.h" - -#include <stdlib.h> -#include <assert.h> - -/* TODO: support barrier_attr */ -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* barrier_attr, - unsigned count) { - int rc; - _uv_barrier* b; - - if (barrier == NULL || count == 0) - return EINVAL; - - if (barrier_attr != NULL) - return ENOTSUP; - - b = uv__malloc(sizeof(*b)); - if (b == NULL) - return ENOMEM; - - b->in = 0; - b->out = 0; - b->threshold = count; - - if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) - goto error2; - if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) - goto error; - - barrier->b = b; - return 0; - -error: - pthread_mutex_destroy(&b->mutex); -error2: - uv__free(b); - return rc; -} - -int pthread_barrier_wait(pthread_barrier_t* barrier) { - int rc; - _uv_barrier* b; - - if (barrier == NULL || barrier->b == NULL) - return EINVAL; - - b = barrier->b; - /* Lock the mutex*/ - if ((rc = pthread_mutex_lock(&b->mutex)) != 0) - return rc; - - /* Increment the count. If this is the first thread to reach the threshold, - wake up waiters, unlock the mutex, then return - PTHREAD_BARRIER_SERIAL_THREAD. */ - if (++b->in == b->threshold) { - b->in = 0; - b->out = b->threshold - 1; - rc = pthread_cond_signal(&b->cond); - assert(rc == 0); - - pthread_mutex_unlock(&b->mutex); - return PTHREAD_BARRIER_SERIAL_THREAD; - } - /* Otherwise, wait for other threads until in is set to 0, - then return 0 to indicate this is not the first thread. */ - do { - if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) - break; - } while (b->in != 0); - - /* mark thread exit */ - b->out--; - pthread_cond_signal(&b->cond); - pthread_mutex_unlock(&b->mutex); - return rc; -} - -int pthread_barrier_destroy(pthread_barrier_t* barrier) { - int rc; - _uv_barrier* b; - - if (barrier == NULL || barrier->b == NULL) - return EINVAL; - - b = barrier->b; - - if ((rc = pthread_mutex_lock(&b->mutex)) != 0) - return rc; - - if (b->in > 0 || b->out > 0) - rc = EBUSY; - - pthread_mutex_unlock(&b->mutex); - - if (rc) - return rc; - - pthread_cond_destroy(&b->cond); - pthread_mutex_destroy(&b->mutex); - uv__free(barrier->b); - barrier->b = NULL; - return 0; -} diff --git a/Utilities/cmlibuv/src/unix/signal.c b/Utilities/cmlibuv/src/unix/signal.c index cb09ead50..01aa55f3f 100644 --- a/Utilities/cmlibuv/src/unix/signal.c +++ b/Utilities/cmlibuv/src/unix/signal.c @@ -28,6 +28,9 @@ #include <string.h> #include <unistd.h> +#ifndef SA_RESTART +# define SA_RESTART 0 +#endif typedef struct { uv_signal_t* handle; @@ -51,8 +54,7 @@ static void uv__signal_unregister_handler(int signum); static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT; static struct uv__signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); -static int uv__signal_lock_pipefd[2]; - +static int uv__signal_lock_pipefd[2] = { -1, -1 }; RB_GENERATE_STATIC(uv__signal_tree_s, uv_signal_s, tree_entry, @@ -61,7 +63,7 @@ RB_GENERATE_STATIC(uv__signal_tree_s, static void uv__signal_global_reinit(void); static void uv__signal_global_init(void) { - if (!uv__signal_lock_pipefd[0]) + if (uv__signal_lock_pipefd[0] == -1) /* 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 @@ -71,15 +73,11 @@ static void uv__signal_global_init(void) { if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit)) abort(); - if (uv__make_pipe(uv__signal_lock_pipefd, 0)) - abort(); - - if (uv__signal_unlock()) - abort(); + uv__signal_global_reinit(); } -static void uv__signal_global_reinit(void) { +UV_DESTRUCTOR(static void uv__signal_global_fini(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 @@ -87,11 +85,26 @@ static void uv__signal_global_reinit(void) { * 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(); + if (uv__signal_lock_pipefd[0] != -1) { + uv__close(uv__signal_lock_pipefd[0]); + uv__signal_lock_pipefd[0] = -1; + } + + if (uv__signal_lock_pipefd[1] != -1) { + uv__close(uv__signal_lock_pipefd[1]); + uv__signal_lock_pipefd[1] = -1; + } +} + + +static void uv__signal_global_reinit(void) { + uv__signal_global_fini(); + + if (uv__make_pipe(uv__signal_lock_pipefd, 0)) + abort(); + + if (uv__signal_unlock()) + abort(); } @@ -100,7 +113,6 @@ void uv__signal_global_once_init(void) { } - static int uv__signal_lock(void) { int r; char data; @@ -216,11 +228,13 @@ static int uv__signal_register_handler(int signum, int oneshot) { if (sigfillset(&sa.sa_mask)) abort(); sa.sa_handler = uv__signal_handler; - sa.sa_flags = oneshot ? SA_RESETHAND : 0; + sa.sa_flags = SA_RESTART; + if (oneshot) + sa.sa_flags |= SA_RESETHAND; /* XXX save old action so we can restore it later on? */ if (sigaction(signum, &sa, NULL)) - return -errno; + return UV__ERR(errno); return 0; } @@ -357,7 +371,7 @@ static int uv__signal_start(uv_signal_t* handle, * eventually. */ if (signum == 0) - return -EINVAL; + return UV_EINVAL; /* Short circuit: if the signal watcher is already watching {signum} don't * go through the process of deregistering and registering the handler. @@ -382,7 +396,7 @@ static int uv__signal_start(uv_signal_t* handle, */ first_handle = uv__signal_first_handle(signum); if (first_handle == NULL || - (!oneshot && (first_handle->flags & UV__SIGNAL_ONE_SHOT))) { + (!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. */ @@ -393,7 +407,7 @@ static int uv__signal_start(uv_signal_t* handle, handle->signum = signum; if (oneshot) - handle->flags |= UV__SIGNAL_ONE_SHOT; + handle->flags |= UV_SIGNAL_ONE_SHOT; RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle); @@ -450,20 +464,20 @@ static void uv__signal_event(uv_loop_t* loop, handle = msg->handle; if (msg->signum == handle->signum) { - assert(!(handle->flags & UV_CLOSING)); + assert(!(handle->flags & UV_HANDLE_CLOSING)); handle->signal_cb(handle, handle->signum); } handle->dispatched_signals++; - if (handle->flags & UV__SIGNAL_ONE_SHOT) + 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. */ - if ((handle->flags & UV_CLOSING) && + if ((handle->flags & UV_HANDLE_CLOSING) && (handle->caught_signals == handle->dispatched_signals)) { uv__make_close_pending((uv_handle_t*) handle); } @@ -491,11 +505,11 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { 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 + /* 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; + f1 = w1->flags & UV_SIGNAL_ONE_SHOT; + f2 = w2->flags & UV_SIGNAL_ONE_SHOT; if (f1 < f2) return -1; if (f1 > f2) return 1; @@ -544,8 +558,8 @@ static void uv__signal_stop(uv_signal_t* handle) { 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; + 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); diff --git a/Utilities/cmlibuv/src/unix/stream.c b/Utilities/cmlibuv/src/unix/stream.c index 7b23d16ec..8121f6464 100644 --- a/Utilities/cmlibuv/src/unix/stream.c +++ b/Utilities/cmlibuv/src/unix/stream.c @@ -58,6 +58,20 @@ struct uv__stream_select_s { fd_set* swrite; size_t swrite_sz; }; + +/* Due to a possible kernel bug at least in OS X 10.10 "Yosemite", + * EPROTOTYPE can be returned while trying to write to a socket that is + * shutting down. If we retry the write, we should get the expected EPIPE + * instead. + */ +# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR || errno == EPROTOTYPE) +# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \ + (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \ + (errno == EMSGSIZE && send_handle != NULL)) +#else +# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR) +# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \ + (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) #endif /* defined(__APPLE__) */ static void uv__stream_connect(uv_stream_t*); @@ -98,7 +112,7 @@ void uv__stream_init(uv_loop_t* loop, loop->emfile_fd = err; } -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(CMAKE_BOOTSTRAP) stream->select = NULL; #endif /* defined(__APPLE_) */ @@ -107,7 +121,7 @@ void uv__stream_init(uv_loop_t* loop, static void uv__stream_osx_interrupt_select(uv_stream_t* stream) { -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(CMAKE_BOOTSTRAP) /* Notify select() thread about state change */ uv__stream_select_t* s; int r; @@ -131,7 +145,7 @@ static void uv__stream_osx_interrupt_select(uv_stream_t* stream) { } -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(CMAKE_BOOTSTRAP) static void uv__stream_osx_select(void* arg) { uv_stream_t* stream; uv__stream_select_t* s; @@ -214,7 +228,7 @@ static void uv__stream_osx_select(void* arg) { uv_sem_wait(&s->async_sem); /* Should be processed at this stage */ - assert((s->events == 0) || (stream->flags & UV_CLOSING)); + assert((s->events == 0) || (stream->flags & UV_HANDLE_CLOSING)); } } } @@ -242,7 +256,7 @@ static void uv__stream_osx_select_cb(uv_async_t* handle) { if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT)) uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT); - if (stream->flags & UV_CLOSING) + if (stream->flags & UV_HANDLE_CLOSING) return; /* NOTE: It is important to do it here, otherwise `select()` might be called @@ -282,7 +296,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { kq = kqueue(); if (kq == -1) { perror("(libuv) kqueue()"); - return -errno; + return UV__ERR(errno); } EV_SET(&filter[0], *fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); @@ -298,7 +312,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { uv__close(kq); if (ret == -1) - return -errno; + return UV__ERR(errno); if (ret == 0 || (events[0].flags & EV_ERROR) == 0 || events[0].data != EINVAL) return 0; @@ -310,7 +324,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { * NOTE: do it ahead of malloc below to allocate enough space for fd_sets */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) - return -errno; + return UV__ERR(errno); max_fd = *fd; if (fds[1] > max_fd) @@ -321,7 +335,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { s = uv__malloc(sizeof(*s) + sread_sz + swrite_sz); if (s == NULL) { - err = -ENOMEM; + err = UV_ENOMEM; goto failed_malloc; } @@ -336,7 +350,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { if (err) goto failed_async_init; - s->async.flags |= UV__HANDLE_INTERNAL; + s->async.flags |= UV_HANDLE_INTERNAL; uv__handle_unref(&s->async); err = uv_sem_init(&s->close_sem, 0); @@ -395,18 +409,20 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { #endif if (!(stream->io_watcher.fd == -1 || stream->io_watcher.fd == fd)) - return -EBUSY; + return UV_EBUSY; assert(fd >= 0); stream->flags |= flags; if (stream->type == UV_TCP) { - if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) - return -errno; + if ((stream->flags & UV_HANDLE_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) + return UV__ERR(errno); /* TODO Use delay the user passed in. */ - if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60)) - return -errno; + if ((stream->flags & UV_HANDLE_TCP_KEEPALIVE) && + uv__tcp_keepalive(fd, 1, 60)) { + return UV__ERR(errno); + } } #if defined(__APPLE__) @@ -414,7 +430,7 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) && errno != ENOTSOCK && errno != EINVAL) { - return -errno; + return UV__ERR(errno); } #endif @@ -441,15 +457,15 @@ void uv__stream_flush_write_queue(uv_stream_t* stream, int error) { void uv__stream_destroy(uv_stream_t* stream) { assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT)); - assert(stream->flags & UV_CLOSED); + assert(stream->flags & UV_HANDLE_CLOSED); if (stream->connect_req) { uv__req_unregister(stream->loop, stream->connect_req); - stream->connect_req->cb(stream->connect_req, -ECANCELED); + stream->connect_req->cb(stream->connect_req, UV_ECANCELED); stream->connect_req = NULL; } - uv__stream_flush_write_queue(stream, -ECANCELED); + uv__stream_flush_write_queue(stream, UV_ECANCELED); uv__write_callbacks(stream); if (stream->shutdown_req) { @@ -459,7 +475,7 @@ void uv__stream_destroy(uv_stream_t* stream) { * callee that the handle has been destroyed. */ uv__req_unregister(stream->loop, stream->shutdown_req); - stream->shutdown_req->cb(stream->shutdown_req, -ECANCELED); + stream->shutdown_req->cb(stream->shutdown_req, UV_ECANCELED); stream->shutdown_req = NULL; } @@ -483,7 +499,7 @@ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) { int emfile_fd; if (loop->emfile_fd == -1) - return -EMFILE; + return UV_EMFILE; uv__close(loop->emfile_fd); loop->emfile_fd = -1; @@ -492,7 +508,7 @@ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) { err = uv__accept(accept_fd); if (err >= 0) uv__close(err); - } while (err >= 0 || err == -EINTR); + } while (err >= 0 || err == UV_EINTR); emfile_fd = uv__open_cloexec("/", O_RDONLY); if (emfile_fd >= 0) @@ -514,9 +530,9 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int err; stream = container_of(w, uv_stream_t, io_watcher); - assert(events == POLLIN); + assert(events & POLLIN); assert(stream->accepted_fd == -1); - assert(!(stream->flags & UV_CLOSING)); + assert(!(stream->flags & UV_HANDLE_CLOSING)); uv__io_start(stream->loop, &stream->io_watcher, POLLIN); @@ -533,15 +549,15 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { err = uv__accept(uv__stream_fd(stream)); if (err < 0) { - if (err == -EAGAIN || err == -EWOULDBLOCK) + if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK)) return; /* Not an error. */ - if (err == -ECONNABORTED) + if (err == UV_ECONNABORTED) continue; /* Ignore. Nothing we can do about that. */ - if (err == -EMFILE || err == -ENFILE) { + if (err == UV_EMFILE || err == UV_ENFILE) { err = uv__emfile_trick(loop, uv__stream_fd(stream)); - if (err == -EAGAIN || err == -EWOULDBLOCK) + if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK)) break; } @@ -559,7 +575,8 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { return; } - if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) { + if (stream->type == UV_TCP && + (stream->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) { /* Give other processes a chance to accept connections. */ struct timespec timeout = { 0, 1 }; nanosleep(&timeout, NULL); @@ -577,14 +594,14 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { assert(server->loop == client->loop); if (server->accepted_fd == -1) - return -EAGAIN; + return UV_EAGAIN; switch (client->type) { case UV_NAMED_PIPE: case UV_TCP: err = uv__stream_open(client, server->accepted_fd, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); if (err) { /* TODO handle error */ uv__close(server->accepted_fd); @@ -601,7 +618,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { break; default: - return -EINVAL; + return UV_EINVAL; } client->flags |= UV_HANDLE_BOUND; @@ -649,7 +666,7 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { break; default: - err = -EINVAL; + err = UV_EINVAL; } if (err == 0) @@ -668,22 +685,22 @@ static void uv__drain(uv_stream_t* stream) { uv__stream_osx_interrupt_select(stream); /* Shutdown? */ - if ((stream->flags & UV_STREAM_SHUTTING) && - !(stream->flags & UV_CLOSING) && - !(stream->flags & UV_STREAM_SHUT)) { + if ((stream->flags & UV_HANDLE_SHUTTING) && + !(stream->flags & UV_HANDLE_CLOSING) && + !(stream->flags & UV_HANDLE_SHUT)) { assert(stream->shutdown_req); req = stream->shutdown_req; stream->shutdown_req = NULL; - stream->flags &= ~UV_STREAM_SHUTTING; + stream->flags &= ~UV_HANDLE_SHUTTING; uv__req_unregister(stream->loop, req); err = 0; if (shutdown(uv__stream_fd(stream), SHUT_WR)) - err = -errno; + err = UV__ERR(errno); if (err == 0) - stream->flags |= UV_STREAM_SHUT; + stream->flags |= UV_HANDLE_SHUT; if (req->cb != NULL) req->cb(req, err); @@ -691,6 +708,14 @@ static void uv__drain(uv_stream_t* stream) { } +static ssize_t uv__writev(int fd, struct iovec* vec, size_t n) { + if (n == 1) + return write(fd, vec->iov_base, vec->iov_len); + else + return writev(fd, vec, n); +} + + static size_t uv__write_req_size(uv_write_t* req) { size_t size; @@ -703,6 +728,37 @@ static size_t uv__write_req_size(uv_write_t* req) { } +/* Returns 1 if all write request data has been written, or 0 if there is still + * more data to write. + * + * Note: the return value only says something about the *current* request. + * There may still be other write requests sitting in the queue. + */ +static int uv__write_req_update(uv_stream_t* stream, + uv_write_t* req, + size_t n) { + uv_buf_t* buf; + size_t len; + + assert(n <= stream->write_queue_size); + stream->write_queue_size -= n; + + buf = req->bufs + req->write_index; + + do { + len = n < buf->len ? n : buf->len; + buf->base += len; + buf->len -= len; + buf += (buf->len == 0); /* Advance to next buffer if this one is empty. */ + n -= len; + } while (n > 0); + + req->write_index = buf - req->bufs; + + return req->write_index == req->nbufs; +} + + static void uv__write_req_finish(uv_write_t* req) { uv_stream_t* stream = req->handle; @@ -750,6 +806,7 @@ static void uv__write(uv_stream_t* stream) { int iovmax; int iovcnt; ssize_t n; + int err; start: @@ -782,14 +839,21 @@ start: */ if (req->send_handle) { + int fd_to_send; struct msghdr msg; struct cmsghdr *cmsg; - int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); union { char data[64]; struct cmsghdr alias; } scratch; + if (uv__is_closing(req->send_handle)) { + err = UV_EBADF; + goto error; + } + + fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); + memset(&scratch, 0, sizeof(scratch)); assert(fd_to_send >= 0); @@ -815,124 +879,64 @@ start: *pi = fd_to_send; } - do { + do n = sendmsg(uv__stream_fd(stream), &msg, 0); - } -#if defined(__APPLE__) - /* - * Due to a possible kernel bug at least in OS X 10.10 "Yosemite", - * EPROTOTYPE can be returned while trying to write to a socket that is - * shutting down. If we retry the write, we should get the expected EPIPE - * instead. - */ - while (n == -1 && (errno == EINTR || errno == EPROTOTYPE)); -#else - while (n == -1 && errno == EINTR); -#endif - } else { - do { - if (iovcnt == 1) { - n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len); - } else { - n = writev(uv__stream_fd(stream), iov, iovcnt); - } - } -#if defined(__APPLE__) - /* - * Due to a possible kernel bug at least in OS X 10.10 "Yosemite", - * EPROTOTYPE can be returned while trying to write to a socket that is - * shutting down. If we retry the write, we should get the expected EPIPE - * instead. - */ - while (n == -1 && (errno == EINTR || errno == EPROTOTYPE)); -#else - while (n == -1 && errno == EINTR); -#endif - } + while (n == -1 && RETRY_ON_WRITE_ERROR(errno)); - if (n < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - /* Error */ - req->error = -errno; - uv__write_req_finish(req); - uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); - if (!uv__io_active(&stream->io_watcher, POLLIN)) - uv__handle_stop(stream); - uv__stream_osx_interrupt_select(stream); - return; - } else if (stream->flags & UV_STREAM_BLOCKING) { - /* If this is a blocking stream, try again. */ - goto start; - } + /* Ensure the handle isn't sent again in case this is a partial write. */ + if (n >= 0) + req->send_handle = NULL; } else { - /* Successful write */ - - while (n >= 0) { - uv_buf_t* buf = &(req->bufs[req->write_index]); - size_t len = buf->len; - - assert(req->write_index < req->nbufs); - - if ((size_t)n < len) { - buf->base += n; - buf->len -= n; - stream->write_queue_size -= n; - n = 0; - - /* There is more to write. */ - if (stream->flags & UV_STREAM_BLOCKING) { - /* - * If we're blocking then we should not be enabling the write - * watcher - instead we need to try again. - */ - goto start; - } else { - /* Break loop and ensure the watcher is pending. */ - break; - } - - } else { - /* Finished writing the buf at index req->write_index. */ - req->write_index++; - - assert((size_t)n >= len); - n -= len; - - assert(stream->write_queue_size >= len); - stream->write_queue_size -= len; + do + n = uv__writev(uv__stream_fd(stream), iov, iovcnt); + while (n == -1 && RETRY_ON_WRITE_ERROR(errno)); + } - if (req->write_index == req->nbufs) { - /* Then we're done! */ - assert(n == 0); - uv__write_req_finish(req); - /* TODO: start trying to write the next request. */ - return; - } - } - } + if (n == -1 && !IS_TRANSIENT_WRITE_ERROR(errno, req->send_handle)) { + err = UV__ERR(errno); + goto error; } - /* Either we've counted n down to zero or we've got EAGAIN. */ - assert(n == 0 || n == -1); + if (n >= 0 && uv__write_req_update(stream, req, n)) { + uv__write_req_finish(req); + return; /* TODO(bnoordhuis) Start trying to write the next request. */ + } - /* Only non-blocking streams should use the write_watcher. */ - assert(!(stream->flags & UV_STREAM_BLOCKING)); + /* If this is a blocking stream, try again. */ + if (stream->flags & UV_HANDLE_BLOCKING_WRITES) + goto start; /* We're not done. */ uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); /* Notify select() thread about state change */ uv__stream_osx_interrupt_select(stream); + + return; + +error: + req->error = err; + uv__write_req_finish(req); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + if (!uv__io_active(&stream->io_watcher, POLLIN)) + uv__handle_stop(stream); + uv__stream_osx_interrupt_select(stream); } static void uv__write_callbacks(uv_stream_t* stream) { uv_write_t* req; QUEUE* q; + QUEUE pq; + + if (QUEUE_EMPTY(&stream->write_completed_queue)) + return; - while (!QUEUE_EMPTY(&stream->write_completed_queue)) { + QUEUE_MOVE(&stream->write_completed_queue, &pq); + + while (!QUEUE_EMPTY(&pq)) { /* Pop a req off write_completed_queue. */ - q = QUEUE_HEAD(&stream->write_completed_queue); + q = QUEUE_HEAD(&pq); req = QUEUE_DATA(q, uv_write_t, queue); QUEUE_REMOVE(q); uv__req_unregister(stream->loop, req); @@ -948,8 +952,6 @@ static void uv__write_callbacks(uv_stream_t* stream) { if (req->cb) req->cb(req, req->error); } - - assert(QUEUE_EMPTY(&stream->write_completed_queue)); } @@ -997,13 +999,13 @@ uv_handle_type uv__handle_type(int fd) { static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { - stream->flags |= UV_STREAM_READ_EOF; + stream->flags |= UV_HANDLE_READ_EOF; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); stream->read_cb(stream, UV_EOF, buf); - stream->flags &= ~UV_STREAM_READING; + stream->flags &= ~UV_HANDLE_READING; } @@ -1017,7 +1019,7 @@ static int uv__stream_queue_fd(uv_stream_t* stream, int fd) { queued_fds = uv__malloc((queue_size - 1) * sizeof(*queued_fds->fds) + sizeof(*queued_fds)); if (queued_fds == NULL) - return -ENOMEM; + return UV_ENOMEM; queued_fds->size = queue_size; queued_fds->offset = 0; stream->queued_fds = queued_fds; @@ -1034,7 +1036,7 @@ static int uv__stream_queue_fd(uv_stream_t* stream, int fd) { * NOTE: if it is fatal - sockets will be closed in uv__stream_close */ if (queued_fds == NULL) - return -ENOMEM; + return UV_ENOMEM; queued_fds->size = queue_size; stream->queued_fds = queued_fds; } @@ -1103,6 +1105,7 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wgnu-folding-constant" +# pragma clang diagnostic ignored "-Wvla-extension" #endif static void uv__read(uv_stream_t* stream) { @@ -1114,7 +1117,7 @@ static void uv__read(uv_stream_t* stream) { int err; int is_ipc; - stream->flags &= ~UV_STREAM_READ_PARTIAL; + stream->flags &= ~UV_HANDLE_READ_PARTIAL; /* Prevent loop starvation when the data comes in as fast as (or faster than) * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. @@ -1123,11 +1126,11 @@ static void uv__read(uv_stream_t* stream) { is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc; - /* XXX: Maybe instead of having UV_STREAM_READING we just test if + /* XXX: Maybe instead of having UV_HANDLE_READING we just test if * tcp->read_cb is NULL or not? */ while (stream->read_cb - && (stream->flags & UV_STREAM_READING) + && (stream->flags & UV_HANDLE_READING) && (count-- > 0)) { assert(stream->alloc_cb != NULL); @@ -1168,7 +1171,7 @@ static void uv__read(uv_stream_t* stream) { /* Error */ if (errno == EAGAIN || errno == EWOULDBLOCK) { /* Wait for the next one. */ - if (stream->flags & UV_STREAM_READING) { + if (stream->flags & UV_HANDLE_READING) { uv__io_start(stream->loop, &stream->io_watcher, POLLIN); uv__stream_osx_interrupt_select(stream); } @@ -1180,9 +1183,9 @@ static void uv__read(uv_stream_t* stream) { #endif } else { /* Error. User should call uv_close(). */ - stream->read_cb(stream, -errno, &buf); - if (stream->flags & UV_STREAM_READING) { - stream->flags &= ~UV_STREAM_READING; + stream->read_cb(stream, UV__ERR(errno), &buf); + if (stream->flags & UV_HANDLE_READING) { + stream->flags &= ~UV_HANDLE_READING; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); @@ -1232,7 +1235,7 @@ static void uv__read(uv_stream_t* stream) { /* Return if we didn't fill the buffer, there is no more data to read. */ if (nread < buflen) { - stream->flags |= UV_STREAM_READ_PARTIAL; + stream->flags |= UV_HANDLE_READ_PARTIAL; return; } } @@ -1249,14 +1252,15 @@ static void uv__read(uv_stream_t* stream) { int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { - assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) && - "uv_shutdown (unix) only supports uv_handle_t right now"); + assert(stream->type == UV_TCP || + stream->type == UV_TTY || + stream->type == UV_NAMED_PIPE); - if (!(stream->flags & UV_STREAM_WRITABLE) || - stream->flags & UV_STREAM_SHUT || - stream->flags & UV_STREAM_SHUTTING || + if (!(stream->flags & UV_HANDLE_WRITABLE) || + stream->flags & UV_HANDLE_SHUT || + stream->flags & UV_HANDLE_SHUTTING || uv__is_closing(stream)) { - return -ENOTCONN; + return UV_ENOTCONN; } assert(uv__stream_fd(stream) >= 0); @@ -1266,7 +1270,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { req->handle = stream; req->cb = cb; stream->shutdown_req = req; - stream->flags |= UV_STREAM_SHUTTING; + stream->flags |= UV_HANDLE_SHUTTING; uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); @@ -1283,7 +1287,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY); - assert(!(stream->flags & UV_CLOSING)); + assert(!(stream->flags & UV_HANDLE_CLOSING)); if (stream->connect_req) { uv__stream_connect(stream); @@ -1292,7 +1296,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(uv__stream_fd(stream) >= 0); - /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */ + /* Ignore POLLHUP here. Even if it's set, there may still be data to read. */ if (events & (POLLIN | POLLERR | POLLHUP)) uv__read(stream); @@ -1306,9 +1310,9 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { * report the EOF yet because there is still data to read. */ if ((events & POLLHUP) && - (stream->flags & UV_STREAM_READING) && - (stream->flags & UV_STREAM_READ_PARTIAL) && - !(stream->flags & UV_STREAM_READ_EOF)) { + (stream->flags & UV_HANDLE_READING) && + (stream->flags & UV_HANDLE_READ_PARTIAL) && + !(stream->flags & UV_HANDLE_READ_EOF)) { uv_buf_t buf = { NULL, 0 }; uv__stream_eof(stream, &buf); } @@ -1355,10 +1359,10 @@ static void uv__stream_connect(uv_stream_t* stream) { SO_ERROR, &error, &errorsize); - error = -error; + error = UV__ERR(error); } - if (error == -EINPROGRESS) + if (error == UV__ERR(EINPROGRESS)) return; stream->connect_req = NULL; @@ -1375,7 +1379,7 @@ static void uv__stream_connect(uv_stream_t* stream) { return; if (error < 0) { - uv__stream_flush_write_queue(stream, -ECANCELED); + uv__stream_flush_write_queue(stream, UV_ECANCELED); uv__write_callbacks(stream); } } @@ -1396,11 +1400,14 @@ int uv_write2(uv_write_t* req, "uv_write (unix) does not yet support other types of streams"); if (uv__stream_fd(stream) < 0) - return -EBADF; + return UV_EBADF; + + if (!(stream->flags & UV_HANDLE_WRITABLE)) + return -EPIPE; if (send_handle) { if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) - return -EINVAL; + return UV_EINVAL; /* XXX We abuse uv_write2() to send over UDP handles to child processes. * Don't call uv__stream_fd() on those handles, it's a macro that on OS X @@ -1409,12 +1416,12 @@ int uv_write2(uv_write_t* req, * which works but only by accident. */ if (uv__handle_fd((uv_handle_t*) send_handle) < 0) - return -EBADF; + return UV_EBADF; #if defined(__CYGWIN__) || defined(__MSYS__) /* Cygwin recvmsg always sets msg_controllen to zero, so we cannot send it. See https://github.com/mirror/newlib-cygwin/blob/86fc4bf0/winsup/cygwin/fhandler_socket.cc#L1736-L1743 */ - return -ENOSYS; + return UV_ENOSYS; #endif } @@ -1439,7 +1446,7 @@ int uv_write2(uv_write_t* req, req->bufs = uv__malloc(nbufs * sizeof(bufs[0])); if (req->bufs == NULL) - return -ENOMEM; + return UV_ENOMEM; memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); req->nbufs = nbufs; @@ -1465,7 +1472,7 @@ int uv_write2(uv_write_t* req, * if this assert fires then somehow the blocking stream isn't being * sufficiently flushed in uv__write. */ - assert(!(stream->flags & UV_STREAM_BLOCKING)); + assert(!(stream->flags & UV_HANDLE_BLOCKING_WRITES)); uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); } @@ -1503,7 +1510,7 @@ int uv_try_write(uv_stream_t* stream, /* Connecting or already writing some data */ if (stream->connect_req != NULL || stream->write_queue_size != 0) - return -EAGAIN; + return UV_EAGAIN; has_pollout = uv__io_active(&stream->io_watcher, POLLOUT); @@ -1534,7 +1541,7 @@ int uv_try_write(uv_stream_t* stream, } if (written == 0 && req_size != 0) - return -EAGAIN; + return req.error < 0 ? req.error : UV_EAGAIN; else return written; } @@ -1546,13 +1553,16 @@ int uv_read_start(uv_stream_t* stream, assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY); - if (stream->flags & UV_CLOSING) - return -EINVAL; + if (stream->flags & UV_HANDLE_CLOSING) + return UV_EINVAL; - /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just + if (!(stream->flags & UV_HANDLE_READABLE)) + return -ENOTCONN; + + /* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just * expresses the desired state of the user. */ - stream->flags |= UV_STREAM_READING; + stream->flags |= UV_HANDLE_READING; /* TODO: try to do the read inline? */ /* TODO: keep track of tcp state. If we've gotten a EOF then we should @@ -1573,10 +1583,10 @@ int uv_read_start(uv_stream_t* stream, int uv_read_stop(uv_stream_t* stream) { - if (!(stream->flags & UV_STREAM_READING)) + if (!(stream->flags & UV_HANDLE_READING)) return 0; - stream->flags &= ~UV_STREAM_READING; + stream->flags &= ~UV_HANDLE_READING; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); @@ -1589,16 +1599,16 @@ int uv_read_stop(uv_stream_t* stream) { int uv_is_readable(const uv_stream_t* stream) { - return !!(stream->flags & UV_STREAM_READABLE); + return !!(stream->flags & UV_HANDLE_READABLE); } int uv_is_writable(const uv_stream_t* stream) { - return !!(stream->flags & UV_STREAM_WRITABLE); + return !!(stream->flags & UV_HANDLE_WRITABLE); } -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(CMAKE_BOOTSTRAP) int uv___stream_fd(const uv_stream_t* handle) { const uv__stream_select_t* s; @@ -1619,7 +1629,7 @@ void uv__stream_close(uv_stream_t* handle) { unsigned int i; uv__stream_queued_fds_t* queued_fds; -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(CMAKE_BOOTSTRAP) /* Terminate select loop first */ if (handle->select != NULL) { uv__stream_select_t* s; @@ -1643,6 +1653,7 @@ void uv__stream_close(uv_stream_t* handle) { uv__io_close(handle->loop, &handle->io_watcher); uv_read_stop(handle); uv__handle_stop(handle); + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); if (handle->io_watcher.fd != -1) { /* Don't close stdio file descriptors. Nothing good comes from it. */ diff --git a/Utilities/cmlibuv/src/unix/sunos.c b/Utilities/cmlibuv/src/unix/sunos.c index 041f3f336..0cd25c10a 100644 --- a/Utilities/cmlibuv/src/unix/sunos.c +++ b/Utilities/cmlibuv/src/unix/sunos.c @@ -77,7 +77,7 @@ int uv__platform_loop_init(uv_loop_t* loop) { fd = port_create(); if (fd == -1) - return -errno; + return UV__ERR(errno); err = uv__cloexec(fd, 1); if (err) { @@ -121,6 +121,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { uintptr_t nfds; assert(loop->watchers != NULL); + assert(fd >= 0); events = (struct port_event*) loop->watchers[loop->nwatchers]; nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; @@ -136,10 +137,12 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { int uv__io_check_fd(uv_loop_t* loop, int fd) { if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) - return -errno; + return UV__ERR(errno); - if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) + if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) { + perror("(libuv) port_dissociate()"); abort(); + } return 0; } @@ -177,8 +180,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w = QUEUE_DATA(q, uv__io_t, watcher_queue); assert(w->pevents != 0); - if (port_associate(loop->backend_fd, PORT_SOURCE_FD, w->fd, w->pevents, 0)) + if (port_associate(loop->backend_fd, + PORT_SOURCE_FD, + w->fd, + w->pevents, + 0)) { + perror("(libuv) port_associate()"); abort(); + } w->events = w->pevents; } @@ -222,10 +231,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { /* Work around another kernel bug: port_getn() may return events even * on error. */ - if (errno == EINTR || errno == ETIME) + if (errno == EINTR || errno == ETIME) { saved_errno = errno; - else + } else { + perror("(libuv) port_getn()"); abort(); + } } /* Update loop->time unconditionally. It's tempting to skip the update when @@ -346,7 +357,7 @@ int uv_exepath(char* buffer, size_t* size) { char buf[128]; if (buffer == NULL || size == NULL || *size == 0) - return -EINVAL; + return UV_EINVAL; snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid()); @@ -355,7 +366,7 @@ int uv_exepath(char* buffer, size_t* size) { res = readlink(buf, buffer, res); if (res == -1) - return -errno; + return UV__ERR(errno); buffer[res] = '\0'; *size = res; @@ -373,6 +384,11 @@ uint64_t uv_get_total_memory(void) { } +uint64_t uv_get_constrained_memory(void) { + return 0; /* Memory constraints are unknown. */ +} + + void uv_loadavg(double avg[3]) { (void) getloadavg(avg, 3); } @@ -382,14 +398,14 @@ void uv_loadavg(double avg[3]) { static int uv__fs_event_rearm(uv_fs_event_t *handle) { if (handle->fd == -1) - return -EBADF; + return UV_EBADF; if (port_associate(handle->loop->fs_fd, PORT_SOURCE_FILE, (uintptr_t) &handle->fo, FILE_ATTRIB | FILE_MODIFIED, handle) == -1) { - return -errno; + return UV__ERR(errno); } handle->fd = PORT_LOADED; @@ -466,13 +482,13 @@ int uv_fs_event_start(uv_fs_event_t* handle, int err; if (uv__is_active(handle)) - return -EINVAL; + return UV_EINVAL; first_run = 0; if (handle->loop->fs_fd == -1) { portfd = port_create(); if (portfd == -1) - return -errno; + return UV__ERR(errno); handle->loop->fs_fd = portfd; first_run = 1; } @@ -525,7 +541,7 @@ void uv__fs_event_close(uv_fs_event_t* handle) { #else /* !defined(PORT_SOURCE_FILE) */ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { - return -ENOSYS; + return UV_ENOSYS; } @@ -533,12 +549,12 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* filename, unsigned int flags) { - return -ENOSYS; + return UV_ENOSYS; } int uv_fs_event_stop(uv_fs_event_t* handle) { - return -ENOSYS; + return UV_ENOSYS; } @@ -556,10 +572,10 @@ int uv_resident_set_memory(size_t* rss) { fd = open("/proc/self/psinfo", O_RDONLY); if (fd == -1) - return -errno; + return UV__ERR(errno); /* FIXME(bnoordhuis) Handle EINTR. */ - err = -EINVAL; + err = UV_EINVAL; if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) { *rss = (size_t)psinfo.pr_rssize * 1024; err = 0; @@ -579,7 +595,7 @@ int uv_uptime(double* uptime) { kc = kstat_open(); if (kc == NULL) - return -EPERM; + return UV_EPERM; ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc"); if (kstat_read(kc, ksp, NULL) == -1) { @@ -603,7 +619,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { kc = kstat_open(); if (kc == NULL) - return -EPERM; + return UV_EPERM; /* Get count of cpus */ lookup_instance = 0; @@ -614,7 +630,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { *cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos)); if (!(*cpu_infos)) { kstat_close(kc); - return -ENOMEM; + return UV_ENOMEM; } *count = lookup_instance; @@ -696,7 +712,9 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { #ifdef SUNOS_NO_IFADDRS int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { - return -ENOSYS; + *count = 0; + *addresses = NULL; + return UV_ENOSYS; } #else /* SUNOS_NO_IFADDRS */ /* @@ -709,13 +727,14 @@ static int uv__set_phys_addr(uv_interface_address_t* address, struct sockaddr_dl* sa_addr; int sockfd; - int i; + size_t i; struct arpreq arpreq; /* This appears to only work as root */ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); for (i = 0; i < sizeof(address->phys_addr); i++) { + /* Check that all bytes of phys_addr are zero. */ if (address->phys_addr[i] != 0) return 0; } @@ -734,11 +753,11 @@ static int uv__set_phys_addr(uv_interface_address_t* address, sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) - return -errno; + return UV__ERR(errno); if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) { uv__close(sockfd); - return -errno; + return UV__ERR(errno); } memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr)); uv__close(sockfd); @@ -751,7 +770,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent) { return 1; if (ent->ifa_addr == NULL) return 1; - if (ent->ifa_addr->sa_family == PF_PACKET) + if (ent->ifa_addr->sa_family != AF_INET && + ent->ifa_addr->sa_family != AF_INET6) return 1; return 0; } @@ -760,12 +780,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; struct ifaddrs* addrs; struct ifaddrs* ent; - int i; - - if (getifaddrs(&addrs)) - return -errno; *count = 0; + *addresses = NULL; + + if (getifaddrs(&addrs)) + return UV__ERR(errno); /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { @@ -774,10 +794,15 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { (*count)++; } + if (*count == 0) { + freeifaddrs(addrs); + return 0; + } + *addresses = uv__malloc(*count * sizeof(**addresses)); if (!(*addresses)) { freeifaddrs(addrs); - return -ENOMEM; + return UV_ENOMEM; } address = *addresses; diff --git a/Utilities/cmlibuv/src/unix/tcp.c b/Utilities/cmlibuv/src/unix/tcp.c index c423dcb15..8cedcd602 100644 --- a/Utilities/cmlibuv/src/unix/tcp.c +++ b/Utilities/cmlibuv/src/unix/tcp.c @@ -28,15 +28,12 @@ #include <errno.h> -static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) { +static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { + struct sockaddr_storage saddr; + socklen_t slen; int sockfd; int err; - if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) { - handle->flags |= flags; - return 0; - } - err = uv__socket(domain, SOCK_STREAM, 0); if (err < 0) return err; @@ -48,20 +45,82 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) { return err; } + if (flags & UV_HANDLE_BOUND) { + /* Bind this new socket to an arbitrary port */ + slen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) { + uv__close(sockfd); + return UV__ERR(errno); + } + + if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) { + uv__close(sockfd); + return UV__ERR(errno); + } + } + return 0; } +static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { + struct sockaddr_storage saddr; + socklen_t slen; + + if (domain == AF_UNSPEC) { + handle->flags |= flags; + return 0; + } + + if (uv__stream_fd(handle) != -1) { + + if (flags & UV_HANDLE_BOUND) { + + if (handle->flags & UV_HANDLE_BOUND) { + /* It is already bound to a port. */ + handle->flags |= flags; + return 0; + } + + /* Query to see if tcp socket is bound. */ + slen = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) + return UV__ERR(errno); + + if ((saddr.ss_family == AF_INET6 && + ((struct sockaddr_in6*) &saddr)->sin6_port != 0) || + (saddr.ss_family == AF_INET && + ((struct sockaddr_in*) &saddr)->sin_port != 0)) { + /* Handle is already bound to a port. */ + handle->flags |= flags; + return 0; + } + + /* Bind to arbitrary port */ + if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) + return UV__ERR(errno); + } + + handle->flags |= flags; + return 0; + } + + return new_socket(handle, domain, flags); +} + + int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) { int domain; /* Use the lower 8 bits for the domain */ domain = flags & 0xFF; if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) - return -EINVAL; + return UV_EINVAL; if (flags & ~0xFF) - return -EINVAL; + return UV_EINVAL; uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP); @@ -95,18 +154,17 @@ int uv__tcp_bind(uv_tcp_t* tcp, /* Cannot set IPv6-only mode on non-IPv6 socket. */ if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6) - return -EINVAL; + return UV_EINVAL; - err = maybe_new_socket(tcp, - addr->sa_family, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + err = maybe_new_socket(tcp, addr->sa_family, 0); if (err) return err; on = 1; if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) - return -errno; + return UV__ERR(errno); +#ifndef __OpenBSD__ #ifdef IPV6_V6ONLY if (addr->sa_family == AF_INET6) { on = (flags & UV_TCP_IPV6ONLY) != 0; @@ -117,22 +175,23 @@ int uv__tcp_bind(uv_tcp_t* tcp, sizeof on) == -1) { #if defined(__MVS__) if (errno == EOPNOTSUPP) - return -EINVAL; + return UV_EINVAL; #endif - return -errno; + return UV__ERR(errno); } } #endif +#endif errno = 0; if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) { if (errno == EAFNOSUPPORT) /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a * socket created with AF_INET to an AF_INET6 address or vice versa. */ - return -EINVAL; - return -errno; + return UV_EINVAL; + return UV__ERR(errno); } - tcp->delayed_error = -errno; + tcp->delayed_error = UV__ERR(errno); tcp->flags |= UV_HANDLE_BOUND; if (addr->sa_family == AF_INET6) @@ -153,11 +212,11 @@ int uv__tcp_connect(uv_connect_t* req, assert(handle->type == UV_TCP); if (handle->connect_req != NULL) - return -EALREADY; /* FIXME(bnoordhuis) -EINVAL or maybe -EBUSY. */ + return UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */ err = maybe_new_socket(handle, addr->sa_family, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); if (err) return err; @@ -176,14 +235,18 @@ int uv__tcp_connect(uv_connect_t* req, if (r == -1 && errno != 0) { if (errno == EINPROGRESS) ; /* not an error */ - else if (errno == ECONNREFUSED) - /* If we get a ECONNREFUSED wait until the next tick to report the - * error. Solaris wants to report immediately--other unixes want to - * wait. + else if (errno == ECONNREFUSED +#if defined(__OpenBSD__) + || errno == EINVAL +#endif + ) + /* If we get ECONNREFUSED (Solaris) or EINVAL (OpenBSD) wait until the + * next tick to report the error. Solaris and OpenBSD wants to report + * immediately -- other unixes want to wait. */ - handle->delayed_error = -errno; + handle->delayed_error = UV__ERR(ECONNREFUSED); else - return -errno; + return UV__ERR(errno); } uv__req_init(handle->loop, req, UV_CONNECT); @@ -204,62 +267,50 @@ int uv__tcp_connect(uv_connect_t* req, int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { int err; + if (uv__fd_exists(handle->loop, sock)) + return UV_EEXIST; + err = uv__nonblock(sock, 1); if (err) return err; return uv__stream_open((uv_stream_t*)handle, sock, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); } int uv_tcp_getsockname(const uv_tcp_t* handle, struct sockaddr* name, int* namelen) { - socklen_t socklen; if (handle->delayed_error) return handle->delayed_error; - if (uv__stream_fd(handle) < 0) - return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ - - /* sizeof(socklen_t) != sizeof(int) on some systems. */ - socklen = (socklen_t) *namelen; - - if (getsockname(uv__stream_fd(handle), name, &socklen)) - return -errno; - - *namelen = (int) socklen; - return 0; + return uv__getsockpeername((const uv_handle_t*) handle, + getsockname, + name, + namelen); } int uv_tcp_getpeername(const uv_tcp_t* handle, struct sockaddr* name, int* namelen) { - socklen_t socklen; if (handle->delayed_error) return handle->delayed_error; - if (uv__stream_fd(handle) < 0) - return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ - - /* sizeof(socklen_t) != sizeof(int) on some systems. */ - socklen = (socklen_t) *namelen; - - if (getpeername(uv__stream_fd(handle), name, &socklen)) - return -errno; - - *namelen = (int) socklen; - return 0; + return uv__getsockpeername((const uv_handle_t*) handle, + getpeername, + name, + namelen); } int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { static int single_accept = -1; + unsigned long flags; int err; if (tcp->delayed_error) @@ -271,35 +322,22 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { } if (single_accept) - tcp->flags |= UV_TCP_SINGLE_ACCEPT; + tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; - err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE); - if (err) - return err; - -#ifdef __MVS__ + flags = 0; +#if defined(__MVS__) /* on zOS the listen call does not bind automatically if the socket is unbound. Hence the manual binding to an arbitrary port is required to be done manually */ - - if (!(tcp->flags & UV_HANDLE_BOUND)) { - struct sockaddr_storage saddr; - socklen_t slen = sizeof(saddr); - memset(&saddr, 0, sizeof(saddr)); - - if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen)) - return -errno; - - if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen)) - return -errno; - - tcp->flags |= UV_HANDLE_BOUND; - } + flags |= UV_HANDLE_BOUND; #endif + err = maybe_new_socket(tcp, AF_INET, flags); + if (err) + return err; if (listen(tcp->io_watcher.fd, backlog)) - return -errno; + return UV__ERR(errno); tcp->connection_cb = cb; tcp->flags |= UV_HANDLE_BOUND; @@ -314,18 +352,18 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { int uv__tcp_nodelay(int fd, int on) { if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on))) - return -errno; + return UV__ERR(errno); return 0; } int uv__tcp_keepalive(int fd, int on, unsigned int delay) { if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on))) - return -errno; + return UV__ERR(errno); #ifdef TCP_KEEPIDLE if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay))) - return -errno; + return UV__ERR(errno); #endif /* Solaris/SmartOS, if you don't support keep-alive, @@ -334,7 +372,7 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) { /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */ #if defined(TCP_KEEPALIVE) && !defined(__sun) if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay))) - return -errno; + return UV__ERR(errno); #endif return 0; @@ -351,9 +389,9 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int on) { } if (on) - handle->flags |= UV_TCP_NODELAY; + handle->flags |= UV_HANDLE_TCP_NODELAY; else - handle->flags &= ~UV_TCP_NODELAY; + handle->flags &= ~UV_HANDLE_TCP_NODELAY; return 0; } @@ -369,9 +407,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { } if (on) - handle->flags |= UV_TCP_KEEPALIVE; + handle->flags |= UV_HANDLE_TCP_KEEPALIVE; else - handle->flags &= ~UV_TCP_KEEPALIVE; + handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge * uv_tcp_t with an int that's almost never used... @@ -383,9 +421,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { if (enable) - handle->flags &= ~UV_TCP_SINGLE_ACCEPT; + handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT; else - handle->flags |= UV_TCP_SINGLE_ACCEPT; + handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; return 0; } diff --git a/Utilities/cmlibuv/src/unix/thread.c b/Utilities/cmlibuv/src/unix/thread.c index a9b5e4c02..045322170 100644 --- a/Utilities/cmlibuv/src/unix/thread.c +++ b/Utilities/cmlibuv/src/unix/thread.c @@ -37,47 +37,223 @@ #include <sys/sem.h> #endif +#ifdef __GLIBC__ +#include <gnu/libc-version.h> /* gnu_get_libc_version() */ +#endif + #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) - -int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { - int err; - pthread_attr_t* attr; -#if defined(__APPLE__) - pthread_attr_t attr_storage; - struct rlimit lim; +#if defined(PTHREAD_BARRIER_SERIAL_THREAD) +STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t)); #endif - /* On OSX threads other than the main thread are created with a reduced stack - * size by default, adjust it to RLIMIT_STACK. - */ -#if defined(__APPLE__) - if (getrlimit(RLIMIT_STACK, &lim)) +/* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */ +#if defined(_AIX) || \ + defined(__OpenBSD__) || \ + !defined(PTHREAD_BARRIER_SERIAL_THREAD) +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + struct _uv_barrier* b; + int rc; + + if (barrier == NULL || count == 0) + return UV_EINVAL; + + b = uv__malloc(sizeof(*b)); + if (b == NULL) + return UV_ENOMEM; + + b->in = 0; + b->out = 0; + b->threshold = count; + + rc = uv_mutex_init(&b->mutex); + if (rc != 0) + goto error2; + + rc = uv_cond_init(&b->cond); + if (rc != 0) + goto error; + + barrier->b = b; + return 0; + +error: + uv_mutex_destroy(&b->mutex); +error2: + uv__free(b); + return rc; +} + + +int uv_barrier_wait(uv_barrier_t* barrier) { + struct _uv_barrier* b; + int last; + + if (barrier == NULL || barrier->b == NULL) + return UV_EINVAL; + + b = barrier->b; + uv_mutex_lock(&b->mutex); + + if (++b->in == b->threshold) { + b->in = 0; + b->out = b->threshold; + uv_cond_signal(&b->cond); + } else { + do + uv_cond_wait(&b->cond, &b->mutex); + while (b->in != 0); + } + + last = (--b->out == 0); + if (!last) + uv_cond_signal(&b->cond); /* Not needed for last thread. */ + + uv_mutex_unlock(&b->mutex); + return last; +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { + struct _uv_barrier* b; + + b = barrier->b; + uv_mutex_lock(&b->mutex); + + assert(b->in == 0); + assert(b->out == 0); + + if (b->in != 0 || b->out != 0) + abort(); + + uv_mutex_unlock(&b->mutex); + uv_mutex_destroy(&b->mutex); + uv_cond_destroy(&b->cond); + + uv__free(barrier->b); + barrier->b = NULL; +} + +#else + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + return UV__ERR(pthread_barrier_init(barrier, NULL, count)); +} + + +int uv_barrier_wait(uv_barrier_t* barrier) { + int rc; + + rc = pthread_barrier_wait(barrier); + if (rc != 0) + if (rc != PTHREAD_BARRIER_SERIAL_THREAD) + abort(); + + return rc == PTHREAD_BARRIER_SERIAL_THREAD; +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { + if (pthread_barrier_destroy(barrier)) abort(); +} + +#endif + + +/* On MacOS, threads other than the main thread are created with a reduced + * stack size by default. Adjust to RLIMIT_STACK aligned to the page size. + * + * On Linux, threads created by musl have a much smaller stack than threads + * created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency. + */ +static size_t thread_stack_size(void) { +#if defined(__APPLE__) || defined(__linux__) + struct rlimit lim; - attr = &attr_storage; - if (pthread_attr_init(attr)) + if (getrlimit(RLIMIT_STACK, &lim)) abort(); if (lim.rlim_cur != RLIM_INFINITY) { /* pthread_attr_setstacksize() expects page-aligned values. */ lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); - if (lim.rlim_cur >= PTHREAD_STACK_MIN) - if (pthread_attr_setstacksize(attr, lim.rlim_cur)) - abort(); + /* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is + * too small to safely receive signals on. + * + * Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has + * the largest MINSIGSTKSZ of the architectures that musl supports) so + * let's use that as a lower bound. + * + * We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ + * is between 28 and 133 KB when compiling against glibc, depending + * on the architecture. + */ + if (lim.rlim_cur >= 8192) + if (lim.rlim_cur >= PTHREAD_STACK_MIN) + return lim.rlim_cur; } +#endif + +#if !defined(__linux__) + return 0; +#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__) + return 4 << 20; /* glibc default. */ #else + return 2 << 20; /* glibc default. */ +#endif +} + + +int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { + uv_thread_options_t params; + params.flags = UV_THREAD_NO_FLAGS; + return uv_thread_create_ex(tid, ¶ms, entry, arg); +} + +int uv_thread_create_ex(uv_thread_t* tid, + const uv_thread_options_t* params, + void (*entry)(void *arg), + void *arg) { + int err; + pthread_attr_t* attr; + pthread_attr_t attr_storage; + size_t pagesize; + size_t stack_size; + + stack_size = + params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0; + attr = NULL; + if (stack_size == 0) { + stack_size = thread_stack_size(); + } else { + pagesize = (size_t)getpagesize(); + /* Round up to the nearest page boundary. */ + stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1); +#ifdef PTHREAD_STACK_MIN + if (stack_size < PTHREAD_STACK_MIN) + stack_size = PTHREAD_STACK_MIN; #endif + } + + if (stack_size > 0) { + attr = &attr_storage; + + if (pthread_attr_init(attr)) + abort(); + + if (pthread_attr_setstacksize(attr, stack_size)) + abort(); + } err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg); if (attr != NULL) pthread_attr_destroy(attr); - return -err; + return UV__ERR(err); } @@ -86,7 +262,7 @@ uv_thread_t uv_thread_self(void) { } int uv_thread_join(uv_thread_t *tid) { - return -pthread_join(*tid, NULL); + return UV__ERR(pthread_join(*tid, NULL)); } @@ -97,7 +273,7 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { int uv_mutex_init(uv_mutex_t* mutex) { #if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK) - return -pthread_mutex_init(mutex, NULL); + return UV__ERR(pthread_mutex_init(mutex, NULL)); #else pthread_mutexattr_t attr; int err; @@ -113,11 +289,30 @@ int uv_mutex_init(uv_mutex_t* mutex) { if (pthread_mutexattr_destroy(&attr)) abort(); - return -err; + return UV__ERR(err); #endif } +int uv_mutex_init_recursive(uv_mutex_t* mutex) { + pthread_mutexattr_t attr; + int err; + + if (pthread_mutexattr_init(&attr)) + abort(); + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) + abort(); + + err = pthread_mutex_init(mutex, &attr); + + if (pthread_mutexattr_destroy(&attr)) + abort(); + + return UV__ERR(err); +} + + void uv_mutex_destroy(uv_mutex_t* mutex) { if (pthread_mutex_destroy(mutex)) abort(); @@ -137,7 +332,7 @@ int uv_mutex_trylock(uv_mutex_t* mutex) { if (err) { if (err != EBUSY && err != EAGAIN) abort(); - return -EBUSY; + return UV_EBUSY; } return 0; @@ -151,7 +346,7 @@ void uv_mutex_unlock(uv_mutex_t* mutex) { int uv_rwlock_init(uv_rwlock_t* rwlock) { - return -pthread_rwlock_init(rwlock, NULL); + return UV__ERR(pthread_rwlock_init(rwlock, NULL)); } @@ -174,7 +369,7 @@ int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { if (err) { if (err != EBUSY && err != EAGAIN) abort(); - return -EBUSY; + return UV_EBUSY; } return 0; @@ -200,7 +395,7 @@ int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { if (err) { if (err != EBUSY && err != EAGAIN) abort(); - return -EBUSY; + return UV_EBUSY; } return 0; @@ -227,12 +422,12 @@ int uv_sem_init(uv_sem_t* sem, unsigned int value) { if (err == KERN_SUCCESS) return 0; if (err == KERN_INVALID_ARGUMENT) - return -EINVAL; + return UV_EINVAL; if (err == KERN_RESOURCE_SHORTAGE) - return -ENOMEM; + return UV_ENOMEM; abort(); - return -EINVAL; /* Satisfy the compiler. */ + return UV_EINVAL; /* Satisfy the compiler. */ } @@ -271,113 +466,151 @@ int uv_sem_trywait(uv_sem_t* sem) { if (err == KERN_SUCCESS) return 0; if (err == KERN_OPERATION_TIMED_OUT) - return -EAGAIN; + return UV_EAGAIN; abort(); - return -EINVAL; /* Satisfy the compiler. */ + return UV_EINVAL; /* Satisfy the compiler. */ +} + +#else /* !(defined(__APPLE__) && defined(__MACH__)) */ + +#ifdef __GLIBC__ + +/* Hack around https://sourceware.org/bugzilla/show_bug.cgi?id=12674 + * by providing a custom implementation for glibc < 2.21 in terms of other + * concurrency primitives. + * Refs: https://github.com/nodejs/node/issues/19903 */ + +/* To preserve ABI compatibility, we treat the uv_sem_t as storage for + * a pointer to the actual struct we're using underneath. */ + +static uv_once_t glibc_version_check_once = UV_ONCE_INIT; +static int platform_needs_custom_semaphore = 0; + +static void glibc_version_check(void) { + const char* version = gnu_get_libc_version(); + platform_needs_custom_semaphore = + version[0] == '2' && version[1] == '.' && + atoi(version + 2) < 21; } #elif defined(__MVS__) -int uv_sem_init(uv_sem_t* sem, unsigned int value) { - uv_sem_t semid; - struct sembuf buf; +#define platform_needs_custom_semaphore 1 + +#else /* !defined(__GLIBC__) && !defined(__MVS__) */ + +#define platform_needs_custom_semaphore 0 + +#endif + +typedef struct uv_semaphore_s { + uv_mutex_t mutex; + uv_cond_t cond; + unsigned int value; +} uv_semaphore_t; + +#if defined(__GLIBC__) || platform_needs_custom_semaphore +STATIC_ASSERT(sizeof(uv_sem_t) >= sizeof(uv_semaphore_t*)); +#endif + +static int uv__custom_sem_init(uv_sem_t* sem_, unsigned int value) { int err; + uv_semaphore_t* sem; - buf.sem_num = 0; - buf.sem_op = value; - buf.sem_flg = 0; + sem = uv__malloc(sizeof(*sem)); + if (sem == NULL) + return UV_ENOMEM; - semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR); - if (semid == -1) - return -errno; + if ((err = uv_mutex_init(&sem->mutex)) != 0) { + uv__free(sem); + return err; + } - if (-1 == semop(semid, &buf, 1)) { - err = errno; - if (-1 == semctl(*sem, 0, IPC_RMID)) - abort(); - return -err; + if ((err = uv_cond_init(&sem->cond)) != 0) { + uv_mutex_destroy(&sem->mutex); + uv__free(sem); + return err; } - *sem = semid; + sem->value = value; + *(uv_semaphore_t**)sem_ = sem; return 0; } -void uv_sem_destroy(uv_sem_t* sem) { - if (-1 == semctl(*sem, 0, IPC_RMID)) - abort(); + +static void uv__custom_sem_destroy(uv_sem_t* sem_) { + uv_semaphore_t* sem; + + sem = *(uv_semaphore_t**)sem_; + uv_cond_destroy(&sem->cond); + uv_mutex_destroy(&sem->mutex); + uv__free(sem); } -void uv_sem_post(uv_sem_t* sem) { - struct sembuf buf; - buf.sem_num = 0; - buf.sem_op = 1; - buf.sem_flg = 0; +static void uv__custom_sem_post(uv_sem_t* sem_) { + uv_semaphore_t* sem; - if (-1 == semop(*sem, &buf, 1)) - abort(); + sem = *(uv_semaphore_t**)sem_; + uv_mutex_lock(&sem->mutex); + sem->value++; + if (sem->value == 1) + uv_cond_signal(&sem->cond); + uv_mutex_unlock(&sem->mutex); } -void uv_sem_wait(uv_sem_t* sem) { - struct sembuf buf; - int op_status; - buf.sem_num = 0; - buf.sem_op = -1; - buf.sem_flg = 0; +static void uv__custom_sem_wait(uv_sem_t* sem_) { + uv_semaphore_t* sem; - do - op_status = semop(*sem, &buf, 1); - while (op_status == -1 && errno == EINTR); - - if (op_status) - abort(); + sem = *(uv_semaphore_t**)sem_; + uv_mutex_lock(&sem->mutex); + while (sem->value == 0) + uv_cond_wait(&sem->cond, &sem->mutex); + sem->value--; + uv_mutex_unlock(&sem->mutex); } -int uv_sem_trywait(uv_sem_t* sem) { - struct sembuf buf; - int op_status; - buf.sem_num = 0; - buf.sem_op = -1; - buf.sem_flg = IPC_NOWAIT; +static int uv__custom_sem_trywait(uv_sem_t* sem_) { + uv_semaphore_t* sem; - do - op_status = semop(*sem, &buf, 1); - while (op_status == -1 && errno == EINTR); + sem = *(uv_semaphore_t**)sem_; + if (uv_mutex_trylock(&sem->mutex) != 0) + return UV_EAGAIN; - if (op_status) { - if (errno == EAGAIN) - return -EAGAIN; - abort(); + if (sem->value == 0) { + uv_mutex_unlock(&sem->mutex); + return UV_EAGAIN; } + sem->value--; + uv_mutex_unlock(&sem->mutex); + return 0; } -#else /* !(defined(__APPLE__) && defined(__MACH__)) */ - -int uv_sem_init(uv_sem_t* sem, unsigned int value) { +static int uv__sem_init(uv_sem_t* sem, unsigned int value) { if (sem_init(sem, 0, value)) - return -errno; + return UV__ERR(errno); return 0; } -void uv_sem_destroy(uv_sem_t* sem) { +static void uv__sem_destroy(uv_sem_t* sem) { if (sem_destroy(sem)) abort(); } -void uv_sem_post(uv_sem_t* sem) { +static void uv__sem_post(uv_sem_t* sem) { if (sem_post(sem)) abort(); } -void uv_sem_wait(uv_sem_t* sem) { +static void uv__sem_wait(uv_sem_t* sem) { int r; do @@ -389,7 +622,7 @@ void uv_sem_wait(uv_sem_t* sem) { } -int uv_sem_trywait(uv_sem_t* sem) { +static int uv__sem_trywait(uv_sem_t* sem) { int r; do @@ -398,20 +631,63 @@ int uv_sem_trywait(uv_sem_t* sem) { if (r) { if (errno == EAGAIN) - return -EAGAIN; + return UV_EAGAIN; abort(); } return 0; } +int uv_sem_init(uv_sem_t* sem, unsigned int value) { +#ifdef __GLIBC__ + uv_once(&glibc_version_check_once, glibc_version_check); +#endif + + if (platform_needs_custom_semaphore) + return uv__custom_sem_init(sem, value); + else + return uv__sem_init(sem, value); +} + + +void uv_sem_destroy(uv_sem_t* sem) { + if (platform_needs_custom_semaphore) + uv__custom_sem_destroy(sem); + else + uv__sem_destroy(sem); +} + + +void uv_sem_post(uv_sem_t* sem) { + if (platform_needs_custom_semaphore) + uv__custom_sem_post(sem); + else + uv__sem_post(sem); +} + + +void uv_sem_wait(uv_sem_t* sem) { + if (platform_needs_custom_semaphore) + uv__custom_sem_wait(sem); + else + uv__sem_wait(sem); +} + + +int uv_sem_trywait(uv_sem_t* sem) { + if (platform_needs_custom_semaphore) + return uv__custom_sem_trywait(sem); + else + return uv__sem_trywait(sem); +} + #endif /* defined(__APPLE__) && defined(__MACH__) */ #if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__) int uv_cond_init(uv_cond_t* cond) { - return -pthread_cond_init(cond, NULL); + return UV__ERR(pthread_cond_init(cond, NULL)); } #else /* !(defined(__APPLE__) && defined(__MACH__)) */ @@ -422,9 +698,9 @@ int uv_cond_init(uv_cond_t* cond) { err = pthread_condattr_init(&attr); if (err) - return -err; + return UV__ERR(err); -#if !(defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)) +#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21) && !defined(__hpux) err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); if (err) goto error2; @@ -444,7 +720,7 @@ error: pthread_cond_destroy(cond); error2: pthread_condattr_destroy(&attr); - return -err; + return UV__ERR(err); } #endif /* defined(__APPLE__) && defined(__MACH__) */ @@ -502,16 +778,26 @@ void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { int r; struct timespec ts; +#if defined(__MVS__) + struct timeval tv; +#endif #if defined(__APPLE__) && defined(__MACH__) ts.tv_sec = timeout / NANOSEC; ts.tv_nsec = timeout % NANOSEC; r = pthread_cond_timedwait_relative_np(cond, mutex, &ts); #else +#if defined(__MVS__) + if (gettimeofday(&tv, NULL)) + abort(); + timeout += tv.tv_sec * NANOSEC + tv.tv_usec * 1e3; +#else timeout += uv__hrtime(UV_CLOCK_PRECISE); +#endif ts.tv_sec = timeout / NANOSEC; ts.tv_nsec = timeout % NANOSEC; -#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + /* * The bionic pthread implementation doesn't support CLOCK_MONOTONIC, * but has this alternative function instead. @@ -519,7 +805,7 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts); #else r = pthread_cond_timedwait(cond, mutex, &ts); -#endif /* __ANDROID__ */ +#endif /* __ANDROID_API__ */ #endif @@ -527,34 +813,17 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { return 0; if (r == ETIMEDOUT) - return -ETIMEDOUT; + return UV_ETIMEDOUT; abort(); - return -EINVAL; /* Satisfy the compiler. */ -} - - -int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { - return -pthread_barrier_init(barrier, NULL, count); -} - - -void uv_barrier_destroy(uv_barrier_t* barrier) { - if (pthread_barrier_destroy(barrier)) - abort(); -} - - -int uv_barrier_wait(uv_barrier_t* barrier) { - int r = pthread_barrier_wait(barrier); - if (r && r != PTHREAD_BARRIER_SERIAL_THREAD) - abort(); - return r == PTHREAD_BARRIER_SERIAL_THREAD; +#ifndef __SUNPRO_C + return UV_EINVAL; /* Satisfy the compiler. */ +#endif } int uv_key_create(uv_key_t* key) { - return -pthread_key_create(key, NULL); + return UV__ERR(pthread_key_create(key, NULL)); } diff --git a/Utilities/cmlibuv/src/unix/timer.c b/Utilities/cmlibuv/src/unix/timer.c deleted file mode 100644 index f46bdf4bf..000000000 --- a/Utilities/cmlibuv/src/unix/timer.c +++ /dev/null @@ -1,172 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include "uv.h" -#include "internal.h" -#include "heap-inl.h" - -#include <assert.h> -#include <limits.h> - - -static int timer_less_than(const struct heap_node* ha, - const struct heap_node* hb) { - const uv_timer_t* a; - const uv_timer_t* b; - - a = container_of(ha, uv_timer_t, heap_node); - b = container_of(hb, uv_timer_t, heap_node); - - if (a->timeout < b->timeout) - return 1; - if (b->timeout < a->timeout) - return 0; - - /* Compare start_id when both have the same timeout. start_id is - * allocated with loop->timer_counter in uv_timer_start(). - */ - if (a->start_id < b->start_id) - return 1; - if (b->start_id < a->start_id) - return 0; - - return 0; -} - - -int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { - uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER); - handle->timer_cb = NULL; - handle->repeat = 0; - return 0; -} - - -int uv_timer_start(uv_timer_t* handle, - uv_timer_cb cb, - uint64_t timeout, - uint64_t repeat) { - uint64_t clamped_timeout; - - if (cb == NULL) - return -EINVAL; - - if (uv__is_active(handle)) - uv_timer_stop(handle); - - clamped_timeout = handle->loop->time + timeout; - if (clamped_timeout < timeout) - clamped_timeout = (uint64_t) -1; - - handle->timer_cb = cb; - handle->timeout = clamped_timeout; - handle->repeat = repeat; - /* start_id is the second index to be compared in uv__timer_cmp() */ - handle->start_id = handle->loop->timer_counter++; - - heap_insert((struct heap*) &handle->loop->timer_heap, - (struct heap_node*) &handle->heap_node, - timer_less_than); - uv__handle_start(handle); - - return 0; -} - - -int uv_timer_stop(uv_timer_t* handle) { - if (!uv__is_active(handle)) - return 0; - - heap_remove((struct heap*) &handle->loop->timer_heap, - (struct heap_node*) &handle->heap_node, - timer_less_than); - uv__handle_stop(handle); - - return 0; -} - - -int uv_timer_again(uv_timer_t* handle) { - if (handle->timer_cb == NULL) - return -EINVAL; - - if (handle->repeat) { - uv_timer_stop(handle); - uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat); - } - - return 0; -} - - -void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) { - handle->repeat = repeat; -} - - -uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { - return handle->repeat; -} - - -int uv__next_timeout(const uv_loop_t* loop) { - const struct heap_node* heap_node; - const uv_timer_t* handle; - uint64_t diff; - - heap_node = heap_min((const struct heap*) &loop->timer_heap); - if (heap_node == NULL) - return -1; /* block indefinitely */ - - handle = container_of(heap_node, uv_timer_t, heap_node); - if (handle->timeout <= loop->time) - return 0; - - diff = handle->timeout - loop->time; - if (diff > INT_MAX) - diff = INT_MAX; - - return diff; -} - - -void uv__run_timers(uv_loop_t* loop) { - struct heap_node* heap_node; - uv_timer_t* handle; - - for (;;) { - heap_node = heap_min((struct heap*) &loop->timer_heap); - if (heap_node == NULL) - break; - - handle = container_of(heap_node, uv_timer_t, heap_node); - if (handle->timeout > loop->time) - break; - - uv_timer_stop(handle); - uv_timer_again(handle); - handle->timer_cb(handle); - } -} - - -void uv__timer_close(uv_timer_t* handle) { - uv_timer_stop(handle); -} diff --git a/Utilities/cmlibuv/src/unix/tty.c b/Utilities/cmlibuv/src/unix/tty.c index ae1018fc4..db479d61b 100644 --- a/Utilities/cmlibuv/src/unix/tty.c +++ b/Utilities/cmlibuv/src/unix/tty.c @@ -48,6 +48,42 @@ static int uv__tty_is_slave(const int fd) { char dummy[256]; result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0; +#elif defined(__NetBSD__) + /* + * NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the slave + * device name for both descriptors, the master one and slave one. + * + * Implement function to compare major device number with pts devices. + * + * The major numbers are machine-dependent, on NetBSD/amd64 they are + * respectively: + * - master tty: ptc - major 6 + * - slave tty: pts - major 5 + */ + + struct stat sb; + /* Lookup device's major for the pts driver and cache it. */ + static devmajor_t pts = NODEVMAJOR; + + if (pts == NODEVMAJOR) { + pts = getdevmajor("pts", S_IFCHR); + if (pts == NODEVMAJOR) + abort(); + } + + /* Lookup stat structure behind the file descriptor. */ + if (fstat(fd, &sb) != 0) + abort(); + + /* Assert character device. */ + if (!S_ISCHR(sb.st_mode)) + abort(); + + /* Assert valid major. */ + if (major(sb.st_rdev) == NODEVMAJOR) + abort(); + + result = (pts == major(sb.st_rdev)); #else /* Fallback to ptsname */ @@ -56,13 +92,15 @@ static int uv__tty_is_slave(const int fd) { return result; } -int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { +int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) { uv_handle_type type; int flags = 0; int newfd = -1; int r; int saved_flags; + int mode; char path[256]; + (void)unused; /* deprecated parameter is no longer needed */ /* File descriptors that refer to files cannot be monitored with epoll. * That restriction also applies to character devices like /dev/random @@ -70,7 +108,16 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { */ type = uv_guess_handle(fd); if (type == UV_FILE || type == UV_UNKNOWN_HANDLE) - return -EINVAL; + return UV_EINVAL; + + /* Save the fd flags in case we need to restore them due to an error. */ + do + saved_flags = fcntl(fd, F_GETFL); + while (saved_flags == -1 && errno == EINTR); + + if (saved_flags == -1) + return UV__ERR(errno); + mode = saved_flags & O_ACCMODE; /* Reopen the file descriptor when it refers to a tty. This lets us put the * tty in non-blocking mode without affecting other processes that share it @@ -89,21 +136,21 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { * slave device. */ if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) - r = uv__open_cloexec(path, O_RDWR); + r = uv__open_cloexec(path, mode); else r = -1; if (r < 0) { /* fallback to using blocking writes */ - if (!readable) - flags |= UV_STREAM_BLOCKING; + if (mode != O_RDONLY) + flags |= UV_HANDLE_BLOCKING_WRITES; goto skip; } newfd = r; r = uv__dup2_cloexec(newfd, fd); - if (r < 0 && r != -EINVAL) { + if (r < 0 && r != UV_EINVAL) { /* EINVAL means newfd == fd which could conceivably happen if another * thread called close(fd) between our calls to isatty() and open(). * That's a rather unlikely event but let's handle it anyway. @@ -115,22 +162,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { fd = newfd; } -#if defined(__APPLE__) - /* Save the fd flags in case we need to restore them due to an error. */ - do - saved_flags = fcntl(fd, F_GETFL); - while (saved_flags == -1 && errno == EINTR); - - if (saved_flags == -1) { - if (newfd != -1) - uv__close(newfd); - return -errno; - } -#endif - - /* Pacify the compiler. */ - (void) &saved_flags; - skip: uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); @@ -138,7 +169,7 @@ skip: * the handle queue, since it was added by uv__handle_init in uv_stream_init. */ - if (!(flags & UV_STREAM_BLOCKING)) + if (!(flags & UV_HANDLE_BLOCKING_WRITES)) uv__nonblock(fd, 1); #if defined(__APPLE__) @@ -155,10 +186,10 @@ skip: } #endif - if (readable) - flags |= UV_STREAM_READABLE; - else - flags |= UV_STREAM_WRITABLE; + if (mode != O_WRONLY) + flags |= UV_HANDLE_READABLE; + if (mode != O_RDONLY) + flags |= UV_HANDLE_WRITABLE; uv__stream_open((uv_stream_t*) tty, fd, flags); tty->mode = UV_TTY_MODE_NORMAL; @@ -169,7 +200,7 @@ skip: static void uv__tty_make_raw(struct termios* tio) { assert(tio != NULL); -#if defined __sun || defined __MVS__ +#if defined __sun || defined __MVS__ || defined __hpux /* * This implementation of cfmakeraw for Solaris and derivatives is taken from * http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html. @@ -195,7 +226,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { fd = uv__stream_fd(tty); if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) { if (tcgetattr(fd, &tty->orig_termios)) - return -errno; + return UV__ERR(errno); /* This is used for uv_tty_reset_mode() */ uv_spinlock_lock(&termios_spinlock); @@ -225,7 +256,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { /* Apply changes after draining */ if (tcsetattr(fd, TCSADRAIN, &tmp)) - return -errno; + return UV__ERR(errno); tty->mode = mode; return 0; @@ -241,7 +272,7 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { while (err == -1 && errno == EINTR); if (err == -1) - return -errno; + return UV__ERR(errno); *width = ws.ws_col; *height = ws.ws_row; @@ -319,12 +350,12 @@ int uv_tty_reset_mode(void) { saved_errno = errno; if (!uv_spinlock_trylock(&termios_spinlock)) - return -EBUSY; /* In uv_tty_set_mode(). */ + return UV_EBUSY; /* In uv_tty_set_mode(). */ err = 0; if (orig_termios_fd != -1) if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios)) - err = -errno; + err = UV__ERR(errno); uv_spinlock_unlock(&termios_spinlock); errno = saved_errno; diff --git a/Utilities/cmlibuv/src/unix/udp.c b/Utilities/cmlibuv/src/unix/udp.c index c556325de..b578e7bc1 100644 --- a/Utilities/cmlibuv/src/unix/udp.c +++ b/Utilities/cmlibuv/src/unix/udp.c @@ -30,6 +30,7 @@ #if defined(__MVS__) #include <xti.h> #endif +#include <sys/un.h> #if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP) # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP @@ -72,7 +73,7 @@ void uv__udp_finish_close(uv_udp_t* handle) { QUEUE_REMOVE(q); req = QUEUE_DATA(q, uv_udp_send_t, queue); - req->status = -ECANCELED; + req->status = UV_ECANCELED; QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue); } @@ -92,8 +93,8 @@ static void uv__udp_run_completed(uv_udp_t* handle) { uv_udp_send_t* req; QUEUE* q; - assert(!(handle->flags & UV_UDP_PROCESSING)); - handle->flags |= UV_UDP_PROCESSING; + assert(!(handle->flags & UV_HANDLE_UDP_PROCESSING)); + handle->flags |= UV_HANDLE_UDP_PROCESSING; while (!QUEUE_EMPTY(&handle->write_completed_queue)) { q = QUEUE_HEAD(&handle->write_completed_queue); @@ -128,7 +129,7 @@ static void uv__udp_run_completed(uv_udp_t* handle) { uv__handle_stop(handle); } - handle->flags &= ~UV_UDP_PROCESSING; + handle->flags &= ~UV_HANDLE_UDP_PROCESSING; } @@ -189,7 +190,7 @@ static void uv__udp_recvmsg(uv_udp_t* handle) { if (errno == EAGAIN || errno == EWOULDBLOCK) handle->recv_cb(handle, 0, &buf, NULL, 0); else - handle->recv_cb(handle, -errno, &buf, NULL, 0); + handle->recv_cb(handle, UV__ERR(errno), &buf, NULL, 0); } else { const struct sockaddr *addr; @@ -227,9 +228,22 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { assert(req != NULL); memset(&h, 0, sizeof h); - h.msg_name = &req->addr; - h.msg_namelen = (req->addr.ss_family == AF_INET6 ? - sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + if (req->addr.ss_family == AF_UNSPEC) { + h.msg_name = NULL; + h.msg_namelen = 0; + } else { + h.msg_name = &req->addr; + if (req->addr.ss_family == AF_INET6) + h.msg_namelen = sizeof(struct sockaddr_in6); + else if (req->addr.ss_family == AF_INET) + h.msg_namelen = sizeof(struct sockaddr_in); + else if (req->addr.ss_family == AF_UNIX) + h.msg_namelen = sizeof(struct sockaddr_un); + else { + assert(0 && "unsupported address family"); + abort(); + } + } h.msg_iov = (struct iovec*) req->bufs; h.msg_iovlen = req->nbufs; @@ -237,10 +251,12 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { size = sendmsg(handle->io_watcher.fd, &h, 0); } while (size == -1 && errno == EINTR); - if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) - break; + if (size == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) + break; + } - req->status = (size == -1 ? -errno : size); + req->status = (size == -1 ? UV__ERR(errno) : size); /* Sending a datagram is an atomic operation: either all data * is written or nothing is (and EMSGSIZE is raised). That is @@ -261,18 +277,32 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { * are different from the BSDs: it _shares_ the port rather than steal it * from the current listener. While useful, it's not something we can emulate * on other platforms so we don't enable it. + * + * zOS does not support getsockname with SO_REUSEPORT option when using + * AF_UNIX. */ static int uv__set_reuse(int fd) { int yes; - -#if defined(SO_REUSEPORT) && !defined(__linux__) yes = 1; + +#if defined(SO_REUSEPORT) && defined(__MVS__) + struct sockaddr_in sockfd; + unsigned int sockfd_len = sizeof(sockfd); + if (getsockname(fd, (struct sockaddr*) &sockfd, &sockfd_len) == -1) + return UV__ERR(errno); + if (sockfd.sin_family == AF_UNIX) { + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) + return UV__ERR(errno); + } else { + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) + return UV__ERR(errno); + } +#elif defined(SO_REUSEPORT) && !defined(__linux__) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) - return -errno; + return UV__ERR(errno); #else - yes = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) - return -errno; + return UV__ERR(errno); #endif return 0; @@ -289,11 +319,11 @@ int uv__udp_bind(uv_udp_t* handle, /* Check for bad flags. */ if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR)) - return -EINVAL; + return UV_EINVAL; /* Cannot set IPv6-only mode on non-IPv6 socket. */ if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) - return -EINVAL; + return UV_EINVAL; fd = handle->io_watcher.fd; if (fd == -1) { @@ -314,21 +344,21 @@ int uv__udp_bind(uv_udp_t* handle, #ifdef IPV6_V6ONLY yes = 1; if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { - err = -errno; + err = UV__ERR(errno); return err; } #else - err = -ENOTSUP; + err = UV_ENOTSUP; return err; #endif } if (bind(fd, addr, addrlen)) { - err = -errno; + err = UV__ERR(errno); if (errno == EAFNOSUPPORT) /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a * socket created with AF_INET to an AF_INET6 address or vice versa. */ - err = -EINVAL; + err = UV_EINVAL; return err; } @@ -381,6 +411,50 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, } +int uv__udp_connect(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen) { + int err; + + err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); + if (err) + return err; + + do { + errno = 0; + err = connect(handle->io_watcher.fd, addr, addrlen); + } while (err == -1 && errno == EINTR); + + if (err) + return UV__ERR(errno); + + handle->flags |= UV_HANDLE_UDP_CONNECTED; + + return 0; +} + + +int uv__udp_disconnect(uv_udp_t* handle) { + int r; + struct sockaddr addr; + + memset(&addr, 0, sizeof(addr)); + + addr.sa_family = AF_UNSPEC; + + do { + errno = 0; + r = connect(handle->io_watcher.fd, &addr, sizeof(addr)); + } while (r == -1 && errno == EINTR); + + if (r == -1 && errno != EAFNOSUPPORT) + return UV__ERR(errno); + + handle->flags &= ~UV_HANDLE_UDP_CONNECTED; + return 0; +} + + int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[], @@ -393,9 +467,11 @@ int uv__udp_send(uv_udp_send_t* req, assert(nbufs > 0); - err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); - if (err) - return err; + if (addr) { + err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); + if (err) + return err; + } /* It's legal for send_queue_count > 0 even when the write_queue is empty; * it means there are error-state requests in the write_completed_queue that @@ -405,7 +481,10 @@ int uv__udp_send(uv_udp_send_t* req, uv__req_init(handle->loop, req, UV_UDP_SEND); assert(addrlen <= sizeof(req->addr)); - memcpy(&req->addr, addr, addrlen); + if (addr == NULL) + req->addr.ss_family = AF_UNSPEC; + else + memcpy(&req->addr, addr, addrlen); req->send_cb = send_cb; req->handle = handle; req->nbufs = nbufs; @@ -416,7 +495,7 @@ int uv__udp_send(uv_udp_send_t* req, if (req->bufs == NULL) { uv__req_unregister(handle->loop, req); - return -ENOMEM; + return UV_ENOMEM; } memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); @@ -425,7 +504,7 @@ int uv__udp_send(uv_udp_send_t* req, QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue); uv__handle_start(handle); - if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) { + if (empty_queue && !(handle->flags & UV_HANDLE_UDP_PROCESSING)) { uv__udp_sendmsg(handle); /* `uv__udp_sendmsg` may not be able to do non-blocking write straight @@ -455,11 +534,15 @@ int uv__udp_try_send(uv_udp_t* handle, /* already sending a message */ if (handle->send_queue_count != 0) - return -EAGAIN; + return UV_EAGAIN; - err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); - if (err) - return err; + if (addr) { + err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); + if (err) + return err; + } else { + assert(handle->flags & UV_HANDLE_UDP_CONNECTED); + } memset(&h, 0, sizeof h); h.msg_name = (struct sockaddr*) addr; @@ -472,10 +555,10 @@ int uv__udp_try_send(uv_udp_t* handle, } while (size == -1 && errno == EINTR); if (size == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - return -EAGAIN; + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) + return UV_EAGAIN; else - return -errno; + return UV__ERR(errno); } return size; @@ -510,7 +593,7 @@ static int uv__udp_set_membership4(uv_udp_t* handle, optname = IP_DROP_MEMBERSHIP; break; default: - return -EINVAL; + return UV_EINVAL; } if (setsockopt(handle->io_watcher.fd, @@ -520,9 +603,9 @@ static int uv__udp_set_membership4(uv_udp_t* handle, sizeof(mreq))) { #if defined(__MVS__) if (errno == ENXIO) - return -ENODEV; + return UV_ENODEV; #endif - return -errno; + return UV__ERR(errno); } return 0; @@ -541,7 +624,7 @@ static int uv__udp_set_membership6(uv_udp_t* handle, if (interface_addr) { if (uv_ip6_addr(interface_addr, 0, &addr6)) - return -EINVAL; + return UV_EINVAL; mreq.ipv6mr_interface = addr6.sin6_scope_id; } else { mreq.ipv6mr_interface = 0; @@ -557,7 +640,7 @@ static int uv__udp_set_membership6(uv_udp_t* handle, optname = IPV6_DROP_MEMBERSHIP; break; default: - return -EINVAL; + return UV_EINVAL; } if (setsockopt(handle->io_watcher.fd, @@ -567,9 +650,9 @@ static int uv__udp_set_membership6(uv_udp_t* handle, sizeof(mreq))) { #if defined(__MVS__) if (errno == ENXIO) - return -ENODEV; + return UV_ENODEV; #endif - return -errno; + return UV__ERR(errno); } return 0; @@ -584,10 +667,10 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { /* Use the lower 8 bits for the domain */ domain = flags & 0xFF; if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) - return -EINVAL; + return UV_EINVAL; if (flags & ~0xFF) - return -EINVAL; + return UV_EINVAL; if (domain != AF_UNSPEC) { err = uv__socket(domain, SOCK_DGRAM, 0); @@ -606,6 +689,7 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { uv__io_init(&handle->io_watcher, uv__udp_io, fd); QUEUE_INIT(&handle->write_queue); QUEUE_INIT(&handle->write_completed_queue); + return 0; } @@ -620,7 +704,10 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { /* Check for already active socket. */ if (handle->io_watcher.fd != -1) - return -EBUSY; + return UV_EBUSY; + + if (uv__fd_exists(handle->loop, sock)) + return UV_EEXIST; err = uv__nonblock(sock, 1); if (err) @@ -631,6 +718,9 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { return err; handle->io_watcher.fd = sock; + if (uv__udp_is_connected(handle)) + handle->flags |= UV_HANDLE_UDP_CONNECTED; + return 0; } @@ -654,7 +744,7 @@ int uv_udp_set_membership(uv_udp_t* handle, return err; return uv__udp_set_membership6(handle, &addr6, interface_addr, membership); } else { - return -EINVAL; + return UV_EINVAL; } } @@ -678,7 +768,7 @@ static int uv__setsockopt(uv_udp_t* handle, val, size); if (r) - return -errno; + return UV__ERR(errno); return 0; } @@ -696,7 +786,7 @@ static int uv__setsockopt_maybe_char(uv_udp_t* handle, #endif if (val < 0 || val > 255) - return -EINVAL; + return UV_EINVAL; return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg)); } @@ -708,7 +798,7 @@ int uv_udp_set_broadcast(uv_udp_t* handle, int on) { SO_BROADCAST, &on, sizeof(on))) { - return -errno; + return UV__ERR(errno); } return 0; @@ -717,11 +807,11 @@ int uv_udp_set_broadcast(uv_udp_t* handle, int on) { int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { if (ttl < 1 || ttl > 255) - return -EINVAL; + return UV_EINVAL; #if defined(__MVS__) if (!(handle->flags & UV_HANDLE_IPV6)) - return -ENOTSUP; /* zOS does not support setting ttl for IPv4 */ + return UV_ENOTSUP; /* zOS does not support setting ttl for IPv4 */ #endif /* @@ -738,13 +828,17 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); -#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || - defined(__MVS__) */ + +#else /* !(defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || + defined(__MVS__)) */ return uv__setsockopt_maybe_char(handle, IP_TTL, IPV6_UNICAST_HOPS, ttl); + +#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || + defined(__MVS__) */ } @@ -755,14 +849,16 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case, * and use the general uv__setsockopt_maybe_char call otherwise. */ -#if defined(__sun) || defined(_AIX) || defined(__MVS__) +#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_TTL, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)); -#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ +#endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) */ return uv__setsockopt_maybe_char(handle, IP_MULTICAST_TTL, @@ -778,14 +874,16 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case, * and use the general uv__setsockopt_maybe_char call otherwise. */ -#if defined(__sun) || defined(_AIX) || defined(__MVS__) +#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_LOOP, IPV6_MULTICAST_LOOP, &on, sizeof(on)); -#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ +#endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) || + defined(__MVS__) */ return uv__setsockopt_maybe_char(handle, IP_MULTICAST_LOOP, @@ -815,7 +913,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) { /* nothing, address was parsed */ } else { - return -EINVAL; + return UV_EINVAL; } if (addr_st.ss_family == AF_INET) { @@ -824,7 +922,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) IP_MULTICAST_IF, (void*) &addr4->sin_addr, sizeof(addr4->sin_addr)) == -1) { - return -errno; + return UV__ERR(errno); } } else if (addr_st.ss_family == AF_INET6) { if (setsockopt(handle->io_watcher.fd, @@ -832,7 +930,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) IPV6_MULTICAST_IF, &addr6->sin6_scope_id, sizeof(addr6->sin6_scope_id)) == -1) { - return -errno; + return UV__ERR(errno); } } else { assert(0 && "unexpected address family"); @@ -842,23 +940,24 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) return 0; } - -int uv_udp_getsockname(const uv_udp_t* handle, +int uv_udp_getpeername(const uv_udp_t* handle, struct sockaddr* name, int* namelen) { - socklen_t socklen; - if (handle->io_watcher.fd == -1) - return -EINVAL; /* FIXME(bnoordhuis) -EBADF */ - - /* sizeof(socklen_t) != sizeof(int) on some systems. */ - socklen = (socklen_t) *namelen; + return uv__getsockpeername((const uv_handle_t*) handle, + getpeername, + name, + namelen); +} - if (getsockname(handle->io_watcher.fd, name, &socklen)) - return -errno; +int uv_udp_getsockname(const uv_udp_t* handle, + struct sockaddr* name, + int* namelen) { - *namelen = (int) socklen; - return 0; + return uv__getsockpeername((const uv_handle_t*) handle, + getsockname, + name, + namelen); } @@ -868,10 +967,10 @@ int uv__udp_recv_start(uv_udp_t* handle, int err; if (alloc_cb == NULL || recv_cb == NULL) - return -EINVAL; + return UV_EINVAL; if (uv__io_active(&handle->io_watcher, POLLIN)) - return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */ + return UV_EALREADY; /* FIXME(bnoordhuis) Should be UV_EBUSY. */ err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0); if (err) |