Skip to content

Commit 335fb7d

Browse files
authored
Add support for PTHREAD_MUTEX_ROBUST (#24666)
This was mostly just a case of copying the robust list handling code from the musl version of pthread_create.
1 parent 1277e22 commit 335fb7d

8 files changed

+78
-4
lines changed

system/lib/pthread/pthread_create.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,10 +312,29 @@ void _emscripten_thread_exit(void* result) {
312312
// Call into the musl function that runs destructors of all thread-specific data.
313313
__pthread_tsd_run_dtors();
314314

315-
if (!--libc.threads_minus_1) libc.need_locks = 0;
316-
317315
__tl_lock();
318316

317+
/* Process robust list in userspace to handle non-pshared mutexes
318+
* and the detached thread case where the robust list head will
319+
* be invalid when the kernel would process it. */
320+
__vm_lock();
321+
volatile void *volatile *rp;
322+
while ((rp=self->robust_list.head) && rp != &self->robust_list.head) {
323+
pthread_mutex_t *m = (void *)((char *)rp
324+
- offsetof(pthread_mutex_t, _m_next));
325+
int waiters = m->_m_waiters;
326+
int priv = (m->_m_type & 128) ^ 128;
327+
self->robust_list.pending = rp;
328+
self->robust_list.head = *rp;
329+
int cont = a_swap(&m->_m_lock, 0x40000000);
330+
self->robust_list.pending = 0;
331+
if (cont < 0 || waiters)
332+
__wake(&m->_m_lock, 1, priv);
333+
}
334+
__vm_unlock();
335+
336+
if (!--libc.threads_minus_1) libc.need_locks = 0;
337+
319338
self->next->prev = self->prev;
320339
self->prev->next = self->next;
321340
self->prev = self->next = self;

test/other/codesize/test_codesize_minimal_pthreads.funcs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ $__timedwait
1818
$__timedwait_cp
1919
$__tl_lock
2020
$__tl_unlock
21+
$__vm_lock
22+
$__vm_unlock
2123
$__wait
2224
$__wake
2325
$__wake
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
19402
1+
19526

test/other/codesize/test_codesize_minimal_pthreads_memgrowth.funcs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ $__timedwait
1818
$__timedwait_cp
1919
$__tl_lock
2020
$__tl_unlock
21+
$__vm_lock
22+
$__vm_unlock
2123
$__wait
2224
$__wake
2325
$__wake
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
19403
1+
19527
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <assert.h>
2+
#include <errno.h>
3+
#include <pthread.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <unistd.h>
8+
9+
pthread_mutex_t mtx;
10+
11+
void* original_owner_thread(void* ptr) {
12+
printf("[original owner] Setting lock...\n");
13+
pthread_mutex_lock(&mtx);
14+
printf("[original owner] Locked. Now exiting without unlocking.\n");
15+
pthread_exit(NULL);
16+
}
17+
18+
int main(void) {
19+
pthread_mutexattr_t attr;
20+
pthread_mutexattr_init(&attr);
21+
pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
22+
23+
pthread_mutex_init(&mtx, &attr);
24+
25+
pthread_t thr;
26+
pthread_create(&thr, NULL, original_owner_thread, NULL);
27+
pthread_join(thr, NULL);
28+
29+
printf("[main] Attempting to lock the robust mutex.\n");
30+
int rtn = pthread_mutex_lock(&mtx);
31+
printf("[main] pthread_mutex_lock -> %s.\n", strerror(rtn));
32+
assert(rtn == EOWNERDEAD && "expected EOWNERDEAD");
33+
printf("[main] Now make the mutex consistent\n");
34+
rtn = pthread_mutex_consistent(&mtx);
35+
assert(rtn == 0);
36+
printf("[main] Mutex is now consistent; unlocking\n");
37+
rtn = pthread_mutex_unlock(&mtx);
38+
assert(rtn == 0);
39+
40+
return 0;
41+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[original owner] Setting lock...
2+
[original owner] Locked. Now exiting without unlocking.
3+
[main] Attempting to lock the robust mutex.
4+
[main] pthread_mutex_lock -> Previous owner died.
5+
[main] Now make the mutex consistent
6+
[main] Mutex is now consistent; unlocking

test/test_core.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2725,6 +2725,10 @@ def test_pthread_run_script(self):
27252725
self.set_setting('EXIT_RUNTIME')
27262726
self.do_runf('pthread/test_pthread_run_script.c')
27272727

2728+
@node_pthreads
2729+
def test_pthread_mutex_robust(self):
2730+
self.do_run_in_out_file_test('pthread/test_pthread_mutex_robust.c')
2731+
27282732
@node_pthreads
27292733
def test_pthread_wait32_notify(self):
27302734
self.do_run_in_out_file_test('atomic/test_wait32_notify.c')

0 commit comments

Comments
 (0)