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-04-18 21:28:45 +0200
commitb8fb4f7106e55f8705d63a8f1d87790efe7505cd (patch)
tree1072ccbed00798785dede13ee2b198f22c19c5d9
parentc1fc42402250ccf43699556a1f06244055c6337e (diff)
downloadglibc-b8fb4f7106e55f8705d63a8f1d87790efe7505cd.tar.gz
Y2038: add function select64
-rw-r--r--include/sys/select.h5
-rw-r--r--sysdeps/unix/sysv/linux/select.c66
2 files changed, 71 insertions, 0 deletions
diff --git a/include/sys/select.h b/include/sys/select.h
index 96d46f4de2..da843b69ca 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..804ebcaacc 100644
--- a/sysdeps/unix/sysv/linux/select.c
+++ b/sysdeps/unix/sysv/linux/select.c
@@ -33,6 +33,8 @@
# define __NR_select __NR__newselect
#endif
+extern int __y2038_linux_support;
+
int
__select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout)
@@ -69,3 +71,67 @@ libc_hidden_def (__select)
weak_alias (__select, select)
weak_alias (__select, __libc_select)
+
+/* 64-bit time version */
+
+extern int __y2038_linux_support;
+
+int
+__select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct __timeval64 *timeout)
+{
+ struct timeval tval32, *timeout32 = NULL;
+#ifndef __NR_select
+ int result;
+ struct timespec ts32, *tsp32 = NULL;
+#endif
+
+ if (__y2038_linux_support)
+ {
+ /* TODO: implement using Linux kernel system call */
+ }
+
+ 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;
+ }
+
+#ifdef __NR_select
+ 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
+}