]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
linux: Add time64 select support
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Mon, 6 Jul 2020 19:06:51 +0000 (16:06 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Mon, 28 Sep 2020 19:21:48 +0000 (16:21 -0300)
The syscall __NR_pselect6_time64 (32-bit) or __NR_pselect6 (64-bit)
is used as default.  For architectures with __ASSUME_TIME64_SYSCALLS
the 32-bit fallback uses __NR_select/__NR__newselect or __NR_pselect6
(it should cover the microblaze case where older kernels do not
provide __NR_pselect6).

Checked on x86_64-linux-gnu and i686-linux-gnu (on 5.4 and on 4.15
kernel).

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
include/sys/select.h
include/time.h
sysdeps/unix/sysv/linux/select.c

index b5ae9af861aabfb5b8bff2e5260199c7700dd456..ec073deeba339a86a5d4c799221bdb9369dff28d 100644 (file)
@@ -5,8 +5,11 @@
 /* Now define the internal interfaces.  */
 # if __TIMESIZE == 64
 #  define __pselect64 __pselect
+#  define __select64  __select
 #else
 # include <struct___timespec64.h>
+# include <struct___timeval64.h>
+
 extern int __pselect64 (int __nfds, fd_set *__readfds,
                        fd_set *__writefds, fd_set *__exceptfds,
                        const struct __timespec64 *__timeout,
@@ -18,6 +21,11 @@ extern int __pselect32 (int __nfds, fd_set *__readfds,
                        const struct __timespec64 *__timeout,
                        const __sigset_t *__sigmask)
   attribute_hidden;
+
+extern int __select64 (int __nfds, fd_set *__readfds,
+                      fd_set *__writefds, fd_set *__exceptfds,
+                      struct __timeval64 *__timeout);
+libc_hidden_proto (__select64)
 #endif
 extern int __pselect (int __nfds, fd_set *__readfds,
                      fd_set *__writefds, fd_set *__exceptfds,
index fe4da9ca10d419bb8e66c7b2493a7c5f6941f705..936486e2062d3f52d71c2aa6e6205a6c9eb10f14 100644 (file)
@@ -464,6 +464,12 @@ valid_timespec_to_timeval32 (const struct timespec ts)
   return (struct __timeval32) { (time_t) ts.tv_sec, ts.tv_nsec / 1000 };
 }
 
+static inline struct __timeval64
+valid_timespec_to_timeval64 (const struct timespec ts)
+{
+  return (struct __timeval64) { (time_t) ts.tv_sec, ts.tv_nsec / 1000 };
+}
+
 /* Check if a value is in the valid nanoseconds range. Return true if
    it is, false otherwise.  */
 static inline bool
index 54c50edba2e572f86963dadc3c8e0fcf29238009..bed52fbda218bdf347e9e8e00542d82cf4b13242 100644 (file)
@@ -21,6 +21,7 @@
 #include <sys/select.h>
 #include <errno.h>
 #include <sysdep-cancel.h>
+#include <time64-support.h>
 
 /* Check the first NFDS descriptors each in READFDS (if not NULL) for read
    readiness, in WRITEFDS (if not NULL) for write readiness, and in EXCEPTFDS
    after waiting the interval specified therein.  Returns the number of ready
    descriptors, or -1 for errors.  */
 
-#ifdef __NR__newselect
-# undef __NR_select
-# define __NR_select __NR__newselect
-#endif
-
 int
-__select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
-         struct timeval *timeout)
+__select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+           struct __timeval64 *timeout)
 {
-#ifdef __NR_select
-  return SYSCALL_CANCEL (select, nfds, readfds, writefds, exceptfds,
-                        timeout);
-#else
-  int result;
-  struct timespec ts, *tsp = NULL;
-
-  if (timeout)
+  struct __timespec64 ts64, *pts64 = NULL;
+  if (timeout != NULL)
     {
-      TIMEVAL_TO_TIMESPEC (timeout, &ts);
-      tsp = &ts;
+      ts64 = timeval64_to_timespec64 (*timeout);
+      pts64 = &ts64;
     }
 
-  result = SYSCALL_CANCEL (pselect6, nfds, readfds, writefds, exceptfds, tsp,
-                          NULL);
-
-  if (timeout)
+#ifndef __NR_pselect6_time64
+# define __NR_pselect6_time64 __NR_pselect6
+#endif
+  int r;
+  if (supports_time64 ())
     {
+      r = SYSCALL_CANCEL (pselect6_time64, nfds, readfds, writefds, exceptfds,
+                         pts64, NULL);
       /* Linux by default will update the timeout after a pselect6 syscall
          (though the pselect() glibc call suppresses this behavior).
          Since select() on Linux has the same behavior as the pselect6
          syscall, we update the timeout here.  */
-      TIMESPEC_TO_TIMEVAL (timeout, &ts);
+      if (r == 0 || errno != ENOSYS)
+       {
+         if (timeout != NULL)
+           TIMEVAL_TO_TIMESPEC (timeout, &ts64);
+         return r;
+       }
+
+      mark_time64_unsupported ();
     }
 
-  return result;
+#ifndef __ASSUME_TIME64_SYSCALLS
+  struct timespec ts32, *pts32 = NULL;
+  if (timeout != NULL)
+    {
+      if (! in_time_t_range (timeout->tv_sec))
+       {
+         __set_errno (EINVAL);
+         return -1;
+       }
+      ts32 = valid_timespec64_to_timespec (ts64);
+      pts32 = &ts32;
+    }
+# ifndef __ASSUME_PSELECT
+#  ifdef __NR__newselect
+#   undef __NR_select
+#   define __NR_select __NR__newselect
+#  endif
+  r = SYSCALL_CANCEL (select, nfds, readfds, writefds, exceptfds, pts32);
+# else
+  r = SYSCALL_CANCEL (pselect6, nfds, readfds, writefds, exceptfds, pts32,
+                     NULL);
+# endif
+  if (r >= 0 && timeout != NULL)
+    *timeout = valid_timespec_to_timeval64 (ts32);
 #endif
+
+  return r;
 }
+
+#if __TIMESIZE != 64
+libc_hidden_def (__select64)
+
+int
+__select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+         struct timeval *timeout)
+{
+  struct __timeval64 tv64, *ptv64 = NULL;
+  if (timeout != NULL)
+    {
+      tv64 = valid_timeval_to_timeval64 (*timeout);
+      ptv64 = &tv64;
+    }
+  int r = __select64 (nfds, readfds, writefds, exceptfds, ptv64);
+  if (r >= 0 && timeout != NULL)
+    /* The remanining timeout will be always less the input TIMEOUT.  */
+    *timeout = valid_timeval64_to_timeval (tv64);
+  return r;
+}
+#endif
 libc_hidden_def (__select)
 
 weak_alias (__select, select)