libuv 1.48.0.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4828 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
2024-02-07 23:12:32 +00:00
parent e98802f5b2
commit 6765254f43
53 changed files with 1172 additions and 305 deletions

View File

@ -90,6 +90,7 @@ extern char** environ;
#if defined(__linux__)
# include <sched.h>
# include <sys/syscall.h>
# define gettid() syscall(SYS_gettid)
# define uv__accept4 accept4
#endif
@ -1557,6 +1558,130 @@ int uv_os_setpriority(uv_pid_t pid, int priority) {
return 0;
}
/**
* If the function succeeds, the return value is 0.
* If the function fails, the return value is non-zero.
* for Linux, when schedule policy is SCHED_OTHER (default), priority is 0.
* So the output parameter priority is actually the nice value.
*/
int uv_thread_getpriority(uv_thread_t tid, int* priority) {
int r;
int policy;
struct sched_param param;
#ifdef __linux__
pid_t pid = gettid();
#endif
if (priority == NULL)
return UV_EINVAL;
r = pthread_getschedparam(tid, &policy, &param);
if (r != 0)
return UV__ERR(errno);
#ifdef __linux__
if (SCHED_OTHER == policy && pthread_equal(tid, pthread_self())) {
errno = 0;
r = getpriority(PRIO_PROCESS, pid);
if (r == -1 && errno != 0)
return UV__ERR(errno);
*priority = r;
return 0;
}
#endif
*priority = param.sched_priority;
return 0;
}
#ifdef __linux__
static int set_nice_for_calling_thread(int priority) {
int r;
int nice;
if (priority < UV_THREAD_PRIORITY_LOWEST || priority > UV_THREAD_PRIORITY_HIGHEST)
return UV_EINVAL;
pid_t pid = gettid();
nice = 0 - priority * 2;
r = setpriority(PRIO_PROCESS, pid, nice);
if (r != 0)
return UV__ERR(errno);
return 0;
}
#endif
/**
* If the function succeeds, the return value is 0.
* If the function fails, the return value is non-zero.
*/
int uv_thread_setpriority(uv_thread_t tid, int priority) {
int r;
int min;
int max;
int range;
int prio;
int policy;
struct sched_param param;
if (priority < UV_THREAD_PRIORITY_LOWEST || priority > UV_THREAD_PRIORITY_HIGHEST)
return UV_EINVAL;
r = pthread_getschedparam(tid, &policy, &param);
if (r != 0)
return UV__ERR(errno);
#ifdef __linux__
/**
* for Linux, when schedule policy is SCHED_OTHER (default), priority must be 0,
* we should set the nice value in this case.
*/
if (SCHED_OTHER == policy && pthread_equal(tid, pthread_self()))
return set_nice_for_calling_thread(priority);
#endif
#ifdef __PASE__
min = 1;
max = 127;
#else
min = sched_get_priority_min(policy);
max = sched_get_priority_max(policy);
#endif
if (min == -1 || max == -1)
return UV__ERR(errno);
range = max - min;
switch (priority) {
case UV_THREAD_PRIORITY_HIGHEST:
prio = max;
break;
case UV_THREAD_PRIORITY_ABOVE_NORMAL:
prio = min + range * 3 / 4;
break;
case UV_THREAD_PRIORITY_NORMAL:
prio = min + range / 2;
break;
case UV_THREAD_PRIORITY_BELOW_NORMAL:
prio = min + range / 4;
break;
case UV_THREAD_PRIORITY_LOWEST:
prio = min;
break;
default:
return 0;
}
if (param.sched_priority != prio) {
param.sched_priority = prio;
r = pthread_setschedparam(tid, policy, &param);
if (r != 0)
return UV__ERR(errno);
}
return 0;
}
int uv_os_uname(uv_utsname_t* buffer) {
struct utsname buf;

View File

@ -84,7 +84,9 @@
#if defined(__CYGWIN__) || \
(defined(__HAIKU__) && B_HAIKU_VERSION < B_HAIKU_VERSION_1_PRE_BETA_5) || \
(defined(__sun) && !defined(__illumos__))
(defined(__sun) && !defined(__illumos__)) || \
(defined(__APPLE__) && !TARGET_OS_IPHONE && \
MAC_OS_X_VERSION_MIN_REQUIRED < 110000)
#define preadv(fd, bufs, nbufs, off) \
pread(fd, (bufs)->iov_base, (bufs)->iov_len, off)
#define pwritev(fd, bufs, nbufs, off) \
@ -1628,6 +1630,16 @@ static void uv__fs_done(struct uv__work* w, int status) {
}
void uv__fs_post(uv_loop_t* loop, uv_fs_t* req) {
uv__req_register(loop, req);
uv__work_submit(loop,
&req->work_req,
UV__WORK_FAST_IO,
uv__fs_work,
uv__fs_done);
}
int uv_fs_access(uv_loop_t* loop,
uv_fs_t* req,
const char* path,

View File

@ -425,6 +425,7 @@ UV_UNUSED(static int uv__stat(const char* path, struct stat* s)) {
}
#if defined(__linux__)
void uv__fs_post(uv_loop_t* loop, uv_fs_t* req);
ssize_t
uv__fs_copy_file_range(int fd_in,
off_t* off_in,

View File

@ -488,11 +488,21 @@ static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
* the struct's kf_structsize must be initialised beforehand
* whether with the KINFO_FILE_SIZE constant or this way.
*/
struct stat statbuf;
struct kinfo_file kf;
kf.kf_structsize = sizeof(kf);
if (fcntl(handle->event_watcher.fd, F_KINFO, &kf) == 0)
path = uv__basename_r(kf.kf_path);
if (handle->event_watcher.fd != -1 &&
(!uv__fstat(handle->event_watcher.fd, &statbuf) && !(statbuf.st_mode & S_IFDIR))) {
/* we are purposely not using KINFO_FILE_SIZE here
* as it is not available on non intl archs
* and here it gives 1392 too on intel.
* anyway, the man page also mentions we can proceed
* this way.
*/
kf.kf_structsize = sizeof(kf);
if (fcntl(handle->event_watcher.fd, F_KINFO, &kf) == 0)
path = uv__basename_r(kf.kf_path);
}
#endif
handle->cb(handle, path, events, 0);

View File

@ -37,12 +37,16 @@
#include <errno.h>
#include <fcntl.h>
#include <ifaddrs.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/sysinfo.h>
@ -120,25 +124,6 @@
# endif
#endif /* __NR_getrandom */
#define HAVE_IFADDRS_H 1
# if defined(__ANDROID_API__) && __ANDROID_API__ < 24
# undef HAVE_IFADDRS_H
#endif
#ifdef __UCLIBC__
# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32
# undef HAVE_IFADDRS_H
# endif
#endif
#ifdef HAVE_IFADDRS_H
# include <ifaddrs.h>
# include <sys/socket.h>
# include <net/ethernet.h>
# include <netpacket/packet.h>
#endif /* HAVE_IFADDRS_H */
enum {
UV__IORING_SETUP_SQPOLL = 2u,
};
@ -478,6 +463,9 @@ static int uv__use_io_uring(void) {
#elif defined(__arm__) && __SIZEOF_POINTER__ == 4
/* See https://github.com/libuv/libuv/issues/4158. */
return 0; /* All 32 bits kernels appear buggy. */
#elif defined(__powerpc64__) || defined(__ppc64__)
/* See https://github.com/libuv/libuv/issues/4283. */
return 0; /* Random SIGSEGV in signal handler. */
#else
/* Ternary: unknown=0, yes=1, no=-1 */
static _Atomic int use_io_uring;
@ -487,8 +475,16 @@ static int uv__use_io_uring(void) {
use = atomic_load_explicit(&use_io_uring, memory_order_relaxed);
if (use == 0) {
use = uv__kernel_version() >=
#if defined(__hppa__)
/* io_uring first supported on parisc in 6.1, functional in .51 */
/* https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/ */
/* 6.1.51 */ 0x060133
#else
/* Older kernels have a bug where the sqpoll thread uses 100% CPU. */
use = uv__kernel_version() >= /* 5.10.186 */ 0x050ABA ? 1 : -1;
/* 5.10.186 */ 0x050ABA
#endif
? 1 : -1;
/* But users can still enable it if they so desire. */
val = getenv("UV_USE_IO_URING");
@ -1162,6 +1158,12 @@ static void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) {
uv__req_unregister(loop, req);
iou->in_flight--;
/* If the op is not supported by the kernel retry using the thread pool */
if (e->res == -EOPNOTSUPP) {
uv__fs_post(loop, req);
continue;
}
/* io_uring stores error codes as negative numbers, same as libuv. */
req->result = e->res;
@ -1908,7 +1910,6 @@ nocpuinfo:
}
#ifdef HAVE_IFADDRS_H
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
return 1;
@ -1922,14 +1923,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
return exclude_type;
return !exclude_type;
}
#endif
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
#ifndef HAVE_IFADDRS_H
*count = 0;
*addresses = NULL;
return UV_ENOSYS;
#else
struct ifaddrs *addrs, *ent;
uv_interface_address_t* address;
int i;
@ -2008,7 +2003,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
freeifaddrs(addrs);
return 0;
#endif
}

View File

@ -30,6 +30,19 @@
#include <stdlib.h>
/* Does the file path contain embedded nul bytes? */
static int includes_nul(const char *s, size_t n) {
if (n == 0)
return 0;
#ifdef __linux__
/* Accept abstract socket namespace path ("\0/virtual/path"). */
s++;
n--;
#endif
return NULL != memchr(s, '\0', n);
}
int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
handle->shutdown_req = NULL;
@ -53,6 +66,7 @@ int uv_pipe_bind2(uv_pipe_t* handle,
char* pipe_fname;
int sockfd;
int err;
socklen_t addrlen;
pipe_fname = NULL;
@ -65,11 +79,8 @@ int uv_pipe_bind2(uv_pipe_t* handle,
if (namelen == 0)
return UV_EINVAL;
#ifndef __linux__
/* Abstract socket namespace only works on Linux. */
if (*name == '\0')
if (includes_nul(name, namelen))
return UV_EINVAL;
#endif
if (flags & UV_PIPE_NO_TRUNCATE)
if (namelen > sizeof(saddr.sun_path))
@ -90,10 +101,15 @@ int uv_pipe_bind2(uv_pipe_t* handle,
* We unlink the file later but abstract sockets disappear
* automatically since they're not real file system entities.
*/
if (*name != '\0') {
pipe_fname = uv__strdup(name);
if (*name == '\0') {
addrlen = offsetof(struct sockaddr_un, sun_path) + namelen;
} else {
pipe_fname = uv__malloc(namelen + 1);
if (pipe_fname == NULL)
return UV_ENOMEM;
memcpy(pipe_fname, name, namelen);
pipe_fname[namelen] = '\0';
addrlen = sizeof saddr;
}
err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
@ -105,7 +121,7 @@ int uv_pipe_bind2(uv_pipe_t* handle,
memcpy(&saddr.sun_path, name, namelen);
saddr.sun_family = AF_UNIX;
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
if (bind(sockfd, (struct sockaddr*)&saddr, addrlen)) {
err = UV__ERR(errno);
/* Convert ENOENT to EACCES for compatibility with Windows. */
if (err == UV_ENOENT)
@ -117,7 +133,7 @@ int uv_pipe_bind2(uv_pipe_t* handle,
/* Success. */
handle->flags |= UV_HANDLE_BOUND;
handle->pipe_fname = pipe_fname; /* NULL or a strdup'ed copy. */
handle->pipe_fname = pipe_fname; /* NULL or a copy of |name| */
handle->io_watcher.fd = sockfd;
return 0;
@ -210,7 +226,22 @@ void uv_pipe_connect(uv_connect_t* req,
uv_pipe_t* handle,
const char* name,
uv_connect_cb cb) {
uv_pipe_connect2(req, handle, name, strlen(name), 0, cb);
int err;
err = uv_pipe_connect2(req, handle, name, strlen(name), 0, cb);
if (err) {
handle->delayed_error = err;
handle->connect_req = req;
uv__req_init(handle->loop, req, UV_CONNECT);
req->handle = (uv_stream_t*) handle;
req->cb = cb;
uv__queue_init(&req->queue);
/* Force callback to run on next tick in case of error. */
uv__io_feed(handle->loop, &handle->io_watcher);
}
}
@ -224,6 +255,7 @@ int uv_pipe_connect2(uv_connect_t* req,
int new_sock;
int err;
int r;
socklen_t addrlen;
if (flags & ~UV_PIPE_NO_TRUNCATE)
return UV_EINVAL;
@ -234,11 +266,8 @@ int uv_pipe_connect2(uv_connect_t* req,
if (namelen == 0)
return UV_EINVAL;
#ifndef __linux__
/* Abstract socket namespace only works on Linux. */
if (*name == '\0')
if (includes_nul(name, namelen))
return UV_EINVAL;
#endif
if (flags & UV_PIPE_NO_TRUNCATE)
if (namelen > sizeof(saddr.sun_path))
@ -261,9 +290,13 @@ int uv_pipe_connect2(uv_connect_t* req,
memcpy(&saddr.sun_path, name, namelen);
saddr.sun_family = AF_UNIX;
if (*name == '\0')
addrlen = offsetof(struct sockaddr_un, sun_path) + namelen;
else
addrlen = sizeof saddr;
do {
r = connect(uv__stream_fd(handle),
(struct sockaddr*)&saddr, sizeof saddr);
r = connect(uv__stream_fd(handle), (struct sockaddr*)&saddr, addrlen);
}
while (r == -1 && errno == EINTR);
@ -295,7 +328,7 @@ out:
handle->connect_req = req;
uv__req_init(handle->loop, req, UV_CONNECT);
req->handle = (uv_stream_t*)handle;
req->handle = (uv_stream_t*) handle;
req->cb = cb;
uv__queue_init(&req->queue);

View File

@ -972,6 +972,7 @@ int uv_spawn(uv_loop_t* loop,
assert(!(options->flags & ~(UV_PROCESS_DETACHED |
UV_PROCESS_SETGID |
UV_PROCESS_SETUID |
UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME |
UV_PROCESS_WINDOWS_HIDE |
UV_PROCESS_WINDOWS_HIDE_CONSOLE |
UV_PROCESS_WINDOWS_HIDE_GUI |

View File

@ -30,12 +30,8 @@
#include <sys/types.h>
#include <sys/socket.h>
#if defined(__PASE__)
#include <as400_protos.h>
#define ifaddrs ifaddrs_pase
#define getifaddrs Qp2getifaddrs
#define freeifaddrs Qp2freeifaddrs
#else
/* ifaddrs is not implemented on AIX and IBM i PASE */
#if !defined(_AIX)
#include <ifaddrs.h>
#endif
@ -225,16 +221,39 @@ static int uv__is_ipv6_link_local(const struct sockaddr* addr) {
static int uv__ipv6_link_local_scope_id(void) {
struct sockaddr_in6* a6;
int rv;
#if defined(_AIX)
/* AIX & IBM i do not have ifaddrs
* so fallback to use uv_interface_addresses */
uv_interface_address_t* interfaces;
uv_interface_address_t* ifa;
int count, i;
if (uv_interface_addresses(&interfaces, &count))
return 0;
rv = 0;
for (ifa = interfaces; ifa != &interfaces[count]; ifa++) {
if (uv__is_ipv6_link_local((struct sockaddr*) &ifa->address)) {
rv = ifa->address.address6.sin6_scope_id;
break;
}
}
uv_free_interface_addresses(interfaces, count);
#else
struct ifaddrs* ifa;
struct ifaddrs* p;
int rv;
if (getifaddrs(&ifa))
return 0;
for (p = ifa; p != NULL; p = p->ifa_next)
if (uv__is_ipv6_link_local(p->ifa_addr))
break;
if (p->ifa_addr != NULL)
if (uv__is_ipv6_link_local(p->ifa_addr))
break;
rv = 0;
if (p != NULL) {
@ -243,6 +262,8 @@ static int uv__ipv6_link_local_scope_id(void) {
}
freeifaddrs(ifa);
#endif /* defined(_AIX) */
return rv;
}
@ -432,26 +453,91 @@ int uv__tcp_nodelay(int fd, int on) {
int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
int idle;
int intvl;
int cnt;
(void) &idle;
(void) &intvl;
(void) &cnt;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
return UV__ERR(errno);
if (!on)
return 0;
if (delay == 0)
return -1;
#ifdef __sun
/* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual
* compared to other Unix-like systems.
* Thus, we need to specialize it on Solaris.
*
* There are two keep-alive mechanisms on Solaris:
* - By default, the first keep-alive probe is sent out after a TCP connection is idle for two hours.
* If the peer does not respond to the probe within eight minutes, the TCP connection is aborted.
* You can alter the interval for sending out the first probe using the socket option TCP_KEEPALIVE_THRESHOLD
* in milliseconds or TCP_KEEPIDLE in seconds.
* The system default is controlled by the TCP ndd parameter tcp_keepalive_interval. The minimum value is ten seconds.
* The maximum is ten days, while the default is two hours. If you receive no response to the probe,
* you can use the TCP_KEEPALIVE_ABORT_THRESHOLD socket option to change the time threshold for aborting a TCP connection.
* The option value is an unsigned integer in milliseconds. The value zero indicates that TCP should never time out and
* abort the connection when probing. The system default is controlled by the TCP ndd parameter tcp_keepalive_abort_interval.
* The default is eight minutes.
*
* - The second implementation is activated if socket option TCP_KEEPINTVL and/or TCP_KEEPCNT are set.
* The time between each consequent probes is set by TCP_KEEPINTVL in seconds.
* The minimum value is ten seconds. The maximum is ten days, while the default is two hours.
* The TCP connection will be aborted after certain amount of probes, which is set by TCP_KEEPCNT, without receiving response.
*/
idle = delay;
/* Kernel expects at least 10 seconds. */
if (idle < 10)
idle = 10;
/* Kernel expects at most 10 days. */
if (idle > 10*24*60*60)
idle = 10*24*60*60;
/* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris
* until version 11.4, but let's take a chance here. */
#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)))
return UV__ERR(errno);
intvl = idle/3;
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
return UV__ERR(errno);
cnt = 3;
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
return UV__ERR(errno);
#else
/* Fall back to the first implementation of tcp-alive mechanism for older Solaris,
* simulate the tcp-alive mechanism on other platforms via `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`.
*/
idle *= 1000; /* kernel expects milliseconds */
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &idle, sizeof(idle)))
return UV__ERR(errno);
/* Note that the consequent probes will not be sent at equal intervals on Solaris,
* but will be sent using the exponential backoff algorithm. */
intvl = idle/3;
cnt = 3;
int time_to_abort = intvl * cnt;
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort)))
return UV__ERR(errno);
#endif
#else /* !defined(__sun) */
#ifdef TCP_KEEPIDLE
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
return UV__ERR(errno);
/* Solaris/SmartOS, if you don't support keep-alive,
* then don't advertise it in your system headers...
*/
/* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
#elif defined(TCP_KEEPALIVE) && !defined(__sun)
#elif defined(TCP_KEEPALIVE)
/* Darwin/macOS uses TCP_KEEPALIVE in place of TCP_KEEPIDLE. */
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
return UV__ERR(errno);
#endif
@ -468,6 +554,7 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
return UV__ERR(errno);
#endif
#endif /* !defined(__sun) */
return 0;
}