diff options
author | Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr> | 2017-09-08 00:42:16 +0200 |
---|---|---|
committer | Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr> | 2018-10-24 12:53:27 +0200 |
commit | c4ec41f9cf3279d8316be52011ba5603215384dd (patch) | |
tree | e837cbefbfa893510e81bb69cc147f960d9e5916 | |
parent | d9a19a386245ebcfa78309709fd6394a45292601 (diff) | |
download | glibc-c4ec41f9cf3279d8316be52011ba5603215384dd.tar glibc-c4ec41f9cf3279d8316be52011ba5603215384dd.tar.gz glibc-c4ec41f9cf3279d8316be52011ba5603215384dd.tar.bz2 glibc-c4ec41f9cf3279d8316be52011ba5603215384dd.zip |
Y2038: add function pselect64
-rw-r--r-- | include/sys/select.h | 8 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/pselect.c | 66 |
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 |