diff options
author | Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr> | 2017-09-08 19:49:07 +0200 |
---|---|---|
committer | Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr> | 2018-10-24 12:53:27 +0200 |
commit | 058c76ad4adc7cca6f43645e4e9b5e8db00bf79e (patch) | |
tree | 36f282e6cb9e0574609f9885813d44ee8e09d655 | |
parent | c4ec41f9cf3279d8316be52011ba5603215384dd (diff) | |
download | glibc-058c76ad4adc7cca6f43645e4e9b5e8db00bf79e.tar.gz glibc-058c76ad4adc7cca6f43645e4e9b5e8db00bf79e.tar.xz glibc-058c76ad4adc7cca6f43645e4e9b5e8db00bf79e.zip |
Y2038: add function select64
-rw-r--r-- | include/sys/select.h | 5 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/select.c | 71 |
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 +} |