about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--nptl/pthread_mutex_lock.c15
-rw-r--r--nptl/pthread_mutex_timedlock.c14
3 files changed, 32 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index c2bb608c0b..e7c9757c4f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2016-12-19  Torvald Riegel  <triegel@redhat.com>
+
+	[BZ #20973]
+	* nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full): Fix lost
+	wake-up in robust mutexes.
+	* nptl/pthread_mutex_timedlock.c (pthread_mutex_timedlock): Likewise.
+
 2016-12-19  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
 
 	* benchtests/Makefile (bench-math): Add fminf and fmaxf.
diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
index bdfa529f63..c92bbeea22 100644
--- a/nptl/pthread_mutex_lock.c
+++ b/nptl/pthread_mutex_lock.c
@@ -182,6 +182,11 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
 		     &mutex->__data.__list.__next);
 
       oldval = mutex->__data.__lock;
+      /* This is set to FUTEX_WAITERS iff we might have shared the
+	 FUTEX_WAITERS flag with other threads, and therefore need to keep it
+	 set to avoid lost wake-ups.  We have the same requirement in the
+	 simple mutex algorithm.  */
+      unsigned int assume_other_futex_waiters = 0;
       do
 	{
 	again:
@@ -190,9 +195,11 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
 	      /* The previous owner died.  Try locking the mutex.  */
 	      int newval = id;
 #ifdef NO_INCR
+	      /* We are not taking assume_other_futex_waiters into accoount
+		 here simply because we'll set FUTEX_WAITERS anyway.  */
 	      newval |= FUTEX_WAITERS;
 #else
-	      newval |= (oldval & FUTEX_WAITERS);
+	      newval |= (oldval & FUTEX_WAITERS) | assume_other_futex_waiters;
 #endif
 
 	      newval
@@ -253,7 +260,11 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
 		}
 	    }
 
-	  oldval = LLL_ROBUST_MUTEX_LOCK (mutex, id);
+	  oldval = LLL_ROBUST_MUTEX_LOCK (mutex,
+					  id | assume_other_futex_waiters);
+	  /* See above.  We set FUTEX_WAITERS and might have shared this flag
+	     with other threads; thus, we need to preserve it.  */
+	  assume_other_futex_waiters = FUTEX_WAITERS;
 
 	  if (__builtin_expect (mutex->__data.__owner
 				== PTHREAD_MUTEX_NOTRECOVERABLE, 0))
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
index 07f0901e52..21e9eeada0 100644
--- a/nptl/pthread_mutex_timedlock.c
+++ b/nptl/pthread_mutex_timedlock.c
@@ -142,13 +142,19 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex,
 		     &mutex->__data.__list.__next);
 
       oldval = mutex->__data.__lock;
+      /* This is set to FUTEX_WAITERS iff we might have shared the
+	 FUTEX_WAITERS flag with other threads, and therefore need to keep it
+	 set to avoid lost wake-ups.  We have the same requirement in the
+	 simple mutex algorithm.  */
+      unsigned int assume_other_futex_waiters = 0;
       do
 	{
 	again:
 	  if ((oldval & FUTEX_OWNER_DIED) != 0)
 	    {
 	      /* The previous owner died.  Try locking the mutex.  */
-	      int newval = id | (oldval & FUTEX_WAITERS);
+	      int newval = id | (oldval & FUTEX_WAITERS)
+		  | assume_other_futex_waiters;
 
 	      newval
 		= atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
@@ -203,8 +209,12 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex,
 		}
 	    }
 
-	  result = lll_robust_timedlock (mutex->__data.__lock, abstime, id,
+	  result = lll_robust_timedlock (mutex->__data.__lock, abstime,
+					 id | assume_other_futex_waiters,
 					 PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
+	  /* See above.  We set FUTEX_WAITERS and might have shared this flag
+	     with other threads; thus, we need to preserve it.  */
+	  assume_other_futex_waiters = FUTEX_WAITERS;
 
 	  if (__builtin_expect (mutex->__data.__owner
 				== PTHREAD_MUTEX_NOTRECOVERABLE, 0))