libuv 1.43.0

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3735 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
2022-01-05 02:04:05 +00:00
parent c02a3d3659
commit e2c25ab414
60 changed files with 1048 additions and 608 deletions

View File

@ -38,9 +38,7 @@ static void init_process_title_mutex_once(void) {
void uv__process_title_cleanup(void) {
/* TODO(bnoordhuis) uv_mutex_destroy(&process_title_mutex)
* and reset process_title_mutex_once?
*/
uv_mutex_destroy(&process_title_mutex);
}

View File

@ -280,14 +280,18 @@ static int uv__get_cpu_speed(uint64_t* speed) {
NULL,
0);
if (freq_ref) {
uint32_t freq;
const UInt8* freq_ref_ptr = pCFDataGetBytePtr(freq_ref);
CFIndex len = pCFDataGetLength(freq_ref);
CFRange range;
range.location = 0;
range.length = len;
if (len == 8)
memcpy(speed, freq_ref_ptr, 8);
else if (len == 4) {
uint32_t v;
memcpy(&v, freq_ref_ptr, 4);
*speed = v;
} else {
*speed = 0;
}
pCFDataGetBytes(freq_ref, range, (UInt8*)&freq);
*speed = freq;
pCFRelease(freq_ref);
pCFRelease(data);
break;

View File

@ -53,7 +53,7 @@ void uv_dlclose(uv_lib_t* lib) {
int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
dlerror(); /* Reset error status. */
*ptr = dlsym(lib->handle, name);
return uv__dlerror(lib);
return *ptr ? 0 : uv__dlerror(lib);
}

View File

@ -946,6 +946,71 @@ static int uv__is_buggy_cephfs(int fd) {
return uv__kernel_version() < /* 4.20.0 */ 0x041400;
}
static int uv__is_cifs_or_smb(int fd) {
struct statfs s;
if (-1 == fstatfs(fd, &s))
return 0;
switch ((unsigned) s.f_type) {
case 0x0000517Bu: /* SMB */
case 0xFE534D42u: /* SMB2 */
case 0xFF534D42u: /* CIFS */
return 1;
}
return 0;
}
static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
int out_fd, size_t len) {
static int no_copy_file_range_support;
ssize_t r;
if (uv__load_relaxed(&no_copy_file_range_support)) {
errno = ENOSYS;
return -1;
}
r = uv__fs_copy_file_range(in_fd, off, out_fd, NULL, len, 0);
if (r != -1)
return r;
switch (errno) {
case EACCES:
/* Pre-4.20 kernels have a bug where CephFS uses the RADOS
* copy-from command when it shouldn't.
*/
if (uv__is_buggy_cephfs(in_fd))
errno = ENOSYS; /* Use fallback. */
break;
case ENOSYS:
uv__store_relaxed(&no_copy_file_range_support, 1);
break;
case EPERM:
/* It's been reported that CIFS spuriously fails.
* Consider it a transient error.
*/
if (uv__is_cifs_or_smb(out_fd))
errno = ENOSYS; /* Use fallback. */
break;
case ENOTSUP:
case EXDEV:
/* ENOTSUP - it could work on another file system type.
* EXDEV - it will not work when in_fd and out_fd are not on the same
* mounted filesystem (pre Linux 5.3)
*/
errno = ENOSYS; /* Use fallback. */
break;
}
return -1;
}
#endif /* __linux__ */
@ -960,40 +1025,21 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
{
off_t off;
ssize_t r;
size_t len;
int try_sendfile;
off = req->off;
len = req->bufsml[0].len;
try_sendfile = 1;
#ifdef __linux__
{
static int no_copy_file_range_support;
if (uv__load_relaxed(&no_copy_file_range_support) == 0) {
r = uv__fs_copy_file_range(in_fd, &off, out_fd, NULL, req->bufsml[0].len, 0);
if (r == -1 && errno == ENOSYS) {
/* ENOSYS - it will never work */
errno = 0;
uv__store_relaxed(&no_copy_file_range_support, 1);
} else if (r == -1 && errno == EACCES && uv__is_buggy_cephfs(in_fd)) {
/* EACCES - pre-4.20 kernels have a bug where CephFS uses the RADOS
copy-from command when it shouldn't */
errno = 0;
uv__store_relaxed(&no_copy_file_range_support, 1);
} else if (r == -1 && (errno == ENOTSUP || errno == EXDEV)) {
/* ENOTSUP - it could work on another file system type */
/* EXDEV - it will not work when in_fd and out_fd are not on the same
mounted filesystem (pre Linux 5.3) */
errno = 0;
} else {
goto ok;
}
}
}
r = uv__fs_try_copy_file_range(in_fd, &off, out_fd, len);
try_sendfile = (r == -1 && errno == ENOSYS);
#endif
r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len);
if (try_sendfile)
r = sendfile(out_fd, in_fd, &off, len);
ok:
/* sendfile() on SunOS returns EINVAL if the target fd is not a socket but
* it still writes out data. Fortunately, we can detect it by checking if
* the offset has been updated.
@ -1277,22 +1323,15 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
if (fchmod(dstfd, src_statsbuf.st_mode) == -1) {
err = UV__ERR(errno);
#ifdef __linux__
/* fchmod() on CIFS shares always fails with EPERM unless the share is
* mounted with "noperm". As fchmod() is a meaningless operation on such
* shares anyway, detect that condition and squelch the error.
*/
if (err != UV_EPERM)
goto out;
{
struct statfs s;
/* fchmod() on CIFS shares always fails with EPERM unless the share is
* mounted with "noperm". As fchmod() is a meaningless operation on such
* shares anyway, detect that condition and squelch the error.
*/
if (fstatfs(dstfd, &s) == -1)
goto out;
if ((unsigned) s.f_type != /* CIFS */ 0xFF534D42u)
goto out;
}
if (!uv__is_cifs_or_smb(dstfd))
goto out;
err = 0;
#else /* !__linux__ */

View File

@ -326,6 +326,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (errno != ENOENT)
abort();
}
if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
revents |= UV__POLLRDHUP;
}
if (ev->filter == EV_OOBAND) {
@ -359,9 +361,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (ev->flags & EV_ERROR)
revents |= POLLERR;
if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
revents |= UV__POLLRDHUP;
if (revents == 0)
continue;

View File

@ -365,24 +365,30 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
const char* inferred_model;
unsigned int model_idx;
unsigned int speed_idx;
unsigned int part_idx;
char buf[1024];
char* model;
FILE* fp;
int model_id;
/* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */
(void) &model_marker;
(void) &speed_marker;
(void) &speed_idx;
(void) &part_idx;
(void) &model;
(void) &buf;
(void) &fp;
(void) &model_id;
model_idx = 0;
speed_idx = 0;
part_idx = 0;
#if defined(__arm__) || \
defined(__i386__) || \
defined(__mips__) || \
defined(__aarch64__) || \
defined(__PPC__) || \
defined(__x86_64__)
fp = uv__open_file("/proc/cpuinfo");
@ -402,11 +408,96 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
continue;
}
}
#if defined(__arm__) || defined(__mips__)
#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
if (model_idx < numcpus) {
#if defined(__arm__)
/* Fallback for pre-3.8 kernels. */
static const char model_marker[] = "Processor\t: ";
#elif defined(__aarch64__)
static const char part_marker[] = "CPU part\t: ";
/* Adapted from: https://github.com/karelzak/util-linux */
struct vendor_part {
const int id;
const char* name;
};
static const struct vendor_part arm_chips[] = {
{ 0x811, "ARM810" },
{ 0x920, "ARM920" },
{ 0x922, "ARM922" },
{ 0x926, "ARM926" },
{ 0x940, "ARM940" },
{ 0x946, "ARM946" },
{ 0x966, "ARM966" },
{ 0xa20, "ARM1020" },
{ 0xa22, "ARM1022" },
{ 0xa26, "ARM1026" },
{ 0xb02, "ARM11 MPCore" },
{ 0xb36, "ARM1136" },
{ 0xb56, "ARM1156" },
{ 0xb76, "ARM1176" },
{ 0xc05, "Cortex-A5" },
{ 0xc07, "Cortex-A7" },
{ 0xc08, "Cortex-A8" },
{ 0xc09, "Cortex-A9" },
{ 0xc0d, "Cortex-A17" }, /* Originally A12 */
{ 0xc0f, "Cortex-A15" },
{ 0xc0e, "Cortex-A17" },
{ 0xc14, "Cortex-R4" },
{ 0xc15, "Cortex-R5" },
{ 0xc17, "Cortex-R7" },
{ 0xc18, "Cortex-R8" },
{ 0xc20, "Cortex-M0" },
{ 0xc21, "Cortex-M1" },
{ 0xc23, "Cortex-M3" },
{ 0xc24, "Cortex-M4" },
{ 0xc27, "Cortex-M7" },
{ 0xc60, "Cortex-M0+" },
{ 0xd01, "Cortex-A32" },
{ 0xd03, "Cortex-A53" },
{ 0xd04, "Cortex-A35" },
{ 0xd05, "Cortex-A55" },
{ 0xd06, "Cortex-A65" },
{ 0xd07, "Cortex-A57" },
{ 0xd08, "Cortex-A72" },
{ 0xd09, "Cortex-A73" },
{ 0xd0a, "Cortex-A75" },
{ 0xd0b, "Cortex-A76" },
{ 0xd0c, "Neoverse-N1" },
{ 0xd0d, "Cortex-A77" },
{ 0xd0e, "Cortex-A76AE" },
{ 0xd13, "Cortex-R52" },
{ 0xd20, "Cortex-M23" },
{ 0xd21, "Cortex-M33" },
{ 0xd41, "Cortex-A78" },
{ 0xd42, "Cortex-A78AE" },
{ 0xd4a, "Neoverse-E1" },
{ 0xd4b, "Cortex-A78C" },
};
if (strncmp(buf, part_marker, sizeof(part_marker) - 1) == 0) {
model = buf + sizeof(part_marker) - 1;
errno = 0;
model_id = strtol(model, NULL, 16);
if ((errno != 0) || model_id < 0) {
fclose(fp);
return UV_EINVAL;
}
for (part_idx = 0; part_idx < ARRAY_SIZE(arm_chips); part_idx++) {
if (model_id == arm_chips[part_idx].id) {
model = uv__strdup(arm_chips[part_idx].name);
if (model == NULL) {
fclose(fp);
return UV_ENOMEM;
}
ci[model_idx++].model = model;
break;
}
}
}
#else /* defined(__mips__) */
static const char model_marker[] = "cpu model\t\t: ";
#endif
@ -421,18 +512,18 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
continue;
}
}
#else /* !__arm__ && !__mips__ */
#else /* !__arm__ && !__mips__ && !__aarch64__ */
if (speed_idx < numcpus) {
if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) {
ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);
continue;
}
}
#endif /* __arm__ || __mips__ */
#endif /* __arm__ || __mips__ || __aarch64__ */
}
fclose(fp);
#endif /* __arm__ || __i386__ || __mips__ || __PPC__ || __x86_64__ */
#endif /* __arm__ || __i386__ || __mips__ || __PPC__ || __x86_64__ || __aarch__ */
/* Now we want to make sure that all the models contain *something* because
* it's not safe to leave them as null. Copy the last entry unless there
@ -697,7 +788,7 @@ uint64_t uv_get_free_memory(void) {
struct sysinfo info;
uint64_t rc;
rc = uv__read_proc_meminfo("MemFree:");
rc = uv__read_proc_meminfo("MemAvailable:");
if (rc != 0)
return rc;

View File

@ -136,6 +136,11 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
}
void uv__os390_cleanup(void) {
msgctl(uv_backend_fd(uv_default_loop()), IPC_RMID, NULL);
}
static void init_message_queue(uv__os390_epoll* lst) {
struct {
long int header;

View File

@ -70,5 +70,6 @@ int sem_destroy(UV_PLATFORM_SEM_T* semid);
int sem_post(UV_PLATFORM_SEM_T* semid);
int sem_trywait(UV_PLATFORM_SEM_T* semid);
int sem_wait(UV_PLATFORM_SEM_T* semid);
void uv__os390_cleanup(void);
#endif /* UV_OS390_SYSCALL_H_ */

