Skip to content

Commit 8352b6d

Browse files
zatrazzshifty91
andcommitted
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>
1 parent dd5adb5 commit 8352b6d

File tree

5 files changed

+72
-56
lines changed

5 files changed

+72
-56
lines changed

nptl/futex-internal.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,66 @@ __futex_abstimed_wait_cancelable64 (unsigned int* futex_word,
140140
abstime, private, true);
141141
}
142142
libc_hidden_def (__futex_abstimed_wait_cancelable64)
143+
144+
int
145+
__futex_lock_pi64 (int *futex_word, clockid_t clockid,
146+
const struct __timespec64 *abstime, int private)
147+
{
148+
int err;
149+
150+
unsigned int clockbit = clockid == CLOCK_REALTIME
151+
? FUTEX_CLOCK_REALTIME : 0;
152+
int op_pi2 = __lll_private_flag (FUTEX_LOCK_PI2 | clockbit, private);
153+
#if __ASSUME_FUTEX_LOCK_PI2
154+
/* Assume __ASSUME_TIME64_SYSCALLS since FUTEX_LOCK_PI2 was added later. */
155+
err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op_pi2, 0, abstime);
156+
#else
157+
/* FUTEX_LOCK_PI does not support clock selection, so for CLOCK_MONOTONIC
158+
the only option is to use FUTEX_LOCK_PI2. */
159+
int op_pi1 = __lll_private_flag (FUTEX_LOCK_PI, private);
160+
int op_pi = abstime != NULL && clockid != CLOCK_REALTIME ? op_pi2 : op_pi1;
161+
162+
# ifdef __ASSUME_TIME64_SYSCALLS
163+
err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op_pi, 0, abstime);
164+
# else
165+
bool need_time64 = abstime != NULL && !in_time_t_range (abstime->tv_sec);
166+
if (need_time64)
167+
err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word, op_pi, 0, abstime);
168+
else
169+
{
170+
struct timespec ts32, *pts32 = NULL;
171+
if (abstime != NULL)
172+
{
173+
ts32 = valid_timespec64_to_timespec (*abstime);
174+
pts32 = &ts32;
175+
}
176+
err = INTERNAL_SYSCALL_CALL (futex, futex_word, op_pi, 0, pts32);
177+
}
178+
# endif /* __ASSUME_TIME64_SYSCALLS */
179+
/* FUTEX_LOCK_PI2 is not available on this kernel. */
180+
if (err == -ENOSYS)
181+
err = -EINVAL;
182+
#endif /* __ASSUME_FUTEX_LOCK_PI2 */
183+
184+
switch (err)
185+
{
186+
case 0:
187+
case -EAGAIN:
188+
case -EINTR:
189+
case -ETIMEDOUT:
190+
case -ESRCH:
191+
case -EDEADLK:
192+
case -EINVAL: /* This indicates either state corruption or that the kernel
193+
found a waiter on futex address which is waiting via
194+
FUTEX_WAIT or FUTEX_WAIT_BITSET. This is reported on
195+
some futex_lock_pi usage (pthread_mutex_timedlock for
196+
instance). */
197+
return -err;
198+
199+
case -EFAULT: /* Must have been caused by a glibc or application bug. */
200+
case -ENOSYS: /* Must have been caused by a glibc bug. */
201+
/* No other errors are documented at this time. */
202+
default:
203+
futex_fatal_error ();
204+
}
205+
}

