diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | nptl/pthread_mutex_lock.c | 15 | ||||
-rw-r--r-- | nptl/pthread_mutex_timedlock.c | 14 |
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)) |