diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index 3d4b2f7b053c0..99402679122be 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -32,6 +32,8 @@ static void dummy_0() {} weak_alias(dummy_0, __pthread_tsd_run_dtors); +weak_alias(dummy_0, __do_orphaned_stdio_locks); +weak_alias(dummy_0, __dl_thread_cleanup); static void __run_cleanup_handlers() { pthread_t self = __pthread_self(); @@ -312,6 +314,16 @@ void _emscripten_thread_exit(void* result) { // Call into the musl function that runs destructors of all thread-specific data. __pthread_tsd_run_dtors(); + // If this is the main runtime thread, don't proceed with + // termination of the thread, but prepare for exit to call + // atexit handlers. + if (emscripten_is_main_runtime_thread()) { + exit(0); + } + + /* At this point we are committed to thread termination. */ + + /* The thread list lock must be AS-safe. */ __tl_lock(); /* Process robust list in userspace to handle non-pshared mutexes @@ -333,24 +345,23 @@ void _emscripten_thread_exit(void* result) { } __vm_unlock(); - if (!--libc.threads_minus_1) libc.need_locks = 0; + __do_orphaned_stdio_locks(); + __dl_thread_cleanup(); + /* Last, unlink thread from the list. This change will not be visible + * until the lock is released via __tl_unlock() below. */ + if (!--libc.threads_minus_1) libc.need_locks = 0; self->next->prev = self->prev; self->prev->next = self->next; self->prev = self->next = self; __tl_unlock(); - if (emscripten_is_main_runtime_thread()) { - exit(0); - return; - } - // Not hosting a pthread anymore in this worker set __pthread_self to NULL __set_thread_state(NULL, 0, 0, 1); - // This atomic potentially competes with a concurrent pthread_detach - // call; the loser is responsible for freeing thread resources. + /* This atomic potentially competes with a concurrent pthread_detach + * call; the loser is responsible for freeing thread resources. */ int state = a_cas(&self->detach_state, DT_JOINABLE, DT_EXITING); if (state == DT_DETACHED) { @@ -363,8 +374,10 @@ void _emscripten_thread_exit(void* result) { // When dynamic linking is enabled we need to keep track of zombie threads _emscripten_thread_exit_joinable(self); #endif + + /* Wake any joiner. */ a_store(&self->detach_state, DT_EXITED); - __wake(&self->detach_state, 1, 1); // Wake any joiner. + __wake(&self->detach_state, 1, 1); } } diff --git a/test/codesize/test_codesize_minimal_pthreads.json b/test/codesize/test_codesize_minimal_pthreads.json index 4e0869c3b49ed..928806850fcd3 100644 --- a/test/codesize/test_codesize_minimal_pthreads.json +++ b/test/codesize/test_codesize_minimal_pthreads.json @@ -2,9 +2,9 @@ "a.out.js": 7367, "a.out.js.gz": 3587, "a.out.nodebug.wasm": 19037, - "a.out.nodebug.wasm.gz": 8786, + "a.out.nodebug.wasm.gz": 8787, "total": 26404, - "total_gz": 12373, + "total_gz": 12374, "sent": [ "a (memory)", "b (exit)", diff --git a/test/codesize/test_codesize_minimal_pthreads_memgrowth.json b/test/codesize/test_codesize_minimal_pthreads_memgrowth.json index d4906b590fa64..5477e9ba79e30 100644 --- a/test/codesize/test_codesize_minimal_pthreads_memgrowth.json +++ b/test/codesize/test_codesize_minimal_pthreads_memgrowth.json @@ -2,9 +2,9 @@ "a.out.js": 7776, "a.out.js.gz": 3791, "a.out.nodebug.wasm": 19038, - "a.out.nodebug.wasm.gz": 8787, + "a.out.nodebug.wasm.gz": 8788, "total": 26814, - "total_gz": 12578, + "total_gz": 12579, "sent": [ "a (memory)", "b (exit)",