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-04-18 21:28:45 +0200 |
commit | b8fb4f7106e55f8705d63a8f1d87790efe7505cd (patch) | |
tree | 1072ccbed00798785dede13ee2b198f22c19c5d9 | |
parent | c1fc42402250ccf43699556a1f06244055c6337e (diff) | |
download | glibc-b8fb4f7106e55f8705d63a8f1d87790efe7505cd.tar.gz |
Y2038: add function select64
-rw-r--r-- | include/sys/select.h | 5 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/select.c | 66 |
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 +} |