[RFC,2/3] nptl: Use futex_lock_pi2()

Message ID 20210621111650.1164689-3-kurt@linutronix.de
State Superseded
Headers
Series nptl: Introduce and use FUTEX_LOCK_PI2 |

Checks

Context Check Description
dj/TryBot-apply_patch success Patch applied to master at the time it was sent

Commit Message

Kurt Kanzenbach June 21, 2021, 11:16 a.m. UTC
  Use futex_lock_pi2() by default, because it supports selectable clocks.

On older kernels futex_lock_pi2() will return ENOSYS. Fallback to
futex_lock_pi() and don't support CLOCK_MONOTONIC then.

Signed-off-by: Kurt Kanzenbach <kurt@linutronix.de>
---
 nptl/pthread_mutex_timedlock.c | 24 ++++++++++++++++++------
 sysdeps/nptl/futex-internal.h  | 17 +++++++++++++++++
 2 files changed, 35 insertions(+), 6 deletions(-)
  

Patch

diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
index 5afd6222d61e..e7e001d2c17a 100644
--- a/nptl/pthread_mutex_timedlock.c
+++ b/nptl/pthread_mutex_timedlock.c
@@ -300,11 +300,15 @@  __pthread_mutex_clocklock_common (pthread_mutex_t *mutex,
     case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
     case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
       {
-	/* Currently futex FUTEX_LOCK_PI operation only provides support for
-	   CLOCK_REALTIME and trying to emulate by converting a
-	   CLOCK_MONOTONIC to CLOCK_REALTIME will take in account possible
-	   changes to the wall clock.  */
-	if (__glibc_unlikely (clockid != CLOCK_REALTIME))
+       /* Currently futex FUTEX_LOCK_PI operation only provides support for
+          CLOCK_REALTIME and trying to emulate by converting a
+          CLOCK_MONOTONIC to CLOCK_REALTIME will take in account possible
+          changes to the wall clock.
+
+	  However, newer Linux kernels support FUTEX_LOCK_PI2 with selectable
+	  clock support.  */
+	if (__glibc_unlikely (! futex_lockpi2_supported () &&
+			      clockid != CLOCK_REALTIME))
 	  return EINVAL;
 
 	int kind, robust;
@@ -370,7 +374,15 @@  __pthread_mutex_clocklock_common (pthread_mutex_t *mutex,
 	    int private = (robust
 			   ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
 			   : PTHREAD_MUTEX_PSHARED (mutex));
-	    int e = futex_lock_pi64 (&mutex->__data.__lock, abstime, private);
+	    int e = futex_lock_pi2_64 (&mutex->__data.__lock, clockid, abstime,
+				       private);
+
+	    /* Use futex futex_lock_pi2() by default. This doesn't work for
+	       older kernels.  So fallback to futex_lock_pi() then. The clockid
+	       is checked above already.  */
+	    if (__glibc_unlikely (e == ENOSYS))
+		e = futex_lock_pi64 (&mutex->__data.__lock, abstime, private);
+
 	    if (e == ETIMEDOUT)
 	      return ETIMEDOUT;
 	    else if (e == ESRCH || e == EDEADLK)
diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h
index 60bdae84405c..b5f101b484c2 100644
--- a/sysdeps/nptl/futex-internal.h
+++ b/sysdeps/nptl/futex-internal.h
@@ -372,6 +372,23 @@  futex_lock_pi2_64 (int *futex_word, clockid_t clockid,
     }
 }
 
+/* Checks whether FUTEX_LOCK_PI2 operation is available on the running Linux
+   kernel. FUTEX_LOCK_PI2 has been introduced on newer kernel versions.
+
+   Returns true if FUTEX_LOCK_PI2 is available, false otherwise.  */
+static __always_inline bool
+futex_lockpi2_supported (void)
+{
+  int err = INTERNAL_SYSCALL_CALL (futex_time64, NULL, FUTEX_LOCK_PI2, 0, NULL);
+
+#ifndef __ASSUME_TIME64_SYSCALLS
+  if (err == -ENOSYS)
+      err = INTERNAL_SYSCALL_CALL (futex, NULL, FUTEX_LOCK_PI2, 0, NULL);
+#endif
+
+  return err != -ENOSYS;
+}
+
 /* Wakes the top priority waiter that called a futex_lock_pi operation on
    the futex.