1
0
mirror of https://github.com/libuv/libuv synced 2025-03-28 21:13:16 +00:00

unix: reinstate preadv/pwritev fallback code (#4345)

I removed the fallback code back in October but it prevents Node.js
from upgrading libuv in their v20.x release line because they support
systems older than we do. Bring back a dlsym-based fallback path.

Fixes: https://github.com/libuv/libuv/issues/4332
This commit is contained in:
Ben Noordhuis 2024-03-20 18:39:18 +01:00 committed by GitHub
parent e0c5fc8714
commit cc23e204d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -31,6 +31,7 @@
#include <errno.h>
#include <dlfcn.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -82,17 +83,6 @@
# include <sys/statfs.h>
#endif
#if defined(__CYGWIN__) || \
(defined(__HAIKU__) && B_HAIKU_VERSION < B_HAIKU_VERSION_1_PRE_BETA_5) || \
(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) \
pwrite(fd, (bufs)->iov_base, (bufs)->iov_len, off)
#endif
#if defined(_AIX) && _XOPEN_SOURCE <= 600
extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
#endif
@ -406,6 +396,115 @@ static ssize_t uv__fs_open(uv_fs_t* req) {
}
static ssize_t uv__preadv_or_pwritev_emul(int fd,
const struct iovec* bufs,
size_t nbufs,
off_t off,
int is_pread) {
ssize_t total;
ssize_t r;
size_t i;
size_t n;
void* p;
total = 0;
for (i = 0; i < (size_t) nbufs; i++) {
p = bufs[i].iov_base;
n = bufs[i].iov_len;
do
if (is_pread)
r = pread(fd, p, n, off);
else
r = pwrite(fd, p, n, off);
while (r == -1 && errno == EINTR);
if (r == -1) {
if (total > 0)
return total;
return -1;
}
off += r;
total += r;
if ((size_t) r < n)
return total;
}
return total;
}
#ifdef __linux__
typedef int uv__iovcnt;
#else
typedef size_t uv__iovcnt;
#endif
static ssize_t uv__preadv_emul(int fd,
const struct iovec* bufs,
uv__iovcnt nbufs,
off_t off) {
return uv__preadv_or_pwritev_emul(fd, bufs, nbufs, off, /*is_pread*/1);
}
static ssize_t uv__pwritev_emul(int fd,
const struct iovec* bufs,
uv__iovcnt nbufs,
off_t off) {
return uv__preadv_or_pwritev_emul(fd, bufs, nbufs, off, /*is_pread*/0);
}
/* The function pointer cache is an uintptr_t because _Atomic void*
* doesn't work on macos/ios/etc...
*/
static ssize_t uv__preadv_or_pwritev(int fd,
const struct iovec* bufs,
size_t nbufs,
off_t off,
_Atomic uintptr_t* cache,
int is_pread) {
ssize_t (*f)(int, const struct iovec*, uv__iovcnt, off_t);
void* p;
p = (void*) atomic_load_explicit(cache, memory_order_relaxed);
if (p == NULL) {
#ifdef RTLD_DEFAULT
p = dlsym(RTLD_DEFAULT, is_pread ? "preadv" : "pwritev");
dlerror(); /* Clear errors. */
#endif /* RTLD_DEFAULT */
if (p == NULL)
p = is_pread ? uv__preadv_emul : uv__pwritev_emul;
atomic_store_explicit(cache, (uintptr_t) p, memory_order_relaxed);
}
f = p;
return f(fd, bufs, nbufs, off);
}
static ssize_t uv__preadv(int fd,
const struct iovec* bufs,
size_t nbufs,
off_t off) {
static _Atomic uintptr_t cache;
return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/1);
}
static ssize_t uv__pwritev(int fd,
const struct iovec* bufs,
size_t nbufs,
off_t off) {
static _Atomic uintptr_t cache;
return uv__preadv_or_pwritev(fd, bufs, nbufs, off, &cache, /*is_pread*/0);
}
static ssize_t uv__fs_read(uv_fs_t* req) {
const struct iovec* bufs;
unsigned int iovmax;
@ -433,7 +532,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
if (nbufs == 1)
r = pread(fd, bufs->iov_base, bufs->iov_len, off);
else if (nbufs > 1)
r = preadv(fd, bufs, nbufs, off);
r = uv__preadv(fd, bufs, nbufs, off);
}
#ifdef __PASE__
@ -1121,7 +1220,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
if (nbufs == 1)
r = pwrite(fd, bufs->iov_base, bufs->iov_len, off);
else if (nbufs > 1)
r = pwritev(fd, bufs, nbufs, off);
r = uv__pwritev(fd, bufs, nbufs, off);
}
return r;