about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlbert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>2017-09-08 00:42:16 +0200
committerAlbert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>2018-10-24 12:53:27 +0200
commitc4ec41f9cf3279d8316be52011ba5603215384dd (patch)
treee837cbefbfa893510e81bb69cc147f960d9e5916
parentd9a19a386245ebcfa78309709fd6394a45292601 (diff)
downloadglibc-c4ec41f9cf3279d8316be52011ba5603215384dd.tar.gz
glibc-c4ec41f9cf3279d8316be52011ba5603215384dd.tar.xz
glibc-c4ec41f9cf3279d8316be52011ba5603215384dd.zip
Y2038: add function pselect64
-rw-r--r--include/sys/select.h8
-rw-r--r--sysdeps/unix/sysv/linux/pselect.c66
2 files changed, 74 insertions, 0 deletions
diff --git a/include/sys/select.h b/include/sys/select.h
index 07bb49b994..ba013a395c 100644
--- a/include/sys/select.h
+++ b/include/sys/select.h
@@ -3,6 +3,7 @@
 
 #ifndef _ISOMAC
 /* Now define the internal interfaces.  */
+
 extern int __pselect (int __nfds, fd_set *__readfds,
 		      fd_set *__writefds, fd_set *__exceptfds,
 		      const struct timespec *__timeout,
@@ -14,5 +15,12 @@ extern int __select (int __nfds, fd_set *__restrict __readfds,
 		     struct timeval *__restrict __timeout);
 libc_hidden_proto (__select)
 
+/* 64-bit time version */
+
+extern int __pselect64 (int __nfds, fd_set *__readfds,
+			fd_set *__writefds, fd_set *__exceptfds,
+			const struct __timespec64 *__timeout,
+			const __sigset_t *__sigmask);
+
 #endif
 #endif
diff --git a/sysdeps/unix/sysv/linux/pselect.c b/sysdeps/unix/sysv/linux/pselect.c
index 2b052e7b00..8a77036697 100644
--- a/sysdeps/unix/sysv/linux/pselect.c
+++ b/sysdeps/unix/sysv/linux/pselect.c
@@ -22,6 +22,7 @@
 #include <sys/poll.h>
 #include <kernel-features.h>
 #include <sysdep-cancel.h>
+#include <y2038-support.h>
 
 
 #ifdef __NR_pselect6
@@ -79,6 +80,71 @@ __pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
 }
 weak_alias (__pselect, pselect)
 
+/* 64-bit time version */
+
+int
+__pselect64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+	       const struct __timespec64 *timeout, const sigset_t *sigmask)
+{
+  struct timespec tval32, *timeout32 = NULL;
+
+  /* Note: the system call expects 7 values but on most architectures
+     we can only pass in 6 directly.  If there is an architecture with
+     support for more parameters a new version of this file needs to
+     be created.  */
+  struct
+  {
+    __syscall_ulong_t ss;
+    __syscall_ulong_t ss_len;
+  } data;
+
+  data.ss = (__syscall_ulong_t) (uintptr_t) sigmask;
+  data.ss_len = _NSIG / 8;
+
+  int result;
+
+#ifdef __NR_pselect6_time64
+  if (__y2038_linux_support > 0)
+  {
+    result = SYSCALL_CANCEL (pselect6_time64, nfds, readfds, writefds,
+			     exceptfds, timeout, &data);
+    if (result == 0 || errno != ENOSYS)
+      return result;
+    __y2038_linux_support = -1;
+  }
+#endif
+
+  /* The Linux kernel can in some situations update the timeout value.
+     We do not want that so use a local variable.  */
+  if (timeout != NULL)
+    {
+      if (timeout->tv_sec > INT_MAX)
+      {
+        errno = EOVERFLOW;
+        return -1;
+      }
+      tval32.tv_sec = timeout->tv_sec;
+      tval32.tv_nsec = timeout->tv_nsec;
+      timeout32 = &tval32;
+    }
+
+#ifndef CALL_PSELECT6
+# define CALL_PSELECT6(nfds, readfds, writefds, exceptfds, timeout, data) \
+  SYSCALL_CANCEL (pselect6, nfds, readfds, writefds, exceptfds,	timeout32, data)
+#endif
+
+  result = CALL_PSELECT6 (nfds, readfds, writefds, exceptfds, timeout32,
+			  &data);
+
+# ifndef __ASSUME_PSELECT
+  if (result == -1 && errno == ENOSYS)
+    result = __generic_pselect (nfds, readfds, writefds, exceptfds, timeout32,
+				sigmask);
+# endif
+
+  return result;
+}
+
 # ifndef __ASSUME_PSELECT
 #  define __pselect static __generic_pselect
 # endif