25845f
commit 353683a22ed8a493a6bd1d78d63e144bc3e85d2f
25845f
Author: Torvald Riegel <triegel@redhat.com>
25845f
Date:   Thu Dec 15 16:06:28 2016 +0100
25845f
25845f
    Robust mutexes: Fix lost wake-up.
25845f
    
25845f
    Assume that Thread 1 waits to acquire a robust mutex using futexes to
25845f
    block (and thus sets the FUTEX_WAITERS flag), and is unblocked when this
25845f
    mutex is released.  If Thread 2 concurrently acquires the lock and is
25845f
    killed, Thread 1 can recover from the died owner but fail to restore the
25845f
    FUTEX_WAITERS flag.  This can lead to a Thread 3 that also blocked using
25845f
    futexes at the same time as Thread 1 to not get woken up because
25845f
    FUTEX_WAITERS is not set anymore.
25845f
    
25845f
    The fix for this is to ensure that we continue to preserve the
25845f
    FUTEX_WAITERS flag whenever we may have set it or shared it with another
25845f
    thread.  This is the same requirement as in the algorithm for normal
25845f
    mutexes, only that the robust mutexes need additional handling for died
25845f
    owners and thus preserving the FUTEX_WAITERS flag cannot be done just in
25845f
    the futex slowpath code.
25845f
    
25845f
            [BZ #20973]
25845f
            * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full): Fix lost
25845f
            wake-up in robust mutexes.
25845f
            * nptl/pthread_mutex_timedlock.c (pthread_mutex_timedlock): Likewise.
25845f
25845f
Index: glibc-2.17-c758a686/nptl/pthread_mutex_lock.c
25845f
===================================================================
25845f
--- glibc-2.17-c758a686.orig/nptl/pthread_mutex_lock.c
25845f
+++ glibc-2.17-c758a686/nptl/pthread_mutex_lock.c
25845f
@@ -183,6 +183,11 @@ __pthread_mutex_lock_full (pthread_mutex
25845f
 		     &mutex->__data.__list.__next);
25845f
 
25845f
       oldval = mutex->__data.__lock;
25845f
+      /* This is set to FUTEX_WAITERS iff we might have shared the
25845f
+	 FUTEX_WAITERS flag with other threads, and therefore need to keep it
25845f
+	 set to avoid lost wake-ups.  We have the same requirement in the
25845f
+	 simple mutex algorithm.  */
25845f
+      unsigned int assume_other_futex_waiters = 0;
25845f
       do
25845f
 	{
25845f
 	again:
25845f
@@ -191,9 +196,11 @@ __pthread_mutex_lock_full (pthread_mutex
25845f
 	      /* The previous owner died.  Try locking the mutex.  */
25845f
 	      int newval = id;
25845f
 #ifdef NO_INCR
25845f
+	      /* We are not taking assume_other_futex_waiters into accoount
25845f
+		 here simply because we'll set FUTEX_WAITERS anyway.  */
25845f
 	      newval |= FUTEX_WAITERS;
25845f
 #else
25845f
-	      newval |= (oldval & FUTEX_WAITERS);
25845f
+	      newval |= (oldval & FUTEX_WAITERS) | assume_other_futex_waiters;
25845f
 #endif
25845f
 
25845f
 	      newval
25845f
@@ -254,7 +261,11 @@ __pthread_mutex_lock_full (pthread_mutex
25845f
 		}
25845f
 	    }
25845f
 
25845f
-	  oldval = LLL_ROBUST_MUTEX_LOCK (mutex, id);
25845f
+	  oldval = LLL_ROBUST_MUTEX_LOCK (mutex,
25845f
+					  id | assume_other_futex_waiters);
25845f
+	  /* See above.  We set FUTEX_WAITERS and might have shared this flag
25845f
+	     with other threads; thus, we need to preserve it.  */
25845f
+	  assume_other_futex_waiters = FUTEX_WAITERS;
25845f
 
25845f
 	  if (__builtin_expect (mutex->__data.__owner
25845f
 				== PTHREAD_MUTEX_NOTRECOVERABLE, 0))
25845f
Index: glibc-2.17-c758a686/nptl/pthread_mutex_timedlock.c
25845f
===================================================================
25845f
--- glibc-2.17-c758a686.orig/nptl/pthread_mutex_timedlock.c
25845f
+++ glibc-2.17-c758a686/nptl/pthread_mutex_timedlock.c
25845f
@@ -142,13 +142,19 @@ pthread_mutex_timedlock (pthread_mutex_t
25845f
 		     &mutex->__data.__list.__next);
25845f
 
25845f
       oldval = mutex->__data.__lock;
25845f
+      /* This is set to FUTEX_WAITERS iff we might have shared the
25845f
+	 FUTEX_WAITERS flag with other threads, and therefore need to keep it
25845f
+	 set to avoid lost wake-ups.  We have the same requirement in the
25845f
+	 simple mutex algorithm.  */
25845f
+      unsigned int assume_other_futex_waiters = 0;
25845f
       do
25845f
 	{
25845f
 	again:
25845f
 	  if ((oldval & FUTEX_OWNER_DIED) != 0)
25845f
 	    {
25845f
 	      /* The previous owner died.  Try locking the mutex.  */
25845f
-	      int newval = id | (oldval & FUTEX_WAITERS);
25845f
+	      int newval = id | (oldval & FUTEX_WAITERS)
25845f
+		  | assume_other_futex_waiters;
25845f
 
25845f
 	      newval
25845f
 		= atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
25845f
@@ -203,8 +209,12 @@ pthread_mutex_timedlock (pthread_mutex_t
25845f
 		}
25845f
 	    }
25845f
 
25845f
-	  result = lll_robust_timedlock (mutex->__data.__lock, abstime, id,
25845f
+	  result = lll_robust_timedlock (mutex->__data.__lock, abstime,
25845f
+					 id | assume_other_futex_waiters,
25845f
 					 PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
25845f
+	  /* See above.  We set FUTEX_WAITERS and might have shared this flag
25845f
+	     with other threads; thus, we need to preserve it.  */
25845f
+	  assume_other_futex_waiters = FUTEX_WAITERS;
25845f
 
25845f
 	  if (__builtin_expect (mutex->__data.__owner
25845f
 				== PTHREAD_MUTEX_NOTRECOVERABLE, 0))