about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlbert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>2017-09-08 19:49:07 +0200
committerAlbert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>2018-10-24 12:53:27 +0200
commit058c76ad4adc7cca6f43645e4e9b5e8db00bf79e (patch)
tree36f282e6cb9e0574609f9885813d44ee8e09d655
parentc4ec41f9cf3279d8316be52011ba5603215384dd (diff)
downloadglibc-058c76ad4adc7cca6f43645e4e9b5e8db00bf79e.tar.gz
glibc-058c76ad4adc7cca6f43645e4e9b5e8db00bf79e.tar.xz
glibc-058c76ad4adc7cca6f43645e4e9b5e8db00bf79e.zip
Y2038: add function select64
-rw-r--r--include/sys/select.h5
-rw-r--r--sysdeps/unix/sysv/linux/select.c71
2 files changed, 76 insertions, 0 deletions
diff --git a/include/sys/select.h b/include/sys/select.h
index ba013a395c..9c58a158d8 100644
--- a/include/sys/select.h
+++ b/include/sys/select.h
@@ -22,5 +22,10 @@ extern int __pselect64 (int __nfds, fd_set *__readfds,
 			const struct __timespec64 *__timeout,
 			const __sigset_t *__sigmask);
 
+extern int __select64 (int __nfds, fd_set *__restrict __readfds,
+		       fd_set *__restrict __writefds,
+		       fd_set *__restrict __exceptfds,
+		       struct __timeval64 *__restrict __timeout);
+
 #endif
 #endif
diff --git a/sysdeps/unix/sysv/linux/select.c b/sysdeps/unix/sysv/linux/select.c
index e4124a104e..ba17746ee9 100644
--- a/sysdeps/unix/sysv/linux/select.c
+++ b/sysdeps/unix/sysv/linux/select.c
@@ -21,6 +21,7 @@
 #include <sys/select.h>
 #include <errno.h>
 #include <sysdep-cancel.h>
+#include <y2038-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
@@ -69,3 +70,73 @@ libc_hidden_def (__select)
 
 weak_alias (__select, select)
 weak_alias (__select, __libc_select)
+
+/* 64-bit time version */
+
+int
+__select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+	      struct __timeval64 *timeout)
+{
+#ifdef __NR_select
+  struct timeval tval32, *timeout32 = NULL;
+#else
+  int result;
+  struct timespec ts32, *tsp32 = NULL;
+#endif
+
+#ifdef __NR_pselect6_time64
+  int res;
+  if (__y2038_linux_support > 0)
+  {
+    res = SYSCALL_CANCEL (pselect6_time64, nfds, readfds, writefds,
+			  exceptfds, timeout, NULL);
+    if (res == 0 || errno != ENOSYS)
+      return res;
+    __y2038_linux_support = -1;
+  }
+#endif
+
+#ifdef __NR_select
+  if (timeout != NULL)
+    {
+      if (timeout->tv_sec > INT_MAX)
+      {
+        errno = EOVERFLOW;
+        return -1;
+      }
+      tval32.tv_sec = timeout->tv_sec;
+      tval32.tv_usec = timeout->tv_usec;
+      timeout32 = &tval32;
+    }
+
+  return SYSCALL_CANCEL (select, nfds, readfds, writefds, exceptfds,
+			 timeout32);
+#else
+  if (timeout)
+    {
+      if (timeout->tv_sec > INT_MAX)
+      {
+        errno = EOVERFLOW;
+        return -1;
+      }
+      ts32.tv_sec = timeout->tv_sec;
+      ts32.tv_nsec = timeout->tv_usec * 1000;
+      tsp32 = &ts32;
+    }
+
+  result = SYSCALL_CANCEL (pselect6, nfds, readfds, writefds, exceptfds, tsp32,
+			   NULL);
+
+  if (timeout)
+    {
+      /* 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.  */
+      timeout->tv_sec = ts32.tv_sec;
+      timeout->tv_usec = ts32.tv_nsec / 1000;
+    }
+
+  return result;
+#endif
+}