View File

@ -26,6 +26,7 @@
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
@ -216,13 +217,32 @@ static void uv__process_child_init(const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
int error_fd) {
sigset_t set;
sigset_t signewset;
int close_fd;
int use_fd;
int err;
int fd;
int n;
/* Reset signal disposition first. 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_errno(error_fd);
}
if (options->flags & UV_PROCESS_DETACHED)
setsid();
@ -304,32 +324,10 @@ static void uv__process_child_init(const uv_process_options_t* options,
environ = options->env;
}
/* Reset signal disposition. Use a hard-coded limit because NSIG
* is not fixed on Linux: it's either 32, 34 or 64, depending on
* whether RT signals are enabled. We are not allowed to touch
* RT signal handlers, glibc uses them internally.
*/
for (n = 1; n < 32; n += 1) {
if (n == SIGKILL || n == SIGSTOP)
continue; /* Can't be changed. */
#if defined(__HAIKU__)
if (n == SIGKILLTHR)
continue; /* Can't be changed. */
#endif
if (SIG_ERR != signal(n, SIG_DFL))
continue;
uv__write_errno(error_fd);
}
/* Reset signal mask. */
sigemptyset(&set);
err = pthread_sigmask(SIG_SETMASK, &set, NULL);
if (err != 0)
uv__write_errno(error_fd);
/* Reset signal mask just before exec. */
sigemptyset(&signewset);
if (sigprocmask(SIG_SETMASK, &signewset, NULL) != 0)
abort();
#ifdef __MVS__
execvpe(options->file, options->args, environ);
@ -338,6 +336,7 @@ static void uv__process_child_init(const uv_process_options_t* options,
#endif
uv__write_errno(error_fd);
abort();
}
#endif
@ -349,6 +348,8 @@ int uv_spawn(uv_loop_t* loop,
/* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
return UV_ENOSYS;
#else
sigset_t signewset;
sigset_t sigoldset;
int signal_pipe[2] = { -1, -1 };
int pipes_storage[8][2];
int (*pipes)[2];
@ -423,25 +424,41 @@ int uv_spawn(uv_loop_t* loop,
/* Acquire write lock to prevent opening new fds in worker threads */
uv_rwlock_wrlock(&loop->cloexec_lock);
pid = fork();
if (pid == -1) {
err = UV__ERR(errno);
uv_rwlock_wrunlock(&loop->cloexec_lock);
uv__close(signal_pipe[0]);
uv__close(signal_pipe[1]);
goto error;
}
if (pid == 0) {
uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
/* Start the child with most signals blocked, to avoid any issues before we
* can reset them, but allow program failures to exit (and not hang). */
sigfillset(&signewset);
sigdelset(&signewset, SIGKILL);
sigdelset(&signewset, SIGSTOP);
sigdelset(&signewset, SIGTRAP);
sigdelset(&signewset, SIGSEGV);
sigdelset(&signewset, SIGBUS);
sigdelset(&signewset, SIGILL);
sigdelset(&signewset, SIGSYS);
sigdelset(&signewset, SIGABRT);
if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0)
abort();
pid = fork();
if (pid == -1)
err = UV__ERR(errno);
if (pid == 0)
uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0)
abort();
}
/* Release lock in parent process */
uv_rwlock_wrunlock(&loop->cloexec_lock);
uv__close(signal_pipe[1]);
if (pid == -1) {
uv__close(signal_pipe[0]);
goto error;
}
process->status = 0;
exec_errorno = 0;
do

