From 112453b9a2f86d3e20c0f898203365388a5c6656 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Sat, 23 May 2026 10:33:12 +0000 Subject: [PATCH] io-util: Drop faulty assumption that poll flags == epoll flags Not the case on the sparc architecture. Replace with two translation functions. The poll to epoll variant isn't used yet but will be used when we add io-uring support to sd-event so we already add it here so that it is in place. Follow-up for cf4c65afa86021a750de38bbed192eeb1c9fd425 --- src/basic/io-util.c | 24 +++++++++++++++++------- src/basic/io-util.h | 11 ++++++----- src/libsystemd/sd-future/fiber-io.c | 2 +- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/basic/io-util.c b/src/basic/io-util.c index 3dbc3670a4..d4a95128c8 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -13,13 +13,23 @@ #include "io-util.h" #include "time-util.h" -/* EPOLL_POLL_COMMON_MASK in io-util.h treats POLL* and EPOLL* as interchangeable; verify it. */ -assert_cc((uint32_t) POLLIN == EPOLLIN); -assert_cc((uint32_t) POLLOUT == EPOLLOUT); -assert_cc((uint32_t) POLLERR == EPOLLERR); -assert_cc((uint32_t) POLLHUP == EPOLLHUP); -assert_cc((uint32_t) POLLPRI == EPOLLPRI); -assert_cc((uint32_t) POLLRDHUP == EPOLLRDHUP); +uint32_t poll_events_to_epoll(uint32_t events) { + return (events & POLLIN ? EPOLLIN : 0) | + (events & POLLOUT ? EPOLLOUT : 0) | + (events & POLLPRI ? EPOLLPRI : 0) | + (events & POLLERR ? EPOLLERR : 0) | + (events & POLLHUP ? EPOLLHUP : 0) | + (events & POLLRDHUP ? EPOLLRDHUP : 0); +} + +uint32_t epoll_events_to_poll(uint32_t events) { + return (events & EPOLLIN ? POLLIN : 0) | + (events & EPOLLOUT ? POLLOUT : 0) | + (events & EPOLLPRI ? POLLPRI : 0) | + (events & EPOLLERR ? POLLERR : 0) | + (events & EPOLLHUP ? POLLHUP : 0) | + (events & EPOLLRDHUP ? POLLRDHUP : 0); +} int flush_fd(int fd) { int count = 0; diff --git a/src/basic/io-util.h b/src/basic/io-util.h index ab52dc8db6..6697f88b54 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -3,11 +3,12 @@ #include "basic-forward.h" -/* The intersection of poll() and epoll_wait() event masks. Linux defines POLL* and EPOLL* with the - * same numeric values for these — see the assert_cc()s in io-util.c — so this mask can be used - * interchangeably as a `revents` (poll) or `events` (epoll) bitset. */ -#define EPOLL_POLL_COMMON_MASK \ - (EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLRDHUP) +/* On most architectures POLL* and EPOLL* share numeric values, but sparc allocates POLLRDHUP at + * 0x800 while EPOLLRDHUP is 0x2000 everywhere. Always go through these helpers when crossing + * between poll() and epoll() event masks. Bits outside the mapped set (EPOLLET, EPOLLONESHOT, + * POLLNVAL, …) are dropped. */ +uint32_t poll_events_to_epoll(uint32_t events); +uint32_t epoll_events_to_poll(uint32_t events); int flush_fd(int fd); diff --git a/src/libsystemd/sd-future/fiber-io.c b/src/libsystemd/sd-future/fiber-io.c index 823e890718..9fe0acfccd 100644 --- a/src/libsystemd/sd-future/fiber-io.c +++ b/src/libsystemd/sd-future/fiber-io.c @@ -410,7 +410,7 @@ int sd_fiber_ppoll(struct pollfd *fds, size_t n_fds, const struct timespec *time if (fds[i].fd < 0) continue; - uint32_t events = fds[i].events & EPOLL_POLL_COMMON_MASK; + uint32_t events = poll_events_to_epoll(fds[i].events); if (events == 0) continue;