diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index b6a7a5ef06ad72ac79d25bea5b3ac6454274426c..893773fa10f0228be9d64af7e1e884dcb048391c 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -4,10 +4,13 @@ #include "libc.h" #include #include +#include void *__mmap(void *, size_t, int, int, int, off_t); int __munmap(void *, size_t); int __mprotect(void *, size_t, int); +void __vm_lock_impl(int); +void __vm_unlock_impl(void); static void dummy_0() { @@ -15,7 +18,6 @@ static void dummy_0() weak_alias(dummy_0, __acquire_ptc); weak_alias(dummy_0, __release_ptc); weak_alias(dummy_0, __pthread_tsd_run_dtors); -weak_alias(dummy_0, __do_private_robust_list); weak_alias(dummy_0, __do_orphaned_stdio_locks); _Noreturn void __pthread_exit(void *result) @@ -72,7 +74,25 @@ _Noreturn void __pthread_exit(void *result) a_dec(&libc.bytelocale_cnt_minus_1); } - __do_private_robust_list(); + /* Process robust list in userspace to handle non-pshared mutexes + * and the detached thread case where the robust list head will + * be invalid when the kernel would process it. */ + __vm_lock_impl(+1); + volatile void *volatile *rp; + while ((rp=self->robust_list.head) && rp != &self->robust_list.head) { + pthread_mutex_t *m = (void *)((char *)rp + - offsetof(pthread_mutex_t, _m_next)); + int waiters = m->_m_waiters; + int priv = (m->_m_type & 128) ^ 128; + self->robust_list.pending = rp; + self->robust_list.head = *rp; + int cont = a_swap(&m->_m_lock, self->tid|0x40000000); + self->robust_list.pending = 0; + if (cont < 0 || waiters) + __wake(&m->_m_lock, 1, priv); + } + __vm_unlock_impl(); + __do_orphaned_stdio_locks(); if (self->detached && self->map_base) { @@ -85,6 +105,11 @@ _Noreturn void __pthread_exit(void *result) * detached later (== 2), we need to clear it here. */ if (self->detached == 2) __syscall(SYS_set_tid_address, 0); + /* Robust list will no longer be valid, and was already + * processed above, so unregister it with the kernel. */ + if (self->robust_list.off) + __syscall(SYS_set_robust_list, 0, 3*sizeof(long)); + /* The following call unmaps the thread's stack mapping * and then exits without touching the stack. */ __unmapself(self->map_base, self->map_size); diff --git a/src/thread/pthread_mutexattr_setrobust.c b/src/thread/pthread_mutexattr_setrobust.c index d06278894a47cd5bb44a1d12e7f525d34ecb777e..dcfa4cf1c771c5347240c3bd826448b69f094f06 100644 --- a/src/thread/pthread_mutexattr_setrobust.c +++ b/src/thread/pthread_mutexattr_setrobust.c @@ -1,28 +1,4 @@ #include "pthread_impl.h" -#include - -void __do_private_robust_list() -{ - pthread_t self = __pthread_self(); - volatile void *volatile *p; - volatile void *volatile *prev; - volatile void *volatile *next; - pthread_mutex_t *m; - - prev = &self->robust_list.head; - for (p=self->robust_list.head; p&&p!=&self->robust_list.head; p=next) { - next = *p; - m = (void *)((char *)p - offsetof(pthread_mutex_t, _m_next)); - if (!(m->_m_type & 128)) { - int waiters = m->_m_waiters; - *prev = next; - int cont = a_swap(&m->_m_lock, self->tid|0x40000000); - if (cont < 0 || waiters) __wake(&m->_m_lock, 1, 1); - } else { - prev = p; - } - } -} int pthread_mutexattr_setrobust(pthread_mutexattr_t *a, int robust) {