d8307d
commit 403b4feb22dcbc85ace72a361d2a951380372471
d8307d
Author: Stefan Liebler <stli@linux.ibm.com>
d8307d
Date:   Wed Oct 17 12:23:04 2018 +0200
d8307d
d8307d
    Fix race in pthread_mutex_lock while promoting to PTHREAD_MUTEX_ELISION_NP [BZ #23275]
d8307d
    
d8307d
    The race leads either to pthread_mutex_destroy returning EBUSY
d8307d
    or triggering an assertion (See description in bugzilla).
d8307d
    
d8307d
    This patch is fixing the race by ensuring that the elision path is
d8307d
    used in all cases if elision is enabled by the GLIBC_TUNABLES framework.
d8307d
    
d8307d
    The __kind variable in struct __pthread_mutex_s is accessed concurrently.
d8307d
    Therefore we are now using the atomic macros.
d8307d
    
d8307d
    The new testcase tst-mutex10 is triggering the race on s390x and intel.
d8307d
    Presumably also on power, but I don't have access to a power machine
d8307d
    with lock-elision. At least the code for power is the same as on the other
d8307d
    two architectures.
d8307d
    
d8307d
    ChangeLog:
d8307d
    
d8307d
            [BZ #23275]
d8307d
            * nptl/tst-mutex10.c: New File.
d8307d
            * nptl/Makefile (tests): Add tst-mutex10.
d8307d
            (tst-mutex10-ENV): New variable.
d8307d
            * sysdeps/unix/sysv/linux/s390/force-elision.h: (FORCE_ELISION):
d8307d
            Ensure that elision path is used if elision is available.
d8307d
            * sysdeps/unix/sysv/linux/powerpc/force-elision.h (FORCE_ELISION):
d8307d
            Likewise.
d8307d
            * sysdeps/unix/sysv/linux/x86/force-elision.h: (FORCE_ELISION):
d8307d
            Likewise.
d8307d
            * nptl/pthreadP.h (PTHREAD_MUTEX_TYPE, PTHREAD_MUTEX_TYPE_ELISION)
d8307d
            (PTHREAD_MUTEX_PSHARED): Use atomic_load_relaxed.
d8307d
            * nptl/pthread_mutex_consistent.c (pthread_mutex_consistent): Likewise.
d8307d
            * nptl/pthread_mutex_getprioceiling.c (pthread_mutex_getprioceiling):
d8307d
            Likewise.
d8307d
            * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full)
d8307d
            (__pthread_mutex_cond_lock_adjust): Likewise.
d8307d
            * nptl/pthread_mutex_setprioceiling.c (pthread_mutex_setprioceiling):
d8307d
            Likewise.
d8307d
            * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Likewise.
d8307d
            * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock): Likewise.
d8307d
            * nptl/pthread_mutex_unlock.c (__pthread_mutex_unlock_full): Likewise.
d8307d
            * sysdeps/nptl/bits/thread-shared-types.h (struct __pthread_mutex_s):
d8307d
            Add comments.
d8307d
            * nptl/pthread_mutex_destroy.c (__pthread_mutex_destroy):
d8307d
            Use atomic_load_relaxed and atomic_store_relaxed.
d8307d
            * nptl/pthread_mutex_init.c (__pthread_mutex_init):
d8307d
            Use atomic_store_relaxed.
d8307d
d8307d
diff --git a/nptl/Makefile b/nptl/Makefile
d8307d
index be8066524cdc57db..49b6faa330c492e0 100644
d8307d
--- a/nptl/Makefile
d8307d
+++ b/nptl/Makefile
d8307d
@@ -241,9 +241,9 @@ LDLIBS-tst-minstack-throw = -lstdc++
d8307d
 
d8307d
 tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
d8307d
 	tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
d8307d
-	tst-mutex7 tst-mutex9 tst-mutex5a tst-mutex7a tst-mutex7robust \
d8307d
-	tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
d8307d
-	tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \
d8307d
+	tst-mutex7 tst-mutex9 tst-mutex10 tst-mutex5a tst-mutex7a \
d8307d
+	tst-mutex7robust tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 \
d8307d
+	tst-mutexpi5 tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \
d8307d
 	tst-mutexpi9 \
d8307d
 	tst-spin1 tst-spin2 tst-spin3 tst-spin4 \
d8307d
 	tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
d8307d
@@ -709,6 +709,8 @@ endif
d8307d
 
d8307d
 $(objpfx)tst-compat-forwarder: $(objpfx)tst-compat-forwarder-mod.so
d8307d
 
d8307d
+tst-mutex10-ENV = GLIBC_TUNABLES=glibc.elision.enable=1
d8307d
+
d8307d
 # The tests here better do not run in parallel
d8307d
 ifneq ($(filter %tests,$(MAKECMDGOALS)),)
d8307d
 .NOTPARALLEL:
