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