linux: Only use 64-bit syscall if required for internal futex

For !__ASSUME_TIME64_SYSCALLS there is no need to issue a 64-bit syscall
if the provided timeout fits in a 32-bit one.  The 64-bit usage should
be rare since the timeout is a relative one.

Checked on i686-linux-gnu on a 4.15 kernel and on a 5.11 kernel
(with and without --enable-kernel=5.1) and on x86_64-linux-gnu.

Reviewed-by: Lukasz Majewski <lukma@denx.de>
This commit is contained in:
Adhemerval Zanella 2021-06-16 11:04:47 -03:00
parent b286eca5d4
commit b769b0a2cb
2 changed files with 50 additions and 26 deletions

View File

@ -32,9 +32,6 @@ __futex_abstimed_wait_common32 (unsigned int* futex_word,
struct timespec ts32, *pts32 = NULL; struct timespec ts32, *pts32 = NULL;
if (abstime != NULL) if (abstime != NULL)
{ {
if (! in_time_t_range (abstime->tv_sec))
return -EOVERFLOW;
ts32 = valid_timespec64_to_timespec (*abstime); ts32 = valid_timespec64_to_timespec (*abstime);
pts32 = &ts32; pts32 = &ts32;
} }
@ -52,12 +49,28 @@ __futex_abstimed_wait_common32 (unsigned int* futex_word,
static int static int
__futex_abstimed_wait_common64 (unsigned int* futex_word, __futex_abstimed_wait_common64 (unsigned int* futex_word,
unsigned int expected, int op,
const struct __timespec64* abstime,
int private, bool cancel)
{
if (cancel)
return INTERNAL_SYSCALL_CANCEL (futex_time64, futex_word, op, expected,
abstime, NULL /* Unused. */,
FUTEX_BITSET_MATCH_ANY);
else
return INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op, expected,
abstime, NULL /* Ununsed. */,
FUTEX_BITSET_MATCH_ANY);
}
static int
__futex_abstimed_wait_common (unsigned int* futex_word,
unsigned int expected, clockid_t clockid, unsigned int expected, clockid_t clockid,
const struct __timespec64* abstime, const struct __timespec64* abstime,
int private, bool cancel) int private, bool cancel)
{ {
unsigned int clockbit;
int err; int err;
unsigned int clockbit;
/* Work around the fact that the kernel rejects negative timeout values /* Work around the fact that the kernel rejects negative timeout values
despite them being valid. */ despite them being valid. */
@ -70,16 +83,19 @@ __futex_abstimed_wait_common64 (unsigned int* futex_word,
clockbit = (clockid == CLOCK_REALTIME) ? FUTEX_CLOCK_REALTIME : 0; clockbit = (clockid == CLOCK_REALTIME) ? FUTEX_CLOCK_REALTIME : 0;
int op = __lll_private_flag (FUTEX_WAIT_BITSET | clockbit, private); int op = __lll_private_flag (FUTEX_WAIT_BITSET | clockbit, private);
if (cancel) #ifdef __ASSUME_TIME64_SYSCALLS
err = INTERNAL_SYSCALL_CANCEL (futex_time64, futex_word, op, expected, err = __futex_abstimed_wait_common64 (futex_word, expected, op, abstime,
abstime, NULL /* Unused. */, private, cancel);
FUTEX_BITSET_MATCH_ANY); #else
else bool need_time64 = abstime != NULL && !in_time_t_range (abstime->tv_sec);
err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op, expected, if (need_time64)
abstime, NULL /* Ununsed. */, {
FUTEX_BITSET_MATCH_ANY); err = __futex_abstimed_wait_common64 (futex_word, expected, op, abstime,
#ifndef __ASSUME_TIME64_SYSCALLS private, cancel);
if (err == -ENOSYS) if (err == -ENOSYS)
err = -EOVERFLOW;
}
else
err = __futex_abstimed_wait_common32 (futex_word, expected, op, abstime, err = __futex_abstimed_wait_common32 (futex_word, expected, op, abstime,
private, cancel); private, cancel);
#endif #endif
@ -109,7 +125,7 @@ __futex_abstimed_wait64 (unsigned int* futex_word, unsigned int expected,
clockid_t clockid, clockid_t clockid,
const struct __timespec64* abstime, int private) const struct __timespec64* abstime, int private)
{ {
return __futex_abstimed_wait_common64 (futex_word, expected, clockid, return __futex_abstimed_wait_common (futex_word, expected, clockid,
abstime, private, false); abstime, private, false);
} }
libc_hidden_def (__futex_abstimed_wait64) libc_hidden_def (__futex_abstimed_wait64)
@ -120,7 +136,7 @@ __futex_abstimed_wait_cancelable64 (unsigned int* futex_word,
const struct __timespec64* abstime, const struct __timespec64* abstime,
int private) int private)
{ {
return __futex_abstimed_wait_common64 (futex_word, expected, clockid, return __futex_abstimed_wait_common (futex_word, expected, clockid,
abstime, private, true); abstime, private, true);
} }
libc_hidden_def (__futex_abstimed_wait_cancelable64) libc_hidden_def (__futex_abstimed_wait_cancelable64)

View File

@ -254,15 +254,23 @@ static __always_inline int
futex_lock_pi64 (int *futex_word, const struct __timespec64 *abstime, futex_lock_pi64 (int *futex_word, const struct __timespec64 *abstime,
int private) int private)
{ {
int err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, int err;
__lll_private_flag #ifdef __ASSUME_TIME64_SYSCALLS
(FUTEX_LOCK_PI, private), 0, abstime); err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word,
#ifndef __ASSUME_TIME64_SYSCALLS __lll_private_flag (FUTEX_LOCK_PI, private), 0,
if (err == -ENOSYS) abstime);
#else
bool need_time64 = abstime != NULL && !in_time_t_range (abstime->tv_sec);
if (need_time64)
{
err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word,
__lll_private_flag (FUTEX_LOCK_PI, private),
0, abstime);
if (err == -ENOSYS)
err = -EOVERFLOW;
}
else
{ {
if (abstime != NULL && ! in_time_t_range (abstime->tv_sec))
return EOVERFLOW;
struct timespec ts32; struct timespec ts32;
if (abstime != NULL) if (abstime != NULL)
ts32 = valid_timespec64_to_timespec (*abstime); ts32 = valid_timespec64_to_timespec (*abstime);