about summary refs log tree commit diff
path: root/sysdeps/nptl/lowlevellock.h
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/nptl/lowlevellock.h')
-rw-r--r--sysdeps/nptl/lowlevellock.h102
1 files changed, 102 insertions, 0 deletions
diff --git a/sysdeps/nptl/lowlevellock.h b/sysdeps/nptl/lowlevellock.h
index 176ba96251..be60c9ac28 100644
--- a/sysdeps/nptl/lowlevellock.h
+++ b/sysdeps/nptl/lowlevellock.h
@@ -20,6 +20,7 @@
 #define _LOWLEVELLOCK_H	1
 
 #include <atomic.h>
+#include <elision-conf.h>
 #include <lowlevellock-futex.h>
 #include <time.h>
 
@@ -160,4 +161,105 @@ libc_hidden_proto (__lll_lock_wait)
 #define LLL_LOCK_INITIALIZER		(0)
 #define LLL_LOCK_INITIALIZER_LOCKED	(1)
 
+/* Elision support.  */
+
+#if ENABLE_ELISION_SUPPORT
+/* Force elision for all new locks.  This is used to decide whether
+   existing DEFAULT locks should be automatically upgraded to elision
+   in pthread_mutex_lock.  Disabled for suid programs.  Only used when
+   elision is available.  */
+extern int __pthread_force_elision;
+libc_hidden_proto (__pthread_force_elision)
+
+extern void __lll_elision_init (void) attribute_hidden;
+extern int __lll_clocklock_elision (int *futex, short *adapt_count,
+                                    clockid_t clockid,
+				    const struct __timespec64 *timeout,
+				    int private);
+libc_hidden_proto (__lll_clocklock_elision)
+
+extern int __lll_lock_elision (int *futex, short *adapt_count, int private);
+libc_hidden_proto (__lll_lock_elision)
+
+# if ELISION_UNLOCK_NEEDS_ADAPT_COUNT
+extern int __lll_unlock_elision (int *lock, short *adapt_count, int private);
+# else
+extern int __lll_unlock_elision (int *lock, int private);
+# endif
+libc_hidden_proto (__lll_unlock_elision)
+
+extern int __lll_trylock_elision (int *lock, short *adapt_count);
+libc_hidden_proto (__lll_trylock_elision)
+
+# define lll_clocklock_elision(futex, adapt_count, clockid, timeout, private) \
+  __lll_clocklock_elision (&(futex), &(adapt_count), clockid, timeout, private)
+# define lll_lock_elision(futex, adapt_count, private)		\
+  __lll_lock_elision (&(futex), &(adapt_count), private)
+# define lll_trylock_elision(futex, adapt_count)	\
+  __lll_trylock_elision (&(futex), &(adapt_count))
+# if ELISION_UNLOCK_NEEDS_ADAPT_COUNT
+#  define lll_unlock_elision(futex, adapt_count, private)	\
+  __lll_unlock_elision (&(futex), &(adapt_count), private)
+# else
+#  define lll_unlock_elision(futex, adapt_count, private)	\
+  __lll_unlock_elision (&(futex), private)
+# endif
+
+/* Automatically enable elision for existing user lock kinds.  */
+# define FORCE_ELISION(m, s)                                            \
+  if (__pthread_force_elision)                                          \
+    {                                                                   \
+      /* See concurrency notes regarding __kind in                      \
+         struct __pthread_mutex_s in                                    \
+         sysdeps/nptl/bits/thread-shared-types.h.                       \
+                                                                        \
+         There are the following cases for the kind of a mutex          \
+         (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags      \
+         PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \
+         only one of both flags can be set):                            \
+         - both flags are not set:                                      \
+         This is the first lock operation for this mutex.  Enable       \
+         elision as it is not enabled so far.                           \
+         Note: It can happen that multiple threads are calling e.g.     \
+         pthread_mutex_lock at the same time as the first lock          \
+         operation for this mutex.  Then elision is enabled for this    \
+         mutex by multiple threads.  Storing with relaxed MO is enough  \
+         as all threads will store the same new value for the kind of   \
+         the mutex.  But we have to ensure that we always use the       \
+         elision path regardless if this thread has enabled elision or  \
+         another one.                                                   \
+                                                                        \
+         - PTHREAD_MUTEX_ELISION_NP flag is set:                        \
+         Elision was already enabled for this mutex by a previous lock  \
+         operation.  See case above.  Just use the elision path.        \
+                                                                        \
+         - PTHREAD_MUTEX_NO_ELISION_NP flag is set:                     \
+         Elision was explicitly disabled by pthread_mutexattr_settype.  \
+         Do not use the elision path.                                   \
+         Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be       \
+         changed after mutex initialization.  */                        \
+      int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind));     \
+      if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0)           \
+        {                                                               \
+          mutex_kind |= PTHREAD_MUTEX_ELISION_NP;                       \
+          atomic_store_relaxed (&((m)->__data.__kind), mutex_kind);     \
+        }                                                               \
+      if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0)                 \
+        {                                                               \
+          s;                                                            \
+        }                                                               \
+    }
+
+#else /* !ENABLE_ELISION_SUPPORT */
+
+# define lll_clocklock_elision(futex, adapt_count, clockid, abstime, private) \
+  __futex_clocklock64 (&(futex), clockid, abstime, private)
+# define lll_lock_elision(lock, try_lock, private)	\
+  ({ lll_lock (lock, private); 0; })
+# define lll_trylock_elision(a,t) lll_trylock(a)
+# define lll_unlock_elision(a,b,c) ({ lll_unlock (a,c); 0; })
+# define FORCE_ELISION(m, s)
+
+#endif /* !ENABLE_ELISION_SUPPORT */
+
 #endif	/* lowlevellock.h */