1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-06-15 06:41:47 +03:00

linux: Add time64 select support

The syscall __NR_pselect6_time64 (32-bit) or __NR_pselect6 (64-bit)
is used as default.  For architectures with __ASSUME_TIME64_SYSCALLS
the 32-bit fallback uses __NR_select/__NR__newselect or __NR_pselect6
(it should cover the microblaze case where older kernels do not
provide __NR_pselect6).

Checked on x86_64-linux-gnu and i686-linux-gnu (on 5.4 and on 4.15
kernel).

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Adhemerval Zanella
2020-07-06 16:06:51 -03:00
parent 50e19ddfcd
commit 2433d39b69
3 changed files with 88 additions and 28 deletions

View File

@ -5,8 +5,11 @@
/* Now define the internal interfaces. */ /* Now define the internal interfaces. */
# if __TIMESIZE == 64 # if __TIMESIZE == 64
# define __pselect64 __pselect # define __pselect64 __pselect
# define __select64 __select
#else #else
# include <struct___timespec64.h> # include <struct___timespec64.h>
# include <struct___timeval64.h>
extern int __pselect64 (int __nfds, fd_set *__readfds, extern int __pselect64 (int __nfds, fd_set *__readfds,
fd_set *__writefds, fd_set *__exceptfds, fd_set *__writefds, fd_set *__exceptfds,
const struct __timespec64 *__timeout, const struct __timespec64 *__timeout,
@ -18,6 +21,11 @@ extern int __pselect32 (int __nfds, fd_set *__readfds,
const struct __timespec64 *__timeout, const struct __timespec64 *__timeout,
const __sigset_t *__sigmask) const __sigset_t *__sigmask)
attribute_hidden; attribute_hidden;
extern int __select64 (int __nfds, fd_set *__readfds,
fd_set *__writefds, fd_set *__exceptfds,
struct __timeval64 *__timeout);
libc_hidden_proto (__select64)
#endif #endif
extern int __pselect (int __nfds, fd_set *__readfds, extern int __pselect (int __nfds, fd_set *__readfds,
fd_set *__writefds, fd_set *__exceptfds, fd_set *__writefds, fd_set *__exceptfds,

View File

@ -464,6 +464,12 @@ valid_timespec_to_timeval32 (const struct timespec ts)
return (struct __timeval32) { (time_t) ts.tv_sec, ts.tv_nsec / 1000 }; return (struct __timeval32) { (time_t) ts.tv_sec, ts.tv_nsec / 1000 };
} }
static inline struct __timeval64
valid_timespec_to_timeval64 (const struct timespec ts)
{
return (struct __timeval64) { (time_t) ts.tv_sec, ts.tv_nsec / 1000 };
}
/* Check if a value is in the valid nanoseconds range. Return true if /* Check if a value is in the valid nanoseconds range. Return true if
it is, false otherwise. */ it is, false otherwise. */
static inline bool static inline bool

View File

@ -21,6 +21,7 @@
#include <sys/select.h> #include <sys/select.h>
#include <errno.h> #include <errno.h>
#include <sysdep-cancel.h> #include <sysdep-cancel.h>
#include <time64-support.h>
/* Check the first NFDS descriptors each in READFDS (if not NULL) for read /* 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 readiness, in WRITEFDS (if not NULL) for write readiness, and in EXCEPTFDS
@ -28,43 +29,88 @@
after waiting the interval specified therein. Returns the number of ready after waiting the interval specified therein. Returns the number of ready
descriptors, or -1 for errors. */ descriptors, or -1 for errors. */
#ifdef __NR__newselect int
# undef __NR_select __select64 (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
# define __NR_select __NR__newselect struct __timeval64 *timeout)
{
struct __timespec64 ts64, *pts64 = NULL;
if (timeout != NULL)
{
ts64 = timeval64_to_timespec64 (*timeout);
pts64 = &ts64;
}
#ifndef __NR_pselect6_time64
# define __NR_pselect6_time64 __NR_pselect6
#endif #endif
int r;
if (supports_time64 ())
{
r = SYSCALL_CANCEL (pselect6_time64, nfds, readfds, writefds, exceptfds,
pts64, NULL);
/* 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. */
if (r == 0 || errno != ENOSYS)
{
if (timeout != NULL)
TIMEVAL_TO_TIMESPEC (timeout, &ts64);
return r;
}
mark_time64_unsupported ();
}
#ifndef __ASSUME_TIME64_SYSCALLS
struct timespec ts32, *pts32 = NULL;
if (timeout != NULL)
{
if (! in_time_t_range (timeout->tv_sec))
{
__set_errno (EINVAL);
return -1;
}
ts32 = valid_timespec64_to_timespec (ts64);
pts32 = &ts32;
}
# ifndef __ASSUME_PSELECT
# ifdef __NR__newselect
# undef __NR_select
# define __NR_select __NR__newselect
# endif
r = SYSCALL_CANCEL (select, nfds, readfds, writefds, exceptfds, pts32);
# else
r = SYSCALL_CANCEL (pselect6, nfds, readfds, writefds, exceptfds, pts32,
NULL);
# endif
if (r >= 0 && timeout != NULL)
*timeout = valid_timespec_to_timeval64 (ts32);
#endif
return r;
}
#if __TIMESIZE != 64
libc_hidden_def (__select64)
int int
__select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, __select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout) struct timeval *timeout)
{ {
#ifdef __NR_select struct __timeval64 tv64, *ptv64 = NULL;
return SYSCALL_CANCEL (select, nfds, readfds, writefds, exceptfds, if (timeout != NULL)
timeout);
#else
int result;
struct timespec ts, *tsp = NULL;
if (timeout)
{ {
TIMEVAL_TO_TIMESPEC (timeout, &ts); tv64 = valid_timeval_to_timeval64 (*timeout);
tsp = &ts; ptv64 = &tv64;
} }
int r = __select64 (nfds, readfds, writefds, exceptfds, ptv64);
result = SYSCALL_CANCEL (pselect6, nfds, readfds, writefds, exceptfds, tsp, if (r >= 0 && timeout != NULL)
NULL); /* The remanining timeout will be always less the input TIMEOUT. */
*timeout = valid_timeval64_to_timeval (tv64);
if (timeout) return r;
{
/* 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. */
TIMESPEC_TO_TIMEVAL (timeout, &ts);
}
return result;
#endif
} }
#endif
libc_hidden_def (__select) libc_hidden_def (__select)
weak_alias (__select, select) weak_alias (__select, select)