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.
This commit is contained in:
Frank Praznik
2025-10-17 12:35:04 -04:00
parent 201ad7f79b
commit 427f838f58
3 changed files with 22 additions and 39 deletions

View File

@@ -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)

View File

@@ -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 */

View File

@@ -23,15 +23,13 @@
#include "SDL_poll.h"
#ifdef HAVE_POLL
#include <poll.h>
#else
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#include <errno.h>
#ifdef HAVE_PPOLL
#include <time.h>
#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;