d8307d
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
d8307d
index 13bdb11133536195..19efe1e35feed5be 100644
d8307d
--- a/nptl/pthreadP.h
d8307d
+++ b/nptl/pthreadP.h
d8307d
@@ -110,19 +110,23 @@ enum
d8307d
 };
d8307d
 #define PTHREAD_MUTEX_PSHARED_BIT 128
d8307d
 
d8307d
+/* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+   in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
 #define PTHREAD_MUTEX_TYPE(m) \
d8307d
-  ((m)->__data.__kind & 127)
d8307d
+  (atomic_load_relaxed (&((m)->__data.__kind)) & 127)
d8307d
 /* Don't include NO_ELISION, as that type is always the same
d8307d
    as the underlying lock type.  */
d8307d
 #define PTHREAD_MUTEX_TYPE_ELISION(m) \
d8307d
-  ((m)->__data.__kind & (127|PTHREAD_MUTEX_ELISION_NP))
d8307d
+  (atomic_load_relaxed (&((m)->__data.__kind))	\
d8307d
+   & (127 | PTHREAD_MUTEX_ELISION_NP))
d8307d
 
d8307d
 #if LLL_PRIVATE == 0 && LLL_SHARED == 128
d8307d
 # define PTHREAD_MUTEX_PSHARED(m) \
d8307d
-  ((m)->__data.__kind & 128)
d8307d
+  (atomic_load_relaxed (&((m)->__data.__kind)) & 128)
d8307d
 #else
d8307d
 # define PTHREAD_MUTEX_PSHARED(m) \
d8307d
-  (((m)->__data.__kind & 128) ? LLL_SHARED : LLL_PRIVATE)
d8307d
+  ((atomic_load_relaxed (&((m)->__data.__kind)) & 128)	\
d8307d
+   ? LLL_SHARED : LLL_PRIVATE)
d8307d
 #endif
d8307d
 
d8307d
 /* The kernel when waking robust mutexes on exit never uses
d8307d
diff --git a/nptl/pthread_mutex_consistent.c b/nptl/pthread_mutex_consistent.c
d8307d
index 85b8e1a6cb027e9b..4fbd875430439e4d 100644
d8307d
--- a/nptl/pthread_mutex_consistent.c
d8307d
+++ b/nptl/pthread_mutex_consistent.c
d8307d
@@ -23,8 +23,11 @@
d8307d
 int
d8307d
 pthread_mutex_consistent (pthread_mutex_t *mutex)
d8307d
 {
d8307d
-  /* Test whether this is a robust mutex with a dead owner.  */
d8307d
-  if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
d8307d
+  /* Test whether this is a robust mutex with a dead owner.
d8307d
+     See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+     in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+  if ((atomic_load_relaxed (&(mutex->__data.__kind))
d8307d
+       & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
d8307d
       || mutex->__data.__owner != PTHREAD_MUTEX_INCONSISTENT)
d8307d
     return EINVAL;
d8307d
 
d8307d
diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c
d8307d
index 5a22611541995778..713ea684962fefc1 100644
d8307d
--- a/nptl/pthread_mutex_destroy.c
d8307d
+++ b/nptl/pthread_mutex_destroy.c
d8307d
@@ -27,12 +27,17 @@ __pthread_mutex_destroy (pthread_mutex_t *mutex)
d8307d
 {
d8307d
   LIBC_PROBE (mutex_destroy, 1, mutex);
d8307d
 
d8307d
-  if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
d8307d
+  /* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+     in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+  if ((atomic_load_relaxed (&(mutex->__data.__kind))
d8307d
+       & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
d8307d
       && mutex->__data.__nusers != 0)
d8307d
     return EBUSY;
d8307d
 
d8307d
-  /* Set to an invalid value.  */
d8307d
-  mutex->__data.__kind = -1;
d8307d
+  /* Set to an invalid value.  Relaxed MO is enough as it is undefined behavior
d8307d
+     if the mutex is used after it has been destroyed.  But you can reinitialize
d8307d
+     it with pthread_mutex_init.  */
d8307d
+  atomic_store_relaxed (&(mutex->__data.__kind), -1);
d8307d
 
d8307d
   return 0;
d8307d
 }
d8307d
diff --git a/nptl/pthread_mutex_getprioceiling.c b/nptl/pthread_mutex_getprioceiling.c
d8307d
index efa37b0d99201f57..ee85949578475f3a 100644
d8307d
--- a/nptl/pthread_mutex_getprioceiling.c
d8307d
+++ b/nptl/pthread_mutex_getprioceiling.c
d8307d
@@ -24,7 +24,9 @@
d8307d
 int
d8307d
 pthread_mutex_getprioceiling (const pthread_mutex_t *mutex, int *prioceiling)
