c6d234
commit 5920a4a624b1f4db310d1c44997b640e2a4653e5
c6d234
Author: Carlos O'Donell <carlos@redhat.com>
c6d234
Date:   Sat Jul 29 00:02:03 2017 -0400
c6d234
c6d234
    mutex: Fix robust mutex lock acquire (Bug 21778)
c6d234
    
c6d234
    65810f0ef05e8c9e333f17a44e77808b163ca298 fixed a robust mutex bug but
c6d234
    introduced BZ 21778: if the CAS used to try to acquire a lock fails, the
c6d234
    expected value is not updated, which breaks other cases in the loce
c6d234
    acquisition loop.  The fix is to simply update the expected value with
c6d234
    the value returned by the CAS, which ensures that behavior is as if the
c6d234
    first case with the CAS never happened (if the CAS fails).
c6d234
    
c6d234
    This is a regression introduced in the last release.
c6d234
    
c6d234
    Tested on x86_64, i686, ppc64, ppc64le, s390x, aarch64, armv7hl.
c6d234
c6d234
Index: glibc-2.17-c758a686/nptl/Makefile
c6d234
===================================================================
c6d234
--- glibc-2.17-c758a686.orig/nptl/Makefile
c6d234
+++ glibc-2.17-c758a686/nptl/Makefile
c6d234
@@ -204,7 +204,7 @@ CFLAGS-tst-thread-exit-clobber.o = -std=
c6d234
 tests = tst-typesizes \
c6d234
 	tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
c6d234
 	tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
c6d234
-	tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \
c6d234
+	tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a tst-mutex7robust \
c6d234
 	tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
c6d234
 	tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \
c6d234
 	tst-mutexpi9 \