nptl/pthread_mutex_lock.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,8 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
421421
int private = (robust
422422
? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
423423
: PTHREAD_MUTEX_PSHARED (mutex));
424-
int e = futex_lock_pi64 (&mutex->__data.__lock, NULL, private);
424+
int e = __futex_lock_pi64 (&mutex->__data.__lock, 0 /* ununsed */,
425+
NULL, private);
425426
if (e == ESRCH || e == EDEADLK)
426427
{
427428
assert (e != EDEADLK

nptl/pthread_mutex_timedlock.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,8 @@ __pthread_mutex_clocklock_common (pthread_mutex_t *mutex,
369369
int private = (robust
370370
? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
371371
: PTHREAD_MUTEX_PSHARED (mutex));
372-
int e = futex_lock_pi64 (&mutex->__data.__lock, abstime, private);
372+
int e = __futex_lock_pi64 (&mutex->__data.__lock, clockid, abstime,
373+
private);
373374
if (e == ETIMEDOUT)
374375
return ETIMEDOUT;
375376
else if (e == ESRCH || e == EDEADLK)

sysdeps/nptl/futex-internal.h

Lines changed: 4 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,8 @@ futex_wake (unsigned int* futex_word, int processes_to_wake, int private)
236236
are done in descending priority order.
237237
238238
The ABSTIME arguments provides an absolute timeout (measured against the
239-
CLOCK_REALTIME clock). If TIMEOUT is NULL, the operation will block
240-
indefinitely.
239+
CLOCK_REALTIME or CLOCK_MONOTONIC clock). If TIMEOUT is NULL, the operation
240+
will block indefinitely.
241241
242242
Returns:
243243
@@ -250,58 +250,8 @@ futex_wake (unsigned int* futex_word, int processes_to_wake, int private)
250250
futex.
251251
- ETIMEDOUT if the ABSTIME expires.
252252
*/
253-
static __always_inline int
254-
futex_lock_pi64 (int *futex_word, const struct __timespec64 *abstime,
255-
int private)
256-
{
257-
int err;
258-
#ifdef __ASSUME_TIME64_SYSCALLS
259-
err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word,
260-
__lll_private_flag (FUTEX_LOCK_PI, private), 0,
261-
abstime);
262-
#else
263-
bool need_time64 = abstime != NULL && !in_time_t_range (abstime->tv_sec);
264-
if (need_time64)
265-
{
266-
err = INTERNAL_SYSCALL_CALL (futex_time64, futex_word,
267-
__lll_private_flag (FUTEX_LOCK_PI, private),
268-
0, abstime);
269-
if (err == -ENOSYS)
270-
err = -EOVERFLOW;
271-
}
272-
else
273-
{
274-
struct timespec ts32;
275-
if (abstime != NULL)
276-
ts32 = valid_timespec64_to_timespec (*abstime);
277-
278-
err = INTERNAL_SYSCALL_CALL (futex, futex_word, __lll_private_flag
279-
(FUTEX_LOCK_PI, private), 0,
280-
abstime != NULL ? &ts32 : NULL);
281-
}
282-
#endif
283-
switch (err)
284-
{
285-
case 0:
286-
case -EAGAIN:
287-
case -EINTR:
288-
case -ETIMEDOUT:
289-
case -ESRCH:
290-
case -EDEADLK:
291-
case -EINVAL: /* This indicates either state corruption or that the kernel
292-
found a waiter on futex address which is waiting via
293-
FUTEX_WAIT or FUTEX_WAIT_BITSET. This is reported on
294-
some futex_lock_pi usage (pthread_mutex_timedlock for
295-
instance). */
296-
return -err;
297-
298-
case -EFAULT: /* Must have been caused by a glibc or application bug. */
299-
case -ENOSYS: /* Must have been caused by a glibc bug. */
300-
/* No other errors are documented at this time. */
301-
default:
302-
futex_fatal_error ();
303-
}
304-
}
253+
int __futex_lock_pi64 (int *futex_word, clockid_t clockid,
254+
const struct __timespec64 *abstime, int private);
305255

306256
/* Wakes the top priority waiter that called a futex_lock_pi operation on
307257
the futex.

sysdeps/nptl/lowlevellock-futex.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#define FUTEX_WAKE_BITSET 10
3939
#define FUTEX_WAIT_REQUEUE_PI 11
4040
#define FUTEX_CMP_REQUEUE_PI 12
41+
#define FUTEX_LOCK_PI2 13
4142
#define FUTEX_PRIVATE_FLAG 128
4243
#define FUTEX_CLOCK_REALTIME 256
4344

0 commit comments

Comments
 (0)