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