View File

@ -1010,7 +1010,6 @@ 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_HANDLE_READ_EOF;
stream->flags &= ~UV_HANDLE_READING;
stream->flags &= ~UV_HANDLE_READABLE;
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
uv__handle_stop(stream);
uv__stream_osx_interrupt_select(stream);
@ -1550,15 +1549,12 @@ int uv__read_start(uv_stream_t* stream,
assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
stream->type == UV_TTY);
/* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just
* expresses the desired state of the user.
*/
/* The UV_HANDLE_READING flag is irrelevant of the state of the stream - it
* just expresses the desired state of the user. */
stream->flags |= UV_HANDLE_READING;
stream->flags &= ~UV_HANDLE_READ_EOF;
/* TODO: try to do the read inline? */
/* TODO: keep track of tcp state. If we've gotten a EOF then we should
* not start the IO watcher.
*/
assert(uv__stream_fd(stream) >= 0);
assert(alloc_cb);

View File

@ -375,8 +375,11 @@ write_queue_drain:
return;
}
/* Safety: npkts known to be >0 below. Hence cast from ssize_t
* to size_t safe.
*/
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
i < pkts && q != &handle->write_queue;
i < (size_t)npkts && q != &handle->write_queue;
++i, q = QUEUE_HEAD(&handle->write_queue)) {
assert(q != NULL);
req = QUEUE_DATA(q, uv_udp_send_t, queue);
@ -651,28 +654,71 @@ int uv__udp_connect(uv_udp_t* handle,
return 0;
}
/* From https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html
* Any of uv supported UNIXs kernel should be standardized, but the kernel
* implementation logic not same, let's use pseudocode to explain the udp
* disconnect behaviors:
*
* Predefined stubs for pseudocode:
* 1. sodisconnect: The function to perform the real udp disconnect
* 2. pru_connect: The function to perform the real udp connect
* 3. so: The kernel object match with socket fd
* 4. addr: The sockaddr parameter from user space
*
* BSDs:
* if(sodisconnect(so) == 0) { // udp disconnect succeed
* if (addr->sa_len != so->addr->sa_len) return EINVAL;
* if (addr->sa_family != so->addr->sa_family) return EAFNOSUPPORT;
* pru_connect(so);
* }
* else return EISCONN;
*
* z/OS (same with Windows):
* if(addr->sa_len < so->addr->sa_len) return EINVAL;
* if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
*
* AIX:
* if(addr->sa_len != sizeof(struct sockaddr)) return EINVAL; // ignore ip proto version
* if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
*
* Linux,Others:
* if(addr->sa_len < sizeof(struct sockaddr)) return EINVAL;
* if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
*/
int uv__udp_disconnect(uv_udp_t* handle) {
int r;
#if defined(__MVS__)
struct sockaddr_storage addr;
#else
struct sockaddr addr;
#endif
memset(&addr, 0, sizeof(addr));
#if defined(__MVS__)
addr.ss_family = AF_UNSPEC;
#else
addr.sa_family = AF_UNSPEC;
#endif
do {
errno = 0;
r = connect(handle->io_watcher.fd, &addr, sizeof(addr));
r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr));
} while (r == -1 && errno == EINTR);
if (r == -1 && errno != EAFNOSUPPORT)
if (r == -1) {
#if defined(BSD) /* The macro BSD is from sys/param.h */
if (errno != EAFNOSUPPORT && errno != EINVAL)
return UV__ERR(errno);
#else
return UV__ERR(errno);
#endif
}
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[],
@ -880,7 +926,7 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
#if !defined(__OpenBSD__) && \
!defined(__NetBSD__) && \
!defined(__ANDROID__) && \
!defined(__DragonFly__) & \
!defined(__DragonFly__) && \
!defined(__QNX__)
static int uv__udp_set_source_membership4(uv_udp_t* handle,
const struct sockaddr_in* multicast_addr,