summaryrefslogtreecommitdiff
path: root/src/thread
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2014-08-17 02:05:14 -0400
committerRich Felker <dalias@aerifal.cx>2014-08-17 02:05:14 -0400
commit4220d298ef7a2226b14fe4b481f7f7699eab6e3f (patch)
tree26c87d9a3a8c178801e4000772004c3aad1935b8 /src/thread
parentde7e99c58508ca70f0b1b8ef259a823a3766c434 (diff)
downloadmusl-4220d298ef7a2226b14fe4b481f7f7699eab6e3f.tar.gz
fix possible failure-to-wake deadlock with robust mutexes
when the kernel is responsible for waking waiters on a robust mutex whose owner died, it does not have a waiters count available and must rely entirely on the waiter bit of the lock value. normally, this bit is only set by newly arriving waiters, so it will be clear if no new waiters arrived after the current owner obtained the lock, even if there are other waiters present. leaving it clear is desirable because it allows timed-lock operations to remove themselves as waiters and avoid causing unnecessary futex wake syscalls. however, for process-shared robust mutexes, we need to set the bit whenever there are existing waiters so that the kernel will know to wake them. for non-process-shared robust mutexes, the wake happens in userspace and can look at the waiters count, so the bit does not need to be set in the non-process-shared case.
Diffstat (limited to 'src/thread')
-rw-r--r--src/thread/pthread_mutex_trylock.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/src/thread/pthread_mutex_trylock.c b/src/thread/pthread_mutex_trylock.c
index 31587e1f..e8515179 100644
--- a/src/thread/pthread_mutex_trylock.c
+++ b/src/thread/pthread_mutex_trylock.c
@@ -22,7 +22,10 @@ int __pthread_mutex_trylock_owner(pthread_mutex_t *m)
}
if (own == 0x40000000) return ENOTRECOVERABLE;
- self->robust_list.pending = &m->_m_next;
+ if (m->_m_type & 128) {
+ if (m->_m_waiters) tid |= 0x80000000;
+ self->robust_list.pending = &m->_m_next;
+ }
if ((own && (!(own & 0x40000000) || !(type & 4)))
|| a_cas(&m->_m_lock, old, tid) != old) {