From 427f838f5868271a89a85d1763e9abdef28ab63f Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Fri, 17 Oct 2025 12:35:04 -0400 Subject: [PATCH] unix: Add ppoll support Allows for finer grained timeout values, and fixes a FIXME. This also drops the legacy select() fallback path in favor of presuming that poll() is always available. poll() is part of the POSIX.1-2001 standard, has been available in Unix since some time in the 1980s, the BSDs since at least the early 90s, and Linux since kernel 2.1, which predates kernel support for Pthreads. glibc also has its own emulation using select(), if necessary. --- CMakeLists.txt | 2 +- include/build_config/SDL_build_config.h.cmake | 2 +- src/core/unix/SDL_poll.c | 57 +++++++------------ 3 files changed, 22 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d7e5d3b409..9e19336771 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1151,7 +1151,7 @@ if(SDL_LIBC) check_symbol_exists(sysctlbyname "sys/types.h;sys/sysctl.h" HAVE_SYSCTLBYNAME) check_symbol_exists(getauxval "sys/auxv.h" HAVE_GETAUXVAL) check_symbol_exists(elf_aux_info "sys/auxv.h" HAVE_ELF_AUX_INFO) - check_symbol_exists(poll "poll.h" HAVE_POLL) + check_symbol_exists(ppoll "poll.h" HAVE_PPOLL) check_symbol_exists(memfd_create "sys/mman.h" HAVE_MEMFD_CREATE) check_symbol_exists(posix_fallocate "fcntl.h" HAVE_POSIX_FALLOCATE) check_symbol_exists(posix_spawn_file_actions_addchdir "spawn.h" HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR) diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index b4e721ca6b..36d642e705 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -199,7 +199,7 @@ #cmakedefine HAVE_SEM_TIMEDWAIT 1 #cmakedefine HAVE_GETAUXVAL 1 #cmakedefine HAVE_ELF_AUX_INFO 1 -#cmakedefine HAVE_POLL 1 +#cmakedefine HAVE_PPOLL 1 #cmakedefine HAVE__EXIT 1 #endif /* HAVE_LIBC */ diff --git a/src/core/unix/SDL_poll.c b/src/core/unix/SDL_poll.c index 572ed5a65b..d84a217863 100644 --- a/src/core/unix/SDL_poll.c +++ b/src/core/unix/SDL_poll.c @@ -23,15 +23,13 @@ #include "SDL_poll.h" -#ifdef HAVE_POLL #include -#else -#include -#include -#include -#endif #include +#ifdef HAVE_PPOLL +#include +#endif + int SDL_IOReady(int fd, int flags, Sint64 timeoutNS) { int result; @@ -40,9 +38,7 @@ int SDL_IOReady(int fd, int flags, Sint64 timeoutNS) // Note: We don't bother to account for elapsed time if we get EINTR do { -#ifdef HAVE_POLL struct pollfd info; - int timeoutMS; info.fd = fd; info.events = 0; @@ -52,7 +48,21 @@ int SDL_IOReady(int fd, int flags, Sint64 timeoutNS) if (flags & SDL_IOR_WRITE) { info.events |= POLLOUT; } - // FIXME: Add support for ppoll() for nanosecond precision + +#ifdef HAVE_PPOLL + struct timespec *timeout = NULL; + struct timespec ts; + + if (timeoutNS >= 0) { + ts.tv_sec = SDL_NS_TO_SECONDS(timeoutNS); + ts.tv_nsec = timeoutNS - SDL_SECONDS_TO_NS(ts.tv_sec); + timeout = &ts; + } + + result = ppoll(&info, 1, timeout, NULL); +#else + int timeoutMS; + if (timeoutNS > 0) { timeoutMS = (int)SDL_NS_TO_MS(timeoutNS + (SDL_NS_PER_MS - 1)); } else if (timeoutNS == 0) { @@ -61,34 +71,7 @@ int SDL_IOReady(int fd, int flags, Sint64 timeoutNS) timeoutMS = -1; } result = poll(&info, 1, timeoutMS); -#else - fd_set rfdset, *rfdp = NULL; - fd_set wfdset, *wfdp = NULL; - struct timeval tv, *tvp = NULL; - - // If this assert triggers we'll corrupt memory here - SDL_assert(fd >= 0 && fd < FD_SETSIZE); - - if (flags & SDL_IOR_READ) { - FD_ZERO(&rfdset); - FD_SET(fd, &rfdset); - rfdp = &rfdset; - } - if (flags & SDL_IOR_WRITE) { - FD_ZERO(&wfdset); - FD_SET(fd, &wfdset); - wfdp = &wfdset; - } - - if (timeoutNS >= 0) { - tv.tv_sec = (timeoutNS / SDL_NS_PER_SECOND); - tv.tv_usec = SDL_NS_TO_US((timeoutNS % SDL_NS_PER_SECOND) + (SDL_NS_PER_US - 1)); - tvp = &tv; - } - - result = select(fd + 1, rfdp, wfdp, NULL, tvp); -#endif // HAVE_POLL - +#endif } while (result < 0 && errno == EINTR && !(flags & SDL_IOR_NO_RETRY)); return result;