Browse Source

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.
Frank Praznik 1 month ago
parent
commit
427f838f58
3 changed files with 22 additions and 39 deletions
  1. 1 1
      CMakeLists.txt
  2. 1 1
      include/build_config/SDL_build_config.h.cmake
  3. 20 37
      src/core/unix/SDL_poll.c

+ 1 - 1
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)

+ 1 - 1
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 */

+ 20 - 37
src/core/unix/SDL_poll.c

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