d8307d
 {
d8307d
-  if (__builtin_expect ((mutex->__data.__kind
d8307d
+  /* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+     in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+  if (__builtin_expect ((atomic_load_relaxed (&(mutex->__data.__kind))
d8307d
 			 & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0, 0))
d8307d
     return EINVAL;
d8307d
 
d8307d
diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c
d8307d
index d8fe4737289c0bd7..5cf290c272e27915 100644
d8307d
--- a/nptl/pthread_mutex_init.c
d8307d
+++ b/nptl/pthread_mutex_init.c
d8307d
@@ -101,7 +101,7 @@ __pthread_mutex_init (pthread_mutex_t *mutex,
d8307d
   memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T);
d8307d
 
d8307d
   /* Copy the values from the attribute.  */
d8307d
-  mutex->__data.__kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS;
d8307d
+  int mutex_kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS;
d8307d
 
d8307d
   if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0)
d8307d
     {
d8307d
@@ -111,17 +111,17 @@ __pthread_mutex_init (pthread_mutex_t *mutex,
d8307d
 	return ENOTSUP;
d8307d
 #endif
d8307d
 
d8307d
-      mutex->__data.__kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP;
d8307d
+      mutex_kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP;
d8307d
     }
d8307d
 
d8307d
   switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK)
d8307d
     {
d8307d
     case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
d8307d
-      mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP;
d8307d
+      mutex_kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP;
d8307d
       break;
d8307d
 
d8307d
     case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
d8307d
-      mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP;
d8307d
+      mutex_kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP;
d8307d
 
d8307d
       int ceiling = (imutexattr->mutexkind
d8307d
 		     & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
d8307d
@@ -145,7 +145,11 @@ __pthread_mutex_init (pthread_mutex_t *mutex,
d8307d
      FUTEX_PRIVATE_FLAG FUTEX_WAKE.  */
d8307d
   if ((imutexattr->mutexkind & (PTHREAD_MUTEXATTR_FLAG_PSHARED
d8307d
 				| PTHREAD_MUTEXATTR_FLAG_ROBUST)) != 0)
d8307d
-    mutex->__data.__kind |= PTHREAD_MUTEX_PSHARED_BIT;
d8307d
+    mutex_kind |= PTHREAD_MUTEX_PSHARED_BIT;
d8307d
+
d8307d
+  /* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+     in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+  atomic_store_relaxed (&(mutex->__data.__kind), mutex_kind);
d8307d
 
d8307d
   /* Default values: mutex not used yet.  */
d8307d
   // mutex->__count = 0;	already done by memset
d8307d
diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
d8307d
index 1519c142bd6ec5cc..29cc143e6cbf2421 100644
d8307d
--- a/nptl/pthread_mutex_lock.c
d8307d
+++ b/nptl/pthread_mutex_lock.c
d8307d
@@ -62,6 +62,8 @@ static int __pthread_mutex_lock_full (pthread_mutex_t *mutex)
d8307d
 int
d8307d
 __pthread_mutex_lock (pthread_mutex_t *mutex)
d8307d
 {
d8307d
+  /* See concurrency notes regarding mutex type which is loaded from __kind
d8307d
+     in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
   unsigned int type = PTHREAD_MUTEX_TYPE_ELISION (mutex);
d8307d
 
d8307d
   LIBC_PROBE (mutex_entry, 1, mutex);
d8307d
@@ -350,8 +352,14 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
d8307d
     case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
d8307d
     case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
d8307d
       {
d8307d
-	int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
d8307d
-	int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
d8307d
+	int kind, robust;
d8307d
+	{
d8307d
+	  /* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+	     in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+	  int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
d8307d
+	  kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP;
d8307d
+	  robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
d8307d
+	}
d8307d
 
d8307d
 	if (robust)
d8307d
 	  {
d8307d
@@ -502,7 +510,10 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
d8307d
     case PTHREAD_MUTEX_PP_NORMAL_NP:
d8307d
     case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
d8307d
       {
d8307d
-	int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
d8307d
+	/* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+	   in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+	int kind = atomic_load_relaxed (&(mutex->__data.__kind))
d8307d
+	  & PTHREAD_MUTEX_KIND_MASK_NP;
d8307d
 
d8307d
 	oldval = mutex->__data.__lock;
d8307d
 
d8307d
@@ -607,15 +618,18 @@ hidden_def (__pthread_mutex_lock)
d8307d
 void
d8307d
 __pthread_mutex_cond_lock_adjust (pthread_mutex_t *mutex)
d8307d
 {
d8307d
-  assert ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0);
d8307d
-  assert ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0);
d8307d
-  assert ((mutex->__data.__kind & PTHREAD_MUTEX_PSHARED_BIT) == 0);
d8307d
+  /* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+     in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+  int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
d8307d
+  assert ((mutex_kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0);
d8307d
+  assert ((mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0);
d8307d
+  assert ((mutex_kind & PTHREAD_MUTEX_PSHARED_BIT) == 0);
d8307d
 
d8307d
   /* Record the ownership.  */
d8307d
   pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
d8307d
   mutex->__data.__owner = id;
d8307d
 
d8307d
-  if (mutex->__data.__kind == PTHREAD_MUTEX_PI_RECURSIVE_NP)
d8307d
+  if (mutex_kind == PTHREAD_MUTEX_PI_RECURSIVE_NP)
d8307d
     ++mutex->__data.__count;
d8307d
 }
d8307d
 #endif
d8307d
diff --git a/nptl/pthread_mutex_setprioceiling.c b/nptl/pthread_mutex_setprioceiling.c
d8307d
index 8594874f8588b7a8..8306cabcf4e56174 100644
d8307d
--- a/nptl/pthread_mutex_setprioceiling.c
d8307d
+++ b/nptl/pthread_mutex_setprioceiling.c
d8307d
@@ -27,9 +27,10 @@ int
d8307d
 pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
d8307d
 			      int *old_ceiling)
d8307d
 {
d8307d
-  /* The low bits of __kind aren't ever changed after pthread_mutex_init,
d8307d
-     so we don't need a lock yet.  */
d8307d
-  if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0)
d8307d
+  /* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+     in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+  if ((atomic_load_relaxed (&(mutex->__data.__kind))
d8307d
+       & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0)
d8307d
     return EINVAL;
d8307d
 
d8307d
   /* See __init_sched_fifo_prio.  */
d8307d
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
d8307d
index 28237b0e58cfcaf5..888c12fe28b2ebfd 100644
d8307d
--- a/nptl/pthread_mutex_timedlock.c
d8307d
+++ b/nptl/pthread_mutex_timedlock.c
d8307d
@@ -53,6 +53,8 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex,
d8307d
   /* We must not check ABSTIME here.  If the thread does not block
d8307d
      abstime must not be checked for a valid value.  */
d8307d
 
d8307d
+  /* See concurrency notes regarding mutex type which is loaded from __kind
d8307d
+     in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
   switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex),
d8307d
 			    PTHREAD_MUTEX_TIMED_NP))
d8307d
     {
d8307d
@@ -338,8 +340,14 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex,
d8307d
     case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
d8307d
     case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
d8307d
       {
d8307d
-	int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
d8307d
-	int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
d8307d
+	int kind, robust;
d8307d
+	{
d8307d
+	  /* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+	     in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+	  int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
d8307d
+	  kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP;
d8307d
+	  robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
d8307d
+	}
d8307d
 
d8307d
 	if (robust)
d8307d
 	  {
d8307d
@@ -509,7 +517,10 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex,
d8307d
     case PTHREAD_MUTEX_PP_NORMAL_NP:
d8307d
     case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
d8307d
       {
d8307d
-	int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
d8307d
+	/* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+	   in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+	int kind = atomic_load_relaxed (&(mutex->__data.__kind))
d8307d
+	  & PTHREAD_MUTEX_KIND_MASK_NP;
d8307d
 
d8307d
 	oldval = mutex->__data.__lock;
d8307d
 
d8307d
diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
d8307d
index 7de61f4f688c1537..fa90c1d1e6f5afc2 100644
d8307d
--- a/nptl/pthread_mutex_trylock.c
d8307d
+++ b/nptl/pthread_mutex_trylock.c
d8307d
@@ -36,6 +36,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
d8307d
   int oldval;
d8307d
   pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
d8307d
 
d8307d
+  /* See concurrency notes regarding mutex type which is loaded from __kind
d8307d
+     in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
   switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex),
d8307d
 			    PTHREAD_MUTEX_TIMED_NP))
d8307d
     {
d8307d
@@ -199,8 +201,14 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
d8307d
     case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
d8307d
     case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
d8307d
       {
d8307d
-	int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
d8307d
-	int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
d8307d
+	int kind, robust;
d8307d
+	{
d8307d
+	  /* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+	     in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+	  int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
d8307d
+	  kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP;
d8307d
+	  robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
d8307d
+	}
d8307d
 
d8307d
 	if (robust)
d8307d
 	  /* Note: robust PI futexes are signaled by setting bit 0.  */
d8307d
@@ -325,7 +333,10 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
d8307d
     case PTHREAD_MUTEX_PP_NORMAL_NP:
d8307d
     case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
d8307d
       {
d8307d
-	int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
d8307d
+	/* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+	   in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+	int kind = atomic_load_relaxed (&(mutex->__data.__kind))
d8307d
+	  & PTHREAD_MUTEX_KIND_MASK_NP;
d8307d
 
d8307d
 	oldval = mutex->__data.__lock;
d8307d
 
d8307d
diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c
d8307d
index 9ea62943b7c6b159..68d04d53955584e5 100644
d8307d
--- a/nptl/pthread_mutex_unlock.c
d8307d
+++ b/nptl/pthread_mutex_unlock.c
d8307d
@@ -35,6 +35,8 @@ int
d8307d
 attribute_hidden
d8307d
 __pthread_mutex_unlock_usercnt (pthread_mutex_t *mutex, int decr)
d8307d
 {
d8307d
+  /* See concurrency notes regarding mutex type which is loaded from __kind
d8307d
+     in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
   int type = PTHREAD_MUTEX_TYPE_ELISION (mutex);
d8307d
   if (__builtin_expect (type &
d8307d
 		~(PTHREAD_MUTEX_KIND_MASK_NP|PTHREAD_MUTEX_ELISION_FLAGS_NP), 0))
d8307d
@@ -222,13 +224,19 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
d8307d
       /* If the previous owner died and the caller did not succeed in
d8307d
 	 making the state consistent, mark the mutex as unrecoverable
d8307d
 	 and make all waiters.  */
d8307d
-      if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0
d8307d
+      /* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+	 in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+      if ((atomic_load_relaxed (&(mutex->__data.__kind))
d8307d
+	   & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0
d8307d
 	  && __builtin_expect (mutex->__data.__owner
d8307d
 			       == PTHREAD_MUTEX_INCONSISTENT, 0))
d8307d
       pi_notrecoverable:
d8307d
        newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
d8307d
 
d8307d
-      if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
d8307d
+      /* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+	 in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+      if ((atomic_load_relaxed (&(mutex->__data.__kind))
d8307d
+	   & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
d8307d
 	{
d8307d
 	continue_pi_robust:
d8307d
 	  /* Remove mutex from the list.
d8307d
@@ -251,7 +259,10 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr)
d8307d
       /* Unlock.  Load all necessary mutex data before releasing the mutex
d8307d
 	 to not violate the mutex destruction requirements (see
d8307d
 	 lll_unlock).  */
d8307d
-      int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
d8307d
+      /* See concurrency notes regarding __kind in struct __pthread_mutex_s
d8307d
+	 in sysdeps/nptl/bits/thread-shared-types.h.  */
d8307d
+      int robust = atomic_load_relaxed (&(mutex->__data.__kind))
d8307d
+	& PTHREAD_MUTEX_ROBUST_NORMAL_NP;
d8307d
       private = (robust
d8307d
 		 ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
d8307d
 		 : PTHREAD_MUTEX_PSHARED (mutex));
d8307d
diff --git a/nptl/tst-mutex10.c b/nptl/tst-mutex10.c
d8307d
new file mode 100644
d8307d
index 0000000000000000..e1113ca60a7c8db5
d8307d
--- /dev/null
d8307d
+++ b/nptl/tst-mutex10.c
d8307d
@@ -0,0 +1,109 @@
d8307d
+/* Testing race while enabling lock elision.
d8307d
+   Copyright (C) 2018 Free Software Foundation, Inc.
d8307d
+   This file is part of the GNU C Library.
d8307d
+
d8307d
+   The GNU C Library is free software; you can redistribute it and/or
d8307d
+   modify it under the terms of the GNU Lesser General Public
d8307d
+   License as published by the Free Software Foundation; either
d8307d
+   version 2.1 of the License, or (at your option) any later version.
d8307d
+
d8307d
+   The GNU C Library is distributed in the hope that it will be useful,
d8307d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
d8307d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
d8307d
+   Lesser General Public License for more details.
d8307d
+
d8307d
+   You should have received a copy of the GNU Lesser General Public
d8307d
+   License along with the GNU C Library; if not, see
d8307d
+   <http://www.gnu.org/licenses/>.  */
d8307d
+#include <stdio.h>
d8307d
+#include <stdlib.h>
d8307d
+#include <stdint.h>
d8307d
+#include <pthread.h>
d8307d
+#include <unistd.h>
d8307d
+#include <getopt.h>
d8307d
+#include <support/support.h>
d8307d
+#include <support/xthread.h>
d8307d
+
d8307d
+static pthread_barrier_t barrier;
d8307d
+static pthread_mutex_t mutex;
d8307d
+static long long int iteration_count = 1000000;
d8307d
+static unsigned int thread_count = 3;
d8307d
+
d8307d
+static void *
d8307d
+thr_func (void *arg)
d8307d
+{
d8307d
+  long long int i;
d8307d
+  for (i = 0; i < iteration_count; i++)
d8307d
+    {
d8307d
+      if ((uintptr_t) arg == 0)
d8307d
+	{
d8307d
+	  xpthread_mutex_destroy (&mutex);
d8307d
+	  xpthread_mutex_init (&mutex, NULL);
d8307d
+	}
d8307d
+
d8307d
+      xpthread_barrier_wait (&barrier);
d8307d
+
d8307d
+      /* Test if enabling lock elision works if it is enabled concurrently.
d8307d
+	 There was a race in FORCE_ELISION macro which leads to either
d8307d
+	 pthread_mutex_destroy returning EBUSY as the owner was recorded
d8307d
+	 by pthread_mutex_lock - in "normal mutex" code path - but was not
d8307d
+	 resetted in pthread_mutex_unlock - in "elision" code path.
d8307d
+	 Or it leads to the assertion in nptl/pthread_mutex_lock.c:
d8307d
+	 assert (mutex->__data.__owner == 0);
d8307d
+	 Please ensure that the test is run with lock elision:
d8307d
+	 export GLIBC_TUNABLES=glibc.elision.enable=1  */
d8307d
+      xpthread_mutex_lock (&mutex);
d8307d
+      xpthread_mutex_unlock (&mutex);
d8307d
+
d8307d
+      xpthread_barrier_wait (&barrier);
d8307d
+    }
d8307d
+  return NULL;
d8307d
+}
d8307d
+
d8307d
+static int
d8307d
+do_test (void)
d8307d
+{
d8307d
+  unsigned int i;
d8307d
+  printf ("Starting %d threads to run %lld iterations.\n",
d8307d
+	  thread_count, iteration_count);
d8307d
+
d8307d
+  pthread_t *threads = xmalloc (thread_count * sizeof (pthread_t));
d8307d
+  xpthread_barrier_init (&barrier, NULL, thread_count);
d8307d
+  xpthread_mutex_init (&mutex, NULL);
d8307d
+
d8307d
+  for (i = 0; i < thread_count; i++)
d8307d
+    threads[i] = xpthread_create (NULL, thr_func, (void *) (uintptr_t) i);
d8307d
+
d8307d
+  for (i = 0; i < thread_count; i++)
d8307d
+    xpthread_join (threads[i]);
d8307d
+
d8307d
+  xpthread_barrier_destroy (&barrier);
d8307d
+  free (threads);
d8307d
+
d8307d
+  return EXIT_SUCCESS;
d8307d
+}
d8307d
+
d8307d
+#define OPT_ITERATIONS	10000
d8307d
+#define OPT_THREADS	10001
d8307d
+#define CMDLINE_OPTIONS						\
d8307d
+  { "iterations", required_argument, NULL, OPT_ITERATIONS },	\
d8307d
+  { "threads", required_argument, NULL, OPT_THREADS },
d8307d
+static void
d8307d
+cmdline_process (int c)
d8307d
+{
d8307d
+  long long int arg = strtoll (optarg, NULL, 0);
d8307d
+  switch (c)
d8307d
+    {
d8307d
+    case OPT_ITERATIONS:
d8307d
+      if (arg > 0)
d8307d
+	iteration_count = arg;
d8307d
+      break;
d8307d
+    case OPT_THREADS:
d8307d
+      if (arg > 0 && arg < 100)
d8307d
+	thread_count = arg;
d8307d
+      break;
d8307d
+    }
d8307d
+}
d8307d
+#define CMDLINE_PROCESS cmdline_process
d8307d
+#define TIMEOUT 50
d8307d
+#include <support/test-driver.c>
d8307d
diff --git a/sysdeps/nptl/bits/thread-shared-types.h b/sysdeps/nptl/bits/thread-shared-types.h
d8307d
index 1e2092a05d5610f7..05c94e7a710c0eb9 100644
d8307d
--- a/sysdeps/nptl/bits/thread-shared-types.h
d8307d
+++ b/sysdeps/nptl/bits/thread-shared-types.h
d8307d
@@ -124,7 +124,27 @@ struct __pthread_mutex_s
d8307d
   unsigned int __nusers;
d8307d
 #endif
d8307d
   /* KIND must stay at this position in the structure to maintain
d8307d
-     binary compatibility with static initializers.  */
d8307d
+     binary compatibility with static initializers.
d8307d
+
d8307d
+     Concurrency notes:
d8307d
+     The __kind of a mutex is initialized either by the static
d8307d
+     PTHREAD_MUTEX_INITIALIZER or by a call to pthread_mutex_init.
d8307d
+
d8307d
+     After a mutex has been initialized, the __kind of a mutex is usually not
d8307d
+     changed.  BUT it can be set to -1 in pthread_mutex_destroy or elision can
d8307d
+     be enabled.  This is done concurrently in the pthread_mutex_*lock functions
d8307d
+     by using the macro FORCE_ELISION. This macro is only defined for
d8307d
+     architectures which supports lock elision.
d8307d
+
d8307d
+     For elision, there are the flags PTHREAD_MUTEX_ELISION_NP and
d8307d
+     PTHREAD_MUTEX_NO_ELISION_NP which can be set in addition to the already set
d8307d
+     type of a mutex.
d8307d
+     Before a mutex is initialized, only PTHREAD_MUTEX_NO_ELISION_NP can be set
d8307d
+     with pthread_mutexattr_settype.
d8307d
+     After a mutex has been initialized, the functions pthread_mutex_*lock can
d8307d
+     enable elision - if the mutex-type and the machine supports it - by setting
d8307d
+     the flag PTHREAD_MUTEX_ELISION_NP. This is done concurrently. Afterwards
d8307d
+     the lock / unlock functions are using specific elision code-paths.  */
d8307d
   int __kind;
d8307d
   __PTHREAD_COMPAT_PADDING_MID
d8307d
 #if __PTHREAD_MUTEX_NUSERS_AFTER_KIND
d8307d
diff --git a/sysdeps/unix/sysv/linux/powerpc/force-elision.h b/sysdeps/unix/sysv/linux/powerpc/force-elision.h
d8307d
index fe5d6ceade2bad36..d8f5a4b1c7713bd4 100644
d8307d
--- a/sysdeps/unix/sysv/linux/powerpc/force-elision.h
d8307d
+++ b/sysdeps/unix/sysv/linux/powerpc/force-elision.h
d8307d
@@ -18,9 +18,45 @@
d8307d
 
d8307d
 /* Automatically enable elision for existing user lock kinds.  */
d8307d
 #define FORCE_ELISION(m, s)						\
d8307d
-  if (__pthread_force_elision						\
d8307d
-      && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0)	\
d8307d
+  if (__pthread_force_elision)						\
d8307d
     {									\
d8307d
-      mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP;			\
d8307d
-      s;								\
d8307d
+      /* See concurrency notes regarding __kind in			\
d8307d
+	 struct __pthread_mutex_s in					\
d8307d
+	 sysdeps/nptl/bits/thread-shared-types.h.			\
d8307d
+									\
d8307d
+	 There are the following cases for the kind of a mutex		\
d8307d
+	 (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags	\
d8307d
+	 PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where	\
d8307d
+	 only one of both flags can be set):				\
d8307d
+	 - both flags are not set:					\
d8307d
+	 This is the first lock operation for this mutex.  Enable	\
d8307d
+	 elision as it is not enabled so far.				\
d8307d
+	 Note: It can happen that multiple threads are calling e.g.	\
d8307d
+	 pthread_mutex_lock at the same time as the first lock		\
d8307d
+	 operation for this mutex.  Then elision is enabled for this	\
d8307d
+	 mutex by multiple threads.  Storing with relaxed MO is enough	\
d8307d
+	 as all threads will store the same new value for the kind of	\
d8307d
+	 the mutex.  But we have to ensure that we always use the	\
d8307d
+	 elision path regardless if this thread has enabled elision or	\
d8307d
+	 another one.							\
d8307d
+									\
d8307d
+	 - PTHREAD_MUTEX_ELISION_NP flag is set:			\
d8307d
+	 Elision was already enabled for this mutex by a previous lock	\
d8307d
+	 operation.  See case above.  Just use the elision path.	\
d8307d
+									\
d8307d
+	 - PTHREAD_MUTEX_NO_ELISION_NP flag is set:			\
d8307d
+	 Elision was explicitly disabled by pthread_mutexattr_settype.	\
d8307d
+	 Do not use the elision path.					\
d8307d
+	 Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be	\
d8307d
+	 changed after mutex initialization.  */			\
d8307d
+      int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind));	\
d8307d
+      if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0)		\
d8307d
+	{								\
d8307d
+	  mutex_kind |= PTHREAD_MUTEX_ELISION_NP;			\
d8307d
+	  atomic_store_relaxed (&((m)->__data.__kind), mutex_kind);	\
d8307d
+	}								\
d8307d
+      if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0)			\
d8307d
+	{								\
d8307d
+	  s;								\
d8307d
+	}								\
d8307d
     }
d8307d
diff --git a/sysdeps/unix/sysv/linux/s390/force-elision.h b/sysdeps/unix/sysv/linux/s390/force-elision.h
d8307d
index d8a1b9972f739cfe..71f32367dd6b6489 100644
d8307d
--- a/sysdeps/unix/sysv/linux/s390/force-elision.h
d8307d
+++ b/sysdeps/unix/sysv/linux/s390/force-elision.h
d8307d
@@ -18,9 +18,45 @@
d8307d
 
d8307d
 /* Automatically enable elision for existing user lock kinds.  */
d8307d
 #define FORCE_ELISION(m, s)						\
d8307d
-  if (__pthread_force_elision						\
d8307d
-      && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0)	\
d8307d
+  if (__pthread_force_elision)						\
d8307d
     {									\
d8307d
-      mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP;			\
d8307d
-      s;								\
d8307d
+      /* See concurrency notes regarding __kind in			\
d8307d
+	 struct __pthread_mutex_s in					\
d8307d
+	 sysdeps/nptl/bits/thread-shared-types.h.			\
d8307d
+									\
d8307d
+	 There are the following cases for the kind of a mutex		\
d8307d
+	 (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags	\
d8307d
+	 PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where	\
d8307d
+	 only one of both flags can be set):				\
d8307d
+	 - both flags are not set:					\
d8307d
+	 This is the first lock operation for this mutex.  Enable	\
d8307d
+	 elision as it is not enabled so far.				\
d8307d
+	 Note: It can happen that multiple threads are calling e.g.	\
d8307d
+	 pthread_mutex_lock at the same time as the first lock		\
d8307d
+	 operation for this mutex.  Then elision is enabled for this	\
d8307d
+	 mutex by multiple threads.  Storing with relaxed MO is enough	\
d8307d
+	 as all threads will store the same new value for the kind of	\
d8307d
+	 the mutex.  But we have to ensure that we always use the	\
d8307d
+	 elision path regardless if this thread has enabled elision or	\
d8307d
+	 another one.							\
d8307d
+									\
d8307d
+	 - PTHREAD_MUTEX_ELISION_NP flag is set:			\
d8307d
+	 Elision was already enabled for this mutex by a previous lock	\
d8307d
+	 operation.  See case above.  Just use the elision path.	\
d8307d
+									\
d8307d
+	 - PTHREAD_MUTEX_NO_ELISION_NP flag is set:			\
d8307d
+	 Elision was explicitly disabled by pthread_mutexattr_settype.	\
d8307d
+	 Do not use the elision path.					\
d8307d
+	 Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be	\
d8307d
+	 changed after mutex initialization.  */			\
d8307d
+      int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind));	\
d8307d
+      if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0)		\
d8307d
+	{								\
d8307d
+	  mutex_kind |= PTHREAD_MUTEX_ELISION_NP;			\
d8307d
+	  atomic_store_relaxed (&((m)->__data.__kind), mutex_kind);	\
d8307d
+	}								\
d8307d
+      if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0)			\
d8307d
+	{								\
d8307d
+	  s;								\
d8307d
+	}								\
d8307d
     }
