olga / rpms / glibc

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