c6d234
Index: glibc-2.17-c758a686/nptl/pthread_mutex_lock.c
c6d234
===================================================================
c6d234
--- glibc-2.17-c758a686.orig/nptl/pthread_mutex_lock.c
c6d234
+++ glibc-2.17-c758a686/nptl/pthread_mutex_lock.c
c6d234
@@ -198,11 +198,14 @@ __pthread_mutex_lock_full (pthread_mutex
c6d234
 	{
c6d234
 	  /* Try to acquire the lock through a CAS from 0 (not acquired) to
c6d234
 	     our TID | assume_other_futex_waiters.  */
c6d234
-	  if (__glibc_likely ((oldval == 0)
c6d234
-			      && (atomic_compare_and_exchange_bool_acq
c6d234
-				  (&mutex->__data.__lock,
c6d234
-				   id | assume_other_futex_waiters, 0) == 0)))
c6d234
-	      break;
c6d234
+	  if (__glibc_likely (oldval == 0))
c6d234
+	    {
c6d234
+	      oldval
c6d234
+	        = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
c6d234
+	            id | assume_other_futex_waiters, 0);
c6d234
+	      if (__glibc_likely (oldval == 0))
c6d234
+		break;
c6d234
+	    }
c6d234
 
c6d234
 	  if ((oldval & FUTEX_OWNER_DIED) != 0)
c6d234
 	    {
c6d234
Index: glibc-2.17-c758a686/nptl/pthread_mutex_timedlock.c
c6d234
===================================================================
c6d234
--- glibc-2.17-c758a686.orig/nptl/pthread_mutex_timedlock.c
c6d234
+++ glibc-2.17-c758a686/nptl/pthread_mutex_timedlock.c
c6d234
@@ -154,11 +154,14 @@ pthread_mutex_timedlock (pthread_mutex_t
c6d234
 	{
c6d234
 	  /* Try to acquire the lock through a CAS from 0 (not acquired) to
c6d234
 	     our TID | assume_other_futex_waiters.  */
c6d234
-	  if (__glibc_likely ((oldval == 0)
c6d234
-			      && (atomic_compare_and_exchange_bool_acq
c6d234
-				  (&mutex->__data.__lock,
c6d234
-				   id | assume_other_futex_waiters, 0) == 0)))
c6d234
-	      break;
c6d234
+	  if (__glibc_likely (oldval == 0))
c6d234
+	    {
c6d234
+	      oldval
c6d234
+	        = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
c6d234
+	            id | assume_other_futex_waiters, 0);
c6d234
+	      if (__glibc_likely (oldval == 0))
c6d234
+		break;
c6d234
+	    }
c6d234
 
c6d234
 	  if ((oldval & FUTEX_OWNER_DIED) != 0)
c6d234
 	    {
c6d234
Index: glibc-2.17-c758a686/nptl/tst-mutex7.c
c6d234
===================================================================
c6d234
--- glibc-2.17-c758a686.orig/nptl/tst-mutex7.c
c6d234
+++ glibc-2.17-c758a686/nptl/tst-mutex7.c
c6d234
@@ -22,25 +22,41 @@
c6d234
 #include <stdlib.h>
c6d234
 #include <time.h>
c6d234
 
c6d234
-
c6d234
+/* This test is a template for other tests to use.  Other tests define
c6d234
+   the following macros to change the behaviour of the template test.
c6d234
+   The test is very simple, it configures N threads given the parameters
c6d234
+   below and then proceeds to go through mutex lock and unlock
c6d234
+   operations in each thread as described before for the thread
c6d234
+   function.  */
c6d234
 #ifndef TYPE
c6d234
 # define TYPE PTHREAD_MUTEX_DEFAULT
c6d234
 #endif
c6d234
-
c6d234
+#ifndef ROBUST
c6d234
+# define ROBUST PTHREAD_MUTEX_STALLED
c6d234
+#endif
c6d234
+#ifndef DELAY_NSEC
c6d234
+# define DELAY_NSEC 11000
c6d234
+#endif
c6d234
+#ifndef ROUNDS
c6d234
+# define ROUNDS 1000
c6d234
+#endif
c6d234
+#ifndef N
c6d234
+# define N 100
c6d234
+#endif
c6d234
 
c6d234
 static pthread_mutex_t lock;
c6d234
 
c6d234
-
c6d234
-#define ROUNDS 1000
c6d234
-#define N 100
c6d234
-
c6d234
-
c6d234
+/* Each thread locks and the subsequently unlocks the lock, yielding
c6d234
+   the smallest critical section possible.  After the unlock the thread
c6d234
+   waits DELAY_NSEC nanoseconds before doing the lock and unlock again.
c6d234
+   Every thread does this ROUNDS times.  The lock and unlock are
c6d234
+   checked for errors.  */
c6d234
 static void *
c6d234
 tf (void *arg)
c6d234
 {
c6d234
   int nr = (long int) arg;
c6d234
   int cnt;
c6d234
-  struct timespec ts = { .tv_sec = 0, .tv_nsec = 11000 };
c6d234
+  struct timespec ts = { .tv_sec = 0, .tv_nsec = DELAY_NSEC };
c6d234
 
c6d234
   for (cnt = 0; cnt < ROUNDS; ++cnt)
c6d234
     {
c6d234
@@ -56,13 +72,16 @@ tf (void *arg)
c6d234
 	  return (void *) 1l;
c6d234
 	}
c6d234
 
c6d234
-      nanosleep (&ts, NULL);
c6d234
+      if ((ts.tv_sec > 0) || (ts.tv_nsec > 0))
c6d234
+	nanosleep (&ts, NULL);
c6d234
     }
c6d234
 
c6d234
   return NULL;
c6d234
 }
c6d234
 
c6d234
-
c6d234
+/* Setup and run N threads, where each thread does as described
c6d234
+   in the above thread function.  The threads are given a minimal 1MiB
c6d234
+   stack since they don't do anything between the lock and unlock.  */
c6d234
 static int
c6d234
 do_test (void)
c6d234
 {
c6d234
@@ -80,6 +99,12 @@ do_test (void)
c6d234
       exit (1);
c6d234
     }
c6d234
 
c6d234
+  if (pthread_mutexattr_setrobust (&a, ROBUST) != 0)
c6d234
+    {
c6d234
+      puts ("mutexattr_setrobust failed");
c6d234
+      exit (1);
c6d234
+    }
c6d234
+
c6d234
 #ifdef ENABLE_PI
c6d234
   if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
c6d234
     {
c6d234
Index: glibc-2.17-c758a686/nptl/tst-mutex7robust.c
c6d234
===================================================================
c6d234
--- /dev/null
c6d234
+++ glibc-2.17-c758a686/nptl/tst-mutex7robust.c
c6d234
@@ -0,0 +1,7 @@
c6d234
+/* Bug 21778: Fix oversight in robust mutex lock acquisition.  */
c6d234
+#define TYPE PTHREAD_MUTEX_NORMAL
c6d234
+#define ROBUST PTHREAD_MUTEX_ROBUST
c6d234
+#define DELAY_NSEC 0
c6d234
+#define ROUNDS 1000
c6d234
+#define N 32
c6d234
+#include "tst-mutex7.c"