d8307d
diff --git a/sysdeps/unix/sysv/linux/x86/force-elision.h b/sysdeps/unix/sysv/linux/x86/force-elision.h
d8307d
index dd659c908f3046c1..61282d6678d89787 100644
d8307d
--- a/sysdeps/unix/sysv/linux/x86/force-elision.h
d8307d
+++ b/sysdeps/unix/sysv/linux/x86/force-elision.h
d8307d
@@ -18,9 +18,45 @@
d8307d
 
d8307d
 /* Automatically enable elision for existing user lock kinds.  */
d8307d
 #define FORCE_ELISION(m, s)						\
d8307d
-  if (__pthread_force_elision						\
d8307d
-      && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0)	\
d8307d
+  if (__pthread_force_elision)						\
d8307d
     {									\
d8307d
-      mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP;			\
d8307d
-      s;								\
d8307d
+      /* See concurrency notes regarding __kind in			\
d8307d
+	 struct __pthread_mutex_s in					\
d8307d
+	 sysdeps/nptl/bits/thread-shared-types.h.			\
d8307d
+									\
d8307d
+	 There are the following cases for the kind of a mutex		\
d8307d
+	 (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags	\
d8307d
+	 PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where	\
d8307d
+	 only one of both flags can be set):				\
d8307d
+	 - both flags are not set:					\
d8307d
+	 This is the first lock operation for this mutex.  Enable	\
d8307d
+	 elision as it is not enabled so far.				\
d8307d
+	 Note: It can happen that multiple threads are calling e.g.	\
d8307d
+	 pthread_mutex_lock at the same time as the first lock		\
d8307d
+	 operation for this mutex.  Then elision is enabled for this	\
d8307d
+	 mutex by multiple threads.  Storing with relaxed MO is enough	\
d8307d
+	 as all threads will store the same new value for the kind of	\
d8307d
+	 the mutex.  But we have to ensure that we always use the	\
d8307d
+	 elision path regardless if this thread has enabled elision or	\
d8307d
+	 another one.							\
d8307d
+									\
d8307d
+	 - PTHREAD_MUTEX_ELISION_NP flag is set:			\
d8307d
+	 Elision was already enabled for this mutex by a previous lock	\
d8307d
+	 operation.  See case above.  Just use the elision path.	\
d8307d
+									\
d8307d
+	 - PTHREAD_MUTEX_NO_ELISION_NP flag is set:			\
d8307d
+	 Elision was explicitly disabled by pthread_mutexattr_settype.	\
d8307d
+	 Do not use the elision path.					\
d8307d
+	 Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be	\
d8307d
+	 changed after mutex initialization.  */			\
d8307d
+      int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind));	\
d8307d
+      if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0)		\
d8307d
+	{								\
d8307d
+	  mutex_kind |= PTHREAD_MUTEX_ELISION_NP;			\
d8307d
+	  atomic_store_relaxed (&((m)->__data.__kind), mutex_kind);	\
d8307d
+	}								\
d8307d
+      if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0)			\
d8307d
+	{								\
d8307d
+	  s;								\
d8307d
+	}								\
d8307d
     }