diff --git a/src/include/override/sys/epoll.h b/src/include/override/sys/epoll.h index 0ed9c27a4b..123283cf09 100644 --- a/src/include/override/sys/epoll.h +++ b/src/include/override/sys/epoll.h @@ -3,8 +3,11 @@ #include_next /* IWYU pragma: export */ -/* epoll_pwait2() was added to glibc 2.35. Redirect to a shim that sets errno=ENOSYS at runtime when - * the libc symbol isn't available, so callers don't need to worry about the libc version. */ -int epoll_pwait2_shim(int fd, struct epoll_event *events, int maxevents, - const struct timespec *timeout, const sigset_t *sigmask); -#define epoll_pwait2 epoll_pwait2_shim +/* epoll_pwait2() was added in glibc 2.35 and is currently unavailable in musl. + * Call the syscall directly instead of relying on the libc wrapper. */ +int missing_epoll_pwait2( + int fd, + struct epoll_event *events, + int maxevents, + const struct timespec *timeout, + const sigset_t *sigmask); diff --git a/src/libc/epoll.c b/src/libc/epoll.c index a7d4075f37..9bd16450c2 100644 --- a/src/libc/epoll.c +++ b/src/libc/epoll.c @@ -1,26 +1,35 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include /* IWYU pragma: keep */ +#include #include +#include +#include -#include "libc-shim.h" +int missing_epoll_pwait2( + int fd, + struct epoll_event *events, + int maxevents, + const struct timespec *timeout, + const sigset_t *sigmask) { -/* On 32-bit architectures built with _TIME_BITS=64, glibc renames epoll_pwait2() to - * __epoll_pwait2_time64 via __asm__() in so the linker picks the variant whose - * struct timespec ABI matches our 64-bit time_t. dlsym() can't see that header-level rename, so - * we have to spell out the right name here, otherwise we'd silently dispatch a 64-bit timespec to - * the legacy 32-bit-time_t entry point. */ -#ifdef __USE_TIME_BITS64 -DEFINE_LIBC_ERRNO_SHIM_NAMED(epoll_pwait2, "__epoll_pwait2_time64", int, - int, fd, - struct epoll_event *, events, - int, maxevents, - const struct timespec *, timeout, - const sigset_t *, sigmask) -#else -DEFINE_LIBC_ERRNO_SHIM(epoll_pwait2, int, - int, fd, - struct epoll_event *, events, - int, maxevents, - const struct timespec *, timeout, - const sigset_t *, sigmask) -#endif + /* We intentionally reject non-NULL sigmask to avoid depending on the architecture-specific kernel + * sigset_t size. If sigmask support is ever added, the correct sigsetsize must be passed to the + * syscall. */ + if (sigmask) { + errno = EINVAL; + return -1; + } + + /* Convert struct timespec to struct __kernel_timespec, as they may differ. */ + struct __kernel_timespec t, *p = NULL; + if (timeout) { + t = (struct __kernel_timespec) { + .tv_sec = timeout->tv_sec, + .tv_nsec = timeout->tv_nsec, + }; + p = &t; + } + + return syscall(__NR_epoll_pwait2, fd, events, maxevents, p, /* sigmask= */ NULL, /* sigsetsize= */ 0); +} diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 590ac06b8e..dd293a89fd 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -4631,14 +4631,16 @@ static int epoll_wait_usec( static bool epoll_pwait2_absent = false; int r, msec; - /* A wrapper that uses epoll_pwait2() if available, and falls back to epoll_wait() if not. */ + + /* A wrapper that uses missing_epoll_pwait2(), which directly calls epoll_pwait2 syscall. */ if (!epoll_pwait2_absent && timeout != USEC_INFINITY) { - r = epoll_pwait2(fd, - events, - maxevents, - TIMESPEC_STORE(timeout), - NULL); + r = missing_epoll_pwait2( + fd, + events, + maxevents, + TIMESPEC_STORE(timeout), + /* sigmask= */ NULL); if (r >= 0) return r; if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))