[18/28] nptl: Add futex_trylock_pi

Message ID 20201118195552.2687336-19-adhemerval.zanella@linaro.org
State Superseded
Headers
Series More Linux syscall refactor |

Commit Message

Adhemerval Zanella Netto Nov. 18, 2020, 7:55 p.m. UTC
  This is similar to other futex wrappers on futex-internal.

Checked on x86_64-linux-gnu.
---
 nptl/pthread_mutex_trylock.c      |  9 +++-----
 sysdeps/nptl/futex-internal.h     | 36 +++++++++++++++++++++++++++++++
 sysdeps/nptl/lowlevellock-futex.h |  5 +++++
 3 files changed, 44 insertions(+), 6 deletions(-)
  

Patch

diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
index 2130f52529..be9d9a3bac 100644
--- a/nptl/pthread_mutex_trylock.c
+++ b/nptl/pthread_mutex_trylock.c
@@ -297,12 +297,9 @@  __pthread_mutex_trylock (pthread_mutex_t *mutex)
 	    int private = (robust
 			   ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
 			   : PTHREAD_MUTEX_PSHARED (mutex));
-	    int e = INTERNAL_SYSCALL_CALL (futex, &mutex->__data.__lock,
-					   __lll_private_flag (FUTEX_TRYLOCK_PI,
-							       private), 0, 0);
-
-	    if (INTERNAL_SYSCALL_ERROR_P (e)
-		&& INTERNAL_SYSCALL_ERRNO (e) == EWOULDBLOCK)
+	    if (futex_trylock_pi ((unsigned int *) &mutex->__data.__lock,
+				  private)
+		== -EWOULDBLOCK)
 	      {
 		/* The kernel has not yet finished the mutex owner death.
 		   We do not need to ensure ordering wrt another memory
diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h
index c27d0cdac8..3cda6c5762 100644
--- a/sysdeps/nptl/futex-internal.h
+++ b/sysdeps/nptl/futex-internal.h
@@ -483,6 +483,42 @@  futex_lock_pi64 (int *futex_word, const struct __timespec64 *abstime,
     }
 }
 
+/* This operaration is similar to futex_lock_pi and it is used when the lock
+   information contains stale state (FUTEX_WAITERS and/or FUTEX_OWNER_DIED).
+   User space can not handle this condition in a race-free manner, but kernel
+   might handle it and acquire the futex.
+
+   Returns:
+
+     - 0 if woken by a PI unlock operation or spuriously.
+     - EAGAIN if the futex owner thread ID is about to exit, but has not yet
+       handled the state cleanup.
+     - EDEADLK if the futex is already locked by the caller.
+     - ESRCH if the thread ID int he futex does not exist.
+     - EINVAL is the state is corrupted or if there is a waiter on the
+       futex.
+*/
+static __always_inline int
+futex_trylock_pi (unsigned int *futex_word, int private)
+{
+  int err = lll_futex_trylock_pi ((int *) futex_word, private);
+  switch (err)
+    {
+    case 0:
+    case -EAGAIN: /* EWOULDBLOCK  */
+    case -EINTR:
+    case -ESRCH:
+    case -EDEADLK:
+    case -EPERM:
+      return -err;
+
+    case -EINVAL:
+    case -EFAULT:
+    default:
+      futex_fatal_error ();
+    }
+}
+
 /* Wakes the top priority waiter that called a futex_lock_pi operation on
    the futex.
 
diff --git a/sysdeps/nptl/lowlevellock-futex.h b/sysdeps/nptl/lowlevellock-futex.h
index 2209ca76a1..0440aeb390 100644
--- a/sysdeps/nptl/lowlevellock-futex.h
+++ b/sysdeps/nptl/lowlevellock-futex.h
@@ -144,6 +144,11 @@ 
 		     __lll_private_flag (FUTEX_LOCK_PI, private),	\
 		     0, abstime)
 
+#define lll_futex_trylock_pi(futexp, private)				\
+  lll_futex_syscall (4, futexp,						\
+		     __lll_private_flag (FUTEX_TRYLOCK_PI, private),	\
+		     0, 0)
+
 #define lll_futex_timed_unlock_pi(futexp, private) 			\
   lll_futex_syscall (4, futexp,						\
 		     __lll_private_flag (FUTEX_UNLOCK_PI, private),	\