nptl: Use FUTEX_LOCK_PI2 when available

This patch uses the new futex PI operation provided by Linux v5.14
when it is required.

The futex_lock_pi64() is moved to futex-internal.c (since it used on
two different places and its code size might be large depending of the
kernel configuration) and clockid is added as an argument.

Co-authored-by: Kurt Kanzenbach <kurt@linutronix.de>
This commit is contained in:
Adhemerval Zanella 2021-06-25 10:11:00 +02:00
parent dd5adb515c
commit 8352b6df37
5 changed files with 72 additions and 56 deletions

View File

@ -140,3 +140,66 @@ __futex_abstimed_wait_cancelable64 (unsigned int* futex_word,
abstime, private, true); abstime, private, true);
} }
libc_hidden_def (__futex_abstimed_wait_cancelable64) libc_hidden_def (__futex_abstimed_wait_cancelable64)
int
__futex_lock_pi64 (int *futex_word, clockid_t clockid,
const struct __timespec64 *abstime, int private)
{
int err;
unsigned int clockbit = clockid == CLOCK_REALTIME
? FUTEX_CLOCK_REALTIME : 0;
int op_pi2 = __lll_private_flag (FUTEX_LOCK_PI2 | clockbit, private);
#if __ASSUME_FUTEX_LOCK_PI2
/* Assume __ASSUME_TIME64_SYSCALLS since FUTEX_LOCK_PI2 was added later. */
err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op_pi2, 0, abstime);
#else
/* FUTEX_LOCK_PI does not support clock selection, so for CLOCK_MONOTONIC
the only option is to use FUTEX_LOCK_PI2. */
int op_pi1 = __lll_private_flag (FUTEX_LOCK_PI, private);
int op_pi = abstime != NULL && clockid != CLOCK_REALTIME ? op_pi2 : op_pi1;
# ifdef __ASSUME_TIME64_SYSCALLS
err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op_pi, 0, 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, op_pi, 0, abstime);
else
{
struct timespec ts32, *pts32 = NULL;
if (abstime != NULL)
{
ts32 = valid_timespec64_to_timespec (*abstime);
pts32 = &ts32;
}
err = INTERNAL_SYSCALL_CALL (futex, futex_word, op_pi, 0, pts32);
}
# endif /* __ASSUME_TIME64_SYSCALLS */
/* FUTEX_LOCK_PI2 is not available on this kernel. */
if (err == -ENOSYS)
err = -EINVAL;
#endif /* __ASSUME_FUTEX_LOCK_PI2 */
switch (err)
{
case 0:
case -EAGAIN:
case -EINTR:
case -ETIMEDOUT:
case -ESRCH:
case -EDEADLK:
case -EINVAL: /* This indicates either state corruption or that the kernel
found a waiter on futex address which is waiting via
FUTEX_WAIT or FUTEX_WAIT_BITSET. This is reported on
some futex_lock_pi usage (pthread_mutex_timedlock for
instance). */
return -err;
case -EFAULT: /* Must have been caused by a glibc or application bug. */
case -ENOSYS: /* Must have been caused by a glibc bug. */
/* No other errors are documented at this time. */
default:
futex_fatal_error ();
}
}

View File

@ -421,7 +421,8 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
int private = (robust int private = (robust
? PTHREAD_ROBUST_MUTEX_PSHARED (mutex) ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
: PTHREAD_MUTEX_PSHARED (mutex)); : PTHREAD_MUTEX_PSHARED (mutex));
int e = futex_lock_pi64 (&mutex->__data.__lock, NULL, private); int e = __futex_lock_pi64 (&mutex->__data.__lock, 0 /* ununsed */,
NULL, private);
if (e == ESRCH || e == EDEADLK) if (e == ESRCH || e == EDEADLK)
{ {
assert (e != EDEADLK assert (e != EDEADLK

View File

@ -369,7 +369,8 @@ __pthread_mutex_clocklock_common (pthread_mutex_t *mutex,
int private = (robust int private = (robust
? PTHREAD_ROBUST_MUTEX_PSHARED (mutex) ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
: PTHREAD_MUTEX_PSHARED (mutex)); : PTHREAD_MUTEX_PSHARED (mutex));
int e = futex_lock_pi64 (&mutex->__data.__lock, abstime, private); int e = __futex_lock_pi64 (&mutex->__data.__lock, clockid, abstime,
private);
if (e == ETIMEDOUT) if (e == ETIMEDOUT)
return ETIMEDOUT; return ETIMEDOUT;
else if (e == ESRCH || e == EDEADLK) else if (e == ESRCH || e == EDEADLK)

View File

@ -236,8 +236,8 @@ futex_wake (unsigned int* futex_word, int processes_to_wake, int private)
are done in descending priority order. are done in descending priority order.
The ABSTIME arguments provides an absolute timeout (measured against the The ABSTIME arguments provides an absolute timeout (measured against the
CLOCK_REALTIME clock). If TIMEOUT is NULL, the operation will block CLOCK_REALTIME or CLOCK_MONOTONIC clock). If TIMEOUT is NULL, the operation
indefinitely. will block indefinitely.
Returns: Returns:
@ -250,58 +250,8 @@ futex_wake (unsigned int* futex_word, int processes_to_wake, int private)
futex. futex.
- ETIMEDOUT if the ABSTIME expires. - ETIMEDOUT if the ABSTIME expires.
*/ */
static __always_inline int int __futex_lock_pi64 (int *futex_word, clockid_t clockid,
futex_lock_pi64 (int *futex_word, const struct __timespec64 *abstime, const struct __timespec64 *abstime, int private);
int private)
{
int err;
#ifdef __ASSUME_TIME64_SYSCALLS
err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word,
__lll_private_flag (FUTEX_LOCK_PI, private), 0,
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
{
struct timespec ts32;
if (abstime != NULL)
ts32 = valid_timespec64_to_timespec (*abstime);
err = INTERNAL_SYSCALL_CALL (futex, futex_word, __lll_private_flag
(FUTEX_LOCK_PI, private), 0,
abstime != NULL ? &ts32 : NULL);
}
#endif
switch (err)
{
case 0:
case -EAGAIN:
case -EINTR:
case -ETIMEDOUT:
case -ESRCH:
case -EDEADLK:
case -EINVAL: /* This indicates either state corruption or that the kernel
found a waiter on futex address which is waiting via
FUTEX_WAIT or FUTEX_WAIT_BITSET. This is reported on
some futex_lock_pi usage (pthread_mutex_timedlock for
instance). */
return -err;
case -EFAULT: /* Must have been caused by a glibc or application bug. */
case -ENOSYS: /* Must have been caused by a glibc bug. */
/* No other errors are documented at this time. */
default:
futex_fatal_error ();
}
}
/* Wakes the top priority waiter that called a futex_lock_pi operation on /* Wakes the top priority waiter that called a futex_lock_pi operation on
the futex. the futex.

View File

@ -38,6 +38,7 @@
#define FUTEX_WAKE_BITSET 10 #define FUTEX_WAKE_BITSET 10
#define FUTEX_WAIT_REQUEUE_PI 11 #define FUTEX_WAIT_REQUEUE_PI 11
#define FUTEX_CMP_REQUEUE_PI 12 #define FUTEX_CMP_REQUEUE_PI 12
#define FUTEX_LOCK_PI2 13
#define FUTEX_PRIVATE_FLAG 128 #define FUTEX_PRIVATE_FLAG 128
#define FUTEX_CLOCK_REALTIME 256 #define FUTEX_CLOCK_REALTIME 256