summaryrefslogtreecommitdiff
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
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
+}